Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
FileEX committed Sep 9, 2024
1 parent e024739 commit 25a207b
Show file tree
Hide file tree
Showing 13 changed files with 280 additions and 135 deletions.
92 changes: 84 additions & 8 deletions Client/game_sa/CModelInfoSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1481,41 +1481,43 @@ void CModelInfoSA::ResetAllVehiclesWheelSizes()
ms_VehicleModelDefaultWheelSizes.clear();
}

bool CModelInfoSA::SetCustomModel(RpClump* pClump)
bool CModelInfoSA::SetCustomModel(RpClump* clump)
{
if (!pClump)
if (!clump)
return false;

if (!IsLoaded())
{
// Wait for the game to eventually stream-in the model and then try to replace it (via MakeCustomModel).
m_pCustomClump = pClump;
m_pCustomClump = clump;
return true;
}

auto modelID = static_cast<std::uint16_t>(m_dwModelID);
bool success = false;

switch (GetModelType())
{
case eModelInfoType::PED:
success = pGame->GetRenderWare()->ReplacePedModel(pClump, static_cast<unsigned short>(m_dwModelID));
success = pGame->GetRenderWare()->ReplacePedModel(clump, modelID);
break;
case eModelInfoType::WEAPON:
success = pGame->GetRenderWare()->ReplaceWeaponModel(pClump, static_cast<unsigned short>(m_dwModelID));
success = pGame->GetRenderWare()->ReplaceWeaponModel(clump, modelID);
break;
case eModelInfoType::VEHICLE:
success = pGame->GetRenderWare()->ReplaceVehicleModel(pClump, static_cast<unsigned short>(m_dwModelID));
success = pGame->GetRenderWare()->ReplaceVehicleModel(clump, modelID);
break;
case eModelInfoType::ATOMIC:
case eModelInfoType::LOD_ATOMIC:
case eModelInfoType::TIME:
success = pGame->GetRenderWare()->ReplaceAllAtomicsInModel(pClump, static_cast<unsigned short>(m_dwModelID));
case eModelInfoType::CLUMP:
success = pGame->GetRenderWare()->ReplaceAllAtomicsInModel(clump, modelID, clump->object.type == RP_TYPE_CLUMP);
break;
default:
break;
}

m_pCustomClump = success ? pClump : nullptr;
m_pCustomClump = success ? clump : nullptr;
return success;
}

Expand Down Expand Up @@ -1778,6 +1780,80 @@ void CModelInfoSA::MakeClumpModel(ushort usBaseID)
CopyStreamingInfoFromModel(usBaseID);
}

static bool GetFirstAtomicCB(RpAtomic* atomic, void* data)
{
RpAtomic** firstAtomic = reinterpret_cast<RpAtomic**>(data);
if (!*firstAtomic)
*firstAtomic = atomic;

return true;
}

bool CModelInfoSA::MakeAtomicModel()
{
if (GetModelType() != eModelInfoType::CLUMP)
return false;

// Create new interface
CAtomicModelInfoSAInterface* newInterface = new CAtomicModelInfoSAInterface();

// Copy existing data to the new interface
CBaseModelInfoSAInterface* pBaseObjectInfo = ppModelInfo[m_dwModelID];
MemCpyFast(newInterface, pBaseObjectInfo, sizeof(CAtomicModelInfoSAInterface));

RpClump* clump = reinterpret_cast<RpClump*>(GetInterface()->pRwObject);
RpAtomic* firstAtomic = nullptr;
RpClumpForAllAtomics(clump, GetFirstAtomicCB, &firstAtomic);

RwFrame* frame = RwFrameCreate();
RpAtomic* cloned = RpAtomicClone(firstAtomic);
RpSetFrame(cloned, frame);

newInterface->pRwObject = nullptr;

// Call CAtomicModelInfo::SetAtomic
((void(__thiscall*)(CAtomicModelInfoSAInterface*, RpAtomic*))FUNC_CAtomicModelInfo_SetAtomic)(newInterface, cloned);

// Replace interface with new
delete ppModelInfo[m_dwModelID];
ppModelInfo[m_dwModelID] = newInterface;

RpClumpDestroy(clump);
m_dwParentID = -1;
return true;
}

