Skip to content

Commit e9e7928

Browse files
committed
Fix old bug
1 parent c7d40e8 commit e9e7928

File tree

11 files changed

+262
-67
lines changed

11 files changed

+262
-67
lines changed

Client/game_sa/CFileLoaderSA.cpp

Lines changed: 3 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "gamesa_renderware.h"
1313
#include "CFileLoaderSA.h"
1414
#include "CModelInfoSA.h"
15+
#include "CRenderWareSA.h"
1516

1617
CFileLoaderSA::CFileLoaderSA()
1718
{
@@ -48,53 +49,6 @@ class CDamagableModelInfo
4849
void CDamagableModelInfo::SetDamagedAtomic(RpAtomic* atomic) { ((void(__thiscall*)(CDamagableModelInfo*, RpAtomic*))0x4C48D0)(this, atomic); }
4950
};
5051

51-
static char* GetFrameNodeName(RwFrame* frame)
52-
{
53-
return ((char*(__cdecl*)(RwFrame*))0x72FB30)(frame);
54-
}
55-
56-
// Originally there was a possibility for this function to cause buffer overflow
57-
// It should be fixed here.
58-
template <size_t OutBuffSize>
59-
void GetNameAndDamage(const char* nodeName, char (&outName)[OutBuffSize], bool& outDamage)
60-
{
61-
const auto nodeNameLen = strlen(nodeName);
62-
63-
const auto NodeNameEndsWith = [=](const char* with) {
64-
const auto withLen = strlen(with);
65-
// dassert(withLen <= nodeNameLen);
66-
return withLen <= nodeNameLen /*dont bother checking otherwise, because it might cause a crash*/
67-
&& strncmp(nodeName + nodeNameLen - withLen, with, withLen) == 0;
68-
};
69-
70-
// Copy `nodeName` into `outName` with `off` trimmed from the end
71-
// Eg.: `dmg_dam` with `off = 4` becomes `dmg`
72-
const auto TerminatedCopy = [&](size_t off) {
73-
dassert(nodeNameLen - off < OutBuffSize);
74-
strncpy_s(outName, nodeName,
75-
std::min(nodeNameLen - off, OutBuffSize - 1)); // By providing `OutBuffSize - 1` it is ensured the array will be null terminated
76-
};
77-
78-
if (NodeNameEndsWith("_dam"))
79-
{
80-
outDamage = true;
81-
TerminatedCopy(sizeof("_dam") - 1);
82-
}
83-
else
84-
{
85-
outDamage = false;
86-
if (NodeNameEndsWith("_l0") || NodeNameEndsWith("_L0"))
87-
{
88-
TerminatedCopy(sizeof("_l0") - 1);
89-
}
90-
else
91-
{
92-
dassert(nodeNameLen < OutBuffSize);
93-
strncpy_s(outName, OutBuffSize, nodeName, OutBuffSize - 1);
94-
}
95-
}
96-
}
97-
9852
static void CVisibilityPlugins_SetAtomicRenderCallback(RpAtomic* pRpAtomic, RpAtomic* (*renderCB)(RpAtomic*))
9953
{
10054
return ((void(__cdecl*)(RpAtomic*, RpAtomic * (*renderCB)(RpAtomic*)))0x7328A0)(pRpAtomic, renderCB);
@@ -170,9 +124,9 @@ RpAtomic* CFileLoader_SetRelatedModelInfoCB(RpAtomic* atomic, SRelatedModelInfo*
170124
CBaseModelInfoSAInterface* pBaseModelInfo = CModelInfo_ms_modelInfoPtrs[gAtomicModelId];
171125
auto pAtomicModelInfo = reinterpret_cast<CAtomicModelInfo*>(pBaseModelInfo);
172126
RwFrame* pOldFrame = reinterpret_cast<RwFrame*>(atomic->object.object.parent);
173-
char* frameNodeName = GetFrameNodeName(pOldFrame);
127+
char* frameNodeName = CRenderWareSA::GetFrameNodeName(pOldFrame);
174128
bool bDamage = false;
175-
GetNameAndDamage(frameNodeName, name, bDamage);
129+
CRenderWareSA::GetNameAndDamage(frameNodeName, name, bDamage);
176130
CVisibilityPlugins_SetAtomicRenderCallback(atomic, 0);
177131

178132
RpAtomic* pOldAtomic = reinterpret_cast<RpAtomic*>(pBaseModelInfo->pRwObject);

Client/game_sa/CModelInfoSA.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ std::map<CTimeInfoSAInterface*, CTimeInfoSAInterface*> CModelInfo
3535
std::unordered_map<DWORD, unsigned short> CModelInfoSA::ms_OriginalObjectPropertiesGroups;
3636
std::unordered_map<DWORD, std::pair<float, float>> CModelInfoSA::ms_VehicleModelDefaultWheelSizes;
3737
std::map<unsigned short, int> CModelInfoSA::ms_DefaultTxdIDMap;
38+
std::unordered_map<std::uint32_t, CBaseModelInfoSAInterface*> CModelInfoSA::m_convertedModelInterfaces;
3839

3940
union tIdeFlags
4041
{
@@ -1512,6 +1513,7 @@ bool CModelInfoSA::SetCustomModel(RpClump* pClump)
15121513
case eModelInfoType::ATOMIC:
15131514
case eModelInfoType::LOD_ATOMIC:
15141515
case eModelInfoType::TIME:
1516+
case eModelInfoType::CLUMP:
15151517
success = pGame->GetRenderWare()->ReplaceAllAtomicsInModel(pClump, static_cast<unsigned short>(m_dwModelID));
15161518
break;
15171519
default:
@@ -1530,6 +1532,16 @@ void CModelInfoSA::RestoreOriginalModel()
15301532
pGame->GetStreaming()->RemoveModel(m_dwModelID);
15311533
}
15321534

1535+
// Restore original interface if model was converted
1536+
if (MapContains(m_convertedModelInterfaces, m_dwModelID))
1537+
{
1538+
CBaseModelInfoSAInterface* currentInterface = ppModelInfo[m_dwModelID];
1539+
ppModelInfo[m_dwModelID] = MapGet(m_convertedModelInterfaces, m_dwModelID);
1540+
1541+
delete currentInterface;
1542+
MapRemove(m_convertedModelInterfaces, m_dwModelID);
1543+
}
1544+
15331545
// Reset the stored custom vehicle clump
15341546
m_pCustomClump = NULL;
15351547
}
@@ -1799,6 +1811,73 @@ void CModelInfoSA::MakeClumpModel(ushort usBaseID)
17991811
CopyStreamingInfoFromModel(usBaseID);
18001812
}
18011813

