2009-07-22 14:15:18 +00:00
/*
2010-12-23 00:01:24 +00:00
* OpenClonk , http : //www.openclonk.org
*
2016-04-03 18:18:29 +00:00
* Copyright ( c ) 2009 - 2016 , The OpenClonk Team and contributors
2009-07-22 14:15:18 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2009-07-22 14:15:18 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2009-07-22 14:15:18 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2009-07-22 14:15:18 +00:00
*/
2009-05-19 22:12:11 +00:00
/* Property lists */
2016-04-03 18:07:56 +00:00
# include "script/C4Value.h"
# include "script/C4StringTable.h"
2009-05-19 22:12:11 +00:00
2011-01-08 16:04:20 +00:00
# ifndef C4PROPLIST_H
# define C4PROPLIST_H
2013-02-04 21:27:04 +00:00
/* C4PropList have a somewhat complicated reference counting scheme. You can:
- Store a C4Proplist * in a C4Value . This is the preferred and often only way .
- Store a C4Object * from GetObject in a C4Object * or C4PropList * if there is a ClearPointer function for it
Use a C4ObjectPtr for help with storing the Object in Savegames .
- Store a C4Def * from GetDef ( ) in a C4Def * or C4PropList *
All PropLists can be destroyed while there are still C4Values referencing them , though
Definitions do not get destroyed during the game . So always check for nullpointers .
The linked list formed by C4PropList : : FirstRef and C4Value : : NextRef is used to
change all C4Values referencing the destroyed Proplist to contain nil instead .
Objects are also cleaned up via various ClearPointer functions .
The list is also used as a reference count to remove unused Proplists .
The exception are C4PropListNumbered and C4Def , which have implicit references
from C4GameObjects , C4Object and C4DefList . They have to be destroyed when loosing that reference . */
2009-10-25 23:09:34 +00:00
2010-03-28 17:58:21 +00:00
class C4Property
{
public :
2017-05-07 11:50:00 +00:00
C4Property ( ) = default ;
2009-07-26 20:31:45 +00:00
C4Property ( C4String * Key , const C4Value & Value ) : Key ( Key ) , Value ( Value )
2015-03-25 18:04:04 +00:00
{ assert ( Key ) ; Key - > IncRef ( ) ; }
2010-03-28 17:58:21 +00:00
C4Property ( const C4Property & o ) : Key ( o . Key ) , Value ( o . Value ) { if ( Key ) Key - > IncRef ( ) ; }
2009-07-26 20:31:45 +00:00
C4Property & operator = ( const C4Property & o )
2012-10-14 12:39:22 +00:00
{ if ( o . Key ) o . Key - > IncRef ( ) ; if ( Key ) Key - > DecRef ( ) ; Key = o . Key ; Value = o . Value ; return * this ; }
2017-05-07 11:50:00 +00:00
C4Property ( C4Property & & o ) : Key ( o . Key ) , Value ( std : : move ( o . Value ) ) { o . Key = nullptr ; }
2012-07-25 23:21:15 +00:00
C4Property & operator = ( C4Property & & o )
2017-05-07 11:50:00 +00:00
{ if ( Key ) Key - > DecRef ( ) ; Key = o . Key ; o . Key = nullptr ; Value = std : : move ( o . Value ) ; return * this ; }
2010-03-28 17:58:21 +00:00
~ C4Property ( ) { if ( Key ) Key - > DecRef ( ) ; }
2011-03-26 22:59:35 +00:00
void CompileFunc ( StdCompiler * pComp , C4ValueNumbers * ) ;
2017-05-07 11:50:00 +00:00
C4String * Key { nullptr } ;
2009-05-19 22:12:11 +00:00
C4Value Value ;
2010-03-21 23:40:03 +00:00
operator const void * ( ) const { return Key ; }
2012-10-14 12:39:22 +00:00
bool operator < ( const C4Property & cmp ) const { return strcmp ( GetSafeKey ( ) , cmp . GetSafeKey ( ) ) < 0 ; }
2016-11-02 23:58:02 +00:00
const char * GetSafeKey ( ) const { if ( Key & & Key - > GetCStr ( ) ) return Key - > GetCStr ( ) ; return " " ; } // get key as C string; return "" if undefined. never return nullptr
2009-05-19 22:12:11 +00:00
} ;
2010-03-21 23:40:03 +00:00
class C4PropListNumbered ;
2010-03-28 17:58:21 +00:00
class C4PropList
{
public :
2013-03-24 17:10:16 +00:00
void Clear ( ) { constant = false ; Properties . Clear ( ) ; prototype . Set0 ( ) ; }
2014-04-20 20:05:50 +00:00
virtual const char * GetName ( ) const ;
2017-05-07 11:50:00 +00:00
virtual void SetName ( const char * NewName = nullptr ) ;
2015-12-18 23:39:08 +00:00
virtual void SetOnFire ( bool OnFire ) { }
2009-05-19 22:12:11 +00:00
2013-02-04 21:27:04 +00:00
// These functions return this or a prototype.
2010-09-10 21:01:30 +00:00
virtual C4Def const * GetDef ( ) const ;
2009-04-12 12:04:28 +00:00
virtual C4Def * GetDef ( ) ;
2009-04-18 00:46:19 +00:00
virtual C4Object * GetObject ( ) ;
2016-04-17 02:02:24 +00:00
virtual C4Object const * GetObject ( ) const ;
2010-12-19 23:13:56 +00:00
virtual C4Effect * GetEffect ( ) ;
2010-03-21 23:40:03 +00:00
virtual C4PropListNumbered * GetPropListNumbered ( ) ;
2013-03-24 12:29:04 +00:00
virtual class C4MapScriptLayer * GetMapScriptLayer ( ) ;
virtual class C4MapScriptMap * GetMapScriptMap ( ) ;
2009-04-12 12:04:28 +00:00
2013-03-24 17:10:16 +00:00
C4PropList * GetPrototype ( ) const { return prototype . _getPropList ( ) ; }
2014-09-26 20:10:42 +00:00
void RemoveCyclicPrototypes ( ) ;
2013-03-24 17:10:16 +00:00
2012-06-01 15:27:59 +00:00
// saved as a reference to a global constant?
2016-11-02 23:58:02 +00:00
virtual class C4PropListStatic * IsStatic ( ) { return nullptr ; }
2014-04-20 13:52:09 +00:00
const class C4PropListStatic * IsStatic ( ) const { return const_cast < C4PropList * > ( this ) - > IsStatic ( ) ; }
2012-06-01 15:27:59 +00:00
// saved as a reference to separately saved objects?
2011-03-27 16:14:41 +00:00
virtual bool IsNumbered ( ) const { return false ; }
2012-06-01 15:27:59 +00:00
// some proplists have references that are not reference-counted
virtual bool Delete ( ) { return false ; }
2010-09-08 18:09:27 +00:00
2012-05-25 23:32:43 +00:00
// These four operate on properties as seen by script, which can be dynamic
2010-12-24 14:10:39 +00:00
// or reflect C++ variables
2016-04-25 20:17:10 +00:00
virtual bool GetPropertyByS ( const C4String * k , C4Value * pResult ) const ;
2012-05-25 23:32:43 +00:00
virtual C4ValueArray * GetProperties ( ) const ;
2010-12-24 14:10:39 +00:00
// not allowed on frozen proplists
virtual void SetPropertyByS ( C4String * k , const C4Value & to ) ;
virtual void ResetProperty ( C4String * k ) ;
// helper functions to get dynamic properties from other parts of the engine
2010-12-06 15:19:15 +00:00
bool GetProperty ( C4PropertyName k , C4Value * pResult ) const
2010-12-06 15:24:41 +00:00
{ return GetPropertyByS ( & Strings . P [ k ] , pResult ) ; }
2010-09-10 21:01:30 +00:00
C4String * GetPropertyStr ( C4PropertyName k ) const ;
2015-01-03 22:21:36 +00:00
C4ValueArray * GetPropertyArray ( C4PropertyName n ) const ;
2011-10-04 21:04:06 +00:00
C4AulFunc * GetFunc ( C4PropertyName k ) const
{ return GetFunc ( & Strings . P [ k ] ) ; }
C4AulFunc * GetFunc ( C4String * k ) const ;
C4AulFunc * GetFunc ( const char * k ) const ;
2017-05-07 11:50:00 +00:00
C4String * EnumerateOwnFuncs ( C4String * prev = nullptr ) const ;
C4Value Call ( C4PropertyName k , C4AulParSet * pPars = nullptr , bool fPassErrors = false )
2012-08-19 19:29:43 +00:00
{ return Call ( & Strings . P [ k ] , pPars , fPassErrors ) ; }
2017-05-07 11:50:00 +00:00
C4Value Call ( C4String * k , C4AulParSet * pPars = nullptr , bool fPassErrors = false ) ;
C4Value Call ( const char * k , C4AulParSet * pPars = nullptr , bool fPassErrors = false ) ;
2010-12-08 22:17:00 +00:00
C4PropertyName GetPropertyP ( C4PropertyName k ) const ;
2016-06-03 05:20:43 +00:00
int32_t GetPropertyBool ( C4PropertyName n , bool default_val = false ) const ;
2015-08-21 00:19:38 +00:00
int32_t GetPropertyInt ( C4PropertyName k , int32_t default_val = 0 ) const ;
2013-03-18 23:35:00 +00:00
C4PropList * GetPropertyPropList ( C4PropertyName k ) const ;
bool HasProperty ( C4String * k ) const { return Properties . Has ( k ) ; }
2010-09-08 12:54:39 +00:00
// not allowed on frozen proplists
2010-12-06 15:19:15 +00:00
void SetProperty ( C4PropertyName k , const C4Value & to )
2010-12-06 15:24:41 +00:00
{ SetPropertyByS ( & Strings . P [ k ] , to ) ; }
2009-04-03 19:06:29 +00:00
2017-05-07 11:50:00 +00:00
static C4PropList * New ( C4PropList * prototype = nullptr ) ;
2012-08-15 17:43:02 +00:00
static C4PropListStatic * NewStatic ( C4PropList * prototype , const C4PropListStatic * parent , C4String * key ) ;
2010-09-08 12:54:39 +00:00
// only freeze proplists which are not going to be modified
2012-06-01 15:27:59 +00:00
// FIXME: Only C4PropListStatic get frozen. Optimize accordingly.
2010-09-08 12:54:39 +00:00
void Freeze ( ) { constant = true ; }
2011-10-14 23:38:59 +00:00
void Thaw ( ) { constant = false ; }
2017-03-26 17:30:48 +00:00
void ThawRecursively ( ) ;
2010-09-10 21:01:30 +00:00
bool IsFrozen ( ) const { return constant ; }
2010-09-08 12:54:39 +00:00
2016-08-27 05:12:08 +00:00
// Freeze this and all proplist in properties and ensure they are static proplists
// If a proplist is not static, replace it with a static proplist and replace all instances
2016-10-01 03:25:28 +00:00
// Place references to all proplists made static in the given value array
C4PropListStatic * FreezeAndMakeStaticRecursively ( std : : vector < C4Value > * prop_lists , const C4PropListStatic * parent = nullptr , C4String * key = nullptr ) ;
2016-08-27 05:12:08 +00:00
2011-03-26 22:59:35 +00:00
virtual void Denumerate ( C4ValueNumbers * ) ;
2009-05-19 22:12:11 +00:00
virtual ~ C4PropList ( ) ;
2009-04-03 19:06:29 +00:00
2011-03-26 22:59:35 +00:00
void CompileFunc ( StdCompiler * pComp , C4ValueNumbers * ) ;
2016-08-27 05:12:08 +00:00
void AppendDataString ( StdStrBuf * out , const char * delim , int depth = 3 , bool ignore_reference_parent = false ) const ;
2017-02-17 19:28:05 +00:00
StdStrBuf ToJSON ( int depth = 10 , bool ignore_reference_parent = false ) const ;
2016-07-13 21:18:08 +00:00
std : : vector < C4String * > GetSortedLocalProperties ( bool add_prototype = true ) const ;
2016-04-17 02:02:24 +00:00
std : : vector < C4String * > GetSortedLocalProperties ( const char * prefix , const C4PropList * ignore_overridden ) const ;
2016-08-02 05:06:24 +00:00
std : : vector < C4String * > GetUnsortedProperties ( const char * prefix , C4PropList * ignore_parent = nullptr ) const ;
2016-06-19 04:08:09 +00:00
std : : vector < C4String * > GetSortedProperties ( const char * prefix , C4PropList * ignore_parent = nullptr ) const ;
2009-05-19 22:12:11 +00:00
2010-09-10 21:01:30 +00:00
bool operator = = ( const C4PropList & b ) const ;
2011-02-06 21:30:31 +00:00
# ifdef _DEBUG
static C4Set < C4PropList * > PropLists ;
# endif
2010-09-10 21:01:30 +00:00
2010-03-28 17:58:21 +00:00
protected :
2017-05-07 11:50:00 +00:00
C4PropList ( C4PropList * prototype = nullptr ) ;
2013-02-04 21:27:04 +00:00
void ClearRefs ( ) { while ( FirstRef ) FirstRef - > Set0 ( ) ; }
2010-03-21 23:40:03 +00:00
2010-03-28 17:58:21 +00:00
private :
2013-02-04 21:27:04 +00:00
void AddRef ( C4Value * pRef ) ;
void DelRef ( const C4Value * pRef , C4Value * pNextRef ) ;
2017-05-07 11:50:00 +00:00
C4Value * FirstRef { nullptr } ; // No-Save
2010-10-17 20:13:12 +00:00
C4Set < C4Property > Properties ;
2013-03-24 17:10:16 +00:00
C4Value prototype ;
2017-05-07 11:50:00 +00:00
bool constant { false } ; // if true, this proplist is not changeable
2013-02-04 21:27:04 +00:00
friend class C4Value ;
2012-05-27 22:31:55 +00:00
friend class C4ScriptHost ;
2010-12-06 18:04:32 +00:00
public :
2017-05-07 11:50:00 +00:00
int32_t Status { 1 } ;
2013-12-07 18:41:34 +00:00
class Iterator
{
private :
std : : shared_ptr < std : : vector < const C4Property * > > properties ;
std : : vector < const C4Property * > : : iterator iter ;
// needed when constructing the iterator
// adds a property or overwrites existing property with same name
void AddProperty ( const C4Property * prop ) ;
void Reserve ( size_t additionalAmount ) ;
// Initializes internal iterator. Needs to be called before actually using the iterator.
void Init ( ) ;
public :
2017-05-07 11:50:00 +00:00
Iterator ( ) : properties ( nullptr ) { }
2013-12-07 18:41:34 +00:00
const C4Property * operator * ( ) const { return * iter ; }
const C4Property * operator - > ( ) const { return * iter ; }
void operator + + ( ) { + + iter ; } ;
void operator + + ( int ) { operator + + ( ) ; }
bool operator = = ( const Iterator & other ) const
{
2017-05-07 11:50:00 +00:00
if ( ( properties = = nullptr | | iter = = properties - > end ( ) ) & & ( other . properties = = nullptr | | other . iter = = other . properties - > end ( ) ) )
2013-12-07 18:41:34 +00:00
return true ;
return properties = = other . properties & & iter = = other . iter ;
}
bool operator ! = ( const Iterator & other ) const
{
return ! ( * this = = other ) ;
}
friend class C4PropList ;
} ;
// do not modify the proplist while iterating over it!
Iterator begin ( ) ;
Iterator end ( ) { return Iterator ( ) ; }
2009-05-19 22:12:11 +00:00
} ;
2016-05-21 10:56:57 +00:00
void CompileNewFunc ( C4PropList * & pStruct , StdCompiler * pComp , C4ValueNumbers * rPar ) ;
2011-03-26 22:59:35 +00:00
2011-03-05 02:32:51 +00:00
// Proplists that are created during a game and get saved in a savegame
2012-06-01 15:27:59 +00:00
// Examples: Objects, Effects
2010-03-28 17:58:21 +00:00
class C4PropListNumbered : public C4PropList
{
public :
2017-05-07 11:50:00 +00:00
int32_t Number { - 1 } ;
~ C4PropListNumbered ( ) override ;
2011-03-27 16:14:41 +00:00
void CompileFunc ( StdCompiler * pComp , C4ValueNumbers * numbers ) ;
2017-05-07 11:50:00 +00:00
C4PropListNumbered * GetPropListNumbered ( ) override ;
bool IsNumbered ( ) const override { return true ; }
2011-03-05 02:32:51 +00:00
static C4PropList * GetByNumber ( int32_t iNumber ) ; // pointer by number
2011-02-06 00:59:49 +00:00
static bool CheckPropList ( C4PropList * ) ; // sanity check: true when the proplist is in the list and not a stale pointer
2011-03-27 16:14:41 +00:00
static void SetEnumerationIndex ( int32_t iMaxObjectNumber ) ;
2011-03-05 02:32:51 +00:00
static int32_t GetEnumerationIndex ( ) { return EnumerationIndex ; }
static void ResetEnumerationIndex ( ) ;
2013-12-15 14:46:18 +00:00
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 ( ) ;
2015-08-21 00:19:38 +00:00
static void ClearNumberedPropLists ( ) ; // empty all properties in numbered prop lists. Used on game clear to ensure prop lists with circular references get cleared.
2010-12-19 23:13:56 +00:00
protected :
2017-05-07 11:50:00 +00:00
C4PropListNumbered ( C4PropList * prototype = nullptr ) ;
2013-12-15 14:46:18 +00:00
void AcquireNumber ( ) ; // acquire a number and add to internal list
void ClearNumber ( ) ; // clear number and remove from internal list
2011-03-05 02:32:51 +00:00
static C4Set < C4PropListNumbered * > PropLists ;
2013-12-15 14:46:18 +00:00
static std : : vector < C4PropListNumbered * > ShelvedPropLists ; // temporary storage for existing proplists while a new section loaded
2011-03-05 02:32:51 +00:00
static int32_t EnumerationIndex ;
friend class C4Game ;
2013-02-04 21:27:04 +00:00
friend class C4GameObjects ;
2010-12-19 23:13:56 +00:00
} ;
2011-03-05 02:32:51 +00:00
// Proplists created by script at runtime
2011-03-27 16:14:41 +00:00
class C4PropListScript : public C4PropList
2010-12-19 23:13:56 +00:00
{
public :
2017-05-07 11:50:00 +00:00
C4PropListScript ( C4PropList * prototype = nullptr ) : C4PropList ( prototype ) { PropLists . Add ( this ) ; }
~ C4PropListScript ( ) override { PropLists . Remove ( this ) ; }
bool Delete ( ) override { return true ; }
2015-08-21 00:19:38 +00:00
static void ClearScriptPropLists ( ) ; // empty all properties in script-created prop lists. Used on game clear to ensure prop lists with circular references get cleared.
protected :
static C4Set < C4PropListScript * > PropLists ;
2010-03-21 23:40:03 +00:00
} ;
2012-06-01 15:27:59 +00:00
// PropLists declared in the game data
// examples: Definitions, local variable initializers
class C4PropListStatic : public C4PropList
{
public :
C4PropListStatic ( C4PropList * prototype , const C4PropListStatic * parent , C4String * key ) :
C4PropList ( prototype ) , Parent ( parent ) , ParentKeyName ( key ) { }
2017-05-07 11:50:00 +00:00
~ C4PropListStatic ( ) override = default ;
bool Delete ( ) override { return true ; }
C4PropListStatic * IsStatic ( ) override { return this ; }
2012-06-01 15:27:59 +00:00
void RefCompileFunc ( StdCompiler * pComp , C4ValueNumbers * numbers ) const ;
2012-05-08 00:24:43 +00:00
StdStrBuf GetDataString ( ) const ;
2017-05-07 11:50:00 +00:00
const char * GetName ( ) const override ;
2016-05-12 16:41:05 +00:00
const C4PropListStatic * GetParent ( ) const { return Parent ; }
2014-04-20 20:05:50 +00:00
C4String * GetParentKeyName ( ) { return ParentKeyName ; }
2012-06-01 15:27:59 +00:00
protected :
const C4PropListStatic * Parent ;
C4RefCntPointer < C4String > ParentKeyName ; // property in parent this proplist was created in
} ;
2010-03-21 23:40:03 +00:00
2013-03-27 20:48:18 +00:00
// static PropList of which another class owns the pointer
class C4PropListStaticMember : public C4PropListStatic
{
public :
C4PropListStaticMember ( C4PropList * prototype , const C4PropListStatic * parent , C4String * key ) :
C4PropListStatic ( prototype , parent , key ) { }
2017-05-07 11:50:00 +00:00
bool Delete ( ) override { return false ; }
2013-03-27 20:48:18 +00:00
} ;
2009-05-19 22:12:11 +00:00
# endif // C4PROPLIST_H