Skip to content

Commit

Permalink
Lua API for buildings (multitheftauto#3274)
Browse files Browse the repository at this point in the history
* createBuilding

* Fix collision issue

* Remove unused changes

* Fix buildings API

* Fix custom models and setElementModel

* Fix build

* Small fixes

* Fix some edge cases

* Fix from review

* Fix optional value

* Fix dynamic model spawn

* Fix function name

* review fixes

* Fix getElementModel function for buildings

* Fix buildings leak

* Add get rotation and set rotation functions for buildings

* fix setElementModel

* Fix rotation

* Add position checks

* fix

* fix IsValidPosition

---------

Co-authored-by: TEDERIs <[email protected]>
  • Loading branch information
TheNormalnij and tederis authored Feb 29, 2024
1 parent 1b40db7 commit 81242ed
Show file tree
Hide file tree
Showing 32 changed files with 739 additions and 51 deletions.
18 changes: 18 additions & 0 deletions Client/game_sa/CBuildingSA.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto v1.0
* LICENSE: See LICENSE in the top level directory
* FILE: game_sa/CBuildingSA.cpp
* PURPOSE: Building entity
*
* Multi Theft Auto is available from http://www.multitheftauto.com/
*
*****************************************************************************/

#include "StdInc.h"
#include "CBuildingSA.h"

CBuildingSA::CBuildingSA(CBuildingSAInterface* pInterface)
{
SetInterface(pInterface);
}
28 changes: 28 additions & 0 deletions Client/game_sa/CBuildingSA.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto v1.0
* LICENSE: See LICENSE in the top level directory
* FILE: game_sa/CBuildingSA.h
* PURPOSE: Header file for game building class
*
* Multi Theft Auto is available from http://www.multitheftauto.com/
*
*****************************************************************************/

#pragma once

#include <game/CBuilding.h>
#include "CEntitySA.h"

class CBuildingSAInterface : public CEntitySAInterface
{
};
static_assert(sizeof(CBuildingSAInterface) == 0x38, "Invalid size CBuildingSAInterface");

class CBuildingSA final : public virtual CBuilding, public virtual CEntitySA
{
public:
CBuildingSA(CBuildingSAInterface* pInterface);

CBuildingSAInterface* GetBuildingInterface() { return reinterpret_cast<CBuildingSAInterface*>(GetInterface()); };
};
6 changes: 6 additions & 0 deletions Client/game_sa/CFileLoaderSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ void CFileLoaderSA::StaticSetHooks()
HookInstall(0x538690, (DWORD)CFileLoader_LoadObjectInstance, 5);
}

CEntitySAInterface* CFileLoaderSA::LoadObjectInstance(SFileObjectInstance* obj)
{
// Second argument is model name. It's unused in the function
return ((CEntitySAInterface * (__cdecl*)(SFileObjectInstance*, const char*))0x538090)(obj, nullptr);
}

class CAtomicModelInfo
{
public:
Expand Down
2 changes: 2 additions & 0 deletions Client/game_sa/CFileLoaderSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class CFileLoaderSA
CFileLoaderSA();
~CFileLoaderSA();

static CEntitySAInterface* LoadObjectInstance(SFileObjectInstance*);

static void StaticSetHooks();
};

Expand Down
2 changes: 2 additions & 0 deletions Client/game_sa/CModelInfoSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,8 @@ class CModelInfoSA : public CModelInfo
// Vehicle towing functions
bool IsTowableBy(CModelInfo* towingModel) override;

bool IsDynamic() { return m_pInterface ? m_pInterface->usDynamicIndex != 0xffff : false; };

private:
void CopyStreamingInfoFromModel(ushort usCopyFromModelID);
void RwSetSupportedUpgrades(RwFrame* parent, DWORD dwModel);
Expand Down
118 changes: 117 additions & 1 deletion Client/game_sa/CPoolsSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "CBikeSA.h"
#include "CBmxSA.h"
#include "CBoatSA.h"
#include "CBuildingSA.h"
#include "CGameSA.h"
#include "CHeliSA.h"
#include "CMonsterTruckSA.h"
Expand All @@ -24,6 +25,7 @@
#include "CTrainSA.h"
#include "CWorldSA.h"
#include "CKeyGenSA.h"
#include "CFileLoaderSA.h"

