Skip to content

Commit 3e48846

Browse files
committed
Remove/restore sa world
1 parent 81242ed commit 3e48846

20 files changed

+699
-268
lines changed

Client/game_sa/CBuildingsPoolSA.cpp

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*****************************************************************************
2+
*
3+
* PROJECT: Multi Theft Auto v1.0
4+
* LICENSE: See LICENSE in the top level directory
5+
* FILE: game_sa/CBuildingsPoolSA.cpp
6+
* PURPOSE: Buildings pool class
7+
*
8+
* Multi Theft Auto is available from http://www.multitheftauto.com/
9+
*
10+
*****************************************************************************/
11+
12+
#include "StdInc.h"
13+
#include "CBuildingsPoolSA.h"
14+
15+
#include "CFileLoaderSA.h"
16+
#include <game/CWorld.h>
17+
#include "CGameSA.h"
18+
19+
extern CGameSA* pGame;
20+
21+
class CClientEntity;
22+
23+
CBuildingsPoolSA::CBuildingsPoolSA() : m_pOriginalBuildingsBackup(nullptr)
24+
{
25+
m_ppBuildingPoolInterface = (CPoolSAInterface<CBuildingSAInterface>**)0xB74498;
26+
}
27+
28+
inline bool CBuildingsPoolSA::AddBuildingToPool(CClientBuilding* pClientBuilding, CBuildingSA* pBuilding)
29+
{
30+
// Grab the new object interface
31+
CBuildingSAInterface* pInterface = pBuilding->GetBuildingInterface();
32+
33+
if (!pInterface)
34+
return false;
35+
36+
uint32_t dwElementIndexInPool = (*m_ppBuildingPoolInterface)->GetObjectIndexSafe(pInterface);
37+
if (dwElementIndexInPool >= -1)
38+
return false;
39+
40+
m_buildingPool.arrayOfClientEntities[dwElementIndexInPool] = {pBuilding, (CClientEntity*)pClientBuilding};
41+
42+
// Increase the count of objects
43+
++m_buildingPool.ulCount;
44+
45+
return true;
46+
}
47+
48+
CBuilding* CBuildingsPoolSA::AddBuilding(CClientBuilding* pClientBuilding, uint16_t modelId, CVector* vPos, CVector4D* vRot, uint8_t interior)
49+
{
50+
if (!HasFreeBuildingSlot())
51+
return nullptr;
52+
53+
// Load building
54+
SFileObjectInstance instance;
55+
instance.modelID = modelId;
56+
instance.lod = -1;
57+
instance.interiorID = interior;
58+
instance.position = *vPos;
59+
instance.rotation = *vRot;
60+
61+
// Fix strange SA rotation
62+
instance.rotation.fW = -instance.rotation.fW;
63+
64+
auto pBuilding = static_cast<CBuildingSAInterface*>(CFileLoaderSA::LoadObjectInstance(&instance));
65+
66+
// Disable lod and ipl
67+
pBuilding->m_pLod = nullptr;
68+
pBuilding->m_iplIndex = 0;
69+
70+
// Always stream model collosion
71+
// TODO We can setup collison bounding box and use GTA streamer for it
72+
auto modelInfo = pGame->GetModelInfo(modelId);
73+
modelInfo->AddColRef();
74+
75+
// Add building in world
76+
auto pBuildingSA = new CBuildingSA(pBuilding);
77+
pGame->GetWorld()->Add(pBuildingSA, CBuildingPool_Constructor);
78+
79+
// Add CBuildingSA object in pool
80+
AddBuildingToPool(pClientBuilding, pBuildingSA);
81+
82+
return pBuildingSA;
83+
}
84+
85+
void CBuildingsPoolSA::RemoveBuilding(CBuilding* pBuilding)
86+
{
87+
assert(NULL != pBuilding);
88+
89+
CBuildingSAInterface* pInterface = pBuilding->GetBuildingInterface();
90+
91+
uint32_t dwElementIndexInPool = (*m_ppBuildingPoolInterface)->GetObjectIndexSafe(pInterface);
92+
if (dwElementIndexInPool == -1)
93+
return;
94+
95+
// Remove building from world
96+
pGame->GetWorld()->Remove(pInterface, CBuildingPool_Destructor);
97+
98+
// Remove col reference
99+
auto modelInfo = pGame->GetModelInfo(pBuilding->GetModelIndex());
100+
modelInfo->RemoveColRef();
101+
102+
// Remove from BuildingSA pool
103+
auto* pBuildingSA = m_buildingPool.arrayOfClientEntities[dwElementIndexInPool].pEntity;
104+
m_buildingPool.arrayOfClientEntities[dwElementIndexInPool] = {nullptr, nullptr};
105+
106+
// Delete it from memory
107+
delete pBuildingSA;
108+
109+
// Remove building from SA pool
110+
(*m_ppBuildingPoolInterface)->Release(dwElementIndexInPool);
111+
112+
// Decrease the count of elements in the pool
113+
--m_buildingPool.ulCount;
114+
}
115+
116+
void CBuildingsPoolSA::RemoveAllBuildings()
117+
{
118+
if (m_pOriginalBuildingsBackup)
119+
return;
120+
121+
m_pOriginalBuildingsBackup = std::make_unique<std::array<std::pair<bool, CBuildingSAInterface>, MAX_BUILDINGS>>();
122+
123+
auto pBuildsingsPool = (*m_ppBuildingPoolInterface);
124+
for (size_t i = 0; i < MAX_BUILDINGS; i++)
125+
{
126+
if (pBuildsingsPool->IsContains(i))
127+
{
128+
auto building = pBuildsingsPool->GetObject(i);
129+
130+
pGame->GetWorld()->Remove(building, CBuildingPool_Destructor);
131+
132+
pBuildsingsPool->Release(i);
133+
134+
(*m_pOriginalBuildingsBackup)[i].first = true;
135+
(*m_pOriginalBuildingsBackup)[i].second = *building;
136+
}
137+
else
138+
{
139+
(*m_pOriginalBuildingsBackup)[i].first = false;
140+
}
141+
}
142+
}
143+
144+
void CBuildingsPoolSA::RestoreAllBuildings()
145+
{
146+
if (!m_pOriginalBuildingsBackup)
147+
return;
148+
149+
auto& originalData = *m_pOriginalBuildingsBackup;
150+
auto pBuildsingsPool = (*m_ppBuildingPoolInterface);
151+
for (size_t i = 0; i < MAX_BUILDINGS; i++)
152+
{
153+
if (originalData[i].first)
154+
{
155+
pBuildsingsPool->AllocateAt(i);
156+
auto building = pBuildsingsPool->GetObject(i);
157+
*building = originalData[i].second;
158+
159+
pGame->GetWorld()->Add(building, CBuildingPool_Constructor);
160+
}
161+
}
162+
163+
m_pOriginalBuildingsBackup.release();
164+
}
165+
166+
bool CBuildingsPoolSA::HasFreeBuildingSlot()
167+
{
168+
return (*m_ppBuildingPoolInterface)->GetFreeSlot() != -1;
169+
}

