Skip to content

Commit 6fea97c

Browse files
committed
engineConvertModelToType
1 parent a411d77 commit 6fea97c

File tree

8 files changed

+287
-140
lines changed

8 files changed

+287
-140
lines changed

Client/game_sa/CModelInfoSA.cpp

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,6 +1541,8 @@ void CModelInfoSA::RestoreOriginalModel()
15411541
if (currentInterface)
15421542
{
15431543
ppModelInfo[m_dwModelID]->usNumberOfRefs = currentInterface->usNumberOfRefs;
1544+
ppModelInfo[m_dwModelID]->pColModel = currentInterface->pColModel;
1545+
15441546
delete currentInterface;
15451547
}
15461548

@@ -1818,6 +1820,9 @@ void CModelInfoSA::MakeClumpModel(ushort usBaseID)
18181820

18191821
bool CModelInfoSA::ConvertToClump()
18201822
{
1823+
if (GetModelType() == eModelInfoType::CLUMP)
1824+
return false;
1825+
18211826
// Get current interface
18221827
CBaseModelInfoSAInterface* currentModelInterface = ppModelInfo[m_dwModelID];
18231828
if (!currentModelInterface)
@@ -1838,34 +1843,94 @@ bool CModelInfoSA::ConvertToClump()
18381843
// Set new interface for ModelInfo
18391844
ppModelInfo[m_dwModelID] = newClumpInterface;
18401845

1841-
// Store original interface
1842-
MapSet(m_convertedModelInterfaces, m_dwModelID, currentModelInterface);
1846+
// Store original (only) interface
1847+
if (!MapContains(m_convertedModelInterfaces, m_dwModelID))
1848+
MapSet(m_convertedModelInterfaces, m_dwModelID, currentModelInterface);
1849+
else
1850+
m_lastConversionInterface = currentModelInterface;
1851+
18431852
return true;
18441853
}
18451854

