Fix crash on global or scenario script reload.

The string table of System.ocg scripts (except the global System.ocg) pointed to nowhere after the initial load phase, but is still required for reload. Added a ref counting option to keep these string tables alive.
lights3
Sven Eberhardt 2015-08-20 13:14:34 -04:00
parent 0d102d2184
commit 5ec9999d4c
4 changed files with 29 additions and 7 deletions

View File

@ -23,7 +23,7 @@
#include "C4LangStringTable.h"
#include "C4InputValidation.h"
C4LangStringTable::C4LangStringTable() {}
C4LangStringTable::C4LangStringTable() : ref_count(1) {}
bool C4LangStringTable::HasTranslation(const std::string &text) const
{

View File

@ -30,6 +30,7 @@ class C4LangStringTable : public C4ComponentHost
typedef std::map<std::string, std::string> Table;
mutable Table strings;
void PopulateStringTable() const;
int32_t ref_count; // ref counter initialized to 1 on ctor; delete when zero is reached
public:
C4LangStringTable();
const std::string &Translate(const std::string &text) const;
@ -39,6 +40,9 @@ public:
void ReplaceStrings(StdStrBuf &rBuf);
void ReplaceStrings(const StdStrBuf &rBuf, StdStrBuf &rTarget);
void AddRef() { ++ref_count; }
void DelRef() { if (!--ref_count) delete this; }
class NoSuchTranslation : public std::runtime_error
{
public:

View File

@ -2827,14 +2827,14 @@ bool C4Game::LoadAdditionalSystemGroup(C4Group &parent_group)
char fn[_MAX_FNAME+1] = { 0 };
if (SysGroup.OpenAsChild(&parent_group, C4CFN_System))
{
C4LangStringTable SysGroupString;
C4Language::LoadComponentHost(&SysGroupString, SysGroup, C4CFN_ScriptStringTbl, Config.General.LanguageEx);
C4LangStringTable *pSysGroupString = new C4LangStringTable();
C4Language::LoadComponentHost(pSysGroupString, SysGroup, C4CFN_ScriptStringTbl, Config.General.LanguageEx);
// load custom scenario control definitions
if (SysGroup.FindEntry(C4CFN_PlayerControls))
{
Log("[!]Loading local scenario player control definitions...");
C4PlayerControlFile PlayerControlFile;
if (!PlayerControlFile.Load(SysGroup, C4CFN_PlayerControls, &SysGroupString))
if (!PlayerControlFile.Load(SysGroup, C4CFN_PlayerControls, pSysGroupString))
{
// non-fatal error here
Log("[!]Error loading scenario defined player controls");
@ -2854,12 +2854,14 @@ bool C4Game::LoadAdditionalSystemGroup(C4Group &parent_group)
// host will be destroyed by script engine, so drop the references
C4ScriptHost *scr = new C4ExtraScriptHost();
scr->Reg2List(&ScriptEngine);
scr->Load(SysGroup, fn, Config.General.LanguageEx, &SysGroupString);
scr->Load(SysGroup, fn, Config.General.LanguageEx, pSysGroupString);
}
// if it's a physical group: watch out for changes
if (!SysGroup.IsPacked() && Game.pFileMonitor)
Game.pFileMonitor->AddDirectory(SysGroup.GetFullName().getData());
SysGroup.Close();
// release string table if no longer used
pSysGroupString->DelRef();
}
return true;
}

View File

@ -51,6 +51,11 @@ void C4ScriptHost::Clear()
LocalValues.Clear();
SourceScripts.clear();
SourceScripts.push_back(this);
if (stringTable)
{
stringTable->DelRef();
stringTable = NULL;
}
// remove includes
Includes.clear();
Appends.clear();
@ -62,7 +67,12 @@ bool C4ScriptHost::Load(C4Group &hGroup, const char *szFilename,
// Base load
bool fSuccess = ComponentHost.Load(hGroup,szFilename,szLanguage);
// String Table
stringTable = pLocalTable;
if (stringTable != pLocalTable)
{
if (stringTable) stringTable->DelRef();
stringTable = pLocalTable;
if (stringTable) stringTable->AddRef();
}
// set name
ScriptName.Ref(ComponentHost.GetFilePath());
// preparse script
@ -73,7 +83,13 @@ bool C4ScriptHost::Load(C4Group &hGroup, const char *szFilename,
bool C4ScriptHost::LoadData(const char *szFilename, const char *szData, class C4LangStringTable *pLocalTable)
{
stringTable = pLocalTable;
// String Table
if (stringTable != pLocalTable)
{
if (stringTable) stringTable->DelRef();
stringTable = pLocalTable;
if (stringTable) stringTable->AddRef();
}
ScriptName.Copy(szFilename);
StdStrBuf tempScript;