Client/game_sa/CBuildingsPoolSA.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*****************************************************************************
2+
*
3+
* PROJECT: Multi Theft Auto v1.0
4+
* LICENSE: See LICENSE in the top level directory
5+
* FILE: game_sa/CBuildingsPoolSA.h
6+
* PURPOSE: Buildings pool class
7+
*
8+
* Multi Theft Auto is available from http://www.multitheftauto.com/
9+
*
10+
*****************************************************************************/
11+
12+
#include <game/CBuildingsPool.h>
13+
#include <CVector.h>
14+
#include "CPoolSAInterface.h"
15+
#include "CBuildingSA.h"
16+
17+
class CBuildingsPoolSA : public CBuildingsPool
18+
{
19+
public:
20+
CBuildingsPoolSA();
21+
~CBuildingsPoolSA() = default;
22+
23+
CBuilding* AddBuilding(CClientBuilding*, uint16_t modelId, CVector* vPos, CVector4D* vRot, uint8_t interior);
24+
void RemoveBuilding(CBuilding* pBuilding);
25+
bool HasFreeBuildingSlot();
26+
27+
void RemoveAllBuildings();
28+
void RestoreAllBuildings();
29+
30+
private:
31+
bool AddBuildingToPool(CClientBuilding* pClientBuilding, CBuildingSA* pBuilding);
32+
33+
private:
34+
SPoolData<CBuildingSA, CBuildingSAInterface, MAX_BUILDINGS> m_buildingPool;
35+
CPoolSAInterface<CBuildingSAInterface>** m_ppBuildingPoolInterface;
36+
37+
std::unique_ptr<std::array<std::pair<bool, CBuildingSAInterface>, MAX_BUILDINGS>> m_pOriginalBuildingsBackup;
38+
};

