Skip to content

Commit 4a2a4fe

Browse files
committed
Resolve CLocalization / CGUI memory leaks
1 parent 0f49768 commit 4a2a4fe

File tree

6 files changed

+71
-32
lines changed

6 files changed

+71
-32
lines changed

Client/core/CGUI.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ void CLocalGUI::ChangeLocale(const char* szName)
134134

135135
m_LastLocaleName = strCanonicalLocale;
136136

137+
// Attempt CEGUI cleanup
138+
if (CGUI* pGUI = CCore::GetSingleton().GetGUI())
139+
pGUI->Cleanup();
140+
137141
if (guiWasLoaded)
138142
{
139143
CreateWindows(guiWasLoaded);

Client/core/CLocalization.cpp

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,7 @@ CLocalization::CLocalization(const SString& strLocale, const SString& strLocaleP
4141

4242
CLocalization::~CLocalization()
4343
{
44-
for (auto iter : m_LanguageMap)
45-
{
46-
delete iter.second;
47-
}
44+
// m_LanguageMap now uses unique_ptr so cleanup is automatic
4845
}
4946

5047
//
@@ -99,29 +96,32 @@ void CLocalization::SetCurrentLanguage(SString strLocale)
9996
CLanguage* CLocalization::GetLanguage(SString strLocale)
10097
{
10198
strLocale = ValidateLocale(strLocale);
102-
CLanguage* pLanguage = MapFindRef(m_LanguageMap, strLocale);
103-
if (!pLanguage)
99+
auto iter = m_LanguageMap.find(strLocale);
100+
if (iter != m_LanguageMap.end())
101+
{
102+
return iter->second.get();
103+
}
104+
105+
Language Lang = Language::from_name(strLocale);
106+
Lang = Lang ? Lang : Language::from_name("en_US");
107+
108+
try
109+
{
110+
std::unique_ptr<CLanguage> pLanguage = std::make_unique<CLanguage>(m_DictManager.get_dictionary(Lang, MTA_LOCALE_TEXTDOMAIN), Lang.str(), Lang.get_name());
111+
CLanguage* pLanguagePtr = pLanguage.get();
112+
m_LanguageMap.emplace(strLocale, std::move(pLanguage));
113+
return pLanguagePtr;
114+
}
115+
catch (const std::exception& ex)
116+
{
117+
WriteDebugEvent(SString("Localization failed to load dictionary for '%s': %s", strLocale.c_str(), ex.what()));
118+
return (strLocale != "en_US") ? GetLanguage("en_US") : nullptr;
119+
}
120+
catch (...)
104121
{
105-
Language Lang = Language::from_name(strLocale);
106-
Lang = Lang ? Lang : Language::from_name("en_US");
107-
108-
try
109-
{
110-
pLanguage = new CLanguage(m_DictManager.get_dictionary(Lang, MTA_LOCALE_TEXTDOMAIN), Lang.str(), Lang.get_name());
111-
MapSet(m_LanguageMap, strLocale, pLanguage);
112-
}
113-
catch (const std::exception& ex)
114-
{
115-
WriteDebugEvent(SString("Localization failed to load dictionary for '%s': %s", strLocale.c_str(), ex.what()));
116-
return (strLocale != "en_US") ? GetLanguage("en_US") : nullptr;
117-
}
118-
catch (...)
119-
{
120-
WriteDebugEvent(SString("Localization failed to load dictionary for '%s': unknown error", strLocale.c_str()));
121-
return (strLocale != "en_US") ? GetLanguage("en_US") : nullptr;
122-
}
122+
WriteDebugEvent(SString("Localization failed to load dictionary for '%s': unknown error", strLocale.c_str()));
123+
return (strLocale != "en_US") ? GetLanguage("en_US") : nullptr;
123124
}
124-
return pLanguage;
125125
}
126126

127127
//

Client/core/CLocalization.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ using namespace tinygettext;
1313

1414
#include <core/CLocalizationInterface.h>
1515
#include "CLanguage.h"
16-
#define MTA_LOCALE_DIR "MTA/locale/"
16+
#define MTA_LOCALE_DIR "MTA/locale/"
1717

1818
#pragma once
1919

@@ -42,7 +42,7 @@ class CLocalization : public CLocalizationInterface
4242
static void LogCallback(const std::string& str);
4343

4444
private:
45-
DictionaryManager m_DictManager;
46-
std::map<SString, CLanguage*> m_LanguageMap;
47-
CLanguage* m_pCurrentLang{};
45+
DictionaryManager m_DictManager;
46+
std::map<SString, std::unique_ptr<CLanguage>> m_LanguageMap;
47+
CLanguage* m_pCurrentLang{};
4848
};

Client/gui/CGUI_Impl.cpp

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,17 @@ CGUI_Impl::~CGUI_Impl()
144144
// DO NOT delete m_pRenderer - it's already deleted by System destructor
145145
}
146146