1814+
bool CModelInfoSA::ConvertToClump()
1815+
{
1816+
if (GetModelType() != eModelInfoType::ATOMIC)
1817+
return false;
1818+
1819+
// Get current interface
1820+
CAtomicModelInfoSAInterface* currentAtomicInterface = static_cast<CAtomicModelInfoSAInterface*>(ppModelInfo[m_dwModelID]);
1821+
if (!currentAtomicInterface)
1822+
return false;
1823+
1824+
// Create new clump interface
1825+
CClumpModelInfoSAInterface* newClumpInterface = new CClumpModelInfoSAInterface();
1826+
MemCpyFast(newClumpInterface, currentAtomicInterface, sizeof(CClumpModelInfoSAInterface));
1827+
newClumpInterface->m_nAnimFileIndex = -1;
1828+
1829+
// (FileEX): We do not destroy or set pRwObject to nullptr here
1830+
// because our IsLoaded code expects the RwObject to exist.
1831+
// We destroy the old RwObject in CRenderWareSA::ReplaceAllAtomicsInModel after passing the IsLoaded condition in the SetCustomModel.
1832+
1833+
// Set CClumpModelInfo vtbl after copying data
1834+
newClumpInterface->VFTBL = reinterpret_cast<CBaseModelInfo_SA_VTBL*>(VTBL_CClumpModelInfo);
1835+
1836+
// Set new interface for ModelInfo
1837+
ppModelInfo[m_dwModelID] = newClumpInterface;
1838+
1839+
// Store original interface
1840+
MapSet(m_convertedModelInterfaces, m_dwModelID, static_cast<CBaseModelInfoSAInterface*>(currentAtomicInterface));
1841+
return true;
1842+
}
1843+
1844+
bool CModelInfoSA::ConvertToAtomic()
1845+
{
1846+
if (GetModelType() != eModelInfoType::CLUMP)
1847+
return false;
1848+
1849+
// Get current interface
1850+
CClumpModelInfoSAInterface* currentClumpInterface = static_cast<CClumpModelInfoSAInterface*>(ppModelInfo[m_dwModelID]);
1851+
if (!currentClumpInterface)
1852+
return false;
1853+
1854+
// Create new atomic interface
1855+
CAtomicModelInfoSAInterface* newAtomicInterface = new CAtomicModelInfoSAInterface();
1856+
MemCpyFast(newAtomicInterface, currentClumpInterface, sizeof(CAtomicModelInfoSAInterface));
1857+
1858+
// (FileEX): We do not destroy or set pRwObject to nullptr here
1859+
// because our IsLoaded code expects the RwObject to exist.
1860+
// We destroy the old RwObject in CFileLoader_SetRelatedModelInfoCB after passing the IsLoaded condition in the SetCustomModel.
1861+
1862+
// Set CAtomicModelInfo vtbl after copying data
1863+
newAtomicInterface->VFTBL = reinterpret_cast<CBaseModelInfo_SA_VTBL*>(VTBL_CAtomicModelInfo);
1864+
1865+
// Set new interface for ModelInfo
1866+
ppModelInfo[m_dwModelID] = newAtomicInterface;
1867+
1868+
// Store original interface
1869+
MapSet(m_convertedModelInterfaces, m_dwModelID, currentClumpInterface);
1870+
return true;
1871+
}
1872+
1873+
CBaseModelInfoSAInterface* CModelInfoSA::GetOriginalInterface() const
1874+
{
1875+
if (!MapContains(m_convertedModelInterfaces, m_dwModelID))
1876+
return nullptr;
1877+
1878+
return MapGet(m_convertedModelInterfaces, m_dwModelID);
1879+
}
1880+
18021881
void CModelInfoSA::MakeVehicleAutomobile(ushort usBaseID)
18031882
{
18041883
CVehicleModelInfoSAInterface* m_pInterface = new CVehicleModelInfoSAInterface();

Client/game_sa/CModelInfoSA.h

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ static void* ARRAY_ModelInfo = *(void**)(0x403DA4 + 3);
6464

6565
#define VAR_CTempColModels_ModelPed1 0x968DF0
6666

67+
#define FUNC_CClumpModelInfo_SetClump 0x4C4F70
68+
#define FUNC_CClumpModelInfo_DeleteRwObject 0x4C4E70
69+
70+
#define FUNC_CAtomicModelInfo_SetAtomic 0x4C4360
71+
#define FUNC_CAtomicModelInfo_DeleteRwObject 0x4C4440
72+
73+
#define VTBL_CClumpModelInfo 0x85BD30
74+
#define VTBL_CAtomicModelInfo 0x85BBF0
75+
6776
class CBaseModelInfoSAInterface;
6877
class CModelInfoSAInterface
6978
{
@@ -252,9 +261,19 @@ class CClumpModelInfoSAInterface : public CBaseModelInfoSAInterface
252261
char* m_animFileName;
253262
uint32_t m_nAnimFileIndex;
254263
};
264+
265+
void DeleteRwObject() { ((void(__thiscall*)(CClumpModelInfoSAInterface*))FUNC_CClumpModelInfo_DeleteRwObject)(this); }
266+
void SetClump(RpClump* clump) { ((void(__thiscall*)(CClumpModelInfoSAInterface*, RpClump*))FUNC_CClumpModelInfo_SetClump)(this, clump); }
255267
};
256268

