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
Günther Brammer 2010-03-22 00:40:03 +01:00
parent 7c118604c4
commit 5d2c3d4c2b
12 changed files with 368 additions and 61 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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();

View File

@ -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.

View File

@ -575,7 +575,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
case AB_PROPLIST:
{
PushPropList(new C4PropList);
PushPropList(C4PropList::New());
break;
}
case AB_PROPSET:

View File

@ -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));

View File

@ -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;
}

View File

@ -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

View File

@ -77,6 +77,7 @@ public:
{
delete[] Table;
}
void CompileFunc(StdCompiler *pComp);
void Clear()
{
for (unsigned int i = 0; i < Capacity; ++i)

View File

@ -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:

View File

@ -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