diff --git a/WeaveLoaderRuntime/src/GameHooks.cpp b/WeaveLoaderRuntime/src/GameHooks.cpp index e7838bc..ac806d3 100644 --- a/WeaveLoaderRuntime/src/GameHooks.cpp +++ b/WeaveLoaderRuntime/src/GameHooks.cpp @@ -29,6 +29,8 @@ namespace GameHooks LoadUVs_fn Original_LoadUVs = nullptr; RegisterIcon_fn Original_RegisterIcon = nullptr; ItemInstanceGetIcon_fn Original_ItemInstanceGetIcon = nullptr; + EntityRendererBindTextureResource_fn Original_EntityRendererBindTextureResource = nullptr; + ItemRendererRenderItemBillboard_fn Original_ItemRendererRenderItemBillboard = nullptr; ItemInstanceMineBlock_fn Original_ItemInstanceMineBlock = nullptr; ItemMineBlock_fn Original_ItemMineBlock = nullptr; ItemMineBlock_fn Original_DiggerItemMineBlock = nullptr; @@ -71,6 +73,9 @@ namespace GameHooks static int s_textureAtlasIdBlocks = -1; static int s_textureAtlasIdItems = -1; static thread_local bool s_inLoadTextureByNameHook = false; + static thread_local bool s_hasForcedBillboardRoute = false; + static thread_local int s_forcedBillboardAtlas = -1; + static thread_local int s_forcedBillboardPage = 0; struct TextureNameArrayNative { @@ -1013,6 +1018,50 @@ namespace GameHooks return icon; } + void __fastcall Hooked_EntityRendererBindTextureResource(void* thisPtr, void* resourcePtr) + { + if (!Original_EntityRendererBindTextureResource) + return; + + const int boundAtlas = DetectAtlasTypeFromResource(resourcePtr); + if (s_hasForcedBillboardRoute && resourcePtr && boundAtlas == s_forcedBillboardAtlas && s_forcedBillboardPage > 0) + { + EnsurePageResourcesInitialized(); + const ResourceLocationNative* originalRes = + reinterpret_cast(resourcePtr); + s_pageResource.textures = originalRes->textures; + s_pageResource.path = BuildVirtualAtlasPath(s_forcedBillboardAtlas, s_forcedBillboardPage); + s_pageResource.preloaded = false; + Original_EntityRendererBindTextureResource(thisPtr, &s_pageResource); + return; + } + + Original_EntityRendererBindTextureResource(thisPtr, resourcePtr); + } + + void __fastcall Hooked_ItemRendererRenderItemBillboard(void* thisPtr, void* entitySharedPtr, void* iconPtr, int count, float a, float red, float green, float blue) + { + const bool hadForcedRoute = s_hasForcedBillboardRoute; + const int prevAtlas = s_forcedBillboardAtlas; + const int prevPage = s_forcedBillboardPage; + + int atlasType = -1; + int page = 0; + if (iconPtr && ModAtlas::TryGetIconRoute(iconPtr, atlasType, page) && page > 0) + { + s_hasForcedBillboardRoute = true; + s_forcedBillboardAtlas = atlasType; + s_forcedBillboardPage = page; + } + + if (Original_ItemRendererRenderItemBillboard) + Original_ItemRendererRenderItemBillboard(thisPtr, entitySharedPtr, iconPtr, count, a, red, green, blue); + + s_hasForcedBillboardRoute = hadForcedRoute; + s_forcedBillboardAtlas = prevAtlas; + s_forcedBillboardPage = prevPage; + } + void __fastcall Hooked_ItemInstanceMineBlock(void* thisPtr, void* level, int tile, int x, int y, int z, void* ownerSharedPtr) { s_itemMineBlockHookCalls++; diff --git a/WeaveLoaderRuntime/src/GameHooks.h b/WeaveLoaderRuntime/src/GameHooks.h index e74d626..d375a53 100644 --- a/WeaveLoaderRuntime/src/GameHooks.h +++ b/WeaveLoaderRuntime/src/GameHooks.h @@ -19,6 +19,8 @@ typedef void* (*GetResourceAsStream_fn)(const void* fileName); typedef void (__fastcall *LoadUVs_fn)(void* thisPtr); typedef void* (__fastcall *RegisterIcon_fn)(void* thisPtr, const std::wstring& name); typedef void* (__fastcall *ItemInstanceGetIcon_fn)(void* thisPtr); +typedef void (__fastcall *EntityRendererBindTextureResource_fn)(void* thisPtr, void* resourcePtr); +typedef void (__fastcall *ItemRendererRenderItemBillboard_fn)(void* thisPtr, void* entitySharedPtr, void* iconPtr, int count, float a, float red, float green, float blue); typedef void (__fastcall *ItemInstanceMineBlock_fn)(void* thisPtr, void* level, int tile, int x, int y, int z, void* ownerSharedPtr); typedef bool (__fastcall *ItemMineBlock_fn)(void* thisPtr, void* itemInstanceSharedPtr, void* level, int tile, int x, int y, int z, void* ownerSharedPtr); typedef bool (__fastcall *GameModeUseItem_fn)(void* thisPtr, void* playerSharedPtr, void* level, void* itemInstanceSharedPtr, bool bTestUseOnly); @@ -53,6 +55,8 @@ namespace GameHooks extern LoadUVs_fn Original_LoadUVs; extern RegisterIcon_fn Original_RegisterIcon; extern ItemInstanceGetIcon_fn Original_ItemInstanceGetIcon; + extern EntityRendererBindTextureResource_fn Original_EntityRendererBindTextureResource; + extern ItemRendererRenderItemBillboard_fn Original_ItemRendererRenderItemBillboard; extern ItemInstanceMineBlock_fn Original_ItemInstanceMineBlock; extern ItemMineBlock_fn Original_ItemMineBlock; extern ItemMineBlock_fn Original_DiggerItemMineBlock; @@ -80,6 +84,8 @@ namespace GameHooks void __fastcall Hooked_LoadUVs(void* thisPtr); void* __fastcall Hooked_RegisterIcon(void* thisPtr, const std::wstring& name); void* __fastcall Hooked_ItemInstanceGetIcon(void* thisPtr); + void __fastcall Hooked_EntityRendererBindTextureResource(void* thisPtr, void* resourcePtr); + void __fastcall Hooked_ItemRendererRenderItemBillboard(void* thisPtr, void* entitySharedPtr, void* iconPtr, int count, float a, float red, float green, float blue); void __fastcall Hooked_ItemInstanceMineBlock(void* thisPtr, void* level, int tile, int x, int y, int z, void* ownerSharedPtr); bool __fastcall Hooked_ItemMineBlock(void* thisPtr, void* itemInstanceSharedPtr, void* level, int tile, int x, int y, int z, void* ownerSharedPtr); bool __fastcall Hooked_DiggerItemMineBlock(void* thisPtr, void* itemInstanceSharedPtr, void* level, int tile, int x, int y, int z, void* ownerSharedPtr); diff --git a/WeaveLoaderRuntime/src/HookManager.cpp b/WeaveLoaderRuntime/src/HookManager.cpp index 76a933c..6d4102d 100644 --- a/WeaveLoaderRuntime/src/HookManager.cpp +++ b/WeaveLoaderRuntime/src/HookManager.cpp @@ -96,6 +96,34 @@ bool HookManager::Install(const SymbolResolver& symbols) } } + if (symbols.pEntityRendererBindTextureResource) + { + if (MH_CreateHook(symbols.pEntityRendererBindTextureResource, + reinterpret_cast(&GameHooks::Hooked_EntityRendererBindTextureResource), + reinterpret_cast(&GameHooks::Original_EntityRendererBindTextureResource)) != MH_OK) + { + LogUtil::Log("[WeaveLoader] Warning: Failed to hook EntityRenderer::bindTexture(ResourceLocation)"); + } + else + { + LogUtil::Log("[WeaveLoader] Hooked EntityRenderer::bindTexture(ResourceLocation) (dropped item atlas routing)"); + } + } + + if (symbols.pItemRendererRenderItemBillboard) + { + if (MH_CreateHook(symbols.pItemRendererRenderItemBillboard, + reinterpret_cast(&GameHooks::Hooked_ItemRendererRenderItemBillboard), + reinterpret_cast(&GameHooks::Original_ItemRendererRenderItemBillboard)) != MH_OK) + { + LogUtil::Log("[WeaveLoader] Warning: Failed to hook ItemRenderer::renderItemBillboard"); + } + else + { + LogUtil::Log("[WeaveLoader] Hooked ItemRenderer::renderItemBillboard (dropped item atlas routing)"); + } + } + if (symbols.pItemMineBlock) { if (MH_CreateHook(symbols.pItemMineBlock, diff --git a/WeaveLoaderRuntime/src/SymbolResolver.cpp b/WeaveLoaderRuntime/src/SymbolResolver.cpp index c055f6d..7257d74 100644 --- a/WeaveLoaderRuntime/src/SymbolResolver.cpp +++ b/WeaveLoaderRuntime/src/SymbolResolver.cpp @@ -19,6 +19,8 @@ static const char* SYM_SIMPLE_ICON_CTOR = "??0SimpleIcon@@QEAA@AEBV?$basic_strin static const char* SYM_OPERATOR_NEW = "??2@YAPEAX_K@Z"; static const char* SYM_REGISTER_ICON = "?registerIcon@PreStitchedTextureMap@@UEAAPEAVIcon@@AEBV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@@Z"; static const char* SYM_ITEMINSTANCE_GETICON = "?getIcon@ItemInstance@@QEAAPEAVIcon@@XZ"; +static const char* SYM_ENTITYRENDERER_BINDTEXTURE_RESOURCE = "?bindTexture@EntityRenderer@@MEAAXPEAVResourceLocation@@@Z"; +static const char* SYM_ITEMRENDERER_RENDERITEMBILLBOARD = "?renderItemBillboard@ItemRenderer@@EEAAXV?$shared_ptr@VItemEntity@@@std@@PEAVIcon@@HMMMM@Z"; static const char* SYM_ITEMINSTANCE_MINEBLOCK = "?mineBlock@ItemInstance@@QEAAXPEAVLevel@@HHHHV?$shared_ptr@VPlayer@@@std@@@Z"; static const char* SYM_ITEM_MINEBLOCK = "?mineBlock@Item@@UEAA_NV?$shared_ptr@VItemInstance@@@std@@PEAVLevel@@HHHHV?$shared_ptr@VLivingEntity@@@3@@Z"; static const char* SYM_DIGGERITEM_MINEBLOCK = "?mineBlock@DiggerItem@@UEAA_NV?$shared_ptr@VItemInstance@@@std@@PEAVLevel@@HHHHV?$shared_ptr@VLivingEntity@@@3@@Z"; @@ -118,6 +120,8 @@ bool SymbolResolver::ResolveGameFunctions() pOperatorNew = Resolve(SYM_OPERATOR_NEW); pRegisterIcon = Resolve(SYM_REGISTER_ICON); pItemInstanceGetIcon = Resolve(SYM_ITEMINSTANCE_GETICON); + pEntityRendererBindTextureResource = Resolve(SYM_ENTITYRENDERER_BINDTEXTURE_RESOURCE); + pItemRendererRenderItemBillboard = Resolve(SYM_ITEMRENDERER_RENDERITEMBILLBOARD); pItemInstanceMineBlock = Resolve(SYM_ITEMINSTANCE_MINEBLOCK); pItemMineBlock = Resolve(SYM_ITEM_MINEBLOCK); pDiggerItemMineBlock = Resolve(SYM_DIGGERITEM_MINEBLOCK); @@ -175,6 +179,8 @@ bool SymbolResolver::ResolveGameFunctions() logSym("operator new", pOperatorNew); logSym("registerIcon", pRegisterIcon); logSym("ItemInstance::getIcon", pItemInstanceGetIcon); + logSym("EntityRenderer::bindTexture(ResourceLocation)", pEntityRendererBindTextureResource); + logSym("ItemRenderer::renderItemBillboard", pItemRendererRenderItemBillboard); logSym("ItemInstance::mineBlock", pItemInstanceMineBlock); logSym("Item::mineBlock", pItemMineBlock); logSym("DiggerItem::mineBlock", pDiggerItemMineBlock); diff --git a/WeaveLoaderRuntime/src/SymbolResolver.h b/WeaveLoaderRuntime/src/SymbolResolver.h index 7ed40c5..8c8a92e 100644 --- a/WeaveLoaderRuntime/src/SymbolResolver.h +++ b/WeaveLoaderRuntime/src/SymbolResolver.h @@ -24,6 +24,8 @@ public: void* pOperatorNew = nullptr; // global operator new(size_t) - for texture injection void* pRegisterIcon = nullptr; // PreStitchedTextureMap::registerIcon(const wstring&) void* pItemInstanceGetIcon = nullptr; // ItemInstance::getIcon() + void* pEntityRendererBindTextureResource = nullptr; // EntityRenderer::bindTexture(ResourceLocation*) + void* pItemRendererRenderItemBillboard = nullptr; // ItemRenderer::renderItemBillboard(shared_ptr,Icon*,...) void* pItemInstanceMineBlock = nullptr; // ItemInstance::mineBlock(Level*,int,int,int,int,shared_ptr) void* pItemMineBlock = nullptr; // Item::mineBlock(shared_ptr,Level*,int,int,int,int,shared_ptr) void* pDiggerItemMineBlock = nullptr; // DiggerItem::mineBlock(shared_ptr,Level*,int,int,int,int,shared_ptr)