bool CModelInfoSA::MakeClumpModel()
{
if (GetModelType() != eModelInfoType::ATOMIC)
return false;

// Create new interface
CClumpModelInfoSAInterface* newInterface = new CClumpModelInfoSAInterface();

// Copy existing data to the new interface
CBaseModelInfoSAInterface* pBaseObjectInfo = ppModelInfo[m_dwModelID];
MemCpyFast(newInterface, pBaseObjectInfo, sizeof(CClumpModelInfoSAInterface));
newInterface->m_nAnimFileIndex = -1;

// Create new empty clump like CFileLoader::LoadClumpFile
RpClump* parentClump = RpClumpCreate();
RpSetFrame(parentClump, RwFrameCreate());

// Set temp atomic to avoid crash because of empty clump
//RpClumpAddAtomic(parentClump, reinterpret_cast<RpAtomic*>(pBaseObjectInfo->pRwObject));

// Call CClumpModelInfo::SetClump
((void(__thiscall*)(CClumpModelInfoSAInterface*, RpClump*))FUNC_CClumpModelInfo_SetClump)(newInterface, parentClump);

// Replace interface with new
delete reinterpret_cast<CBaseModelInfoSAInterface*>(ppModelInfo[m_dwModelID]);
ppModelInfo[m_dwModelID] = newInterface;

m_dwParentID = -1;
return true;
}

void CModelInfoSA::MakeVehicleAutomobile(ushort usBaseID)
{
CVehicleModelInfoSAInterface* m_pInterface = new CVehicleModelInfoSAInterface();
Expand Down
12 changes: 11 additions & 1 deletion Client/game_sa/CModelInfoSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ static void* ARRAY_ModelInfo = *(void**)(0x403DA4 + 3);

#define VAR_CTempColModels_ModelPed1 0x968DF0

#define FUNC_CClumpModelInfo_SetClump 0x4C4F70
#define FUNC_CAtomicModelInfo_SetAtomic 0x4C4360
#define FUNC_CVisibilityPlugins_SetAtomicId 0x732230

class CBaseModelInfoSAInterface;
class CModelInfoSAInterface
{
Expand Down Expand Up @@ -253,6 +257,10 @@ class CClumpModelInfoSAInterface : public CBaseModelInfoSAInterface
};
};

class CAtomicModelInfoSAInterface : public CBaseModelInfoSAInterface
{
};

class CTimeModelInfoSAInterface : public CBaseModelInfoSAInterface
{
public:
Expand Down Expand Up @@ -428,7 +436,7 @@ class CModelInfoSA : public CModelInfo
void SetVoice(const char* szVoiceType, const char* szVoice);

// Custom collision related functions
bool SetCustomModel(RpClump* pClump) override;
bool SetCustomModel(RpClump* clump) override;
void RestoreOriginalModel() override;
void SetColModel(CColModel* pColModel) override;
void RestoreColModel() override;
Expand All @@ -450,6 +458,8 @@ class CModelInfoSA : public CModelInfo
void MakeVehicleAutomobile(ushort usBaseModelID);
void MakeTimedObjectModel(ushort usBaseModelID);
void MakeClumpModel(ushort usBaseModelID);
bool MakeClumpModel();
bool MakeAtomicModel();
void DeallocateModel(void);
unsigned int GetParentID() { return m_dwParentID; };

Expand Down
121 changes: 91 additions & 30 deletions Client/game_sa/CRenderWareSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -477,51 +477,112 @@ unsigned int CRenderWareSA::LoadAtomics(RpClump* pClump, RpAtomicContainer* pAto
}

// Replaces all atomics for a specific model
typedef struct
struct SAtomicsReplace
{
unsigned short usTxdID;
RpClump* pClump;
} SAtomicsReplacer;
bool AtomicsReplacer(RpAtomic* pAtomic, void* data)
std::uint16_t txdID;
RpClump* clump;
};

