From f0f941ebd2048f5ce07a4c049360d7c36a23c135 Mon Sep 17 00:00:00 2001 From: FileEX Date: Tue, 3 Feb 2026 21:23:55 +0100 Subject: [PATCH 1/2] Fix bug --- Client/game_sa/CVehicleSA.cpp | 55 +++++++++++++++++++ Client/game_sa/CVehicleSA.h | 5 ++ Client/game_sa/gamesa_renderware.h | 2 + Client/game_sa/gamesa_renderware.hpp | 1 + .../mods/deathmatch/logic/CClientVehicle.cpp | 3 + Client/mods/deathmatch/logic/CClientVehicle.h | 21 ------- Client/sdk/game/CVehicle.h | 24 ++++++++ 7 files changed, 90 insertions(+), 21 deletions(-) diff --git a/Client/game_sa/CVehicleSA.cpp b/Client/game_sa/CVehicleSA.cpp index 15c6414a320..9c18ec64ce3 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) @@ -2008,6 +2044,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) @@ -2297,6 +2336,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 46e7617e3fb..fe764821339 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..9c97d762203 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 ba37c7ac4b8..b1b15102471 100644 --- a/Client/mods/deathmatch/logic/CClientVehicle.cpp +++ b/Client/mods/deathmatch/logic/CClientVehicle.cpp @@ -2925,6 +2925,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 d302b4313b9..551dd721850 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; +}; + class CVehicle : public virtual CPhysical { public: @@ -331,4 +353,6 @@ class CVehicle : public virtual CPhysical virtual const CVector* GetDummyPositions() const = 0; virtual void ReinitAudio() = 0; + + virtual void SetCacheDataMap(std::map* pCacheData) = 0; }; From 65587976738d98ec80d3f1a6babde9aabc1ef78e Mon Sep 17 00:00:00 2001 From: FileEX Date: Thu, 5 Feb 2026 13:33:28 +0100 Subject: [PATCH 2/2] clang fix --- Client/game_sa/CVehicleSA.cpp | 4 ++-- Client/game_sa/gamesa_renderware.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Client/game_sa/CVehicleSA.cpp b/Client/game_sa/CVehicleSA.cpp index 9c18ec64ce3..14d64c82e01 100644 --- a/Client/game_sa/CVehicleSA.cpp +++ b/Client/game_sa/CVehicleSA.cpp @@ -161,8 +161,8 @@ static void __fastcall SetComponentVisibility(CVehicleSAInterface* vehicleInterf 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*) + 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; diff --git a/Client/game_sa/gamesa_renderware.h b/Client/game_sa/gamesa_renderware.h index 9c97d762203..148b8f4a172 100644 --- a/Client/game_sa/gamesa_renderware.h +++ b/Client/game_sa/gamesa_renderware.h @@ -108,7 +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); +using RwFrameForAllChildren_t = RwFrame*(__cdecl*)(RwFrame * frame, void* callback, void* data); /*****************************************************************************/ /** Renderware function mappings **/