From 4119522cdef99ea94990319eccc730092a7aa519 Mon Sep 17 00:00:00 2001 From: Jacobwasbeast Date: Sat, 7 Mar 2026 02:55:24 -0600 Subject: [PATCH] Add runtime furnace recipe registration support --- WeaveLoaderRuntime/CMakeLists.txt | 1 + .../src/FurnaceRecipeRegistry.cpp | 76 +++++++++++++++++++ .../src/FurnaceRecipeRegistry.h | 9 +++ WeaveLoaderRuntime/src/HookManager.cpp | 2 + WeaveLoaderRuntime/src/NativeExports.cpp | 38 +++++++++- 5 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 WeaveLoaderRuntime/src/FurnaceRecipeRegistry.cpp create mode 100644 WeaveLoaderRuntime/src/FurnaceRecipeRegistry.h diff --git a/WeaveLoaderRuntime/CMakeLists.txt b/WeaveLoaderRuntime/CMakeLists.txt index 3f96f2c..25c8b3b 100644 --- a/WeaveLoaderRuntime/CMakeLists.txt +++ b/WeaveLoaderRuntime/CMakeLists.txt @@ -88,6 +88,7 @@ add_library(WeaveLoaderRuntime SHARED src/IdRegistry.cpp src/NativeExports.cpp src/CreativeInventory.cpp + src/FurnaceRecipeRegistry.cpp src/MainMenuOverlay.cpp src/GameObjectFactory.cpp src/ModStrings.cpp diff --git a/WeaveLoaderRuntime/src/FurnaceRecipeRegistry.cpp b/WeaveLoaderRuntime/src/FurnaceRecipeRegistry.cpp new file mode 100644 index 0000000..a879768 --- /dev/null +++ b/WeaveLoaderRuntime/src/FurnaceRecipeRegistry.cpp @@ -0,0 +1,76 @@ +#include "FurnaceRecipeRegistry.h" +#include "SymbolResolver.h" +#include "PdbParser.h" +#include "LogUtil.h" +#include +#include + +namespace FurnaceRecipeRegistry +{ + +typedef void (__fastcall *ItemInstanceCtor_fn)(void* thisPtr, int id, int count, int auxValue); + +struct FurnaceRecipesLayout +{ + std::unordered_map recipies; + std::unordered_map recipeValue; +}; + +static void** s_furnaceInstanceAddr = nullptr; +static ItemInstanceCtor_fn s_itemInstanceCtor = nullptr; + +static const int ITEMINSTANCE_ALLOC_SIZE = 256; + +bool ResolveSymbols(SymbolResolver& resolver) +{ + s_furnaceInstanceAddr = reinterpret_cast( + resolver.Resolve("?instance@FurnaceRecipes@@0PEAV1@EA")); + + s_itemInstanceCtor = reinterpret_cast( + resolver.Resolve("??0ItemInstance@@QEAA@HHH@Z")); + + if (!s_furnaceInstanceAddr) PdbParser::DumpMatching("instance@FurnaceRecipes"); + if (!s_itemInstanceCtor) PdbParser::DumpMatching("??0ItemInstance@@QEAA@HHH@Z"); + + if (s_furnaceInstanceAddr) + LogUtil::Log("[WeaveLoader] FurnaceRecipes::instance addr @ %p", s_furnaceInstanceAddr); + else + LogUtil::Log("[WeaveLoader] MISSING: FurnaceRecipes::instance addr"); + + if (s_itemInstanceCtor) + LogUtil::Log("[WeaveLoader] ItemInstance::ItemInstance(int,int,int) @ %p", reinterpret_cast(s_itemInstanceCtor)); + else + LogUtil::Log("[WeaveLoader] MISSING: ItemInstance::ItemInstance(int,int,int)"); + + return s_furnaceInstanceAddr && s_itemInstanceCtor; +} + +bool AddRecipe(int inputId, int outputId, float xp) +{ + if (!s_furnaceInstanceAddr || !s_itemInstanceCtor) + { + LogUtil::Log("[WeaveLoader] Cannot add furnace recipe: symbols not resolved"); + return false; + } + + void* instance = *s_furnaceInstanceAddr; + if (!instance) + { + LogUtil::Log("[WeaveLoader] Cannot add furnace recipe: FurnaceRecipes::instance is null"); + return false; + } + + void* resultItem = ::operator new(ITEMINSTANCE_ALLOC_SIZE); + memset(resultItem, 0, ITEMINSTANCE_ALLOC_SIZE); + s_itemInstanceCtor(resultItem, outputId, 1, 0); + + auto* recipes = reinterpret_cast(instance); + recipes->recipies[inputId] = resultItem; + recipes->recipeValue[outputId] = xp; + + LogUtil::Log("[WeaveLoader] Added furnace recipe to vanilla table: %d -> %d (%.1f xp)", + inputId, outputId, xp); + return true; +} + +} // namespace FurnaceRecipeRegistry diff --git a/WeaveLoaderRuntime/src/FurnaceRecipeRegistry.h b/WeaveLoaderRuntime/src/FurnaceRecipeRegistry.h new file mode 100644 index 0000000..e1911bd --- /dev/null +++ b/WeaveLoaderRuntime/src/FurnaceRecipeRegistry.h @@ -0,0 +1,9 @@ +#pragma once + +class SymbolResolver; + +namespace FurnaceRecipeRegistry +{ + bool ResolveSymbols(SymbolResolver& resolver); + bool AddRecipe(int inputId, int outputId, float xp); +} diff --git a/WeaveLoaderRuntime/src/HookManager.cpp b/WeaveLoaderRuntime/src/HookManager.cpp index c5cd9ff..8ce65c8 100644 --- a/WeaveLoaderRuntime/src/HookManager.cpp +++ b/WeaveLoaderRuntime/src/HookManager.cpp @@ -6,6 +6,7 @@ #include "CreativeInventory.h" #include "MainMenuOverlay.h" #include "GameObjectFactory.h" +#include "FurnaceRecipeRegistry.h" #include "LogUtil.h" #include @@ -68,6 +69,7 @@ bool HookManager::Install(const SymbolResolver& symbols) } GameObjectFactory::ResolveSymbols(const_cast(symbols)); + FurnaceRecipeRegistry::ResolveSymbols(const_cast(symbols)); if (symbols.pLoadUVs && symbols.pSimpleIconCtor && symbols.pOperatorNew) { diff --git a/WeaveLoaderRuntime/src/NativeExports.cpp b/WeaveLoaderRuntime/src/NativeExports.cpp index e4b655e..0cf748a 100644 --- a/WeaveLoaderRuntime/src/NativeExports.cpp +++ b/WeaveLoaderRuntime/src/NativeExports.cpp @@ -2,6 +2,7 @@ #include "IdRegistry.h" #include "CreativeInventory.h" #include "GameObjectFactory.h" +#include "FurnaceRecipeRegistry.h" #include "ModStrings.h" #include "LogUtil.h" #include @@ -18,6 +19,19 @@ static std::wstring Utf8ToWide(const char* utf8) return result; } +static int ResolveRecipeId(const char* namespacedId, bool preferItem) +{ + if (!namespacedId || !namespacedId[0]) return -1; + + int itemId = IdRegistry::Instance().GetNumericId(IdRegistry::Type::Item, namespacedId); + int blockId = IdRegistry::Instance().GetNumericId(IdRegistry::Type::Block, namespacedId); + + if (preferItem) + return (itemId >= 0) ? itemId : blockId; + + return (blockId >= 0) ? blockId : itemId; +} + extern "C" { @@ -147,7 +161,29 @@ void native_add_furnace_recipe( const char* outputId, float xp) { - LogUtil::Log("[WeaveLoader] Added furnace recipe: %s -> %s (%.1f xp)", inputId, outputId, xp); + int inputNumeric = ResolveRecipeId(inputId, false); + int outputNumeric = ResolveRecipeId(outputId, true); + + if (inputNumeric < 0) + { + LogUtil::Log("[WeaveLoader] Failed furnace recipe: unknown input '%s'", inputId ? inputId : "(null)"); + return; + } + + if (outputNumeric < 0) + { + LogUtil::Log("[WeaveLoader] Failed furnace recipe: unknown output '%s'", outputId ? outputId : "(null)"); + return; + } + + if (!FurnaceRecipeRegistry::AddRecipe(inputNumeric, outputNumeric, xp)) + { + LogUtil::Log("[WeaveLoader] Failed furnace recipe: %s -> %s (%.1f xp)", inputId, outputId, xp); + return; + } + + LogUtil::Log("[WeaveLoader] Added furnace recipe: %s[%d] -> %s[%d] (%.1f xp)", + inputId, inputNumeric, outputId, outputNumeric, xp); } void native_log(const char* message, int level)