257-
class CTimeModelInfoSAInterface : public CBaseModelInfoSAInterface
269+
class CAtomicModelInfoSAInterface : public CBaseModelInfoSAInterface
270+
{
271+
public:
272+
void DeleteRwObject() { ((void(__thiscall*)(CAtomicModelInfoSAInterface*))FUNC_CAtomicModelInfo_DeleteRwObject)(this); }
273+
void SetAtomic(RpAtomic* atomic) { ((void(__thiscall*)(CAtomicModelInfoSAInterface*, RpAtomic*))FUNC_CAtomicModelInfo_SetAtomic)(this, atomic); }
274+
};
275+
276+
class CTimeModelInfoSAInterface : public CAtomicModelInfoSAInterface
258277
{
259278
public:
260279
CTimeInfoSAInterface timeInfo;
@@ -268,10 +287,12 @@ class CVehicleModelUpgradePosnDesc
268287
};
269288
static_assert(sizeof(CVehicleModelUpgradePosnDesc) == 0x20, "Invalid size of CVehicleModelUpgradePosnDesc class");
270289

271-
class CDamageableModelInfoSAInterface : public CBaseModelInfoSAInterface
290+
class CDamageableModelInfoSAInterface : public CAtomicModelInfoSAInterface
272291
{
273292
public:
274-
void* m_damagedAtomic;
293+
RpAtomic* m_damagedAtomic;
294+
295+
void SetDamagedAtomic(RpAtomic* atomic) { ((void(__thiscall*)(RpAtomic*))FUNC_CAtomicModelInfo_SetAtomic)(atomic); }
275296
};
276297

277298
class CVehicleModelVisualInfoSAInterface // Not sure about this name. If somebody knows more, please change
@@ -356,6 +377,9 @@ class CModelInfoSA : public CModelInfo
356377
static std::map<unsigned short, int> ms_DefaultTxdIDMap;
357378
SVehicleSupportedUpgrades m_ModelSupportedUpgrades;
358379

380+
// Store original model interfaces after conersion clump->atomic or atomic->clump
381+
static std::unordered_map<std::uint32_t, CBaseModelInfoSAInterface*> m_convertedModelInterfaces;
382+
359383
public:
360384
CModelInfoSA();
361385

@@ -489,6 +513,11 @@ class CModelInfoSA : public CModelInfo
489513
void RestoreObjectPropertiesGroup();
490514
static void RestoreAllObjectsPropertiesGroups();
491515

516+
// Model type conversion functions
517+
bool ConvertToClump();
518+
bool ConvertToAtomic();
519+
CBaseModelInfoSAInterface* GetOriginalInterface() const;
520+
492521
// Vehicle towing functions
493522
bool IsTowableBy(CModelInfo* towingModel) override;
494523

0 commit comments

Comments
 (0)