diff --git a/Client/game_sa/CModelInfoSA.h b/Client/game_sa/CModelInfoSA.h index b261bcc04a..971bd6957c 100644 --- a/Client/game_sa/CModelInfoSA.h +++ b/Client/game_sa/CModelInfoSA.h @@ -14,6 +14,7 @@ #include #include #include "CRenderWareSA.h" +#include "game/RenderWare.h" class CPedModelInfoSA; class CPedModelInfoSAInterface; @@ -231,6 +232,11 @@ class CBaseModelInfoSAInterface // +726 = Word array as referenced in CVehicleModelInfo::GetVehicleUpgrade(int) // +762 = Array of WORD containing something relative to paintjobs // +772 = Anim file index + + void Shutdown() + { + ((void(*)())VFTBL->Shutdown)(); + } }; static_assert(sizeof(CBaseModelInfoSAInterface) == 0x20, "Invalid size for CBaseModelInfoSAInterface"); @@ -259,53 +265,66 @@ class CTimeModelInfoSAInterface : public CBaseModelInfoSAInterface CTimeInfoSAInterface timeInfo; }; +class CVehicleModelUpgradePosnDesc +{ + CVector m_vPosition; + RtQuat m_vRotation; + int m_iParentId; +}; + class CVehicleModelVisualInfoSAInterface // Not sure about this name. If somebody knows more, please change { public: - CVector vecDummies[15]; - char m_sUpgrade[18]; + CVector vecDummies[15]; + CVehicleModelUpgradePosnDesc m_sUpgrade[18]; + RpAtomic* m_pExtra[6]; + std::uint8_t m_numExtras; + std::uint8_t _pad[3]; + int m_maskComponentDamagable; }; -class CVehicleModelInfoSAInterface : public CBaseModelInfoSAInterface +class CVehicleModelInfoSAInterface : public CClumpModelInfoSAInterface { public: - uint32 pad1; // +32 - RpMaterial* pPlateMaterial; // +36 + RpMaterial* pPlateMaterial; char plateText[8]; - char pad[2]; + std::uint8_t field_30; + std::uint8_t plateType; char gameName[8]; - char pad2[2]; - unsigned int uiVehicleType; + std::uint8_t field_3A[2]; + std::uint32_t vehicleType; float fWheelSizeFront; float fWheelSizeRear; - short sWheelModel; - short sHandlingID; - byte ucNumDoors; - byte ucVehicleList; - byte ucVehicleFlags; - byte ucWheelUpgradeClass; - byte ucTimesUsed; - short sVehFrequency; - unsigned int uiComponentRules; - float fSteeringAngle; - CVehicleModelVisualInfoSAInterface* pVisualInfo; // +92 - char pad3[464]; - char pDirtMaterial[64]; // *RwMaterial - char pad4[64]; - char primColors[8]; - char secondColors[8]; - char treeColors[8]; - char fourColors[8]; - unsigned char ucNumOfColorVariations; - unsigned char ucLastColorVariation; - unsigned char ucPrimColor; - unsigned char ucSecColor; - unsigned char ucTertColor; - unsigned char ucQuatColor; - char upgrades[36]; - char anRemapTXDs[8]; - char pad5[2]; - char pAnimBlock[4]; + std::int16_t wheelModelID; + std::int16_t handlingID; + std::uint8_t numDoors; + std::uint8_t vehicleClass; + std::uint8_t vehicleFlags; + std::uint8_t wheelUpgradeClass; + std::uint8_t timesUsed; + std::uint8_t field_51; + std::int16_t vehFrequency; + 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* }; class CModelInfoSA : public CModelInfo diff --git a/Client/game_sa/gamesa_renderware.h b/Client/game_sa/gamesa_renderware.h index 594c203b59..4073f8f2b2 100644 --- a/Client/game_sa/gamesa_renderware.h +++ b/Client/game_sa/gamesa_renderware.h @@ -105,6 +105,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); +typedef RpGeometry*(__cdecl* RpGeometryForAllMaterials_t)(RpGeometry* geom, void* callback, void* data); /*****************************************************************************/ /** Renderware function mappings **/ @@ -195,6 +196,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(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 a638cfede0..f52d205dda 100644 --- a/Client/game_sa/gamesa_renderware.hpp +++ b/Client/game_sa/gamesa_renderware.hpp @@ -89,7 +89,8 @@ void InitRwFunctions() RpHAnimIDGetIndex = (RpHAnimIDGetIndex_t)0x7C51A0; RpHAnimHierarchyGetMatrixArray = (RpHAnimHierarchyGetMatrixArray_t)0x7C5120; RtQuatRotate = (RtQuatRotate_t)0x7EB7C0; - + RpGeometryForAllMaterials = (RpGeometryForAllMaterials_t)0x74C790; + SetTextureDict = (SetTextureDict_t)0x007319C0; LoadClumpFile = (LoadClumpFile_t)0x005371F0; LoadModel = (LoadModel_t)0x0040C6B0; diff --git a/Client/multiplayer_sa/CMultiplayerSA_Vehicles.cpp b/Client/multiplayer_sa/CMultiplayerSA_Vehicles.cpp index 88b0b11eb8..afaa8de6f1 100644 --- a/Client/multiplayer_sa/CMultiplayerSA_Vehicles.cpp +++ b/Client/multiplayer_sa/CMultiplayerSA_Vehicles.cpp @@ -9,6 +9,12 @@ *****************************************************************************/ #include "StdInc.h" +#include "..\game_sa\gamesa_renderware.h" + +#define FUNC_CBaseModelInfo_Shutdown 0x4C4D50 +#define IN_PLACE_BUFFER_DIRT_SIZE 30 + +static RwTexture** const ms_aDirtTextures = (RwTexture**)0xC02BD0; static bool __fastcall AreVehicleDoorsUndamageable(CVehicleSAInterface* vehicle) { @@ -107,6 +113,100 @@ static void _declspec(naked) HOOK_CAEVehicleAudioEntity__Initialise() } } +static void __fastcall CVehicleModelInfo_Shutdown(CVehicleModelInfoSAInterface* mi) +{ + if (!mi) + return; + + mi->Shutdown(); + + delete[] mi->m_dirtMaterials; + mi->m_dirtMaterials = nullptr; +} + +static void SetDirtTextures(CVehicleModelInfoSAInterface* mi, std::uint32_t level) +{ + RpMaterial** materials = mi->m_numDirtMaterials > IN_PLACE_BUFFER_DIRT_SIZE ? mi->m_dirtMaterials : mi->m_staticDirtMaterials; + for (std::uint32_t i = 0; i < mi->m_numDirtMaterials; i++) + RpMaterialSetTexture(materials[i], ms_aDirtTextures[level]); +} + +#define HOOKPOS_CVehicleModelInfo_SetDirtTextures 0x5D5DBB +#define HOOKSIZE_CVehicleModelInfo_SetDirtTextures 6 +static constexpr DWORD CONTINUE_CVehicleModelInfo_SetDirtTextures = 0x5D5DE3; +static void _declspec(naked) HOOK_CVehicleModelInfo_SetDirtTextures() +{ + _asm + { + push ebx + push esi + call SetDirtTextures + add esp, 8 + + jmp CONTINUE_CVehicleModelInfo_SetDirtTextures + } +} + +static RpMaterial* GetAtomicGeometryMaterialsCB(RpMaterial* material, void* data) +{ + RwTexture* texture = material->texture; + if (!texture) + return nullptr; + + auto cbData = static_cast*>(data); + if (texture->name && std::strcmp(texture->name, "vehiclegrunge256") == 0) + cbData->push_back(material); + + return material; +} + +static bool GetEditableMaterialListCB(RpAtomic* atomic, void* data) +{ + RpGeometryForAllMaterials(atomic->geometry, &GetAtomicGeometryMaterialsCB, data); + return true; +} + +static void __fastcall FindEditableMaterialList(CVehicleModelInfoSAInterface* mi) +{ + std::vector list; + RpClumpForAllAtomics(reinterpret_cast(mi->pRwObject), &GetEditableMaterialListCB, &list); + + for (std::uint32_t i = 0; i < mi->pVisualInfo->m_numExtras; i++) + GetEditableMaterialListCB(mi->pVisualInfo->m_pExtra[i], &list); + + mi->m_numDirtMaterials = list.size(); + if (mi->m_numDirtMaterials > IN_PLACE_BUFFER_DIRT_SIZE) + { + mi->m_dirtMaterials = new RpMaterial*[mi->m_numDirtMaterials]; + std::copy(list.begin(), list.end(), mi->m_dirtMaterials); + } + else + { + mi->m_dirtMaterials = nullptr; + std::copy(list.begin(), list.end(), mi->m_staticDirtMaterials); + } + + mi->primColor = 255; + mi->secColor = 255; + mi->tertColor = 255; + mi->quatColor = 255; +} + +#define HOOKPOS_CVehicleModelInfo_SetClump 0x4C9648 +#define HOOKSIZE_CVehicleModelInfo_SetClump 24 +static constexpr DWORD CONTINUE_CVehicleModelInfo_SetClump = 0x4C9660; +static void _declspec(naked) HOOK_CVehicleModelInfo_SetClump() +{ + _asm + { + push ecx + call FindEditableMaterialList + pop ecx + + jmp CONTINUE_CVehicleModelInfo_SetClump + } +} + ////////////////////////////////////////////////////////////////////////////////////////// // // CMultiplayerSA::InitHooks_Vehicles @@ -118,4 +218,9 @@ void CMultiplayerSA::InitHooks_Vehicles() { EZHookInstall(CDamageManager__ProgressDoorDamage); EZHookInstall(CAEVehicleAudioEntity__Initialise); + + // Fix vehicle dirt level + EZHookInstall(CVehicleModelInfo_SetClump); + EZHookInstall(CVehicleModelInfo_SetDirtTextures); + MemCpy((void*)0x85C5E4, &CVehicleModelInfo_Shutdown, 4); }