diff --git a/Client/game_sa/CVehicleSA.cpp b/Client/game_sa/CVehicleSA.cpp index b1c37fee24e..fb50dff1eda 100644 --- a/Client/game_sa/CVehicleSA.cpp +++ b/Client/game_sa/CVehicleSA.cpp @@ -147,6 +147,42 @@ static void __declspec(naked) HOOK_CPlane_ProcessFlyingCarStuff() // clang-format on } +static void __fastcall SetComponentVisibility(CVehicleSAInterface* vehicleInterface, RwFrame* frame, int state) +{ + if (!frame) + return; + + SClientEntity* vehicle = pGame->GetPools()->GetVehicle((DWORD*)vehicleInterface); + if (!vehicle || !vehicle->pEntity) + return; + + // > ATOMIC_NONE + // If a component was hidden by a script, don't show it + if (state > 0 && !vehicle->pEntity->IsComponentVisibleInCache(frame->szName)) + return; + + RwFrameForAllObjects(frame, (void*)0x6D2690, (void*)state); // SetVehicleAtomicVisibilityCB(RpAtomic*) + RwFrameForAllChildren(frame, (void*)0x6D26D0, (void*)state); // SetVehicleAtomicVisibilityCB(RwFrame*) +} + +static constexpr std::uintptr_t RETURN_CVehicle_SetComponentVisibility = 0x6D2735; +static void __declspec(naked) HOOK_CVehicle_SetComponentVisibility() +{ + MTA_VERIFY_HOOK_LOCAL_SIZE; + + // clang-format off + __asm + { + mov edx, esi + + push edi + call SetComponentVisibility + + jmp RETURN_CVehicle_SetComponentVisibility + } + // clang-format on +} + namespace { bool ClumpDumpCB(RpAtomic* pAtomic, void* data) @@ -2043,6 +2079,9 @@ void CVehicleSA::StaticSetHooks() // Setup hooks to handle setVehicleRotorState function HookInstall(FUNC_CHeli_ProcessFlyingCarStuff, (DWORD)HOOK_CHeli_ProcessFlyingCarStuff, 5); HookInstall(FUNC_CPlane_ProcessFlyingCarStuff, (DWORD)HOOK_CPlane_ProcessFlyingCarStuff, 5); + + // Setup hook to handle vehicle component visibility changes + HookInstall(0x6D271A, (DWORD)HOOK_CVehicle_SetComponentVisibility); } void CVehicleSA::SetVehiclesSunGlareEnabled(bool bEnabled) @@ -2361,6 +2400,22 @@ bool CVehicleSA::SetComponentVisible(const SString& vehicleComponent, bool bRequ return false; } +bool CVehicleSA::IsComponentVisibleInCache(const SString& vehicleComponent) +{ + SVehicleFrame* component = GetVehicleComponent(vehicleComponent); + if (!component) + return false; + + if (!m_componentCacheData) + return false; + + auto it = m_componentCacheData->find(vehicleComponent); + if (it == m_componentCacheData->end()) + return false; + + return it->second.m_bVisible; +} + bool CVehicleSA::GetComponentVisible(const SString& vehicleComponent, bool& bOutVisible) { SVehicleFrame* pComponent = GetVehicleComponent(vehicleComponent); diff --git a/Client/game_sa/CVehicleSA.h b/Client/game_sa/CVehicleSA.h index c1246fcb096..0a234f6807c 100644 --- a/Client/game_sa/CVehicleSA.h +++ b/Client/game_sa/CVehicleSA.h @@ -449,6 +449,8 @@ class CVehicleSA : public virtual CVehicle, public virtual CPhysicalSA std::array(VehicleDummies::VEHICLE_DUMMY_COUNT)> m_dummyPositions; + std::map* m_componentCacheData{nullptr}; + public: CVehicleSA() = default; ~CVehicleSA(); @@ -698,6 +700,7 @@ class CVehicleSA : public virtual CVehicle, public virtual CPhysicalSA bool GetComponentMatrix(const SString& vehicleComponent, CMatrix& matOutOrientation); bool GetComponentParentToRootMatrix(const SString& vehicleComponent, CMatrix& matOutParentToRoot); bool SetComponentVisible(const SString& vehicleComponent, bool bVisible); + bool IsComponentVisibleInCache(const SString& vehicleComponent); void AddComponent(RwFrame* pFrame, bool bReadOnly); bool GetComponentVisible(const SString& vehicleComponent, bool& bVisible); std::map& GetComponentMap() { return m_ExtraFrames; } @@ -720,6 +723,8 @@ class CVehicleSA : public virtual CVehicle, public virtual CPhysicalSA bool IsOnFire() override { return GetVehicleInterface()->m_pFire != nullptr; } bool SetOnFire(bool onFire) override; + void SetCacheDataMap(std::map* pCacheData) noexcept override { m_componentCacheData = pCacheData; } + static void StaticSetHooks(); static void SetVehiclesSunGlareEnabled(bool bEnabled); static bool GetVehiclesSunGlareEnabled(); diff --git a/Client/game_sa/gamesa_renderware.h b/Client/game_sa/gamesa_renderware.h index 9455a59da76..148b8f4a172 100644 --- a/Client/game_sa/gamesa_renderware.h +++ b/Client/game_sa/gamesa_renderware.h @@ -108,6 +108,7 @@ typedef RpHAnimHierarchy*(__cdecl* GetAnimHierarchyFromSkinClump_t)(RpClump*); typedef int(__cdecl* RpHAnimIDGetIndex_t)(RpHAnimHierarchy*, int); typedef RwMatrix*(__cdecl* RpHAnimHierarchyGetMatrixArray_t)(RpHAnimHierarchy*); typedef RtQuat*(__cdecl* RtQuatRotate_t)(RtQuat* quat, const RwV3d* axis, float angle, RwOpCombineType combineOp); +using RwFrameForAllChildren_t = RwFrame*(__cdecl*)(RwFrame * frame, void* callback, void* data); /*****************************************************************************/ /** Renderware function mappings **/ @@ -200,6 +201,7 @@ RWFUNC(GetAnimHierarchyFromSkinClump_t GetAnimHierarchyFromSkinClump, (GetAnimHi RWFUNC(RpHAnimIDGetIndex_t RpHAnimIDGetIndex, (RpHAnimIDGetIndex_t)0xDEAD) RWFUNC(RpHAnimHierarchyGetMatrixArray_t RpHAnimHierarchyGetMatrixArray, (RpHAnimHierarchyGetMatrixArray_t)0xDEAD) RWFUNC(RtQuatRotate_t RtQuatRotate, (RtQuatRotate_t)0xDEAD) +RWFUNC(RwFrameForAllChildren_t RwFrameForAllChildren, (RwFrameForAllChildren_t)0xDEAD) /*****************************************************************************/ /** GTA function definitions and mappings **/ diff --git a/Client/game_sa/gamesa_renderware.hpp b/Client/game_sa/gamesa_renderware.hpp index dd6d5f442df..acc1ddae49c 100644 --- a/Client/game_sa/gamesa_renderware.hpp +++ b/Client/game_sa/gamesa_renderware.hpp @@ -91,6 +91,7 @@ void InitRwFunctions() RpHAnimIDGetIndex = (RpHAnimIDGetIndex_t)0x7C51A0; RpHAnimHierarchyGetMatrixArray = (RpHAnimHierarchyGetMatrixArray_t)0x7C5120; RtQuatRotate = (RtQuatRotate_t)0x7EB7C0; + RwFrameForAllChildren = reinterpret_cast(0x7F0DC0); SetTextureDict = (SetTextureDict_t)0x007319C0; LoadClumpFile = (LoadClumpFile_t)0x005371F0; diff --git a/Client/mods/deathmatch/logic/CClientVehicle.cpp b/Client/mods/deathmatch/logic/CClientVehicle.cpp index 48adb19ebbb..26aeac27001 100644 --- a/Client/mods/deathmatch/logic/CClientVehicle.cpp +++ b/Client/mods/deathmatch/logic/CClientVehicle.cpp @@ -2927,6 +2927,9 @@ void CClientVehicle::Create() // set our visibility SetComponentVisible(strTemp, (*iter).second.m_bVisible); } + + m_pVehicle->SetCacheDataMap(&m_ComponentData); + // store our spawn position in case we fall through the map m_matCreate = m_Matrix; diff --git a/Client/mods/deathmatch/logic/CClientVehicle.h b/Client/mods/deathmatch/logic/CClientVehicle.h index 2c3c75e89c2..76f2b803f37 100644 --- a/Client/mods/deathmatch/logic/CClientVehicle.h +++ b/Client/mods/deathmatch/logic/CClientVehicle.h @@ -126,27 +126,6 @@ struct SLastSyncedVehData bool bDerailed; bool bIsInWater; }; -struct SVehicleComponentData -{ - SVehicleComponentData() - { - m_bPositionChanged = false; - m_bRotationChanged = false; - m_bScaleChanged = false; - m_bVisible = true; - } - SString m_strParentName; - CVector m_vecComponentPosition; // Parent relative - CVector m_vecComponentRotation; // Parent relative radians - CVector m_vecComponentScale; // Parent relative - CVector m_vecOriginalComponentPosition; // Parent relative - CVector m_vecOriginalComponentRotation; // Parent relative radians - CVector m_vecOriginalComponentScale; // Parent relative - bool m_bPositionChanged; - bool m_bRotationChanged; - bool m_bScaleChanged; - bool m_bVisible; -}; static std::array g_vehicleTypePrefixes; diff --git a/Client/sdk/game/CVehicle.h b/Client/sdk/game/CVehicle.h index 778dbf8a37d..602fbeacdaf 100644 --- a/Client/sdk/game/CVehicle.h +++ b/Client/sdk/game/CVehicle.h @@ -91,6 +91,28 @@ struct SVehicleFrame std::vector frameList; // Frames from root to parent }; +struct SVehicleComponentData +{ + SVehicleComponentData() + { + m_bPositionChanged = false; + m_bRotationChanged = false; + m_bScaleChanged = false; + m_bVisible = true; + } + SString m_strParentName; + CVector m_vecComponentPosition; // Parent relative + CVector m_vecComponentRotation; // Parent relative radians + CVector m_vecComponentScale; // Parent relative + CVector m_vecOriginalComponentPosition; // Parent relative + CVector m_vecOriginalComponentRotation; // Parent relative radians + CVector m_vecOriginalComponentScale; // Parent relative + bool m_bPositionChanged; + bool m_bRotationChanged; + bool m_bScaleChanged; + bool m_bVisible; +}; + enum class VehicleComponentType { NONE = -1, @@ -340,4 +362,6 @@ class CVehicle : public virtual CPhysical virtual const CVector* GetDummyPositions() const = 0; virtual void ReinitAudio() = 0; + + virtual void SetCacheDataMap(std::map* pCacheData) = 0; };