Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Client/game_sa/CGameSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ CGameSA::CGameSA()
CFireSA::StaticSetHooks();
CPtrNodeSingleLinkPoolSA::StaticSetHooks();
CVehicleAudioSettingsManagerSA::StaticSetHooks();
CVehicleModelInfoSAInterface::StaticSetHooks();
}
catch (const std::bad_alloc& e)
{
Expand Down Expand Up @@ -573,6 +574,11 @@ void CGameSA::SetBlurLevel(unsigned char ucLevel)
MemPutFast<unsigned char>(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
Expand Down
4 changes: 4 additions & 0 deletions Client/game_sa/CGameSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;

Expand Down
5 changes: 0 additions & 5 deletions Client/game_sa/CModelInfoSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2178,8 +2178,3 @@ bool CModelInfoSA::ForceUnload()

return true;
}

bool CVehicleModelInfoSAInterface::IsComponentDamageable(int componentIndex) const
{
return pVisualInfo->m_maskComponentDamagable & (1 << componentIndex);
}
75 changes: 51 additions & 24 deletions Client/game_sa/CModelInfoSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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");

Expand Down
148 changes: 148 additions & 0 deletions Client/game_sa/CVehicleModelInfoSA.cpp
Original file line number Diff line number Diff line change
@@ -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<CClumpModelInfoSAInterface*>(this)->SetClump(clump);
SetAtomicRenderCallbacks();
static_cast<CClumpModelInfoSAInterface*>(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<VehicleMaterialCBData*>(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<RpClump*>(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);
}

void CVehicleModelInfoSAInterface::SetVehicleDirtLevelFixEnabled(bool enabled) noexcept
{
fixVehicleDirtLevel = enabled;
}

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);
}
2 changes: 1 addition & 1 deletion Client/game_sa/CVehicleSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions Client/game_sa/gamesa_renderware.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 **/
Expand Down Expand Up @@ -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 **/
Expand Down
4 changes: 3 additions & 1 deletion Client/game_sa/gamesa_renderware.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ void InitRwFunctions()
RpHAnimIDGetIndex = (RpHAnimIDGetIndex_t)0x7C51A0;
RpHAnimHierarchyGetMatrixArray = (RpHAnimHierarchyGetMatrixArray_t)0x7C5120;
RtQuatRotate = (RtQuatRotate_t)0x7EB7C0;

RpMaterialListDeinitialize = reinterpret_cast<RpMaterialListDeinitialize_t>(0x74E150);
RpGeometryForAllMaterials = reinterpret_cast<RpGeometryForAllMaterials_t>(0x74C790);

SetTextureDict = (SetTextureDict_t)0x007319C0;
LoadClumpFile = (LoadClumpFile_t)0x005371F0;
LoadModel = (LoadModel_t)0x0040C6B0;
Expand Down
9 changes: 9 additions & 0 deletions Client/mods/deathmatch/logic/CClientGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
Loading
Loading