Skip to content

Commit

Permalink
Adds some funcs to Slot
Browse files Browse the repository at this point in the history
children_count, get_child, find_child_by_name, find_child_by_tag
RobertBaruch committed Jan 9, 2024

Verified

This commit was signed with the committer’s verified signature.
aj-stein-nist A.J. Stein
1 parent 3a145c7 commit 75141bc
Showing 15 changed files with 457 additions and 135 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -40,7 +40,7 @@ Dergwasm includes a WASM binary, `firmware.wasm`, which implements a [MicroPytho
6:38:54 PM.614 ( -1 FPS) [INFO] [ResoniteModLoader/Dergwasm] Dergwasm patches applied
```
6. Copy this URL, and paste it into your world in Resonite: `resrec:///U-Xekri/R-a6ddab70-db2d-41cf-be0e-4f7a356afe69`. This is a Dergwasm slot hierarchy, already set up.
6. Copy this URL, and paste it into your world in Resonite: `resrec:///U-Xekri/R-c67b56f1-8b83-4108-8ac7-0846ed8ce8b9`. This is a Dergwasm slot hierarchy, already set up.
![The Dergwasm slot](dergwasm_slot.jpg)
7. Re-initialize Dergwasm by using the ProtofluxTool to create a Dynamic Impulse Trigger node. Set its `Tag` to `_dergwasm_init` and its `TargetHierarchy` to the top-level Dergwasm slot. Now trigger the node. There will be a slight hitch as the WASM file is read in and parsed.
1 change: 1 addition & 0 deletions dergwasm_mod/Dergwasm/Dergwasm.cs
Original file line number Diff line number Diff line change
@@ -183,6 +183,7 @@ public static void Init(World world, string filename)
if (consoleSlot != null)
consoleSlot.GetComponent<FrooxEngine.UIX.Text>().Content.Value = "";

Msg($"Dergwasm v{typeof(Dergwasm).Assembly.GetName().Version}");
Msg("Init called");
machine = new Machine();
// machine.Debug = true;
112 changes: 56 additions & 56 deletions dergwasm_mod/Dergwasm/Dergwasm.csproj
Original file line number Diff line number Diff line change
@@ -1,64 +1,64 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>0.1.1.0</Version>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>0.1.3.0</Version>
</PropertyGroup>

<PropertyGroup>
<ResonitePath>$(MSBuildThisFileDirectory)Resonite</ResonitePath>
<ResonitePath Condition="Exists('C:\Program Files (x86)\Steam\steamapps\common\Resonite\')">C:\Program Files (x86)\Steam\steamapps\common\Resonite\</ResonitePath>
<ResonitePath Condition="Exists('D:\Program Files (x86)\Steam\steamapps\common\Resonite\')">D:\Program Files (x86)\Steam\steamapps\common\Resonite\</ResonitePath>
<ResonitePath Condition="Exists('C:\SteamLibrary\steamapps\common\Resonite\')">C:\SteamLibrary\steamapps\common\Resonite\</ResonitePath>
<ResonitePath Condition="Exists('D:\SteamLibrary\steamapps\common\Resonite\')">D:\SteamLibrary\steamapps\common\Resonite\</ResonitePath>
<ResonitePath Condition="Exists('$(HOME)/.steam/steam/steamapps/common/Resonite/')">$(HOME)/.steam/steam/steamapps/common/Resonite/</ResonitePath>
<ResonitePath Condition="Exists('E:\Programs\Steam\steamapps\common\Resonite')">E:\Programs\Steam\steamapps\common\Resonite\</ResonitePath>
<ResonitePath Condition="Exists('F:\Steam\steamapps\common\Resonite')">F:\Steam\steamapps\common\Resonite\</ResonitePath>
<ResoniteCoreLibs>$(ResonitePath)\Resonite_Data\Managed</ResoniteCoreLibs>
<ResoniteNmlLibs>$(ResonitePath)\rml_libs</ResoniteNmlLibs>
<ResoniteNmlMods>$(ResonitePath)\rml_mods</ResoniteNmlMods>
<ResoniteLibs>$(ResonitePath)\Libraries</ResoniteLibs>
</PropertyGroup>
<PropertyGroup>
<ResonitePath>$(MSBuildThisFileDirectory)Resonite</ResonitePath>
<ResonitePath Condition="Exists('C:\Program Files (x86)\Steam\steamapps\common\Resonite\')">C:\Program Files (x86)\Steam\steamapps\common\Resonite\</ResonitePath>
<ResonitePath Condition="Exists('D:\Program Files (x86)\Steam\steamapps\common\Resonite\')">D:\Program Files (x86)\Steam\steamapps\common\Resonite\</ResonitePath>
<ResonitePath Condition="Exists('C:\SteamLibrary\steamapps\common\Resonite\')">C:\SteamLibrary\steamapps\common\Resonite\</ResonitePath>
<ResonitePath Condition="Exists('D:\SteamLibrary\steamapps\common\Resonite\')">D:\SteamLibrary\steamapps\common\Resonite\</ResonitePath>
<ResonitePath Condition="Exists('$(HOME)/.steam/steam/steamapps/common/Resonite/')">$(HOME)/.steam/steam/steamapps/common/Resonite/</ResonitePath>
<ResonitePath Condition="Exists('E:\Programs\Steam\steamapps\common\Resonite')">E:\Programs\Steam\steamapps\common\Resonite\</ResonitePath>
<ResonitePath Condition="Exists('F:\Steam\steamapps\common\Resonite')">F:\Steam\steamapps\common\Resonite\</ResonitePath>
<ResoniteCoreLibs>$(ResonitePath)\Resonite_Data\Managed</ResoniteCoreLibs>
<ResoniteNmlLibs>$(ResonitePath)\rml_libs</ResoniteNmlLibs>
<ResoniteNmlMods>$(ResonitePath)\rml_mods</ResoniteNmlMods>
<ResoniteLibs>$(ResonitePath)\Libraries</ResoniteLibs>
</PropertyGroup>

<ItemGroup>
<Reference Include="0Harmony">
<HintPath>$(ResoniteNmlLibs)\0Harmony.dll</HintPath>
</Reference>
<Reference Include="Elements.Assets">
<HintPath>$(ResoniteCoreLibs)\Elements.Assets.dll</HintPath>
</Reference>
<Reference Include="Elements.Core">
<HintPath>$(ResoniteCoreLibs)\Elements.Core.dll</HintPath>
</Reference>
<Reference Include="FrooxEngine">
<HintPath>$(ResoniteCoreLibs)\FrooxEngine.dll</HintPath>
</Reference>
<Reference Include="ProtoFlux.Core">
<HintPath>$(ResoniteCoreLibs)\ProtoFlux.Core.dll</HintPath>
</Reference>
<Reference Include="ProtoFlux.Nodes.FrooxEngine">
<HintPath>$(ResoniteCoreLibs)\ProtoFlux.Nodes.FrooxEngine.dll</HintPath>
</Reference>
<Reference Include="ResoniteModLoader">
<HintPath>$(ResoniteLibs)\ResoniteModLoader.dll</HintPath>
</Reference>
<Reference Include="SkyFrost.Base">
<HintPath>$(ResoniteCoreLibs)\SkyFrost.Base.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Reference Include="0Harmony">
<HintPath>$(ResoniteNmlLibs)\0Harmony.dll</HintPath>
</Reference>
<Reference Include="Elements.Assets">
<HintPath>$(ResoniteCoreLibs)\Elements.Assets.dll</HintPath>
</Reference>
<Reference Include="Elements.Core">
<HintPath>$(ResoniteCoreLibs)\Elements.Core.dll</HintPath>
</Reference>
<Reference Include="FrooxEngine">
<HintPath>$(ResoniteCoreLibs)\FrooxEngine.dll</HintPath>
</Reference>
<Reference Include="ProtoFlux.Core">
<HintPath>$(ResoniteCoreLibs)\ProtoFlux.Core.dll</HintPath>
</Reference>
<Reference Include="ProtoFlux.Nodes.FrooxEngine">
<HintPath>$(ResoniteCoreLibs)\ProtoFlux.Nodes.FrooxEngine.dll</HintPath>
</Reference>
<Reference Include="ResoniteModLoader">
<HintPath>$(ResoniteLibs)\ResoniteModLoader.dll</HintPath>
</Reference>
<Reference Include="SkyFrost.Base">
<HintPath>$(ResoniteCoreLibs)\SkyFrost.Base.dll</HintPath>
</Reference>
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>

<Target Name="CopyPluginLibrary" AfterTargets="PostBuildEvent"
Condition="Exists($(ResoniteNmlMods))">
<Exec
Command="copy &quot;$(TargetDir)\$(TargetName).dll&quot; &quot;$(ResoniteNmlMods)\&quot;" />
</Target>
<Target Name="CopyPluginLibrary" AfterTargets="PostBuildEvent"
Condition="Exists($(ResoniteNmlMods))">
<Exec
Command="copy &quot;$(TargetDir)\$(TargetName).dll&quot; &quot;$(ResoniteNmlMods)\&quot;" />
</Target>

</Project>
73 changes: 56 additions & 17 deletions dergwasm_mod/Dergwasm/ResoniteEnv.cs
Original file line number Diff line number Diff line change
@@ -182,13 +182,23 @@ public void RegisterHostFuncs()
machine.RegisterVoidHostFunc<ulong, int>("env", "slot__set_name", slot__set_name);
machine.RegisterReturningHostFunc<ulong, int>(
"env",
"value_field__bool__get_value",
value_field__bool__get_value
"slot__get_num_children",
slot__get_num_children
);
machine.RegisterVoidHostFunc<ulong, int>(
machine.RegisterReturningHostFunc<ulong, int, ulong>(
"env",
"slot__get_child",
slot__get_child
);
machine.RegisterReturningHostFunc<ulong, int, int, int, int, ulong>(
"env",
"slot__find_child_by_name",
slot__find_child_by_name
);
machine.RegisterReturningHostFunc<ulong, int, int, ulong>(
"env",
"value_field__bool__set_value",
value_field__bool__set_value
"slot__find_child_by_tag",
slot__find_child_by_tag
);
}

@@ -241,22 +251,51 @@ public void slot__set_name(Frame frame, ulong slot_id, int ptr)
slot.Name = emscriptenEnv.GetUTF8StringFromMem(ptr);
}

