From 844ced3402d728565ac4140ca9c48a8062021e0d Mon Sep 17 00:00:00 2001 From: FileEX Date: Thu, 13 Nov 2025 22:37:04 +0100 Subject: [PATCH 1/2] Fix setVehicleDirtLevel --- Client/game_sa/CGameSA.cpp | 6 + Client/game_sa/CGameSA.h | 4 + Client/game_sa/CModelInfoSA.cpp | 5 - Client/game_sa/CModelInfoSA.h | 75 ++++++--- Client/game_sa/CVehicleModelInfoSA.cpp | 148 ++++++++++++++++++ Client/game_sa/CVehicleSA.h | 2 +- Client/game_sa/gamesa_renderware.h | 4 + Client/game_sa/gamesa_renderware.hpp | 4 +- Client/mods/deathmatch/logic/CClientGame.cpp | 9 ++ .../logic/CClientVehicleManager.cpp | 22 +++ .../deathmatch/logic/CClientVehicleManager.h | 1 + .../mods/deathmatch/logic/CPacketHandler.cpp | 1 + Client/sdk/game/CGame.h | 3 + Client/sdk/game/RenderWare.h | 47 +++++- Server/mods/deathmatch/logic/CGame.cpp | 2 + .../logic/packets/CMapInfoPacket.cpp | 1 + Shared/mods/deathmatch/logic/Enums.cpp | 1 + Shared/mods/deathmatch/logic/Enums.h | 1 + Shared/sdk/net/SyncStructures.h | 2 + 19 files changed, 304 insertions(+), 34 deletions(-) create mode 100644 Client/game_sa/CVehicleModelInfoSA.cpp diff --git a/Client/game_sa/CGameSA.cpp b/Client/game_sa/CGameSA.cpp index 0313327c0b..3d876d761f 100644 --- a/Client/game_sa/CGameSA.cpp +++ b/Client/game_sa/CGameSA.cpp @@ -251,6 +251,7 @@ CGameSA::CGameSA() CFireSA::StaticSetHooks(); CPtrNodeSingleLinkPoolSA::StaticSetHooks(); CVehicleAudioSettingsManagerSA::StaticSetHooks(); + CVehicleModelInfoSAInterface::StaticSetHooks(); } catch (const std::bad_alloc& e) { @@ -573,6 +574,11 @@ void CGameSA::SetBlurLevel(unsigned char ucLevel) MemPutFast(0x8D5104, ucLevel); // CPostEffects::m_SpeedFXAlpha } +void CGameSA::SetVehiclesVannilaDirtEnabled(bool isEnabled) const noexcept +{ + CVehicleModelInfoSAInterface::SetVehicleDirtLevelFixEnabled(isEnabled); +} + unsigned long CGameSA::GetMinuteDuration() { return *(unsigned long*)0xB7015C; // CClock::ms_nMillisecondsPerGameMinute diff --git a/Client/game_sa/CGameSA.h b/Client/game_sa/CGameSA.h index 7ef64b44c4..89634a2064 100644 --- a/Client/game_sa/CGameSA.h +++ b/Client/game_sa/CGameSA.h @@ -262,6 +262,9 @@ class CGameSA : public CGame bool IsVehicleBurnExplosionsEnabled() const noexcept override { return m_isVehicleBurnExplosionsEnabled; } void SetVehicleBurnExplosionsEnabled(bool isEnabled) override; + bool IsVehiclesVannilaDirtEnabled() const noexcept override { return m_isVehiclesVannilaDirtEnabled; } + void SetVehiclesVannilaDirtEnabled(bool isEnabled) const noexcept override; + unsigned long GetMinuteDuration(); void SetMinuteDuration(unsigned long ulTime); @@ -396,6 +399,7 @@ class CGameSA : public CGame bool m_isExtendedWaterCannonsEnabled{false}; bool m_isIgnoreFireStateEnabled{false}; bool m_isVehicleBurnExplosionsEnabled{true}; + bool m_isVehiclesVannilaDirtEnabled{false}; static unsigned int& ClumpOffset; diff --git a/Client/game_sa/CModelInfoSA.cpp b/Client/game_sa/CModelInfoSA.cpp index 927d645be9..030f7de5e6 100644 --- a/Client/game_sa/CModelInfoSA.cpp +++ b/Client/game_sa/CModelInfoSA.cpp @@ -2178,8 +2178,3 @@ bool CModelInfoSA::ForceUnload() return true; } - -bool CVehicleModelInfoSAInterface::IsComponentDamageable(int componentIndex) const -{ - return pVisualInfo->m_maskComponentDamagable & (1 << componentIndex); -} diff --git a/Client/game_sa/CModelInfoSA.h b/Client/game_sa/CModelInfoSA.h index b778f808be..0e50eeefe1 100644 --- a/Client/game_sa/CModelInfoSA.h +++ b/Client/game_sa/CModelInfoSA.h @@ -247,6 +247,9 @@ struct CTimeInfoSAInterface class CClumpModelInfoSAInterface : public CBaseModelInfoSAInterface { public: + void SetClump(RpClump* clump) { ((void(__thiscall*)(CClumpModelInfoSAInterface*, RpClump*))0x4C4F70)(this, clump); } + void SetFrameIds(RwObjectNameIdAssocation* componentList) { ((void(__thiscall*)(CClumpModelInfoSAInterface*, RwObjectNameIdAssocation*))0x4C5460)(this, componentList); } + union { char* m_animFileName; @@ -286,24 +289,51 @@ class CVehicleModelVisualInfoSAInterface // Not sure about this name. }; static_assert(sizeof(CVehicleModelVisualInfoSAInterface) == 0x314, "Invalid size of CVehicleModelVisualInfoSAInterface class"); +// Defines from CVehicleModelInfo.h +#define MAX_PER_VEHICLE_MATERIALS 48 +#define MAX_PER_VEHICLE_MATERIALS2 32 +#define MAX_PER_VEHICLE_MATERIALS3 16 +#define MAX_PER_VEHICLE_MATERIALS4 16 +#define MAX_PER_VEHICLE_DIRT_MATERIALS 32 +#define NUM_DIRT_LEVELS 16 +#define MAX_POSSIBLE_COLOURS 8 +#define MAX_POSSIBLE_UPGRADES 18 +#define MAX_NUM_REMAPS 4 +#define NUM_DIRT_LEVELS 16 +#define CUSTOM_PLATE_NUM_CHARS (8) + class CVehicleModelInfoSAInterface : public CClumpModelInfoSAInterface { +private: + void SetClump(RpClump* clump); + void SetAtomicRenderCallbacks(); + void SetRenderPipelines(); + void PreprocessHierarchy(); + void ReduceMaterialsInVehicle(); + void SetCarCustomPlate(); + + static void SetDirtTextures(CVehicleModelInfoSAInterface* model, int dirtLevel); + static bool GetEditableMaterialListCB(RpAtomic* atomic, void* data); + void FindEditableMaterialList(); + public: + static void StaticSetHooks(); + static void SetVehicleDirtLevelFixEnabled(bool enabled) noexcept; + bool IsComponentDamageable(int componentIndex) const; - RpMaterial* pPlateMaterial; - char plateText[8]; - std::uint8_t field_30; - std::uint8_t plateType; + RpMaterial* pPlateMaterial; // pointer to material containing custom plate texture, NULL if no customizable plate present + char plateText[CUSTOM_PLATE_NUM_CHARS+1]; + std::uint8_t plateType; // custom design: SF, Vegas, LA or default char gameName[8]; std::uint8_t field_3A[2]; - std::uint32_t vehicleType; + std::uint32_t vehicleType; // VehicleClass enum float fWheelSizeFront; float fWheelSizeRear; std::int16_t wheelModelID; std::int16_t handlingID; std::uint8_t numDoors; - std::uint8_t vehicleClass; + std::uint8_t inList; std::uint8_t vehicleFlags; std::uint8_t wheelUpgradeClass; std::uint8_t timesUsed; @@ -312,24 +342,21 @@ class CVehicleModelInfoSAInterface : public CClumpModelInfoSAInterface std::uint32_t componentRules; float bikeSteeringAngle; CVehicleModelVisualInfoSAInterface* pVisualInfo; // vehicleStruct - std::uint8_t field_60[464]; - RpMaterial** m_dirtMaterials; - std::size_t m_numDirtMaterials; - RpMaterial* m_staticDirtMaterials[30]; - std::uint8_t primColors[8]; - std::uint8_t secondColors[8]; - std::uint8_t treeColors[8]; - std::uint8_t fourColors[8]; - std::uint8_t numOfColorVariations; - std::uint8_t lastColorVariation; - std::uint8_t primColor; - std::uint8_t secColor; - std::uint8_t tertColor; - std::uint8_t quatColor; - std::uint8_t upgrades[36]; - std::uint8_t anRemapTXDs[8]; - std::uint8_t field_302[2]; - void* pAnimBlock; // CAnimBlock* + + // Arrays of materials to set the colour of when choosing car colours + RpMaterial* m_primaryColourMaterials[MAX_PER_VEHICLE_MATERIALS+1]; + RpMaterial* m_secondaryColourMaterials[MAX_PER_VEHICLE_MATERIALS2 + 1]; + RpMaterial* m_treeColourMaterials[MAX_PER_VEHICLE_MATERIALS3 + 1]; + RpMaterial* m_fourColourMaterials[MAX_PER_VEHICLE_MATERIALS4 + 1]; + + RpMaterial* m_dirtMaterials[MAX_PER_VEHICLE_DIRT_MATERIALS]; + std::uint8_t colourVariations[4][MAX_POSSIBLE_COLOURS]; + std::uint8_t numOfColourVariations; + std::uint8_t lastUsedColourVariation; + std::uint8_t lastColours[4]; + std::uint16_t upgrades[MAX_POSSIBLE_UPGRADES]; + std::uint16_t anRemapTXDs[MAX_NUM_REMAPS]; + std::uint32_t animFileIndex; }; static_assert(sizeof(CVehicleModelInfoSAInterface) == 0x308, "Invalid size of CVehicleModelInfoSAInterface class"); diff --git a/Client/game_sa/CVehicleModelInfoSA.cpp b/Client/game_sa/CVehicleModelInfoSA.cpp new file mode 100644 index 0000000000..e16ebb6edc --- /dev/null +++ b/Client/game_sa/CVehicleModelInfoSA.cpp @@ -0,0 +1,148 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: game_sa/CVehicleModelInfoSA.cpp + * PURPOSE: Vehicle model info class + * + * Multi Theft Auto is available from https://www.multitheftauto.com/ + * + *****************************************************************************/ + +#include "StdInc.h" +#include "CModelInfoSA.h" +#include "gamesa_renderware.h" +#include "enums/VehicleClass.h" + +#define NUM_DIRT_TEXTURES 16 +#define NUM_MAX_DESCS 12 + +static RwTexture** ms_aDirtTextures = *(RwTexture*(*)[NUM_DIRT_TEXTURES])0xC02BD0; +static RwObjectNameIdAssocation** ms_vehicleDescs = *(RwObjectNameIdAssocation*(*)[NUM_MAX_DESCS])0x8A7740; + +static bool fixVehicleDirtLevel = false; + +struct VehicleMaterialCBData +{ + CVehicleModelInfoSAInterface* modelInfo; + int numDirt; +}; + +void CVehicleModelInfoSAInterface::SetAtomicRenderCallbacks() +{ + ((void(__thiscall*)(CVehicleModelInfoSAInterface*))0x4C7B10)(this); +} + +void CVehicleModelInfoSAInterface::SetRenderPipelines() +{ + ((void(__thiscall*)(CVehicleModelInfoSAInterface*))0x4C8900)(this); +} + +void CVehicleModelInfoSAInterface::PreprocessHierarchy() +{ + ((void(__thiscall*)(CVehicleModelInfoSAInterface*))0x4C8E60)(this); +} + +void CVehicleModelInfoSAInterface::SetClump(RpClump* clump) +{ + // Call CPool_CVehicleStruct::allocate & CVehicleModelInfo::CVehicleStructure::CVehicleStructure constructor + auto* vehicleStruct = ((CVehicleModelVisualInfoSAInterface * (__cdecl*)())0x4C9570)(); + pVisualInfo = vehicleStruct ? ((CVehicleModelVisualInfoSAInterface * (__thiscall*)(CVehicleModelVisualInfoSAInterface*))0x4C8D60)(vehicleStruct) : nullptr; + + static_cast(this)->SetClump(clump); + SetAtomicRenderCallbacks(); + static_cast(this)->SetFrameIds(ms_vehicleDescs[vehicleType]); + SetRenderPipelines(); + PreprocessHierarchy(); + ReduceMaterialsInVehicle(); + + if (fixVehicleDirtLevel) + FindEditableMaterialList(); + + SetCarCustomPlate(); +} + +void CVehicleModelInfoSAInterface::ReduceMaterialsInVehicle() +{ + ((void(__thiscall*)(CVehicleModelInfoSAInterface*))0x4C8BD0)(this); +} + +void CVehicleModelInfoSAInterface::SetCarCustomPlate() +{ + ((void(__thiscall*)(CVehicleModelInfoSAInterface*))0x4C9450)(this); +} + +void CVehicleModelInfoSAInterface::SetDirtTextures(CVehicleModelInfoSAInterface* model, int dirtLevel) +{ + if (!fixVehicleDirtLevel) + return; + + for (int i = 0; i < NUM_DIRT_TEXTURES; ++i) + { + if (!model->m_dirtMaterials[i]) + continue; + + RpMaterialSetTexture(model->m_dirtMaterials[i], ms_aDirtTextures[dirtLevel]); + } +} + +bool CVehicleModelInfoSAInterface::GetEditableMaterialListCB(RpAtomic* atomic, void* data) +{ + RpGeometryForAllMaterials(atomic->geometry, + +[](RpMaterial* material, void* cbData) -> RpMaterial* + { + auto* materialData = static_cast(cbData); + RwTexture* tex = material->texture; + if (tex && std::strcmp(tex->name, "vehiclegrunge256") == 0) + materialData->modelInfo->m_dirtMaterials[materialData->numDirt++] = material; + + return material; + }, + data); + + return true; +} + +void CVehicleModelInfoSAInterface::FindEditableMaterialList() +{ + VehicleMaterialCBData cbData{}; + cbData.modelInfo = this; + cbData.numDirt = 0; + + RpClumpForAllAtomics(reinterpret_cast(pRwObject), GetEditableMaterialListCB, &cbData); + for (int i = 0; i < pVisualInfo->m_numExtras; i++) + GetEditableMaterialListCB(pVisualInfo->m_pExtra[i], &cbData); + + lastColours[0] = 255; + lastColours[1] = 255; + lastColours[2] = 255; + lastColours[3] = 255; +} + +bool CVehicleModelInfoSAInterface::IsComponentDamageable(int componentIndex) const +{ + return pVisualInfo->m_maskComponentDamagable & (1 << componentIndex); +} + +static void CVehicleModelInfo__SetClump() +{ + _asm + { + mov eax, [esp+8] + push eax + call CVehicleModelInfoSAInterface::SetClump + add esp, 4 + retn 4 + } +} + +void CVehicleModelInfoSAInterface::StaticSetHooks() +{ + HookInstall(0x4C95C0, CVehicleModelInfo__SetClump); + HookInstallCall(0x6D0E7E, (DWORD)CVehicleModelInfoSAInterface::SetDirtTextures); +} + +void CVehicleModelInfoSAInterface::SetVehicleDirtLevelFixEnabled(bool enabled) noexcept +{ + fixVehicleDirtLevel = enabled; +} diff --git a/Client/game_sa/CVehicleSA.h b/Client/game_sa/CVehicleSA.h index 19f179cc85..404674195a 100644 --- a/Client/game_sa/CVehicleSA.h +++ b/Client/game_sa/CVehicleSA.h @@ -412,7 +412,7 @@ class CVehicleSAInterface : public CPhysicalSAInterface float m_steeringLeftRight; // 1424 - VehicleClass m_vehicleClass; + VehicleClass m_vehicleClass; // should be 4 bytes (TODO) uint32_t m_vehicleSubClass; int16_t m_peviousRemapTxd; diff --git a/Client/game_sa/gamesa_renderware.h b/Client/game_sa/gamesa_renderware.h index 4bfb5b4332..049c512385 100644 --- a/Client/game_sa/gamesa_renderware.h +++ b/Client/game_sa/gamesa_renderware.h @@ -106,6 +106,8 @@ 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); +typedef RpMaterials*(__cdecl* RpMaterialListDeinitialize_t)(RpMaterials* matList); +typedef RpGeometry*(__cdecl* RpGeometryForAllMaterials_t)(RpGeometry* geom, void* callback, void* data); /*****************************************************************************/ /** Renderware function mappings **/ @@ -196,6 +198,8 @@ 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(RpMaterialListDeinitialize_t RpMaterialListDeinitialize, (RpMaterialListDeinitialize_t)0xDEAD) +RWFUNC(RpGeometryForAllMaterials_t RpGeometryForAllMaterials, (RpGeometryForAllMaterials_t)0xDEAD) /*****************************************************************************/ /** GTA function definitions and mappings **/ diff --git a/Client/game_sa/gamesa_renderware.hpp b/Client/game_sa/gamesa_renderware.hpp index 1561333a14..4f8cebbc36 100644 --- a/Client/game_sa/gamesa_renderware.hpp +++ b/Client/game_sa/gamesa_renderware.hpp @@ -89,7 +89,9 @@ void InitRwFunctions() RpHAnimIDGetIndex = (RpHAnimIDGetIndex_t)0x7C51A0; RpHAnimHierarchyGetMatrixArray = (RpHAnimHierarchyGetMatrixArray_t)0x7C5120; RtQuatRotate = (RtQuatRotate_t)0x7EB7C0; - + RpMaterialListDeinitialize = reinterpret_cast(0x74E150); + RpGeometryForAllMaterials = reinterpret_cast(0x74C790); + SetTextureDict = (SetTextureDict_t)0x007319C0; LoadClumpFile = (LoadClumpFile_t)0x005371F0; LoadModel = (LoadModel_t)0x0040C6B0; diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 7632881bad..29b531a800 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -6096,6 +6096,12 @@ bool CClientGame::SetWorldSpecialProperty(const WorldSpecialProperty property, c case WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART: SetVehicleEngineAutoStartEnabled(enabled); break; + case WorldSpecialProperty::VEHICLES_VANILLA_DIRT: + { + g_pGame->SetVehiclesVannilaDirtEnabled(enabled); + m_pManager->GetVehicleManager()->RecreateStreamedVehiclesRwObject(); + break; + } default: return false; } @@ -6144,6 +6150,8 @@ bool CClientGame::IsWorldSpecialProperty(const WorldSpecialProperty property) return g_pGame->IsVehicleBurnExplosionsEnabled(); case WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART: return IsVehicleEngineAutoStartEnabled(); + case WorldSpecialProperty::VEHICLES_VANILLA_DIRT: + return g_pGame->IsVehiclesVannilaDirtEnabled(); } return false; @@ -6945,6 +6953,7 @@ void CClientGame::ResetWorldProperties(const ResetWorldPropsInfo& resetPropsInfo m_pVehicleManager->SetSpawnFlyingComponentEnabled(true); g_pGame->SetVehicleBurnExplosionsEnabled(true); SetVehicleEngineAutoStartEnabled(true); + g_pGame->SetVehiclesVannilaDirtEnabled(false); } // Reset all setWorldProperty to default diff --git a/Client/mods/deathmatch/logic/CClientVehicleManager.cpp b/Client/mods/deathmatch/logic/CClientVehicleManager.cpp index f1d32978c6..4e44ef5f21 100644 --- a/Client/mods/deathmatch/logic/CClientVehicleManager.cpp +++ b/Client/mods/deathmatch/logic/CClientVehicleManager.cpp @@ -792,6 +792,28 @@ void CClientVehicleManager::RestreamVehicleUpgrades(unsigned short usModel) } } +void CClientVehicleManager::RecreateStreamedVehiclesRwObject() +{ + std::unordered_set modelsToReload{}; + + for (auto& vehicle : m_List) + { + if (!vehicle->IsStreamedIn()) + continue; + + modelsToReload.insert(vehicle->GetModel()); + } + + for (const auto& model : modelsToReload) + { + // Stream out all vehicles of this model to remove ped from it and prevent crash + RestreamVehicles(model); + + // Remove model from streaming to DeleteRwObject + g_pGame->GetStreaming()->RemoveModel(model); + } +} + void CClientVehicleManager::ResetNotControlledRotors(bool engineAutoStart) { // Reset rotors to original or custom state for loaded vehicles without controller diff --git a/Client/mods/deathmatch/logic/CClientVehicleManager.h b/Client/mods/deathmatch/logic/CClientVehicleManager.h index c9d14d848d..0f4981556d 100644 --- a/Client/mods/deathmatch/logic/CClientVehicleManager.h +++ b/Client/mods/deathmatch/logic/CClientVehicleManager.h @@ -58,6 +58,7 @@ class CClientVehicleManager void RestreamVehicles(unsigned short usModel); void RestreamAllVehicles(); void RestreamVehicleUpgrades(unsigned short usModel); + void RecreateStreamedVehiclesRwObject(); std::vector::const_iterator IterBegin() { return m_List.begin(); }; std::vector::const_iterator IterEnd() { return m_List.end(); }; diff --git a/Client/mods/deathmatch/logic/CPacketHandler.cpp b/Client/mods/deathmatch/logic/CPacketHandler.cpp index 339110ff31..19129c7221 100644 --- a/Client/mods/deathmatch/logic/CPacketHandler.cpp +++ b/Client/mods/deathmatch/logic/CPacketHandler.cpp @@ -2420,6 +2420,7 @@ void CPacketHandler::Packet_MapInfo(NetBitStreamInterface& bitStream) g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::FLYINGCOMPONENTS, wsProps.data.flyingcomponents); g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS, wsProps.data.vehicleburnexplosions); g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART, wsProps.data.vehicleEngineAutoStart); + g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::VEHICLES_VANILLA_DIRT, wsProps.data.vehiclesVanillaDirt); float fJetpackMaxHeight = 100; if (!bitStream.Read(fJetpackMaxHeight)) diff --git a/Client/sdk/game/CGame.h b/Client/sdk/game/CGame.h index fbaba31d4b..12461d37d6 100644 --- a/Client/sdk/game/CGame.h +++ b/Client/sdk/game/CGame.h @@ -243,6 +243,9 @@ class __declspec(novtable) CGame virtual bool IsVehicleBurnExplosionsEnabled() const noexcept = 0; virtual void SetVehicleBurnExplosionsEnabled(bool isEnabled) = 0; + virtual bool IsVehiclesVannilaDirtEnabled() const noexcept = 0; + virtual void SetVehiclesVannilaDirtEnabled(bool isEnabled) const noexcept = 0; + virtual CWeapon* CreateWeapon() = 0; virtual CWeaponStat* CreateWeaponStat(eWeaponType weaponType, eWeaponSkill weaponSkill) = 0; diff --git a/Client/sdk/game/RenderWare.h b/Client/sdk/game/RenderWare.h index d43099d0cc..471817bfa3 100644 --- a/Client/sdk/game/RenderWare.h +++ b/Client/sdk/game/RenderWare.h @@ -41,7 +41,7 @@ typedef void RpWorld; typedef struct RpClump RpClump; typedef struct RwRaster RwRaster; typedef struct RpMaterialLighting RpMaterialLighting; -typedef struct RpMaterialList RpMaterialList; +typedef struct RpMaterialList RpMaterialList; // RpMaterials typedef struct RpMaterial RpMaterial; typedef struct RpTriangle RpTriangle; typedef struct RwTextureCoordinates RwTextureCoordinates; @@ -396,8 +396,8 @@ struct RpMaterial struct RpMaterials { RpMaterial** materials; - int entries; - int unknown; + int entries; // numMaterials + int space; // space }; struct RpTriangle { @@ -432,6 +432,47 @@ struct RpGeometry RpMorphTarget* morph_target; }; +struct vehicleComponentFlags +{ + std::uint8_t isVehStructPart : 1; + std::uint8_t isDamageable : 1; + std::uint8_t isWheel : 1; + std::uint8_t isDummy : 1; + std::uint8_t isDoor : 1; + std::uint8_t compIsLeft : 1; + std::uint8_t compIsRight : 1; + std::uint8_t compIsFront : 1; + + std::uint8_t compIsRear : 1; + std::uint8_t isExtra : 1; + std::uint8_t compHasAlpha : 1; + std::uint8_t compIsGlass : 1; + std::uint8_t compCull : 1; + std::uint8_t compIsRearDoor : 1; + std::uint8_t compIsFrontDoor : 1; + std::uint8_t compSwinging : 1; + + std::uint8_t isMainWheel : 1; + std::uint8_t isUpgrade : 1; + std::uint8_t compDisableReflections : 1; + std::uint8_t trainFrontBogie : 1; + std::uint8_t trainRearBogie : 1; + std::uint8_t compRenderAlways : 1; + std::uint8_t unk : 6; +}; + +struct RwObjectNameIdAssocation +{ + char* name; + std::uint32_t hierarchyId; + + union + { + std::uint32_t flags; + vehicleComponentFlags compFlags; + }; +}; + inline auto rwObjectGetParent(RwObject* o) { return (RwObject*)o->parent; } diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index afac77f2a4..51431e75d6 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -266,6 +266,7 @@ CGame::CGame() : m_FloodProtect(4, 30000, 30000) // Max of 4 connecti m_WorldSpecialProps[WorldSpecialProperty::FLYINGCOMPONENTS] = true; m_WorldSpecialProps[WorldSpecialProperty::VEHICLEBURNEXPLOSIONS] = true; m_WorldSpecialProps[WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART] = true; + m_WorldSpecialProps[WorldSpecialProperty::VEHICLES_VANILLA_DIRT] = false; m_JetpackWeapons[WEAPONTYPE_MICRO_UZI] = true; m_JetpackWeapons[WEAPONTYPE_TEC9] = true; @@ -4460,6 +4461,7 @@ void CGame::ResetWorldProperties(const ResetWorldPropsInfo& resetPropsInfo) g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::FLYINGCOMPONENTS, true); g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS, true); g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART, true); + g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLES_VANILLA_DIRT, false); } // Reset all weather stuff like heat haze, wind velocity etc diff --git a/Server/mods/deathmatch/logic/packets/CMapInfoPacket.cpp b/Server/mods/deathmatch/logic/packets/CMapInfoPacket.cpp index aceac1b129..50926bb590 100644 --- a/Server/mods/deathmatch/logic/packets/CMapInfoPacket.cpp +++ b/Server/mods/deathmatch/logic/packets/CMapInfoPacket.cpp @@ -192,6 +192,7 @@ bool CMapInfoPacket::Write(NetBitStreamInterface& BitStream) const wsProps.data.flyingcomponents = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::FLYINGCOMPONENTS); wsProps.data.vehicleburnexplosions = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS); wsProps.data.vehicleEngineAutoStart = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART); + wsProps.data.vehiclesVanillaDirt = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLES_VANILLA_DIRT); BitStream.Write(&wsProps); BitStream.Write(m_fJetpackMaxHeight); diff --git a/Shared/mods/deathmatch/logic/Enums.cpp b/Shared/mods/deathmatch/logic/Enums.cpp index 8bb99db974..ada7a9e670 100644 --- a/Shared/mods/deathmatch/logic/Enums.cpp +++ b/Shared/mods/deathmatch/logic/Enums.cpp @@ -120,6 +120,7 @@ ADD_ENUM(WorldSpecialProperty::IGNOREFIRESTATE, "ignorefirestate") ADD_ENUM(WorldSpecialProperty::FLYINGCOMPONENTS, "flyingcomponents") ADD_ENUM(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS, "vehicleburnexplosions") ADD_ENUM(WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART, "vehicle_engine_autostart") +ADD_ENUM(WorldSpecialProperty::VEHICLES_VANILLA_DIRT, "vehicles_vanilla_dirt") IMPLEMENT_ENUM_CLASS_END("world-special-property") IMPLEMENT_ENUM_BEGIN(ePacketID) diff --git a/Shared/mods/deathmatch/logic/Enums.h b/Shared/mods/deathmatch/logic/Enums.h index 884bb559f5..94bd51376b 100644 --- a/Shared/mods/deathmatch/logic/Enums.h +++ b/Shared/mods/deathmatch/logic/Enums.h @@ -97,6 +97,7 @@ enum class WorldSpecialProperty FLYINGCOMPONENTS, VEHICLEBURNEXPLOSIONS, VEHICLE_ENGINE_AUTOSTART, + VEHICLES_VANILLA_DIRT, }; DECLARE_ENUM_CLASS(WorldSpecialProperty); diff --git a/Shared/sdk/net/SyncStructures.h b/Shared/sdk/net/SyncStructures.h index c30cf4ce50..8174ae2474 100644 --- a/Shared/sdk/net/SyncStructures.h +++ b/Shared/sdk/net/SyncStructures.h @@ -2015,6 +2015,7 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure bool flyingcomponents : 1; bool vehicleburnexplosions : 1; bool vehicleEngineAutoStart : 1; + bool vehiclesVanillaDirt : 1; } data; // Add new ones in separate structs @@ -2042,6 +2043,7 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure data.flyingcomponents = true; data.vehicleburnexplosions = true; data.vehicleEngineAutoStart = true; + data.vehiclesVanillaDirt = false; } }; From 276c0368451f85c7679633051be3bc3b98534727 Mon Sep 17 00:00:00 2001 From: FileEX Date: Thu, 13 Nov 2025 22:46:23 +0100 Subject: [PATCH 2/2] Update CVehicleModelInfoSA.cpp --- Client/game_sa/CVehicleModelInfoSA.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Client/game_sa/CVehicleModelInfoSA.cpp b/Client/game_sa/CVehicleModelInfoSA.cpp index e16ebb6edc..e5e8b3d12b 100644 --- a/Client/game_sa/CVehicleModelInfoSA.cpp +++ b/Client/game_sa/CVehicleModelInfoSA.cpp @@ -124,6 +124,11 @@ bool CVehicleModelInfoSAInterface::IsComponentDamageable(int componentIndex) con return pVisualInfo->m_maskComponentDamagable & (1 << componentIndex); } +void CVehicleModelInfoSAInterface::SetVehicleDirtLevelFixEnabled(bool enabled) noexcept +{ + fixVehicleDirtLevel = enabled; +} + static void CVehicleModelInfo__SetClump() { _asm @@ -141,8 +146,3 @@ void CVehicleModelInfoSAInterface::StaticSetHooks() HookInstall(0x4C95C0, CVehicleModelInfo__SetClump); HookInstallCall(0x6D0E7E, (DWORD)CVehicleModelInfoSAInterface::SetDirtTextures); } - -void CVehicleModelInfoSAInterface::SetVehicleDirtLevelFixEnabled(bool enabled) noexcept -{ - fixVehicleDirtLevel = enabled; -}