Client/game_sa/CGameSA.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#include "CWeatherSA.h"
5757
#include "CWorldSA.h"
5858
#include "D3DResourceSystemSA.h"
59+
#include "CIplStoreSA.h"
5960

6061
extern CGameSA* pGame;
6162

@@ -137,6 +138,7 @@ CGameSA::CGameSA()
137138
m_pWeaponStatsManager = new CWeaponStatManagerSA();
138139
m_pPointLights = new CPointLightsSA();
139140
m_collisionStore = new CColStoreSA();
141+
m_pIplStore = new CIplStoreSA();
140142

141143
// Normal weapon types (WEAPONSKILL_STD)
142144
for (int i = 0; i < NUM_WeaponInfosStdSkill; i++)
@@ -273,6 +275,7 @@ CGameSA::~CGameSA()
273275
delete reinterpret_cast<CAudioContainerSA*>(m_pAudioContainer);
274276
delete reinterpret_cast<CPointLightsSA*>(m_pPointLights);
275277
delete static_cast<CColStoreSA*>(m_collisionStore);
278+
delete static_cast<CIplStore*>(m_pIplStore);
276279

277280
delete[] ModelInfo;
278281
delete[] ObjectGroupsInfo;
@@ -425,6 +428,9 @@ void CGameSA::Reset()
425428

426429
// Restore changed TXD IDs
427430
CModelInfoSA::StaticResetTextureDictionaries();
431+
432+
// Restore default world state
433+
RestoreGameBuildings();
428434
}
429435
}
430436

@@ -882,6 +888,20 @@ void CGameSA::GetShaderReplacementStats(SShaderReplacementStats& outStats)
882888
m_pRenderWare->GetShaderReplacementStats(outStats);
883889
}
884890