public void value_field__bool__set_value(Frame frame, ulong value_field_id, int value)
public int slot__get_num_children(Frame frame, ulong slot_id)
{
ValueField<bool> component =
world.ReferenceController.GetObjectOrNull(new RefID(value_field_id))
as ValueField<bool>;
if (component == null)
return;
component.Value.Value = value != 0;
Slot slot = SlotFromRefID(slot_id);
return slot?.ChildrenCount ?? 0;
}

public ulong slot__get_child(Frame frame, ulong slot_id, int index)
{
Slot slot = SlotFromRefID(slot_id);
return ((ulong?)slot?[index]?.ReferenceID) ?? 0;
}

public ulong slot__find_child_by_name(
Frame frame,
ulong slot_id,
int namePtr,
int match_substring,
int ignore_case,
int max_depth
)
{
Slot slot = SlotFromRefID(slot_id);
string name = emscriptenEnv.GetUTF8StringFromMem(namePtr);
return (
(ulong?)
slot?.FindChild(
name,
match_substring != 0,
ignore_case != 0,
max_depth
)?.ReferenceID
) ?? 0;
}

public int value_field__bool__get_value(Frame frame, ulong value_field_id)
public ulong slot__find_child_by_tag(Frame frame, ulong slot_id, int tagPtr, int max_depth)
{
ValueField<bool> component =
world.ReferenceController.GetObjectOrNull(new RefID(value_field_id))
as ValueField<bool>;
return (component?.Value?.Value ?? false) ? 1 : 0;
Slot slot = SlotFromRefID(slot_id);
string tag = emscriptenEnv.GetUTF8StringFromMem(tagPtr);
return (
(ulong?)
slot?.FindChild(
(Predicate<Slot>)(s => s.Tag == tag),
max_depth
)?.ReferenceID
) ?? 0;
}
}
}
Binary file modified firmware.wasm
Binary file not shown.
3 changes: 2 additions & 1 deletion usercmodule/resonite/micropython.mk
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
USERMODULES_DIR := $(USERMOD_DIR)

