You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2763 lines
66 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include <float.h>
#include "hsStream.h"
#include "hsTimer.h"
#include "hsStlUtils.h"
#include "plSDL.h"
#include "../pnProduct/pnProduct.h"
#include "../pnFactory/plCreatable.h"
#include "../pnKeyedObject/plUoid.h"
#include "../pnKeyedObject/plKey.h"
#include "../pnKeyedObject/plKeyImp.h"
#include "../pnNetCommon/plNetApp.h"
#include "../pnNetCommon/pnNetCommon.h"
#include "../plResMgr/plResManager.h"
#include "../plResMgr/plKeyFinder.h"
#include "../plUnifiedTime/plClientUnifiedTime.h"
#include "../plResMgr/plResManager.h"
#include "../plUnifiedTime/plClientUnifiedTime.h"
/*****************************************************************************
*
* VALIDATE_WITH_FALSE_RETURN
* Used in var getters and setters to validate incoming parameters and
* bail in a non-fatal way on error.
*
***/
#define VALIDATE_WITH_FALSE_RETURN(cond) \
if (!(cond)) { \
plSDLMgr::GetInstance()->GetNetApp()->DebugMsg("SDL var. Validation failed: "#cond); \
ASSERT(!(cond)); \
return false; \
} //
//
// generic creatable which holds any kind of creatable blob
//
class plSDLCreatableStub : public plCreatable
{
private:
UInt16 fClassIndex;
public:
void* fData;
int fDataLen;
plSDLCreatableStub(UInt16 classIndex, int len) : fClassIndex(classIndex),fData(nil),fDataLen(len) {}
~plSDLCreatableStub() { delete [] fData; }
const char* ClassName() const { return "SDLCreatable"; }
UInt16 ClassIndex() const { return fClassIndex; }
void Read(hsStream* s, hsResMgr* mgr) { delete [] fData; fData = TRACKED_NEW char[fDataLen]; s->Read(fDataLen, fData); }
void Write(hsStream* s, hsResMgr* mgr) { s->Write(fDataLen, fData); }
};
/////////////////////////////////////////////////////
// plStateVarNotificationInfo
/////////////////////////////////////////////////////
void plStateVarNotificationInfo::Read(hsStream* s, UInt32 readOptions)
{
UInt8 saveFlags=s->ReadByte(); // unused
char* hint=s->ReadSafeString();
if (hint && !(readOptions & plSDL::kSkipNotificationInfo))
fHintString = (const char*)hint;
// we're done with it...
delete [] hint;
}
void plStateVarNotificationInfo::Write(hsStream* s, UInt32 writeOptions) const
{
UInt8 saveFlags=0; // unused
s->WriteSwap(saveFlags);
s->WriteSafeString(fHintString.c_str());
}
/////////////////////////////////////////////////////
// plStateVariable
/////////////////////////////////////////////////////
bool plStateVariable::ReadData(hsStream* s, float timeConvert, UInt32 readOptions)
{
UInt8 saveFlags;
s->ReadSwap(&saveFlags);
if (saveFlags & plSDL::kHasNotificationInfo)
{
GetNotificationInfo().Read(s, readOptions);
}
return true;
}
bool plStateVariable::WriteData(hsStream* s, float timeConvert, UInt32 writeOptions) const
{
bool writeNotificationInfo = ((writeOptions & plSDL::kSkipNotificationInfo)==0);
UInt8 saveFlags=0;
if (writeNotificationInfo)
saveFlags |= plSDL::kHasNotificationInfo;
s->WriteSwap(saveFlags);
if (writeNotificationInfo)
{
GetNotificationInfo().Write(s, writeOptions);
}
return true;
}
/////////////////////////////////////////////////////
// plSimpleStateVariable
/////////////////////////////////////////////////////
void plSimpleStateVariable::IInit()
{
SetDirty(false);
SetUsed(false);
fBy=nil;
fS=nil;
fI=nil;
fF=nil;
fD=nil;
fB=nil;
fU=nil;
fS32=nil;
fC=nil;
fT=nil;
fTimeStamp.ToEpoch();
}
//
// delete memory
//
#define DEALLOC(type, var) \
case type: \
delete [] var; \
break;
void plSimpleStateVariable::IDeAlloc()
{
int cnt = fVar.GetAtomicCount()*fVar.GetCount();
int type = fVar.GetAtomicType();
switch (type)
{
DEALLOC (plVarDescriptor::kInt, fI)
DEALLOC (plVarDescriptor::kAgeTimeOfDay, fF)
DEALLOC (plVarDescriptor::kShort, fS)
DEALLOC (plVarDescriptor::kByte, fBy)
DEALLOC (plVarDescriptor::kFloat, fF)
DEALLOC (plVarDescriptor::kTime, fT)
DEALLOC (plVarDescriptor::kDouble, fD)
DEALLOC (plVarDescriptor::kBool, fB)
DEALLOC (plVarDescriptor::kKey, fU)
DEALLOC (plVarDescriptor::kString32, fS32)
case plVarDescriptor::kCreatable:
{
if(fC)
{
int i;
// delete each creatable
for(i=0;i<cnt; i++)
delete fC[i];
// delete creatable array
delete [] fC;
}
}
break;
default:
hsAssert(false, xtl::format("undefined atomic type:%d var:%s cnt:%d",
type, GetName() ? GetName() : "?", GetCount()).c_str());
break;
};
}
//
// alloc memory
//
#define SDLALLOC(typeName, type, var) \
case typeName: \
var = TRACKED_NEW type[cnt]; \
break;
void plSimpleStateVariable::Alloc(int listSize)
{
if (listSize != -1)
fVar.SetCount(listSize);
IDeAlloc();
IInit();
int cnt = fVar.GetAtomicCount()*fVar.GetCount();
if (cnt)
{
switch (fVar.GetAtomicType())
{
SDLALLOC(plVarDescriptor::kInt, int, fI)
SDLALLOC(plVarDescriptor::kAgeTimeOfDay, float, fF)
SDLALLOC(plVarDescriptor::kByte, byte, fBy)
SDLALLOC(plVarDescriptor::kShort, short, fS)
SDLALLOC(plVarDescriptor::kFloat, float, fF)
SDLALLOC(plVarDescriptor::kDouble, double, fD)
SDLALLOC(plVarDescriptor::kBool, bool, fB)
SDLALLOC(plVarDescriptor::kCreatable, plCreatable*, fC)
case plVarDescriptor::kTime:
fT = TRACKED_NEW plClientUnifiedTime[cnt];
break;
case plVarDescriptor::kKey:
fU = TRACKED_NEW plUoid[cnt];
break;
case plVarDescriptor::kString32:
fS32 = TRACKED_NEW plVarDescriptor::String32[cnt];
break;
default:
hsAssert(false, "undefined atomic type");
break;
};
}
Reset();
}
#define RESET(typeName, type, var) \
case typeName: \
for(i=0;i<cnt;i++) \
var[i]=0; \
break;
void plSimpleStateVariable::Reset()
{
int i, cnt = fVar.GetAtomicCount()*fVar.GetCount();
if (cnt)
{
switch (fVar.GetAtomicType())
{
RESET(plVarDescriptor::kInt, int, fI)
RESET(plVarDescriptor::kAgeTimeOfDay, float, fF)
RESET(plVarDescriptor::kByte, byte, fBy)
RESET(plVarDescriptor::kShort, short, fS)
RESET(plVarDescriptor::kFloat, float, fF)
RESET(plVarDescriptor::kDouble, double, fD)
RESET(plVarDescriptor::kBool, bool, fB)
RESET(plVarDescriptor::kCreatable, plCreatable*, fC)
case plVarDescriptor::kTime:
break;
case plVarDescriptor::kKey:
break;
case plVarDescriptor::kString32:
for(i=0;i<cnt;i++)
*fS32[i]=0;
break;
default:
hsAssert(false, "undefined atomic type");
break;
};
}
}
//
// Copy the descriptor settings and allocate list
//
void plSimpleStateVariable::CopyFrom(plVarDescriptor* v)
{
if (v)
{
plSimpleVarDescriptor* simV=(plSimpleVarDescriptor*)v;
if (simV)
fVar.CopyFrom(simV);
else
fVar.CopyFrom(v); // copy base class
Alloc();
}
}
void plSimpleStateVariable::TimeStamp( const plUnifiedTime & ut/*=plUnifiedTime::GetCurrentTime()*/ )
{
fTimeStamp = ut;
}
//
// Set value from string. Used to set default values which are specified as strings.
//
bool plSimpleStateVariable::SetFromString(const char* valueConst, int idx, bool timeStampNow)
{
if (!valueConst)
return false;
std::string value = valueConst;
plVarDescriptor::Type type=fVar.GetAtomicType();
switch(type)
{
case plVarDescriptor::kAgeTimeOfDay:
case plVarDescriptor::kTime:
case plVarDescriptor::kDouble:
case plVarDescriptor::kFloat:
case plVarDescriptor::kInt:
case plVarDescriptor::kShort:
case plVarDescriptor::kByte:
{
// handles value in the form "(i,j,k)" for vectors
static char seps[] = "( ,)";
char* ptr = strtok( (char*)value.c_str(), seps );
int i=idx*fVar.GetAtomicCount();
while (ptr)
{
if ((type==plVarDescriptor::kInt) && fI)
fI[i++] = atoi(ptr);
else if (type==plVarDescriptor::kShort && fS)
fS[i++] = (short)atoi(ptr);
else if (type==plVarDescriptor::kByte && fBy)
fBy[i++] = (byte)atoi(ptr);
else if ( (type==plVarDescriptor::kFloat || type==plVarDescriptor::kAgeTimeOfDay) && fF)
fF[i++] = (float)atof(ptr);
else if ( (type==plVarDescriptor::kDouble || type==plVarDescriptor::kTime) && fD)
fD[i++] = atof(ptr);
ptr = strtok(nil, seps);
}
}
break;
case plVarDescriptor::kBool:
{
// handles value in the form "(i,j,k)" for things like vectors
static char seps[] = "( ,)";
char* ptr = strtok( (char*)value.c_str(), seps );
int i=idx*fVar.GetAtomicCount();
while (ptr)
{
if (!stricmp(ptr, "true"))
fB[i++]=true;
else
if (!stricmp(ptr, "false"))
fB[i++]=false;
else
fB[i++] = (atoi(ptr) != 0);
ptr = strtok(nil, seps);
}
}
break;
case plVarDescriptor::kString32:
{
// handles value in the form "(i,j,k)" for things like vectors
static char seps[] = "( ,)";
char* ptr = strtok( (char*)value.c_str(), seps );
int i=idx*fVar.GetAtomicCount();
while (ptr)
{
hsStrncpy(fS32[i++], ptr, 32);
ptr = strtok(nil, seps);
}
}
break;
default:
return false; // err
}
IVarSet(timeStampNow);
return true; // ok
}
//
// Called when a var has been set with a value
//
void plSimpleStateVariable::IVarSet(bool timeStampNow/*=true*/)
{
if (timeStampNow)
TimeStamp();
SetDirty(true);
SetUsed(true);
}
//
// Get value as string.
//
char* plSimpleStateVariable::GetAsString(int idx) const
{
int j;
std::string str;
if (fVar.GetAtomicCount()>1)
str = str + "(";
plVarDescriptor::Type type=fVar.GetAtomicType();
switch(type)
{
case plVarDescriptor::kAgeTimeOfDay:
case plVarDescriptor::kTime:
case plVarDescriptor::kDouble:
case plVarDescriptor::kFloat:
case plVarDescriptor::kInt:
case plVarDescriptor::kByte:
case plVarDescriptor::kShort:
{
// handles value in the form "(i,j,k)" for vectors
int i=idx*fVar.GetAtomicCount();
for(j=0;j<fVar.GetAtomicCount();j++)
{
if (type==plVarDescriptor::kInt)
str.append( xtl::format( "%d", fI[i++]) );
else if (type==plVarDescriptor::kShort)
str.append( xtl::format( "%d", fS[i++]) );
else if (type==plVarDescriptor::kByte)
str.append( xtl::format( "%d", fBy[i++]) );
else if (type==plVarDescriptor::kFloat || type==plVarDescriptor::kAgeTimeOfDay)
str.append( xtl::format( "%.3f", fF[i++]) );
else if (type==plVarDescriptor::kDouble)
str.append( xtl::format( "%.3f", fD[i++]) );
else if (type==plVarDescriptor::kTime)
{
double tmp;
Get(&tmp, i++);
str.append( xtl::format( "%.3f", tmp) );
}
if (j==fVar.GetAtomicCount()-1)
{
if (j)
str += ")";
}
else
str += ",";
}
}
break;
case plVarDescriptor::kBool:
{
// handles value in the form "(i,j,k)" for things like vectors
int i=idx*fVar.GetAtomicCount();
for(j=0;j<fVar.GetAtomicCount();j++)
{
str.append( xtl::format( "%s", fB[i++] ? "true" : "false") );
if (j==fVar.GetAtomicCount()-1)
{
if (j)
str += ")";
}
else
str += ",";
}
}
break;
case plVarDescriptor::kString32:
{
// handles value in the form "(i,j,k)" for things like vectors
int i=idx*fVar.GetAtomicCount();
for(j=0;j<fVar.GetAtomicCount();j++)
{
str.append( xtl::format( "%s", fS32[i++]) );
if (j==fVar.GetAtomicCount()-1)
{
if (j)
str += ")";
}
else
str += ",";
}
}
break;
default:
{
// handles value in the form "(i,j,k)" for things like vectors
int i=idx*fVar.GetAtomicCount();
for(j=0;j<fVar.GetAtomicCount();j++)
{
str.append( xtl::format( "%s", "other") );
if (j==fVar.GetAtomicCount()-1)
{
if (j)
str += ")";
}
else
str += ",";
}
}
break;
}
return hsStrcpy(str.c_str());
}
//
// return false on err
//
bool plSimpleStateVariable::IConvertFromRGB(plVarDescriptor::Type newType)
{
switch(newType)
{
case plVarDescriptor::kRGBA:
{
// rgb to rgba
int i,j;
float* newF = TRACKED_NEW float[fVar.GetCount()*4]; // make more space
for(j=0;j<fVar.GetCount(); j++)
{
// recopy with alpha=0 by default
for(i=0;i<3;i++)
newF[j*4+i] = fF[j*fVar.GetAtomicCount()+i];
newF[j*4+3] = 0;
}
delete [] fF; // delete old
fF = newF; // use new
}
break;
case plVarDescriptor::kRGBA8:
{
// rgb to rgba8
int i,j;
byte * newB = TRACKED_NEW byte [fVar.GetCount()*4]; // make more space
for(j=0;j<fVar.GetCount(); j++)
{
// recopy with alpha=0 by default
for(i=0;i<3;i++)
newB[j*4+i] = byte(fF[j*fVar.GetAtomicCount()+i]*255+.5);
newB[j*4+3] = 0;
}
delete [] fF; // delete old
fBy = newB; // use new
}
break;
case plVarDescriptor::kRGB8:
{
// rgb to rgb8
int i,j;
byte * newB = TRACKED_NEW byte [fVar.GetCount()*3]; // make space
for(j=0;j<fVar.GetCount(); j++)
{
// recopy with alpha=0 by default
for(i=0;i<3;i++)
newB[j*3+i] = byte(fF[j*fVar.GetAtomicCount()+i]*255+.5);
}
delete [] fF; // delete old
fBy = newB; // use new
}
break;
default:
return false; // err
}
return true;
}
bool plSimpleStateVariable::IConvertFromRGB8(plVarDescriptor::Type newType)
{
switch(newType)
{
case plVarDescriptor::kRGBA:
{
// rgb8 to rgba
int i,j;
float* newF = TRACKED_NEW float[fVar.GetCount()*4]; // make more space
for(j=0;j<fVar.GetCount(); j++)
{
// recopy with alpha=0 by default
for(i=0;i<3;i++)
newF[j*4+i] = fBy[j*fVar.GetAtomicCount()+i]/255.f;
newF[j*4+3] = 0;
}
delete [] fBy; // delete old
fF = newF; // use new
}
break;
case plVarDescriptor::kRGB:
{
// rgb8 to rgb
int i,j;
float* newF = TRACKED_NEW float[fVar.GetCount()*3]; // make more space
for(j=0;j<fVar.GetCount(); j++)
{
// recopy with alpha=0 by default
for(i=0;i<3;i++)
newF[j*3+i] = fBy[j*fVar.GetAtomicCount()+i]/255.f;
}
delete [] fBy; // delete old
fF = newF; // use new
}
break;
case plVarDescriptor::kRGBA8:
{
// rgb8 to rgba8
int i,j;
byte * newB = TRACKED_NEW byte [fVar.GetCount()*4]; // make more space
for(j=0;j<fVar.GetCount(); j++)
{
// recopy with alpha=0 by default
for(i=0;i<3;i++)
newB[j*4+i] = fBy[j*fVar.GetAtomicCount()+i];
newB[j*4+3] = 0;
}
delete [] fBy; // delete old
fBy = newB; // use new
}
break;
default:
return false; // err
}
return true;
}
//
// return false on err
//
bool plSimpleStateVariable::IConvertFromRGBA(plVarDescriptor::Type newType)
{
switch(newType)
{
case plVarDescriptor::kRGB:
{
// rgba to rgb
int i,j;
float* newF = TRACKED_NEW float[fVar.GetCount()*3]; // make less space
for(j=0;j<fVar.GetCount(); j++)
{
// recopy and ignore alpha
for(i=0;i<3;i++)
newF[j*3+i] = fF[j*fVar.GetAtomicCount()+i];
}
delete [] fF; // delete old
fF = newF; // use new
}
break;
case plVarDescriptor::kRGB8:
{
// rgba to rgb8
int i,j;
byte* newB = TRACKED_NEW byte[fVar.GetCount()*3]; // make less space
for(j=0;j<fVar.GetCount(); j++)
{
// recopy and ignore alpha
for(i=0;i<3;i++)
newB[j*3+i] = byte(fF[j*fVar.GetAtomicCount()+i]*255+.5);
}
delete [] fF; // delete old
fBy = newB; // use new
}
break;
case plVarDescriptor::kRGBA8:
{
// rgba to rgba8
int i,j;
byte* newBy = TRACKED_NEW byte [fVar.GetCount()*4]; // make less space
for(j=0;j<fVar.GetCount(); j++)
{
// recopy and ignore alpha
for(i=0;i<4;i++)
newBy[j*4+i] = byte(fF[j*fVar.GetAtomicCount()+i]*255+.5);
}
delete [] fF; // delete old
fBy = newBy; // use new
}
break;
default:
return false; // err
}
return true;
}
//
// return false on err
//
bool plSimpleStateVariable::IConvertFromRGBA8(plVarDescriptor::Type newType)
{
switch(newType)
{
case plVarDescriptor::kRGB:
{
// rgba8 to rgb
int i,j;
float* newF = TRACKED_NEW float[fVar.GetCount()*3]; // make less space
for(j=0;j<fVar.GetCount(); j++)
{
// recopy and ignore alpha
for(i=0;i<3;i++)
newF[j*3+i] = fBy[j*fVar.GetAtomicCount()+i]/255.f;
}
delete [] fBy; // delete old
fF = newF; // use new
}
break;
case plVarDescriptor::kRGB8:
{
// rgba8 to rgb8
int i,j;
byte* newB = TRACKED_NEW byte[fVar.GetCount()*3]; // make less space
for(j=0;j<fVar.GetCount(); j++)
{
// recopy and ignore alpha
for(i=0;i<3;i++)
newB[j*3+i] = fBy[j*fVar.GetAtomicCount()+i];
}
delete [] fBy; // delete old
fBy = newB; // use new
}
break;
case plVarDescriptor::kRGBA:
{
// rgba8 to rgba
int i,j;
float* newF = TRACKED_NEW float[fVar.GetCount()*4]; // make less space
for(j=0;j<fVar.GetCount(); j++)
{
// recopy and ignore alpha
for(i=0;i<4;i++)
newF[j*4+i] = fBy[j*fVar.GetAtomicCount()+i]/255.f;
}
delete [] fBy; // delete old
fF = newF; // use new
}
break;
default:
return false; // err
}
return true;
}
//
// return false on err
//
bool plSimpleStateVariable::IConvertFromInt(plVarDescriptor::Type newType)
{
int j;
switch(newType)
{
case plVarDescriptor::kFloat:
{
// int to float
float* newF = TRACKED_NEW float[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newF[j] = (float)(fI[j]);
delete [] fI;
fF = newF;
}
break;
case plVarDescriptor::kShort:
{
// int to short
short* newS = TRACKED_NEW short[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newS[j] = short(fI[j]);
delete [] fI;
fS = newS;
}
break;
case plVarDescriptor::kByte:
{
// int to byte
byte* newBy = TRACKED_NEW byte[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newBy[j] = byte(fI[j]);
delete [] fI;
fBy = newBy;
}
break;
case plVarDescriptor::kDouble:
{
// int to double
double * newD = TRACKED_NEW double[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newD[j] = fI[j];
delete [] fI;
fD = newD;
}
break;
case plVarDescriptor::kBool:
{
// int to bool
bool * newB = TRACKED_NEW bool[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newB[j] = (fI[j]!=0);
delete [] fI;
fB = newB;
}
break;
default:
return false; // err
}
return true;
}
//
// return false on err
//
bool plSimpleStateVariable::IConvertFromShort(plVarDescriptor::Type newType)
{
int j;
switch(newType)
{
case plVarDescriptor::kFloat:
{
float* newF = TRACKED_NEW float[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newF[j] = fS[j];
delete [] fS;
fF = newF;
}
break;
case plVarDescriptor::kInt:
{
int* newI = TRACKED_NEW int[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newI[j] = short(fS[j]);
delete [] fS;
fI = newI;
}
case plVarDescriptor::kByte:
{
byte* newBy = TRACKED_NEW byte[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newBy[j] = byte(fS[j]);
delete [] fS;
fBy = newBy;
}
break;
case plVarDescriptor::kDouble:
{
double * newD = TRACKED_NEW double[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newD[j] = fS[j];
delete [] fS;
fD = newD;
}
break;
case plVarDescriptor::kBool:
{
bool * newB = TRACKED_NEW bool[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newB[j] = (fS[j]!=0);
delete [] fS;
fB = newB;
}
break;
default:
return false; // err
}
return true;
}
//
// return false on err
//
bool plSimpleStateVariable::IConvertFromByte(plVarDescriptor::Type newType)
{
int j;
switch(newType)
{
case plVarDescriptor::kFloat:
{
float* newF = TRACKED_NEW float[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newF[j] = fBy[j];
delete [] fBy;
fF = newF;
}
break;
case plVarDescriptor::kInt:
{
int* newI = TRACKED_NEW int[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newI[j] = short(fBy[j]);
delete [] fBy;
fI = newI;
}
case plVarDescriptor::kShort:
{
short* newS = TRACKED_NEW short[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newS[j] = fBy[j];
delete [] fBy;
fS = newS;
}
break;
case plVarDescriptor::kDouble:
{
double * newD = TRACKED_NEW double[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newD[j] = fBy[j];
delete [] fBy;
fD = newD;
}
break;
case plVarDescriptor::kBool:
{
bool * newB = TRACKED_NEW bool[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newB[j] = (fBy[j]!=0);
delete [] fBy;
fB = newB;
}
break;
default:
return false; // err
}
return true;
}
//
// return false on err
//
bool plSimpleStateVariable::IConvertFromFloat(plVarDescriptor::Type newType)
{
int j;
switch(newType)
{
case plVarDescriptor::kInt:
{
int* newI = TRACKED_NEW int[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newI[j] = (int)(fF[j]+.5f); // round to nearest int
delete [] fF;
fI = newI;
}
break;
case plVarDescriptor::kShort:
{
short* newS = TRACKED_NEW short[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newS[j] = (short)(fF[j]+.5f); // round to nearest int
delete [] fF;
fS = newS;
}
break;
case plVarDescriptor::kByte:
{
byte* newBy = TRACKED_NEW byte[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newBy[j] = (byte)(fF[j]+.5f); // round to nearest int
delete [] fF;
fBy = newBy;
}
break;
case plVarDescriptor::kDouble:
{
double* newD = TRACKED_NEW double[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newD[j] = fF[j];
delete [] fF;
fD = newD;
}
break;
case plVarDescriptor::kBool:
{
bool* newB = TRACKED_NEW bool[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newB[j] = (fF[j]!=0);
delete [] fF;
fB = newB;
}
break;
default:
return false; // err
}
return true;
}
//
// return false on err
//
bool plSimpleStateVariable::IConvertFromDouble(plVarDescriptor::Type newType)
{
int j;
switch(newType)
{
case plVarDescriptor::kInt:
{
int* newI = TRACKED_NEW int[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newI[j] = (int)(fD[j]+.5f); // round to nearest int
delete [] fD;
fI = newI;
}
break;
case plVarDescriptor::kShort:
{
short* newS = TRACKED_NEW short[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newS[j] = (short)(fD[j]+.5f); // round to nearest int
delete [] fD;
fS = newS;
}
break;
case plVarDescriptor::kByte:
{
byte* newBy = TRACKED_NEW byte[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newBy[j] = (byte)(fD[j]+.5f); // round to nearest int
delete [] fD;
fBy = newBy;
}
break;
case plVarDescriptor::kFloat:
{
float* newF = TRACKED_NEW float[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newF[j] = (float)(fD[j]);
delete [] fD;
fF = newF;
}
break;
case plVarDescriptor::kBool:
{
bool* newB = TRACKED_NEW bool[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newB[j] = (fD[j]!=0);
delete [] fD;
fB = newB;
}
break;
default:
return false; // err
}
return true;
}
//
// return false on err
//
bool plSimpleStateVariable::IConvertFromBool(plVarDescriptor::Type newType)
{
int j;
switch(newType)
{
case plVarDescriptor::kInt:
{
int* newI = TRACKED_NEW int[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newI[j] = (fB[j] == true ? 1 : 0);
delete [] fB;
fI = newI;
}
break;
case plVarDescriptor::kShort:
{
short* newS = TRACKED_NEW short[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newS[j] = (fB[j] == true ? 1 : 0);
delete [] fB;
fS = newS;
}
break;
case plVarDescriptor::kByte:
{
byte* newBy = TRACKED_NEW byte[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newBy[j] = (fB[j] == true ? 1 : 0);
delete [] fB;
fBy = newBy;
}
break;
case plVarDescriptor::kFloat:
{
float* newF = TRACKED_NEW float[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newF[j] = (fB[j] == true ? 1.f : 0.f);
delete [] fB;
fF = newF;
}
break;
case plVarDescriptor::kDouble:
{
double* newD= TRACKED_NEW double[fVar.GetCount()];
for(j=0;j<fVar.GetCount(); j++)
newD[j] = (fB[j] == true ? 1.f : 0.f);
delete [] fB;
fD = newD;
}
break;
default:
return false; // err
}
return true;
}
//
// return false on err
//
bool plSimpleStateVariable::IConvertFromString(plVarDescriptor::Type newType)
{
int j;
switch(newType)
{
case plVarDescriptor::kBool:
// string to bool
for(j=0;j<fVar.GetCount(); j++)
{
if (!stricmp(fS32[j], "true") || !stricmp(fS32[j], "1"))
fB[j]=true;
else
if (!stricmp(fS32[j], "false") || !stricmp(fS32[j], "0"))
fB[j]=false;
else
return false; // err
}
break;
case plVarDescriptor::kInt:
// string to int
for(j=0;j<fVar.GetCount(); j++)
{
fI[j] = atoi(fS32[j]);
}
break;
case plVarDescriptor::kFloat:
// string to float
for(j=0;j<fVar.GetCount(); j++)
{
fF[j] = (float) atof(fS32[j]);
}
break;
default:
return false; // err
}
return true;
}
//
// Try to convert my value to another type.
// return false on err.
// called when a data record is read in
//
bool plSimpleStateVariable::ConvertTo(plSimpleVarDescriptor* toVar, bool force )
{
// NOTE: 'force' has no meaning here really, so it is not inforced.
plVarDescriptor::Type newType = toVar->GetType();
int cnt = toVar->GetCount() ? toVar->GetCount() : fVar.GetCount();
if (cnt > fVar.GetCount()) {
#if BUILD_TYPE == BUILD_TYPE_DEV
FATAL("SDL Convert: array size increased, conversion loses data");
#endif
// Reallocate new memory (destroys existing variable state)
Alloc(cnt);
// match types now
fVar.SetCount(cnt);
fVar.SetType(toVar->GetType());
fVar.SetAtomicType(toVar->GetAtomicType());
return true;
}
fVar.SetCount(cnt); // convert count
// types are already the same, done.
if (fVar.GetType()==newType )
return true;
hsLogEntry( plNetApp::StaticDebugMsg( "SSV(%p) converting %s from %s to %s",
this, fVar.GetName(), fVar.GetTypeString(), toVar->GetTypeString() ) );
switch(fVar.GetType()) // original type
{
// FROM RGB
case plVarDescriptor::kRGB:
if (!IConvertFromRGB(newType))
return false;
break;
// FROM RGBA
case plVarDescriptor::kRGBA:
if (!IConvertFromRGBA(newType))
return false;
break;
// FROM RGB8
case plVarDescriptor::kRGB8:
if (!IConvertFromRGB8(newType))
return false;
break;
// FROM RGBA8
case plVarDescriptor::kRGBA8:
if (!IConvertFromRGBA8(newType))
return false;
break;
// FROM INT
case plVarDescriptor::kInt:
if (!IConvertFromInt(newType))
return false;
break;
// FROM SHORT
case plVarDescriptor::kShort:
if (!IConvertFromShort(newType))
return false;
break;
// FROM Byte
case plVarDescriptor::kByte:
if (!IConvertFromByte(newType))
return false;
break;
// FROM FLOAT
case plVarDescriptor::kFloat:
if (!IConvertFromFloat(newType))
return false;
break;
// FROM DOUBLE
case plVarDescriptor::kDouble:
if (!IConvertFromDouble(newType))
return false;
break;
// FROM BOOL
case plVarDescriptor::kBool:
if (!IConvertFromBool(newType))
return false;
break;
// FROM STRING32
case plVarDescriptor::kString32:
if (!IConvertFromString(newType))
return false;
break;
default:
return false; // err
}
// match types now
fVar.SetType(toVar->GetType());
fVar.SetAtomicType(toVar->GetAtomicType());
return true; // ok
}
/////////////////////////////////////////////////////////////
// SETTERS
/////////////////////////////////////////////////////////////
bool plSimpleStateVariable::Set(float v, int idx)
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetType()==plVarDescriptor::kAgeTimeOfDay)
{
hsAssert(false, "AgeTime variables are read-only, can't set");
}
else
if (fVar.GetType()==plVarDescriptor::kFloat)
{
fF[idx]=v;
IVarSet();
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
bool plSimpleStateVariable::Set(double v, int idx)
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetType()==plVarDescriptor::kDouble)
{
fD[idx]=v;
IVarSet();
return true;
}
if (fVar.GetType()==plVarDescriptor::kTime)
{ // convert from,
fT[idx].SetFromGameTime(v, hsTimer::GetSysSeconds());
IVarSet();
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
// floatvector
bool plSimpleStateVariable::Set(float* v, int idx)
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetType()==plVarDescriptor::kAgeTimeOfDay)
{
hsAssert(false, "AgeTime variables are read-only, can't set");
}
else
if (fVar.GetAtomicType()==plVarDescriptor::kFloat)
{
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
fF[cnt+i]=v[i];
IVarSet();
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
// bytevector
bool plSimpleStateVariable::Set(byte* v, int idx)
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetAtomicType()==plVarDescriptor::kByte)
{
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
fBy[cnt+i]=v[i];
IVarSet();
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
//
bool plSimpleStateVariable::Set(double* v, int idx)
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetAtomicType()==plVarDescriptor::kDouble)
{
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
fD[cnt+i]=v[i];
IVarSet();
return true;
}
if (fVar.GetAtomicType()==plVarDescriptor::kTime)
{
double secs=hsTimer::GetSysSeconds();
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
fT[cnt+i].SetFromGameTime(v[i], secs);
IVarSet();
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
bool plSimpleStateVariable::Set(int v, int idx)
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetType()==plVarDescriptor::kInt)
{
fI[idx]=v;
IVarSet();
return true;
}
else
if (fVar.GetType()==plVarDescriptor::kBool)
return Set((bool)(v?true:false), idx); // since 'true' is coming in as an int not bool
else
if (fVar.GetType()==plVarDescriptor::kShort)
return Set((short)v, idx);
else
if (fVar.GetType()==plVarDescriptor::kByte)
return Set((byte)v, idx);
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
bool plSimpleStateVariable::Set(short v, int idx)
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetType()==plVarDescriptor::kShort)
{
fS[idx]=v;
IVarSet();
return true;
}
else
if (fVar.GetType()==plVarDescriptor::kInt)
return Set((int)v, idx);
else
if (fVar.GetType()==plVarDescriptor::kByte)
return Set((byte)v, idx);
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
bool plSimpleStateVariable::Set(byte v, int idx)
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetType()==plVarDescriptor::kByte)
{
fBy[idx]=v;
IVarSet();
return true;
}
else
if (fVar.GetType()==plVarDescriptor::kBool)
return Set((bool)(v?true:false), idx);
else
if (fVar.GetType()==plVarDescriptor::kInt)
return Set((int)v, idx);
else
if (fVar.GetType()==plVarDescriptor::kShort)
return Set((short)v, idx);
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
bool plSimpleStateVariable::Set(const char* v, int idx)
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (v && fVar.GetType()==plVarDescriptor::kString32)
{
hsAssert(hsStrlen(v)<32, "string length overflow");
hsStrncpy(fS32[idx], v, 32);
IVarSet();
return true;
}
hsAssert(false, v ? "passing wrong value type to SDL variable" : "trying to set nil string");
return false;
}
bool plSimpleStateVariable::Set(bool v, int idx)
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetType()==plVarDescriptor::kBool)
{
fB[idx]=v;
IVarSet();
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
bool plSimpleStateVariable::Set(const plKey& v, int idx)
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetType()==plVarDescriptor::kKey)
{
if(v)
{
fU[idx] = v->GetUoid();
}
else
{
fU[idx] = plUoid();
}
IVarSet();
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
bool plSimpleStateVariable::Set(plCreatable* v, int idx)
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetType()==plVarDescriptor::kCreatable)
{
// copy creatable via stream
hsRAMStream stream;
if(v)
{
hsgResMgr::ResMgr()->WriteCreatable(&stream, v);
stream.Rewind();
}
plCreatable* copy = v ? hsgResMgr::ResMgr()->ReadCreatable(&stream): nil;
hsAssert(!v || copy, "failed to create creatable copy");
fC[idx]=copy;
IVarSet();
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
/////////////////////////////////////////////////////////////
// GETTERS
/////////////////////////////////////////////////////////////
bool plSimpleStateVariable::Get(int* value, int idx) const
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetAtomicType()==plVarDescriptor::kInt)
{
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
value[i]=fI[cnt+i];
return true;
}
if (fVar.GetAtomicType()==plVarDescriptor::kShort)
{
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
value[i]=fS[cnt+i];
return true;
}
if (fVar.GetAtomicType()==plVarDescriptor::kByte)
{
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
value[i]=fBy[cnt+i];
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
bool plSimpleStateVariable::Get(short* value, int idx) const
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetAtomicType()==plVarDescriptor::kShort)
{
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
value[i]=fS[cnt+i];
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
bool plSimpleStateVariable::Get(byte* value, int idx) const
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetAtomicType()==plVarDescriptor::kByte)
{
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
value[i]=fBy[cnt+i];
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
// float or floatVector
bool plSimpleStateVariable::Get(float* value, int idx) const
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetAtomicType()==plVarDescriptor::kAgeTimeOfDay)
{
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
{
if (plNetClientApp::GetInstance())
fF[cnt+i] = plNetClientApp::GetInstance()->GetCurrentAgeTimeOfDayPercent();
value[i]=fF[cnt+i];
}
return true;
}
if (fVar.GetAtomicType()==plVarDescriptor::kFloat)
{
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
value[i]=fF[cnt+i];
return true;
}
if (fVar.GetAtomicType()==plVarDescriptor::kDouble)
{
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
value[i]=(float)fD[cnt+i];
return true;
}
if (fVar.GetAtomicType()==plVarDescriptor::kTime) // && fIsUsed)
{
double secs=hsTimer::GetSysSeconds();
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
{
double tmp;
fT[cnt+i].ConvertToGameTime(&tmp, secs);
value[i] = (float)tmp;
}
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
// double
bool plSimpleStateVariable::Get(double* value, int idx) const
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetAtomicType()==plVarDescriptor::kDouble)
{
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
value[i]=fD[cnt+i];
return true;
}
if (fVar.GetAtomicType()==plVarDescriptor::kTime)
{
double secs=hsTimer::GetSysSeconds();
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
fT[cnt+i].ConvertToGameTime(&value[i], secs);
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
bool plSimpleStateVariable::Get(bool* value, int idx) const
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetAtomicType()==plVarDescriptor::kBool)
{
int i;
int cnt=fVar.GetAtomicCount()*idx;
for(i=0;i<fVar.GetAtomicCount();i++)
value[i]=fB[cnt+i];
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
bool plSimpleStateVariable::Get(plKey* value, int idx) const
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetAtomicType()==plVarDescriptor::kKey)
{
if(!(fU[idx] == plUoid())) // compare to default "nil uoid"
{
*value = hsgResMgr::ResMgr()->FindKey(fU[idx]);
if (*value)
{
const plUoid& newUoid = (*value)->GetUoid();
if (stricmp(newUoid.GetObjectName(), fU[idx].GetObjectName()) != 0)
{
// uoid names don't match... chances are the key changed in the local data after the key was written to the sdl
// do a search by name, which takes longer, to get the correct key
std::vector<plKey> foundKeys;
plKeyFinder::Instance().ReallyStupidSubstringSearch(fU[idx].GetObjectName(), fU[idx].GetClassType(), foundKeys, fU[idx].GetLocation());
// not really sure what we can do if it finds MORE then one (they are supposed to be unique names), so just grab the
// first one and return it
if (foundKeys.size() >= 1)
*value = foundKeys[0];
else
*value = nil;
}
}
} else {
*value = nil;
}
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
bool plSimpleStateVariable::Get(char value[], int idx) const
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetType()==plVarDescriptor::kString32)
{
hsStrcpy(value, fS32[idx]);
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
bool plSimpleStateVariable::Get(plCreatable** value, int idx) const
{
VALIDATE_WITH_FALSE_RETURN(idx < fVar.GetCount());
if (fVar.GetAtomicType()==plVarDescriptor::kCreatable)
{
*value = nil;
plCreatable* v = fC[idx];
if (v)
{
*value = plFactory::Create(v->ClassIndex());
hsAssert(*value, "failed to create creatable copy");
hsRAMStream stream;
v->Write(&stream, hsgResMgr::ResMgr());
stream.Rewind();
(*value)->Read(&stream, hsgResMgr::ResMgr());
}
return true;
}
hsAssert(false, "passing wrong value type to SDL variable");
return false;
}
/////////////////////////////////////////////////////////////
const char* plSimpleStateVariable::GetKeyName(int idx) const
{
if (fVar.GetAtomicType()==plVarDescriptor::kKey)
{
if(!(fU[idx] == plUoid())) // compare to default "nil uoid"
{
return fU[idx].GetObjectName();
}
}
hsAssert(false, "passing wrong value type to SDL variable");
return "(nil)";
}
#pragma optimize( "g", off ) // disable float optimizations
bool plSimpleStateVariable::IWriteData(hsStream* s, float timeConvert, int idx, UInt32 writeOptions) const
{
#ifdef HS_DEBUGGING
if (!IsUsed())
{
// hsAssert(false, "plSimpleStateVariable::WriteData doesn't contain data?");
plNetApp::StaticWarningMsg("plSimpleStateVariable::WriteData Var %s doesn't contain data?",
GetName());
}
#endif
int j=idx*fVar.GetAtomicCount();
int i;
switch(fVar.GetAtomicType())
{
case plVarDescriptor::kAgeTimeOfDay:
// don't need to write out ageTime, since it's computed on the fly when Get is called
break;
case plVarDescriptor::kInt:
for(i=0;i<fVar.GetAtomicCount();i++)
s->WriteSwap32(fI[j+i]);
break;
case plVarDescriptor::kShort:
for(i=0;i<fVar.GetAtomicCount();i++)
s->WriteSwap16(fS[j+i]);
break;
case plVarDescriptor::kByte:
for(i=0;i<fVar.GetAtomicCount();i++)
s->WriteByte(fBy[j+i]);
break;
case plVarDescriptor::kFloat:
for(i=0;i<fVar.GetAtomicCount();i++)
s->WriteSwapScalar(fF[j+i]);
break;
case plVarDescriptor::kTime:
for(i=0;i<fVar.GetAtomicCount();i++)
{
if (timeConvert != 0.0)
{
double utDouble=fT[j+i].GetSecsDouble();
hsDoublePrecBegin
utDouble += timeConvert;
hsDoublePrecEnd
plUnifiedTime ut(utDouble);
ut.Write(s);
}
else
fT[j+i].Write(s);
}
break;
case plVarDescriptor::kDouble:
for(i=0;i<fVar.GetAtomicCount();i++)
s->WriteSwapDouble(fD[j+i]);
break;
case plVarDescriptor::kBool:
for(i=0;i<fVar.GetAtomicCount();i++)
s->Writebool(fB[j+i]);
break;
case plVarDescriptor::kKey:
for(i=0;i<fVar.GetAtomicCount();i++)
fU[j+i].Write(s);
break;
case plVarDescriptor::kString32:
for(i=0;i<fVar.GetAtomicCount();i++)
s->Write(32, fS32[j+i]);
break;
case plVarDescriptor::kCreatable:
{
hsAssert(fVar.GetAtomicCount()==1, "invalid atomic count");
plCreatable* cre = fC[j];
s->WriteSwap16(cre ? cre->ClassIndex() : 0x8000); // creatable class index
if (cre)
{
hsRAMStream ramStream;
cre->Write(&ramStream, hsgResMgr::ResMgr());
s->WriteSwap32(ramStream.GetEOF()); // write length
cre->Write(s, hsgResMgr::ResMgr()); // write data
}
}
break;
}
return true;
}
bool plSimpleStateVariable::IReadData(hsStream* s, float timeConvert, int idx, UInt32 readOptions)
{
int j=idx*fVar.GetAtomicCount();
int i;
switch(fVar.GetAtomicType())
{
case plVarDescriptor::kAgeTimeOfDay:
// don't need to read in ageTime, since it's computed on the fly when Get is called
break;
case plVarDescriptor::kInt:
for(i=0;i<fVar.GetAtomicCount();i++)
fI[j+i]=s->ReadSwap32();
break;
case plVarDescriptor::kShort:
for(i=0;i<fVar.GetAtomicCount();i++)
fS[j+i]=s->ReadSwap16();
break;
case plVarDescriptor::kByte:
for(i=0;i<fVar.GetAtomicCount();i++)
fBy[j+i]=s->ReadByte();
break;
case plVarDescriptor::kFloat:
for(i=0;i<fVar.GetAtomicCount();i++)
fF[j+i]=s->ReadSwapScalar();
break;
case plVarDescriptor::kTime:
for(i=0;i<fVar.GetAtomicCount();i++)
{
fT[j+i].Read(s);
if (timeConvert != 0.0)
{
hsDoublePrecBegin
double newUt = (fT[j+i].GetSecsDouble() + timeConvert);
hsDoublePrecEnd
hsAssert(newUt>=0, "negative unified time");
fT[j+i].SetSecsDouble(newUt);
}
}
break;
case plVarDescriptor::kDouble:
for(i=0;i<fVar.GetAtomicCount();i++)
fD[j+i]=s->ReadSwapDouble();
break;
case plVarDescriptor::kBool:
for(i=0;i<fVar.GetAtomicCount();i++)
fB[j+i]=s->Readbool();
break;
case plVarDescriptor::kKey:
for(i=0;i<fVar.GetAtomicCount();i++)
{
fU[j+i].Invalidate();
fU[j+i].Read(s);
}
break;
case plVarDescriptor::kString32:
for(i=0;i<fVar.GetAtomicCount();i++)
s->Read(32, fS32[j+i]);
break;
case plVarDescriptor::kCreatable:
{
hsAssert(fVar.GetAtomicCount()==1, "invalid atomic count");
UInt16 hClass = s->ReadSwap16(); // class index
if (hClass != 0x8000)
{
UInt32 len = s->ReadSwap32(); // length
if (plFactory::CanCreate(hClass))
{
delete fC[j];
fC[j] = plFactory::Create(hClass);
}
else
{
plSDLCreatableStub* stub = TRACKED_NEW plSDLCreatableStub(hClass, len);
fC[j] = stub;
}
fC[j]->Read(s, hsgResMgr::ResMgr()); // data
}
}
break;
default:
hsAssert(false, "invalid atomic type");
return false;
}
return true;
}
#pragma optimize( "", on ) // restore optimizations to their defaults
bool plSimpleStateVariable::WriteData(hsStream* s, float timeConvert, UInt32 writeOptions) const
{
#ifdef HS_DEBUGGING
if (!IsUsed())
{
// hsAssert(false, "plSimpleStateVariable::WriteData Var doesn't contain data?");
plNetApp::StaticWarningMsg("plSimpleStateVariable::WriteData Var %s doesn't contain data?",
GetName());
}
#endif
// write base class data
plStateVariable::WriteData(s, timeConvert, writeOptions);
// check if the same as default
bool sameAsDefaults=false;
if (!GetVarDescriptor()->IsVariableLength())
{
plSimpleStateVariable def;
def.fVar.CopyFrom(&fVar); // copy descriptor
def.Alloc(); // and rest
def.SetFromDefaults(false /* timeStamp */); // may do nothing if nor default
sameAsDefaults = (def == *this);
}
bool writeTimeStamps = (writeOptions & plSDL::kWriteTimeStamps)!=0;
bool writeDirtyFlags = (writeOptions & plSDL::kDontWriteDirtyFlag)==0;
bool forceDirtyFlags = (writeOptions & plSDL::kMakeDirty)!=0;
bool wantTimeStamp = (writeOptions & plSDL::kTimeStampOnRead)!=0;
bool needTimeStamp = (writeOptions & plSDL::kTimeStampOnWrite)!=0;
forceDirtyFlags = forceDirtyFlags || (!sameAsDefaults && (writeOptions & plSDL::kDirtyNonDefaults)!=0);
// write save flags
UInt8 saveFlags = 0;
saveFlags |= writeTimeStamps ? plSDL::kHasTimeStamp : 0;
saveFlags |= forceDirtyFlags || (writeDirtyFlags && IsDirty()) ? plSDL::kHasDirtyFlag : 0;
saveFlags |= wantTimeStamp ? plSDL::kWantTimeStamp : 0;
saveFlags |= needTimeStamp ? plSDL::kHasTimeStamp : 0;
if (sameAsDefaults)
saveFlags |= plSDL::kSameAsDefault;
s->WriteSwap(saveFlags);
if (needTimeStamp) {
// timestamp on write
fTimeStamp.ToCurrentTime();
fTimeStamp.Write(s);
}
else if (writeTimeStamps) {
// write time stamps
fTimeStamp.Write(s);
}
// write var data
if (!sameAsDefaults)
{
// list size
if (GetVarDescriptor()->IsVariableLength())
s->WriteSwap32(GetVarDescriptor()->GetCount()); // have to write out as long since we don't know how big the list is
// list
int i;
for(i=0;i<fVar.GetCount();i++)
if (!IWriteData(s, timeConvert, i, writeOptions))
return false;
}
return true;
}
// assumes var is created from the right type of descriptor (count, type, etc.)
bool plSimpleStateVariable::ReadData(hsStream* s, float timeConvert, UInt32 readOptions)
{
// read base class data
plStateVariable::ReadData(s, timeConvert, readOptions);
plUnifiedTime ut;
ut.ToEpoch();
UInt8 saveFlags;
s->ReadSwap(&saveFlags);
bool isDirty = ( saveFlags & plSDL::kHasDirtyFlag )!=0;
bool setDirty = ( isDirty && ( readOptions & plSDL::kKeepDirty ) ) || ( readOptions & plSDL::kMakeDirty );
bool wantTimestamp = isDirty &&
plSDLMgr::GetInstance()->AllowTimeStamping() &&
( ( saveFlags & plSDL::kWantTimeStamp ) ||
( readOptions & plSDL::kTimeStampOnRead ) );
if (saveFlags & plSDL::kHasTimeStamp)
ut.Read(s);
else if ( wantTimestamp )
ut.ToCurrentTime();
if (!(saveFlags & plSDL::kSameAsDefault))
{
setDirty = setDirty || ( readOptions & plSDL::kDirtyNonDefaults )!=0;
// read list size
if (GetVarDescriptor()->IsVariableLength())
{
UInt32 cnt;
s->ReadSwap(&cnt); // have to read as long since we don't know how big the list is
if (cnt>=0 && cnt<plSDL::kMaxListSize)
fVar.SetCount(cnt);
else
return false;
Alloc(); // alloc after setting count
}
else
{
hsAssert(fVar.GetCount(), "empty var?");
}
}
// compare timestamps
if (fTimeStamp > ut)
return true;
if ( (saveFlags & plSDL::kHasTimeStamp) || (readOptions & plSDL::kTimeStampOnRead) )
TimeStamp(ut);
// read list
if (!(saveFlags & plSDL::kSameAsDefault))
{
int i;
for(i=0;i<fVar.GetCount();i++)
if (!IReadData(s, timeConvert, i, readOptions))
return false;
}
else
{
Reset();
SetFromDefaults(false);
}
SetUsed( true );
SetDirty( setDirty );
return true;
}
void plSimpleStateVariable::CopyData(const plSimpleStateVariable* other, UInt32 writeOptions/*=0*/)
{
// use stream as a medium
hsRAMStream stream;
other->WriteData(&stream, 0, writeOptions);
stream.Rewind();
ReadData(&stream, 0, writeOptions);
}
//
// send notification msg if necessary, called internally
//
#define NOTIFY_CHECK(type, var) \
case type: \
for(i=0;i<cnt;i++) \
if (hsABS(var[i] - other->var[i])>d) \
{ \
notify=true; \
break; \
} \
break;
void plSimpleStateVariable::NotifyStateChange(const plSimpleStateVariable* other, const char* sdlName)
{
if (fChangeNotifiers.size()==0)
return;
bool different=!(*this == *other);
bool notify=false;
int numNotifiers=0;
if (different)
{
StateChangeNotifiers::iterator it=fChangeNotifiers.begin();
for( ; it!=fChangeNotifiers.end(); it++)
{
float d=(*it).fDelta;
if (d==0 && different) // delta of 0 means notify on any change
{
notify=true;
}
else
{
int i;
int cnt = fVar.GetAtomicCount()*fVar.GetCount();
switch(fVar.GetAtomicType())
{
NOTIFY_CHECK(plVarDescriptor::kInt, fI)
NOTIFY_CHECK(plVarDescriptor::kShort, fS)
NOTIFY_CHECK(plVarDescriptor::kByte, fBy)
NOTIFY_CHECK(plVarDescriptor::kFloat, fF)
NOTIFY_CHECK(plVarDescriptor::kDouble, fD)
}
}
if (notify)
{
numNotifiers += (*it).fKeys.size();
(*it).SendNotificationMsg(other /* src */, this /* dst */, sdlName);
}
}
}
if (plNetObjectDebuggerBase::GetInstance() && plNetObjectDebuggerBase::GetInstance()->GetDebugging())
{
plNetObjectDebuggerBase::GetInstance()->LogMsg(
xtl::format("Var %s did %s send notification difference. Has %d notifiers with %d recipients.",
GetName(), !notify ? "NOT" : "", fChangeNotifiers.size(), numNotifiers).c_str());
}
}
//
// Checks to see if data contents are the same on two matching vars.
//
#define EQ_CHECK(type, var) \
case type: \
for(i=0;i<cnt;i++) \
if (var[i]!=other.var[i]) \
return false; \
break;
bool plSimpleStateVariable::operator==(const plSimpleStateVariable &other) const
{
hsAssert(fVar.GetType() == other.GetVarDescriptor()->GetType(), "type mismatch in equality check");
hsAssert(fVar.GetAtomicCount() == other.GetVarDescriptor()->GetAsSimpleVarDescriptor()->GetAtomicCount(),
"atomic cnt mismatch in equality check");
if (GetCount() != other.GetCount())
return false;
int i;
int cnt = fVar.GetAtomicCount()*fVar.GetCount();
switch(fVar.GetAtomicType())
{
EQ_CHECK(plVarDescriptor::kAgeTimeOfDay, fF)
EQ_CHECK(plVarDescriptor::kInt, fI)
EQ_CHECK(plVarDescriptor::kFloat, fF)
EQ_CHECK(plVarDescriptor::kTime, fT)
EQ_CHECK(plVarDescriptor::kDouble, fD)
EQ_CHECK(plVarDescriptor::kBool, fB)
EQ_CHECK(plVarDescriptor::kKey, fU)
EQ_CHECK(plVarDescriptor::kCreatable, fC)
EQ_CHECK(plVarDescriptor::kShort, fS)
EQ_CHECK(plVarDescriptor::kByte, fBy)
case plVarDescriptor::kString32:
for(i=0;i<cnt;i++)
if (stricmp(fS32[i],other.fS32[i]))
return false;
break;
default:
hsAssert(false, "invalid atomic type");
return false;
break;
}
return true;
}
//
// Add and coalate
//
void plSimpleStateVariable::AddStateChangeNotification(plStateChangeNotifier& n)
{
StateChangeNotifiers::iterator it=fChangeNotifiers.begin();
for( ; it != fChangeNotifiers.end(); it++)
{
if ((*it).fDelta==n.fDelta)
{
// merged into an existing entry
(*it).AddNotificationKeys(n.fKeys);
return;
}
}
// add new entry
fChangeNotifiers.push_back(n);
}
//
// remove entries with this key
//
void plSimpleStateVariable::RemoveStateChangeNotification(plKey notificationObj)
{
StateChangeNotifiers::iterator it=fChangeNotifiers.end();
for(; it != fChangeNotifiers.begin();)
{
it--;
int size=(*it).RemoveNotificationKey(notificationObj);
if (size==0)
it=fChangeNotifiers.erase(it); // iterator is moved to item after this one
}
}
//
// remove entries which match
//
void plSimpleStateVariable::RemoveStateChangeNotification(plStateChangeNotifier n)
{
StateChangeNotifiers::iterator it=fChangeNotifiers.end();
for(; it != fChangeNotifiers.begin();)
{
it--;
if ( (*it).fDelta==n.fDelta)
{
int size=(*it).RemoveNotificationKeys(n.fKeys);
if (size==0)
it=fChangeNotifiers.erase(it); // iterator is moved to item after this one
}
}
}
//
//
//
void plSimpleStateVariable::DumpToObjectDebugger(bool dirtyOnly, int level) const
{
plNetObjectDebuggerBase* dbg = plNetObjectDebuggerBase::GetInstance();
if (!dbg)
return;
std::string pad;
int i;
for(i=0;i<level; i++)
pad += " ";
std::string logMsg = xtl::format( "%sSimpleVar, name:%s[%d]", pad.c_str(), GetName(), GetCount());
if (GetCount()>1)
{
dbg->LogMsg(logMsg.c_str()); // it's going to be a long msg, so print it on its own line
logMsg = "";
}
pad += "\t";
for(i=0;i<GetCount(); i++)
{
char* s=GetAsString(i);
if (fVar.GetAtomicType() == plVarDescriptor::kTime)
{
const char* p=fT[i].PrintWMillis();
logMsg += xtl::format( "%sVar:%d gameTime:%s pst:%s ts:%s",
pad.c_str(), i, s ? s : "?", p, fTimeStamp.Format("%c").c_str() );
}
else
{
logMsg +=xtl::format( "%sVar:%d value:%s ts:%s",
pad.c_str(), i, s ? s : "?", fTimeStamp.AtEpoch() ? "0" : fTimeStamp.Format("%c").c_str() );
}
delete [] s;
if ( !dirtyOnly )
logMsg += xtl::format( " dirty:%d", IsDirty() );
dbg->LogMsg(logMsg.c_str());
logMsg = "";
}
}
void plSimpleStateVariable::DumpToStream(hsStream* stream, bool dirtyOnly, int level) const
{
std::string pad;
int i;
for(i=0;i<level; i++)
pad += " ";
std::string logMsg = xtl::format( "%sSimpleVar, name:%s[%d]", pad.c_str(), GetName(), GetCount());
if (GetCount()>1)
{
stream->WriteString(logMsg.c_str()); // it's going to be a long msg, so print it on its own line
logMsg = "";
}
pad += "\t";
for(i=0;i<GetCount(); i++)
{
char* s=GetAsString(i);
if (fVar.GetAtomicType() == plVarDescriptor::kTime)
{
const char* p=fT[i].PrintWMillis();
logMsg += xtl::format( "%sVar:%d gameTime:%s pst:%s ts:%s",
pad.c_str(), i, s ? s : "?", p, fTimeStamp.Format("%c").c_str() );
}
else
{
logMsg +=xtl::format( "%sVar:%d value:%s ts:%s",
pad.c_str(), i, s ? s : "?", fTimeStamp.AtEpoch() ? "0" : fTimeStamp.Format("%c").c_str() );
}
delete [] s;
if ( !dirtyOnly )
logMsg += xtl::format( " dirty:%d", IsDirty() );
stream->WriteString(logMsg.c_str());
logMsg = "";
}
}
//
// set var to its defalt value
//
void plSimpleStateVariable::SetFromDefaults(bool timeStampNow)
{
int i;
for(i=0;i<GetCount();i++)
SetFromString(GetVarDescriptor()->GetDefault(), i, timeStampNow);
}
///////////////////////////////////////////////////////////////////////////////
// plSDStateVariable
///////////////////////////////////////////////////////////////////////////////
plSDStateVariable::plSDStateVariable(plSDVarDescriptor* sdvd) : fVarDescriptor(nil)
{
Alloc(sdvd);
}
plSDStateVariable::~plSDStateVariable()
{
IDeInit();
}
//
// resize the array of state data records
//
void plSDStateVariable::Resize(int cnt)
{
int origCnt=GetCount();
// when sending, this is always freshly allocated. if you then set it to zero,
// the change won't be sent, even though the version on the server might not be zero
// for now, we're just not going to do this optimization
// we could, however, change it to (origCnt==cnt==0), because for sizes other
// than zero the bug won't happen
// if (origCnt==cnt)
// return; // no work to do
// shrinking
if (cnt<origCnt)
{
int i;
for(i=cnt;i<origCnt;i++)
delete fDataRecList[i];
}
fDataRecList.resize(cnt);
// growing
if (cnt>origCnt)
{
int i;
for(i=origCnt;i<cnt;i++)
fDataRecList[i] = TRACKED_NEW plStateDataRecord(fVarDescriptor->GetStateDescriptor());
}
SetDirty(true);
SetUsed(true);
}
//
// create/allocate data records based on the given SDVarDesc
//
void plSDStateVariable::Alloc(plSDVarDescriptor* sdvd, int listSize)
{
if (sdvd==fVarDescriptor)
{
// trick to not have to delete and recreate fVarDescriptor
fVarDescriptor=nil;
IDeInit();
fVarDescriptor=sdvd;
}
else
IDeInit(); // will delete fVarDescriptor
if (sdvd)
{
if (fVarDescriptor==nil)
{
fVarDescriptor = TRACKED_NEW plSDVarDescriptor;
fVarDescriptor->CopyFrom(sdvd);
}
int cnt = listSize==-1 ? sdvd->GetCount() : listSize;
fDataRecList.resize(cnt);
int j;
for (j=0;j<cnt; j++)
InsertStateDataRecord(TRACKED_NEW plStateDataRecord(sdvd->GetStateDescriptor()), j);
}
}
//
// help alloc fxn
//
void plSDStateVariable::Alloc(int listSize)
{
Alloc(fVarDescriptor, listSize);
}
//
// delete all records
//
void plSDStateVariable::IDeInit()
{
DataRecList::iterator it;
for (it=fDataRecList.begin(); it != fDataRecList.end(); it++)
delete *it;
fDataRecList.clear();
delete fVarDescriptor;
fVarDescriptor=nil;
}
//
// Make 'this' into a copy of 'other'.
//
void plSDStateVariable::CopyFrom(plSDStateVariable* other, UInt32 writeOptions/*=0*/)
{
// IDeInit();
Alloc(other->GetSDVarDescriptor(), other->GetCount());
int i;
for(i=0; i<other->GetCount(); i++)
fDataRecList[i]->CopyFrom(*other->GetStateDataRecord(i),writeOptions);
}
//
// Find the data items which are dirty in 'other' and
// copy them to my corresponding item.
// Requires that records have the same descriptor.
//
void plSDStateVariable::UpdateFrom(plSDStateVariable* other, UInt32 writeOptions/*=0*/)
{
hsAssert(!stricmp(other->GetSDVarDescriptor()->GetName(), fVarDescriptor->GetName()),
xtl::format("var descriptor mismatch in UpdateFrom, name %s,%s ver %d,%d",
GetName(), other->GetName()).c_str());
Resize(other->GetCount()); // make sure sizes match
bool dirtyOnly = (writeOptions & plSDL::kDirtyOnly);
int i;
for(i=0; i<other->GetCount(); i++)
{
if ( (dirtyOnly && other->GetStateDataRecord(i)->IsDirty()) ||
(!dirtyOnly &&other->GetStateDataRecord(i)->IsUsed()) )
fDataRecList[i]->UpdateFrom(*other->GetStateDataRecord(i), writeOptions);
}
}
//
// Convert all my stateDataRecords to the type defined by the 'other var'
//
void plSDStateVariable::ConvertTo(plSDStateVariable* otherSDVar, bool force )
{
plStateDescriptor* otherSD=otherSDVar->GetSDVarDescriptor()->GetStateDescriptor();
hsLogEntry( plNetApp::StaticDebugMsg( "SDSV(%p) converting %s from %s to %s (force:%d)",
this, fVarDescriptor->GetName(), fVarDescriptor->GetTypeString(),
otherSDVar->GetSDVarDescriptor()->GetTypeString(), force ) );
int j;
for(j=0;j<GetCount(); j++)
{
GetStateDataRecord(j)->ConvertTo( otherSD, force );
}
}
bool plSDStateVariable::IsDirty() const
{
if (plStateVariable::IsDirty())
return true;
int j;
for(j=0;j<GetCount(); j++)
if (GetStateDataRecord(j)->IsDirty())
return true;
return false;
}
int plSDStateVariable::GetDirtyCount() const
{
int cnt=0;
int j;
for(j=0;j<GetCount(); j++)
if (GetStateDataRecord(j)->IsDirty())
cnt++;
return cnt;
}
bool plSDStateVariable::IsUsed() const
{
if (plStateVariable::IsUsed())
return true;
int j;
for(j=0;j<GetCount(); j++)
if (GetStateDataRecord(j)->IsUsed())
return true;
return false;
}
int plSDStateVariable::GetUsedCount() const
{
int cnt=0;
int j;
for(j=0;j<GetCount(); j++)
if (GetStateDataRecord(j)->IsUsed())
cnt++;
return cnt;
}
void plSDStateVariable::GetUsedDataRecords(ConstDataRecList* recList) const
{
recList->clear();
int j;
for(j=0;j<GetCount(); j++)
if (GetStateDataRecord(j)->IsUsed())
recList->push_back(GetStateDataRecord(j));
}
void plSDStateVariable::GetDirtyDataRecords(ConstDataRecList* recList) const
{
recList->clear();
int j;
for(j=0;j<GetCount(); j++)
if (GetStateDataRecord(j)->IsDirty())
recList->push_back(GetStateDataRecord(j));
}
//
// read all SDVars
//
bool plSDStateVariable::ReadData(hsStream* s, float timeConvert, UInt32 readOptions)
{
plStateVariable::ReadData(s, timeConvert, readOptions);
UInt8 saveFlags;
s->ReadSwap(&saveFlags); // unused
// read total list size
if (GetVarDescriptor()->IsVariableLength())
{
UInt32 total;
s->ReadSwap(&total);
Resize(total);
}
// read dirty list size
int cnt;
plSDL::VariableLengthRead(s,
GetVarDescriptor()->IsVariableLength() ? 0xffffffff : GetVarDescriptor()->GetCount(), &cnt);
// if we are reading the entire list in, then we don't need to read each index
bool all = (cnt==fDataRecList.size());
// read list
int i;
for(i=0;i<cnt; i++)
{
int idx;
if (!all)
plSDL::VariableLengthRead(s,
GetVarDescriptor()->IsVariableLength() ? 0xffffffff : GetVarDescriptor()->GetCount(), &idx);
else
idx=i;
if (idx<fDataRecList.size())
fDataRecList[idx]->Read(s, timeConvert, readOptions);
else
return false;
}
return true;
}
//
// write all SDVars
//
bool plSDStateVariable::WriteData(hsStream* s, float timeConvert, UInt32 writeOptions) const
{
plStateVariable::WriteData(s, timeConvert, writeOptions);
UInt8 saveFlags=0; // unused
s->WriteSwap(saveFlags);
// write total list size
UInt32 total=GetCount();
if (GetVarDescriptor()->IsVariableLength())
s->WriteSwap(total);
// write dirty list size
bool dirtyOnly = (writeOptions & plSDL::kDirtyOnly) != 0;
int writeCnt = dirtyOnly ? GetDirtyCount() : GetUsedCount();
plSDL::VariableLengthWrite(s,
GetVarDescriptor()->IsVariableLength() ? 0xffffffff : GetVarDescriptor()->GetCount(), writeCnt);
// if we are writing the entire list in, then we don't need to read each index
bool all = (writeCnt==fDataRecList.size());
// write list
int i, written=0;
for(i=0;i<total;i++)
{
if ( (dirtyOnly && fDataRecList[i]->IsDirty()) ||
(!dirtyOnly && fDataRecList[i]->IsUsed()) )
{
if (!all)
plSDL::VariableLengthWrite(s,
GetVarDescriptor()->IsVariableLength() ? 0xffffffff : GetVarDescriptor()->GetCount(), i); // idx
fDataRecList[i]->Write(s, timeConvert, dirtyOnly); // item
written++;
}
}
hsAssert(writeCnt==written, "write mismatch");
return true;
}
//
//
//
void plSDStateVariable::DumpToObjectDebugger(bool dirtyOnly, int level) const
{
plNetObjectDebuggerBase* dbg = plNetObjectDebuggerBase::GetInstance();
if (!dbg)
return;
std::string pad;
int i;
for(i=0;i<level; i++)
pad += " ";
int cnt = dirtyOnly ? GetDirtyCount() : GetUsedCount();
dbg->LogMsg(xtl::format( "%sSDVar, name:%s dirtyOnly:%d count:%d",
pad.c_str(), GetName(), dirtyOnly, cnt).c_str());
for(i=0;i<GetCount();i++)
{
if ( (dirtyOnly && fDataRecList[i]->IsDirty()) ||
(!dirtyOnly && fDataRecList[i]->IsUsed()) )
{
fDataRecList[i]->DumpToObjectDebugger(nil, dirtyOnly, level+1);
}
}
}
void plSDStateVariable::DumpToStream(hsStream* stream, bool dirtyOnly, int level) const
{
std::string pad;
int i;
for(i=0;i<level; i++)
pad += " ";
int cnt = dirtyOnly ? GetDirtyCount() : GetUsedCount();
stream->WriteString(xtl::format( "%sSDVar, name:%s dirtyOnly:%d count:%d",
pad.c_str(), GetName(), dirtyOnly, cnt).c_str());
for(i=0;i<GetCount();i++)
{
if ( (dirtyOnly && fDataRecList[i]->IsDirty()) ||
(!dirtyOnly && fDataRecList[i]->IsUsed()) )
{
fDataRecList[i]->DumpToStream(stream, nil, dirtyOnly, level+1);
}
}
}
//
// Checks to see if data contents are the same on two matching vars.
//
bool plSDStateVariable::operator==(const plSDStateVariable &other) const
{
hsAssert(GetSDVarDescriptor()->GetStateDescriptor() == other.GetSDVarDescriptor()->GetStateDescriptor(),
"SD var descriptor mismatch in equality check");
if (GetCount() != other.GetCount())
return false; // different list sizes
int i;
for(i=0;i<GetCount(); i++)
{
if (! (*GetStateDataRecord(i) == *other.GetStateDataRecord(i)))
return false;
}
return true;
}
void plSDStateVariable::SetFromDefaults(bool timeStampNow)
{
int i;
for(i=0;i<GetCount(); i++)
GetStateDataRecord(i)->SetFromDefaults(timeStampNow);
}
void plSDStateVariable::TimeStamp( const plUnifiedTime & ut/*=plUnifiedTime::GetCurrentTime()*/ )
{
hsAssert( false, "not impl" );
}
void plSDStateVariable::FlagNewerState(const plSDStateVariable& other, bool respectAlwaysNew)
{
int i;
for(i=0;i<GetCount(); i++)
GetStateDataRecord(i)->FlagNewerState(*other.GetStateDataRecord(i), respectAlwaysNew);
}
void plSDStateVariable::FlagAlwaysNewState()
{
int i;
for(i=0;i<GetCount(); i++)
GetStateDataRecord(i)->FlagAlwaysNewState();
}