openclonk/src/script/C4PropList.cpp

532 lines
11 KiB
C++
Raw Normal View History

/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2004 Peter Wortmann
2011-09-01 14:58:52 +00:00
* Copyright (c) 2007, 2009-2011 Günther Brammer
* Copyright (c) 2009 Nicolas Hake
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* "Clonk" is a registered trademark of Matthes Bender.
*/
#include <C4Include.h>
#include <C4PropList.h>
2009-07-21 14:46:39 +00:00
#include <C4GameObjects.h>
#include <C4Game.h>
#include <C4Object.h>
void C4PropList::AddRef(C4Value *pRef)
2010-03-28 18:58:01 +00:00
{
#ifdef _DEBUG
C4Value * pVal = FirstRef;
while (pVal)
{
assert(pVal != pRef);
pVal = pVal->NextRef;
}
#endif
pRef->NextRef = FirstRef;
FirstRef = pRef;
2010-03-28 18:58:01 +00:00
}
void C4PropList::DelRef(const C4Value * pRef, C4Value * pNextRef)
2010-03-28 18:58:01 +00:00
{
assert(FirstRef);
// References to objects never have HasBaseArray set
2010-03-28 18:58:01 +00:00
if (pRef == FirstRef)
{
FirstRef = pNextRef;
if (pNextRef) return;
}
else
2010-03-28 18:58:01 +00:00
{
C4Value *pPrev = FirstRef;
while (pPrev->NextRef != pRef)
{
pPrev = pPrev->NextRef;
assert(pPrev);
}
pPrev->NextRef = pNextRef;
return;
2010-03-28 18:58:01 +00:00
}
// Only pure script proplists are garbage collected here, host proplists
// like definitions and effects have their own memory management.
if (IsScriptPropList()) delete this;
2010-03-28 18:58:01 +00:00
}
C4PropList * C4PropList::New(C4PropList * prototype)
2010-03-28 18:58:01 +00:00
{
C4PropList * r = new C4PropListScript(prototype);
return r;
2010-03-28 18:58:01 +00:00
}
C4PropList * C4PropList::NewAnon(C4PropList * prototype)
{
C4PropList * r = new C4PropListScript(prototype);
return r;
}
C4PropList * C4PropList::NewScen(C4PropList * prototype)
{
return new C4PropList(prototype);
}
C4Set<C4PropListNumbered *> C4PropListNumbered::PropLists;
int32_t C4PropListNumbered::EnumerationIndex = 0;
C4PropList *C4PropListNumbered::GetByNumber(int32_t iNumber)
{
return PropLists.Get(iNumber);
}
bool C4PropListNumbered::CheckPropList(C4PropList *pObj)
{
if (!pObj) return false;
C4PropListNumbered * const * p = PropLists.First();
while (p)
{
if (*p == pObj)
return true;
p = PropLists.Next(p);
}
return false;
}
void C4PropListNumbered::SetEnumerationIndex(int32_t iMaxObjectNumber)
{
// update object enumeration index now, because calls like UpdateTransferZone might create objects
EnumerationIndex = Max(EnumerationIndex, iMaxObjectNumber);
}
void C4PropListNumbered::ResetEnumerationIndex()
{
assert(!PropLists.GetSize());
EnumerationIndex = 0;
}
C4PropListNumbered::C4PropListNumbered(C4PropList * prototype): C4PropList(prototype), Number(-1)
2010-03-28 18:58:01 +00:00
{
}
void C4PropListNumbered::AcquireNumber()
2010-03-28 18:58:01 +00:00
{
2009-04-19 21:33:42 +00:00
// Enumerate object
do
Number = ++EnumerationIndex;
while (PropLists.Get(Number));
PropLists.Add(this);
2010-03-28 18:58:01 +00:00
}
C4PropListNumbered* C4PropListNumbered::GetPropListNumbered()
2010-03-28 18:58:01 +00:00
{
return this;
2010-03-28 18:58:01 +00:00
}
void C4PropListNumbered::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers)
{
pComp->Value(Number);
pComp->Separator(StdCompiler::SEP_SEP2);
C4PropList::CompileFunc(pComp, numbers);
if (pComp->isCompiler())
{
if (PropLists.Get(Number))
{
pComp->excCorrupt("multiple PropLists with Number %d", Number);
return;
}
PropLists.Add(this);
}
}
C4PropListNumbered::~C4PropListNumbered()
2010-03-28 18:58:01 +00:00
{
if (Number != -1)
PropLists.Remove(this);
else
Log("removing numbered proplist without number");
2010-03-28 18:58:01 +00:00
}
#ifdef _DEBUG
C4Set<C4PropList *> C4PropList::PropLists;
#endif
C4PropList::C4PropList(C4PropList * prototype):
2011-08-17 21:55:24 +00:00
FirstRef(NULL), prototype(prototype),
constant(false), Status(1)
2010-03-28 18:58:01 +00:00
{
if (prototype)
SetProperty(P_Prototype, C4VPropList(prototype));
#ifdef _DEBUG
PropLists.Add(this);
#endif
2010-03-28 18:58:01 +00:00
}
void C4PropList::Denumerate(C4ValueNumbers * numbers)
2010-03-28 18:58:01 +00:00
{
const C4Property * p = Properties.First();
while (p)
2010-03-28 18:58:01 +00:00
{
const_cast<C4Value &>(p->Value).Denumerate(numbers);
p = Properties.Next(p);
2010-03-28 18:58:01 +00:00
}
C4Value v;
if(GetProperty(P_Prototype, &v))
prototype = v.getPropList();
2010-03-28 18:58:01 +00:00
}
C4PropList::~C4PropList()
2010-03-28 18:58:01 +00:00
{
while (FirstRef)
{
// Manually kill references so DelRef doesn't destroy us again
FirstRef->Data = 0; FirstRef->Type = C4V_Nil;
C4Value *ref = FirstRef;
FirstRef = FirstRef->NextRef;
ref->NextRef = NULL;
}
#ifdef _DEBUG
assert(PropLists.Has(this));
PropLists.Remove(this);
#endif
assert(!C4PropListNumbered::CheckPropList(this));
2010-03-28 18:58:01 +00:00
}
bool C4PropList::operator==(const C4PropList &b) const
{
if (Properties.GetSize() != b.Properties.GetSize()) return false;
if (GetDef() != b.GetDef()) return false;
//if (GetObject() != b.GetObject()) return false;
const C4Property * p = Properties.First();
while (p)
{
if (*p != b.Properties.Get(p->Key)) return false;
p = Properties.Next(p);
}
return true;
}
void C4PropList::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers)
2010-03-28 18:58:01 +00:00
{
pComp->Value(constant);
pComp->Separator(StdCompiler::SEP_SEP2);
pComp->Value(mkParAdapt(Properties, numbers));
}
void CompileNewFunc(C4PropList *&pStruct, StdCompiler *pComp, C4ValueNumbers * const & rPar)
{
std::auto_ptr<C4PropList> temp(C4PropList::New()); // exception-safety
pComp->Value(mkParAdapt(*temp, rPar));
pStruct = temp.release();
2010-03-28 18:58:01 +00:00
}
template<typename T>
void C4Set<T>::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers)
2010-03-28 18:58:01 +00:00
{
bool fNaming = pComp->hasNaming();
if (pComp->isCompiler())
2010-03-28 18:58:01 +00:00
{
// Compiling: Empty previous
Clear();
// Read size (binary only)
uint32_t iSize;
2010-03-28 18:58:01 +00:00
if (!pComp->hasNaming()) pComp->Value(iSize);
// Read new
do
2010-03-28 18:58:01 +00:00
{
// No entries left to read?
2010-03-28 18:58:01 +00:00
if (!fNaming && !iSize--)
break;
// Read entries
try
2010-03-28 18:58:01 +00:00
{
T e;
// This could use the same technique StdArrayAdapt uses
// instead of hardcoding mkParAdapt here
pComp->Value(mkParAdapt(e, numbers));
Add(e);
2010-03-28 18:58:01 +00:00
}
catch (StdCompiler::NotFoundException *pEx)
{
// No value found: Stop reading loop
delete pEx;
break;
}
}
while (pComp->Separator(StdCompiler::SEP_SEP));
2010-03-28 18:58:01 +00:00
}
else
2010-03-28 18:58:01 +00:00
{
// Write size (binary only)
2010-03-28 18:58:01 +00:00
if (!fNaming)
{
int32_t iSize = GetSize();
pComp->Value(iSize);
2010-03-28 18:58:01 +00:00
}
// Write all entries
const T * p = First();
while (p)
2010-03-28 18:58:01 +00:00
{
pComp->Value(mkParAdapt(*const_cast<T *>(p), numbers));
p = Next(p);
if (p) pComp->Separator(StdCompiler::SEP_SEP);
}
}
2010-03-28 18:58:01 +00:00
}
void C4Property::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers)
2010-03-28 18:58:01 +00:00
{
StdStrBuf s;
if (!pComp->isCompiler())
s = Key->GetData();
pComp->Value(s);
if (pComp->isCompiler())
2010-03-28 18:58:01 +00:00
{
if (Key) Key->DecRef();
Key = ::Strings.RegString(s);
Key->IncRef();
2010-03-28 18:58:01 +00:00
}
2010-04-01 21:08:06 +00:00
pComp->Separator(StdCompiler::SEP_SET);
pComp->Value(mkParAdapt(Value, numbers));
2010-03-28 18:58:01 +00:00
}
void C4PropList::AppendDataString(StdStrBuf * out, const char * delim, int depth)
{
StdStrBuf & DataString = *out;
if (depth <= 0 && Properties.GetSize())
{
DataString.Append("...");
return;
}
const C4Property * p = Properties.First();
while (p)
{
DataString.Append(p->Key->GetData());
DataString.Append(" = ");
DataString.Append(p->Value.GetDataString(depth - 1));
p = Properties.Next(p);
if (p) DataString.Append(delim);
}
}
const char * C4PropList::GetName() const
2010-03-28 18:58:01 +00:00
{
C4String * s = GetPropertyStr(P_Name);
if (!s) return "";
return s->GetCStr();
2010-03-28 18:58:01 +00:00
}
void C4PropList::SetName(const char* NewName)
2010-03-28 18:58:01 +00:00
{
if (!NewName)
ResetProperty(&Strings.P[P_Name]);
else
2010-03-28 18:58:01 +00:00
{
SetProperty(P_Name, C4VString(NewName));
}
2010-03-28 18:58:01 +00:00
}
C4Object * C4PropList::GetObject()
2010-03-28 18:58:01 +00:00
{
if (prototype) return prototype->GetObject();
return 0;
2010-03-28 18:58:01 +00:00
}
C4Def * C4PropList::GetDef()
2010-03-28 18:58:01 +00:00
{
if (prototype) return prototype->GetDef();
return 0;
2010-03-28 18:58:01 +00:00
}
C4Def const * C4PropList::GetDef() const
{
if (prototype) return prototype->GetDef();
return 0;
}
C4PropListNumbered * C4PropList::GetPropListNumbered()
2010-03-28 18:58:01 +00:00
{
if (prototype) return prototype->GetPropListNumbered();
return 0;
2010-03-28 18:58:01 +00:00
}
C4Effect * C4PropList::GetEffect()
{
if (prototype) return prototype->GetEffect();
return 0;
}
template<> template<>
unsigned int C4Set<C4Property>::Hash<C4String *>(C4String * e)
2010-03-28 18:58:01 +00:00
{
2010-07-15 18:26:53 +00:00
assert(e);
unsigned int hash = 4, tmp;
hash += ((uintptr_t)e) >> 16;
tmp = ((((uintptr_t)e) & 0xffff) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
hash += hash >> 11;
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
//return e->Hash;
2010-03-28 18:58:01 +00:00
}
template<> template<>
bool C4Set<C4Property>::Equals<C4String *>(C4Property a, C4String * b)
2010-03-28 18:58:01 +00:00
{
return a.Key == b;
2010-03-28 18:58:01 +00:00
}
template<> template<>
unsigned int C4Set<C4Property>::Hash<C4Property>(C4Property p)
2010-03-28 18:58:01 +00:00
{
return C4Set<C4Property>::Hash(p.Key);
2010-03-28 18:58:01 +00:00
}
bool C4PropList::GetPropertyByS(C4String * k, C4Value *pResult) const
2010-03-28 18:58:01 +00:00
{
if (Properties.Has(k))
2010-03-28 18:58:01 +00:00
{
*pResult = Properties.Get(k).Value;
return true;
2010-03-28 18:58:01 +00:00
}
else if(prototype)
return prototype->GetPropertyByS(k, pResult);
else
return false;
2010-03-28 18:58:01 +00:00
}
C4String * C4PropList::GetPropertyStr(C4PropertyName n) const
2010-03-28 18:58:01 +00:00
{
C4String * k = &Strings.P[n];
if (Properties.Has(k))
2010-03-28 18:58:01 +00:00
{
return Properties.Get(k).Value.getStr();
2010-03-28 18:58:01 +00:00
}
if (prototype)
2010-03-28 18:58:01 +00:00
{
return prototype->GetPropertyStr(n);
}
2010-03-28 18:58:01 +00:00
return 0;
}
C4PropertyName C4PropList::GetPropertyP(C4PropertyName n) const
{
C4String * k = &Strings.P[n];
if (Properties.Has(k))
{
C4String * v = Properties.Get(k).Value.getStr();
if (v >= &Strings.P[0] && v < &Strings.P[P_LAST])
return C4PropertyName(v - &Strings.P[0]);
return P_LAST;
}
if (prototype)
{
return prototype->GetPropertyP(n);
}
return P_LAST;
}
int32_t C4PropList::GetPropertyInt(C4PropertyName n) const
2010-03-28 18:58:01 +00:00
{
C4String * k = &Strings.P[n];
if (Properties.Has(k))
2010-03-28 18:58:01 +00:00
{
return Properties.Get(k).Value.getInt();
2010-03-28 18:58:01 +00:00
}
if (prototype)
2010-03-28 18:58:01 +00:00
{
return prototype->GetPropertyInt(n);
}
2010-03-28 18:58:01 +00:00
return 0;
}
void C4PropList::SetPropertyByS(C4String * k, const C4Value & to)
2010-03-28 18:58:01 +00:00
{
assert(!constant);
/*assert(Strings.Set.Has(k));*/
if (k == &Strings.P[P_Prototype] && to.GetType() == C4V_PropList)
2010-03-28 18:58:01 +00:00
{
prototype = to.GetData().PropList;
//return;
2010-03-28 18:58:01 +00:00
}
if (Properties.Has(k))
2010-03-28 18:58:01 +00:00
{
Properties.Get(k).Value = to;
2010-03-28 18:58:01 +00:00
}
else
2010-03-28 18:58:01 +00:00
{
C4Property p(k, to);
Properties.Add(p);
}
2010-03-28 18:58:01 +00:00
}
void C4PropList::ResetProperty(C4String * k)
2010-03-28 18:58:01 +00:00
{
Properties.Remove(k);
2010-03-28 18:58:01 +00:00
}
template<> template<>
unsigned int C4Set<C4PropListNumbered *>::Hash<int>(int e)
2010-03-28 18:58:01 +00:00
{
unsigned int hash = 4, tmp;
hash += e >> 16;
tmp = ((e & 0xffff) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
hash += hash >> 11;
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
2010-03-28 18:58:01 +00:00
}
template<> template<>
unsigned int C4Set<C4PropListNumbered *>::Hash<C4PropList *>(C4PropList * e)
2010-03-28 18:58:01 +00:00
{
return Hash(e->GetPropListNumbered()->Number);
2010-03-28 18:58:01 +00:00
}
template<> template<>
unsigned int C4Set<C4PropListNumbered *>::Hash<C4PropListNumbered *>(C4PropListNumbered * e)
2010-03-28 18:58:01 +00:00
{
return Hash(e->Number);
2010-03-28 18:58:01 +00:00
}
template<> template<>
bool C4Set<C4PropListNumbered *>::Equals<int>(C4PropListNumbered * a, int b)
2010-03-28 18:58:01 +00:00
{
return a->Number == b;
2010-03-28 18:58:01 +00:00
}
template<> template<>
bool C4Set<C4PropListNumbered *>::Equals<C4PropList *>(C4PropListNumbered * a, C4PropList * b)
2010-03-28 18:58:01 +00:00
{
return a == b;
2010-03-28 18:58:01 +00:00
}
template<> template<>
unsigned int C4Set<C4PropList *>::Hash<C4PropList *>(C4PropList * e)
{
return C4Set<C4PropListNumbered *>::Hash(static_cast<int>(reinterpret_cast<intptr_t>(e)));
}