# Add all C files to SRC_USERMOD.
# SRC_USERMOD += $(USERMODULES_DIR)/resonite.c
SRC_USERMOD += $(USERMODULES_DIR)/mp_resonite.c
SRC_USERMOD += $(USERMODULES_DIR)/mp_resonite_slot_impl.c
SRC_USERMOD += $(USERMODULES_DIR)/mp_resonite_slot.c
SRC_USERMOD += $(USERMODULES_DIR)/mp_resonite_utils.c

CFLAGS_USERMOD += -I$(USERMODULES_DIR)

26 changes: 26 additions & 0 deletions usercmodule/resonite/mp_resonite.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "py/obj.h"
#include "py/runtime.h"

#include "mp_resonite_slot.h"

// Define all attributes of the module.
// Table entries are key/value pairs of the attribute name (a string)
// and the MicroPython object reference.
// All identifiers and strings are written as MP_QSTR_xxx and will be
// optimized to word-sized integers by the build system (interned strings).
STATIC const mp_rom_map_elem_t resonite_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_resonite) },
{ MP_ROM_QSTR(MP_QSTR_Slot), MP_ROM_PTR(&resonite_Slot_type) },
};
// Create a const dict named resonite_module_globals, with content resonite_module_globals_table.
STATIC MP_DEFINE_CONST_DICT(resonite_module_globals, resonite_module_globals_table);


