diff --git a/ExampleMod/ExampleMod.cs b/ExampleMod/ExampleMod.cs index a8d1097..3fb0c06 100644 --- a/ExampleMod/ExampleMod.cs +++ b/ExampleMod/ExampleMod.cs @@ -246,7 +246,8 @@ public class ExampleMod : IMod .Icon("examplemod:block/ruby_sand") .Name(Text.Translatable("block.examplemod.ruby_sand")) .RequiredTool(ToolType.Shovel) - .InCreativeTab(CreativeTab.BuildingBlocks)); + .InCreativeTab(CreativeTab.BuildingBlocks) + .Prepend()); RubyStoneSlab = (RegisteredSlabBlock)Registry.Block.Register("examplemod:ruby_stone_slab", new SlabBlock(), @@ -371,7 +372,8 @@ public class ExampleMod : IMod .AttackDamage(1.0f) .Icon("examplemod:item/ruby_hoe") .Name(Text.Translatable("item.examplemod.ruby_hoe")) - .InCreativeTab(CreativeTab.ToolsAndWeapons)); + .InCreativeTab(CreativeTab.ToolsAndWeapons) + .Prepend()); RubyWandItem = Registry.Item.Register("examplemod:ruby_wand", new RubyWand(), new ItemProperties() diff --git a/WeaveLoader.API/Block/BlockProperties.cs b/WeaveLoader.API/Block/BlockProperties.cs index e8fcae1..5e1c7bc 100644 --- a/WeaveLoader.API/Block/BlockProperties.cs +++ b/WeaveLoader.API/Block/BlockProperties.cs @@ -64,6 +64,7 @@ public class BlockProperties internal float LightEmissionValue = 0.0f; internal int LightBlockValue = 255; internal CreativeTab CreativeTabValue = CreativeTab.None; + internal CreativePlacement? CreativePlacementValue; internal Text? NameValue; internal int RequiredHarvestLevelValue = -1; internal ToolType RequiredToolValue = ToolType.None; @@ -82,6 +83,8 @@ public class BlockProperties public BlockProperties LightBlocking(int level) { LightBlockValue = level; return this; } public BlockProperties Indestructible() { HardnessValue = -1.0f; ResistanceValue = 6000000f; return this; } public BlockProperties InCreativeTab(CreativeTab tab) { CreativeTabValue = tab; return this; } + public BlockProperties CreativePlacement(CreativePlacement placement) { CreativePlacementValue = placement; return this; } + public BlockProperties Prepend() { CreativePlacementValue = global::WeaveLoader.API.CreativePlacement.Prepend(); return this; } /// Display name shown in-game (e.g. "Ruby Ore"). Used for localization. public BlockProperties Name(string displayName) { NameValue = Text.Literal(displayName); return this; } /// Localized display name using a language key (e.g. "block.examplemod.ruby_ore"). diff --git a/WeaveLoader.API/Block/BlockRegistry.cs b/WeaveLoader.API/Block/BlockRegistry.cs index 1f1af70..035ec67 100644 --- a/WeaveLoader.API/Block/BlockRegistry.cs +++ b/WeaveLoader.API/Block/BlockRegistry.cs @@ -65,14 +65,13 @@ public static class BlockRegistry properties.AcceptsRedstonePowerValue ? 1 : 0); if (numericId < 0) - throw new InvalidOperationException($"Failed to register block '{id}'. No free IDs or invalid parameters."); - - if (properties.CreativeTabValue != CreativeTab.None) { - NativeInterop.native_add_to_creative(numericId, 1, 0, (int)properties.CreativeTabValue); - Logger.Debug($"Block '{id}' added to creative tab {properties.CreativeTabValue}"); + Logger.Error($"Failed to register block '{id}'. No free IDs or invalid parameters."); + throw new InvalidOperationException($"Failed to register block '{id}'. No free IDs or invalid parameters."); } + AddToCreative(id, numericId, properties); + Logger.Debug($"Registered block '{id}' -> numeric ID {numericId}"); lock (s_lock) { @@ -104,13 +103,13 @@ public static class BlockRegistry properties.AcceptsRedstonePowerValue ? 1 : 0); if (numericId < 0) - throw new InvalidOperationException($"Failed to register managed block '{id}'."); - - if (properties.CreativeTabValue != CreativeTab.None) { - NativeInterop.native_add_to_creative(numericId, 1, 0, (int)properties.CreativeTabValue); + Logger.Error($"Failed to register managed block '{id}'."); + throw new InvalidOperationException($"Failed to register managed block '{id}'."); } + AddToCreative(id, numericId, properties); + ManagedBlockDispatcher.RegisterBlock(id, numericId, managedBlock); int dropNumericId = -1; @@ -150,13 +149,13 @@ public static class BlockRegistry properties.AcceptsRedstonePowerValue ? 1 : 0); if (numericId < 0) - throw new InvalidOperationException($"Failed to register falling block '{id}'."); - - if (properties.CreativeTabValue != CreativeTab.None) { - NativeInterop.native_add_to_creative(numericId, 1, 0, (int)properties.CreativeTabValue); + Logger.Error($"Failed to register falling block '{id}'."); + throw new InvalidOperationException($"Failed to register falling block '{id}'."); } + AddToCreative(id, numericId, properties); + if (managedBlock != null) { ManagedBlockDispatcher.RegisterBlock(id, numericId, managedBlock); @@ -198,14 +197,17 @@ public static class BlockRegistry out int doubleNumericId); if (numericId < 0) - throw new InvalidOperationException($"Failed to register slab block '{id}'."); - if (doubleNumericId < 0) - throw new InvalidOperationException($"Failed to resolve generated slab pair '{doubleId}'."); - - if (properties.CreativeTabValue != CreativeTab.None) { - NativeInterop.native_add_to_creative(numericId, 1, 0, (int)properties.CreativeTabValue); + Logger.Error($"Failed to register slab block '{id}'."); + throw new InvalidOperationException($"Failed to register slab block '{id}'."); } + if (doubleNumericId < 0) + { + Logger.Error($"Failed to resolve generated slab pair '{doubleId}'."); + throw new InvalidOperationException($"Failed to resolve generated slab pair '{doubleId}'."); + } + + AddToCreative(id, numericId, properties); lock (s_lock) { @@ -222,4 +224,59 @@ public static class BlockRegistry return s_idByNumeric.TryGetValue(numericId, out id); } } + + private static void AddToCreative(Identifier id, int numericId, BlockProperties properties) + { + if (properties.CreativeTabValue == CreativeTab.None) + { + Logger.Debug($"Block '{id}' not added to creative (CreativeTab.None)"); + return; + } + + bool added = false; + if (properties.CreativePlacementValue.HasValue) + { + CreativePlacement placement = properties.CreativePlacementValue.Value; + if (placement.Insert == CreativeInsert.Prepend) + { + try + { + NativeInterop.native_add_to_creative_ex( + numericId, 1, 0, (int)properties.CreativeTabValue, + (int)placement.Insert, -1, -1); + } + catch (DllNotFoundException e) + { + Logger.Error($"Creative add failed for block '{id}': {e.Message}. Check that WeaveLoaderRuntime is present."); + throw; + } + catch (EntryPointNotFoundException e) + { + Logger.Error($"Creative add failed for block '{id}': {e.Message}. API/runtime mismatch."); + throw; + } + added = true; + } + } + + if (!added) + { + try + { + NativeInterop.native_add_to_creative(numericId, 1, 0, (int)properties.CreativeTabValue); + } + catch (DllNotFoundException e) + { + Logger.Error($"Creative add failed for block '{id}': {e.Message}. Check that WeaveLoaderRuntime is present."); + throw; + } + catch (EntryPointNotFoundException e) + { + Logger.Error($"Creative add failed for block '{id}': {e.Message}. API/runtime mismatch."); + throw; + } + } + + Logger.Debug($"Block '{id}' added to creative tab {properties.CreativeTabValue}"); + } } diff --git a/WeaveLoader.API/CreativePlacement.cs b/WeaveLoader.API/CreativePlacement.cs new file mode 100644 index 0000000..033c5e6 --- /dev/null +++ b/WeaveLoader.API/CreativePlacement.cs @@ -0,0 +1,20 @@ +namespace WeaveLoader.API; + +public enum CreativeInsert +{ + Append = 0, + Prepend = 1 +} + +public readonly struct CreativePlacement +{ + public CreativeInsert Insert { get; } + + private CreativePlacement(CreativeInsert insert) + { + Insert = insert; + } + + public static CreativePlacement Append() => new(CreativeInsert.Append); + public static CreativePlacement Prepend() => new(CreativeInsert.Prepend); +} diff --git a/WeaveLoader.API/Item/ItemProperties.cs b/WeaveLoader.API/Item/ItemProperties.cs index 8ae34d8..294d41e 100644 --- a/WeaveLoader.API/Item/ItemProperties.cs +++ b/WeaveLoader.API/Item/ItemProperties.cs @@ -12,6 +12,7 @@ public class ItemProperties internal float AttackDamageValue = 0.0f; internal string IconValue = ""; internal CreativeTab CreativeTabValue = CreativeTab.None; + internal CreativePlacement? CreativePlacementValue; internal Text? NameValue; public ItemProperties MaxStackSize(int size) { MaxStackSizeValue = size; return this; } @@ -29,6 +30,8 @@ public class ItemProperties /// Override the native attack damage value for tool items. public ItemProperties AttackDamage(float damage) { AttackDamageValue = damage; return this; } public ItemProperties InCreativeTab(CreativeTab tab) { CreativeTabValue = tab; return this; } + public ItemProperties CreativePlacement(CreativePlacement placement) { CreativePlacementValue = placement; return this; } + public ItemProperties Prepend() { CreativePlacementValue = global::WeaveLoader.API.CreativePlacement.Prepend(); return this; } /// Display name shown in-game (e.g. "Ruby"). Used for localization. public ItemProperties Name(string displayName) { NameValue = Text.Literal(displayName); return this; } /// Localized display name using a language key (e.g. "item.examplemod.ruby"). diff --git a/WeaveLoader.API/Item/ItemRegistry.cs b/WeaveLoader.API/Item/ItemRegistry.cs index 80a5b30..fca7189 100644 --- a/WeaveLoader.API/Item/ItemRegistry.cs +++ b/WeaveLoader.API/Item/ItemRegistry.cs @@ -184,13 +184,63 @@ public static class ItemRegistry } if (numericId < 0) + { + Logger.Error($"Failed to register item '{id}'. No free IDs or invalid parameters."); throw new InvalidOperationException($"Failed to register item '{id}'. No free IDs or invalid parameters."); + } if (properties.CreativeTabValue != CreativeTab.None) { - NativeInterop.native_add_to_creative(numericId, 1, 0, (int)properties.CreativeTabValue); + bool added = false; + if (properties.CreativePlacementValue.HasValue) + { + CreativePlacement placement = properties.CreativePlacementValue.Value; + if (placement.Insert == CreativeInsert.Prepend) + { + try + { + NativeInterop.native_add_to_creative_ex( + numericId, 1, 0, (int)properties.CreativeTabValue, + (int)placement.Insert, -1, -1); + } + catch (DllNotFoundException e) + { + Logger.Error($"Creative add failed for item '{id}': {e.Message}. Check that WeaveLoaderRuntime is present."); + throw; + } + catch (EntryPointNotFoundException e) + { + Logger.Error($"Creative add failed for item '{id}': {e.Message}. API/runtime mismatch."); + throw; + } + added = true; + } + } + + if (!added) + { + try + { + NativeInterop.native_add_to_creative(numericId, 1, 0, (int)properties.CreativeTabValue); + } + catch (DllNotFoundException e) + { + Logger.Error($"Creative add failed for item '{id}': {e.Message}. Check that WeaveLoaderRuntime is present."); + throw; + } + catch (EntryPointNotFoundException e) + { + Logger.Error($"Creative add failed for item '{id}': {e.Message}. API/runtime mismatch."); + throw; + } + } + Logger.Debug($"Item '{id}' added to creative tab {properties.CreativeTabValue}"); } + else + { + Logger.Debug($"Item '{id}' not added to creative (CreativeTab.None)"); + } if (managedItem != null) { diff --git a/WeaveLoader.API/NativeInterop.cs b/WeaveLoader.API/NativeInterop.cs index 3f0c190..15e3534 100644 --- a/WeaveLoader.API/NativeInterop.cs +++ b/WeaveLoader.API/NativeInterop.cs @@ -225,6 +225,9 @@ internal static class NativeInterop [DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl)] internal static extern void native_add_to_creative(int numericId, int count, int auxValue, int groupIndex); + [DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void native_add_to_creative_ex(int numericId, int count, int auxValue, int groupIndex, int insertMode, int anchorId, int anchorAux); + [DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] internal static extern nint native_find_symbol(string fullName); diff --git a/WeaveLoaderRuntime/src/CreativeInventory.cpp b/WeaveLoaderRuntime/src/CreativeInventory.cpp index 89143b2..fa5f1b8 100644 --- a/WeaveLoaderRuntime/src/CreativeInventory.cpp +++ b/WeaveLoaderRuntime/src/CreativeInventory.cpp @@ -16,6 +16,7 @@ void* pSpecs = nullptr; std::vector s_pendingItems; static bool s_didInjectItems = false; +static bool s_creativeReady = false; static const int CREATIVE_GROUP_COUNT = 15; static const int SIZEOF_MSVC_VECTOR = 24; @@ -49,8 +50,27 @@ typedef void (__fastcall *VectorPushBackMove_fn)(void* vectorThis, void* sharedP void AddPending(int itemId, int count, int auxValue, int groupIndex) { - s_pendingItems.push_back({ itemId, count, auxValue, groupIndex }); - LogUtil::Log("[WeaveLoader] Queued creative item: id=%d group=%d", itemId, groupIndex); + AddPendingEx(itemId, count, auxValue, groupIndex, InsertAppend, -1, -1); +} + +void AddPendingEx(int itemId, int count, int auxValue, int groupIndex, int insertMode, int anchorId, int anchorAux) +{ + (void)anchorId; + (void)anchorAux; + s_pendingItems.push_back({ itemId, count, auxValue, groupIndex, insertMode }); + LogUtil::Log("[WeaveLoader] Queued creative item: id=%d group=%d mode=%d", + itemId, groupIndex, insertMode); + + if (s_creativeReady) + { + InjectItems(); + UpdateTabPageCounts(); + } +} + +void SetCreativeReady() +{ + s_creativeReady = true; } bool ResolveSymbols(SymbolResolver& resolver) @@ -90,7 +110,7 @@ bool ResolveSymbols(SymbolResolver& resolver) PdbParser::DumpMatching("specs@IUIScene_CreativeMenu"); } - return pCategoryGroups && pItemInstanceCtor && pSharedPtrCtor && pVectorPushBack; + return pCategoryGroups && pItemInstanceCtor && pSharedPtrCtor; } static size_t ReadVectorSize(char* vec) @@ -101,6 +121,102 @@ static size_t ReadVectorSize(char* vec) return static_cast((last - first) / SIZEOF_MSVC_SHARED_PTR); } +static char* VectorBegin(char* vec) { return *reinterpret_cast(vec); } +static char* VectorEnd(char* vec) { return *reinterpret_cast(vec + 8); } +static char* VectorCap(char* vec) { return *reinterpret_cast(vec + 16); } + +static void SetVectorPointers(char* vec, char* begin, char* end, char* cap) +{ + *reinterpret_cast(vec) = begin; + *reinterpret_cast(vec + 8) = end; + *reinterpret_cast(vec + 16) = cap; +} + +static bool EnsureVectorCapacity(char* vec, size_t desiredCount) +{ + char* begin = VectorBegin(vec); + char* end = VectorEnd(vec); + char* cap = VectorCap(vec); + size_t size = begin ? static_cast((end - begin) / SIZEOF_MSVC_SHARED_PTR) : 0; + size_t capacity = begin ? static_cast((cap - begin) / SIZEOF_MSVC_SHARED_PTR) : 0; + + if (capacity >= desiredCount) + return true; + + size_t newCap = capacity ? capacity * 2 : 4; + if (newCap < desiredCount) + newCap = desiredCount; + + char* newBuf = reinterpret_cast(::operator new(newCap * SIZEOF_MSVC_SHARED_PTR)); + if (!newBuf) + return false; + + if (begin && size > 0) + memcpy(newBuf, begin, size * SIZEOF_MSVC_SHARED_PTR); + + if (begin) + ::operator delete(begin); + + SetVectorPointers(vec, newBuf, newBuf + size * SIZEOF_MSVC_SHARED_PTR, newBuf + newCap * SIZEOF_MSVC_SHARED_PTR); + return true; +} + +static bool InsertSharedPtrAt(char* vec, const void* sharedPtrBuf, size_t index) +{ + size_t size = ReadVectorSize(vec); + if (index > size) index = size; + + if (!EnsureVectorCapacity(vec, size + 1)) + return false; + + char* begin = VectorBegin(vec); + char* end = VectorEnd(vec); + char* insertPos = begin + index * SIZEOF_MSVC_SHARED_PTR; + size_t tailBytes = static_cast(end - insertPos); + memmove(insertPos + SIZEOF_MSVC_SHARED_PTR, insertPos, tailBytes); + memcpy(insertPos, sharedPtrBuf, SIZEOF_MSVC_SHARED_PTR); + SetVectorPointers(vec, begin, end + SIZEOF_MSVC_SHARED_PTR, VectorCap(vec)); + return true; +} + +static bool InsertItemInstance(char* vec, const PendingCreativeItem& item, size_t insertIndex, + ItemInstanceCtor_fn ctorFn, SharedPtrCtor_fn spCtorFn) +{ + size_t sizeBefore = ReadVectorSize(vec); + + void* rawItem = ::operator new(ITEMINSTANCE_ALLOC_SIZE); + memset(rawItem, 0, ITEMINSTANCE_ALLOC_SIZE); + ctorFn(rawItem, item.itemId, item.count, item.auxValue); + + // Verify ItemInstance vtable was set (first 8 bytes should be non-null) + void* vtable = *reinterpret_cast(rawItem); + LogUtil::Log("[WeaveLoader] ItemInstance(%d,%d,%d) @ %p, vtable=%p", + item.itemId, item.count, item.auxValue, rawItem, vtable); + + char spBuf[16]; + memset(spBuf, 0, sizeof(spBuf)); + spCtorFn(spBuf, rawItem); + + // Log shared_ptr contents (ptr + control block) + void* spPtr = *reinterpret_cast(spBuf); + void* spCtrl = *reinterpret_cast(spBuf + 8); + LogUtil::Log("[WeaveLoader] shared_ptr: ptr=%p ctrl=%p", spPtr, spCtrl); + + bool inserted = InsertSharedPtrAt(vec, spBuf, insertIndex); + size_t sizeAfter = ReadVectorSize(vec); + if (!inserted) + { + LogUtil::Log("[WeaveLoader] Failed to insert creative item id=%d into group %d", + item.itemId, item.groupIndex); + return false; + } + + LogUtil::Log("[WeaveLoader] Injected item id=%d into creative group %d " + "(vector @ %p, size: %zu -> %zu, index=%zu)", + item.itemId, item.groupIndex, vec, sizeBefore, sizeAfter, insertIndex); + return true; +} + void UpdateTabPageCounts() { if (!s_didInjectItems) @@ -163,7 +279,7 @@ void UpdateTabPageCounts() void InjectItems() { - if (!pCategoryGroups || !pItemInstanceCtor || !pSharedPtrCtor || !pVectorPushBack) + if (!pCategoryGroups || !pItemInstanceCtor || !pSharedPtrCtor) { LogUtil::Log("[WeaveLoader] Cannot inject creative items: missing symbols"); return; @@ -171,20 +287,21 @@ void InjectItems() if (s_pendingItems.empty()) { - LogUtil::Log("[WeaveLoader] No creative items to inject"); - s_didInjectItems = false; + if (s_didInjectItems) + LogUtil::Log("[WeaveLoader] No creative items to inject (pending empty; already injected)"); + else + LogUtil::Log("[WeaveLoader] No creative items to inject (none queued)"); return; } s_didInjectItems = true; auto ctorFn = reinterpret_cast(pItemInstanceCtor); auto spCtorFn = reinterpret_cast(pSharedPtrCtor); - auto pushFn = reinterpret_cast(pVectorPushBack); - // categoryGroups is a static array of vectors (vector<...> categoryGroups[15]). // pCategoryGroups is the address of the first vector; no dereference needed. char* groups = reinterpret_cast(pCategoryGroups); + std::vector grouped[CREATIVE_GROUP_COUNT]; for (auto& item : s_pendingItems) { if (item.groupIndex < 0 || item.groupIndex >= CREATIVE_GROUP_COUNT) @@ -193,37 +310,36 @@ void InjectItems() item.itemId, item.groupIndex); continue; } - - void* rawItem = ::operator new(ITEMINSTANCE_ALLOC_SIZE); - memset(rawItem, 0, ITEMINSTANCE_ALLOC_SIZE); - ctorFn(rawItem, item.itemId, item.count, item.auxValue); - - // Verify ItemInstance vtable was set (first 8 bytes should be non-null) - void* vtable = *reinterpret_cast(rawItem); - LogUtil::Log("[WeaveLoader] ItemInstance(%d,%d,%d) @ %p, vtable=%p", - item.itemId, item.count, item.auxValue, rawItem, vtable); - - char spBuf[16]; - memset(spBuf, 0, sizeof(spBuf)); - spCtorFn(spBuf, rawItem); - - // Log shared_ptr contents (ptr + control block) - void* spPtr = *reinterpret_cast(spBuf); - void* spCtrl = *reinterpret_cast(spBuf + 8); - LogUtil::Log("[WeaveLoader] shared_ptr: ptr=%p ctrl=%p", spPtr, spCtrl); - - char* vec = groups + item.groupIndex * SIZEOF_MSVC_VECTOR; - size_t sizeBefore = ReadVectorSize(vec); - - pushFn(vec, spBuf); - - size_t sizeAfter = ReadVectorSize(vec); - LogUtil::Log("[WeaveLoader] Injected item id=%d into creative group %d " - "(vector @ %p, size: %zu -> %zu)", - item.itemId, item.groupIndex, vec, sizeBefore, sizeAfter); + grouped[item.groupIndex].push_back(item); } - LogUtil::Log("[WeaveLoader] Injected %zu items into creative inventory", s_pendingItems.size()); + size_t injectedCount = 0; + for (int groupIndex = 0; groupIndex < CREATIVE_GROUP_COUNT; ++groupIndex) + { + auto& pending = grouped[groupIndex]; + if (pending.empty()) + continue; + + char* vec = groups + groupIndex * SIZEOF_MSVC_VECTOR; + size_t prependIndex = 0; + for (auto& item : pending) + { + size_t insertIndex = ReadVectorSize(vec); + if (item.insertMode == InsertPrepend) + { + insertIndex = prependIndex; + ++prependIndex; + } + + if (InsertItemInstance(vec, item, insertIndex, ctorFn, spCtorFn)) + ++injectedCount; + else + LogUtil::Log("[WeaveLoader] Failed to insert creative item id=%d in group %d", + item.itemId, groupIndex); + } + } + + LogUtil::Log("[WeaveLoader] Injected %zu items into creative inventory", injectedCount); s_pendingItems.clear(); } diff --git a/WeaveLoaderRuntime/src/CreativeInventory.h b/WeaveLoaderRuntime/src/CreativeInventory.h index 190a70b..bfadfea 100644 --- a/WeaveLoaderRuntime/src/CreativeInventory.h +++ b/WeaveLoaderRuntime/src/CreativeInventory.h @@ -9,11 +9,22 @@ struct PendingCreativeItem int count; int auxValue; int groupIndex; + int insertMode; }; namespace CreativeInventory { + enum InsertMode + { + InsertAppend = 0, + InsertPrepend = 1, + InsertBefore = 2, + InsertAfter = 3 + }; + void AddPending(int itemId, int count, int auxValue, int groupIndex); + void AddPendingEx(int itemId, int count, int auxValue, int groupIndex, int insertMode, int anchorId, int anchorAux); + void SetCreativeReady(); bool ResolveSymbols(SymbolResolver& resolver); void InjectItems(); void UpdateTabPageCounts(); diff --git a/WeaveLoaderRuntime/src/GameHooks.cpp b/WeaveLoaderRuntime/src/GameHooks.cpp index 330a23a..e4cb096 100644 --- a/WeaveLoaderRuntime/src/GameHooks.cpp +++ b/WeaveLoaderRuntime/src/GameHooks.cpp @@ -2637,6 +2637,7 @@ namespace GameHooks { LogUtil::Log("[WeaveLoader] Hook: CreativeStaticCtor -- building vanilla creative lists"); Original_CreativeStaticCtor(); + CreativeInventory::SetCreativeReady(); // Inject AFTER vanilla lists so modded entries are appended to the end // of each creative category. diff --git a/WeaveLoaderRuntime/src/NativeExports.cpp b/WeaveLoaderRuntime/src/NativeExports.cpp index cd2e3f3..26526bc 100644 --- a/WeaveLoaderRuntime/src/NativeExports.cpp +++ b/WeaveLoaderRuntime/src/NativeExports.cpp @@ -772,6 +772,11 @@ void native_add_to_creative(int numericId, int count, int auxValue, int groupInd CreativeInventory::AddPending(numericId, count, auxValue, groupIndex); } +void native_add_to_creative_ex(int numericId, int count, int auxValue, int groupIndex, int insertMode, int anchorId, int anchorAux) +{ + CreativeInventory::AddPendingEx(numericId, count, auxValue, groupIndex, insertMode, anchorId, anchorAux); +} + void* native_find_symbol(const char* fullName) { return SymbolRegistry::Instance().FindAddress(fullName); diff --git a/WeaveLoaderRuntime/src/NativeExports.h b/WeaveLoaderRuntime/src/NativeExports.h index f194628..c144c9b 100644 --- a/WeaveLoaderRuntime/src/NativeExports.h +++ b/WeaveLoaderRuntime/src/NativeExports.h @@ -193,6 +193,14 @@ extern "C" int count, int auxValue, int groupIndex); + __declspec(dllexport) void native_add_to_creative_ex( + int numericId, + int count, + int auxValue, + int groupIndex, + int insertMode, + int anchorId, + int anchorAux); __declspec(dllexport) void* native_find_symbol(const char* fullName); __declspec(dllexport) int native_has_symbol(const char* fullName);