891+
void CGameSA::RemoveAllBuildings()
892+
{
893+
m_pIplStore->SetDynamicIplStreamingEnabled(false);
894+
895+
m_pPools->GetBuildingsPool().RemoveAllBuildings();
896+
}
897+
898+
void CGameSA::RestoreGameBuildings()
899+
{
900+
m_pPools->GetBuildingsPool().RestoreAllBuildings();
901+
902+
m_pIplStore->SetDynamicIplStreamingEnabled(true);
903+
}
904+
885905
// Ensure models have the default lod distances
886906
void CGameSA::ResetModelLodDistances()
887907
{

Client/game_sa/CGameSA.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ class CGameSA : public CGame
152152
CColStore* GetCollisionStore() override { return m_collisionStore; }
153153
CRenderWareSA* GetRenderWareSA() { return m_pRenderWare; }
154154
CFxManagerSA* GetFxManagerSA() { return m_pFxManager; }
155+
CIplStore* GetIplStore() { return m_pIplStore; };
155156

156157
CWeaponInfo* GetWeaponInfo(eWeaponType weapon, eWeaponSkill skill = WEAPONSKILL_STD);
157158
CModelInfo* GetModelInfo(DWORD dwModelID, bool bCanBeInvalid = false);
@@ -273,6 +274,9 @@ class CGameSA : public CGame
273274
PostWeaponFireHandler* m_pPostWeaponFireHandler;
274275
TaskSimpleBeHitHandler* m_pTaskSimpleBeHitHandler;
275276

277+
void RemoveAllBuildings();
278+
void RestoreGameBuildings();
279+
276280
private:
277281
CPools* m_pPools;
278282
CPlayerInfo* m_pPlayerInfo;
@@ -320,6 +324,7 @@ class CGameSA : public CGame
320324
CGameSettings* m_pSettings;
321325
CCarEnterExit* m_pCarEnterExit;
322326
CControllerConfigManager* m_pControllerConfigManager;
327+
CIplStore* m_pIplStore;
323328

324329
eGameVersion m_eGameVersion;
325330
bool m_bAsyncScriptEnabled;

Client/game_sa/CIplSA.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*****************************************************************************
2+
*
3+
* PROJECT: Multi Theft Auto v1.0
4+
* LICENSE: See LICENSE in the top level directory
5+
* FILE: game_sa/CIplSA.h
6+
* PURPOSE: Header file for game IPL class
7+
*
8+
* Multi Theft Auto is available from http://www.multitheftauto.com/
9+
*
10+
*****************************************************************************/
11+
12+
#pragma once
13+
14+
#include <cstdint>
15+
#include "CRect.h"
16+
17+
class CIplSAInterface
18+
{
19+
public:
20+
CRect rect;
21+
char name[16];
22+
uint16_t unk;
23+
uint16_t minBuildId;
24+
uint16_t maxBuildId;
25+
uint16_t minBummyId;
26+
uint16_t maxDummyId;
27+
uint16_t relatedIpl;
28+
uint8_t interior;
29+
uint8_t unk2;
30+
uint8_t bLoadReq;
31+
uint8_t bDisabledStreaming;
32+
uint8_t unk3;
33+
uint8_t unk4;
34+
uint8_t unk5;
35+
uint8_t unk6;
36+
};
37+
static_assert(sizeof(CIplSAInterface) == 0x34, "Wrong CIplSAInterface size");

Client/game_sa/CIplStoreSA.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*****************************************************************************
2+
*
3+
* PROJECT: Multi Theft Auto v1.0
4+
* LICENSE: See LICENSE in the top level directory
5+
* FILE: game_sa/CIplStore.cpp
6+
* PURPOSE: IPL store class
7+
*
8+
* Multi Theft Auto is available from http://www.multitheftauto.com/
9+
*
10+
*****************************************************************************/
11+
12+
#include "StdInc.h"
13+
14+
#include "CIplStoreSA.h"
15+
#include "CQuadTreeNodeSA.h"
16+
17+
static auto gIplQuadTree = (CQuadTreeNodesSAInterface<CIplSAInterface>**)0x8E3FAC;
18+
19+
CIplStoreSA::CIplStoreSA(): m_isStreamingEnbabled(true), m_ppIplPoolInterface((CPoolSAInterface<CIplSAInterface>**)0x8E3FB0)
20+
{
21+
}
22+
23+
void CIplStoreSA::UnloadAndDisableStreaming(int iplId)
24+
{
25+
typedef void*(__cdecl * Function_EnableStreaming)(int);
26+
((Function_EnableStreaming)(0x405890))(iplId);
27+
}
28+
29+
void CIplStoreSA::SetDynamicIplStreamingEnabled(bool state)
30+
{
31+
if (m_isStreamingEnbabled == state)
32+
return;
33+
34+
// Ipl with 0 index is generic
35+
// We don't unload this IPL
36+
37+
auto pPool = *m_ppIplPoolInterface;
38+
if (!state)
39+
{
40+
for (int i = 1; i < pPool->m_nSize; i++)
41+
{
42+
if (pPool->IsContains(i))
43+
{
44+
UnloadAndDisableStreaming(i);
45+
}
46+
}
47+
(*gIplQuadTree)->RemoveAllItems();
48+
}
49+
else
50+
{
51+
for (int i = 1; i < pPool->m_nSize; i++)
52+
{
53+
if (pPool->IsContains(i))
54+
{
55+
auto ipl = pPool->GetObject(i);
56+
ipl->bDisabledStreaming = false;
57+
58+
(*gIplQuadTree)->AddItem(ipl, &ipl->rect);
59+
}
60+
}
61+
}
62+
63+
m_isStreamingEnbabled = state;
64+
}

0 commit comments

Comments
 (0)