// Define module object.
const mp_obj_module_t resonite_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&resonite_module_globals,
};

// Register the module to make it available in Python.
MP_REGISTER_MODULE(MP_QSTR_resonite, resonite_user_cmodule);
30 changes: 8 additions & 22 deletions usercmodule/resonite/mp_resonite_slot.c
Original file line number Diff line number Diff line change
@@ -11,6 +11,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(resonite_Slot_get_parent_obj, resonite_Slot_get
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(resonite_Slot_get_object_root_obj, 1, resonite_Slot_get_object_root);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(resonite_Slot_get_name_obj, resonite_Slot_get_name);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(resonite_Slot_set_name_obj, resonite_Slot_set_name);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(resonite_Slot_children_count_obj, resonite_Slot_children_count);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(resonite_Slot_get_child_obj, resonite_Slot_get_child);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(resonite_Slot_find_child_by_name_obj, 2, resonite_Slot_find_child_by_name);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(resonite_Slot_find_child_by_tag_obj, 2, resonite_Slot_find_child_by_tag);

// This collects all methods and other static class attributes of Slot.
// The table structure is similar to the module table, as detailed below.
@@ -20,6 +24,10 @@ STATIC const mp_rom_map_elem_t resonite_Slot_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_get_object_root), MP_ROM_PTR(&resonite_Slot_get_object_root_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_name), MP_ROM_PTR(&resonite_Slot_get_name_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_name), MP_ROM_PTR(&resonite_Slot_set_name_obj) },
{ MP_ROM_QSTR(MP_QSTR_children_count), MP_ROM_PTR(&resonite_Slot_children_count_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_child), MP_ROM_PTR(&resonite_Slot_get_child_obj) },
{ MP_ROM_QSTR(MP_QSTR_find_child_by_name), MP_ROM_PTR(&resonite_Slot_find_child_by_name_obj) },
{ MP_ROM_QSTR(MP_QSTR_find_child_by_tag), MP_ROM_PTR(&resonite_Slot_find_child_by_tag_obj) },
};
// Create a const dict named resonite_Slot_locals_dict, with content
// resonite_Slot_locals_dict_table.
@@ -34,25 +42,3 @@ MP_DEFINE_CONST_OBJ_TYPE(
print, resonite_Slot_print,
locals_dict, &resonite_Slot_locals_dict
);

// Define all attributes of the module.
// Table entries are key/value pairs of the attribute name (a string)
// and the MicroPython object reference.
// All identifiers and strings are written as MP_QSTR_xxx and will be
// optimized to word-sized integers by the build system (interned strings).
STATIC const mp_rom_map_elem_t resonite_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_resonite) },
{ MP_ROM_QSTR(MP_QSTR_Slot), MP_ROM_PTR(&resonite_Slot_type) },
};
// Create a const dict named resonite_module_globals, with content resonite_module_globals_table.
STATIC MP_DEFINE_CONST_DICT(resonite_module_globals, resonite_module_globals_table);