extern CGameSA* pGame;

Expand All @@ -33,6 +35,7 @@ CPoolsSA::CPoolsSA()
m_ppObjectPoolInterface = (CPoolSAInterface<CObjectSAInterface>**)0xB7449C;
m_ppVehiclePoolInterface = (CPoolSAInterface<CVehicleSAInterface>**)0xB74494;
m_ppTxdPoolInterface = (CPoolSAInterface<CTextureDictonarySAInterface>**)0xC8800C;
m_ppBuildingPoolInterface = (CPoolSAInterface<CBuildingSAInterface>**)0xB74498;

m_bGetVehicleEnabled = true;
}
Expand Down Expand Up @@ -329,6 +332,107 @@ void CPoolsSA::DeleteAllObjects()
}
}

//////////////////////////////////////////////////////////////////////////////////////////
// BUILDINGS POOL //
//////////////////////////////////////////////////////////////////////////////////////////

inline bool CPoolsSA::AddBuildingToPool(CClientBuilding* pClientBuilding, CBuildingSA* pBuilding)
{
// Grab the new object interface
CBuildingSAInterface* pInterface = pBuilding->GetBuildingInterface();

if (!pInterface)
return false;

DWORD dwElementIndexInPool = GetBuildingPoolIndex((std::uint8_t*)pInterface);
if (dwElementIndexInPool >= MAX_BUILDINGS)
{
return false;
}

m_buildingPool.arrayOfClientEntities[dwElementIndexInPool] = {pBuilding, (CClientEntity*)pClientBuilding};

// Increase the count of objects
++m_buildingPool.ulCount;

return true;
}

CBuilding* CPoolsSA::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 CPoolsSA::RemoveBuilding(CBuilding* pBuilding)
{
assert(NULL != pBuilding);

CBuildingSAInterface* pInterface = pBuilding->GetBuildingInterface();

DWORD dwElementIndexInPool = GetBuildingPoolIndex((std::uint8_t*)pInterface);
if (dwElementIndexInPool >= MAX_BUILDINGS)
{
return;
}

// Remove building from world
pGame->GetWorld()->Remove(pInterface, CBuildingPool_Destructor);

// 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;
}

bool CPoolsSA::HasFreeBuildingSlot()
{
return (*m_ppBuildingPoolInterface)->GetFreeSlot() != -1;
}

//////////////////////////////////////////////////////////////////////////////////////////
// PEDS POOL //
//////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -676,7 +780,7 @@ DWORD CPoolsSA::GetPedPoolIndex(std::uint8_t* pInterface)
{
return MAX_PEDS;
}
return ((pInterface - pTheObjects) / dwAlignedSize);
return ((pInterface - pTheObjects) / dwAlignedSize);
}

DWORD CPoolsSA::GetVehiclePoolIndex(std::uint8_t* pInterface)
Expand All @@ -703,6 +807,18 @@ DWORD CPoolsSA::GetObjectPoolIndex(std::uint8_t* pInterface)
return ((pInterface - pTheObjects) / dwAlignedSize);
}

DWORD CPoolsSA::GetBuildingPoolIndex(std::uint8_t* pInterface)
{
DWORD dwAlignedSize = sizeof(CBuildingSAInterface);
std::uint8_t* pTheObjects = (std::uint8_t*)(*m_ppBuildingPoolInterface)->m_pObjects;
DWORD dwMaxIndex = MAX_BUILDINGS - 1;
if (pInterface < pTheObjects || pInterface > pTheObjects + (dwMaxIndex * dwAlignedSize))
{
return MAX_BUILDINGS;
}
return ((pInterface - pTheObjects) / dwAlignedSize);
}

