diff --git a/src/d2dx/D2DXContext.cpp b/src/d2dx/D2DXContext.cpp index 3879bb0..d4f80fd 100644 --- a/src/d2dx/D2DXContext.cpp +++ b/src/d2dx/D2DXContext.cpp @@ -1179,8 +1179,6 @@ void D2DXContext::EndDrawText() _isDrawingText = false; } -#define MAKE_PLAYER_TYPE(a, b, c, d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24)) - _Use_decl_annotations_ void D2DXContext::BeginDrawImage( const D2::CellContext* cellContext, @@ -1191,37 +1189,35 @@ void D2DXContext::BeginDrawImage( return; } - - DrawParameters drawParameters = _gameHelper->GetDrawParameters(cellContext); - - if (drawParameters.unitType == 0 && ( - drawParameters.unitToken == MAKE_PLAYER_TYPE('A', 'M', ' ', ' ') || - drawParameters.unitToken == MAKE_PLAYER_TYPE('S', 'O', ' ', ' ') || - drawParameters.unitToken == MAKE_PLAYER_TYPE('N', 'E', ' ', ' ') || - drawParameters.unitToken == MAKE_PLAYER_TYPE('P', 'A', ' ', ' ') || - drawParameters.unitToken == MAKE_PLAYER_TYPE('B', 'A', ' ', ' ') || - drawParameters.unitToken == MAKE_PLAYER_TYPE('A', 'M', ' ', ' ') || - drawParameters.unitToken == MAKE_PLAYER_TYPE('D', 'Z', ' ', ' ') || - drawParameters.unitToken == MAKE_PLAYER_TYPE('A', 'I', ' ', ' '))) - { - // The player unit itself. - _scratchBatch.SetTextureCategory(TextureCategory::Player); - _playerScreenPos = pos; - } - else if (_playerScreenPos.x > 0 && - pos.x == _playerScreenPos.x && - pos.y == _playerScreenPos.y) + if (currentlyDrawingUnit) { - // Overlays will be drawn at the player position, so mark them as part of the player. - _scratchBatch.SetTextureCategory(TextureCategory::Player); + if (currentlyDrawingUnit == _gameHelper->GetPlayerUnit()) + { + // The player unit itself. + _scratchBatch.SetTextureCategory(TextureCategory::Player); + _playerScreenPos = pos; + } } - else if ( - drawParameters.unitId == 0 && - drawParameters.unitType == 0 && - cellContext->dwMode == 0) + else { - // UI elements have zero unit ID and unit type. - _scratchBatch.SetTextureCategory(TextureCategory::UserInterface); + DrawParameters drawParameters = _gameHelper->GetDrawParameters(cellContext); + + //if (_playerScreenPos.x > 0 && + // pos.x == _playerScreenPos.x && + // pos.y == _playerScreenPos.y) + //{ + // // Overlays will be drawn at the player position, so mark them as part of the player. + // _scratchBatch.SetTextureCategory(TextureCategory::Player); + //} + //else + if ( + drawParameters.unitId == 0 && + drawParameters.unitType == 0 && + cellContext->dwMode == 0) + { + // UI elements have zero unit ID and unit type. + _scratchBatch.SetTextureCategory(TextureCategory::UserInterface); + } } } diff --git a/src/d2dx/D2Types.h b/src/d2dx/D2Types.h index 8e3ee6c..f94e8e3 100644 --- a/src/d2dx/D2Types.h +++ b/src/d2dx/D2Types.h @@ -103,68 +103,105 @@ namespace d2dx }; static_assert(sizeof(StaticPath) == 0x20, "StaticPath size"); + - struct UnitAny { - UnitType dwType; // 0x00 - DWORD dwTxtFileNo; // 0x04 - DWORD _1; // 0x08 - DWORD dwUnitId; // 0x0C - DWORD dwMode; // 0x10 - union { - void* pPlayerData; - void* pItemData; - void* pMonsterData; - void* pObjectData; - // TileData *pTileData doesn't appear to exist anymore - }; // 0x14 - DWORD dwAct; // 0x18 - void* pAct; // 0x1C - DWORD dwSeed[2]; // 0x20 - DWORD _2; // 0x28 - union { - Path* path; - StaticPath* staticPath; - }; // 0x2C - DWORD _3[2]; // 0x30 - union { - Path* path2; - StaticPath* staticPath2; - }; // 0x38 - DWORD unk[2]; - DWORD dwGfxFrame; // 0x44 - DWORD dwFrameRemain; // 0x48 - WORD wFrameRate; // 0x4C - WORD _4; // 0x4E - BYTE* pGfxUnk; // 0x50 - DWORD* pGfxInfo; // 0x54 - DWORD _5; // 0x58 - void* pStats; // 0x5C - void* pInventory; // 0x60 - void* ptLight; // 0x64 - DWORD dwStartLightRadius; // 0x68 - WORD nPl2ShiftIdx; // 0x6C - WORD nUpdateType; // 0x6E - UnitAny* pUpdateUnit; // 0x70 - Used when updating unit. - DWORD* pQuestRecord; // 0x74 - DWORD bSparklyChest; // 0x78 bool - DWORD* pTimerArgs; // 0x7C - DWORD dwSoundSync; // 0x80 - DWORD _6[2]; // 0x84 - WORD wX; // 0x8C - WORD wY; // 0x8E - DWORD _7; // 0x90 - DWORD dwOwnerType; // 0x94 - DWORD dwOwnerId; // 0x98 - DWORD _8[2]; // 0x9C - void* pOMsg; // 0xA4 - void* pInfo; // 0xA8 - DWORD _9[6]; // 0xAC - DWORD dwFlags; // 0xC4 - DWORD dwFlags2; // 0xC8 - DWORD _10[5]; // 0xCC - UnitAny* pChangedNext; // 0xE0 - UnitAny* pListNext; // 0xE4 -> 0xD8 - UnitAny* pRoomNext; // 0xE8 + struct UnitAny + { + union + { + struct + { + D2::UnitType dwType; // 0x00 + DWORD dwClassId; // 0x04 + void* pMemPool; // 0x08 + DWORD dwUnitId; // 0x0C + DWORD dwMode; // 0x10 + union { + void* pPlayerData; + void* pItemData; + void* pMonsterData; + void* pObjectData; + // TileData *pTileData doesn't appear to exist anymore + }; // 0x14 + DWORD dwAct; // 0x18 + void* pAct; // 0x1C + DWORD dwSeed[2]; // 0x20 + DWORD _2; // 0x28 + union { + Path* path; + StaticPath* staticPath; + }; // 0x2C + DWORD _3[2]; // 0x30 + union { + Path* path2; + StaticPath* staticPath2; + }; // 0x38 + } v109; + + struct + { + UnitType dwType; // 0x00 + DWORD dwTxtFileNo; // 0x04 + DWORD _1; // 0x08 + DWORD dwUnitId; // 0x0C + DWORD dwMode; // 0x10 + union { + void* pPlayerData; + void* pItemData; + void* pMonsterData; + void* pObjectData; + // TileData *pTileData doesn't appear to exist anymore + }; // 0x14 + DWORD dwAct; // 0x18 + void* pAct; // 0x1C + DWORD dwSeed[2]; // 0x20 + DWORD _2; // 0x28 + union { + Path* path; + StaticPath* staticPath; + }; // 0x2C + DWORD _3[2]; // 0x30 + union { + Path* path2; + StaticPath* staticPath2; + }; // 0x38 + DWORD unk[2]; + DWORD dwGfxFrame; // 0x44 + DWORD dwFrameRemain; // 0x48 + WORD wFrameRate; // 0x4C + WORD _4; // 0x4E + BYTE* pGfxUnk; // 0x50 + DWORD* pGfxInfo; // 0x54 + DWORD _5; // 0x58 + void* pStats; // 0x5C + void* pInventory; // 0x60 + void* ptLight; // 0x64 + DWORD dwStartLightRadius; // 0x68 + WORD nPl2ShiftIdx; // 0x6C + WORD nUpdateType; // 0x6E + UnitAny* pUpdateUnit; // 0x70 - Used when updating unit. + DWORD* pQuestRecord; // 0x74 + DWORD bSparklyChest; // 0x78 bool + DWORD* pTimerArgs; // 0x7C + DWORD dwSoundSync; // 0x80 + DWORD _6[2]; // 0x84 + WORD wX; // 0x8C + WORD wY; // 0x8E + DWORD _7; // 0x90 + DWORD dwOwnerType; // 0x94 + DWORD dwOwnerId; // 0x98 + DWORD _8[2]; // 0x9C + void* pOMsg; // 0xA4 + void* pInfo; // 0xA8 + DWORD _9[6]; // 0xAC + DWORD dwFlags; // 0xC4 + DWORD dwFlags2; // 0xC8 + DWORD _10[5]; // 0xCC + UnitAny* pChangedNext; // 0xE0 + UnitAny* pListNext; // 0xE4 -> 0xD8 + UnitAny* pRoomNext; // 0xE8 + } v112; + } u; }; static_assert(sizeof(UnitAny) == 0xEC, "UnitAny size"); diff --git a/src/d2dx/Detours.cpp b/src/d2dx/Detours.cpp index 60ecc3f..2101e03 100644 --- a/src/d2dx/Detours.cpp +++ b/src/d2dx/Detours.cpp @@ -415,7 +415,7 @@ void __fastcall D2Win_DrawText_Hooked( D2::UnitAny* currentlyDrawingUnit = nullptr; -__declspec(naked) void D2Client_DrawUnit_Hooked() +__declspec(naked) void D2Client_DrawUnit_Stack_Hooked() { static void* origReturnAddr = nullptr; @@ -455,7 +455,7 @@ __declspec(naked) void D2Client_DrawUnit_Hooked() } } -__declspec(naked) void D2Client_DrawUnit114d_Hooked() +__declspec(naked) void D2Client_DrawUnit_ESI_Hooked() { static void* origReturnAddr = nullptr; @@ -560,7 +560,10 @@ void d2dx::AttachLateDetours( DetourAttach(&(PVOID&)D2Gfx_DrawShadow_Real, D2Gfx_DrawShadow_Hooked); DetourAttach(&(PVOID&)D2Win_DrawText_Real, D2Win_DrawText_Hooked); - DetourAttach(&(PVOID&)D2Client_DrawUnit_Real, gameHelper->GetVersion() == GameVersion::Lod114d ? D2Client_DrawUnit114d_Hooked : D2Client_DrawUnit_Hooked); + DetourAttach(&(PVOID&)D2Client_DrawUnit_Real, + (gameHelper->GetVersion() == GameVersion::Lod109d || + gameHelper->GetVersion() == GameVersion::Lod110 || + gameHelper->GetVersion() == GameVersion::Lod114d)? D2Client_DrawUnit_ESI_Hooked : D2Client_DrawUnit_Stack_Hooked); LONG lError = DetourTransactionCommit(); diff --git a/src/d2dx/GameHelper.cpp b/src/d2dx/GameHelper.cpp index 92e1df4..f069706 100644 --- a/src/d2dx/GameHelper.cpp +++ b/src/d2dx/GameHelper.cpp @@ -575,19 +575,52 @@ D2::UnitAny* GameHelper::GetPlayerUnit() const return nullptr; } } -Offset GameHelper::GetUnitPos(const D2::UnitAny* unit) + +_Use_decl_annotations_ +D2::UnitType GameHelper::GetUnitType( + const D2::UnitAny* unit) const +{ + if (_version == GameVersion::Lod109d) + { + return unit->u.v109.dwType; + } + else + { + return unit->u.v112.dwType; + } +} + +_Use_decl_annotations_ +uint32_t GameHelper::GetUnitId( + const D2::UnitAny* unit) const { - if (unit->dwType == D2::UnitType::Player || - unit->dwType == D2::UnitType::Monster || - unit->dwType == D2::UnitType::Missile) + if (_version == GameVersion::Lod109d) { - D2::Path* path = _version == GameVersion::Lod109d ? unit->path2 : unit->path; + return unit->u.v109.dwUnitId; + } + else + { + return unit->u.v112.dwUnitId; + } +} + +_Use_decl_annotations_ +Offset GameHelper::GetUnitPos( + const D2::UnitAny* unit) const +{ + auto unitType = GetUnitType(unit); + + if (unitType == D2::UnitType::Player || + unitType == D2::UnitType::Monster || + unitType == D2::UnitType::Missile) + { + D2::Path* path = _version == GameVersion::Lod109d ? unit->u.v109.path2 : unit->u.v112.path; return { (int32_t)path->x, (int32_t)path->y }; } else { - D2::StaticPath* path = _version == GameVersion::Lod109d ? unit->staticPath2 : unit->staticPath; - return { (int32_t)unit->staticPath->xPos * 65536 + (int32_t)unit->staticPath->xOffset, (int32_t)unit->staticPath->yPos * 65536 + (int32_t)unit->staticPath->yOffset }; + D2::StaticPath* path = _version == GameVersion::Lod109d ? unit->u.v109.staticPath2 : unit->u.v112.staticPath; + return { (int32_t)path->xPos * 65536 + (int32_t)path->xOffset, (int32_t)path->yPos * 65536 + (int32_t)path->yOffset }; } } @@ -630,16 +663,18 @@ void* GameHelper::GetFunction( hModule = _hD2GfxDll; ordinal = 10076; break; - case D2Function::D2Gfx_DrawShadow: + case D2Function::D2Gfx_DrawShadow: hModule = _hD2GfxDll; ordinal = 10075; - break; + break; case D2Function::D2Win_DrawText: hModule = _hD2WinDll; ordinal = 10117; break; case D2Function::D2Client_DrawUnit: - return (void*)((uintptr_t)_hD2ClientDll + 0xBBA70); + return _version == GameVersion::Lod110 ? + (void*)((uintptr_t)_hD2ClientDll + 0xBA720) : + (void*)((uintptr_t)_hD2ClientDll + 0xB8350); default: break; } diff --git a/src/d2dx/GameHelper.h b/src/d2dx/GameHelper.h index 4b08e05..0a5b7ce 100644 --- a/src/d2dx/GameHelper.h +++ b/src/d2dx/GameHelper.h @@ -49,9 +49,6 @@ namespace d2dx virtual bool TryApplyFpsFix() override; - virtual Offset GetUnitPos( - _In_ const D2::UnitAny* unit) override; - virtual Offset GetPlayerTargetPos() const override; virtual void* GetFunction( @@ -62,6 +59,15 @@ namespace d2dx virtual D2::UnitAny* GetPlayerUnit() const override; + virtual Offset GetUnitPos( + _In_ const D2::UnitAny* unit) const override; + + virtual D2::UnitType GetUnitType( + _In_ const D2::UnitAny* unit) const override; + + virtual uint32_t GetUnitId( + _In_ const D2::UnitAny* unit) const override; + private: uint16_t ReadU16(HANDLE module, uint32_t offset) const; uint32_t ReadU32(HANDLE module, uint32_t offset) const; diff --git a/src/d2dx/IGameHelper.h b/src/d2dx/IGameHelper.h index 7a851a0..8cfd5ae 100644 --- a/src/d2dx/IGameHelper.h +++ b/src/d2dx/IGameHelper.h @@ -66,9 +66,6 @@ namespace d2dx virtual bool TryApplyFpsFix() = 0; - virtual Offset GetUnitPos( - _In_ const D2::UnitAny* unit) = 0; - virtual Offset GetPlayerTargetPos() const = 0; virtual void* GetFunction( @@ -78,5 +75,14 @@ namespace d2dx _In_ const D2::CellContext* cellContext) const = 0; virtual D2::UnitAny* GetPlayerUnit() const = 0; + + virtual Offset GetUnitPos( + _In_ const D2::UnitAny* unit) const = 0; + + virtual D2::UnitType GetUnitType( + _In_ const D2::UnitAny* unit) const = 0; + + virtual uint32_t GetUnitId( + _In_ const D2::UnitAny* unit) const = 0; }; } diff --git a/src/d2dx/UnitMotionPredictor.cpp b/src/d2dx/UnitMotionPredictor.cpp index c605728..5b84afe 100644 --- a/src/d2dx/UnitMotionPredictor.cpp +++ b/src/d2dx/UnitMotionPredictor.cpp @@ -48,8 +48,9 @@ void UnitMotionPredictor::Update( } UnitMotion& um = _unitMotions.items[i]; + auto unitId = _gameHelper->GetUnitId(unit); - if ((_frame - um.lastUsedFrame) > 1 || unit->dwUnitId == 0xFFFFFFFF || unit->dwUnitId == 0) + if ((_frame - um.lastUsedFrame) > 1 || unitId == 0xFFFFFFFF || unitId == 0) { _unitPtrs.items[i] = nullptr; expiredUnitIndex = i;