// Define module object.
const mp_obj_module_t resonite_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&resonite_module_globals,
};

// Register the module to make it available in Python.
MP_REGISTER_MODULE(MP_QSTR_resonite, resonite_user_cmodule);
16 changes: 11 additions & 5 deletions usercmodule/resonite/mp_resonite_slot.h
Original file line number Diff line number Diff line change
@@ -15,16 +15,22 @@ typedef struct _resonite_Slot_obj_t {

extern const mp_obj_type_t resonite_Slot_type;

// Utility function to create a Slot object from a reference ID.
extern mp_obj_t resonite_create_slot(resonite_slot_refid_t reference_id);
// Creates a Slot object from a reference ID.
extern mp_obj_t resonite_new_Slot(resonite_slot_refid_t reference_id);
// Creates a Slot object from a reference ID, or None if the reference ID is 0.
extern mp_obj_t resonite_new_Slot_or_none(resonite_slot_refid_t reference_id);

// This represents Slot.__init__.
extern mp_obj_t resonite_Slot_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
extern void resonite_Slot_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
extern mp_obj_t resonite_Slot_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args);
extern void resonite_Slot_print(const mp_print_t* print, mp_obj_t self_in, mp_print_kind_t kind);
extern mp_obj_t resonite_Slot_root_slot(mp_obj_t cls_in);
extern mp_obj_t resonite_Slot_get_parent(mp_obj_t self_in);
extern mp_obj_t resonite_Slot_get_object_root(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t resonite_Slot_get_object_root(size_t n_args, const mp_obj_t* pos_args, mp_map_t* kw_args);
extern mp_obj_t resonite_Slot_get_name(mp_obj_t self_in);
extern mp_obj_t resonite_Slot_set_name(mp_obj_t self_in, mp_obj_t name);
extern mp_obj_t resonite_Slot_children_count(mp_obj_t self_in);
extern mp_obj_t resonite_Slot_get_child(mp_obj_t self_in, mp_obj_t index);
extern mp_obj_t resonite_Slot_find_child_by_name(size_t n_args, const mp_obj_t* pos_args, mp_map_t* kw_args);
extern mp_obj_t resonite_Slot_find_child_by_tag(size_t n_args, const mp_obj_t* pos_args, mp_map_t* kw_args);

#endif // __RESONITE_RESONITE_SLOT_H__
92 changes: 74 additions & 18 deletions usercmodule/resonite/mp_resonite_slot_impl.c
Original file line number Diff line number Diff line change
@@ -5,52 +5,108 @@
#include "py/obj.h"
#include "py/runtime.h"
#include "resonite_slot_api.h"
#include "mp_resonite_utils.h"

mp_obj_t resonite_create_slot(resonite_slot_refid_t reference_id) {
resonite_Slot_obj_t *self = mp_obj_malloc(resonite_Slot_obj_t, &resonite_Slot_type);
mp_obj_t resonite_new_Slot_or_none(resonite_slot_refid_t reference_id) {
if (reference_id == 0) {
return mp_const_none;
}
resonite_Slot_obj_t* self = mp_obj_malloc(resonite_Slot_obj_t, &resonite_Slot_type);
self->reference_id = reference_id;
return MP_OBJ_FROM_PTR(self);
}

void resonite_Slot_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
resonite_Slot_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "Slot(ID=%ul)", self->reference_id);
mp_obj_t resonite_new_Slot(resonite_slot_refid_t reference_id) {
resonite_Slot_obj_t* self = mp_obj_malloc(resonite_Slot_obj_t, &resonite_Slot_type);
self->reference_id = reference_id;
return MP_OBJ_FROM_PTR(self);
}

mp_obj_t resonite_Slot_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
return resonite_create_slot((uint64_t)mp_obj_get_int(args[0]));
void resonite_Slot_print(const mp_print_t* print, mp_obj_t self_in, mp_print_kind_t kind) {
resonite_Slot_obj_t* self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "Slot(ID=%ul)", self->reference_id);
}

mp_obj_t resonite_Slot_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) {
mp_arg_check_num(n_args, n_kw, 1, 1, false);
if (!mp_obj_is_type(args[0], &mp_type_int)) {
mp_raise_ValueError(MP_ERROR_TEXT("Slot ID must be an int"));
}
return resonite_new_Slot(mp_obj_int_get_uint64_checked(args[0]));
}