1846-
bool CModelInfoSA::ConvertToAtomic()
1855+
bool CModelInfoSA::ConvertToAtomic(bool damageable)
18471856
{
18481857
// Get current interface
1849-
CClumpModelInfoSAInterface* currentClumpInterface = static_cast<CClumpModelInfoSAInterface*>(ppModelInfo[m_dwModelID]);
1850-
if (!currentClumpInterface)
1858+
CBaseModelInfoSAInterface* currentModelInterface = ppModelInfo[m_dwModelID];
1859+
if (!currentModelInterface)
1860+
return false;
1861+
1862+
if (GetModelType() == eModelInfoType::ATOMIC && ((damageable && currentModelInterface->IsDamageAtomicVTBL()) || (!damageable && currentModelInterface->IsAtomicVTBL())))
18511863
return false;
18521864

18531865
// Create new atomic interface
1854-
CAtomicModelInfoSAInterface* newAtomicInterface = new CAtomicModelInfoSAInterface();
1855-
MemCpyFast(newAtomicInterface, currentClumpInterface, sizeof(CAtomicModelInfoSAInterface));
1866+
CAtomicModelInfoSAInterface* newAtomicInterface = nullptr;
1867+
CDamageableModelInfoSAInterface* newDamageableAtomicInterface = nullptr;
18561868

18571869
// (FileEX): We do not destroy or set pRwObject to nullptr here
18581870
// because our IsLoaded code expects the RwObject to exist.
18591871
// We destroy the old RwObject in CRenderWareSA::ReplaceAllAtomicsInModel after passing the IsLoaded condition in the SetCustomModel.
18601872

1861-
// Set CAtomicModelInfo vtbl after copying data
1862-
newAtomicInterface->VFTBL = reinterpret_cast<CBaseModelInfo_SA_VTBL*>(VTBL_CAtomicModelInfo);
1873+
if (damageable)
1874+
{
1875+
newDamageableAtomicInterface = new CDamageableModelInfoSAInterface();
1876+
MemCpyFast(newDamageableAtomicInterface, currentModelInterface, sizeof(CDamageableModelInfoSAInterface));
1877+
newDamageableAtomicInterface->m_damagedAtomic = nullptr;
1878+
1879+
// Set CDamageAtomicModelInfo vtbl after copying data
1880+
newDamageableAtomicInterface->VFTBL = reinterpret_cast<CBaseModelInfo_SA_VTBL*>(VTBL_CDamageAtomicModelInfo);
1881+
}
1882+
else
1883+
{
1884+
newAtomicInterface = new CAtomicModelInfoSAInterface();
1885+
MemCpyFast(newAtomicInterface, currentModelInterface, sizeof(CAtomicModelInfoSAInterface));
1886+
1887+
// Set CAtomicModelInfo vtbl after copying data
1888+
newAtomicInterface->VFTBL = reinterpret_cast<CBaseModelInfo_SA_VTBL*>(VTBL_CAtomicModelInfo);
1889+
}
18631890

18641891
// Set new interface for ModelInfo
1865-
ppModelInfo[m_dwModelID] = newAtomicInterface;
1892+
ppModelInfo[m_dwModelID] = damageable ? newDamageableAtomicInterface : newAtomicInterface;
1893+
1894+
// Store original (only) interface
1895+
if (!MapContains(m_convertedModelInterfaces, m_dwModelID))
1896+
MapSet(m_convertedModelInterfaces, m_dwModelID, currentModelInterface);
1897+
else
1898+
m_lastConversionInterface = currentModelInterface;
1899+
1900+
return true;
1901+
}
1902+
1903+
bool CModelInfoSA::ConvertToTimedObject()
1904+
{
1905+
if (GetModelType() == eModelInfoType::TIME)
1906+
return false;
1907+
1908+
// Get current interface
1909+
CBaseModelInfoSAInterface* currentModelInterface = ppModelInfo[m_dwModelID];
1910+
if (!currentModelInterface)
1911+
return false;
1912+
1913+
// Create new interface
1914+
CTimeModelInfoSAInterface* newTimedInterface = new CTimeModelInfoSAInterface();
1915+
MemCpyFast(newTimedInterface, currentModelInterface, sizeof(CTimeModelInfoSAInterface));
1916+
newTimedInterface->timeInfo.m_wOtherTimeModel = 0;
1917+
1918+
// (FileEX): We do not destroy or set pRwObject to nullptr here
1919+
// because our IsLoaded code expects the RwObject to exist.
1920+
// We destroy the old RwObject in CRenderWareSA::ReplaceAllAtomicsInModel after passing the IsLoaded condition in the SetCustomModel.
1921+
1922+
// Set CTimeModelInfo vtbl after copying data
1923+
newTimedInterface->VFTBL = reinterpret_cast<CBaseModelInfo_SA_VTBL*>(VTBL_CTimeModelInfo);
1924+
1925+
// Set new interface for ModelInfo
1926+
ppModelInfo[m_dwModelID] = newTimedInterface;
1927+
1928+
// Store original (only) interface
1929+
if (!MapContains(m_convertedModelInterfaces, m_dwModelID))
1930+
MapSet(m_convertedModelInterfaces, m_dwModelID, currentModelInterface);
1931+
else
1932+
m_lastConversionInterface = currentModelInterface;
18661933

1867-
// Store original interface
1868-
MapSet(m_convertedModelInterfaces, m_dwModelID, currentClumpInterface);
18691934
return true;
18701935
}
18711936

Client/game_sa/CModelInfoSA.h

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ static void* ARRAY_ModelInfo = *(void**)(0x403DA4 + 3);
6666

6767
#define VTBL_CClumpModelInfo 0x85BD30
6868
#define VTBL_CAtomicModelInfo 0x85BBF0
69+
#define VTBL_CDamageAtomicModelInfo 0x85BC30
70+
#define VTBL_CTimeModelInfo 0x85BCB0
6971

