Skip to content

Add removeAllGameBuildings / restoreAllGameBuildings API #3275

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 178 additions & 0 deletions Client/game_sa/CBuildingsPoolSA.cpp
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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");
Loading