Rework prop list renumbering on section load (again).

Turns out changing prop list numbers while they are still indexed by number in the hash map was a bad idea. Existing prop lists are now de-numbered, pushed to an external shelve and re-numbered when added after section load.
stable-5.4
Sven Eberhardt 2013-12-15 15:46:18 +01:00
parent 1cca6fd1ad
commit 25ddb14dca
6 changed files with 45 additions and 24 deletions

View File

@ -36,6 +36,7 @@
C4Set<C4PropList *> C4PropList::PropLists;
#endif
C4Set<C4PropListNumbered *> C4PropListNumbered::PropLists;
std::vector<C4PropListNumbered *> C4PropListNumbered::ShelvedPropLists;
int32_t C4PropListNumbered::EnumerationIndex = 0;
C4StringTable Strings;
C4AulScriptEngine ScriptEngine;

View File

@ -617,6 +617,7 @@ void C4Game::Clear()
::FontLoader.Clear();
#endif
C4PropListNumbered::ClearShelve(); // may be nonempty if there was a fatal error during section load
ScriptEngine.Clear();
MainSysLangStringTable.Clear();
ScenarioLangStringTable.Clear();
@ -1635,7 +1636,7 @@ void C4Game::CompileFunc(StdCompiler *pComp, CompileSettings comp, C4ValueNumber
// Section load: Clear existing prop list numbering to make room for the new objects
// Numbers will be re-acquired in C4GameObjects::PostLoad
if (comp.fScenarioSection) C4PropListNumbered::ClearAllProplistNumbers();
if (comp.fScenarioSection) C4PropListNumbered::ShelveNumberedPropLists();
pComp->Value(mkParAdapt(Objects, !comp.fExact, numbers));
@ -3330,6 +3331,8 @@ bool C4Game::LoadScenarioSection(const char *szSection, DWORD dwFlags)
DebugLog("LoadScenarioSection: Error reiniting game");
return false;
}
// restore shelved proplists in case loading failed
C4PropListNumbered::UnshelveNumberedPropLists();
// set new current section
pCurrentScenarioSection = pLoadSect;
SCopy(pCurrentScenarioSection->szName, CurrentScenarioSection);

View File

@ -234,7 +234,6 @@ int C4GameObjects::PostLoad(bool fKeepInactive, C4ValueNumbers * numbers)
// Process objects
C4ObjectLink *cLnk;
C4Object *pObj;
bool fObjectNumberCollision = false;
int32_t iMaxObjectNumber = 0;
for (cLnk = Last; cLnk; cLnk = cLnk->Prev)
{
@ -262,7 +261,7 @@ int C4GameObjects::PostLoad(bool fKeepInactive, C4ValueNumbers * numbers)
if (fKeepInactive)
{
InactiveObjects.First=pInFirst;
C4PropListNumbered::AcquireAllProplistNumbers();
C4PropListNumbered::UnshelveNumberedPropLists();
}
// special checks:

View File

@ -108,45 +108,60 @@ void C4PropListNumbered::ResetEnumerationIndex()
EnumerationIndex = 0;
}
void C4PropListNumbered::ClearAllProplistNumbers()
void C4PropListNumbered::ShelveNumberedPropLists()
{
// unnumber all proplists. To be used on remaining objects before a savegame load.
C4PropListNumbered *const* p = PropLists.First();
while (p)
// unnumber all proplists and put them on the shelve. To be used on remaining objects before a savegame load.
assert(ShelvedPropLists.empty());
ShelvedPropLists.reserve(PropLists.GetSize());
C4PropListNumbered *const* p_next = PropLists.First(), *const* p;
while ((p = p_next))
{
(*p)->ClearNumber();
p = PropLists.Next(p);
p_next = PropLists.Next(p);
C4PropListNumbered *pl = *p;
if (pl->Number != -1)
{
pl->ClearNumber();
ShelvedPropLists.push_back(pl);
}
}
}
void C4PropListNumbered::AcquireAllProplistNumbers()
void C4PropListNumbered::UnshelveNumberedPropLists()
{
C4PropListNumbered *const* p = PropLists.First();
while (p)
{
if (!(*p)->Number) (*p)->AcquireNumber(true);
p = PropLists.Next(p);
}
// re-insert shelved proplists into main list and give them a number
for (std::vector<C4PropListNumbered *>::iterator i=ShelvedPropLists.begin(); i!=ShelvedPropLists.end(); ++i)
(*i)->AcquireNumber();
ShelvedPropLists.clear();
}
void C4PropListNumbered::ClearShelve()
{
// cleanup shelve - used in game clear, un unsuccessful section load, etc.
ShelvedPropLists.clear();
}
C4PropListNumbered::C4PropListNumbered(C4PropList * prototype): C4PropList(prototype), Number(-1)
{
}
void C4PropListNumbered::AcquireNumber(bool check_double_add)
void C4PropListNumbered::AcquireNumber()
{
// Enumerate object
do
Number = ++EnumerationIndex;
while (PropLists.Get(Number));
// Add to list (unless it's already in there)
if (!check_double_add || !C4PropListNumbered::CheckPropList(this)) PropLists.Add(this);
// Add to list
PropLists.Add(this);
}
void C4PropListNumbered::ClearNumber()
{
// Make proplist invisible during denumeration process
Number = 0;
if (Number != -1)
{
PropLists.Remove(this);
Number = -1;
}
}
C4PropListNumbered* C4PropListNumbered::GetPropListNumbered()

View File

@ -177,14 +177,16 @@ public:
static void SetEnumerationIndex(int32_t iMaxObjectNumber);
static int32_t GetEnumerationIndex() { return EnumerationIndex; }
static void ResetEnumerationIndex();
static void ClearAllProplistNumbers(); // unnumber all proplists. To be used on remaining objects before a savegame load.
static void AcquireAllProplistNumbers(); // acquire a number on all proplists that are currently unnumbered
static void ShelveNumberedPropLists(); // unnumber all proplists and put them on the shelve. To be used on remaining objects before a savegame load.
static void UnshelveNumberedPropLists(); // re-insert shelved proplists into main list
static void ClearShelve();
protected:
C4PropListNumbered(C4PropList * prototype = 0);
void AcquireNumber(bool check_double_add=false); // acquire a number and add to internal list. if check_double_add is set, check if the proplist is already in the list before
void ClearNumber();
void AcquireNumber(); // acquire a number and add to internal list
void ClearNumber(); // clear number and remove from internal list
static C4Set<C4PropListNumbered *> PropLists;
static std::vector<C4PropListNumbered *> ShelvedPropLists; // temporary storage for existing proplists while a new section loaded
static int32_t EnumerationIndex;
friend class C4Game;
friend class C4GameObjects;

View File

@ -36,6 +36,7 @@
C4Set<C4PropList *> C4PropList::PropLists;
#endif
C4Set<C4PropListNumbered *> C4PropListNumbered::PropLists;
std::vector<C4PropListNumbered *> C4PropListNumbered::ShelvedPropLists;
int32_t C4PropListNumbered::EnumerationIndex = 0;
C4StringTable Strings;
C4AulScriptEngine ScriptEngine;