7072
class CBaseModelInfoSAInterface;
7173
class CModelInfoSAInterface
@@ -235,6 +237,12 @@ class CBaseModelInfoSAInterface
235237
// +726 = Word array as referenced in CVehicleModelInfo::GetVehicleUpgrade(int)
236238
// +762 = Array of WORD containing something relative to paintjobs
237239
// +772 = Anim file index
240+
241+
void DeleteRwObject() { ((void(__thiscall*)(void*))VFTBL->DeleteRwObject)(this); }
242+
243+
bool IsAtomicVTBL() const { return VFTBL == reinterpret_cast<CBaseModelInfo_SA_VTBL*>(VTBL_CAtomicModelInfo); }
244+
bool IsDamageAtomicVTBL() const { return VFTBL == reinterpret_cast<CBaseModelInfo_SA_VTBL*>(VTBL_CDamageAtomicModelInfo); }
245+
bool IsClumpVTBL() const { return VFTBL == reinterpret_cast<CBaseModelInfo_SA_VTBL*>(VTBL_CClumpModelInfo); }
238246
};
239247
static_assert(sizeof(CBaseModelInfoSAInterface) == 0x20, "Invalid size for CBaseModelInfoSAInterface");
240248

@@ -267,6 +275,13 @@ class CAtomicModelInfoSAInterface : public CBaseModelInfoSAInterface
267275
void SetAtomic(RpAtomic* atomic) { ((void(__thiscall*)(CAtomicModelInfoSAInterface*, RpAtomic*))0x4C4360)(this, atomic); }
268276
};
269277

278+
class CLodAtomicModelInfoSAInterface : public CAtomicModelInfoSAInterface
279+
{
280+
public:
281+
std::int16_t numChildren; // num child higher level LODs
282+
std::int16_t numChildrenRendered; // num child higher level LODs that have been rendered
283+
};
284+
270285
class CTimeModelInfoSAInterface : public CAtomicModelInfoSAInterface
271286
{
272287
public:
@@ -286,7 +301,7 @@ class CDamageableModelInfoSAInterface : public CAtomicModelInfoSAInterface
286301
public:
287302
RpAtomic* m_damagedAtomic;
288303

289-
void SetDamagedAtomic(RpAtomic* atomic) { ((void(__thiscall*)(RpAtomic*))FUNC_CAtomicModelInfo_SetAtomic)(atomic); }
304+
void SetDamagedAtomic(RpAtomic* atomic) { ((void(__thiscall*)(CDamageableModelInfoSAInterface*, RpAtomic*))0x4C48D0)(this, atomic); }
290305
};
291306

292307
class CVehicleModelVisualInfoSAInterface // Not sure about this name. If somebody knows more, please change
@@ -371,6 +386,7 @@ class CModelInfoSA : public CModelInfo
371386
static std::map<unsigned short, int> ms_DefaultTxdIDMap;
372387
SVehicleSupportedUpgrades m_ModelSupportedUpgrades;
373388

389+
CBaseModelInfoSAInterface* m_lastConversionInterface{nullptr};
374390
// Store original model interfaces after conersion clump->atomic or atomic->clump
375391
static std::unordered_map<std::uint32_t, CBaseModelInfoSAInterface*> m_convertedModelInterfaces;
376392

@@ -508,9 +524,12 @@ class CModelInfoSA : public CModelInfo
508524
static void RestoreAllObjectsPropertiesGroups();
509525

510526
// Model type conversion functions
511-
bool ConvertToClump();
512-
bool ConvertToAtomic();
513-
CBaseModelInfoSAInterface* GetOriginalInterface() const;
527+
bool ConvertToClump() override;
528+
bool ConvertToAtomic(bool damageable) override;
529+
bool ConvertToTimedObject() override;
530+
CBaseModelInfoSAInterface* GetLastConversionInterface() const noexcept override { return m_lastConversionInterface; }
531+
void SetLastConversionInterface(CBaseModelInfoSAInterface* lastInterace) noexcept override { m_lastConversionInterface = lastInterace; }
532+
CBaseModelInfoSAInterface* GetOriginalInterface() const override;
514533

515534
// Vehicle towing functions
516535
bool IsTowableBy(CModelInfo* towingModel) override;

0 commit comments

Comments
 (0)