Skip to content

Commit

Permalink
Add removeAllGameBuildings / restoreAllGameBuildings API (#3275)
Browse files Browse the repository at this point in the history
  • Loading branch information
TheNormalnij committed Apr 5, 2024
1 parent aa932d2 commit eb6b18a
Show file tree
Hide file tree
Showing 20 changed files with 743 additions and 277 deletions.
178 changes: 178 additions & 0 deletions Client/game_sa/CBuildingsPoolSA.cpp
@@ -0,0 +1,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;
}
38 changes: 38 additions & 0 deletions Client/game_sa/CBuildingsPoolSA.h
@@ -0,0 +1,38 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto v1.0
* LICENSE: See LICENSE in the top level directory
* FILE: game_sa/CBuildingsPoolSA.h
* PURPOSE: Buildings pool class
*
* Multi Theft Auto is available from http://www.multitheftauto.com/
*
*****************************************************************************/

#include <game/CBuildingsPool.h>
#include <CVector.h>
#include "CPoolSAInterface.h"
#include "CBuildingSA.h"

class CBuildingsPoolSA : public CBuildingsPool
{
public:
CBuildingsPoolSA();
~CBuildingsPoolSA() = default;

CBuilding* AddBuilding(CClientBuilding*, uint16_t modelId, CVector* vPos, CVector4D* vRot, uint8_t interior);
void RemoveBuilding(CBuilding* pBuilding);
bool HasFreeBuildingSlot();

void RemoveAllBuildings();
void RestoreAllBuildings();

private:
bool AddBuildingToPool(CClientBuilding* pClientBuilding, CBuildingSA* pBuilding);

private:
SPoolData<CBuildingSA, CBuildingSAInterface, MAX_BUILDINGS> m_buildingPool;
CPoolSAInterface<CBuildingSAInterface>** m_ppBuildingPoolInterface;

std::unique_ptr<std::array<std::pair<bool, CBuildingSAInterface>, MAX_BUILDINGS>> m_pOriginalBuildingsBackup;
};
20 changes: 20 additions & 0 deletions Client/game_sa/CGameSA.cpp
Expand Up @@ -56,6 +56,7 @@
#include "CWeatherSA.h"
#include "CWorldSA.h"
#include "D3DResourceSystemSA.h"
#include "CIplStoreSA.h"

extern CGameSA* pGame;

Expand Down Expand Up @@ -137,6 +138,7 @@ CGameSA::CGameSA()
m_pWeaponStatsManager = new CWeaponStatManagerSA();
m_pPointLights = new CPointLightsSA();
m_collisionStore = new CColStoreSA();
m_pIplStore = new CIplStoreSA();

// Normal weapon types (WEAPONSKILL_STD)
for (int i = 0; i < NUM_WeaponInfosStdSkill; i++)
Expand Down Expand Up @@ -273,6 +275,7 @@ CGameSA::~CGameSA()
delete reinterpret_cast<CAudioContainerSA*>(m_pAudioContainer);
delete reinterpret_cast<CPointLightsSA*>(m_pPointLights);
delete static_cast<CColStoreSA*>(m_collisionStore);
delete static_cast<CIplStore*>(m_pIplStore);

delete[] ModelInfo;
delete[] ObjectGroupsInfo;
Expand Down Expand Up @@ -425,6 +428,9 @@ void CGameSA::Reset()

// Restore changed TXD IDs
CModelInfoSA::StaticResetTextureDictionaries();

// Restore default world state
RestoreGameBuildings();
}
}

Expand Down Expand Up @@ -882,6 +888,20 @@ void CGameSA::GetShaderReplacementStats(SShaderReplacementStats& outStats)
m_pRenderWare->GetShaderReplacementStats(outStats);
}

void CGameSA::RemoveAllBuildings()
{
m_pIplStore->SetDynamicIplStreamingEnabled(false);

m_pPools->GetBuildingsPool().RemoveAllBuildings();
}

void CGameSA::RestoreGameBuildings()
{
m_pPools->GetBuildingsPool().RestoreAllBuildings();

m_pIplStore->SetDynamicIplStreamingEnabled(true, [](CIplSAInterface* ipl) { return memcmp("barriers", ipl->name, 8) != 0; });
}

// Ensure models have the default lod distances
void CGameSA::ResetModelLodDistances()
{
Expand Down
5 changes: 5 additions & 0 deletions Client/game_sa/CGameSA.h
Expand Up @@ -152,6 +152,7 @@ class CGameSA : public CGame
CColStore* GetCollisionStore() override { return m_collisionStore; }
CRenderWareSA* GetRenderWareSA() { return m_pRenderWare; }
CFxManagerSA* GetFxManagerSA() { return m_pFxManager; }
CIplStore* GetIplStore() { return m_pIplStore; };

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

void RemoveAllBuildings();
void RestoreGameBuildings();

private:
CPools* m_pPools;
CPlayerInfo* m_pPlayerInfo;
Expand Down Expand Up @@ -320,6 +324,7 @@ class CGameSA : public CGame
CGameSettings* m_pSettings;
CCarEnterExit* m_pCarEnterExit;
CControllerConfigManager* m_pControllerConfigManager;
CIplStore* m_pIplStore;

eGameVersion m_eGameVersion;
bool m_bAsyncScriptEnabled;
Expand Down
37 changes: 37 additions & 0 deletions Client/game_sa/CIplSA.h
@@ -0,0 +1,37 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto v1.0
* LICENSE: See LICENSE in the top level directory
* FILE: game_sa/CIplSA.h
* PURPOSE: Header file for game IPL class
*
* Multi Theft Auto is available from http://www.multitheftauto.com/
*
*****************************************************************************/

#pragma once

#include <cstdint>
#include "CRect.h"

class CIplSAInterface
{
public:
CRect rect;
char name[16];
uint16_t unk;
uint16_t minBuildId;
uint16_t maxBuildId;
uint16_t minBummyId;
uint16_t maxDummyId;
uint16_t relatedIpl;
uint8_t interior;
uint8_t unk2;
uint8_t bLoadReq;
uint8_t bDisabledStreaming;
uint8_t unk3;
uint8_t unk4;
uint8_t unk5;
uint8_t unk6;
};
static_assert(sizeof(CIplSAInterface) == 0x34, "Wrong CIplSAInterface size");

0 comments on commit eb6b18a

Please sign in to comment.