diff --git a/Client/mods/deathmatch/logic/CClientDisplay.cpp b/Client/mods/deathmatch/logic/CClientDisplay.cpp index 1709a4eb364..b6df06f697a 100644 --- a/Client/mods/deathmatch/logic/CClientDisplay.cpp +++ b/Client/mods/deathmatch/logic/CClientDisplay.cpp @@ -10,25 +10,16 @@ #include -CClientDisplay::CClientDisplay(CClientDisplayManager* pDisplayManager, unsigned long ulID) +CClientDisplay::CClientDisplay(unsigned long ulID) { - m_pDisplayManager = pDisplayManager; m_ulID = ulID; m_ulExpirationTime = 0; m_bVisible = true; m_Color = SColorRGBA(255, 255, 255, 255); - - m_pDisplayManager->AddToList(this); -} - -CClientDisplay::~CClientDisplay() -{ - // Remove us from the manager - m_pDisplayManager->RemoveFromList(this); } void CClientDisplay::SetColorAlpha(unsigned char ucAlpha) { m_Color.A = ucAlpha; -} \ No newline at end of file +} diff --git a/Client/mods/deathmatch/logic/CClientDisplay.h b/Client/mods/deathmatch/logic/CClientDisplay.h index 291180c3c55..8fe714d68ee 100644 --- a/Client/mods/deathmatch/logic/CClientDisplay.h +++ b/Client/mods/deathmatch/logic/CClientDisplay.h @@ -22,18 +22,16 @@ enum eDisplayType class CClientDisplay { - friend class CClientDisplayManager; - public: - CClientDisplay(class CClientDisplayManager* pDisplayManager, unsigned long ulID); - virtual ~CClientDisplay(); + CClientDisplay(unsigned long ulID); + virtual ~CClientDisplay() = default; - unsigned long GetID() { return m_ulID; } + unsigned long GetID() const { return m_ulID; } virtual eDisplayType GetType() = 0; - unsigned long GetExpirationTime() { return m_ulExpirationTime; }; + unsigned long GetExpirationTime() const { return m_ulExpirationTime; }; void SetExpirationTime(unsigned long ulTime) { m_ulExpirationTime = ulTime; }; - unsigned long GetTimeTillExpiration() { return m_ulExpirationTime - CClientTime::GetTime(); }; + unsigned long GetTimeTillExpiration() const { return m_ulExpirationTime - CClientTime::GetTime(); }; void SetTimeTillExpiration(unsigned long ulMs) { m_ulExpirationTime = CClientTime::GetTime() + ulMs; }; virtual const CVector& GetPosition() { return m_vecPosition; }; @@ -49,9 +47,7 @@ class CClientDisplay virtual void Render() = 0; protected: - bool IsExpired() { return (m_ulExpirationTime != 0 && (CClientTime::GetTime() > m_ulExpirationTime)); }; - - CClientDisplayManager* m_pDisplayManager; + bool IsExpired() const { return (m_ulExpirationTime != 0 && (CClientTime::GetTime() > m_ulExpirationTime)); }; unsigned long m_ulID; unsigned long m_ulExpirationTime; diff --git a/Client/mods/deathmatch/logic/CClientDisplayManager.cpp b/Client/mods/deathmatch/logic/CClientDisplayManager.cpp index 5eafeea8cc9..651b1d2efa1 100644 --- a/Client/mods/deathmatch/logic/CClientDisplayManager.cpp +++ b/Client/mods/deathmatch/logic/CClientDisplayManager.cpp @@ -12,27 +12,21 @@ using std::list; -CClientDisplayManager::CClientDisplayManager() -{ - // Init - m_bCanRemoveFromList = true; -} - -CClientDisplayManager::~CClientDisplayManager() -{ - RemoveAll(); -} - -CClientDisplay* CClientDisplayManager::Get(unsigned long ulID) +std::shared_ptr CClientDisplayManager::Get(unsigned long ulID) { // Find the display with the given id - list::const_iterator iter = m_List.begin(); - for (; iter != m_List.end(); iter++) + auto iter = m_List.begin(); + + for (; iter != m_List.end(); iter++) // Iterate weak_ptr list { - if ((*iter)->GetID() == ulID) + if (const auto& display = (*iter).lock()) // Make sure the shared_ptr still exists { - return *iter; + if (display->GetID() == ulID) + { + return display; + } } + } return NULL; @@ -49,57 +43,38 @@ void CClientDisplayManager::DrawText2D(const char* szCaption, const CVector& vec static_cast(fResHeight), rgbaColor, szCaption, fScale, fScale, 0); } -void CClientDisplayManager::AddToList(CClientDisplay* pDisplay) +void CClientDisplayManager::AddToList(const std::shared_ptr& display) { - m_List.push_back(pDisplay); + m_List.push_back(display); } -void CClientDisplayManager::RemoveAll() +void CClientDisplayManager::DoPulse() { - // Delete all the items in the list - m_bCanRemoveFromList = false; - list::iterator iter = m_List.begin(); - for (; iter != m_List.end(); iter++) - { - delete *iter; - } + // Render all our displays + auto iter = m_List.begin(); - // Clear the list - m_List.clear(); - m_bCanRemoveFromList = true; -} + // Clean up expired weak_ptr + m_List.remove_if([](const std::weak_ptr& wp) { return wp.expired(); }); -void CClientDisplayManager::RemoveFromList(CClientDisplay* pDisplay) -{ - if (m_bCanRemoveFromList) + for (; iter != m_List.end(); iter++) // Iterate weak_ptr list { - if (!m_List.empty()) + if (const auto& display = (*iter).lock()) // Make sure the shared_ptr still exists { - m_List.remove(pDisplay); + display->Render(); } } } -void CClientDisplayManager::DoPulse() +std::shared_ptr CClientDisplayManager::CreateVectorGraphicDisplay(CClientVectorGraphic* svg) { - // Render all our displays - m_bCanRemoveFromList = false; - list::iterator iter = m_List.begin(); - while (iter != m_List.end()) - { - CClientDisplay* pObject = *iter; - if (pObject->IsExpired()) - { - // Delete it and remove it from the list - delete pObject; - iter = m_List.erase(iter); - } - else - { - ++iter; - pObject->Render(); - } - } + auto display = std::make_shared(svg); + AddToList(display); + return display; +} - m_bCanRemoveFromList = true; +std::shared_ptr CClientDisplayManager::CreateTextDisplay(int ID) +{ + auto display = std::make_shared(ID); + AddToList(display); + return display; } diff --git a/Client/mods/deathmatch/logic/CClientDisplayManager.h b/Client/mods/deathmatch/logic/CClientDisplayManager.h index f4fcffdfd5a..eac7e290842 100644 --- a/Client/mods/deathmatch/logic/CClientDisplayManager.h +++ b/Client/mods/deathmatch/logic/CClientDisplayManager.h @@ -13,9 +13,12 @@ class CClientDisplayManager; #pragma once #include "CClientManager.h" -#include -class CClientDisplay; +#include "CClientDisplay.h" +#include "CClientVectorGraphicDisplay.h" +#include "CClientTextDisplay.h" + +#include class CClientDisplayManager { @@ -23,21 +26,21 @@ class CClientDisplayManager friend class CClientDisplay; public: - CClientDisplayManager(); - ~CClientDisplayManager(); + CClientDisplayManager() = default; + ~CClientDisplayManager() = default; void DoPulse(); unsigned int Count() { return static_cast(m_List.size()); }; - CClientDisplay* Get(unsigned long ulID); + std::shared_ptr Get(unsigned long ulID); void DrawText2D(const char* szCaption, const CVector& vecPosition, float fScale = 1.0f, RGBA rgbaColor = 0xFFFFFFFF); - void RemoveAll(); + void AddToList(const std::shared_ptr& display); - void AddToList(CClientDisplay* pDisplay); - void RemoveFromList(CClientDisplay* pDisplay); + std::shared_ptr CreateVectorGraphicDisplay(CClientVectorGraphic* svg); + std::shared_ptr CreateTextDisplay(int ID = 0xFFFFFFFF); - std::list m_List; - bool m_bCanRemoveFromList; + std::list> m_List; }; + diff --git a/Client/mods/deathmatch/logic/CClientTextDisplay.cpp b/Client/mods/deathmatch/logic/CClientTextDisplay.cpp index 8b7962f5b0e..5ebc9a692ed 100644 --- a/Client/mods/deathmatch/logic/CClientTextDisplay.cpp +++ b/Client/mods/deathmatch/logic/CClientTextDisplay.cpp @@ -14,7 +14,7 @@ using std::list; float CClientTextDisplay::m_fGlobalScale = 1.0f; -CClientTextDisplay::CClientTextDisplay(CClientDisplayManager* pDisplayManager, int ID) : CClientDisplay(pDisplayManager, ID) +CClientTextDisplay::CClientTextDisplay(int ID) : CClientDisplay(ID) { // Init m_fScale = 1; @@ -22,10 +22,6 @@ CClientTextDisplay::CClientTextDisplay(CClientDisplayManager* pDisplayManager, i m_bVisible = true; } -CClientTextDisplay::~CClientTextDisplay() -{ -} - void CClientTextDisplay::SetCaption(const char* szCaption) { if (szCaption) diff --git a/Client/mods/deathmatch/logic/CClientTextDisplay.h b/Client/mods/deathmatch/logic/CClientTextDisplay.h index 74e0cd382ad..299c3f6c5e3 100644 --- a/Client/mods/deathmatch/logic/CClientTextDisplay.h +++ b/Client/mods/deathmatch/logic/CClientTextDisplay.h @@ -16,13 +16,11 @@ class CClientTextDisplay; #include "CClientDisplayManager.h" #include -class CClientTextDisplay : public CClientDisplay +class CClientTextDisplay final : public CClientDisplay { - friend class CClientDisplayManager; - public: - CClientTextDisplay(CClientDisplayManager* pDisplayManager, int ID = 0xFFFFFFFF); - ~CClientTextDisplay(); + CClientTextDisplay(int ID = 0xFFFFFFFF); + ~CClientTextDisplay() = default; eDisplayType GetType() { return DISPLAY_TEXT; } @@ -34,24 +32,24 @@ class CClientTextDisplay : public CClientDisplay void SetColorAlpha(unsigned char ucAlpha); void SetShadowAlpha(unsigned char ucShadowAlpha); - float GetScale() { return m_fScale; }; + float GetScale() const { return m_fScale; }; void SetScale(float fScale); - unsigned long GetFormat() { return m_ulFormat; }; + unsigned long GetFormat() const { return m_ulFormat; }; void SetFormat(unsigned long ulFormat); void SetVisible(bool bVisible); void Render(); - static void SetGlobalScale(float fScale) { m_fGlobalScale = fScale; } + static void SetGlobalScale(float fScale) { m_fGlobalScale = fScale; }; private: SString m_strCaption; float m_fScale; unsigned long m_ulFormat; - unsigned char m_ucShadowAlpha; + unsigned char m_ucShadowAlpha{}; static float m_fGlobalScale; }; diff --git a/Client/mods/deathmatch/logic/CClientVectorGraphic.cpp b/Client/mods/deathmatch/logic/CClientVectorGraphic.cpp index bb2f078b1a3..f2435adf810 100644 --- a/Client/mods/deathmatch/logic/CClientVectorGraphic.cpp +++ b/Client/mods/deathmatch/logic/CClientVectorGraphic.cpp @@ -17,8 +17,7 @@ CClientVectorGraphic::CClientVectorGraphic(CClientManager* pManager, ElementID I SetTypeName("svg"); m_pManager = pManager; - - m_pVectorGraphicDisplay = std::make_unique(m_pManager->GetDisplayManager(), this); + m_pVectorGraphicDisplay = m_pManager->GetDisplayManager()->CreateVectorGraphicDisplay(this); // Generate the default XML document SString defaultXmlString = SString("", pVectorGraphicItem->m_uiSizeX, pVectorGraphicItem->m_uiSizeY); @@ -46,7 +45,7 @@ bool CClientVectorGraphic::LoadFromString(std::string strData) bool CClientVectorGraphic::SetDocument(CXMLNode* node) { - if (!node || !node->IsValid()) + if (!m_pVectorGraphicDisplay || !node || !node->IsValid()) return false; if (m_pXMLString && m_pXMLString->node != node) @@ -80,11 +79,14 @@ bool CClientVectorGraphic::RemoveUpdateCallback() void CClientVectorGraphic::OnUpdate() { + if (!m_pVectorGraphicDisplay) + return; + m_pVectorGraphicDisplay->UpdateTexture(); if (std::holds_alternative(m_updateCallbackRef)) { - auto func = std::get(m_updateCallbackRef); + auto& func = std::get(m_updateCallbackRef); auto state = func.GetLuaVM(); if (VERIFY_FUNCTION(func) && state != NULL) diff --git a/Client/mods/deathmatch/logic/CClientVectorGraphic.h b/Client/mods/deathmatch/logic/CClientVectorGraphic.h index d1d0493a7f2..274191d39f1 100644 --- a/Client/mods/deathmatch/logic/CClientVectorGraphic.h +++ b/Client/mods/deathmatch/logic/CClientVectorGraphic.h @@ -57,7 +57,7 @@ class CClientVectorGraphic final : public CClientTexture std::unique_ptr m_pXMLString = nullptr; CXMLNode* m_pXMLDocument = nullptr; - std::unique_ptr m_pVectorGraphicDisplay; + std::shared_ptr m_pVectorGraphicDisplay; std::variant m_updateCallbackRef = false; diff --git a/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.cpp b/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.cpp index ce91d2882d6..ba495968c62 100644 --- a/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.cpp +++ b/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.cpp @@ -13,8 +13,8 @@ using namespace lunasvg; -CClientVectorGraphicDisplay::CClientVectorGraphicDisplay(CClientDisplayManager* pDisplayManager, CClientVectorGraphic* pVectorGraphic, int ID) - : CClientDisplay(pDisplayManager, ID) +CClientVectorGraphicDisplay::CClientVectorGraphicDisplay(CClientVectorGraphic* pVectorGraphic, int ID) + : CClientDisplay(ID) { m_pVectorGraphic = pVectorGraphic; m_bVisible = true; @@ -25,8 +25,11 @@ CClientVectorGraphicDisplay::CClientVectorGraphicDisplay(CClientDisplayManager* void CClientVectorGraphicDisplay::Render() { + // When the underlying vector graphic is deleted, this display will be destroyed automatically by the manager. + // CClientVectorGraphicDisplay::Render should be called as long as the display manager is still alive. + // see CClientDisplayManager::DoPulse if (!m_pVectorGraphic || m_pVectorGraphic->IsDestroyed()) - return; + return SetTimeTillExpiration(1); if (!m_bVisible) { diff --git a/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.h b/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.h index 40da0d46f27..dbff889da76 100644 --- a/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.h +++ b/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.h @@ -20,7 +20,7 @@ class CClientVectorGraphicDisplay final : public CClientDisplay friend class CClientDisplayManager; public: - CClientVectorGraphicDisplay(CClientDisplayManager* pDisplayManager, CClientVectorGraphic* pVectorGraphic, int ID = DISPLAY_VECTORGRAPHIC); + CClientVectorGraphicDisplay(CClientVectorGraphic* pVectorGraphic, int ID = DISPLAY_VECTORGRAPHIC); ~CClientVectorGraphicDisplay() = default; eDisplayType GetType() { return DISPLAY_VECTORGRAPHIC; } @@ -38,7 +38,6 @@ class CClientVectorGraphicDisplay final : public CClientDisplay private: void UnpremultiplyBitmap(lunasvg::Bitmap& bitmap); -private: CClientVectorGraphic* m_pVectorGraphic; bool m_bIsCleared; diff --git a/Client/mods/deathmatch/logic/CPacketHandler.cpp b/Client/mods/deathmatch/logic/CPacketHandler.cpp index 094812d816b..ad5d7cfb4e4 100644 --- a/Client/mods/deathmatch/logic/CPacketHandler.cpp +++ b/Client/mods/deathmatch/logic/CPacketHandler.cpp @@ -4496,10 +4496,11 @@ void CPacketHandler::Packet_TextItem(NetBitStreamInterface& bitStream) if (bDelete) { // Grab it and delete it - CClientDisplay* pDisplay = g_pClientGame->m_pDisplayManager->Get(ulID); + std::shared_ptr pDisplay = g_pClientGame->m_pDisplayManager->Get(ulID); + if (pDisplay) { - delete pDisplay; + m_displayTextList.remove(std::static_pointer_cast(pDisplay)); } } else @@ -4535,26 +4536,28 @@ void CPacketHandler::Packet_TextItem(NetBitStreamInterface& bitStream) } // Does the text not already exist? Create it - CClientTextDisplay* pTextDisplay = NULL; - CClientDisplay* pDisplay = g_pClientGame->m_pDisplayManager->Get(ulID); - if (pDisplay && pDisplay->GetType() == DISPLAY_TEXT) + std::shared_ptr textDisplay = nullptr; + std::shared_ptr display = g_pClientGame->m_pDisplayManager->Get(ulID); + + if (display && display->GetType() == DISPLAY_TEXT) { - pTextDisplay = static_cast(pDisplay); + textDisplay = std::static_pointer_cast(display); } - if (!pTextDisplay) + if (!textDisplay) { // Create it - pTextDisplay = new CClientTextDisplay(g_pClientGame->m_pDisplayManager, ulID); + textDisplay = g_pClientGame->m_pDisplayManager->CreateTextDisplay(ulID); + m_displayTextList.push_back(textDisplay); } // Set the text properties - pTextDisplay->SetCaption(szText); - pTextDisplay->SetPosition(CVector(fX, fY, 0)); - pTextDisplay->SetColor(color); - pTextDisplay->SetScale(fScale); - pTextDisplay->SetFormat((unsigned long)ucFormat); - pTextDisplay->SetShadowAlpha(ucShadowAlpha); + textDisplay->SetCaption(szText); + textDisplay->SetPosition(CVector(fX, fY, 0)); + textDisplay->SetColor(color); + textDisplay->SetScale(fScale); + textDisplay->SetFormat((unsigned long)ucFormat); + textDisplay->SetShadowAlpha(ucShadowAlpha); delete[] szText; } diff --git a/Client/mods/deathmatch/logic/CPacketHandler.h b/Client/mods/deathmatch/logic/CPacketHandler.h index 9a50b246156..8a370774b58 100644 --- a/Client/mods/deathmatch/logic/CPacketHandler.h +++ b/Client/mods/deathmatch/logic/CPacketHandler.h @@ -16,6 +16,7 @@ class CClientEntity; class CCustomData; +class CClientTextDisplay; class CPacketHandler { @@ -112,4 +113,6 @@ class CPacketHandler std::vector m_EntityAddReadOffsetStore; NetBitStreamInterface* m_pEntityAddBitStream; uint m_uiEntityAddNumEntities; + + std::list> m_displayTextList; }; diff --git a/Client/mods/deathmatch/logic/CPlayerMap.cpp b/Client/mods/deathmatch/logic/CPlayerMap.cpp index de1529972a5..332ef0282ed 100644 --- a/Client/mods/deathmatch/logic/CPlayerMap.cpp +++ b/Client/mods/deathmatch/logic/CPlayerMap.cpp @@ -87,7 +87,7 @@ CPlayerMap::CPlayerMap(CClientManager* pManager) for (uint i = 0; i < NUMELMS(messageList); i++) { - CClientTextDisplay* pTextDisplay = new CClientTextDisplay(m_pManager->GetDisplayManager()); + auto pTextDisplay = m_pManager->GetDisplayManager()->CreateTextDisplay(); pTextDisplay->SetCaption(messageList[i].strMessage); pTextDisplay->SetColor(messageList[i].color); pTextDisplay->SetPosition(CVector(0.50f, messageList[i].fPosY, 0)); @@ -112,8 +112,7 @@ CPlayerMap::~CPlayerMap() for (uint i = 0; i < m_markerTextureList.size(); i++) SAFE_RELEASE(m_markerTextureList[i]); m_markerTextureList.clear(); - - // Don't need to delete the help texts as those are destroyed by the display manager + m_HelpTextList.clear(); } void CPlayerMap::CreateOrUpdateMapTexture() diff --git a/Client/mods/deathmatch/logic/CPlayerMap.h b/Client/mods/deathmatch/logic/CPlayerMap.h index 0d6edebb6f2..04022ce3ce6 100644 --- a/Client/mods/deathmatch/logic/CPlayerMap.h +++ b/Client/mods/deathmatch/logic/CPlayerMap.h @@ -116,7 +116,7 @@ class CPlayerMap unsigned long m_ulUpdateTime; - std::vector m_HelpTextList; + std::vector> m_HelpTextList; bool m_bHideHelpText; bool m_bHudVisible;