From f8e7139e9e8c3bacdf71b7ec4bf0f01163e85bfe Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Mon, 18 Dec 2023 03:10:15 +0300 Subject: [PATCH 01/21] createBuilding --- Client/game_sa/CBuildingSA.cpp | 18 ++++ Client/game_sa/CBuildingSA.h | 28 ++++++ Client/game_sa/CEntitySA.cpp | 6 ++ Client/game_sa/CEntitySA.h | 1 + Client/game_sa/CFileLoaderSA.cpp | 9 +- Client/game_sa/CFileLoaderSA.h | 6 +- Client/game_sa/CPoolsSA.cpp | 94 ++++++++++++++++++- Client/game_sa/CPoolsSA.h | 30 ++++-- Client/mods/deathmatch/StdInc.h | 2 + .../mods/deathmatch/logic/CClientBuilding.cpp | 53 +++++++++++ .../mods/deathmatch/logic/CClientBuilding.h | 44 +++++++++ .../logic/CClientBuildingManager.cpp | 66 +++++++++++++ .../deathmatch/logic/CClientBuildingManager.h | 41 ++++++++ Client/mods/deathmatch/logic/CClientEntity.h | 2 + .../mods/deathmatch/logic/CClientManager.cpp | 4 + Client/mods/deathmatch/logic/CClientManager.h | 3 + .../deathmatch/logic/lua/CLuaFunctionDefs.cpp | 2 + .../deathmatch/logic/lua/CLuaFunctionDefs.h | 1 + .../logic/lua/CLuaFunctionParseHelpers.h | 4 + .../mods/deathmatch/logic/lua/CLuaManager.cpp | 1 + Client/mods/deathmatch/logic/lua/LuaCommon.h | 1 + .../logic/luadefs/CLuaBuildingDefs.cpp | 51 ++++++++++ .../logic/luadefs/CLuaBuildingDefs.h | 23 +++++ .../deathmatch/logic/luadefs/CLuaDefs.cpp | 2 + .../mods/deathmatch/logic/luadefs/CLuaDefs.h | 1 + Client/sdk/game/CBuilding.h | 24 +++++ Client/sdk/game/CPools.h | 6 ++ .../deathmatch/logic/lua/CLuaFunctionParser.h | 2 - 28 files changed, 508 insertions(+), 17 deletions(-) create mode 100644 Client/game_sa/CBuildingSA.cpp create mode 100644 Client/game_sa/CBuildingSA.h create mode 100644 Client/mods/deathmatch/logic/CClientBuilding.cpp create mode 100644 Client/mods/deathmatch/logic/CClientBuilding.h create mode 100644 Client/mods/deathmatch/logic/CClientBuildingManager.cpp create mode 100644 Client/mods/deathmatch/logic/CClientBuildingManager.h create mode 100644 Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp create mode 100644 Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.h create mode 100644 Client/sdk/game/CBuilding.h diff --git a/Client/game_sa/CBuildingSA.cpp b/Client/game_sa/CBuildingSA.cpp new file mode 100644 index 00000000000..964506dd02d --- /dev/null +++ b/Client/game_sa/CBuildingSA.cpp @@ -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); +} diff --git a/Client/game_sa/CBuildingSA.h b/Client/game_sa/CBuildingSA.h new file mode 100644 index 00000000000..6d6794ceb76 --- /dev/null +++ b/Client/game_sa/CBuildingSA.h @@ -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 +#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(GetInterface()); }; +}; diff --git a/Client/game_sa/CEntitySA.cpp b/Client/game_sa/CEntitySA.cpp index 4466a53fe4b..ad1506abc9f 100644 --- a/Client/game_sa/CEntitySA.cpp +++ b/Client/game_sa/CEntitySA.cpp @@ -43,6 +43,12 @@ void CEntitySAInterface::UpdateRpHAnim() ((void(__thiscall*)(CEntitySAInterface*))0x532B20)(this); } +void CEntitySAInterface::AddRect() +{ + typedef void(__thiscall * add_rect_t)(CEntitySAInterface*); + ((add_rect_t)(this->vtbl->Add))(this); +} + CRect* CEntitySAInterface::GetBoundRect_(CRect* pRect) { CColModelSAInterface* colModel = CModelInfoSAInterface::GetModelInfo(m_nModelIndex)->pColModel; diff --git a/Client/game_sa/CEntitySA.h b/Client/game_sa/CEntitySA.h index 101b88a46af..708f0e0aab9 100644 --- a/Client/game_sa/CEntitySA.h +++ b/Client/game_sa/CEntitySA.h @@ -191,6 +191,7 @@ class CEntitySAInterface uint8 m_pad0; // 55 + void AddRect(); CRect* GetBoundRect_(CRect* pRect); void TransformFromObjectSpace(CVector& outPosn, CVector const& offset); CVector* GetBoundCentre(CVector* pOutCentre); diff --git a/Client/game_sa/CFileLoaderSA.cpp b/Client/game_sa/CFileLoaderSA.cpp index 5bb8dd1fe0f..01372c29bbc 100644 --- a/Client/game_sa/CFileLoaderSA.cpp +++ b/Client/game_sa/CFileLoaderSA.cpp @@ -28,6 +28,11 @@ void CFileLoaderSA::StaticSetHooks() HookInstall(0x538690, (DWORD)CFileLoader_LoadObjectInstance, 5); } +CBuildingSAInterface* CFileLoaderSA::LoadFileObjectInstance(SFileObjectInstance* obj) +{ + return ((CBuildingSAInterface * (__cdecl*)(SFileObjectInstance*))0x538090)(obj); +} + class CAtomicModelInfo { public: @@ -201,7 +206,7 @@ RpAtomic* CFileLoader_SetRelatedModelInfoCB(RpAtomic* atomic, SRelatedModelInfo* return atomic; } -CEntitySAInterface* CFileLoader_LoadObjectInstance(const char* szLine) +CBuildingSAInterface* CFileLoader_LoadObjectInstance(const char* szLine) { char szModelName[24]; SFileObjectInstance inst; @@ -217,5 +222,5 @@ CEntitySAInterface* CFileLoader_LoadObjectInstance(const char* szLine) if (fLenSq > 0.0f && std::fabs(fLenSq - 1.0f) > std::numeric_limits::epsilon()) inst.rotation /= std::sqrt(fLenSq); - return ((CEntitySAInterface * (__cdecl*)(SFileObjectInstance*))0x538090)(&inst); + return ((CBuildingSAInterface * (__cdecl*)(SFileObjectInstance*))0x538090)(&inst); } diff --git a/Client/game_sa/CFileLoaderSA.h b/Client/game_sa/CFileLoaderSA.h index f18c7e4633c..ad5103c75c1 100644 --- a/Client/game_sa/CFileLoaderSA.h +++ b/Client/game_sa/CFileLoaderSA.h @@ -3,7 +3,7 @@ #include "CVector.h" #include "CVector4D.h" -class CEntitySAInterface; +class CBuildingSAInterface; struct RpAtomic; struct RpClump; struct RwStream; @@ -29,9 +29,11 @@ class CFileLoaderSA CFileLoaderSA(); ~CFileLoaderSA(); + CBuildingSAInterface* LoadFileObjectInstance(SFileObjectInstance*); + static void StaticSetHooks(); }; bool CFileLoader_LoadAtomicFile(RwStream* stream, unsigned int modelId); RpAtomic* CFileLoader_SetRelatedModelInfoCB(RpAtomic* atomic, SRelatedModelInfo* pRelatedModelInfo); -CEntitySAInterface* CFileLoader_LoadObjectInstance(const char* szLine); +CBuildingSAInterface* CFileLoader_LoadObjectInstance(const char* szLine); diff --git a/Client/game_sa/CPoolsSA.cpp b/Client/game_sa/CPoolsSA.cpp index 9f3260029dd..1c817548627 100644 --- a/Client/game_sa/CPoolsSA.cpp +++ b/Client/game_sa/CPoolsSA.cpp @@ -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" @@ -24,6 +25,7 @@ #include "CTrainSA.h" #include "CWorldSA.h" #include "CKeyGenSA.h" +#include "CFileLoaderSA.h" extern CGameSA* pGame; @@ -33,6 +35,7 @@ CPoolsSA::CPoolsSA() m_ppObjectPoolInterface = (CPoolSAInterface**)0xB7449C; m_ppVehiclePoolInterface = (CPoolSAInterface**)0xB74494; m_ppTxdPoolInterface = (CPoolSAInterface**)0xC8800C; + m_ppBuildingPoolInterface = (CPoolSAInterface**)0xB74498; m_bGetVehicleEnabled = true; } @@ -329,6 +332,83 @@ 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; + } + else + { + 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(class CClientBuilding* pClientBuilding, uint16_t modelId, CVector vPos, CVector4D vRot, uint8_t interior) +{ + CFileLoaderSA loader{}; + + SFileObjectInstance instance; + instance.modelID = modelId; + instance.lod = -1; + instance.interiorID = interior; + instance.position = vPos; + instance.rotation = vRot; + + auto pBuilding = loader.LoadFileObjectInstance(&instance); + + pBuilding->m_pLod = nullptr; + pBuilding->m_iplIndex = 0; + + pBuilding->AddRect(); + + auto pBuildingSA = new CBuildingSA(pBuilding); + + 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; + } + + auto* pBuildingSA = m_buildingPool.arrayOfClientEntities[dwElementIndexInPool].pEntity; + m_buildingPool.arrayOfClientEntities[dwElementIndexInPool] = {nullptr, nullptr}; + + // Delete it from memory + delete pBuildingSA; + + // Decrease the count of elements in the pool + --m_buildingPool.ulCount; +} + ////////////////////////////////////////////////////////////////////////////////////////// // PEDS POOL // ////////////////////////////////////////////////////////////////////////////////////////// @@ -676,7 +756,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) @@ -703,6 +783,18 @@ DWORD CPoolsSA::GetObjectPoolIndex(std::uint8_t* pInterface) return ((pInterface - pTheObjects) / dwAlignedSize); } +DWORD CPoolsSA::GetBuildingPoolIndex(std::uint8_t* pInterface) +{ + DWORD dwAlignedSize = 412; + 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 diff --git a/Client/game_sa/CPoolsSA.h b/Client/game_sa/CPoolsSA.h index 60f5d549e83..edc404a7bb3 100644 --- a/Client/game_sa/CPoolsSA.h +++ b/Client/game_sa/CPoolsSA.h @@ -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 @@ -170,6 +171,14 @@ 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(class CClientBuilding*, uint16_t modelId, CVector vPos, CVector4D vRot, uint8_t interior); + void RemoveBuilding(CBuilding* pBuilding); + // Peds pool CPed* AddPed(CClientPed* pClientPed, unsigned int nModelIndex); CPed* AddPed(CClientPed* pClientPed, DWORD* pGameInterface); @@ -195,6 +204,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); @@ -231,16 +241,16 @@ class CPoolsSA : public CPools }; // Pools - typedef SPoolData vehiclePool_t; - typedef SPoolData pedPool_t; - typedef SPoolData objectPool_t; - vehiclePool_t m_vehiclePool; - pedPool_t m_pedPool; - objectPool_t m_objectPool; - CPoolSAInterface** m_ppPedPoolInterface; - CPoolSAInterface** m_ppObjectPoolInterface; - CPoolSAInterface** m_ppVehiclePoolInterface; - CPoolSAInterface** m_ppTxdPoolInterface; + SPoolData m_vehiclePool; + SPoolData m_pedPool; + SPoolData m_objectPool; + SPoolData m_buildingPool; + + CPoolSAInterface** m_ppPedPoolInterface; + CPoolSAInterface** m_ppObjectPoolInterface; + CPoolSAInterface** m_ppVehiclePoolInterface; + CPoolSAInterface** m_ppTxdPoolInterface; + CPoolSAInterface** m_ppBuildingPoolInterface; bool m_bGetVehicleEnabled; }; diff --git a/Client/mods/deathmatch/StdInc.h b/Client/mods/deathmatch/StdInc.h index 0d7cc5168c9..68b18a6ab58 100644 --- a/Client/mods/deathmatch/StdInc.h +++ b/Client/mods/deathmatch/StdInc.h @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -143,6 +144,7 @@ #include #include #include +#include #include // Shared includes diff --git a/Client/mods/deathmatch/logic/CClientBuilding.cpp b/Client/mods/deathmatch/logic/CClientBuilding.cpp new file mode 100644 index 00000000000..17621730d6b --- /dev/null +++ b/Client/mods/deathmatch/logic/CClientBuilding.cpp @@ -0,0 +1,53 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto v1.0 + * (Shared logic for modifications) + * LICENSE: See LICENSE in the top level directory + * FILE: mods/shared_logic/CClientBuilding.cpp + * PURPOSE: Buildings handling class + * + *****************************************************************************/ + +#include "StdInc.h" + +CClientBuilding::CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, CVector pos, CVector4D rot, uint8_t interior) + : ClassInit(this), + CClientEntity(ID), + m_pBuildingManager(pManager->GetBuildingManager()), + m_usModelId(usModelId), + m_vPos(pos), + m_vRot(rot), + m_interior(interior) +{ + m_pBuilding = nullptr; + m_pManager = pManager; + SetTypeName("building"); + m_pBuildingManager->AddToList(this); + Create(); +} + +CClientBuilding::~CClientBuilding() +{ + m_pBuildingManager->RemoveFromList(this); + if (m_pBuilding) + { + Destroy(); + } +} + +void CClientBuilding::Create() +{ + if (m_pBuilding) + return; + + m_pBuilding = g_pGame->GetPools()->AddBuilding(this, m_usModelId, m_vPos, m_vRot, m_interior); +} + +void CClientBuilding::Destroy() +{ + if (m_pBuilding) + { + g_pGame->GetPools()->RemoveBuilding(m_pBuilding); + m_pBuilding = nullptr; + } +} diff --git a/Client/mods/deathmatch/logic/CClientBuilding.h b/Client/mods/deathmatch/logic/CClientBuilding.h new file mode 100644 index 00000000000..7ff5e768857 --- /dev/null +++ b/Client/mods/deathmatch/logic/CClientBuilding.h @@ -0,0 +1,44 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto v1.0 + * (Shared logic for modifications) + * LICENSE: See LICENSE in the top level directory + * FILE: mods/shared_logic/CClientBuilding.h + * PURPOSE: Physical object entity class + * + *****************************************************************************/ + +class CClientBuilding; + +#pragma once + +#include + +class CClientBuilding : public CClientEntity +{ + DECLARE_CLASS(CClientBuilding, CClientEntity) + friend class CClientBuildingManager; + +public: + CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, CVector pos, CVector4D rot, uint8_t interior); + ~CClientBuilding(); + + void Unlink(){}; + void GetPosition(CVector& vecPosition) const { vecPosition = m_vPos; }; + void SetPosition(const CVector& vecPosition) { m_vPos = vecPosition; }; + + eClientEntityType GetType() const { return CCLIENTBUILDING; } + +private: + void Create(); + void Destroy(); + +private: + CClientBuildingManager* m_pBuildingManager; + + CBuilding* m_pBuilding; + uint16_t m_usModelId; + CVector m_vPos; + CVector4D m_vRot; + uint8_t m_interior; +}; diff --git a/Client/mods/deathmatch/logic/CClientBuildingManager.cpp b/Client/mods/deathmatch/logic/CClientBuildingManager.cpp new file mode 100644 index 00000000000..fb9a512ff29 --- /dev/null +++ b/Client/mods/deathmatch/logic/CClientBuildingManager.cpp @@ -0,0 +1,66 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto v1.0 + * (Shared logic for modifications) + * LICENSE: See LICENSE in the top level directory + * FILE: mods/shared_logic/CClientBuildingManager.cpp + * PURPOSE: Building manager class + * + *****************************************************************************/ + +#include "StdInc.h" + +CClientBuildingManager::CClientBuildingManager(CClientManager* pManager) +{ + // Init + m_bRemoveFromList = true; +} + +CClientBuildingManager::~CClientBuildingManager() +{ + // Delete all our buildings + RemoveAll(); +} + +void CClientBuildingManager::RemoveAll() +{ + // Make sure they don't remove themselves from our list + m_bRemoveFromList = false; + + // Run through our list deleting the buildings + auto iter = m_List.begin(); + for (; iter != m_List.end(); iter++) + { + delete *iter; + } + + // Allow list removal again + m_bRemoveFromList = true; +} + +bool CClientBuildingManager::Exists(CClientBuilding* pBuilding) +{ + // Matches given DFF? + auto iter = m_List.begin(); + for (; iter != m_List.end(); iter++) + { + // Match? + if (pBuilding == *iter) + { + // It exists + return true; + } + } + + // It doesn't + return false; +} + +void CClientBuildingManager::RemoveFromList(CClientBuilding* pBuilding) +{ + // Can we remove anything from the list? + if (m_bRemoveFromList) + { + m_List.remove(pBuilding); + } +} diff --git a/Client/mods/deathmatch/logic/CClientBuildingManager.h b/Client/mods/deathmatch/logic/CClientBuildingManager.h new file mode 100644 index 00000000000..dd595d3cb37 --- /dev/null +++ b/Client/mods/deathmatch/logic/CClientBuildingManager.h @@ -0,0 +1,41 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto v1.0 + * (Shared logic for modifications) + * LICENSE: See LICENSE in the top level directory + * FILE: mods/shared_logic/CClientBuildingManager.h + * PURPOSE: Building manager class + * + *****************************************************************************/ + +class CClientBuildingManager; + +#pragma once + +#include +#include "CClientBuilding.h" + +class CClientBuildingManager +{ + friend class CClientBuilding; + +public: + CClientBuildingManager(class CClientManager* pManager); + ~CClientBuildingManager(); + + void RemoveAll(); + bool Exists(CClientBuilding* pBuilding); + + std::list::const_iterator IterBegin() { return m_List.begin(); } + std::list::const_iterator IterEnd() { return m_List.end(); } + +private: + void AddToList(CClientBuilding* pBuilding) { m_List.push_back(pBuilding); } + void RemoveFromList(CClientBuilding* pBuilding); + + class CClientObjectManager* m_pObjectManager; + class CClientVehicleManager* m_pVehicleManager; + + std::list m_List; + bool m_bRemoveFromList; +}; diff --git a/Client/mods/deathmatch/logic/CClientEntity.h b/Client/mods/deathmatch/logic/CClientEntity.h index bd60dab3ba4..0d84526d8bf 100644 --- a/Client/mods/deathmatch/logic/CClientEntity.h +++ b/Client/mods/deathmatch/logic/CClientEntity.h @@ -79,6 +79,7 @@ enum eClientEntityType CCLIENTVECTORGRAPHIC, CCLIENTUNKNOWN, CCLIENTIMG, + CCLIENTBUILDING, }; class CEntity; @@ -143,6 +144,7 @@ enum eCClientEntityClassTypes CLASS_CClientPointLights, CLASS_CClientSearchLight, CLASS_CClientIMG, + CLASS_CClientBuilding, }; class CClientEntity : public CClientEntityBase diff --git a/Client/mods/deathmatch/logic/CClientManager.cpp b/Client/mods/deathmatch/logic/CClientManager.cpp index 21962cc8f33..e3a808555b4 100644 --- a/Client/mods/deathmatch/logic/CClientManager.cpp +++ b/Client/mods/deathmatch/logic/CClientManager.cpp @@ -54,6 +54,7 @@ CClientManager::CClientManager() m_pModelManager = new CClientModelManager(); m_pPacketRecorder = new CClientPacketRecorder(this); m_pImgManager = new CClientIMGManager(this); + m_pBuildingManager = new CClientBuildingManager(this); m_bBeingDeleted = false; m_bGameUnloadedFlag = false; @@ -177,6 +178,9 @@ CClientManager::~CClientManager() delete m_pImgManager; m_pImgManager = nullptr; + + delete m_pBuildingManager; + m_pBuildingManager = nullptr; } // diff --git a/Client/mods/deathmatch/logic/CClientManager.h b/Client/mods/deathmatch/logic/CClientManager.h index e916c8eb738..92f8481db85 100644 --- a/Client/mods/deathmatch/logic/CClientManager.h +++ b/Client/mods/deathmatch/logic/CClientManager.h @@ -43,6 +43,7 @@ class CClientManager; #include "CClientPointLightsManager.h" #include "CClientModelManager.h" #include "CClientIMGManager.h" +#include "CClientBuildingManager.h" class CClientProjectileManager; class CClientExplosionManager; @@ -96,6 +97,7 @@ class CClientManager CClientEffectManager* GetEffectManager() { return m_pEffectManager; } CClientPointLightsManager* GetPointLightsManager() { return m_pPointLightsManager; } CClientIMGManager* GetIMGManager() { return m_pImgManager; } + CClientBuildingManager* GetBuildingManager() { return m_pBuildingManager; } bool IsGameLoaded() { return g_pGame->GetSystemState() == 9 && !m_bGameUnloadedFlag && g_pCore->GetNetwork()->GetServerBitStreamVersion(); } bool IsBeingDeleted() { return m_bBeingDeleted; } @@ -148,6 +150,7 @@ class CClientManager CClientModelManager* m_pModelManager; CClientIMGManager* m_pImgManager; CClientPacketRecorder* m_pPacketRecorder; + CClientBuildingManager* m_pBuildingManager; bool m_bBeingDeleted; bool m_bGameUnloadedFlag; int m_iNumLowLODElements; diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.cpp b/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.cpp index 912fd99f66b..feb2bdf0585 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.cpp @@ -31,6 +31,7 @@ CClientDFFManager* CLuaFunctionDefs::m_pDFFManager; CClientColModelManager* CLuaFunctionDefs::m_pColModelManager; CRegisteredCommands* CLuaFunctionDefs::m_pRegisteredCommands; CClientIMGManager* CLuaFunctionDefs::m_pImgManager; +CClientBuildingManager* CLuaFunctionDefs::m_pBuildingManager; void CLuaFunctionDefs::Initialize(CLuaManager* pLuaManager, CScriptDebugging* pScriptDebugging, CClientGame* pClientGame) { @@ -55,4 +56,5 @@ void CLuaFunctionDefs::Initialize(CLuaManager* pLuaManager, CScriptDebugging* pS m_pColModelManager = m_pManager->GetColModelManager(); m_pRegisteredCommands = m_pClientGame->GetRegisteredCommands(); m_pImgManager = m_pManager->GetIMGManager(); + m_pBuildingManager = m_pManager->GetBuildingManager(); } diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.h b/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.h index 1681110616d..105754152f5 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.h +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.h @@ -139,4 +139,5 @@ class CLuaFunctionDefs static CClientColModelManager* m_pColModelManager; static CRegisteredCommands* m_pRegisteredCommands; static CClientIMGManager* m_pImgManager; + static CClientBuildingManager* m_pBuildingManager; }; diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h index 5688c78d345..7f0b98c6791 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h @@ -272,6 +272,10 @@ inline SString GetClassTypeName(CClientIMG*) { return "img"; } +inline SString GetClassTypeName(CClientBuilding*) +{ + return "building"; +} inline SString GetClassTypeName(CClientSound*) { return "sound"; diff --git a/Client/mods/deathmatch/logic/lua/CLuaManager.cpp b/Client/mods/deathmatch/logic/lua/CLuaManager.cpp index 33388a5edc1..c2a28809af0 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaManager.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaManager.cpp @@ -280,4 +280,5 @@ void CLuaManager::LoadCFunctions() CLuaXMLDefs::LoadFunctions(); CLuaClientDefs::LoadFunctions(); CLuaDiscordDefs::LoadFunctions(); + CLuaBuildingDefs::LoadFunctions(); } diff --git a/Client/mods/deathmatch/logic/lua/LuaCommon.h b/Client/mods/deathmatch/logic/lua/LuaCommon.h index 238cfeeed52..20dda7ff111 100644 --- a/Client/mods/deathmatch/logic/lua/LuaCommon.h +++ b/Client/mods/deathmatch/logic/lua/LuaCommon.h @@ -38,6 +38,7 @@ class CClientRadarMarker; class CClientTeam; class CClientTXD; class CClientIMG; +class CClientBuilding; class CClientVehicle; class CClientWater; class CClientWeapon; diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp new file mode 100644 index 00000000000..1015fc453ca --- /dev/null +++ b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp @@ -0,0 +1,51 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ + +#include "StdInc.h" +#include + +void CLuaBuildingDefs::LoadFunctions() +{ + // Backwards compatibility functions + constexpr static const std::pair functions[]{ + {"createBuilding", ArgumentParser}, + }; + + // Add functions + for (const auto& [name, func] : functions) + CLuaCFunctions::AddFunction(name, func); +} + +void CLuaBuildingDefs::AddClass(lua_State* luaVM) +{ + lua_newclass(luaVM); + + lua_classfunction(luaVM, "create", "createBuilding"); + + lua_registerclass(luaVM, "Building"); +} + +CClientBuilding* CLuaBuildingDefs::CreateBuilding(lua_State* const luaVM, uint16_t modelId, CVector pos, CVector4D rot, uint8_t interior) +{ + CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaVM); + + // Get the resource we belong to + CResource* pResource = pLuaMain->GetResource(); + if (!pResource) + return false; + + // Grab the resource root entity + CClientEntity* pRoot = pResource->GetResourceDynamicEntity(); + // Create the img handle + CClientBuilding* pBuilding = new CClientBuilding(m_pManager, INVALID_ELEMENT_ID, modelId, pos, rot, interior); + + pBuilding->SetParent(pRoot); + + return pBuilding; +} diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.h new file mode 100644 index 00000000000..f158f225879 --- /dev/null +++ b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.h @@ -0,0 +1,23 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto v1.x + * LICENSE: See LICENSE in the top level directory + * FILE: mods/shared_logic/luadefs/CLuaBuildingDefs.h + * PURPOSE: Lua building definitions class header + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ + +#pragma once +#include "CLuaDefs.h" + +class CLuaBuildingDefs : public CLuaDefs +{ +public: + static void LoadFunctions(); + static void AddClass(lua_State* luaVM); + + // Buiding create funcs + static CClientBuilding* CreateBuilding(lua_State* const luaVM, uint16_t modelId, CVector pos, CVector4D rot, uint8_t interior = 0); +}; diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaDefs.cpp index de07ea84a4d..457f72998f8 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaDefs.cpp @@ -31,6 +31,7 @@ CClientDFFManager* CLuaDefs::m_pDFFManager = NULL; CClientColModelManager* CLuaDefs::m_pColModelManager = NULL; CRegisteredCommands* CLuaDefs::m_pRegisteredCommands = NULL; CClientIMGManager* CLuaDefs::m_pImgManager = NULL; +CClientBuildingManager* CLuaDefs::m_pBuildingManager = nullptr; bool ms_bRegisterdPostCallHook = false; void CLuaDefs::Initialize(CClientGame* pClientGame, CLuaManager* pLuaManager, CScriptDebugging* pScriptDebugging) @@ -56,6 +57,7 @@ void CLuaDefs::Initialize(CClientGame* pClientGame, CLuaManager* pLuaManager, CS m_pColModelManager = m_pManager->GetColModelManager(); m_pRegisteredCommands = pClientGame->GetRegisteredCommands(); m_pImgManager = m_pManager->GetIMGManager(); + m_pBuildingManager = m_pManager->GetBuildingManager(); } int CLuaDefs::CanUseFunction(lua_CFunction f, lua_State* luaVM) diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaDefs.h index cf043b45729..3f3c18386f4 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaDefs.h @@ -65,6 +65,7 @@ class CLuaDefs static CClientColModelManager* m_pColModelManager; static CRegisteredCommands* m_pRegisteredCommands; static CClientIMGManager* m_pImgManager; + static CClientBuildingManager* m_pBuildingManager; protected: // Old style: Only warn on failure. This should diff --git a/Client/sdk/game/CBuilding.h b/Client/sdk/game/CBuilding.h new file mode 100644 index 00000000000..8cbaf6abb45 --- /dev/null +++ b/Client/sdk/game/CBuilding.h @@ -0,0 +1,24 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto v1.0 + * LICENSE: See LICENSE in the top level directory + * FILE: sdk/game/CBuilding.h + * PURPOSE: Physical entity interface + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ + +#pragma once + +#include "CEntity.h" + +class CBuildingSAInterface; + +class CBuilding : public virtual CEntity +{ +public: + virtual ~CBuilding(){}; + + virtual CBuildingSAInterface* GetBuildingInterface() = 0; +}; diff --git a/Client/sdk/game/CPools.h b/Client/sdk/game/CPools.h index 76a39d99897..44cf5bf8fd1 100644 --- a/Client/sdk/game/CPools.h +++ b/Client/sdk/game/CPools.h @@ -18,6 +18,8 @@ class CObject; class CObjectSA; class CPed; class CPedSA; +class CBuilding; +class CBuildingSA; class CVector; class CVehicle; class CVehicleSA; @@ -82,6 +84,10 @@ class CPools virtual CPed* GetPedFromRef(DWORD dwGameRef) = 0; virtual unsigned long GetPedCount() = 0; + // Buildings pool + virtual CBuilding* AddBuilding(class CClientBuilding*, uint16_t modelId, CVector vPos, CVector4D vRot, uint8_t interior) = 0; + virtual void RemoveBuilding(CBuilding* pObject) = 0; + // Others virtual CVehicle* AddTrain(class CClientVehicle* pClientVehicle, CVector* vecPosition, DWORD dwModels[], int iSize, bool iDirection, uchar ucTrackId = 0xFF) = 0; diff --git a/Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h b/Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h index db8056763df..686a855deb9 100644 --- a/Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h +++ b/Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h @@ -588,8 +588,6 @@ struct CLuaFunctionParserBase // A vector3 may also be filled from a vector4 if (CLuaVector4D* pVec4D = cast((CLuaVector4D*)0); pVec4D != nullptr) return *pVec4D; - if (CLuaMatrix* pMatrix = cast((CLuaMatrix*)0); pMatrix != nullptr) - return *pMatrix; // Subtract one from the index, as the call to lua::PopPrimitive above increments the index, even if the // underlying element is of a wrong type From 5bc15b1cf525f41a70db7c345752427d6d0bea8b Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Mon, 18 Dec 2023 20:35:29 +0300 Subject: [PATCH 02/21] Fix collision issue --- Client/game_sa/CPoolsSA.cpp | 21 ++++++++++++++++++--- Client/sdk/game/CWorld.h | 2 ++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Client/game_sa/CPoolsSA.cpp b/Client/game_sa/CPoolsSA.cpp index 1c817548627..783127fcb79 100644 --- a/Client/game_sa/CPoolsSA.cpp +++ b/Client/game_sa/CPoolsSA.cpp @@ -364,8 +364,7 @@ inline bool CPoolsSA::AddBuildingToPool(CClientBuilding* pClientBuilding, CBuild CBuilding* CPoolsSA::AddBuilding(class CClientBuilding* pClientBuilding, uint16_t modelId, CVector vPos, CVector4D vRot, uint8_t interior) { - CFileLoaderSA loader{}; - + // Load building SFileObjectInstance instance; instance.modelID = modelId; instance.lod = -1; @@ -373,15 +372,23 @@ CBuilding* CPoolsSA::AddBuilding(class CClientBuilding* pClientBuilding, uint16_ instance.position = vPos; instance.rotation = vRot; + CFileLoaderSA loader{}; auto pBuilding = loader.LoadFileObjectInstance(&instance); + // Disable lod and ipl pBuilding->m_pLod = nullptr; pBuilding->m_iplIndex = 0; - pBuilding->AddRect(); + // 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; @@ -399,6 +406,14 @@ void CPoolsSA::RemoveBuilding(CBuilding* pBuilding) 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}; diff --git a/Client/sdk/game/CWorld.h b/Client/sdk/game/CWorld.h index c2319988d9e..de74bb40499 100644 --- a/Client/sdk/game/CWorld.h +++ b/Client/sdk/game/CWorld.h @@ -154,6 +154,8 @@ enum eDebugCaller CCivPed_Constructor, CCivPed_Destructor, CBuilding_Destructor, + CBuildingPool_Constructor, + CBuildingPool_Destructor, }; From e1f06fae9e9db9cae8b95474c63267745d541a72 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Mon, 18 Dec 2023 20:38:13 +0300 Subject: [PATCH 03/21] Remove unused changes --- Client/game_sa/CEntitySA.cpp | 6 ------ Client/game_sa/CEntitySA.h | 1 - 2 files changed, 7 deletions(-) diff --git a/Client/game_sa/CEntitySA.cpp b/Client/game_sa/CEntitySA.cpp index ad1506abc9f..4466a53fe4b 100644 --- a/Client/game_sa/CEntitySA.cpp +++ b/Client/game_sa/CEntitySA.cpp @@ -43,12 +43,6 @@ void CEntitySAInterface::UpdateRpHAnim() ((void(__thiscall*)(CEntitySAInterface*))0x532B20)(this); } -void CEntitySAInterface::AddRect() -{ - typedef void(__thiscall * add_rect_t)(CEntitySAInterface*); - ((add_rect_t)(this->vtbl->Add))(this); -} - CRect* CEntitySAInterface::GetBoundRect_(CRect* pRect) { CColModelSAInterface* colModel = CModelInfoSAInterface::GetModelInfo(m_nModelIndex)->pColModel; diff --git a/Client/game_sa/CEntitySA.h b/Client/game_sa/CEntitySA.h index 708f0e0aab9..101b88a46af 100644 --- a/Client/game_sa/CEntitySA.h +++ b/Client/game_sa/CEntitySA.h @@ -191,7 +191,6 @@ class CEntitySAInterface uint8 m_pad0; // 55 - void AddRect(); CRect* GetBoundRect_(CRect* pRect); void TransformFromObjectSpace(CVector& outPosn, CVector const& offset); CVector* GetBoundCentre(CVector* pOutCentre); From 388b4fe7f52a190fde05e67ab63fe7dd44a00368 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Mon, 18 Dec 2023 22:01:37 +0300 Subject: [PATCH 04/21] Fix buildings API --- Client/game_sa/CPoolsSA.cpp | 9 ++++--- Client/game_sa/CPoolsSA.h | 2 +- .../mods/deathmatch/logic/CClientBuilding.cpp | 25 +++++++++++++++++-- .../mods/deathmatch/logic/CClientBuilding.h | 19 +++++++++++--- .../logic/luadefs/CLuaBuildingDefs.cpp | 3 ++- Client/sdk/game/CPools.h | 2 +- Shared/mods/deathmatch/logic/Utils.h | 15 +++++++++++ 7 files changed, 63 insertions(+), 12 deletions(-) diff --git a/Client/game_sa/CPoolsSA.cpp b/Client/game_sa/CPoolsSA.cpp index 783127fcb79..2692b4942e5 100644 --- a/Client/game_sa/CPoolsSA.cpp +++ b/Client/game_sa/CPoolsSA.cpp @@ -362,15 +362,18 @@ inline bool CPoolsSA::AddBuildingToPool(CClientBuilding* pClientBuilding, CBuild return true; } -CBuilding* CPoolsSA::AddBuilding(class CClientBuilding* pClientBuilding, uint16_t modelId, CVector vPos, CVector4D vRot, uint8_t interior) +CBuilding* CPoolsSA::AddBuilding(CClientBuilding* pClientBuilding, uint16_t modelId, CVector *vPos, CVector4D *vRot, uint8_t interior) { // Load building SFileObjectInstance instance; instance.modelID = modelId; instance.lod = -1; instance.interiorID = interior; - instance.position = vPos; - instance.rotation = vRot; + instance.position = *vPos; + instance.rotation = *vRot; + + // Fix strange SA rotation + instance.rotation.fW = -instance.rotation.fW; CFileLoaderSA loader{}; auto pBuilding = loader.LoadFileObjectInstance(&instance); diff --git a/Client/game_sa/CPoolsSA.h b/Client/game_sa/CPoolsSA.h index edc404a7bb3..70cf4f20e2e 100644 --- a/Client/game_sa/CPoolsSA.h +++ b/Client/game_sa/CPoolsSA.h @@ -176,7 +176,7 @@ class CPoolsSA : public CPools bool AddBuildingToPool(CClientBuilding* pClientBuilding, CBuildingSA* pBuilding); public: - CBuilding* AddBuilding(class CClientBuilding*, uint16_t modelId, CVector vPos, CVector4D vRot, uint8_t interior); + CBuilding* AddBuilding(CClientBuilding*, uint16_t modelId, CVector *vPos, CVector4D *vRot, uint8_t interior); void RemoveBuilding(CBuilding* pBuilding); // Peds pool diff --git a/Client/mods/deathmatch/logic/CClientBuilding.cpp b/Client/mods/deathmatch/logic/CClientBuilding.cpp index 17621730d6b..daa27164039 100644 --- a/Client/mods/deathmatch/logic/CClientBuilding.cpp +++ b/Client/mods/deathmatch/logic/CClientBuilding.cpp @@ -10,7 +10,7 @@ #include "StdInc.h" -CClientBuilding::CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, CVector pos, CVector4D rot, uint8_t interior) +CClientBuilding::CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, CVector pos, CVector rot, uint8_t interior) : ClassInit(this), CClientEntity(ID), m_pBuildingManager(pManager->GetBuildingManager()), @@ -35,12 +35,33 @@ CClientBuilding::~CClientBuilding() } } +void CClientBuilding::SetPosition(const CVector& vecPosition) +{ + m_vPos = vecPosition; + Recreate(); +} + +void CClientBuilding::SetRotationRadians(const CVector& vecRadians) +{ + m_vRot = vecRadians; + Recreate(); +} + +void CClientBuilding::SetInterior(uint8_t ucInterior) +{ + m_interior = ucInterior; + Recreate(); +} + void CClientBuilding::Create() { if (m_pBuilding) return; - m_pBuilding = g_pGame->GetPools()->AddBuilding(this, m_usModelId, m_vPos, m_vRot, m_interior); + CVector4D vRot4D; + ConvertEulersToQuaternion(m_vRot, vRot4D); + + m_pBuilding = g_pGame->GetPools()->AddBuilding(this, m_usModelId, &m_vPos, &vRot4D, m_interior); } void CClientBuilding::Destroy() diff --git a/Client/mods/deathmatch/logic/CClientBuilding.h b/Client/mods/deathmatch/logic/CClientBuilding.h index 7ff5e768857..c2d4e922916 100644 --- a/Client/mods/deathmatch/logic/CClientBuilding.h +++ b/Client/mods/deathmatch/logic/CClientBuilding.h @@ -20,12 +20,17 @@ class CClientBuilding : public CClientEntity friend class CClientBuildingManager; public: - CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, CVector pos, CVector4D rot, uint8_t interior); + CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, CVector pos, CVector rot, uint8_t interior); ~CClientBuilding(); void Unlink(){}; - void GetPosition(CVector& vecPosition) const { vecPosition = m_vPos; }; - void SetPosition(const CVector& vecPosition) { m_vPos = vecPosition; }; + void GetPosition(CVector& vecPosition) const override { vecPosition = m_vPos; }; + void SetPosition(const CVector& vecPosition) override; + + void GetRotationRadians(CVector& vecOutRadians) const override { vecOutRadians = m_vPos; }; + void SetRotationRadians(const CVector& vecRadians) override; + + void SetInterior(uint8_t ucInterior) override; eClientEntityType GetType() const { return CCLIENTBUILDING; } @@ -33,12 +38,18 @@ class CClientBuilding : public CClientEntity void Create(); void Destroy(); + void Recreate() + { + Destroy(); + Create(); + }; + private: CClientBuildingManager* m_pBuildingManager; CBuilding* m_pBuilding; uint16_t m_usModelId; CVector m_vPos; - CVector4D m_vRot; + CVector m_vRot; uint8_t m_interior; }; diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp index 1015fc453ca..6501bc763ee 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp @@ -42,7 +42,8 @@ CClientBuilding* CLuaBuildingDefs::CreateBuilding(lua_State* const luaVM, uint16 // Grab the resource root entity CClientEntity* pRoot = pResource->GetResourceDynamicEntity(); - // Create the img handle + + // Create the building handle CClientBuilding* pBuilding = new CClientBuilding(m_pManager, INVALID_ELEMENT_ID, modelId, pos, rot, interior); pBuilding->SetParent(pRoot); diff --git a/Client/sdk/game/CPools.h b/Client/sdk/game/CPools.h index 44cf5bf8fd1..621efd9afbf 100644 --- a/Client/sdk/game/CPools.h +++ b/Client/sdk/game/CPools.h @@ -85,7 +85,7 @@ class CPools virtual unsigned long GetPedCount() = 0; // Buildings pool - virtual CBuilding* AddBuilding(class CClientBuilding*, uint16_t modelId, CVector vPos, CVector4D vRot, uint8_t interior) = 0; + virtual CBuilding* AddBuilding(class CClientBuilding*, uint16_t modelId, CVector *vPos, CVector4D *vRot, uint8_t interior) = 0; virtual void RemoveBuilding(CBuilding* pObject) = 0; // Others diff --git a/Shared/mods/deathmatch/logic/Utils.h b/Shared/mods/deathmatch/logic/Utils.h index 43f71aab541..81f8323c3d2 100644 --- a/Shared/mods/deathmatch/logic/Utils.h +++ b/Shared/mods/deathmatch/logic/Utils.h @@ -246,6 +246,21 @@ inline float GetSmallestWrapUnsigned(float fValue, float fHigh) void RotateVector(CVector& vecLine, const CVector& vecRotation); +inline void ConvertEulersToQuaternion(const CVector& vecFrom, CVector4D vecTo) +{ + double cy = cos(vecFrom.fZ * 0.5); + double sy = sin(vecFrom.fZ * 0.5); + double cr = cos(vecFrom.fX * 0.5); + double sr = sin(vecFrom.fX * 0.5); + double cp = cos(vecFrom.fY * 0.5); + double sp = sin(vecFrom.fY * 0.5); + + vecTo.fW = cy * cr * cp + sy * sr * sp; + vecTo.fX = cy * sr * cp - sy * cr * sp; + vecTo.fY = cy * cr * sp + sy * sr * cp; + vecTo.fY = sy * cr * cp - cy * sr * sp; +} + #ifdef MTA_CLIENT // Misc utility functions unsigned int StripUnwantedCharacters(char* szText, unsigned char cReplace = ' '); From 96bfdb8140ae0b3edd96bce65127827b235210f4 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Mon, 18 Dec 2023 23:44:23 +0300 Subject: [PATCH 05/21] Fix custom models and setElementModel --- .../mods/deathmatch/logic/CClientBuilding.cpp | 9 +++ .../mods/deathmatch/logic/CClientBuilding.h | 3 + Client/mods/deathmatch/logic/CClientModel.cpp | 32 +++++++-- .../logic/CStaticFunctionDefinitions.cpp | 67 +++++++++---------- .../logic/luadefs/CLuaBuildingDefs.cpp | 3 + 5 files changed, 76 insertions(+), 38 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientBuilding.cpp b/Client/mods/deathmatch/logic/CClientBuilding.cpp index daa27164039..f769fbe7945 100644 --- a/Client/mods/deathmatch/logic/CClientBuilding.cpp +++ b/Client/mods/deathmatch/logic/CClientBuilding.cpp @@ -51,6 +51,15 @@ void CClientBuilding::SetInterior(uint8_t ucInterior) { m_interior = ucInterior; Recreate(); +} + +void CClientBuilding::SetModel(uint16_t model) +{ + if (CClientObjectManager::IsValidModel(model)) + { + m_usModelId = model; + Recreate(); + } } void CClientBuilding::Create() diff --git a/Client/mods/deathmatch/logic/CClientBuilding.h b/Client/mods/deathmatch/logic/CClientBuilding.h index c2d4e922916..23f63d296e5 100644 --- a/Client/mods/deathmatch/logic/CClientBuilding.h +++ b/Client/mods/deathmatch/logic/CClientBuilding.h @@ -32,6 +32,9 @@ class CClientBuilding : public CClientEntity void SetInterior(uint8_t ucInterior) override; + uint16_t GetModel() { return m_usModelId; }; + void SetModel(uint16_t ulModel); + eClientEntityType GetType() const { return CCLIENTBUILDING; } private: diff --git a/Client/mods/deathmatch/logic/CClientModel.cpp b/Client/mods/deathmatch/logic/CClientModel.cpp index e42ee3a695a..a30bdabe0e5 100644 --- a/Client/mods/deathmatch/logic/CClientModel.cpp +++ b/Client/mods/deathmatch/logic/CClientModel.cpp @@ -122,6 +122,13 @@ void CClientModel::RestoreEntitiesUsingThisModel() void CClientModel::RestoreDFF(CModelInfo* pModelInfo) { + auto callElementChangeEvent = [](auto &element, unsigned short usParentID, auto modelId) { + CLuaArguments Arguments; + Arguments.PushNumber(modelId); + Arguments.PushNumber(usParentID); + element.CallEvent("onClientElementModelChange", Arguments, true); + }; + auto unloadModelsAndCallEvents = [&](auto iterBegin, auto iterEnd, unsigned short usParentID, auto setElementModelLambda) { for (auto iter = iterBegin; iter != iterEnd; iter++) { @@ -135,10 +142,21 @@ void CClientModel::RestoreDFF(CModelInfo* pModelInfo) setElementModelLambda(element); - CLuaArguments Arguments; - Arguments.PushNumber(m_iModelID); - Arguments.PushNumber(usParentID); - element.CallEvent("onClientElementModelChange", Arguments, true); + callElementChangeEvent(element, usParentID, m_iModelID); + } + }; + + auto unloadModelsAndCallEventsNonStreamed = [&](auto iterBegin, auto iterEnd, unsigned short usParentID, auto setElementModelLambda) + { + for (auto iter = iterBegin; iter != iterEnd; iter++) + { + auto& element = **iter; + + if (element.GetModel() != m_iModelID) + continue; + + setElementModelLambda(element); + callElementChangeEvent(element, usParentID, m_iModelID); } }; @@ -166,6 +184,12 @@ void CClientModel::RestoreDFF(CModelInfo* pModelInfo) unloadModelsAndCallEvents(pPickupManager->IterBegin(), pPickupManager->IterEnd(), usParentID, [=](auto& element) { element.SetModel(usParentID); }); + // Restore buildings + CClientBuildingManager* pBuildingsManager = g_pClientGame->GetManager()->GetBuildingManager(); + + unloadModelsAndCallEventsNonStreamed(pBuildingsManager->IterBegin(), pBuildingsManager->IterEnd(), usParentID, + [=](auto& element) { element.SetModel(usParentID); }); + // Restore COL g_pClientGame->GetManager()->GetColModelManager()->RestoreModel(m_iModelID); break; diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index ffc4466a339..3782356db3c 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -1461,6 +1461,26 @@ bool CStaticFunctionDefinitions::SetElementModel(CClientEntity& Entity, unsigned { RUN_CHILDREN(SetElementModel(**iter, usModel)) + auto callOnChangeEvent = [](auto &element, uint16_t usCurrentModel, uint16_t usModel) { + CLuaArguments Arguments; + Arguments.PushNumber(usCurrentModel); + Arguments.PushNumber(usModel); + bool bContinue = element.CallEvent("onClientElementModelChange", Arguments, true); + + // Check for another call to setElementModel + if (usModel != element.GetModel()) + return false; + + if (!bContinue) + { + // Change canceled + element.SetModel(usCurrentModel); + return false; + } + + return true; + }; + switch (Entity.GetType()) { case CCLIENTPED: @@ -1476,23 +1496,7 @@ bool CStaticFunctionDefinitions::SetElementModel(CClientEntity& Entity, unsigned if (!Ped.SetModel(usModel)) return false; - CLuaArguments Arguments; - Arguments.PushNumber(usCurrentModel); - Arguments.PushNumber(usModel); - bool bContinue = Ped.CallEvent("onClientElementModelChange", Arguments, true); - - // Check for another call to setElementModel - if (usModel != Ped.GetModel()) - return false; - - if (!bContinue) - { - // Change canceled - Ped.SetModel(usCurrentModel); - return false; - } - - break; + return callOnChangeEvent(Ped, usCurrentModel, usModel); } case CCLIENTVEHICLE: { @@ -1539,23 +1543,22 @@ bool CStaticFunctionDefinitions::SetElementModel(CClientEntity& Entity, unsigned Object.SetModel(usModel); - CLuaArguments Arguments; - Arguments.PushNumber(usCurrentModel); - Arguments.PushNumber(usModel); - bool bContinue = Object.CallEvent("onClientElementModelChange", Arguments, true); + return callOnChangeEvent(Object, usCurrentModel, usModel); + } + case CCLIENTBUILDING: + { + CClientBuilding& Object = static_cast(Entity); + const unsigned short usCurrentModel = Object.GetModel(); - // Check for another call to setElementModel - if (usModel != Object.GetModel()) + if (usCurrentModel == usModel) return false; - if (!bContinue) - { - // Change canceled - Object.SetModel(usCurrentModel); + if (!CClientObjectManager::IsValidModel(usModel)) return false; - } - break; + Object.SetModel(usModel); + + return callOnChangeEvent(Object, usCurrentModel, usModel); } case CCLIENTPROJECTILE: { @@ -1570,11 +1573,7 @@ bool CStaticFunctionDefinitions::SetElementModel(CClientEntity& Entity, unsigned Projectile.SetModel(usModel); - CLuaArguments Arguments; - Arguments.PushNumber(usCurrentModel); - Arguments.PushNumber(usModel); - Projectile.CallEvent("onClientElementModelChange", Arguments, true); - break; + return callOnChangeEvent(Projectile, usCurrentModel, usModel); } default: return false; diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp index 6501bc763ee..c4422770cb1 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp @@ -40,6 +40,9 @@ CClientBuilding* CLuaBuildingDefs::CreateBuilding(lua_State* const luaVM, uint16 if (!pResource) return false; + if (!CClientObjectManager::IsValidModel(modelId)) + throw std::invalid_argument("Invalid model id"); + // Grab the resource root entity CClientEntity* pRoot = pResource->GetResourceDynamicEntity(); From 2d0a51f293578a163dc48e0aa1717c6a3d1b38b7 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Mon, 18 Dec 2023 23:54:01 +0300 Subject: [PATCH 06/21] Fix build --- Client/mods/deathmatch/logic/CClientBuilding.cpp | 2 +- Client/mods/deathmatch/logic/CClientBuilding.h | 6 +++--- Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp | 2 +- Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientBuilding.cpp b/Client/mods/deathmatch/logic/CClientBuilding.cpp index f769fbe7945..567eaadd97c 100644 --- a/Client/mods/deathmatch/logic/CClientBuilding.cpp +++ b/Client/mods/deathmatch/logic/CClientBuilding.cpp @@ -10,7 +10,7 @@ #include "StdInc.h" -CClientBuilding::CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, CVector pos, CVector rot, uint8_t interior) +CClientBuilding::CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, CVector &pos, CVector &rot, uint8_t interior) : ClassInit(this), CClientEntity(ID), m_pBuildingManager(pManager->GetBuildingManager()), diff --git a/Client/mods/deathmatch/logic/CClientBuilding.h b/Client/mods/deathmatch/logic/CClientBuilding.h index 23f63d296e5..3e7eb577b9d 100644 --- a/Client/mods/deathmatch/logic/CClientBuilding.h +++ b/Client/mods/deathmatch/logic/CClientBuilding.h @@ -20,7 +20,7 @@ class CClientBuilding : public CClientEntity friend class CClientBuildingManager; public: - CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, CVector pos, CVector rot, uint8_t interior); + CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, CVector &pos, CVector &rot, uint8_t interior); ~CClientBuilding(); void Unlink(){}; @@ -32,10 +32,10 @@ class CClientBuilding : public CClientEntity void SetInterior(uint8_t ucInterior) override; - uint16_t GetModel() { return m_usModelId; }; + uint16_t GetModel() const noexcept { return m_usModelId; }; void SetModel(uint16_t ulModel); - eClientEntityType GetType() const { return CCLIENTBUILDING; } + eClientEntityType GetType() const noexcept { return CCLIENTBUILDING; } private: void Create(); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp index c4422770cb1..ceb1ad6c13e 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp @@ -31,7 +31,7 @@ void CLuaBuildingDefs::AddClass(lua_State* luaVM) lua_registerclass(luaVM, "Building"); } -CClientBuilding* CLuaBuildingDefs::CreateBuilding(lua_State* const luaVM, uint16_t modelId, CVector pos, CVector4D rot, uint8_t interior) +CClientBuilding* CLuaBuildingDefs::CreateBuilding(lua_State* const luaVM, uint16_t modelId, CVector pos, CVector rot, uint8_t interior) { CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaVM); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.h index f158f225879..6b9fc5cbd47 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.h @@ -19,5 +19,5 @@ class CLuaBuildingDefs : public CLuaDefs static void AddClass(lua_State* luaVM); // Buiding create funcs - static CClientBuilding* CreateBuilding(lua_State* const luaVM, uint16_t modelId, CVector pos, CVector4D rot, uint8_t interior = 0); + static CClientBuilding* CreateBuilding(lua_State* const luaVM, uint16_t modelId, CVector pos, CVector rot, uint8_t interior = 0); }; From a61b54d2ee0d98d63c2f53eba1fc52a8ae854bae Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Tue, 19 Dec 2023 02:57:43 +0300 Subject: [PATCH 07/21] Small fixes --- Client/game_sa/CPoolsSA.cpp | 18 +++++++----------- Shared/mods/deathmatch/logic/Utils.h | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/Client/game_sa/CPoolsSA.cpp b/Client/game_sa/CPoolsSA.cpp index 2692b4942e5..f70b1c93749 100644 --- a/Client/game_sa/CPoolsSA.cpp +++ b/Client/game_sa/CPoolsSA.cpp @@ -342,22 +342,18 @@ inline bool CPoolsSA::AddBuildingToPool(CClientBuilding* pClientBuilding, CBuild CBuildingSAInterface* pInterface = pBuilding->GetBuildingInterface(); if (!pInterface) + return false; + + DWORD dwElementIndexInPool = GetBuildingPoolIndex((std::uint8_t*)pInterface); + if (dwElementIndexInPool >= MAX_BUILDINGS) { return false; } - else - { - DWORD dwElementIndexInPool = GetBuildingPoolIndex((std::uint8_t*)pInterface); - if (dwElementIndexInPool >= MAX_BUILDINGS) - { - return false; - } - m_buildingPool.arrayOfClientEntities[dwElementIndexInPool] = {pBuilding, (CClientEntity*)pClientBuilding}; + m_buildingPool.arrayOfClientEntities[dwElementIndexInPool] = {pBuilding, (CClientEntity*)pClientBuilding}; - // Increase the count of objects - ++m_buildingPool.ulCount; - } + // Increase the count of objects + ++m_buildingPool.ulCount; return true; } diff --git a/Shared/mods/deathmatch/logic/Utils.h b/Shared/mods/deathmatch/logic/Utils.h index 81f8323c3d2..e8d27e3943c 100644 --- a/Shared/mods/deathmatch/logic/Utils.h +++ b/Shared/mods/deathmatch/logic/Utils.h @@ -258,7 +258,7 @@ inline void ConvertEulersToQuaternion(const CVector& vecFrom, CVector4D vecTo) vecTo.fW = cy * cr * cp + sy * sr * sp; vecTo.fX = cy * sr * cp - sy * cr * sp; vecTo.fY = cy * cr * sp + sy * sr * cp; - vecTo.fY = sy * cr * cp - cy * sr * sp; + vecTo.fZ = sy * cr * cp - cy * sr * sp; } #ifdef MTA_CLIENT From f6f39cdb1b257a6a195f85619b12a18dd7952f7f Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Tue, 19 Dec 2023 17:40:32 +0300 Subject: [PATCH 08/21] Fix some edge cases --- Client/game_sa/CPoolsSA.cpp | 8 ++++++++ Client/game_sa/CPoolsSA.h | 1 + Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp | 6 ++++++ Client/sdk/game/CPools.h | 1 + 4 files changed, 16 insertions(+) diff --git a/Client/game_sa/CPoolsSA.cpp b/Client/game_sa/CPoolsSA.cpp index f70b1c93749..a8075fbe326 100644 --- a/Client/game_sa/CPoolsSA.cpp +++ b/Client/game_sa/CPoolsSA.cpp @@ -360,6 +360,9 @@ inline bool CPoolsSA::AddBuildingToPool(CClientBuilding* pClientBuilding, CBuild 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; @@ -423,6 +426,11 @@ void CPoolsSA::RemoveBuilding(CBuilding* pBuilding) --m_buildingPool.ulCount; } +bool CPoolsSA::HasFreeBuildingSlot() +{ + return (*m_ppBuildingPoolInterface)->GetFreeSlot() != -1; +} + ////////////////////////////////////////////////////////////////////////////////////////// // PEDS POOL // ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Client/game_sa/CPoolsSA.h b/Client/game_sa/CPoolsSA.h index 70cf4f20e2e..106846b162f 100644 --- a/Client/game_sa/CPoolsSA.h +++ b/Client/game_sa/CPoolsSA.h @@ -178,6 +178,7 @@ class CPoolsSA : public CPools 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); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp index ceb1ad6c13e..f2e174cbac7 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp @@ -43,6 +43,12 @@ CClientBuilding* CLuaBuildingDefs::CreateBuilding(lua_State* const luaVM, uint16 if (!CClientObjectManager::IsValidModel(modelId)) throw std::invalid_argument("Invalid model id"); + if (!g_pGame->GetPools()->HasFreeBuildingSlot()) + throw std::invalid_argument("No free slot in buildings pool"); + + if (pos.fX < -3000.0f || pos.fX > 3000.0f || pos.fY < -3000.0f || pos.fY > 3000.0f) + throw std::invalid_argument("Position is outside of game world"); + // Grab the resource root entity CClientEntity* pRoot = pResource->GetResourceDynamicEntity(); diff --git a/Client/sdk/game/CPools.h b/Client/sdk/game/CPools.h index 621efd9afbf..f758084639d 100644 --- a/Client/sdk/game/CPools.h +++ b/Client/sdk/game/CPools.h @@ -87,6 +87,7 @@ class CPools // Buildings pool virtual CBuilding* AddBuilding(class CClientBuilding*, uint16_t modelId, CVector *vPos, CVector4D *vRot, uint8_t interior) = 0; virtual void RemoveBuilding(CBuilding* pObject) = 0; + virtual bool HasFreeBuildingSlot() = 0; // Others virtual CVehicle* AddTrain(class CClientVehicle* pClientVehicle, CVector* vecPosition, DWORD dwModels[], int iSize, bool iDirection, From 84fa9a03d141f946c20c8d0350976510e19d18ca Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Mon, 25 Dec 2023 15:12:07 +0300 Subject: [PATCH 09/21] Fix from review --- Client/game_sa/CFileLoaderSA.cpp | 8 +++---- Client/game_sa/CFileLoaderSA.h | 6 ++--- Client/game_sa/CPoolsSA.cpp | 4 ++-- .../mods/deathmatch/logic/CClientBuilding.cpp | 17 ++++++++------ .../mods/deathmatch/logic/CClientBuilding.h | 2 +- .../logic/CClientBuildingManager.cpp | 22 +++++-------------- .../deathmatch/logic/CClientBuildingManager.h | 6 +---- Client/mods/deathmatch/logic/CClientManager.h | 2 +- Client/mods/deathmatch/logic/CClientModel.cpp | 4 ++-- .../logic/luadefs/CLuaBuildingDefs.cpp | 5 ++--- Shared/mods/deathmatch/logic/Utils.h | 2 +- 11 files changed, 32 insertions(+), 46 deletions(-) diff --git a/Client/game_sa/CFileLoaderSA.cpp b/Client/game_sa/CFileLoaderSA.cpp index 01372c29bbc..c235479a222 100644 --- a/Client/game_sa/CFileLoaderSA.cpp +++ b/Client/game_sa/CFileLoaderSA.cpp @@ -28,9 +28,9 @@ void CFileLoaderSA::StaticSetHooks() HookInstall(0x538690, (DWORD)CFileLoader_LoadObjectInstance, 5); } -CBuildingSAInterface* CFileLoaderSA::LoadFileObjectInstance(SFileObjectInstance* obj) +CEntitySAInterface* CFileLoaderSA::LoadFileObjectInstance(SFileObjectInstance* obj) { - return ((CBuildingSAInterface * (__cdecl*)(SFileObjectInstance*))0x538090)(obj); + return ((CEntitySAInterface * (__cdecl*)(SFileObjectInstance*))0x538090)(obj); } class CAtomicModelInfo @@ -206,7 +206,7 @@ RpAtomic* CFileLoader_SetRelatedModelInfoCB(RpAtomic* atomic, SRelatedModelInfo* return atomic; } -CBuildingSAInterface* CFileLoader_LoadObjectInstance(const char* szLine) +CEntitySAInterface* CFileLoader_LoadObjectInstance(const char* szLine) { char szModelName[24]; SFileObjectInstance inst; @@ -222,5 +222,5 @@ CBuildingSAInterface* CFileLoader_LoadObjectInstance(const char* szLine) if (fLenSq > 0.0f && std::fabs(fLenSq - 1.0f) > std::numeric_limits::epsilon()) inst.rotation /= std::sqrt(fLenSq); - return ((CBuildingSAInterface * (__cdecl*)(SFileObjectInstance*))0x538090)(&inst); + return ((CEntitySAInterface * (__cdecl*)(SFileObjectInstance*))0x538090)(&inst); } diff --git a/Client/game_sa/CFileLoaderSA.h b/Client/game_sa/CFileLoaderSA.h index ad5103c75c1..4fe983cc513 100644 --- a/Client/game_sa/CFileLoaderSA.h +++ b/Client/game_sa/CFileLoaderSA.h @@ -3,7 +3,7 @@ #include "CVector.h" #include "CVector4D.h" -class CBuildingSAInterface; +class CEntitySAInterface; struct RpAtomic; struct RpClump; struct RwStream; @@ -29,11 +29,11 @@ class CFileLoaderSA CFileLoaderSA(); ~CFileLoaderSA(); - CBuildingSAInterface* LoadFileObjectInstance(SFileObjectInstance*); + CEntitySAInterface* LoadFileObjectInstance(SFileObjectInstance*); static void StaticSetHooks(); }; bool CFileLoader_LoadAtomicFile(RwStream* stream, unsigned int modelId); RpAtomic* CFileLoader_SetRelatedModelInfoCB(RpAtomic* atomic, SRelatedModelInfo* pRelatedModelInfo); -CBuildingSAInterface* CFileLoader_LoadObjectInstance(const char* szLine); +CEntitySAInterface* CFileLoader_LoadObjectInstance(const char* szLine); diff --git a/Client/game_sa/CPoolsSA.cpp b/Client/game_sa/CPoolsSA.cpp index a8075fbe326..5efe19f7c1f 100644 --- a/Client/game_sa/CPoolsSA.cpp +++ b/Client/game_sa/CPoolsSA.cpp @@ -375,7 +375,7 @@ CBuilding* CPoolsSA::AddBuilding(CClientBuilding* pClientBuilding, uint16_t mode instance.rotation.fW = -instance.rotation.fW; CFileLoaderSA loader{}; - auto pBuilding = loader.LoadFileObjectInstance(&instance); + auto pBuilding = static_cast(loader.LoadFileObjectInstance(&instance)); // Disable lod and ipl pBuilding->m_pLod = nullptr; @@ -807,7 +807,7 @@ DWORD CPoolsSA::GetObjectPoolIndex(std::uint8_t* pInterface) DWORD CPoolsSA::GetBuildingPoolIndex(std::uint8_t* pInterface) { - DWORD dwAlignedSize = 412; + 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)) diff --git a/Client/mods/deathmatch/logic/CClientBuilding.cpp b/Client/mods/deathmatch/logic/CClientBuilding.cpp index 567eaadd97c..ef282ed9e29 100644 --- a/Client/mods/deathmatch/logic/CClientBuilding.cpp +++ b/Client/mods/deathmatch/logic/CClientBuilding.cpp @@ -10,16 +10,16 @@ #include "StdInc.h" -CClientBuilding::CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, CVector &pos, CVector &rot, uint8_t interior) +CClientBuilding::CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, const CVector &pos, const CVector &rot, uint8_t interior) : ClassInit(this), CClientEntity(ID), m_pBuildingManager(pManager->GetBuildingManager()), m_usModelId(usModelId), m_vPos(pos), m_vRot(rot), - m_interior(interior) + m_interior(interior), + m_pBuilding(nullptr) { - m_pBuilding = nullptr; m_pManager = pManager; SetTypeName("building"); m_pBuildingManager->AddToList(this); @@ -29,26 +29,29 @@ CClientBuilding::CClientBuilding(class CClientManager* pManager, ElementID ID, u CClientBuilding::~CClientBuilding() { m_pBuildingManager->RemoveFromList(this); - if (m_pBuilding) - { - Destroy(); - } + Destroy(); } void CClientBuilding::SetPosition(const CVector& vecPosition) { + if (m_vPos == vecPosition) + return; m_vPos = vecPosition; Recreate(); } void CClientBuilding::SetRotationRadians(const CVector& vecRadians) { + if (m_vRot == vecRadians) + return; m_vRot = vecRadians; Recreate(); } void CClientBuilding::SetInterior(uint8_t ucInterior) { + if (m_interior == ucInterior) + return; m_interior = ucInterior; Recreate(); } diff --git a/Client/mods/deathmatch/logic/CClientBuilding.h b/Client/mods/deathmatch/logic/CClientBuilding.h index 3e7eb577b9d..3e91effa941 100644 --- a/Client/mods/deathmatch/logic/CClientBuilding.h +++ b/Client/mods/deathmatch/logic/CClientBuilding.h @@ -20,7 +20,7 @@ class CClientBuilding : public CClientEntity friend class CClientBuildingManager; public: - CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, CVector &pos, CVector &rot, uint8_t interior); + CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, const CVector &pos, const CVector &rot, uint8_t interior); ~CClientBuilding(); void Unlink(){}; diff --git a/Client/mods/deathmatch/logic/CClientBuildingManager.cpp b/Client/mods/deathmatch/logic/CClientBuildingManager.cpp index fb9a512ff29..59e421b6c68 100644 --- a/Client/mods/deathmatch/logic/CClientBuildingManager.cpp +++ b/Client/mods/deathmatch/logic/CClientBuildingManager.cpp @@ -28,32 +28,20 @@ void CClientBuildingManager::RemoveAll() m_bRemoveFromList = false; // Run through our list deleting the buildings - auto iter = m_List.begin(); - for (; iter != m_List.end(); iter++) + for (CClientBuilding* building : m_List) { - delete *iter; + delete building; } + m_List.clear(); + // Allow list removal again m_bRemoveFromList = true; } bool CClientBuildingManager::Exists(CClientBuilding* pBuilding) { - // Matches given DFF? - auto iter = m_List.begin(); - for (; iter != m_List.end(); iter++) - { - // Match? - if (pBuilding == *iter) - { - // It exists - return true; - } - } - - // It doesn't - return false; + return std::find(m_List.begin(), m_List.end(), pBuilding) != m_List.end(); } void CClientBuildingManager::RemoveFromList(CClientBuilding* pBuilding) diff --git a/Client/mods/deathmatch/logic/CClientBuildingManager.h b/Client/mods/deathmatch/logic/CClientBuildingManager.h index dd595d3cb37..0e1c381ad7a 100644 --- a/Client/mods/deathmatch/logic/CClientBuildingManager.h +++ b/Client/mods/deathmatch/logic/CClientBuildingManager.h @@ -26,16 +26,12 @@ class CClientBuildingManager void RemoveAll(); bool Exists(CClientBuilding* pBuilding); - std::list::const_iterator IterBegin() { return m_List.begin(); } - std::list::const_iterator IterEnd() { return m_List.end(); } + const std::list& GetBuildings() { return m_List; }; private: void AddToList(CClientBuilding* pBuilding) { m_List.push_back(pBuilding); } void RemoveFromList(CClientBuilding* pBuilding); - class CClientObjectManager* m_pObjectManager; - class CClientVehicleManager* m_pVehicleManager; - std::list m_List; bool m_bRemoveFromList; }; diff --git a/Client/mods/deathmatch/logic/CClientManager.h b/Client/mods/deathmatch/logic/CClientManager.h index 92f8481db85..0e9f0c77026 100644 --- a/Client/mods/deathmatch/logic/CClientManager.h +++ b/Client/mods/deathmatch/logic/CClientManager.h @@ -97,7 +97,7 @@ class CClientManager CClientEffectManager* GetEffectManager() { return m_pEffectManager; } CClientPointLightsManager* GetPointLightsManager() { return m_pPointLightsManager; } CClientIMGManager* GetIMGManager() { return m_pImgManager; } - CClientBuildingManager* GetBuildingManager() { return m_pBuildingManager; } + CClientBuildingManager* GetBuildingManager() const noexcept { return m_pBuildingManager; } bool IsGameLoaded() { return g_pGame->GetSystemState() == 9 && !m_bGameUnloadedFlag && g_pCore->GetNetwork()->GetServerBitStreamVersion(); } bool IsBeingDeleted() { return m_bBeingDeleted; } diff --git a/Client/mods/deathmatch/logic/CClientModel.cpp b/Client/mods/deathmatch/logic/CClientModel.cpp index a30bdabe0e5..a80d637b8c5 100644 --- a/Client/mods/deathmatch/logic/CClientModel.cpp +++ b/Client/mods/deathmatch/logic/CClientModel.cpp @@ -186,8 +186,8 @@ void CClientModel::RestoreDFF(CModelInfo* pModelInfo) // Restore buildings CClientBuildingManager* pBuildingsManager = g_pClientGame->GetManager()->GetBuildingManager(); - - unloadModelsAndCallEventsNonStreamed(pBuildingsManager->IterBegin(), pBuildingsManager->IterEnd(), usParentID, + auto& buildingsList = pBuildingsManager->GetBuildings(); + unloadModelsAndCallEventsNonStreamed(buildingsList.begin(), buildingsList.end(), usParentID, [=](auto& element) { element.SetModel(usParentID); }); // Restore COL diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp index f2e174cbac7..fced4f0519e 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp @@ -49,12 +49,11 @@ CClientBuilding* CLuaBuildingDefs::CreateBuilding(lua_State* const luaVM, uint16 if (pos.fX < -3000.0f || pos.fX > 3000.0f || pos.fY < -3000.0f || pos.fY > 3000.0f) throw std::invalid_argument("Position is outside of game world"); - // Grab the resource root entity - CClientEntity* pRoot = pResource->GetResourceDynamicEntity(); + ConvertDegreesToRadians(rot); - // Create the building handle CClientBuilding* pBuilding = new CClientBuilding(m_pManager, INVALID_ELEMENT_ID, modelId, pos, rot, interior); + CClientEntity* pRoot = pResource->GetResourceDynamicEntity(); pBuilding->SetParent(pRoot); return pBuilding; diff --git a/Shared/mods/deathmatch/logic/Utils.h b/Shared/mods/deathmatch/logic/Utils.h index e8d27e3943c..96a4429d1f3 100644 --- a/Shared/mods/deathmatch/logic/Utils.h +++ b/Shared/mods/deathmatch/logic/Utils.h @@ -246,7 +246,7 @@ inline float GetSmallestWrapUnsigned(float fValue, float fHigh) void RotateVector(CVector& vecLine, const CVector& vecRotation); -inline void ConvertEulersToQuaternion(const CVector& vecFrom, CVector4D vecTo) +inline void ConvertEulersToQuaternion(const CVector& vecFrom, CVector4D &vecTo) { double cy = cos(vecFrom.fZ * 0.5); double sy = sin(vecFrom.fZ * 0.5); From 1d89b6d81b32b3f927866a4d6641f43f1b20dd3e Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Mon, 25 Dec 2023 15:29:45 +0300 Subject: [PATCH 10/21] Fix optional value --- Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp | 4 ++-- Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp index fced4f0519e..1f2b7b471d2 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp @@ -31,7 +31,7 @@ void CLuaBuildingDefs::AddClass(lua_State* luaVM) lua_registerclass(luaVM, "Building"); } -CClientBuilding* CLuaBuildingDefs::CreateBuilding(lua_State* const luaVM, uint16_t modelId, CVector pos, CVector rot, uint8_t interior) +CClientBuilding* CLuaBuildingDefs::CreateBuilding(lua_State* const luaVM, uint16_t modelId, CVector pos, CVector rot, std::optional interior) { CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaVM); @@ -51,7 +51,7 @@ CClientBuilding* CLuaBuildingDefs::CreateBuilding(lua_State* const luaVM, uint16 ConvertDegreesToRadians(rot); - CClientBuilding* pBuilding = new CClientBuilding(m_pManager, INVALID_ELEMENT_ID, modelId, pos, rot, interior); + CClientBuilding* pBuilding = new CClientBuilding(m_pManager, INVALID_ELEMENT_ID, modelId, pos, rot, interior.value_or(0)); CClientEntity* pRoot = pResource->GetResourceDynamicEntity(); pBuilding->SetParent(pRoot); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.h index 6b9fc5cbd47..5d4d69c65b5 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.h @@ -19,5 +19,5 @@ class CLuaBuildingDefs : public CLuaDefs static void AddClass(lua_State* luaVM); // Buiding create funcs - static CClientBuilding* CreateBuilding(lua_State* const luaVM, uint16_t modelId, CVector pos, CVector rot, uint8_t interior = 0); + static CClientBuilding* CreateBuilding(lua_State* const luaVM, uint16_t modelId, CVector pos, CVector rot, std::optional interior); }; From a27cbc7a113fb5a951bd69724330b561516c7e35 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Mon, 25 Dec 2023 16:28:09 +0300 Subject: [PATCH 11/21] Fix dynamic model spawn --- Client/game_sa/CModelInfoSA.h | 2 ++ .../logic/CClientBuildingManager.cpp | 25 +++++++++++++++++++ .../deathmatch/logic/CClientBuildingManager.h | 2 ++ .../logic/luadefs/CLuaBuildingDefs.cpp | 4 +-- Client/sdk/game/CModelInfo.h | 1 + 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Client/game_sa/CModelInfoSA.h b/Client/game_sa/CModelInfoSA.h index b46818d72bb..329d2e3e50f 100644 --- a/Client/game_sa/CModelInfoSA.h +++ b/Client/game_sa/CModelInfoSA.h @@ -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); diff --git a/Client/mods/deathmatch/logic/CClientBuildingManager.cpp b/Client/mods/deathmatch/logic/CClientBuildingManager.cpp index 59e421b6c68..de8cf656df3 100644 --- a/Client/mods/deathmatch/logic/CClientBuildingManager.cpp +++ b/Client/mods/deathmatch/logic/CClientBuildingManager.cpp @@ -52,3 +52,28 @@ void CClientBuildingManager::RemoveFromList(CClientBuilding* pBuilding) m_List.remove(pBuilding); } } + +bool CClientBuildingManager::IsValidModel(uint16_t modelId) +{ + if (modelId >= static_cast(g_pGame->GetBaseIDforTXD())) + return false; + + // Clothes and hands cause artefacts + if (384 <= modelId && modelId <= 397) + return false; + + CModelInfo* pModelInfo = g_pGame->GetModelInfo(modelId); + if (!pModelInfo || !pModelInfo->GetInterface()) + return false; + + if (!pModelInfo->IsAllocatedInArchive()) + return false; + + if (pModelInfo->IsDynamic()) + { + return false; + } + + eModelInfoType eType = pModelInfo->GetModelType(); + return (eType == eModelInfoType::CLUMP || eType == eModelInfoType::ATOMIC || eType == eModelInfoType::WEAPON || eType == eModelInfoType::TIME); +} diff --git a/Client/mods/deathmatch/logic/CClientBuildingManager.h b/Client/mods/deathmatch/logic/CClientBuildingManager.h index 0e1c381ad7a..5c0f0426303 100644 --- a/Client/mods/deathmatch/logic/CClientBuildingManager.h +++ b/Client/mods/deathmatch/logic/CClientBuildingManager.h @@ -28,6 +28,8 @@ class CClientBuildingManager const std::list& GetBuildings() { return m_List; }; + static bool IsValidModel(uint16_t modelId); + private: void AddToList(CClientBuilding* pBuilding) { m_List.push_back(pBuilding); } void RemoveFromList(CClientBuilding* pBuilding); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp index 1f2b7b471d2..4f140a0d2b6 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp @@ -40,8 +40,8 @@ CClientBuilding* CLuaBuildingDefs::CreateBuilding(lua_State* const luaVM, uint16 if (!pResource) return false; - if (!CClientObjectManager::IsValidModel(modelId)) - throw std::invalid_argument("Invalid model id"); + if (!CClientBuildingManager::IsValidModel(modelId)) + throw std::invalid_argument("Invalid building model id"); if (!g_pGame->GetPools()->HasFreeBuildingSlot()) throw std::invalid_argument("No free slot in buildings pool"); diff --git a/Client/sdk/game/CModelInfo.h b/Client/sdk/game/CModelInfo.h index ede6ca59cc4..440f079be67 100644 --- a/Client/sdk/game/CModelInfo.h +++ b/Client/sdk/game/CModelInfo.h @@ -246,4 +246,5 @@ class CModelInfo virtual bool IsTowableBy(CModelInfo* towingModel) = 0; virtual unsigned int GetParentID() = 0; + virtual bool IsDynamic() = 0; }; From d8028f34115162911645f8a461f6afaf4f5c0213 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Mon, 25 Dec 2023 17:26:45 +0300 Subject: [PATCH 12/21] Fix function name --- Client/game_sa/CFileLoaderSA.cpp | 2 +- Client/game_sa/CFileLoaderSA.h | 2 +- Client/game_sa/CPoolsSA.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Client/game_sa/CFileLoaderSA.cpp b/Client/game_sa/CFileLoaderSA.cpp index c235479a222..42a19bb02df 100644 --- a/Client/game_sa/CFileLoaderSA.cpp +++ b/Client/game_sa/CFileLoaderSA.cpp @@ -28,7 +28,7 @@ void CFileLoaderSA::StaticSetHooks() HookInstall(0x538690, (DWORD)CFileLoader_LoadObjectInstance, 5); } -CEntitySAInterface* CFileLoaderSA::LoadFileObjectInstance(SFileObjectInstance* obj) +CEntitySAInterface* CFileLoaderSA::LoadObjectInstance(SFileObjectInstance* obj) { return ((CEntitySAInterface * (__cdecl*)(SFileObjectInstance*))0x538090)(obj); } diff --git a/Client/game_sa/CFileLoaderSA.h b/Client/game_sa/CFileLoaderSA.h index 4fe983cc513..9860eeecff8 100644 --- a/Client/game_sa/CFileLoaderSA.h +++ b/Client/game_sa/CFileLoaderSA.h @@ -29,7 +29,7 @@ class CFileLoaderSA CFileLoaderSA(); ~CFileLoaderSA(); - CEntitySAInterface* LoadFileObjectInstance(SFileObjectInstance*); + CEntitySAInterface* LoadObjectInstance(SFileObjectInstance*); static void StaticSetHooks(); }; diff --git a/Client/game_sa/CPoolsSA.cpp b/Client/game_sa/CPoolsSA.cpp index 5efe19f7c1f..3bc706eb3af 100644 --- a/Client/game_sa/CPoolsSA.cpp +++ b/Client/game_sa/CPoolsSA.cpp @@ -375,7 +375,7 @@ CBuilding* CPoolsSA::AddBuilding(CClientBuilding* pClientBuilding, uint16_t mode instance.rotation.fW = -instance.rotation.fW; CFileLoaderSA loader{}; - auto pBuilding = static_cast(loader.LoadFileObjectInstance(&instance)); + auto pBuilding = static_cast(loader.LoadObjectInstance(&instance)); // Disable lod and ipl pBuilding->m_pLod = nullptr; From a2694a69c705264cdec92bbf3a96f3acb0baca31 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Wed, 27 Dec 2023 18:36:52 +0300 Subject: [PATCH 13/21] review fixes --- Client/game_sa/CFileLoaderSA.cpp | 3 ++- Client/game_sa/CFileLoaderSA.h | 2 +- Client/game_sa/CPoolsSA.cpp | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Client/game_sa/CFileLoaderSA.cpp b/Client/game_sa/CFileLoaderSA.cpp index 42a19bb02df..67cb476cf51 100644 --- a/Client/game_sa/CFileLoaderSA.cpp +++ b/Client/game_sa/CFileLoaderSA.cpp @@ -30,7 +30,8 @@ void CFileLoaderSA::StaticSetHooks() CEntitySAInterface* CFileLoaderSA::LoadObjectInstance(SFileObjectInstance* obj) { - return ((CEntitySAInterface * (__cdecl*)(SFileObjectInstance*))0x538090)(obj); + // Second argument is model name. It's unused in the function + return ((CEntitySAInterface * (__cdecl*)(SFileObjectInstance*, const char*))0x538090)(obj, nullptr); } class CAtomicModelInfo diff --git a/Client/game_sa/CFileLoaderSA.h b/Client/game_sa/CFileLoaderSA.h index 9860eeecff8..260bc93cb24 100644 --- a/Client/game_sa/CFileLoaderSA.h +++ b/Client/game_sa/CFileLoaderSA.h @@ -29,7 +29,7 @@ class CFileLoaderSA CFileLoaderSA(); ~CFileLoaderSA(); - CEntitySAInterface* LoadObjectInstance(SFileObjectInstance*); + static CEntitySAInterface* LoadObjectInstance(SFileObjectInstance*); static void StaticSetHooks(); }; diff --git a/Client/game_sa/CPoolsSA.cpp b/Client/game_sa/CPoolsSA.cpp index 3bc706eb3af..1853ee72977 100644 --- a/Client/game_sa/CPoolsSA.cpp +++ b/Client/game_sa/CPoolsSA.cpp @@ -374,8 +374,7 @@ CBuilding* CPoolsSA::AddBuilding(CClientBuilding* pClientBuilding, uint16_t mode // Fix strange SA rotation instance.rotation.fW = -instance.rotation.fW; - CFileLoaderSA loader{}; - auto pBuilding = static_cast(loader.LoadObjectInstance(&instance)); + auto pBuilding = static_cast(CFileLoaderSA::LoadObjectInstance(&instance)); // Disable lod and ipl pBuilding->m_pLod = nullptr; From 17fcf1346a6b57ce63b20cf32264996121bd3a5f Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Thu, 28 Dec 2023 02:00:12 +0300 Subject: [PATCH 14/21] Fix getElementModel function for buildings --- Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 3782356db3c..32beefb326c 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -762,6 +762,12 @@ bool CStaticFunctionDefinitions::GetElementModel(CClientEntity& Entity, unsigned usModel = pPickup.GetModel(); break; } + case CCLIENTBUILDING: + { + CClientBuilding& pBuilding = static_cast(Entity); + usModel = pBuilding.GetModel(); + break; + } case CCLIENTPROJECTILE: { CClientProjectile& pProjectile = static_cast(Entity); From 5f9983e6f6750709ce37cb60ed562d091030d639 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Thu, 28 Dec 2023 19:10:08 +0300 Subject: [PATCH 15/21] Fix buildings leak --- Client/game_sa/CPoolsSA.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Client/game_sa/CPoolsSA.cpp b/Client/game_sa/CPoolsSA.cpp index 1853ee72977..6680e821949 100644 --- a/Client/game_sa/CPoolsSA.cpp +++ b/Client/game_sa/CPoolsSA.cpp @@ -421,6 +421,9 @@ void CPoolsSA::RemoveBuilding(CBuilding* pBuilding) // 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; } From 27cc7b12f8ecef5d360e058820a1d607e9e66e54 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Thu, 28 Dec 2023 21:12:39 +0300 Subject: [PATCH 16/21] Add get rotation and set rotation functions for buildings --- .../logic/CStaticFunctionDefinitions.cpp | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 32beefb326c..be0e47a0764 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -426,6 +426,16 @@ bool CStaticFunctionDefinitions::GetElementRotation(CClientEntity& Entity, CVect } break; } + case CCLIENTBUILDING: + { + CClientBuilding& pBuilding = static_cast(Entity); + pBuilding.GetRotationDegrees(vecRotation); + if (desiredRotOrder != EULER_DEFAULT && desiredRotOrder != EULER_ZXY) + { + vecRotation = ConvertEulerRotationOrder(vecRotation, EULER_ZXY, desiredRotOrder); + } + break; + } case CCLIENTPROJECTILE: { CClientProjectile& Projectile = static_cast(Entity); @@ -1113,6 +1123,19 @@ bool CStaticFunctionDefinitions::SetElementRotation(CClientEntity& Entity, const break; } + case CCLIENTBUILDING: + { + CClientBuilding& pBuilding = static_cast(Entity); + if (argumentRotOrder == EULER_DEFAULT || argumentRotOrder == EULER_ZXY) + { + pBuilding.SetRotationDegrees(vecRotation); + } + else + { + pBuilding.SetRotationDegrees(ConvertEulerRotationOrder(vecRotation, argumentRotOrder, EULER_ZXY)); + } + break; + } case CCLIENTPROJECTILE: { // Didn't implement anything for projectiles since I couldn't really test (only non crashing element was satchel and its rotation is ugly) From a1617b9addc2c0d219a8cbed0ae510b85900f0c2 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Wed, 3 Jan 2024 18:13:17 +0300 Subject: [PATCH 17/21] fix setElementModel --- Client/mods/deathmatch/logic/CClientBuilding.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/mods/deathmatch/logic/CClientBuilding.cpp b/Client/mods/deathmatch/logic/CClientBuilding.cpp index ef282ed9e29..ebec1a18355 100644 --- a/Client/mods/deathmatch/logic/CClientBuilding.cpp +++ b/Client/mods/deathmatch/logic/CClientBuilding.cpp @@ -58,7 +58,7 @@ void CClientBuilding::SetInterior(uint8_t ucInterior) void CClientBuilding::SetModel(uint16_t model) { - if (CClientObjectManager::IsValidModel(model)) + if (CClientBuildingManager::IsValidModel(model)) { m_usModelId = model; Recreate(); From 035931923db2f54f8f95bcc7738af0c0b560593a Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Wed, 3 Jan 2024 21:01:23 +0300 Subject: [PATCH 18/21] Fix rotation --- .../mods/deathmatch/logic/CClientBuilding.cpp | 2 +- Shared/mods/deathmatch/logic/Utils.h | 25 ++++++++++--------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientBuilding.cpp b/Client/mods/deathmatch/logic/CClientBuilding.cpp index ebec1a18355..6b7898aa0c2 100644 --- a/Client/mods/deathmatch/logic/CClientBuilding.cpp +++ b/Client/mods/deathmatch/logic/CClientBuilding.cpp @@ -71,7 +71,7 @@ void CClientBuilding::Create() return; CVector4D vRot4D; - ConvertEulersToQuaternion(m_vRot, vRot4D); + ConvertZXYEulersToQuaternion(m_vRot, vRot4D); m_pBuilding = g_pGame->GetPools()->AddBuilding(this, m_usModelId, &m_vPos, &vRot4D, m_interior); } diff --git a/Shared/mods/deathmatch/logic/Utils.h b/Shared/mods/deathmatch/logic/Utils.h index 96a4429d1f3..d6c2a1ebc42 100644 --- a/Shared/mods/deathmatch/logic/Utils.h +++ b/Shared/mods/deathmatch/logic/Utils.h @@ -246,19 +246,20 @@ inline float GetSmallestWrapUnsigned(float fValue, float fHigh) void RotateVector(CVector& vecLine, const CVector& vecRotation); -inline void ConvertEulersToQuaternion(const CVector& vecFrom, CVector4D &vecTo) +inline void ConvertZXYEulersToQuaternion(const CVector& vecFrom, CVector4D &vecTo) { - double cy = cos(vecFrom.fZ * 0.5); - double sy = sin(vecFrom.fZ * 0.5); - double cr = cos(vecFrom.fX * 0.5); - double sr = sin(vecFrom.fX * 0.5); - double cp = cos(vecFrom.fY * 0.5); - double sp = sin(vecFrom.fY * 0.5); - - vecTo.fW = cy * cr * cp + sy * sr * sp; - vecTo.fX = cy * sr * cp - sy * cr * sp; - vecTo.fY = cy * cr * sp + sy * sr * cp; - vecTo.fZ = sy * cr * cp - cy * sr * sp; + const float c1 = cos(vecFrom.fX / 2.0f); + const float c2 = cos(vecFrom.fY / 2.0f); + const float c3 = cos(vecFrom.fZ / 2.0f); + + const float s1 = sin(vecFrom.fX / 2.0f); + const float s2 = sin(vecFrom.fY / 2.0f); + const float s3 = sin(vecFrom.fZ / 2.0f); + + vecTo.fX = s1 * c2 * c3 - c1 * s2 * s3; + vecTo.fY = c1 * s2 * c3 + s1 * c2 * s3; + vecTo.fZ = c1 * c2 * s3 + s1 * s2 * c3; + vecTo.fW = c1 * c2 * c3 - s1 * s2 * s3; } #ifdef MTA_CLIENT From 8b33fa44efe22a240972e031c1e0828676125fb1 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Wed, 3 Jan 2024 21:40:00 +0300 Subject: [PATCH 19/21] Add position checks --- .../mods/deathmatch/logic/CClientBuilding.cpp | 23 +++++++++++++++++++ .../mods/deathmatch/logic/CClientBuilding.h | 5 ++++ .../logic/CClientBuildingManager.cpp | 5 ++++ .../deathmatch/logic/CClientBuildingManager.h | 1 + .../logic/luadefs/CLuaBuildingDefs.cpp | 2 +- 5 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Client/mods/deathmatch/logic/CClientBuilding.cpp b/Client/mods/deathmatch/logic/CClientBuilding.cpp index 6b7898aa0c2..393774c20b1 100644 --- a/Client/mods/deathmatch/logic/CClientBuilding.cpp +++ b/Client/mods/deathmatch/logic/CClientBuilding.cpp @@ -34,6 +34,9 @@ CClientBuilding::~CClientBuilding() void CClientBuilding::SetPosition(const CVector& vecPosition) { + if (!CClientBuildingManager::IsValidPosition(vecPosition)) + return; + if (m_vPos == vecPosition) return; m_vPos = vecPosition; @@ -48,6 +51,26 @@ void CClientBuilding::SetRotationRadians(const CVector& vecRadians) Recreate(); } +bool CClientBuilding::SetMatrix(const CMatrix& matrix) +{ + if (!CClientBuildingManager::IsValidPosition(matrix.vPos)) + return false; + + m_vPos = matrix.vPos; + + CVector vecRotation; + g_pMultiplayer->ConvertMatrixToEulerAngles(matrix, vecRotation.fX, vecRotation.fY, vecRotation.fZ); + + ConvertRadiansToDegreesNoWrap(vecRotation); + vecRotation = ConvertEulerRotationOrder(vecRotation, EULER_MINUS_ZYX, EULER_ZXY); + ConvertDegreesToRadiansNoWrap(vecRotation); + + m_vRot = vecRotation; + + Recreate(); + return true; +} + void CClientBuilding::SetInterior(uint8_t ucInterior) { if (m_interior == ucInterior) diff --git a/Client/mods/deathmatch/logic/CClientBuilding.h b/Client/mods/deathmatch/logic/CClientBuilding.h index 3e91effa941..f9f423f4a3c 100644 --- a/Client/mods/deathmatch/logic/CClientBuilding.h +++ b/Client/mods/deathmatch/logic/CClientBuilding.h @@ -30,6 +30,11 @@ class CClientBuilding : public CClientEntity void GetRotationRadians(CVector& vecOutRadians) const override { vecOutRadians = m_vPos; }; void SetRotationRadians(const CVector& vecRadians) override; + CEntity* GetGameEntity() override { return m_pBuilding; }; + const CEntity* GetGameEntity() const override { return m_pBuilding; }; + + bool SetMatrix(const CMatrix& matrix) override; + void SetInterior(uint8_t ucInterior) override; uint16_t GetModel() const noexcept { return m_usModelId; }; diff --git a/Client/mods/deathmatch/logic/CClientBuildingManager.cpp b/Client/mods/deathmatch/logic/CClientBuildingManager.cpp index de8cf656df3..1f482b3683d 100644 --- a/Client/mods/deathmatch/logic/CClientBuildingManager.cpp +++ b/Client/mods/deathmatch/logic/CClientBuildingManager.cpp @@ -77,3 +77,8 @@ bool CClientBuildingManager::IsValidModel(uint16_t modelId) eModelInfoType eType = pModelInfo->GetModelType(); return (eType == eModelInfoType::CLUMP || eType == eModelInfoType::ATOMIC || eType == eModelInfoType::WEAPON || eType == eModelInfoType::TIME); } + +bool CClientBuildingManager::IsValidPosition(const CVector& pos) noexcept +{ + return (pos.fX >- -3000.0f && pos.fX <= 3000.0f && pos.fY >= -3000.0f && pos.fY <= 3000.0f); +} diff --git a/Client/mods/deathmatch/logic/CClientBuildingManager.h b/Client/mods/deathmatch/logic/CClientBuildingManager.h index 5c0f0426303..e47ce1e0ebf 100644 --- a/Client/mods/deathmatch/logic/CClientBuildingManager.h +++ b/Client/mods/deathmatch/logic/CClientBuildingManager.h @@ -29,6 +29,7 @@ class CClientBuildingManager const std::list& GetBuildings() { return m_List; }; static bool IsValidModel(uint16_t modelId); + static bool IsValidPosition(const CVector& pos) noexcept; private: void AddToList(CClientBuilding* pBuilding) { m_List.push_back(pBuilding); } diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp index 4f140a0d2b6..205d571d80c 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp @@ -46,7 +46,7 @@ CClientBuilding* CLuaBuildingDefs::CreateBuilding(lua_State* const luaVM, uint16 if (!g_pGame->GetPools()->HasFreeBuildingSlot()) throw std::invalid_argument("No free slot in buildings pool"); - if (pos.fX < -3000.0f || pos.fX > 3000.0f || pos.fY < -3000.0f || pos.fY > 3000.0f) + if (!CClientBuildingManager::IsValidPosition(pos)) throw std::invalid_argument("Position is outside of game world"); ConvertDegreesToRadians(rot); From 787eb35405a928887219292f9bb53cd6a124b5a2 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Thu, 4 Jan 2024 13:56:08 +0300 Subject: [PATCH 20/21] fix --- Shared/mods/deathmatch/logic/Utils.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Shared/mods/deathmatch/logic/Utils.h b/Shared/mods/deathmatch/logic/Utils.h index d6c2a1ebc42..3930514d805 100644 --- a/Shared/mods/deathmatch/logic/Utils.h +++ b/Shared/mods/deathmatch/logic/Utils.h @@ -248,13 +248,13 @@ void RotateVector(CVector& vecLine, const CVector& vecRotation); inline void ConvertZXYEulersToQuaternion(const CVector& vecFrom, CVector4D &vecTo) { - const float c1 = cos(vecFrom.fX / 2.0f); - const float c2 = cos(vecFrom.fY / 2.0f); - const float c3 = cos(vecFrom.fZ / 2.0f); + const float c1 = cos(vecFrom.fX * 0.5f); + const float c2 = cos(vecFrom.fY * 0.5f); + const float c3 = cos(vecFrom.fZ * 0.5f); - const float s1 = sin(vecFrom.fX / 2.0f); - const float s2 = sin(vecFrom.fY / 2.0f); - const float s3 = sin(vecFrom.fZ / 2.0f); + const float s1 = sin(vecFrom.fX * 0.5f); + const float s2 = sin(vecFrom.fY * 0.5f); + const float s3 = sin(vecFrom.fZ * 0.5f); vecTo.fX = s1 * c2 * c3 - c1 * s2 * s3; vecTo.fY = c1 * s2 * c3 + s1 * c2 * s3; From e6be3fff3666c88eea20c4ba509a5cc53334f2ac Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Fri, 5 Jan 2024 16:18:41 +0300 Subject: [PATCH 21/21] fix IsValidPosition --- Client/mods/deathmatch/logic/CClientBuildingManager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Client/mods/deathmatch/logic/CClientBuildingManager.cpp b/Client/mods/deathmatch/logic/CClientBuildingManager.cpp index 1f482b3683d..13a32464973 100644 --- a/Client/mods/deathmatch/logic/CClientBuildingManager.cpp +++ b/Client/mods/deathmatch/logic/CClientBuildingManager.cpp @@ -10,6 +10,8 @@ #include "StdInc.h" +constexpr float WORLD_DISTANCE_FROM_CENTER = 3000.0f; + CClientBuildingManager::CClientBuildingManager(CClientManager* pManager) { // Init @@ -80,5 +82,6 @@ bool CClientBuildingManager::IsValidModel(uint16_t modelId) bool CClientBuildingManager::IsValidPosition(const CVector& pos) noexcept { - return (pos.fX >- -3000.0f && pos.fX <= 3000.0f && pos.fY >= -3000.0f && pos.fY <= 3000.0f); + return (pos.fX >= -WORLD_DISTANCE_FROM_CENTER && pos.fX <= WORLD_DISTANCE_FROM_CENTER && pos.fY >= -WORLD_DISTANCE_FROM_CENTER && + pos.fY <= WORLD_DISTANCE_FROM_CENTER); }