uint CPoolsSA::GetModelIdFromClump(RpClump* pRpClump)
{
// Search our pools for a match
Expand Down
31 changes: 21 additions & 10 deletions Client/game_sa/CPoolsSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "CPedSA.h"
#include "CVehicleSA.h"
#include "CObjectSA.h"
#include "CBuildingSA.h"
#include "CTextureDictonarySA.h"

#define INVALID_POOL_ARRAY_ID 0xFFFFFFFF
Expand Down Expand Up @@ -170,6 +171,15 @@ class CPoolsSA : public CPools
unsigned long GetObjectCount() { return m_objectPool.ulCount; }
void DeleteAllObjects();

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

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

// Peds pool
CPed* AddPed(CClientPed* pClientPed, unsigned int nModelIndex);
CPed* AddPed(CClientPed* pClientPed, DWORD* pGameInterface);
Expand All @@ -195,6 +205,7 @@ class CPoolsSA : public CPools
DWORD GetPedPoolIndex(std::uint8_t* pInterface);
DWORD GetVehiclePoolIndex(std::uint8_t* pInterfacee);
DWORD GetObjectPoolIndex(std::uint8_t* pInterface);
DWORD GetBuildingPoolIndex(std::uint8_t* pInterface);

int GetNumberOfUsedSpaces(ePools pools);
int GetPoolDefaultCapacity(ePools pool);
Expand Down Expand Up @@ -231,16 +242,16 @@ class CPoolsSA : public CPools
};

// Pools
typedef SPoolData<CVehicleSA, CVehicleSAInterface, MAX_VEHICLES> vehiclePool_t;
typedef SPoolData<CPedSA, CPedSAInterface, MAX_PEDS> pedPool_t;
typedef SPoolData<CObjectSA, CObjectSAInterface, MAX_OBJECTS> objectPool_t;
vehiclePool_t m_vehiclePool;
pedPool_t m_pedPool;
objectPool_t m_objectPool;
CPoolSAInterface<CPedSAInterface>** m_ppPedPoolInterface;
CPoolSAInterface<CObjectSAInterface>** m_ppObjectPoolInterface;
CPoolSAInterface<CVehicleSAInterface>** m_ppVehiclePoolInterface;
CPoolSAInterface<CTextureDictonarySAInterface>** m_ppTxdPoolInterface;
SPoolData<CVehicleSA, CVehicleSAInterface, MAX_VEHICLES> m_vehiclePool;
SPoolData<CPedSA, CPedSAInterface, MAX_PEDS> m_pedPool;
SPoolData<CObjectSA, CObjectSAInterface, MAX_OBJECTS> m_objectPool;
SPoolData<CBuildingSA, CBuildingSAInterface, MAX_BUILDINGS> m_buildingPool;

CPoolSAInterface<CPedSAInterface>** m_ppPedPoolInterface;
CPoolSAInterface<CObjectSAInterface>** m_ppObjectPoolInterface;
CPoolSAInterface<CVehicleSAInterface>** m_ppVehiclePoolInterface;
CPoolSAInterface<CTextureDictonarySAInterface>** m_ppTxdPoolInterface;
CPoolSAInterface<CBuildingSAInterface>** m_ppBuildingPoolInterface;

bool m_bGetVehicleEnabled;
};
Expand Down
2 changes: 2 additions & 0 deletions Client/mods/deathmatch/StdInc.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include <CClientCommon.h>
#include <CClientManager.h>
#include <CClient3DMarker.h>
#include <CClientBuilding.h>
#include <CClientCheckpoint.h>
#include <CClientColShape.h>
#include <CClientColCircle.h>
Expand Down Expand Up @@ -143,6 +144,7 @@
#include <luadefs/CLuaWaterDefs.h>
#include <luadefs/CLuaWeaponDefs.h>
#include <luadefs/CLuaWorldDefs.h>
#include <luadefs/CLuaBuildingDefs.h>
#include <CRemoteCalls.h>

// Shared includes
Expand Down
Loading

0 comments on commit 81242ed

Please sign in to comment.