diff --git a/WeaveLoaderRuntime/src/CrashHandler.cpp b/WeaveLoaderRuntime/src/CrashHandler.cpp index d03a461..cbf6fb2 100644 --- a/WeaveLoaderRuntime/src/CrashHandler.cpp +++ b/WeaveLoaderRuntime/src/CrashHandler.cpp @@ -88,6 +88,24 @@ static bool IsFatalException(DWORD code) } } +static bool ShouldWriteVectoredReport(EXCEPTION_RECORD* er) +{ + if (!er) + return false; + + switch (er->ExceptionCode) + { + case STATUS_STACK_BUFFER_OVERRUN: + case STATUS_INVALID_CRUNTIME_PARAMETER: + case STATUS_FAIL_FAST_EXCEPTION: + case EXCEPTION_STACK_OVERFLOW: + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + return true; + default: + return false; + } +} + static void GetModuleForAddr(DWORD64 addr, char* nameBuf, size_t nameBufSize, DWORD64* outBase) { *outBase = 0; @@ -353,7 +371,16 @@ static LONG WINAPI VectoredHandler(EXCEPTION_POINTERS* ep) if (!IsFatalException(code)) return EXCEPTION_CONTINUE_SEARCH; - WriteCrashReport("VectoredExceptionHandler", ep->ExceptionRecord, ep->ContextRecord); + // TODO: Remove this suppression once the animated texture pack fault is fixed + // at the source. For now, a vectored handler sees first-chance exceptions + // before local __try/__except blocks run, and logging those handled faults + // as crashes causes severe log spam and stalls under Windows. + // + // Keep vectored reporting only for fail-fast/noncontinuable cases that will + // not normally make it to the top-level unhandled filter. + if (ShouldWriteVectoredReport(ep->ExceptionRecord)) + WriteCrashReport("VectoredExceptionHandler", ep->ExceptionRecord, ep->ContextRecord); + return EXCEPTION_CONTINUE_SEARCH; } diff --git a/WeaveLoaderRuntime/src/GameHooks.cpp b/WeaveLoaderRuntime/src/GameHooks.cpp index ac806d3..67e0c0c 100644 --- a/WeaveLoaderRuntime/src/GameHooks.cpp +++ b/WeaveLoaderRuntime/src/GameHooks.cpp @@ -31,6 +31,12 @@ namespace GameHooks ItemInstanceGetIcon_fn Original_ItemInstanceGetIcon = nullptr; EntityRendererBindTextureResource_fn Original_EntityRendererBindTextureResource = nullptr; ItemRendererRenderItemBillboard_fn Original_ItemRendererRenderItemBillboard = nullptr; + AnimatedTextureCycleFrames_fn Original_CompassTextureCycleFrames = nullptr; + AnimatedTextureCycleFrames_fn Original_ClockTextureCycleFrames = nullptr; + TextureGetSourceDim_fn Original_CompassTextureGetSourceWidth = nullptr; + TextureGetSourceDim_fn Original_CompassTextureGetSourceHeight = nullptr; + TextureGetSourceDim_fn Original_ClockTextureGetSourceWidth = nullptr; + TextureGetSourceDim_fn Original_ClockTextureGetSourceHeight = nullptr; ItemInstanceMineBlock_fn Original_ItemInstanceMineBlock = nullptr; ItemMineBlock_fn Original_ItemMineBlock = nullptr; ItemMineBlock_fn Original_DiggerItemMineBlock = nullptr; @@ -76,6 +82,7 @@ namespace GameHooks static thread_local bool s_hasForcedBillboardRoute = false; static thread_local int s_forcedBillboardAtlas = -1; static thread_local int s_forcedBillboardPage = 0; + static int s_animatedTextureGuardLogCount = 0; struct TextureNameArrayNative { @@ -1062,6 +1069,102 @@ namespace GameHooks s_forcedBillboardPage = prevPage; } + static void LogAnimatedTextureGuard(const char* what, void* thisPtr) + { + if (s_animatedTextureGuardLogCount >= 12) + return; + LogUtil::Log("[WeaveLoader] AnimatedTextureGuard: %s fallback for %p", what, thisPtr); + s_animatedTextureGuardLogCount++; + } + + void __fastcall Hooked_CompassTextureCycleFrames(void* thisPtr) + { + if (!Original_CompassTextureCycleFrames) + return; + __try + { + Original_CompassTextureCycleFrames(thisPtr); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + LogAnimatedTextureGuard("CompassTexture::cycleFrames", thisPtr); + } + } + + void __fastcall Hooked_ClockTextureCycleFrames(void* thisPtr) + { + if (!Original_ClockTextureCycleFrames) + return; + __try + { + Original_ClockTextureCycleFrames(thisPtr); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + LogAnimatedTextureGuard("ClockTexture::cycleFrames", thisPtr); + } + } + + int __fastcall Hooked_CompassTextureGetSourceWidth(void* thisPtr) + { + if (!Original_CompassTextureGetSourceWidth) + return 16; + __try + { + return Original_CompassTextureGetSourceWidth(thisPtr); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + LogAnimatedTextureGuard("CompassTexture::getSourceWidth", thisPtr); + return 16; + } + } + + int __fastcall Hooked_CompassTextureGetSourceHeight(void* thisPtr) + { + if (!Original_CompassTextureGetSourceHeight) + return 16; + __try + { + return Original_CompassTextureGetSourceHeight(thisPtr); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + LogAnimatedTextureGuard("CompassTexture::getSourceHeight", thisPtr); + return 16; + } + } + + int __fastcall Hooked_ClockTextureGetSourceWidth(void* thisPtr) + { + if (!Original_ClockTextureGetSourceWidth) + return 16; + __try + { + return Original_ClockTextureGetSourceWidth(thisPtr); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + LogAnimatedTextureGuard("ClockTexture::getSourceWidth", thisPtr); + return 16; + } + } + + int __fastcall Hooked_ClockTextureGetSourceHeight(void* thisPtr) + { + if (!Original_ClockTextureGetSourceHeight) + return 16; + __try + { + return Original_ClockTextureGetSourceHeight(thisPtr); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + LogAnimatedTextureGuard("ClockTexture::getSourceHeight", thisPtr); + return 16; + } + } + 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 d375a53..d37668e 100644 --- a/WeaveLoaderRuntime/src/GameHooks.h +++ b/WeaveLoaderRuntime/src/GameHooks.h @@ -21,6 +21,8 @@ typedef void* (__fastcall *RegisterIcon_fn)(void* thisPtr, const std::wstring& n 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 *AnimatedTextureCycleFrames_fn)(void* thisPtr); +typedef int (__fastcall *TextureGetSourceDim_fn)(void* thisPtr); 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); @@ -57,6 +59,12 @@ namespace GameHooks extern ItemInstanceGetIcon_fn Original_ItemInstanceGetIcon; extern EntityRendererBindTextureResource_fn Original_EntityRendererBindTextureResource; extern ItemRendererRenderItemBillboard_fn Original_ItemRendererRenderItemBillboard; + extern AnimatedTextureCycleFrames_fn Original_CompassTextureCycleFrames; + extern AnimatedTextureCycleFrames_fn Original_ClockTextureCycleFrames; + extern TextureGetSourceDim_fn Original_CompassTextureGetSourceWidth; + extern TextureGetSourceDim_fn Original_CompassTextureGetSourceHeight; + extern TextureGetSourceDim_fn Original_ClockTextureGetSourceWidth; + extern TextureGetSourceDim_fn Original_ClockTextureGetSourceHeight; extern ItemInstanceMineBlock_fn Original_ItemInstanceMineBlock; extern ItemMineBlock_fn Original_ItemMineBlock; extern ItemMineBlock_fn Original_DiggerItemMineBlock; @@ -86,6 +94,12 @@ namespace GameHooks 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_CompassTextureCycleFrames(void* thisPtr); + void __fastcall Hooked_ClockTextureCycleFrames(void* thisPtr); + int __fastcall Hooked_CompassTextureGetSourceWidth(void* thisPtr); + int __fastcall Hooked_CompassTextureGetSourceHeight(void* thisPtr); + int __fastcall Hooked_ClockTextureGetSourceWidth(void* thisPtr); + int __fastcall Hooked_ClockTextureGetSourceHeight(void* thisPtr); 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 6d4102d..f8c5a01 100644 --- a/WeaveLoaderRuntime/src/HookManager.cpp +++ b/WeaveLoaderRuntime/src/HookManager.cpp @@ -124,6 +124,90 @@ bool HookManager::Install(const SymbolResolver& symbols) } } + if (symbols.pCompassTextureCycleFrames) + { + if (MH_CreateHook(symbols.pCompassTextureCycleFrames, + reinterpret_cast(&GameHooks::Hooked_CompassTextureCycleFrames), + reinterpret_cast(&GameHooks::Original_CompassTextureCycleFrames)) != MH_OK) + { + LogUtil::Log("[WeaveLoader] Warning: Failed to hook CompassTexture::cycleFrames"); + } + else + { + LogUtil::Log("[WeaveLoader] Hooked CompassTexture::cycleFrames (texture pack crash guard)"); + } + } + + if (symbols.pClockTextureCycleFrames) + { + if (MH_CreateHook(symbols.pClockTextureCycleFrames, + reinterpret_cast(&GameHooks::Hooked_ClockTextureCycleFrames), + reinterpret_cast(&GameHooks::Original_ClockTextureCycleFrames)) != MH_OK) + { + LogUtil::Log("[WeaveLoader] Warning: Failed to hook ClockTexture::cycleFrames"); + } + else + { + LogUtil::Log("[WeaveLoader] Hooked ClockTexture::cycleFrames (texture pack crash guard)"); + } + } + + if (symbols.pCompassTextureGetSourceWidth) + { + if (MH_CreateHook(symbols.pCompassTextureGetSourceWidth, + reinterpret_cast(&GameHooks::Hooked_CompassTextureGetSourceWidth), + reinterpret_cast(&GameHooks::Original_CompassTextureGetSourceWidth)) != MH_OK) + { + LogUtil::Log("[WeaveLoader] Warning: Failed to hook CompassTexture::getSourceWidth"); + } + else + { + LogUtil::Log("[WeaveLoader] Hooked CompassTexture::getSourceWidth (texture pack crash guard)"); + } + } + + if (symbols.pCompassTextureGetSourceHeight) + { + if (MH_CreateHook(symbols.pCompassTextureGetSourceHeight, + reinterpret_cast(&GameHooks::Hooked_CompassTextureGetSourceHeight), + reinterpret_cast(&GameHooks::Original_CompassTextureGetSourceHeight)) != MH_OK) + { + LogUtil::Log("[WeaveLoader] Warning: Failed to hook CompassTexture::getSourceHeight"); + } + else + { + LogUtil::Log("[WeaveLoader] Hooked CompassTexture::getSourceHeight (texture pack crash guard)"); + } + } + + if (symbols.pClockTextureGetSourceWidth) + { + if (MH_CreateHook(symbols.pClockTextureGetSourceWidth, + reinterpret_cast(&GameHooks::Hooked_ClockTextureGetSourceWidth), + reinterpret_cast(&GameHooks::Original_ClockTextureGetSourceWidth)) != MH_OK) + { + LogUtil::Log("[WeaveLoader] Warning: Failed to hook ClockTexture::getSourceWidth"); + } + else + { + LogUtil::Log("[WeaveLoader] Hooked ClockTexture::getSourceWidth (texture pack crash guard)"); + } + } + + if (symbols.pClockTextureGetSourceHeight) + { + if (MH_CreateHook(symbols.pClockTextureGetSourceHeight, + reinterpret_cast(&GameHooks::Hooked_ClockTextureGetSourceHeight), + reinterpret_cast(&GameHooks::Original_ClockTextureGetSourceHeight)) != MH_OK) + { + LogUtil::Log("[WeaveLoader] Warning: Failed to hook ClockTexture::getSourceHeight"); + } + else + { + LogUtil::Log("[WeaveLoader] Hooked ClockTexture::getSourceHeight (texture pack crash guard)"); + } + } + if (symbols.pItemMineBlock) { if (MH_CreateHook(symbols.pItemMineBlock, diff --git a/WeaveLoaderRuntime/src/SymbolResolver.cpp b/WeaveLoaderRuntime/src/SymbolResolver.cpp index 7257d74..31ca576 100644 --- a/WeaveLoaderRuntime/src/SymbolResolver.cpp +++ b/WeaveLoaderRuntime/src/SymbolResolver.cpp @@ -21,6 +21,12 @@ static const char* SYM_REGISTER_ICON = "?registerIcon@PreStitchedTextureMap@@UEA 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_COMPASS_CYCLEFRAMES = "?cycleFrames@CompassTexture@@UEAAXXZ"; +static const char* SYM_CLOCK_CYCLEFRAMES = "?cycleFrames@ClockTexture@@UEAAXXZ"; +static const char* SYM_COMPASS_GETSOURCEWIDTH = "?getSourceWidth@CompassTexture@@UEBAHXZ"; +static const char* SYM_COMPASS_GETSOURCEHEIGHT = "?getSourceHeight@CompassTexture@@UEBAHXZ"; +static const char* SYM_CLOCK_GETSOURCEWIDTH = "?getSourceWidth@ClockTexture@@UEBAHXZ"; +static const char* SYM_CLOCK_GETSOURCEHEIGHT = "?getSourceHeight@ClockTexture@@UEBAHXZ"; 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"; @@ -122,6 +128,12 @@ bool SymbolResolver::ResolveGameFunctions() pItemInstanceGetIcon = Resolve(SYM_ITEMINSTANCE_GETICON); pEntityRendererBindTextureResource = Resolve(SYM_ENTITYRENDERER_BINDTEXTURE_RESOURCE); pItemRendererRenderItemBillboard = Resolve(SYM_ITEMRENDERER_RENDERITEMBILLBOARD); + pCompassTextureCycleFrames = Resolve(SYM_COMPASS_CYCLEFRAMES); + pClockTextureCycleFrames = Resolve(SYM_CLOCK_CYCLEFRAMES); + pCompassTextureGetSourceWidth = Resolve(SYM_COMPASS_GETSOURCEWIDTH); + pCompassTextureGetSourceHeight = Resolve(SYM_COMPASS_GETSOURCEHEIGHT); + pClockTextureGetSourceWidth = Resolve(SYM_CLOCK_GETSOURCEWIDTH); + pClockTextureGetSourceHeight = Resolve(SYM_CLOCK_GETSOURCEHEIGHT); pItemInstanceMineBlock = Resolve(SYM_ITEMINSTANCE_MINEBLOCK); pItemMineBlock = Resolve(SYM_ITEM_MINEBLOCK); pDiggerItemMineBlock = Resolve(SYM_DIGGERITEM_MINEBLOCK); @@ -181,6 +193,12 @@ bool SymbolResolver::ResolveGameFunctions() logSym("ItemInstance::getIcon", pItemInstanceGetIcon); logSym("EntityRenderer::bindTexture(ResourceLocation)", pEntityRendererBindTextureResource); logSym("ItemRenderer::renderItemBillboard", pItemRendererRenderItemBillboard); + logSym("CompassTexture::cycleFrames", pCompassTextureCycleFrames); + logSym("ClockTexture::cycleFrames", pClockTextureCycleFrames); + logSym("CompassTexture::getSourceWidth", pCompassTextureGetSourceWidth); + logSym("CompassTexture::getSourceHeight", pCompassTextureGetSourceHeight); + logSym("ClockTexture::getSourceWidth", pClockTextureGetSourceWidth); + logSym("ClockTexture::getSourceHeight", pClockTextureGetSourceHeight); 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 8c8a92e..5111dc9 100644 --- a/WeaveLoaderRuntime/src/SymbolResolver.h +++ b/WeaveLoaderRuntime/src/SymbolResolver.h @@ -26,6 +26,12 @@ public: void* pItemInstanceGetIcon = nullptr; // ItemInstance::getIcon() void* pEntityRendererBindTextureResource = nullptr; // EntityRenderer::bindTexture(ResourceLocation*) void* pItemRendererRenderItemBillboard = nullptr; // ItemRenderer::renderItemBillboard(shared_ptr,Icon*,...) + void* pCompassTextureCycleFrames = nullptr; // CompassTexture::cycleFrames() + void* pClockTextureCycleFrames = nullptr; // ClockTexture::cycleFrames() + void* pCompassTextureGetSourceWidth = nullptr; // CompassTexture::getSourceWidth() const + void* pCompassTextureGetSourceHeight = nullptr; // CompassTexture::getSourceHeight() const + void* pClockTextureGetSourceWidth = nullptr; // ClockTexture::getSourceWidth() const + void* pClockTextureGetSourceHeight = nullptr; // ClockTexture::getSourceHeight() const 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)