From f32574e75feaf1e376e257d3b70373d8340f8bed Mon Sep 17 00:00:00 2001 From: saml1er Date: Wed, 18 Nov 2020 00:05:28 +0500 Subject: [PATCH] Fix #1840: Crash on disconnect --- Client/mods/deathmatch/logic/CClientModel.cpp | 24 ++++------- Client/mods/deathmatch/logic/CClientModel.h | 14 +++---- .../deathmatch/logic/CClientModelManager.cpp | 42 +++++++------------ .../deathmatch/logic/CClientModelManager.h | 15 ++++--- .../mods/deathmatch/logic/CClientObject.cpp | 4 ++ Client/mods/deathmatch/logic/CClientObject.h | 10 +++-- .../logic/lua/CLuaFunctionDefs.Util.cpp | 2 +- .../logic/luadefs/CLuaEngineDefs.cpp | 12 +++--- 8 files changed, 54 insertions(+), 69 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientModel.cpp b/Client/mods/deathmatch/logic/CClientModel.cpp index 2031c0b0ec..004dff2fda 100644 --- a/Client/mods/deathmatch/logic/CClientModel.cpp +++ b/Client/mods/deathmatch/logic/CClientModel.cpp @@ -12,20 +12,14 @@ CClientModel::CClientModel(CClientManager* pManager, int iModelID, eClientModelType eModelType) { - // Init m_pManager = pManager; - m_pModelManager = pManager->GetModelManager(); m_iModelID = iModelID; m_eModelType = eModelType; - - m_pModelManager->Add(this); } CClientModel::~CClientModel(void) { Deallocate(); - - m_pModelManager->Remove(this); } bool CClientModel::Allocate(ushort usParentID) @@ -67,13 +61,16 @@ bool CClientModel::Deallocate(void) { if (!m_bAllocatedByUs) return false; - CModelInfo* pModelInfo = g_pGame->GetModelInfo(m_iModelID, true); - - // ModelInfo must be valid if (!pModelInfo->IsValid()) return false; + pModelInfo->DeallocateModel(); + this->SetParentResource(nullptr); + return true; +} +void CClientModel::RestoreEntitiesUsingThisModel() +{ auto unloadModelsAndCallEvents = [&](auto iterBegin, auto iterEnd, unsigned short usParentID, auto setElementModelLambda) { for (auto iter = iterBegin; iter != iterEnd; iter++) { @@ -106,8 +103,8 @@ bool CClientModel::Deallocate(void) } case eClientModelType::OBJECT: { - const auto& objects = &g_pClientGame->GetManager()->GetObjectManager()->GetObjects(); - unsigned short usParentID = g_pGame->GetModelInfo(m_iModelID)->GetParentID(); + const auto& objects = &g_pClientGame->GetManager()->GetObjectManager()->GetObjects(); + unsigned short usParentID = g_pGame->GetModelInfo(m_iModelID)->GetParentID(); unloadModelsAndCallEvents(objects->begin(), objects->end(), usParentID, [=](auto& element) { element.SetModel(usParentID); }); @@ -128,9 +125,4 @@ bool CClientModel::Deallocate(void) // Restore DFF/TXD g_pClientGame->GetManager()->GetDFFManager()->RestoreModel(m_iModelID); - - pModelInfo->DeallocateModel(); - - this->SetParentResource(nullptr); - return true; } diff --git a/Client/mods/deathmatch/logic/CClientModel.h b/Client/mods/deathmatch/logic/CClientModel.h index bc109c8eea..26cae9c1ce 100644 --- a/Client/mods/deathmatch/logic/CClientModel.h +++ b/Client/mods/deathmatch/logic/CClientModel.h @@ -30,16 +30,16 @@ class CClientModel CClientModel(CClientManager* pManager, int iModelID, eClientModelType eModelType); ~CClientModel(void); - int GetModelID(void) const { return m_iModelID; }; - eClientModelType GetModelType(void) const { return m_eModelType; }; - bool Allocate(ushort usParentID); - bool Deallocate(void); - void SetParentResource(CResource* pResource) { m_pParentResource = pResource; } - CResource* GetParentResource(void) const { return m_pParentResource; } + int GetModelID(void) const { return m_iModelID; }; + eClientModelType GetModelType(void) const { return m_eModelType; }; + bool Allocate(ushort usParentID); + bool Deallocate(void); + void RestoreEntitiesUsingThisModel(); + void SetParentResource(CResource* pResource) { m_pParentResource = pResource; } + CResource* GetParentResource(void) const { return m_pParentResource; } protected: CClientManager* m_pManager; - class CClientModelManager* m_pModelManager; int m_iModelID; eClientModelType m_eModelType; diff --git a/Client/mods/deathmatch/logic/CClientModelManager.cpp b/Client/mods/deathmatch/logic/CClientModelManager.cpp index ba405722aa..188d7ea86b 100644 --- a/Client/mods/deathmatch/logic/CClientModelManager.cpp +++ b/Client/mods/deathmatch/logic/CClientModelManager.cpp @@ -1,6 +1,6 @@ /***************************************************************************** * - * PROJECT: Multi Theft Auto + * PROJECT: Multi Theft Auto * (Shared logic for modifications) * LICENSE: See LICENSE in the top level directory * FILE: mods/deathmatch/logic/CClientModelManager.cpp @@ -10,17 +10,8 @@ #include "StdInc.h" -CClientModelManager::CClientModelManager(CClientManager* pManager) -{ - for (ushort i = 0; i < MAX_MODEL_ID; i++) - { - m_Models[i] = nullptr; - } -} - CClientModelManager::~CClientModelManager(void) { - // Delete all our models RemoveAll(); } @@ -28,27 +19,29 @@ void CClientModelManager::RemoveAll(void) { for (int i = 0; i < MAX_MODEL_ID; i++) { - Remove(m_Models[i]); + m_Models[i] = nullptr; } m_modelCount = 0; } -void CClientModelManager::Add(CClientModel* pModel) +void CClientModelManager::Add(const std::shared_ptr& pModel) { if (m_Models[pModel->GetModelID()] != nullptr) { - dassert(m_Models[pModel->GetModelID()] == pModel); + dassert(m_Models[pModel->GetModelID()].get() == pModel.get()); return; } m_Models[pModel->GetModelID()] = pModel; m_modelCount++; } -bool CClientModelManager::Remove(CClientModel* pModel) +bool CClientModelManager::Remove(const std::shared_ptr& pModel) { - if (pModel && m_Models[pModel->GetModelID()] != nullptr) + int modelId = pModel ? pModel->GetModelID() : 0; + if (pModel && m_Models[modelId] != nullptr) { - m_Models[pModel->GetModelID()] = nullptr; + m_Models[modelId]->RestoreEntitiesUsingThisModel(); + m_Models[modelId] = nullptr; m_modelCount--; return true; } @@ -68,7 +61,7 @@ int CClientModelManager::GetFirstFreeModelID(void) return INVALID_MODEL_ID; } -CClientModel* CClientModelManager::FindModelByID(int iModelID) +std::shared_ptr CClientModelManager::FindModelByID(int iModelID) { if (iModelID < MAX_MODEL_ID) { @@ -77,14 +70,14 @@ CClientModel* CClientModelManager::FindModelByID(int iModelID) return nullptr; } -std::vector CClientModelManager::GetModelsByType(const eClientModelType type, const unsigned int minModelID) +std::vector> CClientModelManager::GetModelsByType(const eClientModelType type, const unsigned int minModelID) { - std::vector found; + std::vector> found; found.reserve(m_modelCount); for (int i = minModelID; i < MAX_MODEL_ID; i++) { - CClientModel* model = m_Models[i]; + std::shared_ptr model = m_Models[i]; if (model && model->GetModelType() == type) { found.push_back(model); @@ -97,12 +90,7 @@ void CClientModelManager::DeallocateModelsAllocatedByResource(CResource* pResour { for (ushort i = 0; i < MAX_MODEL_ID; i++) { - if (m_Models[i] != nullptr) - { - if (m_Models[i]->GetParentResource() == pResource) - { - m_Models[i]->Deallocate(); - } - } + if (m_Models[i] != nullptr && m_Models[i]->GetParentResource() == pResource) + Remove(m_Models[i]); } } diff --git a/Client/mods/deathmatch/logic/CClientModelManager.h b/Client/mods/deathmatch/logic/CClientModelManager.h index 4b8a958cd4..bc215a5eef 100644 --- a/Client/mods/deathmatch/logic/CClientModelManager.h +++ b/Client/mods/deathmatch/logic/CClientModelManager.h @@ -23,24 +23,23 @@ class CClientModelManager friend class CClientModel; public: - CClientModelManager(class CClientManager* pManager); + CClientModelManager(class CClientManager* pManager) {} ~CClientModelManager(void); void RemoveAll(void); - void Add(CClientModel* pModel); - bool Remove(CClientModel* pModel); + void Add(const std::shared_ptr& pModel); + bool Remove(const std::shared_ptr& pModel); int GetFirstFreeModelID(void); - CClientModel* FindModelByID(int iModelID); - - std::vector CClientModelManager::GetModelsByType(const eClientModelType type, const unsigned int minModelID = 0); + std::shared_ptr FindModelByID(int iModelID); + std::vector> GetModelsByType(const eClientModelType type, const unsigned int minModelID = 0); void DeallocateModelsAllocatedByResource(CResource* pResource); private: - CClientModel* m_Models[MAX_MODEL_ID]; - unsigned int m_modelCount = 0; + std::shared_ptr m_Models[MAX_MODEL_ID]; + unsigned int m_modelCount = 0; }; diff --git a/Client/mods/deathmatch/logic/CClientObject.cpp b/Client/mods/deathmatch/logic/CClientObject.cpp index 1cb5b8024e..bf7deb304f 100644 --- a/Client/mods/deathmatch/logic/CClientObject.cpp +++ b/Client/mods/deathmatch/logic/CClientObject.cpp @@ -53,6 +53,7 @@ CClientObject::CClientObject(CClientManager* pManager, ElementID ID, unsigned sh if (m_bIsLowLod) m_pManager->OnLowLODElementCreated(); + m_clientModel = pManager->GetModelManager()->FindModelByID(usModel); } CClientObject::~CClientObject() @@ -71,6 +72,7 @@ CClientObject::~CClientObject() if (m_bIsLowLod) m_pManager->OnLowLODElementDestroyed(); + m_clientModel = nullptr; } void CClientObject::Unlink() @@ -261,6 +263,8 @@ void CClientObject::SetModel(unsigned short usModel) // Set the new model ID and recreate the model m_usModel = usModel; + if (m_clientModel && m_clientModel->GetModelID() != m_usModel) + m_clientModel = nullptr; m_pModelInfo = g_pGame->GetModelInfo(usModel); UpdateSpatialData(); diff --git a/Client/mods/deathmatch/logic/CClientObject.h b/Client/mods/deathmatch/logic/CClientObject.h index 332453875b..b73d41e8f7 100644 --- a/Client/mods/deathmatch/logic/CClientObject.h +++ b/Client/mods/deathmatch/logic/CClientObject.h @@ -13,6 +13,7 @@ class CClientObject; #pragma once #include "CClientStreamElement.h" +#include "CClientModel.h" struct SLastSyncedObjectData { @@ -156,10 +157,11 @@ class CClientObject : public CClientStreamElement CVector m_vecMoveSpeed; CVector m_vecTurnSpeed; - const bool m_bIsLowLod; // true if this object is low LOD - CClientObject* m_pLowLodObject; // Pointer to low LOD version of this object - std::vector m_HighLodObjectList; // List of objects that use this object as a low LOD version - bool m_IsHiddenLowLod; // true if this object is low LOD and should not be drawn + const bool m_bIsLowLod; // true if this object is low LOD + CClientObject* m_pLowLodObject; // Pointer to low LOD version of this object + std::vector m_HighLodObjectList; // List of objects that use this object as a low LOD version + bool m_IsHiddenLowLod; // true if this object is low LOD and should not be drawn + std::shared_ptr m_clientModel; public: CObject* m_pObject; diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.Util.cpp b/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.Util.cpp index 42a1fc8f38..76092b2192 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.Util.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.Util.cpp @@ -28,7 +28,7 @@ int CLuaFunctionDefs::GetValidPedModels(lua_State* luaVM) // Gather our custom skin model IDs allocated with engineRequestModel // (there might be some < 313 as well, and since we don't want duplicates, we start at 313, others are already included by the loop above) - for (const CClientModel* model : m_pManager->GetModelManager()->GetModelsByType(eClientModelType::PED, 313)) + for (auto model : m_pManager->GetModelManager()->GetModelsByType(eClientModelType::PED, 313)) { lua_pushnumber(luaVM, ++iIndex); lua_pushnumber(luaVM, model->GetModelID()); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp index 6e3f2c0a3e..40a127b9ab 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp @@ -582,10 +582,10 @@ int CLuaEngineDefs::EngineRequestModel(lua_State* luaVM) { int iModelID = m_pManager->GetModelManager()->GetFirstFreeModelID(); if (iModelID != INVALID_MODEL_ID) { - CClientModel* pModel = m_pManager->GetModelManager()->FindModelByID(iModelID); + std::shared_ptr pModel = m_pManager->GetModelManager()->FindModelByID(iModelID); if (pModel == nullptr) - pModel = new CClientModel(m_pManager, iModelID, eModelType); - + pModel = std::make_shared(m_pManager, iModelID, eModelType); + m_pManager->GetModelManager()->Add(pModel); ushort usParentID = -1; if (argStream.NextIsNumber()) @@ -631,9 +631,9 @@ int CLuaEngineDefs::EngineFreeModel(lua_State* luaVM) if (!argStream.HasErrors()) { - CClientModel* pModel = m_pManager->GetModelManager()->FindModelByID(iModelID); - - if (pModel && pModel->Deallocate()) + auto modelManager = m_pManager->GetModelManager(); + std::shared_ptr pModel = modelManager->FindModelByID(iModelID); + if (pModel && modelManager->Remove(pModel)) { lua_pushboolean(luaVM, true); return 1;