static bool ReplaceAtomicsInModelCB(RpAtomic* atomic, void* data)
{
SAtomicsReplacer* pData = reinterpret_cast<SAtomicsReplacer*>(data);
SRelatedModelInfo relatedModelInfo = {0};
relatedModelInfo.pClump = pData->pClump;
auto* cbData = reinterpret_cast<SAtomicsReplace*>(data);
SRelatedModelInfo relatedModelInfo = {};
relatedModelInfo.pClump = cbData->clump;
relatedModelInfo.bDeleteOldRwObject = true;
CFileLoader_SetRelatedModelInfoCB(pAtomic, &relatedModelInfo);

// The above function adds a reference to the model's TXD by either
// calling CAtomicModelInfo::SetAtomic or CDamagableModelInfo::SetDamagedAtomic. Remove it again.
CTxdStore_RemoveRef(pData->usTxdID);
CFileLoader_SetRelatedModelInfoCB(atomic, &relatedModelInfo);

// The above function adds a reference to the model's TXD by
// calling CDamagableModelInfo::SetDamagedAtomic. Remove it again.
CTxdStore_RemoveRef(cbData->txdID);
return true;
}

bool CRenderWareSA::ReplaceAllAtomicsInModel(RpClump* pNew, unsigned short usModelID)
struct SAtomicsClone
{
CModelInfo* pModelInfo = pGame->GetModelInfo(usModelID);
std::uint16_t modelID;
RpClump* clump;
};