mp_obj_t resonite_Slot_root_slot(mp_obj_t cls_in) {
return resonite_create_slot(slot__root_slot());
return resonite_new_Slot_or_none(slot__root_slot());
}

mp_obj_t resonite_Slot_get_parent(mp_obj_t self_in) {
resonite_Slot_obj_t *self = MP_OBJ_TO_PTR(self_in);
return resonite_create_slot(slot__get_parent(self->reference_id));
resonite_Slot_obj_t* self = MP_OBJ_TO_PTR(self_in);
return resonite_new_Slot_or_none(slot__get_parent(self->reference_id));
}

mp_obj_t resonite_Slot_get_object_root(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_obj_t resonite_Slot_get_object_root(size_t n_args, const mp_obj_t* pos_args, mp_map_t* kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_only_explicit, MP_ARG_BOOL, {.u_bool = false} },
};
resonite_Slot_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
{ MP_QSTR_only_explicit, MP_ARG_BOOL, {.u_bool = false} },
};
resonite_Slot_obj_t* self = MP_OBJ_TO_PTR(pos_args[0]);

mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
int only_explicit = args[0].u_bool ? 1 : 0;

return resonite_create_slot(slot__get_object_root(self->reference_id, only_explicit));
return resonite_new_Slot_or_none(slot__get_object_root(self->reference_id, only_explicit));
}

mp_obj_t resonite_Slot_get_name(mp_obj_t self_in) {
resonite_Slot_obj_t *self = MP_OBJ_TO_PTR(self_in);
char* name = slot__get_name(self->reference_id);
resonite_Slot_obj_t* self = MP_OBJ_TO_PTR(self_in);
char* name = slot__get_name(self->reference_id);
return mp_obj_new_str(name, strlen(name));
}

mp_obj_t resonite_Slot_set_name(mp_obj_t self_in, mp_obj_t name) {
resonite_Slot_obj_t *self = MP_OBJ_TO_PTR(self_in);
resonite_Slot_obj_t* self = MP_OBJ_TO_PTR(self_in);
slot__set_name(self->reference_id, mp_obj_str_get_str(name));
return mp_const_none;
}

mp_obj_t resonite_Slot_children_count(mp_obj_t self_in) {
resonite_Slot_obj_t* self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_int(slot__get_num_children(self->reference_id));
}

mp_obj_t resonite_Slot_get_child(mp_obj_t self_in, mp_obj_t index) {
resonite_Slot_obj_t* self = MP_OBJ_TO_PTR(self_in);
return resonite_new_Slot_or_none(slot__get_child(self->reference_id, mp_obj_get_int(index)));
}

mp_obj_t resonite_Slot_find_child_by_name(size_t n_args, const mp_obj_t* pos_args, mp_map_t* kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_name, MP_ARG_REQUIRED | MP_ARG_OBJ, },
{ MP_QSTR_match_substring, MP_ARG_BOOL, {.u_bool = true} },
{ MP_QSTR_ignore_case, MP_ARG_BOOL, {.u_bool = false} },
{ MP_QSTR_max_depth, MP_ARG_INT, {.u_int = -1} },
};
resonite_Slot_obj_t* self = MP_OBJ_TO_PTR(pos_args[0]);

mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
const char* name = mp_obj_str_get_str(args[0].u_obj);
int match_substring = args[1].u_bool ? 1 : 0;
int ignore_case = args[2].u_bool ? 1 : 0;
int max_depth = args[3].u_int;
return resonite_new_Slot_or_none(slot__find_child_by_name(self->reference_id, name, match_substring, ignore_case, max_depth));
}

mp_obj_t resonite_Slot_find_child_by_tag(size_t n_args, const mp_obj_t* pos_args, mp_map_t* kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_tag, MP_ARG_REQUIRED | MP_ARG_OBJ, },
{ MP_QSTR_max_depth, MP_ARG_INT, {.u_int = -1} },
};
resonite_Slot_obj_t* self = MP_OBJ_TO_PTR(pos_args[0]);

mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
const char* tag = mp_obj_str_get_str(args[0].u_obj);
int max_depth = args[1].u_int;
return resonite_new_Slot_or_none(slot__find_child_by_tag(self->reference_id, tag, max_depth));
}
82 changes: 82 additions & 0 deletions usercmodule/resonite/mp_resonite_utils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#include "mp_resonite_utils.h"

#include <math.h>
#include <stdint.h>

#include "py/obj.h"
#include "py/runtime.h"
#include "py/mpz.h"
#include "py/objint.h"
#include "py/smallint.h"

// An MPZ is stored as an array of n-bit "digits". In the WASM port, each digit is 16 bits.
// They are stored little-endian. For example, the value 0x1234567890 is stored as
// { 0x7890, 0x3456, 0x0012 }.
static bool mpz_as_int64_checked(const mpz_t* i, int64_t* value) {
uint64_t val = 0;
mpz_dig_t* d = i->dig + i->len;

while (d-- > i->dig) {
if (val > (0x7FFFFFFFFFFFFFFFULL >> MPZ_DIG_SIZE)) {
// will overflow when shifted left by MPZ_DIG_SIZE.
return false;
}
val = (val << MPZ_DIG_SIZE) | *d;
}

if (i->neg != 0) {
val = -val;
}

*value = val;
return true;
}

static bool mpz_as_uint64_checked(const mpz_t* i, uint64_t* value) {
if (i->neg != 0) {
// Can't represent negative numbers.
return false;
}

uint64_t val = 0;
mpz_dig_t* d = i->dig + i->len;

while (d-- > i->dig) {
if (val > (0x7FFFFFFFFFFFFFFFULL >> (MPZ_DIG_SIZE - 1))) {
// will overflow when shifted left by MPZ_DIG_SIZE.
return false;
}
val = (val << MPZ_DIG_SIZE) | *d;
}

*value = val;
return true;
}

int64_t mp_obj_int_get_int64_checked(mp_const_obj_t self_in) {
if (mp_obj_is_small_int(self_in)) {
return MP_OBJ_SMALL_INT_VALUE(self_in);
}
const mp_obj_int_t* self = MP_OBJ_TO_PTR(self_in);
int64_t value;
if (mpz_as_int64_checked(&self->mpz, &value)) {
return value;
}
mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("overflow converting Python int to 64-bit unsigned int"));
}

uint64_t mp_obj_int_get_uint64_checked(mp_const_obj_t self_in) {
if (mp_obj_is_small_int(self_in)) {
if (MP_OBJ_SMALL_INT_VALUE(self_in) > 0) {
return MP_OBJ_SMALL_INT_VALUE(self_in);
}
}
else {
const mp_obj_int_t* self = MP_OBJ_TO_PTR(self_in);
uint64_t value;
if (mpz_as_uint64_checked(&self->mpz, &value)) {
return value;
}
}
mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("overflow converting Python int to 64-bit signed int"));
}
13 changes: 13 additions & 0 deletions usercmodule/resonite/mp_resonite_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef __RESONITE_RESONITE_UTILS_H__
#define __RESONITE_RESONITE_UTILS_H__

#include <stdint.h>

#include "py/obj.h"
#include "py/runtime.h"
#include "resonite_api_types.h"

extern int64_t mp_obj_int_get_int64_checked(mp_const_obj_t o);
extern uint64_t mp_obj_int_get_uint64_checked(mp_const_obj_t o);

#endif // __RESONITE_RESONITE_UTILS_H__
108 changes: 108 additions & 0 deletions usercmodule/resonite/resonite.pyi
Original file line number Diff line number Diff line change
@@ -9,6 +9,64 @@ from __future__ import annotations
from collections.abc import Iterator


# These types are necessary to mirror the Resonite types. Python's type system is
# more general.
#
# Type conversion between these numerics must be explicit. For example, you cannot
# multiply an Int and a UInt -- you would have to convert the Int to a UInt, or the
# UInt to an Int.
class Int:
"""A 32-bit signed integer."""
def __init__(self, val: int):
"""
Makes a new Int instance.
Args:
val: The value.
Raises:
OverflowError: If the value cannot fit in a signed 32-bit int.
"""

class UInt:
"""A 32-bit unsigned integer."""
def __init__(self, val: int):
"""
Makes a new UInt instance.
Args:
val: The value.
Raises:
OverflowError: If the value is negative or cannot fit in an unsigned 32-bit int.
"""

