From e32464b6ea19162d6a3d5fc3544040280ac50e7a Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Sat, 16 Jul 2016 15:45:36 +0300 Subject: [PATCH] Don't clear entity containers untill after the virtual machine was closed. Should close #22 --- source/Core.cpp | 92 +++++++++++++++++------ source/Core.hpp | 187 ++++++++++++++++++++++++++++++++++++++++++---- source/Main.cpp | 1 + source/SqBase.hpp | 15 ++++ 4 files changed, 260 insertions(+), 35 deletions(-) diff --git a/source/Core.cpp b/source/Core.cpp index b4c36c1a..a1a36413 100644 --- a/source/Core.cpp +++ b/source/Core.cpp @@ -87,6 +87,37 @@ public: } }; +/* ------------------------------------------------------------------------------------------------ + * Implements RAII to make sure that entity containers area cleaned up at all costs. +*/ +template < typename T > class ContainerCleaner +{ + // -------------------------------------------------------------------------------------------- + const EntityType m_Type; // The type of entity container to clear. + +public: + + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + ContainerCleaner(T & container, EntityType type) + : m_Type(type) + { + for (auto & ent : container) + { + ent.Destroy(); + } + } + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~ContainerCleaner() + { + Core::Get().ClearContainer(m_Type); + } +}; + // ------------------------------------------------------------------------------------------------ Core Core::s_Inst; @@ -413,14 +444,16 @@ void Core::Terminate() // Tell modules to do their monkey business _Func->SendPluginCommand(0xDEADC0DE, ""); } + LogDbg("Clearing the entity containers"); // Release all entity resources by clearing the containers - m_Players.clear(); - m_Vehicles.clear(); - m_Objects.clear(); - m_Pickups.clear(); - m_Checkpoints.clear(); - m_Blips.clear(); - m_Keybinds.clear(); + ContainerCleaner< Players > cc_players(m_Players, ENT_PLAYER); + ContainerCleaner< Vehicles > cc_vehicles(m_Vehicles, ENT_VEHICLE); + ContainerCleaner< Objects > cc_objects(m_Objects, ENT_OBJECT); + ContainerCleaner< Pickups > cc_pickups(m_Pickups, ENT_PICKUP); + ContainerCleaner< Checkpoints > cc_checkpoints(m_Checkpoints, ENT_CHECKPOINT); + ContainerCleaner< Blips > cc_blips(m_Blips, ENT_BLIP); + ContainerCleaner< Keybinds > cc_keybinds(m_Keybinds, ENT_KEYBIND); + LogDbg("Terminating routines an commands"); // Release all resources from routines TerminateRoutines(); // Release all resources from command managers @@ -435,6 +468,7 @@ void Core::Terminate() // Is there a VM to close? if (m_VM) { + LogDbg("Closing the virtual machine"); // Release all script callbacks ResetFunc(); // Release the script instances @@ -451,6 +485,8 @@ void Core::Terminate() // Tell modules to do their monkey business _Func->SendPluginCommand(0xDEADBEAF, ""); } + + LogDbg("Squirrel plugin was successfully terminated"); } // ------------------------------------------------------------------------------------------------ @@ -688,7 +724,7 @@ void Core::BindEvent(Int32 id, Object & env, Function & func) } // ------------------------------------------------------------------------------------------------ -Core::BlipInst::~BlipInst() +void Core::BlipInst::Destroy() { // Should we notify that this entity is being cleaned up? if (VALID_ENTITY(mID)) @@ -711,12 +747,14 @@ Core::BlipInst::~BlipInst() // Now attempt to destroy this entity from the server _Func->DestroyCoordBlip(mID); } - // Don't release the callbacks abruptly in destructor + // Reset the instance to it's initial state + ResetInst(*this); + // Don't release the callbacks abruptly Core::ResetFunc(*this); } // ------------------------------------------------------------------------------------------------ -Core::CheckpointInst::~CheckpointInst() +void Core::CheckpointInst::Destroy() { // Should we notify that this entity is being cleaned up? if (VALID_ENTITY(mID)) @@ -739,12 +777,14 @@ Core::CheckpointInst::~CheckpointInst() // Now attempt to destroy this entity from the server _Func->DeleteCheckPoint(mID); } - // Don't release the callbacks abruptly in destructor + // Reset the instance to it's initial state + ResetInst(*this); + // Don't release the callbacks abruptly Core::ResetFunc(*this); } // ------------------------------------------------------------------------------------------------ -Core::KeybindInst::~KeybindInst() +void Core::KeybindInst::Destroy() { // Should we notify that this entity is being cleaned up? if (VALID_ENTITY(mID)) @@ -767,12 +807,14 @@ Core::KeybindInst::~KeybindInst() // Now attempt to destroy this entity from the server _Func->RemoveKeyBind(mID); } - // Don't release the callbacks abruptly in destructor + // Reset the instance to it's initial state + ResetInst(*this); + // Don't release the callbacks abruptly Core::ResetFunc(*this); } // ------------------------------------------------------------------------------------------------ -Core::ObjectInst::~ObjectInst() +void Core::ObjectInst::Destroy() { // Should we notify that this entity is being cleaned up? if (VALID_ENTITY(mID)) @@ -795,12 +837,14 @@ Core::ObjectInst::~ObjectInst() // Now attempt to destroy this entity from the server _Func->DeleteObject(mID); } - // Don't release the callbacks abruptly in destructor + // Reset the instance to it's initial state + ResetInst(*this); + // Don't release the callbacks abruptly Core::ResetFunc(*this); } // ------------------------------------------------------------------------------------------------ -Core::PickupInst::~PickupInst() +void Core::PickupInst::Destroy() { // Should we notify that this entity is being cleaned up? if (VALID_ENTITY(mID)) @@ -823,12 +867,14 @@ Core::PickupInst::~PickupInst() // Now attempt to destroy this entity from the server _Func->DeletePickup(mID); } - // Don't release the callbacks abruptly in destructor + // Reset the instance to it's initial state + ResetInst(*this); + // Don't release the callbacks abruptly Core::ResetFunc(*this); } // ------------------------------------------------------------------------------------------------ -Core::PlayerInst::~PlayerInst() +void Core::PlayerInst::Destroy() { // Should we notify that this entity is being cleaned up? if (VALID_ENTITY(mID)) @@ -845,12 +891,14 @@ Core::PlayerInst::~PlayerInst() // Release the used memory buffer mInst->m_Buffer.ResetAll(); } - // Don't release the callbacks abruptly in destructor + // Reset the instance to it's initial state + ResetInst(*this); + // Don't release the callbacks abruptly Core::ResetFunc(*this); } // ------------------------------------------------------------------------------------------------ -Core::VehicleInst::~VehicleInst() +void Core::VehicleInst::Destroy() { // Should we notify that this entity is being cleaned up? if (VALID_ENTITY(mID)) @@ -873,7 +921,9 @@ Core::VehicleInst::~VehicleInst() // Now attempt to destroy this entity from the server _Func->DeleteVehicle(mID); } - // Don't release the callbacks abruptly in destructor + // Reset the instance to it's initial state + ResetInst(*this); + // Don't release the callbacks abruptly Core::ResetFunc(*this); } diff --git a/source/Core.hpp b/source/Core.hpp index 3594f259..4abfd21e 100644 --- a/source/Core.hpp +++ b/source/Core.hpp @@ -15,6 +15,11 @@ // ------------------------------------------------------------------------------------------------ namespace SqMod { +/* ------------------------------------------------------------------------------------------------ + * Forward declarations. +*/ +template < typename T > class ContainerCleaner; + /* ------------------------------------------------------------------------------------------------ * Circular locks employed by the central core. */ @@ -29,6 +34,9 @@ enum CoreCircularLocks */ class Core { + // -------------------------------------------------------------------------------------------- + template < typename T > friend class ContainerCleaner; + private: // -------------------------------------------------------------------------------------------- @@ -71,10 +79,29 @@ protected: */ struct BlipInst { + /* ---------------------------------------------------------------------------------------- + * Default constructor. + */ BlipInst() : mID(-1), mFlags(ENF_DEFAULT), mInst(nullptr) - { /* ... */ } + { + Core::Get().ResetInst(*this); + } - ~BlipInst(); + /* ---------------------------------------------------------------------------------------- + * Destructor. + */ + ~BlipInst() + { + if (VALID_ENTITY(mID)) + { + Destroy(); + } + } + + /* ---------------------------------------------------------------------------------------- + * Destroy the entity instance from the server, if necessary. + */ + void Destroy(); // ---------------------------------------------------------------------------------------- Int32 mID; @@ -103,10 +130,29 @@ protected: */ struct CheckpointInst { + /* ---------------------------------------------------------------------------------------- + * Default constructor. + */ CheckpointInst() : mID(-1), mFlags(ENF_DEFAULT), mInst(nullptr) - { /* ... */ } + { + Core::Get().ResetInst(*this); + } - ~CheckpointInst(); + /* ---------------------------------------------------------------------------------------- + * Destructor. + */ + ~CheckpointInst() + { + if (VALID_ENTITY(mID)) + { + Destroy(); + } + } + + /* ---------------------------------------------------------------------------------------- + * Destroy the entity instance from the server, if necessary. + */ + void Destroy(); // ---------------------------------------------------------------------------------------- Int32 mID; @@ -127,10 +173,29 @@ protected: */ struct KeybindInst { + /* ---------------------------------------------------------------------------------------- + * Default constructor. + */ KeybindInst() : mID(-1), mFlags(ENF_DEFAULT), mInst(nullptr) - { /* ... */ } + { + Core::Get().ResetInst(*this); + } - ~KeybindInst(); + /* ---------------------------------------------------------------------------------------- + * Destructor. + */ + ~KeybindInst() + { + if (VALID_ENTITY(mID)) + { + Destroy(); + } + } + + /* ---------------------------------------------------------------------------------------- + * Destroy the entity instance from the server, if necessary. + */ + void Destroy(); // ---------------------------------------------------------------------------------------- Int32 mID; @@ -158,10 +223,29 @@ protected: */ struct ObjectInst { + /* ---------------------------------------------------------------------------------------- + * Default constructor. + */ ObjectInst() : mID(-1), mFlags(ENF_DEFAULT), mInst(nullptr) - { /* ... */ } + { + Core::Get().ResetInst(*this); + } - ~ObjectInst(); + /* ---------------------------------------------------------------------------------------- + * Destructor. + */ + ~ObjectInst() + { + if (VALID_ENTITY(mID)) + { + Destroy(); + } + } + + /* ---------------------------------------------------------------------------------------- + * Destroy the entity instance from the server, if necessary. + */ + void Destroy(); // ---------------------------------------------------------------------------------------- Int32 mID; @@ -183,10 +267,29 @@ protected: */ struct PickupInst { + /* ---------------------------------------------------------------------------------------- + * Default constructor. + */ PickupInst() : mID(-1), mFlags(ENF_DEFAULT), mInst(nullptr) - { /* ... */ } + { + Core::Get().ResetInst(*this); + } - ~PickupInst(); + /* ---------------------------------------------------------------------------------------- + * Destructor. + */ + ~PickupInst() + { + if (VALID_ENTITY(mID)) + { + Destroy(); + } + } + + /* ---------------------------------------------------------------------------------------- + * Destroy the entity instance from the server, if necessary. + */ + void Destroy(); // ---------------------------------------------------------------------------------------- Int32 mID; @@ -209,10 +312,29 @@ protected: */ struct PlayerInst { + /* ---------------------------------------------------------------------------------------- + * Default constructor. + */ PlayerInst() : mID(-1), mFlags(ENF_DEFAULT), mInst(nullptr) - { /* ... */ } + { + Core::Get().ResetInst(*this); + } - ~PlayerInst(); + /* ---------------------------------------------------------------------------------------- + * Destructor. + */ + ~PlayerInst() + { + if (VALID_ENTITY(mID)) + { + Destroy(); + } + } + + /* ---------------------------------------------------------------------------------------- + * Destroy the entity instance from the server, if necessary. + */ + void Destroy(); // ---------------------------------------------------------------------------------------- Int32 mID; @@ -310,10 +432,29 @@ protected: */ struct VehicleInst { + /* ---------------------------------------------------------------------------------------- + * Default constructor. + */ VehicleInst() : mID(-1), mFlags(ENF_DEFAULT), mInst(nullptr) - { /* ... */ } + { + Core::Get().ResetInst(*this); + } - ~VehicleInst(); + /* ---------------------------------------------------------------------------------------- + * Destructor. + */ + ~VehicleInst() + { + if (VALID_ENTITY(mID)) + { + Destroy(); + } + } + + /* ---------------------------------------------------------------------------------------- + * Destroy the entity instance from the server, if necessary. + */ + void Destroy(); // ---------------------------------------------------------------------------------------- Int32 mID; @@ -667,6 +808,24 @@ public: protected: + /* -------------------------------------------------------------------------------------------- + * Container cleaner. + */ + void ClearContainer(EntityType type) + { + switch (type) + { + case ENT_BLIP: m_Blips.clear(); break; + case ENT_CHECKPOINT: m_Blips.clear(); break; + case ENT_KEYBIND: m_Blips.clear(); break; + case ENT_OBJECT: m_Blips.clear(); break; + case ENT_PICKUP: m_Blips.clear(); break; + case ENT_PLAYER: m_Blips.clear(); break; + case ENT_VEHICLE: m_Blips.clear(); break; + default: STHROWF("Cannot clear unknown entity type container"); + } + } + /* -------------------------------------------------------------------------------------------- * Instance cleaners. */ diff --git a/source/Main.cpp b/source/Main.cpp index ae521fae..6bdd6ba8 100644 --- a/source/Main.cpp +++ b/source/Main.cpp @@ -224,6 +224,7 @@ static void OnPlayerDisconnect(int32_t player_id, vcmpDisconnectReason reason) // Attempt to forward the event try { + printf("Disconnecting... %d\n", player_id); Core::Get().DisconnectPlayer(player_id, reason, NullObject()); } SQMOD_CATCH_EVENT_EXCEPTION(OnPlayerDisconnect) diff --git a/source/SqBase.hpp b/source/SqBase.hpp index 2987b316..067e9eb3 100644 --- a/source/SqBase.hpp +++ b/source/SqBase.hpp @@ -394,6 +394,21 @@ enum EntityFlags ENF_LOCKED = (2 << 1) }; +/* ------------------------------------------------------------------------------------------------ + * Used to identify entity types. +*/ +enum EntityType +{ + ENT_UNKNOWN = 0, + ENT_BLIP, + ENT_CHECKPOINT, + ENT_KEYBIND, + ENT_OBJECT, + ENT_PICKUP, + ENT_PLAYER, + ENT_VEHICLE +}; + } // Namespace:: SqMod /* ------------------------------------------------------------------------------------------------