diff --git a/WeaveLoaderRuntime/src/GameHooks.cpp b/WeaveLoaderRuntime/src/GameHooks.cpp index 842ab7d..8d573e4 100644 --- a/WeaveLoaderRuntime/src/GameHooks.cpp +++ b/WeaveLoaderRuntime/src/GameHooks.cpp @@ -95,6 +95,8 @@ namespace GameHooks PlayerCanDestroy_fn Original_PlayerCanDestroy = nullptr; GameModeUseItem_fn Original_ServerPlayerGameModeUseItem = nullptr; GameModeUseItem_fn Original_MultiPlayerGameModeUseItem = nullptr; + ServerPlayerGameModeUseItemOn_fn Original_ServerPlayerGameModeUseItemOn = nullptr; + MultiPlayerGameModeUseItemOn_fn Original_MultiPlayerGameModeUseItemOn = nullptr; MinecraftSetLevel_fn Original_MinecraftSetLevel = nullptr; TexturesBindTextureResource_fn Original_TexturesBindTextureResource = nullptr; TexturesLoadTextureByName_fn Original_TexturesLoadTextureByName = nullptr; @@ -1915,7 +1917,11 @@ namespace GameHooks if (result && tile > 0) DispatchManagedBlockById(tile, thisPtr, x, y, z, 0, 0); - if (result && tile > 0 && Original_LevelSetData) + bool isClientSide = false; + if (thisPtr && IsReadableRange(static_cast(thisPtr) + kLevelIsClientSideOffset, sizeof(bool))) + isClientSide = *reinterpret_cast(static_cast(thisPtr) + kLevelIsClientSideOffset); + + if (result && tile > 0 && Original_LevelSetData && !isClientSide) { const int profile = ModelRegistry::GetRotationProfile(tile); if (profile == 1 || profile == 3) @@ -2726,7 +2732,11 @@ namespace GameHooks bool __fastcall Hooked_ItemInstanceUseOn(void* thisPtr, void* playerSharedPtr, void* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) { - if (!bTestUseOnOnly) + bool isClientSide = false; + if (level && IsReadableRange(static_cast(level) + kLevelIsClientSideOffset, sizeof(bool))) + isClientSide = *reinterpret_cast(static_cast(level) + kLevelIsClientSideOffset); + + if (!bTestUseOnOnly && !isClientSide) { void* playerPtr = DecodePlayerPtrFromSharedArg(playerSharedPtr); if (playerPtr) @@ -3097,6 +3107,42 @@ namespace GameHooks return false; } + bool __fastcall Hooked_ServerPlayerGameModeUseItemOn(void* thisPtr, void* playerSharedPtr, void* level, void* itemInstanceSharedPtr, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly, bool* pbUsedItem) + { + if (!bTestUseOnOnly) + { + void* playerPtr = DecodePlayerPtrFromSharedArg(playerSharedPtr); + if (playerPtr) + { + s_lastUsePlayer = playerPtr; + s_lastUseLevel = level; + s_lastUseTimeMs = GetTickCount64(); + } + } + + if (Original_ServerPlayerGameModeUseItemOn) + return Original_ServerPlayerGameModeUseItemOn(thisPtr, playerSharedPtr, level, itemInstanceSharedPtr, x, y, z, face, clickX, clickY, clickZ, bTestUseOnOnly, pbUsedItem); + return false; + } + + bool __fastcall Hooked_MultiPlayerGameModeUseItemOn(void* thisPtr, void* playerSharedPtr, void* level, void* itemInstanceSharedPtr, int x, int y, int z, int face, void* hitVec3Ptr, bool bTestUseOnly, bool* pbUsedItem) + { + if (!bTestUseOnly) + { + void* playerPtr = DecodePlayerPtrFromSharedArg(playerSharedPtr); + if (playerPtr) + { + s_lastUsePlayer = playerPtr; + s_lastUseLevel = level; + s_lastUseTimeMs = GetTickCount64(); + } + } + + if (Original_MultiPlayerGameModeUseItemOn) + return Original_MultiPlayerGameModeUseItemOn(thisPtr, playerSharedPtr, level, itemInstanceSharedPtr, x, y, z, face, hitVec3Ptr, bTestUseOnly, pbUsedItem); + return false; + } + void __fastcall Hooked_MinecraftSetLevel(void* thisPtr, void* level, int message, void* forceInsertPlayerSharedPtr, bool doForceStatsSave, bool bPrimaryPlayerSignedOut) { if (Original_MinecraftSetLevel) diff --git a/WeaveLoaderRuntime/src/GameHooks.h b/WeaveLoaderRuntime/src/GameHooks.h index bf7e55e..e4448e9 100644 --- a/WeaveLoaderRuntime/src/GameHooks.h +++ b/WeaveLoaderRuntime/src/GameHooks.h @@ -52,6 +52,8 @@ typedef void* (__fastcall *StoneSlabItemGetIcon_fn)(void* thisPtr, int auxValue) typedef unsigned int (__fastcall *StoneSlabItemGetDescriptionId_fn)(void* thisPtr, void* itemInstanceSharedPtr); typedef bool (__fastcall *PlayerCanDestroy_fn)(void* thisPtr, void* tilePtr); typedef bool (__fastcall *GameModeUseItem_fn)(void* thisPtr, void* playerSharedPtr, void* level, void* itemInstanceSharedPtr, bool bTestUseOnly); +typedef bool (__fastcall *MultiPlayerGameModeUseItemOn_fn)(void* thisPtr, void* playerSharedPtr, void* level, void* itemInstanceSharedPtr, int x, int y, int z, int face, void* hitVec3Ptr, bool bTestUseOnly, bool* pbUsedItem); +typedef bool (__fastcall *ServerPlayerGameModeUseItemOn_fn)(void* thisPtr, void* playerSharedPtr, void* level, void* itemInstanceSharedPtr, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly, bool* pbUsedItem); typedef void (__fastcall *MinecraftSetLevel_fn)(void* thisPtr, void* level, int message, void* forceInsertPlayerSharedPtr, bool doForceStatsSave, bool bPrimaryPlayerSignedOut); typedef bool (__fastcall *LevelAddEntity_fn)(void* thisPtr, void* entitySharedPtr); typedef void (__fastcall *EntityMoveTo_fn)(void* thisPtr, double x, double y, double z, float yRot, float xRot); @@ -154,6 +156,8 @@ namespace GameHooks extern PlayerCanDestroy_fn Original_PlayerCanDestroy; extern GameModeUseItem_fn Original_ServerPlayerGameModeUseItem; extern GameModeUseItem_fn Original_MultiPlayerGameModeUseItem; + extern ServerPlayerGameModeUseItemOn_fn Original_ServerPlayerGameModeUseItemOn; + extern MultiPlayerGameModeUseItemOn_fn Original_MultiPlayerGameModeUseItemOn; extern MinecraftSetLevel_fn Original_MinecraftSetLevel; extern TexturesBindTextureResource_fn Original_TexturesBindTextureResource; extern TexturesLoadTextureByName_fn Original_TexturesLoadTextureByName; @@ -246,6 +250,8 @@ namespace GameHooks bool __fastcall Hooked_PlayerCanDestroy(void* thisPtr, void* tilePtr); bool __fastcall Hooked_ServerPlayerGameModeUseItem(void* thisPtr, void* playerSharedPtr, void* level, void* itemInstanceSharedPtr, bool bTestUseOnly); bool __fastcall Hooked_MultiPlayerGameModeUseItem(void* thisPtr, void* playerSharedPtr, void* level, void* itemInstanceSharedPtr, bool bTestUseOnly); + bool __fastcall Hooked_ServerPlayerGameModeUseItemOn(void* thisPtr, void* playerSharedPtr, void* level, void* itemInstanceSharedPtr, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly, bool* pbUsedItem); + bool __fastcall Hooked_MultiPlayerGameModeUseItemOn(void* thisPtr, void* playerSharedPtr, void* level, void* itemInstanceSharedPtr, int x, int y, int z, int face, void* hitVec3Ptr, bool bTestUseOnly, bool* pbUsedItem); void __fastcall Hooked_MinecraftSetLevel(void* thisPtr, void* level, int message, void* forceInsertPlayerSharedPtr, bool doForceStatsSave, bool bPrimaryPlayerSignedOut); void __fastcall Hooked_TexturesBindTextureResource(void* thisPtr, void* resourcePtr); int __fastcall Hooked_TexturesLoadTextureByName(void* thisPtr, int texId, const std::wstring& resourceName); diff --git a/WeaveLoaderRuntime/src/HookManager.cpp b/WeaveLoaderRuntime/src/HookManager.cpp index ca903ca..06b2031 100644 --- a/WeaveLoaderRuntime/src/HookManager.cpp +++ b/WeaveLoaderRuntime/src/HookManager.cpp @@ -25,6 +25,8 @@ bool HookManager::Install(const SymbolResolver& symbols) WorldIdRemap::SetLevelChunkTileSymbols( symbols.Level.pLevelChunkGetTile, symbols.Level.pLevelChunkSetTile, + symbols.Level.pLevelChunkGetData, + symbols.Level.pLevelChunkSetTileAndData, symbols.Level.pLevelChunkGetPos, symbols.Level.pLevelChunkGetHighestNonEmptyY); WorldIdRemap::SetCompressedTileStorageSetSymbol(symbols.Level.pCompressedTileStorageSet); @@ -112,6 +114,34 @@ bool HookManager::Install(const SymbolResolver& symbols) } } + if (symbols.Entity.pServerPlayerGameModeUseItemOn) + { + if (MH_CreateHook(symbols.Entity.pServerPlayerGameModeUseItemOn, + reinterpret_cast(&GameHooks::Hooked_ServerPlayerGameModeUseItemOn), + reinterpret_cast(&GameHooks::Original_ServerPlayerGameModeUseItemOn)) != MH_OK) + { + LogUtil::Log("[WeaveLoader] Warning: Failed to hook ServerPlayerGameMode::useItemOn"); + } + else + { + LogUtil::Log("[WeaveLoader] Hooked ServerPlayerGameMode::useItemOn (placement tracking)"); + } + } + + if (symbols.Entity.pMultiPlayerGameModeUseItemOn) + { + if (MH_CreateHook(symbols.Entity.pMultiPlayerGameModeUseItemOn, + reinterpret_cast(&GameHooks::Hooked_MultiPlayerGameModeUseItemOn), + reinterpret_cast(&GameHooks::Original_MultiPlayerGameModeUseItemOn)) != MH_OK) + { + LogUtil::Log("[WeaveLoader] Warning: Failed to hook MultiPlayerGameMode::useItemOn"); + } + else + { + LogUtil::Log("[WeaveLoader] Hooked MultiPlayerGameMode::useItemOn (placement tracking)"); + } + } + if (symbols.Item.pItemInstanceUseOn) { if (MH_CreateHook(symbols.Item.pItemInstanceUseOn, diff --git a/WeaveLoaderRuntime/src/Symbols/SymbolGroups.cpp b/WeaveLoaderRuntime/src/Symbols/SymbolGroups.cpp index 6b655ab..5f9ac66 100644 --- a/WeaveLoaderRuntime/src/Symbols/SymbolGroups.cpp +++ b/WeaveLoaderRuntime/src/Symbols/SymbolGroups.cpp @@ -122,10 +122,14 @@ namespace static const char* SYM_LEVEL_HASNEIGHBORSIGNAL = "?hasNeighborSignal@Level@@QEAA_NHHH@Z"; static const char* SYM_LEVEL_ADDTOTICKNEXTTICK = "?addToTickNextTick@Level@@UEAAXHHHHH@Z"; static const char* SYM_SERVERLEVEL_ADDTOTICKNEXTTICK = "?addToTickNextTick@ServerLevel@@UEAAXHHHHH@Z"; + static const char* SYM_LEVELCHUNK_GETDATA = "?getData@LevelChunk@@UEAAHHHH@Z"; + static const char* SYM_LEVELCHUNK_SETTILEANDDATA = "?setTileAndData@LevelChunk@@UEAA_NHHHHH@Z"; static const char* SYM_PLAYER_CANDESTROY = "?canDestroy@Player@@QEAA_NPEAVTile@@@Z"; static const char* SYM_SERVER_PLAYER_GAMEMODE_USEITEM = "?useItem@ServerPlayerGameMode@@QEAA_NV?$shared_ptr@VPlayer@@@std@@PEAVLevel@@V?$shared_ptr@VItemInstance@@@3@_N@Z"; static const char* SYM_MULTI_PLAYER_GAMEMODE_USEITEM = "?useItem@MultiPlayerGameMode@@UEAA_NV?$shared_ptr@VPlayer@@@std@@PEAVLevel@@V?$shared_ptr@VItemInstance@@@3@_N@Z"; + static const char* SYM_SERVER_PLAYER_GAMEMODE_USEITEMON = "?useItemOn@ServerPlayerGameMode@@QEAA_NV?$shared_ptr@VPlayer@@@std@@PEAVLevel@@V?$shared_ptr@VItemInstance@@@3@HHHHMMM_NPEA_N@Z"; + static const char* SYM_MULTI_PLAYER_GAMEMODE_USEITEMON = "?useItemOn@MultiPlayerGameMode@@UEAA_NV?$shared_ptr@VPlayer@@@std@@PEAVLevel@@V?$shared_ptr@VItemInstance@@@3@HHHHPEAVVec3@@_NPEA_N@Z"; static const char* SYM_LEVEL_ADDENTITY = "?addEntity@Level@@UEAA_NV?$shared_ptr@VEntity@@@std@@@Z"; static const char* SYM_ENTITYIO_NEWBYID = "?newById@EntityIO@@SA?AV?$shared_ptr@VEntity@@@std@@HPEAVLevel@@@Z"; static const char* SYM_ENTITY_MOVETO = "?moveTo@Entity@@QEAAXNNNMM@Z"; @@ -439,6 +443,12 @@ bool LevelSymbols::Resolve(SymbolResolver& resolver) pServerLevelAddToTickNextTick = resolver.Resolve(SYM_SERVERLEVEL_ADDTOTICKNEXTTICK); pLevelChunkGetTile = resolver.ResolveExact("LevelChunk::getTile"); pLevelChunkSetTile = resolver.ResolveExact("LevelChunk::setTile"); + pLevelChunkGetData = resolver.Resolve(SYM_LEVELCHUNK_GETDATA); + if (!pLevelChunkGetData) + pLevelChunkGetData = resolver.ResolveExact("LevelChunk::getData"); + pLevelChunkSetTileAndData = resolver.Resolve(SYM_LEVELCHUNK_SETTILEANDDATA); + if (!pLevelChunkSetTileAndData) + pLevelChunkSetTileAndData = resolver.ResolveExact("LevelChunk::setTileAndData"); pLevelChunkGetPos = resolver.ResolveExact("LevelChunk::getPos"); pLevelChunkGetHighestNonEmptyY = resolver.ResolveExact("LevelChunk::getHighestNonEmptyY"); pCompressedTileStorageSet = resolver.ResolveExact("CompressedTileStorage::set"); @@ -461,6 +471,8 @@ void LevelSymbols::Log() const LogSym("ServerLevel::addToTickNextTick", pServerLevelAddToTickNextTick); LogSym("LevelChunk::getTile", pLevelChunkGetTile); LogSym("LevelChunk::setTile", pLevelChunkSetTile); + LogSym("LevelChunk::getData", pLevelChunkGetData); + LogSym("LevelChunk::setTileAndData", pLevelChunkSetTileAndData); LogSym("LevelChunk::getPos", pLevelChunkGetPos); LogSym("LevelChunk::getHighestNonEmptyY", pLevelChunkGetHighestNonEmptyY); LogSym("CompressedTileStorage::set", pCompressedTileStorageSet); @@ -471,6 +483,8 @@ bool EntitySymbols::Resolve(SymbolResolver& resolver) pPlayerCanDestroy = resolver.Resolve(SYM_PLAYER_CANDESTROY); pServerPlayerGameModeUseItem = resolver.Resolve(SYM_SERVER_PLAYER_GAMEMODE_USEITEM); pMultiPlayerGameModeUseItem = resolver.Resolve(SYM_MULTI_PLAYER_GAMEMODE_USEITEM); + pServerPlayerGameModeUseItemOn = resolver.Resolve(SYM_SERVER_PLAYER_GAMEMODE_USEITEMON); + pMultiPlayerGameModeUseItemOn = resolver.Resolve(SYM_MULTI_PLAYER_GAMEMODE_USEITEMON); pLevelAddEntity = resolver.Resolve(SYM_LEVEL_ADDENTITY); pEntityIONewById = resolver.Resolve(SYM_ENTITYIO_NEWBYID); pEntityMoveTo = resolver.Resolve(SYM_ENTITY_MOVETO); @@ -492,6 +506,8 @@ void EntitySymbols::Log() const LogSym("Player::canDestroy", pPlayerCanDestroy); LogSym("ServerPlayerGameMode::useItem", pServerPlayerGameModeUseItem); LogSym("MultiPlayerGameMode::useItem", pMultiPlayerGameModeUseItem); + LogSym("ServerPlayerGameMode::useItemOn", pServerPlayerGameModeUseItemOn); + LogSym("MultiPlayerGameMode::useItemOn", pMultiPlayerGameModeUseItemOn); LogSym("Level::addEntity", pLevelAddEntity); LogSym("EntityIO::newById", pEntityIONewById); LogSym("Entity::moveTo", pEntityMoveTo); diff --git a/WeaveLoaderRuntime/src/Symbols/SymbolGroups.h b/WeaveLoaderRuntime/src/Symbols/SymbolGroups.h index fbddbe2..ad8da28 100644 --- a/WeaveLoaderRuntime/src/Symbols/SymbolGroups.h +++ b/WeaveLoaderRuntime/src/Symbols/SymbolGroups.h @@ -150,6 +150,8 @@ struct LevelSymbols void* pServerLevelAddToTickNextTick = nullptr; void* pLevelChunkGetTile = nullptr; void* pLevelChunkSetTile = nullptr; + void* pLevelChunkGetData = nullptr; + void* pLevelChunkSetTileAndData = nullptr; void* pLevelChunkGetPos = nullptr; void* pLevelChunkGetHighestNonEmptyY = nullptr; void* pCompressedTileStorageSet = nullptr; @@ -163,6 +165,8 @@ struct EntitySymbols void* pPlayerCanDestroy = nullptr; void* pServerPlayerGameModeUseItem = nullptr; void* pMultiPlayerGameModeUseItem = nullptr; + void* pServerPlayerGameModeUseItemOn = nullptr; + void* pMultiPlayerGameModeUseItemOn = nullptr; void* pLevelAddEntity = nullptr; void* pEntityIONewById = nullptr; void* pEntityMoveTo = nullptr; diff --git a/WeaveLoaderRuntime/src/WorldIdRemap.cpp b/WeaveLoaderRuntime/src/WorldIdRemap.cpp index 713bee6..fa48cae 100644 --- a/WeaveLoaderRuntime/src/WorldIdRemap.cpp +++ b/WeaveLoaderRuntime/src/WorldIdRemap.cpp @@ -39,6 +39,8 @@ namespace using TagNewTag_fn = void* (__fastcall *)(unsigned char type, const std::wstring& name); using LevelChunkGetTile_fn = int (__fastcall *)(void* thisPtr, int x, int y, int z); using LevelChunkSetTile_fn = bool (__fastcall *)(void* thisPtr, int x, int y, int z, int tile); + using LevelChunkGetData_fn = int (__fastcall *)(void* thisPtr, int x, int y, int z); + using LevelChunkSetTileAndData_fn = bool (__fastcall *)(void* thisPtr, int x, int y, int z, int tile, int data); using LevelChunkGetPos_fn = void* (__fastcall *)(void* thisPtr); using LevelChunkGetHighestNonEmptyY_fn = int (__fastcall *)(void* thisPtr); using CompressedTileStorageSet_fn = void (__fastcall *)(void* thisPtr, int x, int y, int z, int val); @@ -62,6 +64,8 @@ namespace void* s_tileArray = nullptr; LevelChunkGetTile_fn s_levelChunkGetTile = nullptr; LevelChunkSetTile_fn s_levelChunkSetTile = nullptr; + LevelChunkGetData_fn s_levelChunkGetData = nullptr; + LevelChunkSetTileAndData_fn s_levelChunkSetTileAndData = nullptr; LevelChunkGetPos_fn s_levelChunkGetPos = nullptr; LevelChunkGetHighestNonEmptyY_fn s_levelChunkGetHighestNonEmptyY = nullptr; CompressedTileStorageSet_fn s_compressedTileStorageSet = nullptr; @@ -460,7 +464,7 @@ namespace static bool SafeSetChunkTile(void* levelChunkPtr, int x, int y, int z, int tileId) { - if (!s_levelChunkSetTile) + if (!s_levelChunkSetTile && !s_levelChunkSetTileAndData) return false; // If the current block has no valid Tile pointer, setTileAndData will crash when it @@ -490,7 +494,19 @@ namespace #if defined(_MSC_VER) __try { - s_levelChunkSetTile(levelChunkPtr, x, y, z, tileId); + if (s_levelChunkSetTileAndData && s_levelChunkGetData) + { + const int data = s_levelChunkGetData(levelChunkPtr, x, y, z); + s_levelChunkSetTileAndData(levelChunkPtr, x, y, z, tileId, data); + } + else if (s_levelChunkSetTile) + { + s_levelChunkSetTile(levelChunkPtr, x, y, z, tileId); + } + else + { + return false; + } return true; } __except (EXCEPTION_EXECUTE_HANDLER) @@ -498,7 +514,19 @@ namespace return false; } #else - s_levelChunkSetTile(levelChunkPtr, x, y, z, tileId); + if (s_levelChunkSetTileAndData && s_levelChunkGetData) + { + const int data = s_levelChunkGetData(levelChunkPtr, x, y, z); + s_levelChunkSetTileAndData(levelChunkPtr, x, y, z, tileId, data); + } + else if (s_levelChunkSetTile) + { + s_levelChunkSetTile(levelChunkPtr, x, y, z, tileId); + } + else + { + return false; + } return true; #endif } @@ -659,10 +687,12 @@ namespace WorldIdRemap s_tileArray = tileArrayPtr; } - void SetLevelChunkTileSymbols(void* getTileFn, void* setTileFn, void* getPosFn, void* getHighestNonEmptyYFn) + void SetLevelChunkTileSymbols(void* getTileFn, void* setTileFn, void* getDataFn, void* setTileAndDataFn, void* getPosFn, void* getHighestNonEmptyYFn) { s_levelChunkGetTile = reinterpret_cast(getTileFn); s_levelChunkSetTile = reinterpret_cast(setTileFn); + s_levelChunkGetData = reinterpret_cast(getDataFn); + s_levelChunkSetTileAndData = reinterpret_cast(setTileAndDataFn); s_levelChunkGetPos = reinterpret_cast(getPosFn); s_levelChunkGetHighestNonEmptyY = reinterpret_cast(getHighestNonEmptyYFn); } diff --git a/WeaveLoaderRuntime/src/WorldIdRemap.h b/WeaveLoaderRuntime/src/WorldIdRemap.h index e30398d..9ceab2a 100644 --- a/WeaveLoaderRuntime/src/WorldIdRemap.h +++ b/WeaveLoaderRuntime/src/WorldIdRemap.h @@ -6,7 +6,7 @@ namespace WorldIdRemap { void SetTagNewTagSymbol(void* fnPtr); void SetTileArraySymbol(void* tileArrayPtr); - void SetLevelChunkTileSymbols(void* getTileFn, void* setTileFn, void* getPosFn, void* getHighestNonEmptyYFn); + void SetLevelChunkTileSymbols(void* getTileFn, void* setTileFn, void* getDataFn, void* setTileAndDataFn, void* getPosFn, void* getHighestNonEmptyYFn); void SetCompressedTileStorageSetSymbol(void* setFn); void EnsureMissingPlaceholders(); int RemapChunkBlockIds(void* chunkStoragePtr, void* levelChunkPtr, int chunkX, int chunkZ);