mirror of
https://github.com/thug1src/thug.git
synced 2025-01-22 05:43:47 +00:00
2081 lines
57 KiB
C++
2081 lines
57 KiB
C++
///////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// struct.cpp KSH 22 Oct 2001
|
|
//
|
|
// CStruct class member functions.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <gel/scripting/struct.h>
|
|
#include <gel/scripting/checksum.h>
|
|
#include <gel/scripting/component.h>
|
|
#include <gel/scripting/string.h>
|
|
#include <gel/scripting/vecpair.h>
|
|
#include <gel/scripting/array.h>
|
|
#include <gel/scripting/symboltable.h>
|
|
#include <core/crc.h>
|
|
#include <core/math.h>
|
|
#include <core/math/vector.h>
|
|
|
|
|
|
//#define __DEBUG_STRUCT_ALLOCS
|
|
|
|
// This does technically cause a cyclic dependency, but what the heck, it's only needed
|
|
// for some debugging. (Making the Get function print the contents of the struct in
|
|
// the event of not finding the required parameter)
|
|
#include <gel/scripting/utils.h>
|
|
|
|
DefinePoolableClass(Script::CStruct);
|
|
|
|
namespace Script
|
|
{
|
|
|
|
#ifdef __DEBUG_STRUCT_ALLOCS
|
|
#define MAX_LAST 200
|
|
static int head = 0;
|
|
static bool init_last = true;
|
|
static CStruct * last[MAX_LAST];
|
|
#endif
|
|
|
|
void DumpLastStructs()
|
|
{
|
|
#ifdef __DEBUG_STRUCT_ALLOCS
|
|
for (int i=0;i<MAX_LAST;i++)
|
|
{
|
|
if (last[i])
|
|
{
|
|
printf ("Final Structure %d\n",i);
|
|
PrintContents(last[i]);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
// Deletes any entity pointed to by p_comp, so that p_comp can safely be deleted afterwards.
|
|
void CleanUpComponent(CComponent *p_comp)
|
|
{
|
|
Dbg_MsgAssert(p_comp,("NULL p_comp"));
|
|
|
|
switch (p_comp->mType)
|
|
{
|
|
case ESYMBOLTYPE_STRING:
|
|
case ESYMBOLTYPE_LOCALSTRING:
|
|
if (p_comp->mpString)
|
|
{
|
|
DeleteString(p_comp->mpString);
|
|
}
|
|
break;
|
|
case ESYMBOLTYPE_PAIR:
|
|
if (p_comp->mpPair)
|
|
{
|
|
delete p_comp->mpPair;
|
|
}
|
|
break;
|
|
case ESYMBOLTYPE_VECTOR:
|
|
if (p_comp->mpVector)
|
|
{
|
|
delete p_comp->mpVector;
|
|
}
|
|
break;
|
|
case ESYMBOLTYPE_STRUCTURE:
|
|
if (p_comp->mpStructure)
|
|
{
|
|
delete p_comp->mpStructure;
|
|
}
|
|
break;
|
|
case ESYMBOLTYPE_ARRAY:
|
|
if (p_comp->mpArray)
|
|
{
|
|
CleanUpArray(p_comp->mpArray);
|
|
delete p_comp->mpArray;
|
|
}
|
|
break;
|
|
case ESYMBOLTYPE_QSCRIPT:
|
|
if (p_comp->mpScript)
|
|
{
|
|
Mem::Free(p_comp->mpScript);
|
|
}
|
|
p_comp->mScriptSize=0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
// This will zero the union, which includes all the above pointers.
|
|
p_comp->mUnion=0;
|
|
|
|
p_comp->mType=ESYMBOLTYPE_NONE;
|
|
}
|
|
|
|
// Copies the contents of p_source into p_dest, but without copying any pointers over.
|
|
// Eg, if p_source contains an array, a new array will be created for p_dest.
|
|
void CopyComponent(CComponent *p_dest, const CComponent *p_source)
|
|
{
|
|
Dbg_MsgAssert(p_dest,("NULL p_dest"));
|
|
Dbg_MsgAssert(p_source,("NULL p_source"));
|
|
|
|
// Make sure p_dest is cleaned up first.
|
|
if (p_dest->mUnion) // This 'if' is just a small speed optimization to avoid an unnecessay call
|
|
{
|
|
CleanUpComponent(p_dest);
|
|
}
|
|
|
|
p_dest->mType=p_source->mType;
|
|
p_dest->mNameChecksum=p_source->mNameChecksum;
|
|
|
|
switch (p_source->mType)
|
|
{
|
|
case ESYMBOLTYPE_NONE:
|
|
break;
|
|
|
|
case ESYMBOLTYPE_INTEGER:
|
|
case ESYMBOLTYPE_FLOAT:
|
|
case ESYMBOLTYPE_NAME:
|
|
p_dest->mUnion=p_source->mUnion;
|
|
break;
|
|
|
|
case ESYMBOLTYPE_STRING:
|
|
Dbg_MsgAssert(p_source->mpString,("NULL p_source->mpString ?"));
|
|
p_dest->mpString=CreateString(p_source->mpString);
|
|
break;
|
|
|
|
case ESYMBOLTYPE_LOCALSTRING:
|
|
Dbg_MsgAssert(p_source->mpLocalString,("NULL p_source->mpLocalString ?"));
|
|
p_dest->mpLocalString=CreateString(p_source->mpLocalString);
|
|
break;
|
|
|
|
case ESYMBOLTYPE_PAIR:
|
|
Dbg_MsgAssert(p_source->mpPair,("NULL p_source->mpPair ?"));
|
|
p_dest->mpPair=new CPair;
|
|
p_dest->mpPair->mX=p_source->mpPair->mX;
|
|
p_dest->mpPair->mY=p_source->mpPair->mY;
|
|
break;
|
|
|
|
case ESYMBOLTYPE_VECTOR:
|
|
Dbg_MsgAssert(p_source->mpVector,("NULL p_source->mpVector ?"));
|
|
p_dest->mpVector=new CVector;
|
|
p_dest->mpVector->mX=p_source->mpVector->mX;
|
|
p_dest->mpVector->mY=p_source->mpVector->mY;
|
|
p_dest->mpVector->mZ=p_source->mpVector->mZ;
|
|
break;
|
|
|
|
case ESYMBOLTYPE_STRUCTURE:
|
|
Dbg_MsgAssert(p_source->mpStructure,("NULL p_source->mpStructure ?"));
|
|
p_dest->mpStructure=new CStruct;
|
|
*p_dest->mpStructure=*p_source->mpStructure;
|
|
break;
|
|
|
|
case ESYMBOLTYPE_ARRAY:
|
|
Dbg_MsgAssert(p_source->mpArray,("NULL p_source->mpArray ?"));
|
|
p_dest->mpArray=new CArray;
|
|
CopyArray(p_dest->mpArray,p_source->mpArray);
|
|
break;
|
|
|
|
case ESYMBOLTYPE_QSCRIPT:
|
|
{
|
|
Dbg_MsgAssert(p_source->mpScript,("NULL p_source->mpScript ?"));
|
|
|
|
// Allocate a buffer off the script heap
|
|
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().ScriptHeap());
|
|
Dbg_MsgAssert(p_source->mScriptSize,("Zero source script size"));
|
|
p_dest->mpScript=(uint8*)Mem::Malloc(p_source->mScriptSize);
|
|
p_dest->mScriptSize=p_source->mScriptSize;
|
|
Mem::Manager::sHandle().PopContext();
|
|
|
|
// Copy the script into the new buffer.
|
|
const uint8 *p_from=p_source->mpScript;
|
|
uint8 *p_to=p_dest->mpScript;
|
|
for (uint32 i=0; i<p_source->mScriptSize; ++i)
|
|
{
|
|
*p_to++=*p_from++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
Dbg_MsgAssert(0,("Bad p_source->mType of '%s'",GetTypeName(p_source->mType)));
|
|
break;
|
|
}
|
|
}
|
|
|
|
// This will run through all the elements of p_array deleting any entities pointed to by it.
|
|
// It will also call the array's Clear function to delete the array buffer, so it is not
|
|
// necessary to call Clear again after calling this.
|
|
void CleanUpArray(CArray *p_array)
|
|
{
|
|
Dbg_MsgAssert(p_array,("NULL p_array"));
|
|
|
|
ESymbolType type=p_array->GetType();
|
|
uint32 size=p_array->GetSize();
|
|
uint32 *p_array_data=p_array->GetArrayPointer();
|
|
if (size)
|
|
{
|
|
Dbg_MsgAssert(p_array_data,("NULL p_array_data ?"));
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
case ESYMBOLTYPE_NONE:
|
|
case ESYMBOLTYPE_INTEGER:
|
|
case ESYMBOLTYPE_FLOAT:
|
|
case ESYMBOLTYPE_NAME:
|
|
// Nothing to delete
|
|
break;
|
|
|
|
case ESYMBOLTYPE_STRING:
|
|
case ESYMBOLTYPE_LOCALSTRING:
|
|
{
|
|
char **pp_string=(char**)p_array_data;
|
|
for (uint32 i=0; i<size; ++i)
|
|
{
|
|
if (*pp_string)
|
|
{
|
|
DeleteString(*pp_string);
|
|
*pp_string=NULL;
|
|
}
|
|
++pp_string;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ESYMBOLTYPE_PAIR:
|
|
{
|
|
CPair **pp_pair=(CPair**)p_array_data;
|
|
for (uint32 i=0; i<size; ++i)
|
|
{
|
|
if (*pp_pair)
|
|
{
|
|
delete *pp_pair;
|
|
*pp_pair=NULL;
|
|
}
|
|
++pp_pair;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ESYMBOLTYPE_VECTOR:
|
|
{
|
|
CVector **pp_vector=(CVector**)p_array_data;
|
|
for (uint32 i=0; i<size; ++i)
|
|
{
|
|
if (*pp_vector)
|
|
{
|
|
delete *pp_vector;
|
|
*pp_vector=NULL;
|
|
}
|
|
++pp_vector;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ESYMBOLTYPE_STRUCTURE:
|
|
{
|
|
CStruct **pp_structure=(CStruct**)p_array_data;
|
|
for (uint32 i=0; i<size; ++i)
|
|
{
|
|
if (*pp_structure)
|
|
{
|
|
delete *pp_structure;
|
|
*pp_structure=NULL;
|
|
}
|
|
++pp_structure;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ESYMBOLTYPE_ARRAY:
|
|
{
|
|
CArray **pp_array=(CArray**)p_array_data;
|
|
for (uint32 i=0; i<size; ++i)
|
|
{
|
|
if (*pp_array)
|
|
{
|
|
CleanUpArray(*pp_array);
|
|
delete *pp_array;
|
|
*pp_array=NULL;
|
|
}
|
|
++pp_array;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
Dbg_MsgAssert(0,("Bad CArray::m_type of '%s'",GetTypeName(type)));
|
|
break;
|
|
}
|
|
|
|
// This will delete the actual array buffer too.
|
|
p_array->Clear();
|
|
}
|
|
|
|
// Copies the contents of p_source into p_dest. No pointers will be copied over, new entities will be
|
|
// created for p_dest. So p_source can safely be deleted afterwards.
|
|
void CopyArray(CArray *p_dest, const CArray *p_source)
|
|
{
|
|
Dbg_MsgAssert(p_source,("NULL p_source ?"));
|
|
Dbg_MsgAssert(p_dest,("NULL p_dest ?"));
|
|
|
|
// Make sure that p_dest is cleaned up first.
|
|
CleanUpArray(p_dest);
|
|
|
|
ESymbolType type=p_source->GetType();
|
|
uint32 size=p_source->GetSize();
|
|
|
|
p_dest->SetSizeAndType(size,type);
|
|
|
|
if (size==0)
|
|
{
|
|
// Finished.
|
|
return;
|
|
}
|
|
|
|
uint32 *p_source_array=p_source->GetArrayPointer();
|
|
Dbg_MsgAssert(p_source_array,("NULL p_source_array ?"));
|
|
|
|
uint32 *p_dest_array=p_dest->GetArrayPointer();
|
|
Dbg_MsgAssert(p_dest_array,("NULL p_dest_array ?"));
|
|
|
|
switch (type)
|
|
{
|
|
case ESYMBOLTYPE_INTEGER:
|
|
case ESYMBOLTYPE_FLOAT:
|
|
case ESYMBOLTYPE_NAME:
|
|
{
|
|
uint32 *p_source_word=p_source_array;
|
|
uint32 *p_dest_word=p_dest_array;
|
|
for (uint32 i=0; i<size; ++i)
|
|
{
|
|
*p_dest_word++=*p_source_word++;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ESYMBOLTYPE_STRING:
|
|
case ESYMBOLTYPE_LOCALSTRING:
|
|
{
|
|
char **pp_source_string=(char**)p_source_array;
|
|
char **pp_dest_string=(char**)p_dest_array;
|
|
for (uint32 i=0; i<size; ++i)
|
|
{
|
|
char *p_source_string=*pp_source_string;
|
|
if (p_source_string)
|
|
{
|
|
// Create a new copy of the source string.
|
|
*pp_dest_string=CreateString(p_source_string);
|
|
}
|
|
++pp_source_string;
|
|
++pp_dest_string;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ESYMBOLTYPE_PAIR:
|
|
{
|
|
CPair **pp_source_pair=(CPair**)p_source_array;
|
|
CPair **pp_dest_pair=(CPair**)p_dest_array;
|
|
for (uint32 i=0; i<size; ++i)
|
|
{
|
|
CPair *p_source_pair=*pp_source_pair;
|
|
if (p_source_pair)
|
|
{
|
|
CPair *p_new_pair=new CPair;
|
|
// The default assignement operator works OK for CPair since it contains no pointers.
|
|
*p_new_pair=*p_source_pair;
|
|
*pp_dest_pair=p_new_pair;
|
|
}
|
|
++pp_source_pair;
|
|
++pp_dest_pair;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ESYMBOLTYPE_VECTOR:
|
|
{
|
|
CVector **pp_source_vector=(CVector**)p_source_array;
|
|
CVector **pp_dest_vector=(CVector**)p_dest_array;
|
|
for (uint32 i=0; i<size; ++i)
|
|
{
|
|
CVector *p_source_vector=*pp_source_vector;
|
|
if (p_source_vector)
|
|
{
|
|
CVector *p_new_vector=new CVector;
|
|
// The default assignement operator works OK for CVector since it contains no pointers.
|
|
*p_new_vector=*p_source_vector;
|
|
*pp_dest_vector=p_new_vector;
|
|
}
|
|
++pp_source_vector;
|
|
++pp_dest_vector;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ESYMBOLTYPE_STRUCTURE:
|
|
{
|
|
CStruct **pp_source_structure=(CStruct**)p_source_array;
|
|
CStruct **pp_dest_structure=(CStruct**)p_dest_array;
|
|
for (uint32 i=0; i<size; ++i)
|
|
{
|
|
CStruct *p_source_structure=*pp_source_structure;
|
|
if (p_source_structure)
|
|
{
|
|
CStruct *p_new_structure=new CStruct;
|
|
// Copy the contents using CStruct's assignement operator.
|
|
*p_new_structure=*p_source_structure;
|
|
*pp_dest_structure=p_new_structure;
|
|
}
|
|
++pp_source_structure;
|
|
++pp_dest_structure;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ESYMBOLTYPE_ARRAY:
|
|
{
|
|
CArray **pp_source_carray=(CArray**)p_source_array;
|
|
CArray **pp_dest_carray=(CArray**)p_dest_array;
|
|
for (uint32 i=0; i<size; ++i)
|
|
{
|
|
CArray *p_source_carray=*pp_source_carray;
|
|
if (p_source_carray)
|
|
{
|
|
CArray *p_new_carray=new CArray;
|
|
// No assignement operator defined for CArray (cos it would cause cyclic dependencies)
|
|
// so need to use CopyArray.
|
|
CopyArray(p_new_carray,p_source_carray);
|
|
*pp_dest_carray=p_new_carray;
|
|
}
|
|
++pp_source_carray;
|
|
++pp_dest_carray;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
Dbg_MsgAssert(0,("Bad source array type of '%s'",GetTypeName(type)));
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Initialises all the members.
|
|
void CStruct::init()
|
|
{
|
|
mp_components=NULL;
|
|
|
|
#ifdef __NOPT_ASSERT__
|
|
mp_parent_script=NULL;
|
|
#endif
|
|
|
|
#ifdef __DEBUG_STRUCT_ALLOCS
|
|
if (init_last)
|
|
{
|
|
for (int i=0;i<MAX_LAST;i++)
|
|
{
|
|
last[i] = NULL;
|
|
}
|
|
head = 0;
|
|
init_last = 0;
|
|
}
|
|
|
|
last[head++] = this;
|
|
if (head == MAX_LAST)
|
|
head = 0;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
static int x = 0;
|
|
static int max = 18000;
|
|
|
|
// Usual constructor.
|
|
CStruct::CStruct()
|
|
{
|
|
// Initialise everything. CStruct is not derived from CClass so we don't get
|
|
// the auro-zeroing.
|
|
init();
|
|
|
|
#if 0
|
|
// For tracking down Struct leaks
|
|
// when we go over a certain maximum, start printing out the callstack of the structs that take us over that max
|
|
if (CStruct::SGetNumUsedItems()>max)
|
|
{
|
|
max = CStruct::SGetNumUsedItems();
|
|
DumpUnwindStack(20,0);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Copy constructor.
|
|
CStruct::CStruct( const CStruct& rhs )
|
|
{
|
|
// Initialise everything. CStruct is not derived from CClass so we don't get
|
|
// the auro-zeroing.
|
|
init();
|
|
|
|
// use the overridden assignment operator
|
|
*this = rhs;
|
|
|
|
x++;
|
|
if (x>max)
|
|
{
|
|
max = x;
|
|
// DumpUnwindStack(20,0);
|
|
}
|
|
}
|
|
|
|
// Assignement operator.
|
|
CStruct& CStruct::operator=( const CStruct& rhs )
|
|
{
|
|
// don't try to assign to yourself
|
|
if ( &rhs == this )
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
this->Clear();
|
|
*this+=rhs;
|
|
|
|
return *this;
|
|
}
|
|
|
|
// This will merge the contents of the rhs into this structure.
|
|
// Functionally the same as the old AppendStructure function, except AppendStructure would accept a NULL pointer.
|
|
CStruct& CStruct::operator+=( const CStruct& rhs )
|
|
{
|
|
CComponent *p_source_component=rhs.mp_components;
|
|
while (p_source_component)
|
|
{
|
|
CComponent *p_new=new CComponent;
|
|
CopyComponent(p_new, p_source_component);
|
|
AddComponent(p_new);
|
|
p_source_component=p_source_component->mpNext;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// TODO: Remove at some point. Provided for back-compatibility.
|
|
void CStruct::AppendStructure(const CStruct *p_struct)
|
|
{
|
|
if (p_struct)
|
|
{
|
|
*this+=*p_struct;
|
|
}
|
|
}
|
|
|
|
// Written specially for use by CScriptDebugger::transmit_cscript_list.
|
|
// This will append the passed component to the structure's list of components
|
|
// and will leave the existing list untouched, ie it will not remove any of the same name.
|
|
// This is so that the script debugger code can store a list of CScript instances into a structure
|
|
// even though many may have the same name.
|
|
void CStruct::AppendComponentPointer(CComponent *p_comp)
|
|
{
|
|
CComponent *p_last=NULL;
|
|
CComponent *p_scan=mp_components;
|
|
|
|
// Find p_last, the last component in the list.
|
|
while (p_scan)
|
|
{
|
|
p_last=p_scan;
|
|
p_scan=p_scan->mpNext;
|
|
}
|
|
|
|
// Tag p_comp onto the end of the list.
|
|
if (p_last)
|
|
{
|
|
p_last->mpNext=p_comp;
|
|
}
|
|
else
|
|
{
|
|
mp_components=p_comp;
|
|
}
|
|
p_comp->mpNext=NULL;
|
|
}
|
|
|
|
CStruct::~CStruct()
|
|
{
|
|
|
|
#ifdef __DEBUG_STRUCT_ALLOCS
|
|
for (int i=0;i<MAX_LAST;i++)
|
|
{
|
|
if (last[i] == this)
|
|
{
|
|
// step the head back to the last entry added
|
|
head--;
|
|
if (head <0)
|
|
{
|
|
head = MAX_LAST-1;
|
|
}
|
|
// if the head is not the entry we just removed
|
|
// then copy the head into this slot
|
|
if (i!=head)
|
|
{
|
|
last[i] = last[head];
|
|
}
|
|
// and clear the head, which now contains the entry we deleted
|
|
last[head] = NULL;
|
|
// and we don't need to iterate no more
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
Clear();
|
|
}
|
|
|
|
// Deletes all components, deleting any arrays or structures referenced by the components.
|
|
void CStruct::Clear()
|
|
{
|
|
CComponent *p_comp=mp_components;
|
|
while (p_comp)
|
|
{
|
|
CComponent *p_next=p_comp->mpNext;
|
|
// Note: The CComponent destructor cannot clean up, because that would cause cyclic dependencies.
|
|
CleanUpComponent(p_comp);
|
|
delete p_comp;
|
|
p_comp=p_next;
|
|
}
|
|
mp_components=NULL;
|
|
}
|
|
|
|
void CStruct::RemoveComponent(uint32 nameChecksum)
|
|
{
|
|
CComponent *p_last=NULL;
|
|
CComponent *p_comp=mp_components;
|
|
while (p_comp)
|
|
{
|
|
CComponent *p_next=p_comp->mpNext;
|
|
|
|
if (p_comp->mNameChecksum==nameChecksum)
|
|
{
|
|
// p_comp must be removed.
|
|
|
|
// Unlink it.
|
|
if (p_last)
|
|
{
|
|
p_last->mpNext=p_next;
|
|
}
|
|
else
|
|
{
|
|
Dbg_MsgAssert(p_comp==mp_components,("Eh ? p_comp!=mp_components ??"));
|
|
mp_components=p_next;
|
|
}
|
|
|
|
// Note: The CComponent destructor cannot clean up, because that would cause cyclic dependencies.
|
|
CleanUpComponent(p_comp);
|
|
delete p_comp;
|
|
|
|
// Carries on, in case there is more than one component with the given name.
|
|
p_comp=p_next;
|
|
}
|
|
else
|
|
{
|
|
p_last=p_comp;
|
|
p_comp=p_next;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CStruct::RemoveComponent(const char *p_name)
|
|
{
|
|
RemoveComponent(Crc::GenerateCRCFromString(p_name));
|
|
}
|
|
|
|
// Same as RemoveComponent except the type must matched the passed type too.
|
|
// Used by eval.cpp when subtracting a structure from another structure.
|
|
void CStruct::RemoveComponentWithType(uint32 nameChecksum, uint8 type)
|
|
{
|
|
CComponent *p_last=NULL;
|
|
CComponent *p_comp=mp_components;
|
|
while (p_comp)
|
|
{
|
|
CComponent *p_next=p_comp->mpNext;
|
|
|
|
if (p_comp->mNameChecksum==nameChecksum && p_comp->mType==type)
|
|
{
|
|
// p_comp must be removed.
|
|
|
|
// Unlink it.
|
|
if (p_last)
|
|
{
|
|
p_last->mpNext=p_next;
|
|
}
|
|
else
|
|
{
|
|
Dbg_MsgAssert(p_comp==mp_components,("Eh ? p_comp!=mp_components ??"));
|
|
mp_components=p_next;
|
|
}
|
|
|
|
// Note: The CComponent destructor cannot clean up, because that would cause cyclic dependencies.
|
|
CleanUpComponent(p_comp);
|
|
delete p_comp;
|
|
|
|
// Carries on, in case there is more than one component with the given name.
|
|
p_comp=p_next;
|
|
}
|
|
else
|
|
{
|
|
p_last=p_comp;
|
|
p_comp=p_next;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CStruct::RemoveComponentWithType(const char *p_name, uint8 type)
|
|
{
|
|
RemoveComponentWithType(Crc::GenerateCRCFromString(p_name),type);
|
|
}
|
|
|
|
// Note: Logical inconsistencies that could be an issue later maybe:
|
|
// If the unnamed-name resolves to a global structure, should the component still be removed?
|
|
// If there is a referenced global structure, should it have any of the specified flag removed
|
|
// too, and so on recursively? (probably not, since global structures should remain constant)
|
|
void CStruct::RemoveFlag(uint32 checksum)
|
|
{
|
|
CComponent *p_last=NULL;
|
|
CComponent *p_comp=mp_components;
|
|
while (p_comp)
|
|
{
|
|
CComponent *p_next=p_comp->mpNext;
|
|
|
|
if (p_comp->mNameChecksum==0 && p_comp->mChecksum==checksum)
|
|
{
|
|
// p_comp must be removed.
|
|
|
|
// Unlink it.
|
|
if (p_last)
|
|
{
|
|
p_last->mpNext=p_next;
|
|
}
|
|
else
|
|
{
|
|
Dbg_MsgAssert(p_comp==mp_components,("Eh ? p_comp!=mp_components ??"));
|
|
mp_components=p_next;
|
|
}
|
|
|
|
// Note: The CComponent destructor cannot clean up, because that would cause cyclic dependencies.
|
|
CleanUpComponent(p_comp);
|
|
// Note: All the CleanUpComponent call will have done will be to zero the union,
|
|
// cos a flag component does not contain any pointers that need deleting.
|
|
// So I could have just set p_comp->mChecksum to 0 instead. Just calling
|
|
// CleanUpComponent for consistency.
|
|
delete p_comp;
|
|
|
|
// Carries on, in case there is more than one flag with the given name.
|
|
// There shouldn't be, but check anyway.
|
|
p_comp=p_next;
|
|
}
|
|
else
|
|
{
|
|
p_last=p_comp;
|
|
p_comp=p_next;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CStruct::RemoveFlag(const char *p_name)
|
|
{
|
|
RemoveFlag(Crc::GenerateCRCFromString(p_name));
|
|
}
|
|
|
|
// Returns true if the structure contains no components.
|
|
bool CStruct::IsEmpty() const
|
|
{
|
|
return mp_components==NULL;
|
|
}
|
|
|
|
// Searches for a component with the given name, but will also recurse into substructures.
|
|
// Used when resolving the <ParamName> syntax.
|
|
CComponent *CStruct::FindNamedComponentRecurse(uint32 nameChecksum) const
|
|
{
|
|
CComponent *p_found=NULL;
|
|
|
|
CComponent *p_comp=mp_components;
|
|
while (p_comp)
|
|
{
|
|
if (p_comp->mNameChecksum==nameChecksum)
|
|
{
|
|
p_found=p_comp;
|
|
}
|
|
else if (p_comp->mNameChecksum==0 && p_comp->mType==ESYMBOLTYPE_NAME)
|
|
{
|
|
CSymbolTableEntry *p_entry=Resolve(p_comp->mChecksum);
|
|
if (p_entry && p_entry->mType==ESYMBOLTYPE_STRUCTURE)
|
|
{
|
|
Dbg_MsgAssert(p_entry->mpStructure,("NULL p_entry->mpStructure"));
|
|
CComponent *p_new_found=p_entry->mpStructure->FindNamedComponentRecurse(nameChecksum);
|
|
if (p_new_found)
|
|
{
|
|
p_found=p_new_found;
|
|
}
|
|
}
|
|
}
|
|
p_comp=p_comp->mpNext;
|
|
}
|
|
|
|
return p_found;
|
|
}
|
|
|
|
// If passed NULL this will return the first (leftmost) component.
|
|
// If passed non-NULL it return the next component (to the right)
|
|
// Returns NULL if the passed component is the last component.
|
|
CComponent *CStruct::GetNextComponent(CComponent *p_comp) const
|
|
{
|
|
if (p_comp==NULL)
|
|
{
|
|
return mp_components;
|
|
}
|
|
|
|
return p_comp->mpNext;
|
|
}
|
|
|
|
// This will copy the contents of this structure into p_dest, but in such a way that
|
|
// p_dest will contain no unnamed-structure references, they will all get expanded.
|
|
// This was added because sometimes one wants to step through each of the components of
|
|
// a structure using GetNextComponent, but GetNextComponent itself cannot recurse into
|
|
// unnamed structures, because when it reaches the end of one it won't know how to get back
|
|
// to the parent.
|
|
// So instead just create a new structure, copy the other structure into it using ExpandInto,
|
|
// then step through that using GetNextComponent, then delete the new structure once finished.
|
|
// It's a bit memory intensive, but saves having to write special code to resolve unnamed
|
|
// structures & recursing whenever one wants to scan through the components.
|
|
// Could be handy for other things later too.
|
|
// recursionCount is just to catch infinite recursion, so no need to pass it a value. (defaults to 0)
|
|
void CStruct::ExpandInto(CStruct *p_dest, int recursionCount) const
|
|
{
|
|
Dbg_MsgAssert(recursionCount<=20,("Possible infinite recursion of CStruct::ExpandInto! More than 20 recursions have occurred."));
|
|
Dbg_MsgAssert(p_dest,("NULL p_dest sent to ExpandInto"));
|
|
|
|
CComponent *p_comp=mp_components;
|
|
while (p_comp)
|
|
{
|
|
bool added_structure=false;
|
|
|
|
if (p_comp->mNameChecksum==0)
|
|
{
|
|
Dbg_MsgAssert(p_comp->mType!=ESYMBOLTYPE_STRUCTURE,("Unexpected unnamed structure in CStruct"));
|
|
|
|
if (p_comp->mType==ESYMBOLTYPE_NAME)
|
|
{
|
|
CSymbolTableEntry *p_global=Resolve(p_comp->mChecksum);
|
|
if (p_global && p_global->mType==ESYMBOLTYPE_STRUCTURE)
|
|
{
|
|
Dbg_MsgAssert(p_global->mpStructure,("NULL p_global->mpStructure"));
|
|
p_global->mpStructure->ExpandInto(p_dest,recursionCount+1);
|
|
added_structure=true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!added_structure)
|
|
{
|
|
CComponent *p_new_component=new CComponent;
|
|
CopyComponent(p_new_component,p_comp);
|
|
p_dest->AddComponent(p_new_component);
|
|
}
|
|
|
|
p_comp=p_comp->mpNext;
|
|
}
|
|
}
|
|
|
|
// Adds the component p_comp to the end of the list of components, removing any existing components
|
|
// that have the same name and type, and asserting if any components exist with the same name but different
|
|
// type.
|
|
// However, if p_comp is a flag (an un-named component of type ESYMBOLTYPE_NAME) then it will always add it,
|
|
// because otherwise we would not be able to have more than one flag in a structure.
|
|
//
|
|
// Note: Even two identical flags are allowed, because sometimes this is handy. For example I use a list
|
|
// of words in a structure as a way for Scott to represent trick button sequences (see airtricks.q) and
|
|
// sometimes two of the words might need to be identical.
|
|
//
|
|
// Another note: This function needs to be pretty fast because it will need to be called many times for
|
|
// each line of script executed. Optimize later.
|
|
//
|
|
void CStruct::AddComponent(CComponent *p_comp)
|
|
{
|
|
Dbg_MsgAssert(p_comp,("NULL p_comp"));
|
|
|
|
// Unnamed structure components are not allowed, because to support them would require
|
|
// modifying the search_for function. No need, since when structures are created from lists
|
|
// of tokens any substructures get expanded and added component by component at that stage.
|
|
// So in theory no components of type structure should get added.
|
|
Dbg_MsgAssert(!(p_comp->mNameChecksum==0 && p_comp->mType==ESYMBOLTYPE_STRUCTURE),("Tried to add an un-named structure component ..."));
|
|
|
|
Dbg_MsgAssert(p_comp->mType!=ESYMBOLTYPE_NONE,("Tried to add a structure component with no type, name='%s' ...",FindChecksumName(p_comp->mNameChecksum)));
|
|
|
|
CComponent *p_last=NULL;
|
|
CComponent *p_scan=mp_components;
|
|
bool remove=false;
|
|
|
|
while (p_scan)
|
|
{
|
|
if (p_scan->mNameChecksum==p_comp->mNameChecksum)
|
|
{
|
|
// Same name ...
|
|
|
|
remove=false;
|
|
|
|
if (p_scan->mType==p_comp->mType)
|
|
{
|
|
if (p_scan->mType==ESYMBOLTYPE_NAME &&
|
|
p_scan->mNameChecksum==0 &&
|
|
p_scan->mChecksum!=p_comp->mChecksum)
|
|
{
|
|
// Allow multiple un-named checksums if their values are different, because
|
|
// these are flags.
|
|
}
|
|
else
|
|
{
|
|
remove=true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Consider floats and ints to be the same type, so that x=3.1 overrides x=3 and vice versa
|
|
if ((p_scan->mType==ESYMBOLTYPE_FLOAT && p_comp->mType==ESYMBOLTYPE_INTEGER) ||
|
|
(p_scan->mType==ESYMBOLTYPE_INTEGER && p_comp->mType==ESYMBOLTYPE_FLOAT))
|
|
{
|
|
remove=true;
|
|
}
|
|
}
|
|
|
|
if (remove)
|
|
{
|
|
// Remove this component.
|
|
if (p_last)
|
|
{
|
|
p_last->mpNext=p_scan->mpNext;
|
|
CleanUpComponent(p_scan);
|
|
delete p_scan;
|
|
p_scan=p_last->mpNext;
|
|
}
|
|
else
|
|
{
|
|
mp_components=p_scan->mpNext;
|
|
CleanUpComponent(p_scan);
|
|
delete p_scan;
|
|
p_scan=mp_components;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Same name but different type.
|
|
// The old code would assert in this case, but the new code allows it.
|
|
// This is because there is no problem if a structure contains {x=7 x="Blaa"}
|
|
// Getting an integer called x from it would give 7, getting a string called x would give "Blaa"
|
|
// Also, it would allow {x=7 x=foo} where foo may be defined elsewhere to be a different integer,
|
|
// which is useful.
|
|
p_last=p_scan;
|
|
p_scan=p_scan->mpNext;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
p_last=p_scan;
|
|
p_scan=p_scan->mpNext;
|
|
}
|
|
}
|
|
|
|
// Now, p_last points to the last component in the list, and may be NULL.
|
|
// Tag p_comp onto the end of the list.
|
|
if (p_last)
|
|
{
|
|
p_last->mpNext=p_comp;
|
|
}
|
|
else
|
|
{
|
|
mp_components=p_comp;
|
|
}
|
|
p_comp->mpNext=NULL;
|
|
}
|
|
|
|
#ifdef __NOPT_ASSERT__
|
|
void CStruct::SetParentScript(CScript *p_parentScript)
|
|
{
|
|
mp_parent_script=p_parentScript;
|
|
}
|
|
|
|
CScript *CStruct::GetParentScript() const
|
|
{
|
|
return mp_parent_script;
|
|
}
|
|
#endif
|
|
|
|
|
|
void CStruct::AddString(uint32 nameChecksum, const char *p_string)
|
|
{
|
|
CComponent *p_new=new CComponent;
|
|
|
|
p_new->mNameChecksum=nameChecksum;
|
|
p_new->mType=ESYMBOLTYPE_STRING;
|
|
p_new->mpString=CreateString(p_string);
|
|
|
|
AddComponent(p_new);
|
|
}
|
|
|
|
void CStruct::AddString(const char *p_name, const char *p_string)
|
|
{
|
|
AddString(Crc::GenerateCRCFromString(p_name),p_string);
|
|
}
|
|
|
|
void CStruct::AddLocalString(uint32 nameChecksum, const char *p_string)
|
|
{
|
|
CComponent *p_new=new CComponent;
|
|
|
|
p_new->mNameChecksum=nameChecksum;
|
|
p_new->mType=ESYMBOLTYPE_LOCALSTRING;
|
|
p_new->mpString=CreateString(p_string);
|
|
|
|
AddComponent(p_new);
|
|
}
|
|
|
|
void CStruct::AddLocalString(const char *p_name, const char *p_string)
|
|
{
|
|
AddLocalString(Crc::GenerateCRCFromString(p_name),p_string);
|
|
}
|
|
|
|
void CStruct::AddInteger(uint32 nameChecksum, int integer)
|
|
{
|
|
CComponent *p_new=new CComponent;
|
|
|
|
p_new->mNameChecksum=nameChecksum;
|
|
p_new->mType=ESYMBOLTYPE_INTEGER;
|
|
p_new->mIntegerValue=integer;
|
|
|
|
AddComponent(p_new);
|
|
}
|
|
|
|
void CStruct::AddInteger(const char *p_name, int integer)
|
|
{
|
|
AddInteger(Crc::GenerateCRCFromString(p_name),integer);
|
|
}
|
|
|
|
void CStruct::AddFloat(uint32 nameChecksum, float float_val)
|
|
{
|
|
CComponent *p_new=new CComponent;
|
|
|
|
p_new->mNameChecksum=nameChecksum;
|
|
p_new->mType=ESYMBOLTYPE_FLOAT;
|
|
p_new->mFloatValue=float_val;
|
|
|
|
AddComponent(p_new);
|
|
}
|
|
|
|
void CStruct::AddFloat(const char *p_name, float float_val)
|
|
{
|
|
AddFloat(Crc::GenerateCRCFromString(p_name),float_val);
|
|
}
|
|
|
|
void CStruct::AddChecksum(uint32 nameChecksum, uint32 checksum)
|
|
{
|
|
CComponent *p_new=new CComponent;
|
|
|
|
p_new->mNameChecksum=nameChecksum;
|
|
p_new->mType=ESYMBOLTYPE_NAME;
|
|
p_new->mChecksum=checksum;
|
|
|
|
AddComponent(p_new);
|
|
}
|
|
|
|
void CStruct::AddChecksum(const char *p_name, uint32 checksum)
|
|
{
|
|
AddChecksum(Crc::GenerateCRCFromString(p_name),checksum);
|
|
}
|
|
|
|
void CStruct::AddVector(uint32 nameChecksum, float x, float y, float z)
|
|
{
|
|
CComponent *p_new=new CComponent;
|
|
|
|
p_new->mNameChecksum=nameChecksum;
|
|
p_new->mType=ESYMBOLTYPE_VECTOR;
|
|
p_new->mpVector=new CVector;
|
|
p_new->mpVector->mX=x;
|
|
p_new->mpVector->mY=y;
|
|
p_new->mpVector->mZ=z;
|
|
|
|
AddComponent(p_new);
|
|
}
|
|
|
|
void CStruct::AddVector(const char *p_name, float x, float y, float z)
|
|
{
|
|
AddVector(Crc::GenerateCRCFromString(p_name),x,y,z);
|
|
}
|
|
|
|
void CStruct::AddVector( uint32 nameChecksum, Mth::Vector vector )
|
|
{
|
|
AddVector( nameChecksum, vector.GetX(), vector.GetY(), vector.GetZ() );
|
|
}
|
|
|
|
void CStruct::AddVector( const char* p_name, Mth::Vector vector )
|
|
{
|
|
AddVector( Crc::GenerateCRCFromString( p_name ), vector.GetX(), vector.GetY(), vector.GetZ() );
|
|
}
|
|
|
|
void CStruct::AddPair(uint32 nameChecksum, float x, float y)
|
|
{
|
|
CComponent *p_new=new CComponent;
|
|
|
|
p_new->mNameChecksum=nameChecksum;
|
|
p_new->mType=ESYMBOLTYPE_PAIR;
|
|
p_new->mpPair=new CPair;
|
|
p_new->mpPair->mX=x;
|
|
p_new->mpPair->mY=y;
|
|
|
|
AddComponent(p_new);
|
|
}
|
|
|
|
void CStruct::AddPair(const char *p_name, float x, float y)
|
|
{
|
|
AddPair(Crc::GenerateCRCFromString(p_name),x,y);
|
|
}
|
|
|
|
// Creates a new array & copies in the contents of the passed array.
|
|
void CStruct::AddArray(uint32 nameChecksum, const CArray *p_array)
|
|
{
|
|
CComponent *p_new=new CComponent;
|
|
|
|
p_new->mNameChecksum=nameChecksum;
|
|
p_new->mType=ESYMBOLTYPE_ARRAY;
|
|
p_new->mpArray=new CArray;
|
|
CopyArray(p_new->mpArray,p_array);
|
|
|
|
AddComponent(p_new);
|
|
}
|
|
|
|
void CStruct::AddArray(const char *p_name, const CArray *p_array)
|
|
{
|
|
AddArray(Crc::GenerateCRCFromString(p_name),p_array);
|
|
}
|
|
|
|
// This stores the passed pointer rather than copying the contents, so in this case it
|
|
// is important for the calling code not to delete the passed pointer.
|
|
// The CStruct will delete it in its destructor.
|
|
// Faster than copying the contents.
|
|
// Used parse.cpp, when creating the structure for holding function params.
|
|
void CStruct::AddArrayPointer(uint32 nameChecksum, CArray *p_array)
|
|
{
|
|
CComponent *p_new=new CComponent;
|
|
|
|
p_new->mNameChecksum=nameChecksum;
|
|
p_new->mType=ESYMBOLTYPE_ARRAY;
|
|
p_new->mpArray=p_array;
|
|
|
|
AddComponent(p_new);
|
|
}
|
|
|
|
void CStruct::AddArrayPointer(const char *p_name, CArray *p_array)
|
|
{
|
|
AddArrayPointer(Crc::GenerateCRCFromString(p_name),p_array);
|
|
}
|
|
|
|
// Creates a new structure & copies in the contents of the passed structure.
|
|
void CStruct::AddStructure(uint32 nameChecksum, const CStruct *p_structure)
|
|
{
|
|
Dbg_MsgAssert(p_structure,("NULL p_structure"));
|
|
|
|
CComponent *p_new=new CComponent;
|
|
|
|
p_new->mNameChecksum=nameChecksum;
|
|
p_new->mType=ESYMBOLTYPE_STRUCTURE;
|
|
p_new->mpStructure=new CStruct;
|
|
*p_new->mpStructure=*p_structure;
|
|
|
|
AddComponent(p_new);
|
|
}
|
|
|
|
void CStruct::AddStructure(const char *p_name, const CStruct *p_structure)
|
|
{
|
|
AddStructure(Crc::GenerateCRCFromString(p_name),p_structure);
|
|
}
|
|
|
|
// This stores the passed pointer rather than copying the contents, so in this case it
|
|
// is important for the calling code not to delete the passed pointer.
|
|
// The CStruct will delete it in its destructor.
|
|
// Faster than copying the contents.
|
|
// Used parse.cpp, when creating the structure for holding function params.
|
|
void CStruct::AddStructurePointer(uint32 nameChecksum, CStruct *p_structure)
|
|
{
|
|
Dbg_MsgAssert(p_structure,("NULL p_structure"));
|
|
|
|
CComponent *p_new=new CComponent;
|
|
|
|
p_new->mNameChecksum=nameChecksum;
|
|
p_new->mType=ESYMBOLTYPE_STRUCTURE;
|
|
p_new->mpStructure=p_structure;
|
|
|
|
AddComponent(p_new);
|
|
}
|
|
|
|
void CStruct::AddStructurePointer(const char *p_name, CStruct *p_structure)
|
|
{
|
|
AddStructurePointer(Crc::GenerateCRCFromString(p_name),p_structure);
|
|
}
|
|
|
|
void CStruct::AddScript(uint32 nameChecksum, const uint8 *p_scriptTokens, uint32 size)
|
|
{
|
|
CComponent *p_new=new CComponent;
|
|
|
|
p_new->mNameChecksum=nameChecksum;
|
|
p_new->mType=ESYMBOLTYPE_QSCRIPT;
|
|
p_new->mScriptSize=size;
|
|
|
|
// Allocate a buffer off the script heap
|
|
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().ScriptHeap());
|
|
Dbg_MsgAssert(size,("Zero script size"));
|
|
uint8 *p_new_script=(uint8*)Mem::Malloc(size);
|
|
Mem::Manager::sHandle().PopContext();
|
|
|
|
// Copy the script into the new buffer.
|
|
Dbg_MsgAssert(p_scriptTokens,("NULL p_scriptTokens"));
|
|
const uint8 *p_source=p_scriptTokens;
|
|
uint8 *p_dest=p_new_script;
|
|
for (uint32 i=0; i<size; ++i)
|
|
{
|
|
*p_dest++=*p_source++;
|
|
}
|
|
|
|
// Give the new buffer to the new component.
|
|
p_new->mpScript=p_new_script;
|
|
|
|
AddComponent(p_new);
|
|
}
|
|
|
|
void CStruct::AddScript(const char *p_name, const uint8 *p_scriptTokens, uint32 size)
|
|
{
|
|
AddScript(Crc::GenerateCRCFromString(p_name),p_scriptTokens,size);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// TODO: Remove all these AddComponent functions at some point.
|
|
// They are only included to provide back compatibility with the old code without
|
|
// having to change thousands of occurrences of calls to AddComponent.
|
|
// Gradually phase out the old AddComponent instead.
|
|
//
|
|
|
|
// String or local string.
|
|
void CStruct::AddComponent(uint32 nameChecksum, ESymbolType type, const char *p_string)
|
|
{
|
|
Dbg_MsgAssert(type==ESYMBOLTYPE_LOCALSTRING || type==ESYMBOLTYPE_STRING,("Bad type sent to AddComponent"));
|
|
Dbg_MsgAssert(p_string,("NULL p_string"));
|
|
|
|
if (type==ESYMBOLTYPE_STRING)
|
|
{
|
|
AddString(nameChecksum,p_string);
|
|
}
|
|
else
|
|
{
|
|
AddLocalString(nameChecksum,p_string);
|
|
}
|
|
}
|
|
|
|
// Integer or any other 4 byte value.
|
|
void CStruct::AddComponent(uint32 nameChecksum, ESymbolType type, int integer)
|
|
{
|
|
switch (type)
|
|
{
|
|
case ESYMBOLTYPE_INTEGER:
|
|
AddInteger(nameChecksum,integer);
|
|
break;
|
|
case ESYMBOLTYPE_FLOAT:
|
|
AddFloat(nameChecksum,*(float*)&integer);
|
|
break;
|
|
case ESYMBOLTYPE_STRUCTUREPOINTER:
|
|
AddStructurePointer(nameChecksum,(CStruct*)integer);
|
|
break;
|
|
case ESYMBOLTYPE_ARRAY:
|
|
AddArrayPointer(nameChecksum,(CArray*)integer);
|
|
break;
|
|
case ESYMBOLTYPE_NAME:
|
|
AddChecksum(nameChecksum,(uint32)integer);
|
|
break;
|
|
default:
|
|
Dbg_MsgAssert(0,("Bad type of '%s' sent to AddComponent",GetTypeName(type)));
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Vector
|
|
void CStruct::AddComponent(uint32 nameChecksum, float x, float y, float z)
|
|
{
|
|
AddVector(nameChecksum,x,y,z);
|
|
}
|
|
|
|
// Pair
|
|
void CStruct::AddComponent(uint32 nameChecksum, float x, float y)
|
|
{
|
|
AddPair(nameChecksum,x,y);
|
|
}
|
|
|
|
// Array
|
|
void CStruct::AddComponent(uint32 nameChecksum, CArray *p_array)
|
|
{
|
|
AddArray(nameChecksum,p_array);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
struct SWhatever
|
|
{
|
|
union
|
|
{
|
|
int mIntegerValue;
|
|
float mFloatValue;
|
|
char *mpString;
|
|
char *mpLocalString;
|
|
CPair *mpPair;
|
|
CVector *mpVector;
|
|
CStruct *mpStructure;
|
|
CArray *mpArray;
|
|
uint8 *mpScript;
|
|
uint32 mChecksum;
|
|
uint32 mUnion;
|
|
};
|
|
};
|
|
|
|
// Infinite recursion of search_for could occur, for example if we have a global structure foo={foo}
|
|
// which is trying to include itself.
|
|
// This counter will make an assert go off if search_for tries to recurse a suspicious number of times.
|
|
#ifdef __NOPT_ASSERT__
|
|
static uint32 s_num_search_for_recursions=0;
|
|
#endif
|
|
|
|
bool CStruct::search_for(uint32 nameChecksum, ESymbolType type, SWhatever *p_value) const
|
|
{
|
|
Dbg_MsgAssert(s_num_search_for_recursions<10,("Possible infinite recursion of the CStruct::search_for function, bailing out!\nLast search was for parameter named '%s' of type '%s'",FindChecksumName(nameChecksum),GetTypeName(type)));
|
|
#ifdef __NOPT_ASSERT__
|
|
++s_num_search_for_recursions;
|
|
#endif
|
|
|
|
Dbg_MsgAssert(p_value,("NULL p_value"));
|
|
|
|
bool found=false;
|
|
|
|
CComponent *p_comp=mp_components;
|
|
while (p_comp)
|
|
{
|
|
if (p_comp->mNameChecksum==nameChecksum)
|
|
{
|
|
// The name of the component matches that required.
|
|
if (p_comp->mType==type)
|
|
{
|
|
// The type also matches, so the required component has been found.
|
|
// Only set a flag though. Need to keep searching in case the structure
|
|
// has the form {x=7 x=foo} where foo is a global defined to be an integer,
|
|
// and which must override the previous 7.
|
|
|
|
p_value->mUnion=p_comp->mUnion;
|
|
found=true;
|
|
}
|
|
else
|
|
{
|
|
// The type does not match.
|
|
if (p_comp->mType==ESYMBOLTYPE_NAME)
|
|
{
|
|
// The name of the component matches what we're looking for, but the type
|
|
// does not and is of type name.
|
|
// For example, we might be searching for an integer called x,
|
|
// but we've found a component x=foo
|
|
|
|
// So, see if foo is the name of a global defined somewhere.
|
|
CSymbolTableEntry *p_global=Resolve(p_comp->mChecksum);
|
|
if (p_global)
|
|
{
|
|
// It is! So check if this global has the type that we're looking for ...
|
|
if (p_global->mType==type)
|
|
{
|
|
// It does! So we have a match.
|
|
// Just set the found flag though, because we need to keep searching in
|
|
// case the structure has the form {x=foo x=7} where the later 7 needs to
|
|
// override what we've just found.
|
|
p_value->mUnion=p_global->mUnion;
|
|
found=true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The name of the component does not match what we're looking for.
|
|
|
|
// See if the component is an un-named name, eg the blaa in {a=3 blaa}
|
|
if (p_comp->mNameChecksum==0 && p_comp->mType==ESYMBOLTYPE_NAME)
|
|
{
|
|
// It is, so check whether it resolves to a global structure.
|
|
// If a global structure is referenced by name in another structure, then
|
|
// it is considered 'pasted in' to that structure, so it needs to be searched too.
|
|
CSymbolTableEntry *p_global=Resolve(p_comp->mChecksum);
|
|
if (p_global)
|
|
{
|
|
// It is a global something ...
|
|
if (p_global->mType==ESYMBOLTYPE_STRUCTURE)
|
|
{
|
|
// It is a structure. So search it for the required component also.
|
|
Dbg_MsgAssert(p_global->mpStructure,("NULL p_global->mpStructure ?"));
|
|
SWhatever value;
|
|
if (p_global->mpStructure->search_for(nameChecksum,type,&value))
|
|
{
|
|
// Found! Load the value, set the found flag and carry on.
|
|
*p_value=value;
|
|
found=true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
p_comp=p_comp->mpNext;
|
|
}
|
|
|
|
Dbg_MsgAssert(s_num_search_for_recursions,("Eh ???"));
|
|
#ifdef __NOPT_ASSERT__
|
|
--s_num_search_for_recursions;
|
|
#endif
|
|
|
|
return found;
|
|
}
|
|
|
|
|
|
bool CStruct::GetString(uint32 nameChecksum, const char **pp_text, EAssertType assert) const
|
|
{
|
|
Dbg_MsgAssert(pp_text,("NULL pp_text"));
|
|
|
|
SWhatever value;
|
|
if (search_for(nameChecksum,ESYMBOLTYPE_STRING,&value))
|
|
{
|
|
*pp_text=value.mpString;
|
|
return true;
|
|
}
|
|
if (search_for(nameChecksum,ESYMBOLTYPE_LOCALSTRING,&value))
|
|
{
|
|
*pp_text=value.mpString;
|
|
return true;
|
|
}
|
|
if (assert)
|
|
{
|
|
PrintContents(this);
|
|
Dbg_MsgAssert(0,("Could not find string component named '%s' in structure",FindChecksumName(nameChecksum)));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CStruct::GetString(const char *p_paramName, const char **pp_text, EAssertType assert) const
|
|
{
|
|
return GetString(Crc::GenerateCRCFromString(p_paramName),pp_text,assert);
|
|
}
|
|
|
|
bool CStruct::GetLocalString(uint32 nameChecksum, const char **pp_text, EAssertType assert) const
|
|
{
|
|
return GetString(nameChecksum,pp_text,assert);
|
|
}
|
|
|
|
bool CStruct::GetLocalString(const char *p_paramName, const char **pp_text, EAssertType assert) const
|
|
{
|
|
return GetString(Crc::GenerateCRCFromString(p_paramName),pp_text,assert);
|
|
}
|
|
|
|
bool CStruct::GetInteger(uint32 nameChecksum, int *p_integerValue, EAssertType assert) const
|
|
{
|
|
Dbg_MsgAssert(p_integerValue,("NULL p_integerValue"));
|
|
|
|
SWhatever value;
|
|
if (search_for(nameChecksum,ESYMBOLTYPE_INTEGER,&value))
|
|
{
|
|
*p_integerValue=value.mIntegerValue;
|
|
return true;
|
|
}
|
|
if (assert)
|
|
{
|
|
PrintContents(this);
|
|
Dbg_MsgAssert(0,("Could not find integer component named '%s' in structure",FindChecksumName(nameChecksum)));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CStruct::GetInteger(const char *p_paramName, int *p_integerValue, EAssertType assert) const
|
|
{
|
|
return GetInteger(Crc::GenerateCRCFromString(p_paramName),p_integerValue,assert);
|
|
}
|
|
|
|
bool CStruct::GetFloat(uint32 nameChecksum, float *p_floatValue, EAssertType assert) const
|
|
{
|
|
Dbg_MsgAssert(p_floatValue,("NULL p_floatValue"));
|
|
|
|
SWhatever value;
|
|
if (search_for(nameChecksum,ESYMBOLTYPE_FLOAT,&value))
|
|
{
|
|
*p_floatValue=value.mFloatValue;
|
|
return true;
|
|
}
|
|
// If a float was not found, check for any int's with the same name, and if found cast to a float.
|
|
// Note that the extra search means that {x=3.0} will result in x being found quicker than {x=3}
|
|
// Could speed this up by making search_for() match integers with floats, but that would slightly slow
|
|
// down the other Get... functions. Need to do some tests to see what is best.
|
|
if (search_for(nameChecksum,ESYMBOLTYPE_INTEGER,&value))
|
|
{
|
|
*p_floatValue=value.mIntegerValue;
|
|
return true;
|
|
}
|
|
if (assert)
|
|
{
|
|
PrintContents(this);
|
|
Dbg_MsgAssert(0,("Could not find float component named '%s' in structure",FindChecksumName(nameChecksum)));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CStruct::GetFloat(const char *p_paramName, float *p_floatValue, EAssertType assert) const
|
|
{
|
|
return GetFloat(Crc::GenerateCRCFromString(p_paramName),p_floatValue,assert);
|
|
}
|
|
|
|
bool CStruct::GetVector(uint32 nameChecksum, Mth::Vector *p_vector, EAssertType assert) const
|
|
{
|
|
Dbg_MsgAssert(p_vector,("NULL p_vector"));
|
|
|
|
SWhatever value;
|
|
if (search_for(nameChecksum,ESYMBOLTYPE_VECTOR,&value))
|
|
{
|
|
Dbg_MsgAssert(value.mpVector,("NULL value.mpVector"));
|
|
p_vector->Set(value.mpVector->mX,value.mpVector->mY,value.mpVector->mZ);
|
|
return true;
|
|
}
|
|
if (assert)
|
|
{
|
|
PrintContents(this);
|
|
Dbg_MsgAssert(0,("Could not find vector component named '%s' in structure",FindChecksumName(nameChecksum)));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CStruct::GetVector(const char *p_paramName, Mth::Vector *p_vector, EAssertType assert) const
|
|
{
|
|
return GetVector(Crc::GenerateCRCFromString(p_paramName),p_vector,assert);
|
|
}
|
|
|
|
bool CStruct::GetPair(uint32 nameChecksum, float *p_x, float *p_y, EAssertType assert) const
|
|
{
|
|
Dbg_MsgAssert(p_x,("NULL p_x"));
|
|
Dbg_MsgAssert(p_y,("NULL p_y"));
|
|
|
|
SWhatever value;
|
|
if (search_for(nameChecksum,ESYMBOLTYPE_PAIR,&value))
|
|
{
|
|
Dbg_MsgAssert(value.mpPair,("NULL value.mpPair"));
|
|
*p_x=value.mpPair->mX;
|
|
*p_y=value.mpPair->mY;
|
|
return true;
|
|
}
|
|
if (assert)
|
|
{
|
|
PrintContents(this);
|
|
Dbg_MsgAssert(0,("Could not find pair component named '%s' in structure",FindChecksumName(nameChecksum)));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CStruct::GetPair(const char *p_paramName, float *p_x, float *p_y, EAssertType assert) const
|
|
{
|
|
return GetPair(Crc::GenerateCRCFromString(p_paramName),p_x,p_y,assert);
|
|
}
|
|
|
|
bool CStruct::GetStructure(uint32 nameChecksum, CStruct **pp_structure, EAssertType assert) const
|
|
{
|
|
Dbg_MsgAssert(pp_structure,("NULL pp_structure"));
|
|
|
|
SWhatever value;
|
|
if (search_for(nameChecksum,ESYMBOLTYPE_STRUCTURE,&value))
|
|
{
|
|
Dbg_MsgAssert(value.mpStructure,("NULL value.mpStructure"));
|
|
*pp_structure=value.mpStructure;
|
|
return true;
|
|
}
|
|
if (assert)
|
|
{
|
|
PrintContents(this);
|
|
Dbg_MsgAssert(0,("Could not find structure component named '%s' in structure",FindChecksumName(nameChecksum)));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CStruct::GetStructure(const char *p_paramName, CStruct **pp_structure, EAssertType assert) const
|
|
{
|
|
return GetStructure(Crc::GenerateCRCFromString(p_paramName),pp_structure,assert);
|
|
}
|
|
|
|
bool CStruct::GetArray(uint32 nameChecksum, CArray **pp_array, EAssertType assert) const
|
|
{
|
|
Dbg_MsgAssert(pp_array,("NULL pp_array"));
|
|
|
|
SWhatever value;
|
|
if (search_for(nameChecksum,ESYMBOLTYPE_ARRAY,&value))
|
|
{
|
|
Dbg_MsgAssert(value.mpArray,("NULL value.mpArray"));
|
|
*pp_array=value.mpArray;
|
|
return true;
|
|
}
|
|
if (assert)
|
|
{
|
|
PrintContents(this);
|
|
Dbg_MsgAssert(0,("Could not find array component named '%s' in structure",FindChecksumName(nameChecksum)));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CStruct::GetArray(const char *p_paramName, CArray **pp_array, EAssertType assert) const
|
|
{
|
|
return GetArray(Crc::GenerateCRCFromString(p_paramName),pp_array,assert);
|
|
}
|
|
|
|
bool CStruct::GetScript(uint32 nameChecksum, SStructScript *p_structScript, EAssertType assert) const
|
|
{
|
|
Dbg_MsgAssert(p_structScript,("NULL p_structScript"));
|
|
|
|
SWhatever value;
|
|
if (search_for(nameChecksum,ESYMBOLTYPE_QSCRIPT,&value))
|
|
{
|
|
Dbg_MsgAssert(value.mpScript,("NULL value.mpScript"));
|
|
p_structScript->mNameChecksum=nameChecksum;
|
|
p_structScript->mpScriptTokens=value.mpScript;
|
|
return true;
|
|
}
|
|
if (assert)
|
|
{
|
|
PrintContents(this);
|
|
Dbg_MsgAssert(0,("Could not find script component named '%s' in structure",FindChecksumName(nameChecksum)));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CStruct::GetScript(const char *p_paramName, SStructScript *p_structScript, EAssertType assert) const
|
|
{
|
|
return GetScript(Crc::GenerateCRCFromString(p_paramName),p_structScript,assert);
|
|
}
|
|
|
|
bool CStruct::GetChecksum(uint32 nameChecksum, uint32 *p_checksum, EAssertType assert) const
|
|
{
|
|
Dbg_MsgAssert(p_checksum,("NULL p_checksum"));
|
|
|
|
// Does not use the search_for function, because GetChecksum needs to ignore unnamed names
|
|
// that resolve to structures.
|
|
|
|
bool found=false;
|
|
CComponent *p_comp=mp_components;
|
|
while (p_comp)
|
|
{
|
|
if (p_comp->mNameChecksum==nameChecksum)
|
|
{
|
|
if (p_comp->mType==ESYMBOLTYPE_NAME)
|
|
{
|
|
uint32 ch=p_comp->mChecksum;
|
|
|
|
// The name matches and the type matches, but ignore any un-named names which
|
|
// resolve to structures since these are considered 'part of' the original structure.
|
|
CSymbolTableEntry *p_entry=Resolve(ch);
|
|
if (p_entry && p_entry->mType==ESYMBOLTYPE_STRUCTURE && p_comp->mNameChecksum==0)
|
|
{
|
|
// Do nothing.
|
|
}
|
|
else
|
|
{
|
|
*p_checksum=ch;
|
|
found=true;
|
|
}
|
|
}
|
|
}
|
|
else if (p_comp->mNameChecksum==0 && p_comp->mType==ESYMBOLTYPE_NAME)
|
|
{
|
|
// It's an unnamed name, so check whether it is a structure.
|
|
uint32 ch=p_comp->mChecksum;
|
|
CSymbolTableEntry *p_entry=Resolve(ch);
|
|
if (p_entry && p_entry->mType==ESYMBOLTYPE_STRUCTURE)
|
|
{
|
|
// It is a structure, so search that.
|
|
Dbg_MsgAssert(p_entry->mpStructure,("NULL p_entry->mpStructure"));
|
|
// Note: Must not assert if not found, cos could be found later.
|
|
if (p_entry->mpStructure->GetChecksum(nameChecksum,p_checksum))
|
|
{
|
|
found=true;
|
|
}
|
|
}
|
|
}
|
|
|
|
p_comp=p_comp->mpNext;
|
|
}
|
|
if (assert && !found)
|
|
{
|
|
PrintContents(this);
|
|
Dbg_MsgAssert(0,("Checksum parameter '%s' not found in structure",FindChecksumName(nameChecksum)));
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
bool CStruct::GetChecksum(const char *p_paramName, uint32 *p_checksum, EAssertType assert) const
|
|
{
|
|
return GetChecksum(Crc::GenerateCRCFromString(p_paramName),p_checksum,assert);
|
|
}
|
|
|
|
// Looks for a name, and if no name component is found, looks for a string instead, and if found
|
|
// calculates the checksum of that.
|
|
bool CStruct::GetChecksumOrStringChecksum(uint32 nameChecksum, uint32 *p_checksum, EAssertType assert) const
|
|
{
|
|
Dbg_MsgAssert(p_checksum,("NULL p_checksum"));
|
|
|
|
if (GetChecksum(nameChecksum,p_checksum,assert))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
const char *p_string=NULL;
|
|
if (GetString(nameChecksum,&p_string,assert))
|
|
{
|
|
Dbg_MsgAssert(p_string,("NULL p_string ?"));
|
|
*p_checksum=Crc::GenerateCRCFromString(p_string);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CStruct::GetChecksumOrStringChecksum(const char *p_paramName, uint32 *p_checksum, EAssertType assert) const
|
|
{
|
|
return GetChecksumOrStringChecksum(Crc::GenerateCRCFromString(p_paramName),p_checksum,assert);
|
|
}
|
|
|
|
// Infinite recursion of ContainsComponentNamed could occur, for example if we have a global structure foo={foo}
|
|
// which is trying to include itself.
|
|
// This counter will make an assert go off if ContainsComponentNamed tries to recurse a suspicious number of times.
|
|
#ifdef __NOPT_ASSERT__
|
|
static uint32 s_num_contains_component_named_recursions=0;
|
|
#endif
|
|
|
|
// Checks to see if there is any component with the given name.
|
|
// This is similar to ContainsFlag, except it doesn't care what the type is.
|
|
// This function is used by the script function GotParam.
|
|
bool CStruct::ContainsComponentNamed(uint32 checksum) const
|
|
{
|
|
Dbg_MsgAssert(s_num_contains_component_named_recursions<10,("Possible infinite recursion of ContainsComponentNamed when searching for component named '%s'",FindChecksumName(checksum)));
|
|
#ifdef __NOPT_ASSERT__
|
|
++s_num_contains_component_named_recursions;
|
|
#endif
|
|
|
|
CComponent *p_comp=mp_components;
|
|
while (p_comp)
|
|
{
|
|
if (p_comp->mNameChecksum==checksum)
|
|
{
|
|
// The name of the component matches, so return true.
|
|
Dbg_MsgAssert(s_num_contains_component_named_recursions,("Eh ?"));
|
|
#ifdef __NOPT_ASSERT__
|
|
--s_num_contains_component_named_recursions;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
if (p_comp->mNameChecksum==0)
|
|
{
|
|
// It's an unnamed component, so maybe it's a single isolated name, or maybe it
|
|
// is a name referring to a structure defined elsewhere ...
|
|
if (p_comp->mType==ESYMBOLTYPE_NAME)
|
|
{
|
|
// It is a name. Check first to see if it is the name being searched for ...
|
|
uint32 ch=p_comp->mChecksum;
|
|
if (ch==checksum)
|
|
{
|
|
// It is.
|
|
Dbg_MsgAssert(s_num_contains_component_named_recursions,("Eh ?"));
|
|
#ifdef __NOPT_ASSERT__
|
|
--s_num_contains_component_named_recursions;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
// Oh well, maybe the name is referring to a global structure ...
|
|
CSymbolTableEntry *p_global=Resolve(ch);
|
|
if (p_global)
|
|
{
|
|
// It is a global ...
|
|
if (p_global->mType==ESYMBOLTYPE_STRUCTURE)
|
|
{
|
|
// It is a structure, so call this function on that.
|
|
Dbg_MsgAssert(p_global->mpStructure,("NULL p_global->mpStructure"));
|
|
if (p_global->mpStructure->ContainsComponentNamed(checksum))
|
|
{
|
|
Dbg_MsgAssert(s_num_contains_component_named_recursions,("Eh ?"));
|
|
#ifdef __NOPT_ASSERT__
|
|
--s_num_contains_component_named_recursions;
|
|
#endif
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
p_comp=p_comp->mpNext;
|
|
}
|
|
|
|
Dbg_MsgAssert(s_num_contains_component_named_recursions,("Eh ?"));
|
|
#ifdef __NOPT_ASSERT__
|
|
--s_num_contains_component_named_recursions;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
bool CStruct::ContainsComponentNamed(const char *p_name) const
|
|
{
|
|
return ContainsComponentNamed(Crc::GenerateCRCFromString(p_name));
|
|
}
|
|
|
|
// Infinite recursion of ContainsFlag could occur, for example if we have a global structure foo={foo}
|
|
// which is trying to include itself.
|
|
// This counter will make an assert go off if ContainsFlag tries to recurse a suspicious number of times.
|
|
#ifdef __NOPT_ASSERT__
|
|
static uint32 s_num_contains_flag_recursions=0;
|
|
#endif
|
|
|
|
// Returns true if the structure contains an unnamed component of type Name, whose checksum
|
|
// matches that passed.
|
|
// Eg, the structure Foo={Type=type_car Position=(0,0,0) CreatedAtStart} does contain an
|
|
// unnamed component of type name, with value GenerateCRC("CreatedAtStart"), so CreatedAtStart
|
|
// is like a flag.
|
|
bool CStruct::ContainsFlag(uint32 checksum) const
|
|
{
|
|
Dbg_MsgAssert(s_num_contains_flag_recursions<10,("Possible infinite recursion of ContainsFlag when searching for flag '%s'",FindChecksumName(checksum)));
|
|
#ifdef __NOPT_ASSERT__
|
|
++s_num_contains_flag_recursions;
|
|
#endif
|
|
|
|
CComponent *p_comp=mp_components;
|
|
while (p_comp)
|
|
{
|
|
if (p_comp->mNameChecksum==0 && p_comp->mType==ESYMBOLTYPE_NAME)
|
|
{
|
|
// Found an unnamed component of type name.
|
|
uint32 name_checksum=p_comp->mChecksum;
|
|
|
|
if (name_checksum==checksum)
|
|
{
|
|
Dbg_MsgAssert(s_num_contains_flag_recursions,("Eh ?"));
|
|
#ifdef __NOPT_ASSERT__
|
|
--s_num_contains_flag_recursions;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
// The component might be a structure.
|
|
CSymbolTableEntry *p_global=Resolve(name_checksum);
|
|
if (p_global)
|
|
{
|
|
// It is a global ...
|
|
if (p_global->mType==ESYMBOLTYPE_STRUCTURE)
|
|
{
|
|
// It is a structure so check that structure to see if it contains the flag.
|
|
Dbg_MsgAssert(p_global->mpStructure,("NULL p_global->mpStructure"));
|
|
if (p_global->mpStructure->ContainsFlag(checksum))
|
|
{
|
|
Dbg_MsgAssert(s_num_contains_flag_recursions,("Eh ?"));
|
|
#ifdef __NOPT_ASSERT__
|
|
--s_num_contains_flag_recursions;
|
|
#endif
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
p_comp=p_comp->mpNext;
|
|
}
|
|
|
|
Dbg_MsgAssert(s_num_contains_flag_recursions,("Eh ?"));
|
|
#ifdef __NOPT_ASSERT__
|
|
--s_num_contains_flag_recursions;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
bool CStruct::ContainsFlag(const char *p_name) const
|
|
{
|
|
return ContainsFlag(Crc::GenerateCRCFromString(p_name));
|
|
}
|
|
|
|
// Returns true if this structure contains p_struct as a substructure anywhere.
|
|
// This is used in CScript::set_script, to determine whether clearing a structure
|
|
// will result in the clearing of another structure.
|
|
bool CStruct::References(CStruct *p_struct)
|
|
{
|
|
if (p_struct==this)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
CComponent *p_comp=mp_components;
|
|
while (p_comp)
|
|
{
|
|
if (p_comp->mType==ESYMBOLTYPE_STRUCTURE)
|
|
{
|
|
Dbg_MsgAssert(p_comp->mpStructure,("NULL p_comp->mpStructure"));
|
|
if (p_comp->mpStructure->References(p_struct))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
p_comp=p_comp->mpNext;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// TODO: Remove the following Get... functions at some point.
|
|
// They are only included to provide back compatibility with the old code without
|
|
// having to change thousands of occurrences.
|
|
//
|
|
bool CStruct::GetText(uint32 nameChecksum, const char **pp_text, bool assert) const
|
|
{
|
|
return GetString(nameChecksum,pp_text,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetText(const char *p_paramName, const char **pp_text, bool assert) const
|
|
{
|
|
return GetString(p_paramName,pp_text,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetLocalText(uint32 nameChecksum, const char **pp_text, bool assert) const
|
|
{
|
|
return GetString(nameChecksum,pp_text,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetLocalText(const char *p_paramName, const char **pp_text, bool assert) const
|
|
{
|
|
return GetString(p_paramName,pp_text,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetInteger(uint32 nameChecksum, int *p_integerValue, bool assert) const
|
|
{
|
|
return GetInteger(nameChecksum,p_integerValue,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetInteger(const char *p_paramName, int *p_integerValue, bool assert) const
|
|
{
|
|
return GetInteger(p_paramName,p_integerValue,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetFloat(uint32 nameChecksum, float *p_float, bool assert) const
|
|
{
|
|
return GetFloat(nameChecksum,p_float,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetFloat(const char *p_paramName, float *p_floatValue, bool assert) const
|
|
{
|
|
return GetFloat(p_paramName,p_floatValue,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetVector(uint32 nameChecksum, Mth::Vector *p_vector, bool assert) const
|
|
{
|
|
return GetVector(nameChecksum,p_vector,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetVector(const char *p_paramName, Mth::Vector *p_vector, bool assert) const
|
|
{
|
|
return GetVector(p_paramName,p_vector,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetPair(uint32 nameChecksum, CPair *p_pair, bool assert) const
|
|
{
|
|
float x=0.0f;
|
|
float y=0.0f;
|
|
bool ret_val=GetPair(nameChecksum,&x,&y,assert?ASSERT:NO_ASSERT);
|
|
Dbg_MsgAssert(p_pair,("NULL p_pair"));
|
|
p_pair->mX=x;
|
|
p_pair->mY=y;
|
|
return ret_val;
|
|
}
|
|
|
|
bool CStruct::GetPair(const char *p_paramName, CPair *p_pair, bool assert) const
|
|
{
|
|
float x=0.0f;
|
|
float y=0.0f;
|
|
bool ret_val=GetPair(p_paramName,&x,&y,assert?ASSERT:NO_ASSERT);
|
|
Dbg_MsgAssert(p_pair,("NULL p_pair"));
|
|
p_pair->mX=x;
|
|
p_pair->mY=y;
|
|
return ret_val;
|
|
}
|
|
|
|
bool CStruct::GetStructure(uint32 nameChecksum, CStruct **pp_struct, bool assert) const
|
|
{
|
|
return GetStructure(nameChecksum,pp_struct,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetStructure(const char *p_paramName, CStruct **pp_struct, bool assert) const
|
|
{
|
|
return GetStructure(p_paramName,pp_struct,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetChecksum(uint32 nameChecksum, uint32 *p_checksum, bool assert) const
|
|
{
|
|
return GetChecksum(nameChecksum,p_checksum,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetChecksum(const char *p_paramName, uint32 *p_checksum, bool assert) const
|
|
{
|
|
return GetChecksum(p_paramName,p_checksum,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetChecksumOrStringChecksum(uint32 nameChecksum, uint32 *p_checksum, bool assert) const
|
|
{
|
|
return GetChecksumOrStringChecksum(nameChecksum,p_checksum,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetChecksumOrStringChecksum(const char *p_paramName, uint32 *p_checksum, bool assert) const
|
|
{
|
|
return GetChecksumOrStringChecksum(p_paramName,p_checksum,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetArray(uint32 nameChecksum, CArray **pp_array, bool assert) const
|
|
{
|
|
return GetArray(nameChecksum,pp_array,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
bool CStruct::GetArray(const char *p_paramName, CArray **pp_array, bool assert) const
|
|
{
|
|
return GetArray(p_paramName,pp_array,assert?ASSERT:NO_ASSERT);
|
|
}
|
|
|
|
#if 0
|
|
// Go throught the raw pool and see which entries are valid, and dump them
|
|
// uint8 * mp_buffer;
|
|
// uint8 * mp_buffer_end;
|
|
// int m_totalItems; // that we have room for
|
|
// int m_itemSize;
|
|
|
|
|
|
void DumpStructs()
|
|
{
|
|
Mem::CCompactPool * p_pool = Mem::CPoolable<CStruct>::sp_pool[Mem::CPoolable<CStruct>::s_currentPool];
|
|
CStruct *p_struct = (CStruct *)p_pool->mp_buffer;
|
|
while (p_struct < (CStruct *)p_pool->mp_buffer_end)
|
|
{
|
|
if (p_pool->IsInPool(p_struct))
|
|
{
|
|
PrintContents(p_struct);
|
|
}
|
|
|
|
p_struct++;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
} // namespace Script
|
|
|