if (pModelInfo)
{
RpAtomic* pOldAtomic = (RpAtomic*)pModelInfo->GetRwObject();
static bool CloneAtomicsToClumpCB(RpAtomic* atomic, void* data)
{
auto* cbData = reinterpret_cast<SAtomicsClone*>(data);

if (reinterpret_cast<RpClump*>(pOldAtomic) != pNew && !DoContainTheSameGeometry(pNew, NULL, pOldAtomic))
{
// Clone the clump that's to be replaced (FUNC_AtomicsReplacer removes the atomics from the source clump)
RpClump* pCopy = RpClumpClone(pNew);
// Clone atomic
RpAtomic* clone = RpAtomicClone(atomic);
RwFrame* frame = RpGetFrame(atomic);

// Replace the atomics
SAtomicsReplacer data;
data.usTxdID = ((CBaseModelInfoSAInterface**)ARRAY_ModelInfo)[usModelID]->usTextureDictionary;
data.pClump = pCopy;
// Set frames
RpAtomicSetFrame(clone, frame);

MemPutFast<DWORD>((DWORD*)DWORD_AtomicsReplacerModelID, usModelID);
RpClumpForAllAtomics(pCopy, AtomicsReplacer, &data);
// Add atomic to new clump
RpClumpAddAtomic(cbData->clump, clone);

// Get rid of the now empty copied clump
RpClumpDestroy(pCopy);
}
RwFrame* oldFrame = RpGetFrame(atomic);
RwFrame* newFrame = RwFrameCreate();
RpAtomicSetFrame(clone, newFrame);
RwFrameCopyMatrix(RpGetFrame(clone), oldFrame);
RwFrame* rootFrame = RpGetFrame(cbData->clump);
RwFrameAddChild(rootFrame, newFrame);

// Update atomic ID like in the CFileLoader::SetRelatedModelInfoCB
// Call CVisibilityPlugins::SetAtomicId
((int(__cdecl*)(RpAtomic*, std::uint16_t))FUNC_CVisibilityPlugins_SetAtomicId)(clone, cbData->modelID);

return true;
}

static bool GetFirstAtomicCB(RpAtomic* atomic, void* data)
{
RpAtomic** firstAtomic = reinterpret_cast<RpAtomic**>(data);
if (!*firstAtomic)
*firstAtomic = atomic;

return true;
}

bool CRenderWareSA::ReplaceAllAtomicsInModel(RpClump* newClump, std::uint16_t modelID, bool isClump)
{
CModelInfo* modelInfo = pGame->GetModelInfo(modelID);
if (!modelInfo)
return true;

RpAtomic* oldAtomic = reinterpret_cast<RpAtomic*>(modelInfo->GetRwObject());
if (reinterpret_cast<RpClump*>(oldAtomic) == newClump || DoContainTheSameGeometry(newClump, nullptr, oldAtomic))
return true;

// Clone the clump that's to be replaced (CFileLoader_SetRelatedModelInfoCB removes the atomics from the source clump)
RpClump* copy = RpClumpClone(newClump);

// Check if new model is clump or atomic
if (isClump)
{
SAtomicsClone data = {};
data.modelID = modelID;
// Get our new clump created in MakeClumpModel
data.clump = reinterpret_cast<RpClump*>(modelInfo->GetInterface()->pRwObject);

//RpAtomic* firstAtomic = nullptr;
//RpClumpForAllAtomics(data.clump, GetFirstAtomicCB, &firstAtomic);
//RpClumpRemoveAtomic(data.clump, firstAtomic);

// Clone atomics from new model to our empty clump
RpClumpForAllAtomics(copy, CloneAtomicsToClumpCB, &data);
}
else
{
// Replace the atomics
SAtomicsReplace data = {};
data.txdID = static_cast<CBaseModelInfoSAInterface**>(ARRAY_ModelInfo)[modelID]->usTextureDictionary;
data.clump = copy;

MemPutFast<DWORD>(reinterpret_cast<DWORD*>(DWORD_AtomicsReplacerModelID), modelID);
RpClumpForAllAtomics(copy, ReplaceAtomicsInModelCB, &data);
}

// Destroy empty clump
RpClumpDestroy(copy);

return true;
}

Expand Down
2 changes: 1 addition & 1 deletion Client/game_sa/CRenderWareSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class CRenderWareSA : public CRenderWare
unsigned int LoadAtomics(RpClump* pClump, RpAtomicContainer* pAtomics);

// Replaces all atomics for a specific model
bool ReplaceAllAtomicsInModel(RpClump* pSrc, unsigned short usModelID) override;
bool ReplaceAllAtomicsInModel(RpClump* newClump, std::uint16_t modelID, bool isClump = false) override;

// Replaces all atomics in a clump
void ReplaceAllAtomicsInClump(RpClump* pDst, RpAtomicContainer* pAtomics, unsigned int uiAtomics);
Expand Down
2 changes: 2 additions & 0 deletions Client/game_sa/gamesa_renderware.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 RpClump*(__cdecl* RpClumpCreate_t)();

/*****************************************************************************/
/** Renderware function mappings **/
Expand Down Expand Up @@ -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(RpClumpCreate_t RpClumpCreate, reinterpret_cast<RpClumpCreate_t>(0xDEAD))

/*****************************************************************************/
/** GTA function definitions and mappings **/
Expand Down
3 changes: 2 additions & 1 deletion Client/game_sa/gamesa_renderware.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ void InitRwFunctions()
RpHAnimIDGetIndex = (RpHAnimIDGetIndex_t)0x7C51A0;
RpHAnimHierarchyGetMatrixArray = (RpHAnimHierarchyGetMatrixArray_t)0x7C5120;
RtQuatRotate = (RtQuatRotate_t)0x7EB7C0;

RpClumpCreate = reinterpret_cast<RpClumpCreate_t>(0x74A290);

SetTextureDict = (SetTextureDict_t)0x007319C0;
LoadClumpFile = (LoadClumpFile_t)0x005371F0;
LoadModel = (LoadModel_t)0x0040C6B0;
Expand Down
Loading

0 comments on commit 25a207b

Please sign in to comment.