diff --git a/Client/game_sa/CPlayerPedSA.cpp b/Client/game_sa/CPlayerPedSA.cpp index 534f8376c6..cf8a03faea 100644 --- a/Client/game_sa/CPlayerPedSA.cpp +++ b/Client/game_sa/CPlayerPedSA.cpp @@ -18,6 +18,7 @@ #include "CPlayerInfoSA.h" #include "CPlayerPedSA.h" #include "CWorldSA.h" +#include "CProjectileInfoSA.h" extern CCoreInterface* g_pCore; extern CGameSA* pGame; @@ -137,6 +138,7 @@ CPlayerPedSA::~CPlayerPedSA() if ((DWORD)GetInterface()->vtbl != VTBL_CPlaceable) { CWorldSA* world = (CWorldSA*)pGame->GetWorld(); + pGame->GetProjectileInfo()->RemoveEntityReferences(this); world->Remove(m_pInterface, CPlayerPed_Destructor); DWORD dwThis = (DWORD)m_pInterface; diff --git a/Client/game_sa/CProjectileInfoSA.cpp b/Client/game_sa/CProjectileInfoSA.cpp index 439553941d..843f029462 100644 --- a/Client/game_sa/CProjectileInfoSA.cpp +++ b/Client/game_sa/CProjectileInfoSA.cpp @@ -180,3 +180,18 @@ DWORD CProjectileInfoSA::GetCounter() { return internalInterface->dwCounter - pGame->GetSystemTime(); } + +void CProjectileInfoSA::RemoveEntityReferences(CEntity* entity) +{ + const CEntitySAInterface* entityInterface = entity->GetInterface(); + for (int i = 0; i < PROJECTILE_INFO_COUNT; i++) + { + auto projectileInterface = projectileInfo[i]->internalInterface; + + if (projectileInterface->pEntProjectileOwner == entityInterface) + projectileInterface->pEntProjectileOwner = nullptr; + + if (projectileInterface->pEntProjectileTarget == entityInterface) + projectileInterface->pEntProjectileTarget = nullptr; + } +} diff --git a/Client/game_sa/CProjectileInfoSA.h b/Client/game_sa/CProjectileInfoSA.h index 2d8ba9cb32..73b69f74e2 100644 --- a/Client/game_sa/CProjectileInfoSA.h +++ b/Client/game_sa/CProjectileInfoSA.h @@ -42,7 +42,8 @@ class CProjectileInfoSAInterface }; // #pragma pack(pop) -class CProjectileInfoSA : public CProjectileInfo +// TODO extract manager class +class CProjectileInfoSA final : public CProjectileInfo { private: CProjectileInfoSA* projectileInfo[PROJECTILE_INFO_COUNT]; @@ -65,6 +66,7 @@ class CProjectileInfoSA : public CProjectileInfo CProjectileInfo* GetProjectileInfo(DWORD dwIndex); bool AddProjectile(CEntity* creator, eWeaponType eWeapon, CVector vecOrigin, float fForce, CVector* target, CEntity* targetEntity); CProjectile* GetProjectile(void* projectilePointer); + void RemoveEntityReferences(CEntity* entity); CEntity* GetTarget(); void SetTarget(CEntity* pEntity); diff --git a/Client/game_sa/CVehicleSA.cpp b/Client/game_sa/CVehicleSA.cpp index 9d4a02598e..579ebb6180 100644 --- a/Client/game_sa/CVehicleSA.cpp +++ b/Client/game_sa/CVehicleSA.cpp @@ -224,6 +224,7 @@ CVehicleSA::~CVehicleSA() } CWorldSA* pWorld = (CWorldSA*)pGame->GetWorld(); + pGame->GetProjectileInfo()->RemoveEntityReferences(this); pWorld->Remove(m_pInterface, CVehicle_Destructor); pWorld->RemoveReferencesToDeletedObject(m_pInterface); diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 7169125a24..acc385998c 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -34,6 +34,7 @@ #include #include #include "game/CClock.h" +#include #include #include "CServerInfo.h" @@ -403,6 +404,10 @@ CClientGame::CClientGame(bool bLocalPlay) : m_ServerInfo(new CServerInfo()) CClientGame::~CClientGame() { m_bBeingDeleted = true; + // Remove active projectile references to local player + if (auto pLocalPlayer = g_pClientGame->GetLocalPlayer()) + g_pGame->GetProjectileInfo()->RemoveEntityReferences(pLocalPlayer->GetGameEntity()); + // Stop all explosions. Unfortunately this doesn't fix the crash // if a vehicle is destroyed while it explodes. g_pGame->GetExplosionManager()->RemoveAllExplosions(); diff --git a/Client/sdk/game/CProjectileInfo.h b/Client/sdk/game/CProjectileInfo.h index 586cbd029c..d32a538623 100644 --- a/Client/sdk/game/CProjectileInfo.h +++ b/Client/sdk/game/CProjectileInfo.h @@ -24,6 +24,7 @@ class CProjectileInfo virtual CProjectileInfo* GetProjectileInfo(void* projectileInfoInterface) = 0; // don't use virtual void RemoveProjectile(CProjectileInfo* pProjectileInfo, CProjectile* pProjectile, bool bBlow = true) = 0; virtual CProjectileInfo* GetProjectileInfo(DWORD Index) = 0; + virtual void RemoveEntityReferences(CEntity* entity) = 0; virtual CEntity* GetTarget() = 0; virtual void SetTarget(CEntity* pEntity) = 0;