class Long:
"""A 64-bit signed integer."""
def __init__(self, val: int):
"""
Makes a new Long instance.
Args:
val: The value.
Raises:
OverflowError: If the value cannot fit in a signed 64-bit int.
"""

class ULong:
"""A 64-bit unsigned integer."""
def __init__(self, val: int):
"""
Makes a new ULong instance.
Args:
val: The value.
Raises:
OverflowError: If the value is negative or cannot fit in an unsigned 64-bit int.
"""

class Slot:
"""A Slot."""
def __init__(self, reference_id: int):
@@ -197,3 +255,53 @@ class Slot:
ProtoFlux equivalent: Slots/Searching/FindParentByTag
FrooxEngine equivalent: Slot.FindParent
"""

def get_components(self) -> Iterator[Component]:
"""Returns an iterator over the components of this slot.
Warning about added and deleted components during iteration.
Warning about storing iterators across MicroPython calls.
ProtoFlux equivalent: None
FrooxEngine equivalent: Slot.Components
"""

class Component:
"""Base class for Components."""
def __init__(self, reference_id: int):
"""
Makes a new Component instance.
Args:
reference_id: The Component's ReferenceID.
"""

class ValueField[T](Component):
"""A ValueField storing a value of type T."""
def __init__(self, reference_id: int, value_type: type[T]):
"""
Makes a new ValueField instance holding a type of value_type.
We must pass the type of the value as a type hint, because
while the Python runtime may not care, C# does.
Args:
reference_id: The ValueField's ReferenceID.
value_type: The type of the value.
"""

def get_value_type(self) -> type:
"""Returns the type of the value stored in this ValueField."""

def get_value(self) -> T:
"""Returns the value of this ValueField.
ProtoFlux equivalent: ValueFields/GetValue
FrooxEngine equivalent: ValueField.Value
"""

def set_value(self, value: T) -> None:
"""Sets the value of this ValueField.
ProtoFlux equivalent: ValueFields/SetValue
FrooxEngine equivalent: ValueField.Value
"""
24 changes: 9 additions & 15 deletions usercmodule/resonite/resonite_api.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
mergeInto(LibraryManager.library, {
slot__root_slot: function () { }
});
mergeInto(LibraryManager.library, {
slot__get_parent: function () { }
});
mergeInto(LibraryManager.library, {
slot__get_object_root: function () { }
});
mergeInto(LibraryManager.library, {
slot__get_name: function () { }
});
mergeInto(LibraryManager.library, {
slot__set_name: function () { }
});
mergeInto(LibraryManager.library, { slot__root_slot: function () { } });
mergeInto(LibraryManager.library, { slot__get_parent: function () { } });
mergeInto(LibraryManager.library, { slot__get_object_root: function () { } });
mergeInto(LibraryManager.library, { slot__get_name: function () { } });
mergeInto(LibraryManager.library, { slot__set_name: function () { } });
mergeInto(LibraryManager.library, { slot__get_num_children: function () { } });
mergeInto(LibraryManager.library, { slot__get_child: function () { } });
mergeInto(LibraryManager.library, { slot__find_child_by_name: function () { } });
mergeInto(LibraryManager.library, { slot__find_child_by_tag: function () { } });
10 changes: 10 additions & 0 deletions usercmodule/resonite/resonite_slot_api.h
Original file line number Diff line number Diff line change
@@ -42,4 +42,14 @@ extern char* slot__get_name(resonite_slot_refid_t slot_id);
// Sets the name for the given slot.
extern void slot__set_name(resonite_slot_refid_t slot_id, const char* name);

extern int slot__get_num_children(resonite_slot_refid_t slot_id);

extern resonite_slot_refid_t slot__get_child(resonite_slot_refid_t slot_id, int index);

extern resonite_slot_refid_t slot__find_child_by_name(resonite_slot_refid_t slot_id,
const char* name, int match_substring, int ignore_case, int max_depth);

extern resonite_slot_refid_t slot__find_child_by_tag(resonite_slot_refid_t slot_id,
const char* tag, int max_depth);

#endif // __RESONITE_RESONITE_SLOT_API_H__

0 comments on commit 75141bc

Please sign in to comment.