forked from Mirrors/openclonk
Savegames: (De)serialize PropLists
Because PropLists have an identity, they need to be saved in a central place and have C4Values reference them, the same as objects. Objects.txt can be used for that. This doesn't save PropLists which are definitions. These are reloaded from the c4ds at game start and identified by their C4ID, not their number.stable-5.1
parent
7c118604c4
commit
5d2c3d4c2b
|
@ -58,6 +58,115 @@ void C4GameObjects::Init(int32_t iWidth, int32_t iHeight)
|
|||
Sectors.Init(iWidth, iHeight);
|
||||
}
|
||||
|
||||
|
||||
void C4GameObjects::CompileFunc(StdCompiler *pComp, bool fSkipPlayerObjects)
|
||||
{
|
||||
// "Object" section count
|
||||
int32_t iObjCnt = ObjectCount();
|
||||
pComp->Value(mkNamingCountAdapt(iObjCnt, "Object"));
|
||||
// "Def" section count
|
||||
//int32_t iDefCnt = ::Definitions.GetDefCount();
|
||||
//pComp->Value(mkNamingCountAdapt(iDefCnt, "Def"));
|
||||
// "PropList" section count
|
||||
int32_t iPropListCnt = PropLists.GetSize() - iObjCnt /*- iDefCnt*/;
|
||||
pComp->Value(mkNamingCountAdapt(iPropListCnt, "PropList"));
|
||||
// skipping player objects would screw object counting in non-naming compilers
|
||||
assert(!fSkipPlayerObjects || pComp->hasNaming());
|
||||
if(pComp->isDecompiler())
|
||||
{
|
||||
// Decompile all objects in reverse order
|
||||
for(C4ObjectLink *pPos = Last; pPos; pPos = pPos->Prev)
|
||||
if (pPos->Obj->Status)
|
||||
if (!fSkipPlayerObjects || !pPos->Obj->IsUserPlayerObject())
|
||||
pComp->Value(mkNamingAdapt(*pPos->Obj, "Object"));
|
||||
/*for(C4PropList * const * ppPropList = PropLists.First(); ppPropList; ppPropList = PropLists.Next(ppPropList))
|
||||
if (dynamic_cast<C4Def *>(*ppPropList))
|
||||
{
|
||||
pComp->Name("Def");
|
||||
pComp->Value(mkNamingAdapt(mkC4IDAdapt(dynamic_cast<C4Def *>(*ppPropList)->id), "id", C4ID_None));
|
||||
pComp->Value(mkNamingAdapt((*ppPropList)->Number, "Number", -1));
|
||||
pComp->NameEnd();
|
||||
}*/
|
||||
for(C4PropListNumbered * const * ppPropList = PropLists.First(); ppPropList; ppPropList = PropLists.Next(ppPropList))
|
||||
if (!dynamic_cast<C4Object *>(*ppPropList) && !dynamic_cast<C4Def *>(*ppPropList))
|
||||
{
|
||||
pComp->Value(mkNamingAdapt(**ppPropList, "PropList"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this mode not supported
|
||||
assert(!fSkipPlayerObjects);
|
||||
// Remove previous data
|
||||
Clear();
|
||||
//assert(PropLists.GetSize() == ::Definitions.GetDefCount());
|
||||
// Load objects, add them to the list.
|
||||
for(int i = 0; i < iObjCnt; i++)
|
||||
{
|
||||
C4Object *pObj = NULL;
|
||||
try
|
||||
{
|
||||
pComp->Value(mkNamingAdapt(mkPtrAdaptNoNull(pObj), "Object"));
|
||||
C4ObjectList::Add(pObj, stReverse);
|
||||
}
|
||||
catch (StdCompiler::Exception *pExc)
|
||||
{
|
||||
// Failsafe object loading: If an error occurs during object loading, just skip that object and load the next one
|
||||
if(!pExc->Pos.getLength())
|
||||
LogF("ERROR: Object loading: %s", pExc->Msg.getData());
|
||||
else
|
||||
LogF("ERROR: Object loading(%s): %s", pExc->Pos.getData(), pExc->Msg.getData());
|
||||
delete pExc;
|
||||
}
|
||||
}
|
||||
// Load object numbers of the definitions
|
||||
/*for(int i = 0; i < iDefCnt; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
pComp->Name("Def");
|
||||
C4ID id;
|
||||
pComp->Value(mkNamingAdapt(mkC4IDAdapt(id), "id", C4ID_None));
|
||||
C4Def * pDef = ::Definitions.ID2Def(id);
|
||||
if (!pDef)
|
||||
{ pComp->excNotFound(LoadResStr("IDS_PRC_UNDEFINEDOBJECT"),C4IdText(id)); continue; }
|
||||
PropLists.Remove(static_cast<C4PropList *>(pDef));
|
||||
pComp->Value(mkNamingAdapt(pDef->Number, "Number", -1));
|
||||
PropLists.Add(static_cast<C4PropList *>(pDef));
|
||||
}
|
||||
catch (StdCompiler::Exception *pExc)
|
||||
{
|
||||
// Failsafe object loading: If an error occurs during object loading, just skip that object and load the next one
|
||||
if(!pExc->Pos.getLength())
|
||||
LogF("ERROR: Definition loading: %s", pExc->Msg.getData());
|
||||
else
|
||||
LogF("ERROR: Definition loading(%s): %s", pExc->Pos.getData(), pExc->Msg.getData());
|
||||
delete pExc;
|
||||
pComp->NameEnd(true);
|
||||
}
|
||||
pComp->NameEnd();
|
||||
}*/
|
||||
// Load proplists
|
||||
for(int i = 0; i < iPropListCnt; i++)
|
||||
{
|
||||
C4PropListNumbered *pPropList = NULL;
|
||||
try
|
||||
{
|
||||
pComp->Value(mkNamingAdapt(mkPtrAdaptNoNull(pPropList), "PropList"));
|
||||
}
|
||||
catch (StdCompiler::Exception *pExc)
|
||||
{
|
||||
// Failsafe object loading: If an error occurs during object loading, just skip that object and load the next one
|
||||
if(!pExc->Pos.getLength())
|
||||
LogF("ERROR: PropList loading: %s", pExc->Msg.getData());
|
||||
else
|
||||
LogF("ERROR: PropList loading(%s): %s", pExc->Pos.getData(), pExc->Msg.getData());
|
||||
delete pExc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool C4GameObjects::Add(C4Object *nObj)
|
||||
{
|
||||
// add inactive objects to the inactive list only
|
||||
|
@ -289,13 +398,22 @@ C4Object *C4GameObjects::ObjectPointer(int32_t iNumber)
|
|||
return 0;
|
||||
}
|
||||
|
||||
C4PropList *C4GameObjects::PropListPointer(int32_t iNumber)
|
||||
{
|
||||
return PropLists.Get(iNumber);
|
||||
}
|
||||
|
||||
int32_t C4GameObjects::ObjectNumber(C4PropList *pObj)
|
||||
{
|
||||
if(!pObj) return 0;
|
||||
C4PropList * const * p = PropLists.First();
|
||||
C4PropListNumbered * const * p = PropLists.First();
|
||||
while (p)
|
||||
{
|
||||
if(*p == pObj) return (*p)->Number;
|
||||
if(*p == pObj)
|
||||
{
|
||||
if ((*p)->GetPropListNumbered()) return (*p)->GetPropListNumbered()->Number;
|
||||
return 0;
|
||||
}
|
||||
p = PropLists.Next(p);
|
||||
}
|
||||
return 0;
|
||||
|
@ -621,7 +739,8 @@ int C4GameObjects::Load(C4Group &hGroup, bool fKeepInactive)
|
|||
C4ObjectLink *pInFirst = NULL;
|
||||
if (fObjectNumberCollision) { pInFirst = InactiveObjects.First; InactiveObjects.First = NULL; }
|
||||
// denumerate pointers
|
||||
Denumerate();
|
||||
for (C4PropListNumbered * const * ppPropList = PropLists.First(); ppPropList; ppPropList = PropLists.Next(ppPropList))
|
||||
(*ppPropList)->DenumeratePointers();
|
||||
// update object enumeration index now, because calls like UpdateTransferZone might create objects
|
||||
Game.ObjectEnumerationIndex = Max(Game.ObjectEnumerationIndex, iMaxObjectNumber);
|
||||
// end faking and adjust object numbers
|
||||
|
@ -716,6 +835,8 @@ int C4GameObjects::Load(C4Group &hGroup, bool fKeepInactive)
|
|||
// update flipdir (for old objects.txt with no flipdir defined)
|
||||
// assigns Action.DrawDir as well
|
||||
pObj->UpdateFlipDir();
|
||||
// initial OCF update
|
||||
pObj->SetOCF();
|
||||
}
|
||||
// Done
|
||||
return ObjectCount();
|
||||
|
@ -741,7 +862,7 @@ bool C4GameObjects::Save(const char *szFilename, bool fSaveGame, bool fSaveInact
|
|||
|
||||
// Decompile objects to buffer
|
||||
StdStrBuf Buffer;
|
||||
bool fSuccess = DecompileToBuf_Log<StdCompilerINIWrite>(mkParAdapt(*this, false, !fSaveGame), &Buffer, szFilename);
|
||||
bool fSuccess = DecompileToBuf_Log<StdCompilerINIWrite>(mkParAdapt(*this, !fSaveGame), &Buffer, szFilename);
|
||||
|
||||
// Decompile inactives
|
||||
if(fSaveInactive)
|
||||
|
|
|
@ -37,6 +37,7 @@ class C4GameObjects : public C4NotifyingObjectList
|
|||
void Init(int32_t iWidth, int32_t iHeight);
|
||||
void Clear(bool fClearInactive); // clear objects
|
||||
void Clear() { Clear(true); } // don't use default parameters so we get a correct vtbl entry
|
||||
void CompileFunc(StdCompiler *pComp, bool fSkipPlayerObjects = false);
|
||||
|
||||
public:
|
||||
C4LSectors Sectors; // section object lists
|
||||
|
@ -59,6 +60,7 @@ class C4GameObjects : public C4NotifyingObjectList
|
|||
|
||||
C4Object *FindInternal(C4ID id); // find object in first sector
|
||||
virtual C4Object *ObjectPointer(int32_t iNumber); // object pointer by number
|
||||
virtual C4PropList *PropListPointer(int32_t iNumber); // object pointer by number
|
||||
int32_t ObjectNumber(C4PropList *pObj); // object number by pointer
|
||||
C4Object* SafeObjectPointer(int32_t iNumber);
|
||||
C4Object* Denumerated(C4Object *pObj);
|
||||
|
@ -96,8 +98,8 @@ class C4GameObjects : public C4NotifyingObjectList
|
|||
void UpdateTransferZones();
|
||||
void SetOCF();
|
||||
protected:
|
||||
C4Set<C4PropList *> PropLists;
|
||||
friend class C4PropList;
|
||||
C4Set<C4PropListNumbered *> PropLists;
|
||||
friend class C4PropListNumbered;
|
||||
};
|
||||
|
||||
extern C4GameObjects Objects;
|
||||
|
|
|
@ -162,6 +162,7 @@ bool C4Object::Init(C4PropList *pDef, C4Object *pCreator,
|
|||
int32_t nx, int32_t ny, int32_t nr,
|
||||
FIXED nxdir, FIXED nydir, FIXED nrdir, int32_t iController)
|
||||
{
|
||||
C4PropListNumbered::AcquireNumber();
|
||||
// currently initializing
|
||||
Initializing=true;
|
||||
|
||||
|
@ -2643,7 +2644,6 @@ void C4Object::CompileFunc(StdCompiler *pComp)
|
|||
if(fCompiler)
|
||||
{
|
||||
Def = ::Definitions.ID2Def(id);
|
||||
SetProperty(Strings.P[P_Prototype], C4VPropList(Def));
|
||||
if(!Def)
|
||||
{ pComp->excNotFound(LoadResStr("IDS_PRC_UNDEFINEDOBJECT"),id.ToString()); return; }
|
||||
}
|
||||
|
@ -2656,8 +2656,7 @@ void C4Object::CompileFunc(StdCompiler *pComp)
|
|||
// Write the name only if the object has an individual name
|
||||
// 2do: And what about binary compilers?
|
||||
pComp->Value(mkNamingAdapt(Name, "Name"));*/
|
||||
|
||||
pComp->Value(mkNamingAdapt( Number, "Number", -1 ));
|
||||
C4PropListNumbered::CompileFunc(pComp);
|
||||
pComp->Value(mkNamingAdapt( Status, "Status", 1 ));
|
||||
pComp->Value(mkNamingAdapt( toC4CStrBuf(nInfo), "Info", "" ));
|
||||
pComp->Value(mkNamingAdapt( Owner, "Owner", NO_OWNER ));
|
||||
|
@ -2665,13 +2664,6 @@ void C4Object::CompileFunc(StdCompiler *pComp)
|
|||
pComp->Value(mkNamingAdapt( Controller, "Controller", NO_OWNER ));
|
||||
pComp->Value(mkNamingAdapt( LastEnergyLossCausePlayer, "LastEngLossPlr", NO_OWNER ));
|
||||
pComp->Value(mkNamingAdapt( Category, "Category", 0 ));
|
||||
// old-style coordinates - compile dummy value to prevent warning
|
||||
// remove this once all Objects.txt have been rewritten without the values
|
||||
int32_t qX=0, qY=0, motion_x = 0, motion_y = 0;
|
||||
pComp->Value(mkNamingAdapt( qX, "X", 0 ));
|
||||
pComp->Value(mkNamingAdapt( qY, "Y", 0 ));
|
||||
pComp->Value(mkNamingAdapt( motion_x, "MotionX", 0 ));
|
||||
pComp->Value(mkNamingAdapt( motion_y, "MotionY", 0 ));
|
||||
|
||||
pComp->Value(mkNamingAdapt( r, "Rotation", 0 ));
|
||||
|
||||
|
@ -2688,9 +2680,8 @@ void C4Object::CompileFunc(StdCompiler *pComp)
|
|||
pComp->Value(mkNamingAdapt( FirePhase, "FirePhase", 0 ));
|
||||
pComp->Value(mkNamingAdapt( Color, "Color", 0u )); // TODO: Convert
|
||||
pComp->Value(mkNamingAdapt( Color, "ColorDw", 0u ));
|
||||
// default to X/Y values to support objects where FixX/FixY was manually removed
|
||||
pComp->Value(mkNamingAdapt( fix_x, "FixX", itofix(qX) ));
|
||||
pComp->Value(mkNamingAdapt( fix_y, "FixY", itofix(qY) ));
|
||||
pComp->Value(mkNamingAdapt( fix_x, "X", Fix0 ));
|
||||
pComp->Value(mkNamingAdapt( fix_y, "Y", Fix0 ));
|
||||
pComp->Value(mkNamingAdapt( fix_r, "FixR", 0 ));
|
||||
pComp->Value(mkNamingAdapt( xdir, "XDir", 0 ));
|
||||
pComp->Value(mkNamingAdapt( ydir, "YDir", 0 ));
|
||||
|
@ -2797,9 +2788,6 @@ void C4Object::CompileFunc(StdCompiler *pComp)
|
|||
// object needs to be resorted? May happen if there's unsorted objects in savegame
|
||||
if (Unsorted) Game.fResortAnyObject = true;
|
||||
|
||||
// initial OCF update
|
||||
SetOCF();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2832,7 +2820,7 @@ void C4Object::EnumeratePointers()
|
|||
|
||||
void C4Object::DenumeratePointers()
|
||||
{
|
||||
|
||||
C4PropList::DenumeratePointers();
|
||||
// Standard enumerated pointers
|
||||
Contained = ::Objects.ObjectPointer(nContained);
|
||||
Action.Target = ::Objects.ObjectPointer(nActionTarget1);
|
||||
|
|
|
@ -111,7 +111,7 @@ class C4Action
|
|||
void GetBridgeData(int32_t &riBridgeTime, bool &rfMoveClonk, bool &rfWall, int32_t &riBridgeMaterial);
|
||||
};
|
||||
|
||||
class C4Object: public C4PropList
|
||||
class C4Object: public C4PropListNumbered
|
||||
{
|
||||
public:
|
||||
C4Object();
|
||||
|
|
|
@ -999,7 +999,7 @@ static C4String *FnGetAction(C4AulObjectContext *cthr)
|
|||
|
||||
static C4PropList * FnCreatePropList(C4AulContext *cthr, C4PropList * prototype)
|
||||
{
|
||||
return new C4PropList(prototype);
|
||||
return C4PropList::New(prototype);
|
||||
}
|
||||
|
||||
static C4Value FnGetProperty_C4V(C4AulContext *cthr, C4Value * key_C4V, C4Value * pObj_C4V)
|
||||
|
@ -1493,7 +1493,10 @@ static C4Value FnAddMenuItem(C4AulContext *cthr, C4Value *pPars)
|
|||
break;
|
||||
case C4V_C4Object:
|
||||
case C4V_PropList:
|
||||
sprintf(parameter, "Object(%d)", Parameter.getPropList()->Number);
|
||||
if (Parameter.getPropList()->GetPropListNumbered())
|
||||
sprintf(parameter, "Object(%d)", Parameter.getPropList()->GetPropListNumbered()->Number);
|
||||
else
|
||||
sprintf(parameter, "C4Id(\"%s\")", Parameter.getPropList()->GetDef()->id.ToString());
|
||||
break;
|
||||
case C4V_String:
|
||||
// note this breaks if there is '"' in the string.
|
||||
|
|
|
@ -575,7 +575,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
|
||||
case AB_PROPLIST:
|
||||
{
|
||||
PushPropList(new C4PropList);
|
||||
PushPropList(C4PropList::New());
|
||||
break;
|
||||
}
|
||||
case AB_PROPSET:
|
||||
|
|
|
@ -266,7 +266,7 @@ void C4AulScriptEngine::Link(C4DefList *rDefs)
|
|||
// FIXME: move this to script
|
||||
if (GlobalNamed.GetItem("Action"))
|
||||
{
|
||||
C4PropList * Action = new C4PropList;
|
||||
C4PropList * Action = C4PropList::New();
|
||||
Action->SetProperty(Strings.P[P_Length], C4VInt(1));
|
||||
Action->SetProperty(Strings.P[P_Directions], C4VInt(1));
|
||||
Action->SetProperty(Strings.P[P_Step], C4VInt(1));
|
||||
|
|
|
@ -54,18 +54,66 @@ void C4PropList::AssignRemoval()
|
|||
Game.ClearPointers(this);
|
||||
}
|
||||
|
||||
C4PropList * C4PropList::New(C4PropList * prototype)
|
||||
{
|
||||
C4PropListNumbered * r = new C4PropListNumbered(prototype);
|
||||
r->AcquireNumber();
|
||||
return r;
|
||||
}
|
||||
|
||||
C4PropListNumbered::C4PropListNumbered(C4PropList * prototype): C4PropList(prototype), Number(-1)
|
||||
{
|
||||
}
|
||||
|
||||
void C4PropListNumbered::AcquireNumber()
|
||||
{
|
||||
// Enumerate object
|
||||
do
|
||||
Number = ++Game.ObjectEnumerationIndex;
|
||||
while (::Objects.PropLists.Get(Number));
|
||||
::Objects.PropLists.Add(this);
|
||||
}
|
||||
|
||||
C4PropListNumbered* C4PropListNumbered::GetPropListNumbered()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void C4PropListNumbered::CompileFunc(StdCompiler *pComp)
|
||||
{
|
||||
pComp->Value(mkNamingAdapt(Number, "Number"));
|
||||
C4PropList::CompileFunc(pComp);
|
||||
if(pComp->isCompiler())
|
||||
::Objects.PropLists.Add(this);
|
||||
}
|
||||
|
||||
C4PropListNumbered::~C4PropListNumbered()
|
||||
{
|
||||
if(Number != -1)
|
||||
::Objects.PropLists.Remove(this);
|
||||
else
|
||||
Log("removing numbered proplist without number");
|
||||
}
|
||||
|
||||
C4PropList::C4PropList(C4PropList * prototype):
|
||||
Number(-1), Status(1),
|
||||
Status(1),
|
||||
FirstRef(NULL), prototype(prototype)
|
||||
{
|
||||
if(prototype)
|
||||
SetProperty(Strings.P[P_Prototype], C4VPropList(prototype));
|
||||
}
|
||||
|
||||
// Enumerate object
|
||||
do
|
||||
Number = ++Game.ObjectEnumerationIndex;
|
||||
while (::Objects.PropLists.Get(Game.ObjectEnumerationIndex));
|
||||
::Objects.PropLists.Add(this);
|
||||
void C4PropList::DenumeratePointers()
|
||||
{
|
||||
const C4Property * p = Properties.First();
|
||||
while (p)
|
||||
{
|
||||
const_cast<C4Value &>(p->Value).DenumeratePointer();
|
||||
p = Properties.Next(p);
|
||||
}
|
||||
C4Value v;
|
||||
GetProperty(Strings.P[P_Prototype], v);
|
||||
prototype = v.getPropList();
|
||||
}
|
||||
|
||||
C4PropList::~C4PropList()
|
||||
|
@ -78,10 +126,81 @@ C4PropList::~C4PropList()
|
|||
FirstRef = FirstRef->NextRef;
|
||||
ref->NextRef = NULL;
|
||||
}
|
||||
::Objects.PropLists.Remove(this);
|
||||
assert(!::Objects.ObjectNumber(this));
|
||||
}
|
||||
|
||||
void C4PropList::CompileFunc(StdCompiler *pComp)
|
||||
{
|
||||
pComp->Value(mkNamingAdapt(Properties, "Properties"));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void C4Set<T>::CompileFunc(StdCompiler *pComp)
|
||||
{
|
||||
bool fNaming = pComp->hasNaming();
|
||||
if (pComp->isCompiler())
|
||||
{
|
||||
// Compiling: Empty previous
|
||||
Clear();
|
||||
// Read size (binary only)
|
||||
uint32_t iSize;
|
||||
if(!pComp->hasNaming()) pComp->Value(iSize);
|
||||
// Read new
|
||||
do
|
||||
{
|
||||
// No entries left to read?
|
||||
if(!fNaming && !iSize--)
|
||||
break;
|
||||
// Read entries
|
||||
try
|
||||
{
|
||||
T e;
|
||||
pComp->Value(e);
|
||||
Add(e);
|
||||
}
|
||||
catch(StdCompiler::NotFoundException *pEx)
|
||||
{
|
||||
// No value found: Stop reading loop
|
||||
delete pEx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(pComp->Seperator(StdCompiler::SEP_SEP2));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write size (binary only)
|
||||
if(!fNaming)
|
||||
{
|
||||
int32_t iSize = GetSize();
|
||||
pComp->Value(iSize);
|
||||
}
|
||||
// Write all entries
|
||||
const T * p = First();
|
||||
while (p)
|
||||
{
|
||||
pComp->Value(*const_cast<T *>(p));
|
||||
p = Next(p);
|
||||
if (p) pComp->Seperator(StdCompiler::SEP_SEP2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void C4Property::CompileFunc(StdCompiler *pComp)
|
||||
{
|
||||
StdStrBuf s;
|
||||
if (!pComp->isCompiler())
|
||||
s = Key->GetData();
|
||||
pComp->Value(s);
|
||||
if (pComp->isCompiler())
|
||||
{
|
||||
if (Key) Key->DecRef();
|
||||
Key = ::Strings.RegString(s);
|
||||
Key->IncRef();
|
||||
}
|
||||
pComp->Seperator(StdCompiler::SEP_SET);
|
||||
pComp->Value(Value);
|
||||
}
|
||||
|
||||
|
||||
const char * C4PropList::GetName()
|
||||
|
@ -117,6 +236,12 @@ C4Def * C4PropList::GetDef()
|
|||
}
|
||||
|
||||
|
||||
C4PropListNumbered * C4PropList::GetPropListNumbered()
|
||||
{
|
||||
if (prototype) return prototype->GetPropListNumbered();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
template<> template<>
|
||||
unsigned int C4Set<C4Property>::Hash<C4String *>(C4String * e)
|
||||
|
@ -210,7 +335,7 @@ void C4PropList::ResetProperty(C4String * k)
|
|||
|
||||
|
||||
template<> template<>
|
||||
unsigned int C4Set<C4PropList *>::Hash<int>(int e)
|
||||
unsigned int C4Set<C4PropListNumbered *>::Hash<int>(int e)
|
||||
{
|
||||
unsigned int hash = 4, tmp;
|
||||
hash += e >> 16;
|
||||
|
@ -227,13 +352,25 @@ unsigned int C4Set<C4PropList *>::Hash<int>(int e)
|
|||
}
|
||||
|
||||
template<> template<>
|
||||
unsigned int C4Set<C4PropList *>::Hash<C4PropList *>(C4PropList * e)
|
||||
unsigned int C4Set<C4PropListNumbered *>::Hash<C4PropList *>(C4PropList * e)
|
||||
{
|
||||
return Hash(e->GetPropListNumbered()->Number);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
unsigned int C4Set<C4PropListNumbered *>::Hash<C4PropListNumbered *>(C4PropListNumbered * e)
|
||||
{
|
||||
return Hash(e->Number);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
bool C4Set<C4PropList *>::Equals<int>(C4PropList * a, int b)
|
||||
bool C4Set<C4PropListNumbered *>::Equals<int>(C4PropListNumbered * a, int b)
|
||||
{
|
||||
return a->Number == b;
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
bool C4Set<C4PropListNumbered *>::Equals<C4PropList *>(C4PropListNumbered * a, C4PropList * b)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
|
|
|
@ -34,17 +34,17 @@ class C4Property {
|
|||
C4Property(const C4Property &o) : Key(o.Key), Value(o.Value) { if(Key) Key->IncRef(); }
|
||||
C4Property & operator = (const C4Property &o)
|
||||
{ assert(o.Key); o.Key->IncRef(); if(Key) Key->DecRef(); Key = o.Key; Value = o.Value; return *this; }
|
||||
~C4Property() { if(Key) Key->DecRef();}
|
||||
~C4Property() { if(Key) Key->DecRef(); }
|
||||
void CompileFunc(StdCompiler *pComp);
|
||||
C4String * Key;
|
||||
C4Value Value;
|
||||
operator void * () { return Key; }
|
||||
operator const void * () const { return Key; }
|
||||
C4Property & operator = (void * p) { assert(!p); if(Key) Key->DecRef(); Key = 0; Value.Set0(); return *this; }
|
||||
};
|
||||
|
||||
class C4PropListNumbered;
|
||||
class C4PropList {
|
||||
public:
|
||||
int32_t Number;
|
||||
int32_t Status; // NoSave //
|
||||
int32_t Status;
|
||||
void AddRef(C4Value *pRef);
|
||||
void DelRef(const C4Value *pRef, C4Value * pNextRef);
|
||||
void AssignRemoval();
|
||||
|
@ -53,6 +53,7 @@ class C4PropList {
|
|||
|
||||
virtual C4Def * GetDef();
|
||||
virtual C4Object * GetObject();
|
||||
virtual C4PropListNumbered * GetPropListNumbered();
|
||||
C4PropList * GetPrototype() { return prototype; }
|
||||
|
||||
bool GetProperty(C4String * k, C4Value & to);
|
||||
|
@ -61,15 +62,34 @@ class C4PropList {
|
|||
void SetProperty(C4String * k, const C4Value & to);
|
||||
void ResetProperty(C4String * k);
|
||||
|
||||
C4PropList(C4PropList * prototype = 0);
|
||||
static C4PropList * New(C4PropList * prototype = 0);
|
||||
virtual void DenumeratePointers();
|
||||
virtual ~C4PropList();
|
||||
|
||||
protected:
|
||||
C4Value *FirstRef; // No-Save
|
||||
// Every proplist has to be initialized by either Init or CompileFunc.
|
||||
void CompileFunc(StdCompiler *pComp);
|
||||
|
||||
protected:
|
||||
C4PropList(C4PropList * prototype = 0);
|
||||
C4Set<C4Property> Properties;
|
||||
|
||||
private:
|
||||
C4Value *FirstRef; // No-Save
|
||||
bool constant; // if true, this proplist is neither saved nor changeable FIXME: implement
|
||||
|
||||
C4PropList * prototype;
|
||||
friend void CompileNewFunc<C4PropList>(C4PropList *&pStruct, StdCompiler *pComp);
|
||||
};
|
||||
|
||||
class C4PropListNumbered: public C4PropList {
|
||||
public:
|
||||
int32_t Number;
|
||||
C4PropListNumbered(C4PropList * prototype = 0);
|
||||
~C4PropListNumbered();
|
||||
void CompileFunc(StdCompiler *pComp);
|
||||
virtual C4PropListNumbered * GetPropListNumbered();
|
||||
void AcquireNumber();
|
||||
};
|
||||
|
||||
|
||||
#endif // C4PROPLIST_H
|
||||
|
|
|
@ -77,6 +77,7 @@ public:
|
|||
{
|
||||
delete[] Table;
|
||||
}
|
||||
void CompileFunc(StdCompiler *pComp);
|
||||
void Clear()
|
||||
{
|
||||
for (unsigned int i = 0; i < Capacity; ++i)
|
||||
|
|
|
@ -67,7 +67,7 @@ void C4Value::AddDataRef()
|
|||
Data.PropList->AddRef(this);
|
||||
#ifdef _DEBUG
|
||||
// check if the object actually exists
|
||||
if(!::Objects.ObjectNumber(Data.PropList))
|
||||
if(Data.PropList->GetPropListNumbered() && !::Objects.ObjectNumber(Data.PropList))
|
||||
{ LogF("Warning: using wild object ptr %p!", static_cast<void*>(Data.PropList)); }
|
||||
else if(!Data.PropList->Status)
|
||||
{ LogF("Warning: using ptr on deleted object %p (%s)!", static_cast<void*>(Data.PropList), Data.PropList->GetName()); }
|
||||
|
@ -284,6 +284,8 @@ char GetC4VID(const C4V_Type Type)
|
|||
return 'V'; // should never happen
|
||||
case C4V_C4ObjectEnum:
|
||||
return 'O';
|
||||
case C4V_C4DefEnum:
|
||||
return 'D';
|
||||
case C4V_Array:
|
||||
return 'a';
|
||||
case C4V_PropList:
|
||||
|
@ -310,6 +312,8 @@ C4V_Type GetC4VFromID(const char C4VID)
|
|||
return C4V_pC4Value;
|
||||
case 'O':
|
||||
return C4V_C4ObjectEnum;
|
||||
case 'D':
|
||||
return C4V_C4DefEnum;
|
||||
case 'a':
|
||||
return C4V_Array;
|
||||
case 'p':
|
||||
|
@ -470,9 +474,9 @@ StdStrBuf C4Value::GetDataString()
|
|||
else
|
||||
if (Data.PropList)
|
||||
if (Data.Obj->Status == C4OS_NORMAL)
|
||||
return FormatString("%s #%d", Data.PropList->GetName(), (int) Data.PropList->Number);
|
||||
return FormatString("%s #%d", Data.PropList->GetName(), Objects.ObjectNumber(Data.PropList));
|
||||
else
|
||||
return FormatString("{%s #%d}", Data.PropList->GetName(), (int) Data.PropList->Number);
|
||||
return FormatString("{%s #%d}", Data.PropList->GetName(), Objects.ObjectNumber(Data.PropList));
|
||||
else
|
||||
return StdStrBuf("0"); // (impossible)
|
||||
}
|
||||
|
@ -520,16 +524,17 @@ void C4Value::DenumeratePointer()
|
|||
return;
|
||||
}
|
||||
// object types only
|
||||
if(Type != C4V_C4ObjectEnum && Type != C4V_Any) return;
|
||||
if(Type != C4V_C4ObjectEnum) return;
|
||||
// get obj id, search object
|
||||
int iObjID = Data.Int;
|
||||
C4PropList *pObj = ::Objects.ObjectPointer(iObjID);
|
||||
C4PropList *pObj = Objects.PropListPointer(iObjID);
|
||||
if(pObj)
|
||||
// set
|
||||
SetPropList(pObj);
|
||||
else
|
||||
{
|
||||
// object: invalid value - set to zero
|
||||
LogF("ERROR: Object number %d is missing.", Data.Int);
|
||||
Set0();
|
||||
}
|
||||
}
|
||||
|
@ -546,6 +551,10 @@ void C4Value::CompileFunc(StdCompiler *pComp)
|
|||
// Object reference is saved enumerated
|
||||
if(Type == C4V_C4Object)
|
||||
cC4VID = GetC4VID(C4V_C4ObjectEnum);
|
||||
if(Type == C4V_PropList && getPropList()->GetDef())
|
||||
cC4VID = GetC4VID(C4V_C4DefEnum);
|
||||
else if(Type == C4V_PropList)
|
||||
cC4VID = GetC4VID(C4V_C4ObjectEnum);
|
||||
// Write
|
||||
pComp->Character(cC4VID);
|
||||
}
|
||||
|
@ -600,18 +609,43 @@ void C4Value::CompileFunc(StdCompiler *pComp)
|
|||
|
||||
// object: save object number instead
|
||||
case C4V_C4Object: case C4V_PropList:
|
||||
if(!fCompiler)
|
||||
iTmp = ::Objects.ObjectNumber(getPropList());
|
||||
case C4V_C4ObjectEnum:
|
||||
if(!fCompiler) if (Type == C4V_C4ObjectEnum)
|
||||
iTmp = Data.Int;
|
||||
pComp->Value(iTmp);
|
||||
if(fCompiler)
|
||||
{
|
||||
assert(!fCompiler);
|
||||
C4PropList * p = getPropList();
|
||||
if (Type == C4V_PropList && p->GetDef())
|
||||
pComp->Value(p->GetDef()->id);
|
||||
else
|
||||
{
|
||||
Type = C4V_C4ObjectEnum;
|
||||
Data.Int = iTmp; // must be denumerated later
|
||||
iTmp = ::Objects.ObjectNumber(getPropList());
|
||||
pComp->Value(iTmp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case C4V_C4ObjectEnum:
|
||||
assert(fCompiler);
|
||||
pComp->Value(iTmp); // must be denumerated later
|
||||
Data.Int = iTmp;
|
||||
break;
|
||||
|
||||
case C4V_C4DefEnum:
|
||||
{
|
||||
assert(fCompiler);
|
||||
C4ID id;
|
||||
pComp->Value(id); // must be denumerated later
|
||||
Data.PropList = Definitions.ID2Def(id);
|
||||
Type = C4V_PropList;
|
||||
if(!Data.PropList)
|
||||
{
|
||||
LogF("ERROR: Definition %s is missing.", id.ToString());
|
||||
Type = C4V_Any;
|
||||
}
|
||||
else
|
||||
{
|
||||
Data.PropList->AddRef(this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// string: save string number
|
||||
case C4V_String:
|
||||
|
|
|
@ -41,7 +41,8 @@ enum C4V_Type
|
|||
C4V_Array=6, // pointer on array of values
|
||||
C4V_pC4Value=7, // reference on a value (variable)
|
||||
|
||||
C4V_C4ObjectEnum=9 // enumerated object
|
||||
C4V_C4ObjectEnum=9, // enumerated object
|
||||
C4V_C4DefEnum=10, // enumerated object
|
||||
};
|
||||
|
||||
#define C4V_Last (int) C4V_pC4Value
|
||||
|
|
Loading…
Reference in New Issue