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.
2779 lines
67 KiB
2779 lines
67 KiB
14 years ago
|
/*==LICENSE==*
|
||
|
|
||
|
CyanWorlds.com Engine - MMOG client, server and tools
|
||
13 years ago
|
Copyright (C) 2011 Cyan Worlds, Inc.
|
||
14 years ago
|
|
||
|
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
|
||
13 years ago
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
14 years ago
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
13 years ago
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
Additional permissions under GNU GPL version 3 section 7
|
||
|
|
||
|
If you modify this Program, or any covered work, by linking or
|
||
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||
|
(or a modified version of those libraries),
|
||
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||
|
licensors of this Program grant you additional
|
||
|
permission to convey the resulting work. Corresponding Source for a
|
||
|
non-source form of such a combination shall include the source code for
|
||
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||
|
work.
|
||
14 years ago
|
|
||
|
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();
|
||
|
}
|