147+
void CGUI_Impl::CreateRootWindow()
148+
{
149+
// Create dummy GUI root
150+
m_pTop = reinterpret_cast<CEGUI::DefaultWindow*>(m_pWindowManager->createWindow("DefaultWindow", "guiroot"));
151+
m_pSystem->setGUISheet(m_pTop);
152+
}
153+
147154
void CGUI_Impl::SetSkin(const char* szName)
148155
{
156+
m_currentSkin = szName;
157+
149158
if (m_HasSchemeLoaded)
150159
{
151160
CEGUI::GlobalEventSet::getSingletonPtr()->removeAllEvents();
@@ -165,9 +174,8 @@ void CGUI_Impl::SetSkin(const char* szName)
165174
// Destroy any windows we already have
166175
CEGUI::WindowManager::getSingleton().destroyAllWindows();
167176

168-
// Create dummy GUI root
169-
m_pTop = reinterpret_cast<CEGUI::DefaultWindow*>(m_pWindowManager->createWindow("DefaultWindow", "guiroot"));
170-
m_pSystem->setGUISheet(m_pTop);
177+
// Clean up CEGUI - this also re-creates the root window
178+
Cleanup();
171179

172180
// Disable single click timeouts
173181
m_pSystem->setSingleClickTimeout(100000000.0f);
@@ -1797,3 +1805,22 @@ CEGUI::Window* CGUI_Impl::GetMasterWindow(CEGUI::Window* wnd)
17971805
}
17981806
return wnd;
17991807
}
1808+
1809+
void CGUI_Impl::Cleanup()
1810+
{
1811+
try
1812+
{
1813+
CleanDeadPool();
1814+
1815+
if (m_pWindowManager)
1816+
m_pWindowManager->destroyAllWindows();
1817+
1818+
// Clear redraw structures that may reference old elements
1819+
m_RedrawQueue.clear();
1820+
m_RedrawRegistry.clear();
1821+
1822+
// Recreate the root window (destroyed above via destroyAllWindows)
1823+
CreateRootWindow();
1824+
}
1825+
catch (...) {}
1826+
}

Client/gui/CGUI_Impl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,9 @@ class CGUI_Impl : public CGUI, public CGUITabList
283283
CGUIWindow* LoadLayout(CGUIElement* pParent, const SString& strFilename);
284284
bool LoadImageset(const SString& strFilename);
285285

286+
// Cleanup CEGUI active resources (dead pool)
287+
void Cleanup();
288+
286289
private:
287290
friend class CGUIElement_Impl;
288291
CGUIButton* _CreateButton(CGUIElement_Impl* pParent = NULL, const char* szCaption = "");
@@ -361,4 +364,7 @@ class CGUI_Impl : public CGUI, public CGUITabList
361364
bool m_HasSchemeLoaded;
362365
SString m_CurrentSchemeName;
363366
CElapsedTime m_RenderOkTimer;
367+
const char* m_currentSkin;
368+
369+
void CreateRootWindow();
364370
};

Client/sdk/gui/CGUI.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,6 @@ class CGUI
170170

171171
virtual CGUIWindow* LoadLayout(CGUIElement* pParent, const SString& strFilename) = 0;
172172
virtual bool LoadImageset(const SString& strFilename) = 0;
173+
174+
virtual void Cleanup() = 0;
173175
};

0 commit comments

Comments
 (0)