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