Skip to content

Commit

Permalink
Fix multitheftauto#1840: Crash on disconnect
Browse files Browse the repository at this point in the history
  • Loading branch information
codenulls committed Nov 17, 2020
1 parent 8dd31b4 commit f32574e
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 69 deletions.
24 changes: 8 additions & 16 deletions Client/mods/deathmatch/logic/CClientModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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++)
{
Expand Down Expand Up @@ -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); });

Expand All @@ -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;
}
14 changes: 7 additions & 7 deletions Client/mods/deathmatch/logic/CClientModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
42 changes: 15 additions & 27 deletions Client/mods/deathmatch/logic/CClientModelManager.cpp
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -10,45 +10,38 @@

#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();
}

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<CClientModel>& 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<CClientModel>& 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;
}
Expand All @@ -68,7 +61,7 @@ int CClientModelManager::GetFirstFreeModelID(void)
return INVALID_MODEL_ID;
}

CClientModel* CClientModelManager::FindModelByID(int iModelID)
std::shared_ptr<CClientModel> CClientModelManager::FindModelByID(int iModelID)
{
if (iModelID < MAX_MODEL_ID)
{
Expand All @@ -77,14 +70,14 @@ CClientModel* CClientModelManager::FindModelByID(int iModelID)
return nullptr;
}

std::vector<CClientModel*> CClientModelManager::GetModelsByType(const eClientModelType type, const unsigned int minModelID)
std::vector<std::shared_ptr<CClientModel>> CClientModelManager::GetModelsByType(const eClientModelType type, const unsigned int minModelID)
{
std::vector<CClientModel*> found;
std::vector<std::shared_ptr<CClientModel>> found;
found.reserve(m_modelCount);

for (int i = minModelID; i < MAX_MODEL_ID; i++)
{
CClientModel* model = m_Models[i];
std::shared_ptr<CClientModel> model = m_Models[i];
if (model && model->GetModelType() == type)
{
found.push_back(model);
Expand All @@ -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]);
}
}
15 changes: 7 additions & 8 deletions Client/mods/deathmatch/logic/CClientModelManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<CClientModel>& pModel);
bool Remove(const std::shared_ptr<CClientModel>& pModel);

int GetFirstFreeModelID(void);

CClientModel* FindModelByID(int iModelID);

std::vector<CClientModel*> CClientModelManager::GetModelsByType(const eClientModelType type, const unsigned int minModelID = 0);
std::shared_ptr<CClientModel> FindModelByID(int iModelID);

std::vector<std::shared_ptr<CClientModel>> 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<CClientModel> m_Models[MAX_MODEL_ID];
unsigned int m_modelCount = 0;
};
4 changes: 4 additions & 0 deletions Client/mods/deathmatch/logic/CClientObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -71,6 +72,7 @@ CClientObject::~CClientObject()

if (m_bIsLowLod)
m_pManager->OnLowLODElementDestroyed();
m_clientModel = nullptr;
}

void CClientObject::Unlink()
Expand Down Expand Up @@ -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();

Expand Down
10 changes: 6 additions & 4 deletions Client/mods/deathmatch/logic/CClientObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class CClientObject;
#pragma once

#include "CClientStreamElement.h"
#include "CClientModel.h"

struct SLastSyncedObjectData
{
Expand Down Expand Up @@ -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<CClientObject*> 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<CClientObject*> 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<CClientModel> m_clientModel;

public:
CObject* m_pObject;
Expand Down
2 changes: 1 addition & 1 deletion Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.Util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
12 changes: 6 additions & 6 deletions Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CClientModel> pModel = m_pManager->GetModelManager()->FindModelByID(iModelID);
if (pModel == nullptr)
pModel = new CClientModel(m_pManager, iModelID, eModelType);

pModel = std::make_shared<CClientModel>(m_pManager, iModelID, eModelType);
m_pManager->GetModelManager()->Add(pModel);
ushort usParentID = -1;

if (argStream.NextIsNumber())
Expand Down Expand Up @@ -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<CClientModel> pModel = modelManager->FindModelByID(iModelID);
if (pModel && modelManager->Remove(pModel))
{
lua_pushboolean(luaVM, true);
return 1;
Expand Down

0 comments on commit f32574e

Please sign in to comment.