1
0
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-20 04:09:16 +00:00

Initial Commit of CyanWorlds.com Engine Open Source Client/Plugin

This commit is contained in:
JWPlatt
2011-03-12 12:34:52 -05:00
commit a20a222fc2
3976 changed files with 1301355 additions and 0 deletions

View File

@ -0,0 +1,72 @@
#===============================================
# Changing an SDL record? Be sure to leave the
# legacy record intact and make changes in
# a new copy of the record. - eap
#===============================================
#
# Animation State Description
#
#
# Defines the state of an animation controller
#
STATEDESC AnimTimeConvert
{
VERSION 5
VAR INT flags[1] DEFAULT=0
VAR FLOAT lastStateAnimTime[1] DEFAULT=0
VAR FLOAT loopEnd[1] DEFAULT=0
VAR FLOAT loopBegin[1] DEFAULT=0
VAR FLOAT speed[1] DEFAULT=1
VAR CREATABLE speedEaseCurve[1]
VAR BYTE currentEaseCurve[1] DEFAULT=0 # 0=nil, 1=easeIn, 2=easeOut, 3=speed
VAR TIME currentEaseBeginWorldTime[1] DEFAULT=0
VAR TIME lastStateChange[1] DEFAULT=0
}
STATEDESC AnimTimeConvert
{
VERSION 6
VAR INT flags[1] DEFAULT=0
VAR FLOAT lastStateAnimTime[1] DEFAULT=0
VAR FLOAT loopEnd[1] DEFAULT=0
VAR FLOAT loopBegin[1] DEFAULT=0
VAR FLOAT speed[1] DEFAULT=1
VAR BYTE currentEaseCurve[1] DEFAULT=0 # 0=nil, 1=easeIn, 2=easeOut, 3=speed
VAR TIME currentEaseBeginWorldTime[1] DEFAULT=0
VAR TIME lastStateChange[1] DEFAULT=0
}
#
# TOP LEVEL
# Describes the state of an animated object (non-material)
#
STATEDESC AGMaster
{
VERSION 5
VAR $AnimTimeConvert atcs[] # variable length list
VAR BYTE blends[]
}
#
# TOP LEVEL
# Describes the state of an animated layer
#
STATEDESC Layer
{
VERSION 6
VAR $AnimTimeConvert atc[1]
VAR INT passThruChannels[1] DEFAULT=0
VAR FLOAT transform[] # Size will be 0 or 16, depending on whether we own the channel
VAR BYTE channelData[] # A byte array for the channels below. Its size
# will depend on the layer's fOwnedChannels.
#VAR RGB8 preshadeColor[1] DEFAULT=(1,1,1)
#VAR RGB8 runtimeColor[1] DEFAULT=(1,1,1)
#VAR RGB8 ambientColor[1] DEFAULT=(1,1,1)
#VAR BYTE opacity[1] DEFAULT=255
}

View File

@ -0,0 +1,150 @@
#===============================================
# Changing an SDL record? Be sure to leave the
# legacy record intact and make changes in
# a new copy of the record. - eap
#===============================================
#
# Avatar State Description
# You might want to read these from the bottom of the file up to get the top-down perspective
#
#
# Defines a standard anim stage (used by the genericBrain)
#
STATEDESC standardStage
{
VERSION 2
VAR STRING32 name[1]
VAR SHORT numLoops[1] DEFAULT=0 # -1=loopForever
VAR BYTE forward[1] DEFAULT=0 # 0=none, 1=kbd, 2=auto
VAR BYTE backward[1] DEFAULT=0 # 0=none, 1=kbd
VAR BYTE stageAdvance[1] DEFAULT=0 # 0=none, 1=auto
VAR BYTE stageRegress[1] DEFAULT=0 # 0=none, 1=auto
VAR BOOL notifyEnter[1] DEFAULT=false
VAR BOOL notifyLoop[1] DEFAULT=false
VAR BOOL notifyStageAdvance[1] DEFAULT=false
VAR BOOL notifyStageRegress[1] DEFAULT=false
VAR BOOL useGlobalCoords[1] DEFAULT=false
VAR FLOAT localTime[1] DEFAULT=0
VAR FLOAT length[1] DEFAULT=0
VAR SHORT currentLoop[1] DEFAULT=0
VAR BOOL isAttached[1] DEFAULT=false
}
STATEDESC standardStage
{
VERSION 3
VAR STRING32 name[1]
VAR SHORT numLoops[1] DEFAULT=0 # -1=loopForever
VAR BYTE forward[1] DEFAULT=0 # 0=none, 1=kbd, 2=auto
VAR BYTE backward[1] DEFAULT=0 # 0=none, 1=kbd
VAR BYTE stageAdvance[1] DEFAULT=0 # 0=none, 1=auto
VAR BYTE stageRegress[1] DEFAULT=0 # 0=none, 1=auto
VAR BOOL notifyEnter[1] DEFAULT=false
VAR BOOL notifyLoop[1] DEFAULT=false
VAR BOOL notifyStageAdvance[1] DEFAULT=false
VAR BOOL notifyStageRegress[1] DEFAULT=false
VAR BOOL useGlobalCoords[1] DEFAULT=false
VAR FLOAT localTime[1] DEFAULT=0
VAR SHORT currentLoop[1] DEFAULT=0
VAR BOOL isAttached[1] DEFAULT=false
}
#
# State for the plAvBrainGeneric
#
STATEDESC genericBrain
{
VERSION 3
VAR BOOL noBrain[1] DEFAULT=true # set if not a brain
VAR $standardStage stages[]
VAR BYTE currentStage[1] DEFAULT=0
VAR BOOL freezePhysicalAtEnd[1] DEFAULT=false
VAR PLKEY callbackRcvr[1]
VAR BOOL movingForward[1] DEFAULT=true
VAR BYTE exitFlags[1] DEFAULT=0
VAR BYTE type[1] # could be byte
VAR BYTE mode[1] # could be byte
VAR FLOAT fadeIn[1] DEFAULT=1.0
VAR FLOAT fadeOut[1] DEFAULT=1.0
VAR BYTE moveMode[1] # could be byte
VAR BYTE bodyUsage[1] # could be byte
}
#
# State for the plAvBrainClimb
#
STATEDESC climbBrain
{
VERSION 1
VAR INT curMode[1]
VAR INT nextMode[1]
VAR INT allowedDirections[1]
VAR INT allowedDismounts[1]
VAR FLOAT vertProbeLength[1]
VAR FLOAT horizProbeLength[1]
VAR BOOL curStageAttached[1]
VAR INT curStage[1]
VAR FLOAT curStageTime[1]
VAR FLOAT curStageStrength[1]
VAR BOOL exitStageAttached[1]
VAR INT exitStage[1]
VAR FLOAT exitStageTime[1]
VAR BOOL exitStageStrength[1]
}
STATEDESC driveBrain
{
VERSION 1
VAR INT unUsed[1]
}
#
# A pseudo-union structure. It looks like it contains several varying-length
# arrays, but in reality only one of them has anything in it, and only one
# brain at that.
STATEDESC brainUnion
{
VERSION 1
VAR $genericBrain fGenericBrain[]
VAR $climbBrain fClimbBrain[]
VAR $driveBrain fDriveBrain[]
}
#
# The base block contains state for the plAvBrainHuman (which all avatars must have)
# and a variable-length state of brains of varying type.
#
STATEDESC avatar
{
VERSION 5
VAR $brainUnion brainStack[]
VAR BYTE invisibilityLevel[1] DEFAULT=0 # 0 means visible, >0 is CCR level of invisibility
}
STATEDESC avatar
{
VERSION 6
VAR $brainUnion brainStack[]
VAR BYTE invisibilityLevel[1] DEFAULT=0 # 0 means visible, >0 is CCR level of invisibility
VAR POINT3 position[1] DEFAULT=(0,0,0)
VAR FLOAT rotation[1] DEFAULT=0.0
VAR PLKEY subworld[1]
}
STATEDESC avatar
{
VERSION 7
VAR $brainUnion brainStack[]
VAR BYTE invisibilityLevel[1] DEFAULT=0 # 0 means visible, >0 is CCR level of invisibility
}
STATEDESC avatarPhysical
{
VERSION 1
VAR POINT3 position[1] DEFAULT=(0,0,0)
VAR FLOAT rotation[1] DEFAULT=0.0
VAR PLKEY subworld[1]
}

View File

@ -0,0 +1,23 @@
#===============================================
# Changing an SDL record? Be sure to leave the
# legacy record intact and make changes in
# a new copy of the record. - eap
#===============================================
#
# State Description Language for a LoadClone message
# Currently only used by the gameserver to store a loadClone msg as dynamic object state
#
#
# This is the only SDL file allowed to use the "CREATABLE" type. Normally that type is
# a security hole. We can't guarantee that trying to read a creatable on an arbitrary
# (i.e. hacked) stream won't crash the game. However, since this state is generated by the
# server, we can trust that.
#
STATEDESC CloneMessage
{
VERSION 1
VAR CREATABLE message[1] # The message as a creatable stream
}

View File

@ -0,0 +1,46 @@
#===============================================
# Changing an SDL record? Be sure to leave the
# legacy record intact and make changes in
# a new copy of the record. - eap
#===============================================
#
# State Description for an avatar's clothing
#
#
# Helper SDL desc
# Defines an item of clothing
#
STATEDESC clothingItem
{
VERSION 3 # version is an int
VAR PLKEY item[1]
VAR RGB8 tint[1] DEFAULT=(1,1,1)
VAR RGB8 tint2[1] DEFAULT=(1,1,1)
}
#
# Helper SDL desc
# Defines appearance options
#
STATEDESC appearanceOptions
{
VERSION 2
VAR RGB8 skinTint[1] DEFAULT=(1,1,1)
VAR BYTE faceBlends[] DEFAULT=0;
}
#
# Top level SDL desc
# A variable-length list of clothing items
#
STATEDESC clothing
{
VERSION 4
VAR $clothingItem wardrobe[]
VAR $appearanceOptions appearance[1]
VAR PLKEY linkInAnim[1] DEFAULT=nil
}

View File

@ -0,0 +1,28 @@
#===============================================
# Changing an SDL record? Be sure to leave the
# legacy record intact and make changes in
# a new copy of the record. - eap
#===============================================
#
# State Description for a morph sequence modifier
#
STATEDESC MorphSet
{
VERSION 2
VAR PLKEY mesh[1] DEFAULT=nil
VAR BYTE weights[] DEFAULT=0
}
STATEDESC MorphSequence
{
VERSION 2
# User data. The avatar sets this so that it can later differentiate between
# various records in the vault
VAR BYTE targetID[1] DEFAULT=0
VAR $MorphSet morphs[]
}

View File

@ -0,0 +1,17 @@
#===============================================
# Changing an SDL record? Be sure to leave the
# legacy record intact and make changes in
# a new copy of the record. - eap
#===============================================
#
# State Description for a morph sequence modifier
# 99% of the particle systems won't need this (and won't save state)
# This is intended for cloned systems that attach to the avatar.
#
STATEDESC ParticleSystem
{
VERSION 1
VAR INT numParticles[1] DEFAULT=0
}

View File

@ -0,0 +1,23 @@
#===============================================
# Changing an SDL record? Be sure to leave the
# legacy record intact and make changes in
# a new copy of the record. - eap
#===============================================
#
# State Description Language for
# physical changes to an object
#
STATEDESC physical
{
VERSION 2
VAR POINT3 position[1] DEFAULT=(0,0,0)
VAR QUATERNION orientation[1] DEFAULT=(0,0,0,1)
VAR VECTOR3 linear[1] DEFAULT=(0,0,0)
VAR VECTOR3 angular[1] DEFAULT=(0,0,0)
VAR PLKEY subworld[1]
}

View File

@ -0,0 +1,24 @@
#===============================================
# Changing an SDL record? Be sure to leave the
# legacy record intact and make changes in
# a new copy of the record. - eap
#===============================================
#
# State Description Language for a responder
#
STATEDESC Responder
{
VERSION 3
VAR INT curState[1] DEFAULT=0 # The current state (first index for fCommandList)
VAR INT curCommand[1] DEFAULT=-1 # The command we are currently waiting to send
# (or -1 if we're not sending)
VAR BOOL netRequest[1] DEFAULT=false # Was the last trigger a net request
VAR INT completedEvents[] # Which events that commands are waiting on have completed
VAR BOOL enabled[1] DEFAULT=true
VAR PLKEY playerKey[1] # The player who triggered this last
VAR PLKEY triggerer[1] # Whoever triggered us (for sending notify callbacks)
}

View File

@ -0,0 +1,29 @@
#===============================================
# Changing an SDL record? Be sure to leave the
# legacy record intact and make changes in
# a new copy of the record. - eap
#===============================================
#
# State Description Language for sounds
#
STATEDESC SoundState
{
VERSION 1
VAR FLOAT desiredVolume[1] DEFAULT=0 # 0 to 1
VAR TIME time[1] DEFAULT=0 # time sound was started
VAR BOOL playing[1] DEFAULT=false # is it playing
}
#
# Describes the sound state for a sceneObject
# TOPLEVEL
#
STATEDESC Sound
{
VERSION 1
VAR $SoundState sounds[] # List of soundStates on a sceneObject
}

View File

@ -0,0 +1,15 @@
#===============================================
# Changing an SDL record? Be sure to leave the
# legacy record intact and make changes in
# a new copy of the record. - eap
#===============================================
#
# State Description Language for Exclude Regions
#
STATEDESC XRegion
{
VERSION 1
VAR BOOL cleared[1] DEFAULT=false # is it cleared
}

View File

@ -0,0 +1,552 @@
/*==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==*/
#ifndef PL_SDL_inc
#define PL_SDL_inc
//
// Code for the State Description Language (SDL)
//
#include "plSDLDescriptor.h"
#include "hsUtils.h"
#include "hsStlUtils.h"
#include "../pnFactory/plCreatable.h"
#include "../pnKeyedObject/plKey.h"
#include "../pnKeyedObject/plUoid.h"
#include "../plUnifiedTime/plUnifiedTime.h"
namespace plSDL
{
typedef std::list<plStateDescriptor*> DescriptorList;
enum GeneralPurpose
{
kLatestVersion = -1, // used when requesting the latest version of a state descriptor
kMaxListSize = 9999 // maximum size of var lists
};
enum ContentsFlags // or saveFlags, 16 bits
{
kHasUoid = 0x1,
kHasNotificationInfo = 0x2,
kHasTimeStamp = 0x4,
kSameAsDefault = 0x8,
kHasDirtyFlag = 0x10,
kWantTimeStamp = 0x20,
kAddedVarLengthIO = 0x8000, // using to establish a new version in the header, can delete in 8/03
kHasMaximumValue= 0xffff,
};
enum RWOptions
{
kDirtyOnly = 1<< 0, // write option
kSkipNotificationInfo = 1<< 1, // read/write option
kBroadcast = 1<< 2, // send option
kWriteTimeStamps = 1<< 3, // write out time stamps
kTimeStampOnRead = 1<< 4, // read: timestamp each var when it gets read. write: request that the reader timestamp the dirty vars.
kTimeStampOnWrite = 1<< 5, // read: n/a. write: timestamp each var when it gets written.
kKeepDirty = 1<< 6, // don't clear dirty flag on read
kDontWriteDirtyFlag = 1<< 7, // write option. don't write var dirty flag.
kMakeDirty = 1<< 8, // read/write: set dirty flag on var read/write.
kDirtyNonDefaults = 1<< 9, // dirty the var if non default value.
kForceConvert = 1<<10, // always try to convert rec to latest on read
};
enum BehaviorFlags
{
kDisallowTimeStamping = 0x1,
};
extern const char* kAgeSDLObjectName;
void VariableLengthRead(hsStream* s, int size, int* val);
void VariableLengthWrite(hsStream* s, int size, int val);
};
class plStateVarNotificationInfo
{
private:
std::string fHintString;
public:
void SetHintString(const char* c) { fHintString=c; }
const char* GetHintString() const { return fHintString.c_str(); }
void Read(hsStream* s, UInt32 readOptions);
void Write(hsStream* s, UInt32 writeOptions) const;
};
//
// Base class for a state variable.
// A state var is a var descriptor and it's value (contents)
//
class plSimpleStateVariable;
class plSDStateVariable;
class plStateVariable
{
public:
enum Flags
{
kDirty = 0x1, // true when someone sets the value using Set(...), can be cleared after writing
kUsed = 0x2 // true when it contains some value (either by Set(...) or Read() )
};
protected:
UInt32 fFlags;
plStateVarNotificationInfo fNotificationInfo;
public:
plStateVariable() : fFlags(0) {}
virtual ~plStateVariable() {}
const char* GetName() const { return GetVarDescriptor()->GetName(); }
bool IsNamed(const char* n) const { return (n && !stricmp(GetName(), n)); }
virtual int GetCount() const = 0;
// conversion ops
virtual plSimpleStateVariable* GetAsSimpleStateVar() = 0;
virtual plSDStateVariable* GetAsSDStateVar() = 0;
virtual plVarDescriptor* GetVarDescriptor() = 0;
virtual const plVarDescriptor* GetVarDescriptor() const = 0;
virtual void Alloc(int cnt=-1 /* -1 means don't change count */) = 0;
virtual bool IsDirty() const { return (fFlags & kDirty) != 0; }
virtual bool IsUsed() const { return (fFlags & kUsed) != 0; }
void SetDirty(bool d) { if (d) fFlags |= kDirty; else fFlags &= ~kDirty; }
void SetUsed(bool d) { if (d) fFlags |= kUsed; else fFlags &= ~kUsed; }
virtual void SetFromDefaults(bool timeStampNow) = 0;
virtual void TimeStamp( const plUnifiedTime & ut=plUnifiedTime::GetCurrentTime() ) = 0;
virtual const plUnifiedTime& GetTimeStamp() const = 0;
plStateVarNotificationInfo& GetNotificationInfo() { return fNotificationInfo; }
const plStateVarNotificationInfo& GetNotificationInfo() const { return fNotificationInfo; }
virtual void DumpToObjectDebugger(bool dirtyOnly, int level) const {}
virtual void DumpToStream(hsStream* stream, bool dirtyOnly, int level) const {}
// IO
virtual bool ReadData(hsStream* s, float timeConvert, UInt32 readOptions);
virtual bool WriteData(hsStream* s, float timeConvert, UInt32 writeOptions) const;
};
//
// Change Notifier.
// When a plSimpleStateVariable changes it's value by more than the given delta value,
// a notification msg will be sent to the objects that registered interest.
//
class plStateChangeNotifier
{
friend class plSimpleStateVariable;
private:
float fDelta;
typedef std::vector<plKey> KeyList;
KeyList fKeys; // the objects to notify on change>delta
static UInt32 fCurrentPlayerID;
void IAddKey(plKey k);
int IRemoveKey(plKey k);
public:
plStateChangeNotifier();
plStateChangeNotifier(float i, plKey k);
void AddNotificationKey(plKey k) { IAddKey(k); }
void AddNotificationKeys(KeyList keys);
int RemoveNotificationKey(plKey k); // returns number of keys left after removal
int RemoveNotificationKeys(KeyList keys); // returns number of keys left after removal
void SendNotificationMsg(const plSimpleStateVariable* srcVar, const plSimpleStateVariable* dstVar, const char* sdlName);
bool GetValue(float* i) const;
bool SetValue(float i);
static UInt32 GetCurrentPlayerID() { return fCurrentPlayerID; }
static void SetCurrentPlayerID(UInt32 p) { fCurrentPlayerID=p; }
bool operator==(const plStateChangeNotifier &) const;
};
//
// A (non-nested) variable descriptor and its data contents.
//
class plUoid;
class plKey;
class plClientUnifiedTime;
typedef unsigned char byte;
class plSimpleStateVariable : public plStateVariable
{
protected:
union
{
int* fI; // array of int
short* fS; // array of short
byte* fBy; // array of byte
float* fF; // array of float
double* fD; // array of double
bool* fB; // array of bool
plUoid* fU; // array of uoid
plCreatable** fC; // array of plCreatable ptrs
plVarDescriptor::String32* fS32; // array of strings
plClientUnifiedTime* fT; // array of Times
};
mutable plUnifiedTime fTimeStamp; // the last time the var was changed
plSimpleVarDescriptor fVar;
typedef std::vector<plStateChangeNotifier> StateChangeNotifiers;
StateChangeNotifiers fChangeNotifiers;
void IDeAlloc();
void IInit(); // initize vars
void IVarSet(bool timeStampNow=false);
// converter fxns
bool IConvertFromBool(plVarDescriptor::Type newType);
bool IConvertFromInt(plVarDescriptor::Type newType);
bool IConvertFromByte(plVarDescriptor::Type newType);
bool IConvertFromShort(plVarDescriptor::Type newType);
bool IConvertFromFloat(plVarDescriptor::Type newType);
bool IConvertFromDouble(plVarDescriptor::Type newType);
bool IConvertFromString(plVarDescriptor::Type newType);
bool IConvertFromRGB(plVarDescriptor::Type newType);
bool IConvertFromRGBA(plVarDescriptor::Type newType);
bool IConvertFromRGB8(plVarDescriptor::Type newType);
bool IConvertFromRGBA8(plVarDescriptor::Type newType);
bool IReadData(hsStream* s, float timeConvert, int idx, UInt32 readOptions);
bool IWriteData(hsStream* s, float timeConvert, int idx, UInt32 writeOptions) const;
public:
plSimpleStateVariable() { IInit(); }
plSimpleStateVariable(plVarDescriptor* vd) { IInit(); CopyFrom(vd); }
~plSimpleStateVariable() { IDeAlloc(); }
// conversion ops
plSimpleStateVariable* GetAsSimpleStateVar() { return this; }
plSDStateVariable* GetAsSDStateVar() { return nil; }
bool operator==(const plSimpleStateVariable &other) const; // assumes matching var descriptors
void TimeStamp( const plUnifiedTime & ut=plUnifiedTime::GetCurrentTime() );
void CopyFrom(plVarDescriptor* v);
void CopyData(const plSimpleStateVariable* other, UInt32 writeOptions=0);
bool SetFromString(const char* value, int idx, bool timeStampNow); // set value from string, type. return false on err
char* GetAsString(int idx) const;
bool ConvertTo(plSimpleVarDescriptor* toVar, bool force=false); // return false on err
void Alloc(int cnt=-1 /* -1 means don't change count */); // alloc memory after setting type
void Reset();
// setters
bool Set(float v, int idx=0);
bool Set(float* v, int idx=0); // floatVector
bool Set(double v, int idx=0);
bool Set(double* v, int idx=0); // doubleVector
bool Set(int v, int idx=0);
bool Set(int* v, int idx=0) { return Set(*v, idx); } // helper since there is no int vec type
bool Set(byte v, int idx=0);
bool Set(byte* v, int idx=0); // byteVector
bool Set(short v, int idx=0);
bool Set(short* v, int idx=0) { return Set(*v, idx); } // helper since there is no short vec type
bool Set(bool v, int idx=0);
bool Set(bool* v, int idx=0) { return Set(*v, idx); } // helper since there is no bool vec type
bool Set(const char* v, int idx=0); // string
bool Set(const plKey& v, int idx=0);
bool Set(plCreatable*, int idx=0); // only SDL generated by the server is allowed to use this type.
void SetFromDefaults(bool timeStampNow);
// getters
bool Get(int* value, int idx=0) const;
bool Get(short* value, int idx=0) const;
bool Get(byte* value, int idx=0) const; // returns byte or byteVector
bool Get(float* value, int idx=0) const; // returns float or floatVector
bool Get(double* value, int idx=0) const; // returns double or doubleVector
bool Get(bool* value, int idx=0) const;
bool Get(char value[], int idx=0) const;
bool Get(plKey* value, int idx=0) const;
bool Get(plCreatable** value, int idx=0) const;
const plUnifiedTime& GetTimeStamp() const { return fTimeStamp; }
// Special backdoor so the KI Manager can get the key name without having a ResMgr
const char* GetKeyName(int idx=0) const;
int GetCount() const { return fVar.GetCount(); } // helper
plVarDescriptor* GetVarDescriptor() { return &fVar; }
plSimpleVarDescriptor* GetSimpleVarDescriptor() { return fVar.GetAsSimpleVarDescriptor(); }
const plVarDescriptor* GetVarDescriptor() const { return &fVar; }
const plSimpleVarDescriptor* GetSimpleVarDescriptor() const { return fVar.GetAsSimpleVarDescriptor(); }
// State Change Notification
void AddStateChangeNotification(plStateChangeNotifier& n);
void RemoveStateChangeNotification(plKey notificationObj); // remove all with this key
void RemoveStateChangeNotification(plStateChangeNotifier n); // remove ones which match
void NotifyStateChange(const plSimpleStateVariable* other, const char* sdlName); // send notification msg if necessary, internal use
void DumpToObjectDebugger(bool dirtyOnly, int level) const;
void DumpToStream(hsStream* stream, bool dirtyOnly, int level) const;
// IO
bool ReadData(hsStream* s, float timeConvert, UInt32 readOptions);
bool WriteData(hsStream* s, float timeConvert, UInt32 writeOptions) const;
};
//
// A list of state data records, all of which are the same kind.
// Corresponds to a SD var descriptor.
//
class plStateDataRecord;
class plSDStateVariable : public plStateVariable
{
public:
typedef std::vector<const plStateDataRecord*> ConstDataRecList;
protected:
typedef std::vector<plStateDataRecord*> DataRecList;
DataRecList fDataRecList;
plSDVarDescriptor* fVarDescriptor;
void IDeInit();
public:
plSDStateVariable(plSDVarDescriptor* sdvd);
~plSDStateVariable(); // delete all records
// conversion ops
plSimpleStateVariable* GetAsSimpleStateVar() { return nil; }
plSDStateVariable* GetAsSDStateVar() { return this; }
bool operator==(const plSDStateVariable &other) const; // assumes matching var descriptors
void ConvertTo(plSDStateVariable* otherSDVar, bool force=false);
void CopyFrom(plSDStateVariable* other, UInt32 writeOptions=0);
void UpdateFrom(plSDStateVariable* other, UInt32 writeOptions=0);
void AddStateDataRecord(plStateDataRecord *sdr) { fDataRecList.push_back(sdr); SetDirty(true); SetUsed(true); }
void InsertStateDataRecord(plStateDataRecord *sdr, int i) { fDataRecList[i] = sdr; SetDirty(true); SetUsed(true);}
void SetFromDefaults(bool timeStampNow);
void TimeStamp( const plUnifiedTime & ut=plUnifiedTime::GetCurrentTime() );
const plUnifiedTime& GetTimeStamp() const { static plUnifiedTime foo; return foo; }
void Alloc(int cnt=-1 /* -1 means don't change count */); // wipe and re-create
void Alloc(plSDVarDescriptor* sdvd, int cnt=-1); // wipe and re-create
void Resize(int cnt);
bool IsDirty() const;
bool IsUsed() const;
// getters
plStateDataRecord* GetStateDataRecord(int i) { return fDataRecList[i]; }
const plStateDataRecord* GetStateDataRecord(int i) const { return fDataRecList[i]; }
int GetCount() const { return fDataRecList.size(); }
int GetUsedCount() const;
int GetDirtyCount() const;
void GetUsedDataRecords(ConstDataRecList*) const;
void GetDirtyDataRecords(ConstDataRecList*) const;
plVarDescriptor* GetVarDescriptor() { return fVarDescriptor; }
plSDVarDescriptor* GetSDVarDescriptor() { return fVarDescriptor->GetAsSDVarDescriptor(); }
const plVarDescriptor* GetVarDescriptor() const { return fVarDescriptor; }
const plSDVarDescriptor* GetSDVarDescriptor() const { return fVarDescriptor->GetAsSDVarDescriptor(); }
void FlagNewerState(const plSDStateVariable&, bool respectAlwaysNew);
void FlagAlwaysNewState();
void DumpToObjectDebugger(bool dirtyOnly, int level) const;
void DumpToStream(hsStream* stream, bool dirtyOnly, int level) const;
// IO
bool ReadData(hsStream* s, float timeConvert, UInt32 readOptions);
bool WriteData(hsStream* s, float timeConvert, UInt32 writeOptions) const;
};
//
// Contains the actual data contents and points to its associated descriptor
//
class plNetMsgSDLState;
class plStateDataRecord : public plCreatable
{
public:
typedef std::vector<plSimpleStateVariable*> SimpleVarsList;
typedef std::vector<plSDStateVariable*> SDVarsList;
enum Flags
{
kVolatile = 0x1
};
protected:
typedef std::vector<plStateVariable*> VarsList;
const plStateDescriptor* fDescriptor;
plUoid fAssocObject; // optional
VarsList fVarsList; // list of variables
VarsList fSDVarsList; // list of nested data records
UInt32 fFlags;
static const UInt8 kIOVersion; // I/O Version
void IDeleteVarsList(VarsList& vars);
void IInitDescriptor(const char* name, int version); // or plSDL::kLatestVersion
void IInitDescriptor(const plStateDescriptor* sd);
void IReadHeader(hsStream* s);
void IWriteHeader(hsStream* s) const;
bool IConvertVar(plSimpleStateVariable* fromVar, plSimpleStateVariable* toVar, bool force);
plStateVariable* IFindVar(const VarsList& vars, const char* name) const;
int IGetNumUsedVars(const VarsList& vars) const;
int IGetUsedVars(const VarsList& varsOut, VarsList *varsIn) const; // build a list of vars that have data
bool IHasUsedVars(const VarsList& vars) const;
int IGetNumDirtyVars(const VarsList& vars) const;
int IGetDirtyVars(const VarsList& varsOut, VarsList *varsIn) const; // build a list of vars that are dirty
bool IHasDirtyVars(const VarsList& vars) const;
public:
CLASSNAME_REGISTER( plStateDataRecord );
GETINTERFACE_ANY( plStateDataRecord, plCreatable);
plStateDataRecord(const char* sdName, int version=plSDL::kLatestVersion);
plStateDataRecord(plStateDescriptor* sd);
plStateDataRecord(const plStateDataRecord &other, UInt32 writeOptions=0 ):fFlags(0) { CopyFrom(other, writeOptions); }
plStateDataRecord():fFlags(0) {}
~plStateDataRecord();
bool ConvertTo(plStateDescriptor* other, bool force=false );
bool operator==(const plStateDataRecord &other) const; // assumes matching state descriptors
UInt32 GetFlags() const { return fFlags; }
void SetFlags(UInt32 f) { fFlags =f; }
plSimpleStateVariable* FindVar(const char* name) const { return (plSimpleStateVariable*)IFindVar(fVarsList, name); }
plSDStateVariable* FindSDVar(const char* name) const { return (plSDStateVariable*)IFindVar(fSDVarsList, name); }
plStateDataRecord& operator=(const plStateDataRecord& other) { CopyFrom(other); }
void CopyFrom(const plStateDataRecord& other, UInt32 writeOptions=0);
void UpdateFrom(const plStateDataRecord& other, UInt32 writeOptions=0);
void SetFromDefaults(bool timeStampNow);
void TimeStampDirtyVars();
int GetNumVars() const { return fVarsList.size(); }
plSimpleStateVariable* GetVar(int i) const { return (plSimpleStateVariable*)fVarsList[i]; }
int GetNumSDVars() const { return fSDVarsList.size(); }
plSDStateVariable* GetSDVar(int i) const { return (plSDStateVariable*)fSDVarsList[i]; }
// Used vars
bool IsUsed() const { return (HasUsedVars() || HasUsedSDVars()); }
int GetNumUsedVars() const { return IGetNumUsedVars(fVarsList); }
int GetUsedVars(SimpleVarsList *vars) const { return IGetUsedVars(fVarsList, (VarsList*)vars); } // build a list of vars that have data
bool HasUsedVars() const { return IHasUsedVars(fVarsList); }
int GetNumUsedSDVars() const { return IGetNumUsedVars(fSDVarsList); }
int GetUsedSDVars(SDVarsList *vars) const { return IGetUsedVars(fSDVarsList, (VarsList*)vars); } // build a list of SD vars that have data
bool HasUsedSDVars() const { return IHasUsedVars(fSDVarsList); }
// Dirty Vars
bool IsDirty() const { return (HasDirtyVars() || HasDirtySDVars()); }
int GetNumDirtyVars() const { return IGetNumDirtyVars(fVarsList); }
int GetDirtyVars(SimpleVarsList *vars) const { return IGetDirtyVars(fVarsList, (VarsList*)vars); } // build a list of vars that are dirty
bool HasDirtyVars() const { return IHasDirtyVars(fVarsList); }
int GetNumDirtySDVars() const { return IGetNumDirtyVars(fSDVarsList); }
int GetDirtySDVars(SDVarsList *vars) const { return IGetDirtyVars(fSDVarsList, (VarsList*)vars); }; // build a list of Sdvars that are dirty
bool HasDirtySDVars() const { return IHasDirtyVars(fSDVarsList); }
const plStateDescriptor* GetDescriptor() const { return fDescriptor; }
void SetDescriptor(const char* sdName, int version);
plNetMsgSDLState* PrepNetMsg(float timeConvert, UInt32 writeOptions) const; // create/prep a net msg with this data
void SetAssocObject(const plUoid& u) { fAssocObject=u; } // optional
plUoid* GetAssocObject() { return &fAssocObject; } // optional
const plUoid* GetAssocObject() const { return &fAssocObject; } // optional
// utils
void FlagDifferentState(const plStateDataRecord& other); // mark items which differ from 'other' as dirty
void FlagNewerState(const plStateDataRecord& other, bool respectAlwaysNew=false); // mark items which are newer than 'other' as dirty
void FlagAlwaysNewState(); // mark 'alwaysNew' items as dirty
void DumpToObjectDebugger(const char* msg, bool dirtyOnly=false, int level=0) const;
void DumpToStream(hsStream* stream, const char* msg, bool dirtyOnly=false, int level=0) const;
// IO
bool Read(hsStream* s, float timeConvert, UInt32 readOptions=0);
void Write(hsStream* s, float timeConvert, UInt32 writeOptions=0) const;
static bool ReadStreamHeader(hsStream* s, char** name, int* version, plUoid* objUoid=nil);
void WriteStreamHeader(hsStream* s, plUoid* objUoid=nil) const;
};
//
// Simple SDL parser
//
class plSDLMgr;
class plSDLParser
{
private:
bool IReadDescriptors() const;
bool ILoadSDLFile(const char* fileName) const;
bool IParseVarDesc(const char* fileName, hsStream* stream, char token[], plStateDescriptor*& curDesc,
plVarDescriptor*& curVar) const;
bool IParseStateDesc(const char* fileName, hsStream* stream, char token[], plStateDescriptor*& curDesc) const;
void DebugMsg(char* fmt, ...) const;
void DebugMsgV(char* fmt, va_list args) const;
public:
bool Parse() const; // reads sdl folder, creates descriptor list
};
//
// Holds, loads and unloads all state descriptors from sdl files.
// Singleton.
//
class plNetApp;
class plSDLMgr
{
friend class plSDLParser;
private:
std::string fSDLDir;
plSDL::DescriptorList fDescriptors;
plNetApp* fNetApp;
UInt32 fBehaviorFlags;
void IDeleteDescriptors(plSDL::DescriptorList* dl);
public:
plSDLMgr();
~plSDLMgr();
static plSDLMgr* GetInstance();
plStateDescriptor* FindDescriptor(const char* name, int version, const plSDL::DescriptorList * dl=nil) const; // version or kLatestVersion
const plSDL::DescriptorList * GetDescriptors( void ) const { return &fDescriptors;}
void SetSDLDir(const char* s) { fSDLDir=s; }
const char* GetSDLDir() const { return fSDLDir.c_str(); }
void SetNetApp(plNetApp* a) { fNetApp=a; }
plNetApp* GetNetApp() const { return fNetApp; }
bool Init( UInt32 behaviorFlags=0 ); // parse sdl folder
void DeInit();
UInt32 GetBehaviorFlags() const { return fBehaviorFlags; }
void SetBehaviorFlags(UInt32 v) { fBehaviorFlags=v; }
bool AllowTimeStamping() const { return ! ( fBehaviorFlags&plSDL::kDisallowTimeStamping ); }
// I/O - return # of bytes read/written
int Write(hsStream* s, const plSDL::DescriptorList* dl=nil); // write descriptors to a stream
int Read(hsStream* s, plSDL::DescriptorList* dl=nil); // read descriptors into provided list (use legacyList if nil)
};
#endif // PL_SDL_inc

View File

@ -0,0 +1,33 @@
/*==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==*/
#ifndef plSDLCreatable_h
#define plSDLCreatable_h
#include "plSDL.h"
REGISTER_CREATABLE(plStateDataRecord);
#endif // plSDLCreatable_h

View File

@ -0,0 +1,240 @@
/*==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==*/
#ifndef plSDL_DESC_inc
#define plSDL_DESC_inc
//
// Code for State Description Language (SDL) Descriptors.
// These define a schema representing an object's saveState buffer.
//
#include "hsTypes.h"
#include "hsUtils.h"
#include "hsStlUtils.h"
//
// Describes a variable in a state descriptor.
// Every variable is actually a list, either fixed or variable length.
// Abstract base class.
//
class hsStream;
class plSimpleVarDescriptor;
class plSDVarDescriptor;
class plVarDescriptor
{
public:
enum Type
{
kNone = -1,
// atomic types
kInt,
kFloat,
kBool,
kString32,
kKey, // plKey - basically a uoid
kStateDescriptor, // this var refers to another state descriptor
kCreatable, // plCreatable - basically a classIdx and a read/write buffer
kDouble,
kTime, // double which is automatically converted to server clock and back, use for animation times
kByte,
kShort,
kAgeTimeOfDay, // float which is automatically set to the current age time of day (0-1)
// the following are a vector of floats
kVector3=50,// atomicCount=3
kPoint3, // atomicCount=3
kRGB, // atomicCount=3
kRGBA, // atomicCount=4
kQuaternion, // atomicCount=4
kRGB8, // atomicCount=3
kRGBA8, // atomicCount=4
};
typedef char String32[32];
enum Flags
{
kInternal = 0x1, // Don't allow access to this var in Vault Mgr
kAlwaysNew = 0x2, // Treat this var as always having the latest timestamp when FlaggingNewerState
kVariableLength = 0x4 // Var is defined as int foo[], so it's length is variable, starting at 0
};
protected:
static const UInt8 kVersion; // for Read/Write format
char* fDefault; // set by .sdl
char* fName; // set by .sdl
int fCount; // set by .sdl
Type fType; // set by .sdl
char* fTypeString; // string version of fType
UInt32 fFlags;
std::string fDisplayOptions; // set by .sdl
public:
plVarDescriptor();
virtual ~plVarDescriptor();
virtual void CopyFrom(const plVarDescriptor* v);
// conversion ops
virtual plSimpleVarDescriptor* GetAsSimpleVarDescriptor() = 0;
virtual plSDVarDescriptor* GetAsSDVarDescriptor() = 0;
virtual const plSimpleVarDescriptor* GetAsSimpleVarDescriptor() const = 0;
virtual const plSDVarDescriptor* GetAsSDVarDescriptor() const = 0;
// getters
const char* GetDefault() const { return fDefault; }
const char* GetName() const { return fName; }
Type GetType() const { return fType; }
const char* GetTypeString() const { return fTypeString; }
int GetCount() const { return fCount; }
bool IsInternal() const { return (fFlags & kInternal) != 0; }
bool IsAlwaysNew() const { return (fFlags & kAlwaysNew) != 0; }
bool IsVariableLength() const { return (fFlags & kVariableLength) != 0; }
const char* GetDisplayOptions() const { return fDisplayOptions.c_str(); }
// setters
void SetDefault(const char* n) { delete [] fDefault; fDefault= hsStrcpy(n); }
void SetName(const char* n) { delete [] fName; fName = hsStrcpy(n); }
void SetCount(int c) { fCount=c; }
virtual bool SetType(const char* type);
void SetType(Type t) { fType=t; }
void SetInternal(bool d) { if (d) fFlags |= kInternal; else fFlags &= ~kInternal; }
void SetAlwaysNew(bool d) { if (d) fFlags |= kAlwaysNew; else fFlags &= ~kAlwaysNew; }
void SetVariableLength(bool d) { if (d) fFlags |= kVariableLength; else fFlags &= ~kVariableLength; }
void SetDisplayOptions(const char* s) { fDisplayOptions=s; }
// IO
virtual bool Read(hsStream* s);
virtual void Write(hsStream* s) const;
};
//
// Simple, non-nested var descriptors. These are comprised of single types, as opposed to
// referring to another state descriptor.
//
class plSimpleVarDescriptor : public plVarDescriptor
{
protected:
Type fAtomicType; // base type (it. quaternion == kFloat)
int fAtomicCount; // computed from type in .sdl (ie. quaternion == 4)
public:
plSimpleVarDescriptor();
virtual ~plSimpleVarDescriptor() { }
plSimpleVarDescriptor* GetAsSimpleVarDescriptor() { return this; }
plSDVarDescriptor* GetAsSDVarDescriptor() { return nil; }
const plSimpleVarDescriptor* GetAsSimpleVarDescriptor() const { return this; }
const plSDVarDescriptor* GetAsSDVarDescriptor() const { return nil; }
void CopyFrom(const plSimpleVarDescriptor* v);
void CopyFrom(const plVarDescriptor* v) { plVarDescriptor::CopyFrom(v); } // lame compiler
// getters
int GetSize() const;
int GetAtomicSize() const; // size of one item in bytes (regardless of count)
Type GetAtomicType() const { return fAtomicType; }
int GetAtomicCount() const { return fAtomicCount; }
// setters
bool SetType(const char* type);
void SetType(Type t) { plVarDescriptor::SetType(t); } // for lame compiler
void SetAtomicType(Type t) { fAtomicType=t; }
// IO
virtual bool Read(hsStream* s);
virtual void Write(hsStream* s) const;
};
//
// A var descriptor which references another state descriptor.
//
class plStateDescriptor;
class plSDVarDescriptor : public plVarDescriptor
{
protected:
plStateDescriptor* fStateDesc;
public:
plSDVarDescriptor(plStateDescriptor* sd=nil) : fStateDesc(sd) { }
plSimpleVarDescriptor* GetAsSimpleVarDescriptor() { return nil; }
plSDVarDescriptor* GetAsSDVarDescriptor() { return this; }
const plSimpleVarDescriptor* GetAsSimpleVarDescriptor() const { return nil; }
const plSDVarDescriptor* GetAsSDVarDescriptor() const { return this; }
// getters
plStateDescriptor* GetStateDescriptor() const { return fStateDesc; }
// setters
void SetStateDesc(plStateDescriptor* sd) { fStateDesc=sd; }
void CopyFrom(const plSDVarDescriptor* v);
void CopyFrom(const plVarDescriptor* v) { plVarDescriptor::CopyFrom(v); } // lame compiler
// IO
bool Read(hsStream* s);
void Write(hsStream* s) const;
};
//
// A state descriptor - describes the contents of a type of state buffer.
// There is one of these for each persistent object type.
// These descriptors are defined in a user-created .sdl file.
//
class plKey;
class plStateDescriptor
{
private:
static const UInt8 kVersion; // for Read/Write format
typedef std::vector<plVarDescriptor*> VarsList;
VarsList fVarsList;
int fVersion;
char* fName;
std::string fFilename; // the filename this descriptor was read from
void IDeInit();
public:
plStateDescriptor() : fVersion(-1),fName(nil) {}
~plStateDescriptor();
// getters
const char* GetName() const { return fName; }
int GetNumVars() const { return fVarsList.size(); }
plVarDescriptor* GetVar(int i) const { return fVarsList[i]; }
int GetVersion() const { return fVersion; }
const char * GetFilename() const { return fFilename.c_str();}
// setters
void SetVersion(int v) { fVersion=v; }
void SetName(const char* n) { delete [] fName; fName=hsStrcpy(n); }
void AddVar(plVarDescriptor* v) { fVarsList.push_back(v); }
void SetFilename( const char * n ) { fFilename=n;}
plVarDescriptor* FindVar(const char* name, int* idx=nil) const;
// IO
bool Read(hsStream* s);
void Write(hsStream* s) const;
};
#endif // plSDL_DESC_inc

View File

@ -0,0 +1,191 @@
/*==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 "hsStream.h"
#include "hsStlUtils.h"
#include "plSDL.h"
#include "../pnNetCommon/plNetApp.h"
#include "../pnNetCommon/pnNetCommon.h"
#include <algorithm>
/////////////////////////////////////////////////////////////////////////////////
// SDL MGR
/////////////////////////////////////////////////////////////////////////////////
//
//
//
plSDLMgr::plSDLMgr() : fSDLDir("SDL"), fNetApp(nil), fBehaviorFlags(0)
{
}
//
//
//
plSDLMgr::~plSDLMgr()
{
DeInit();
}
bool plSDLMgr::Init( UInt32 behaviorFlags )
{
fBehaviorFlags = behaviorFlags;
plSDLParser parser;
return parser.Parse();
}
void plSDLMgr::DeInit()
{
IDeleteDescriptors(&fDescriptors);
}
//
// delete all descriptors
//
void plSDLMgr::IDeleteDescriptors(plSDL::DescriptorList* dl)
{
std::for_each( dl->begin(), dl->end(), xtl::delete_ptr() );
dl->clear();
}
//
// STATIC
//
plSDLMgr* plSDLMgr::GetInstance()
{
static plSDLMgr gSDLMgr;
return &gSDLMgr;
}
//
// search latest and legacy descriptors for one that matches.
// if version is -1, search for latest descriptor with matching name
//
plStateDescriptor* plSDLMgr::FindDescriptor(const char* name, int version, const plSDL::DescriptorList * dl) const
{
if (!name)
return nil;
if ( !dl )
dl = &fDescriptors;
plStateDescriptor* sd = nil;
plSDL::DescriptorList::const_iterator it;
int highestFound = -1;
for(it=(*dl).begin(); it!= (*dl).end(); it++)
{
if (!_stricmp((*it)->GetName(), name) )
{
if ( (*it)->GetVersion()==version )
{
sd = *it;
break;
}
else if ( version==plSDL::kLatestVersion && (*it)->GetVersion()>highestFound )
{
sd = *it;
highestFound = (*it)->GetVersion();
}
}
}
return sd;
}
//
// write latest descriptors to a stream.
// return number of bytes
//
int plSDLMgr::Write(hsStream* s, const plSDL::DescriptorList* dl)
{
int pos=s->GetPosition();
if (dl==nil)
dl=&fDescriptors;
UInt16 num=dl->size();
s->WriteSwap(num);
plSDL::DescriptorList::const_iterator it;
for(it=dl->begin(); it!= dl->end(); it++)
(*it)->Write(s);
int bytes=s->GetPosition()-pos;
if (fNetApp)
{
hsLogEntry(fNetApp->DebugMsg("Writing %d SDL descriptors, %d bytes", num, bytes));
}
return bytes;
}
//
// read descriptors into provided list
// return number of bytes
//
int plSDLMgr::Read(hsStream* s, plSDL::DescriptorList* dl)
{
int pos=s->GetPosition();
if (dl==nil)
dl=&fDescriptors;
// clear dl
IDeleteDescriptors(dl);
UInt16 num;
try
{
// read dtor list
s->ReadSwap(&num);
int i;
for(i=0;i<num;i++)
{
plStateDescriptor* sd=TRACKED_NEW plStateDescriptor;
if (sd->Read(s))
dl->push_back(sd);
}
}
catch(...)
{
if (fNetApp)
{
hsLogEntry(fNetApp->DebugMsg("Something bad happened while reading SDLMgr data"));
}
return 0;
}
int bytes=s->GetPosition()-pos;
if (fNetApp)
{
hsLogEntry(fNetApp->DebugMsg("Reading %d SDL descriptors, %d bytes", num, bytes));
}
return bytes;
}

View File

@ -0,0 +1,422 @@
/*==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 "hsStlUtils.h"
#include "plSDL.h"
#include "../plFile/hsFiles.h"
#include "../plFile/plStreamSource.h"
#include "../pnNetCommon/pnNetCommon.h"
#include "../pnNetCommon/plNetApp.h"
static const int kTokenLen=256;
void plSDLParser::DebugMsg(char* fmt, ...) const
{
return;
plNetApp* netApp = plSDLMgr::GetInstance()->GetNetApp();
va_list args;
va_start(args, fmt);
if (netApp)
{
hsLogEntry(netApp->DebugMsgV(fmt, args));
}
else
DebugMsgV(fmt, args);
va_end(args);
}
void plSDLParser::DebugMsgV(char* fmt, va_list args) const
{
if (strlen(fmt)==nil)
return;
hsStatusMessage(xtl::formatv(fmt,args).c_str());
}
//
// parsing stateDesc
// read name, version
// return true to skip the next token read
//
bool plSDLParser::IParseStateDesc(const char* fileName, hsStream* stream, char token[], plStateDescriptor*& curDesc) const
{
plSDL::DescriptorList* descList = &plSDLMgr::GetInstance()->fDescriptors;
bool ok = true;
//
// NAME
//
// curDesc=plSDLMgr::GetInstance()->FindDescriptor(token, plSDL::kLatestVersion);
// if (!curDesc)
{
curDesc = TRACKED_NEW plStateDescriptor;
curDesc->SetName(token);
DebugMsg("SDL: DESC name=%s", token);
}
//
// {
//
stream->GetToken(token, kTokenLen); // skip '{'
//
// VERSION
//
if (stream->GetToken(token, kTokenLen))
{
if (!strcmp(token, "VERSION"))
{
// read desc version
hsAssert(curDesc, xtl::format("Syntax problem with .sdl file, fileName=%s", fileName).c_str());
if (stream->GetToken(token, kTokenLen))
{
int v=atoi(token);
curDesc->SetVersion(v);
DebugMsg("\tVersion=%d", v);
}
}
else
{
hsAssert(false, xtl::format("Error parsing state desc, missing VERSION, fileName=%s",
fileName).c_str());
ok = false;
}
}
else
{
hsAssert(false, xtl::format("Error parsing state desc, fileName=%s", fileName).c_str());
ok = false;
}
if ( ok )
{
ok = ( plSDLMgr::GetInstance()->FindDescriptor(curDesc->GetName(), curDesc->GetVersion())==nil );
if ( !ok )
{
std::string err = xtl::format( "Found duplicate SDL descriptor for %s version %d.\nFailed to parse file: %s", curDesc->GetName(), curDesc->GetVersion(), fileName );
plNetApp::StaticErrorMsg( err.c_str() );
hsAssert( false, err.c_str() );
}
}
if ( ok )
{
descList->push_back(curDesc);
}
else
{
delete curDesc;
curDesc = nil;
}
return false;
}
//
// Parse a variable descriptor.
// read type, name, count [default]
// return true to skip the next token read
//
bool plSDLParser::IParseVarDesc(const char* fileName, hsStream* stream, char token[], plStateDescriptor*& curDesc,
plVarDescriptor*& curVar) const
{
hsAssert(curDesc, xtl::format("Syntax problem with .sdl file, fileName=%s", fileName).c_str());
if ( !curDesc )
return false;
bool skipNext=false;
std::string dbgStr;
static char seps[] = "( ,)[]";
// read type, name, cnt, [default]
//
// TYPE
// create new state var, make current
//
if (*token == '$')
{
// nested sdls
char* sdlName = token+1;
plStateDescriptor* stateDesc = plSDLMgr::GetInstance()->FindDescriptor(sdlName, plSDL::kLatestVersion);
hsAssert(stateDesc, xtl::format("can't find nested state desc reference %s, fileName=%s",
sdlName, fileName).c_str());
curVar = TRACKED_NEW plSDVarDescriptor(stateDesc);
}
else
curVar = TRACKED_NEW plSimpleVarDescriptor;
curDesc->AddVar(curVar);
bool ok=curVar->SetType(token);
hsAssert(ok, xtl::format("Variable 'type' syntax problem with .sdl file, type=%s, fileName=%s", token, fileName).c_str());
dbgStr = xtl::format("\tVAR Type=%s ", token).c_str();
//
// NAME (foo[1])
//
if (stream->GetToken(token, kTokenLen))
{
hsAssert(strstr(token, "[") && strstr(token, "]"), xtl::format("invalid var syntax, missing [x], fileName=%s",
fileName).c_str());
char* ptr = strtok( token, seps ); // skip [
hsAssert(curVar, xtl::format("Missing current var. Syntax problem with .sdl file, fileName=%s", fileName).c_str());
curVar->SetName(token);
//
// COUNT
//
char* cntTok=strtok(nil, seps); // kill ]
int cnt = cntTok ? atoi(cntTok) : 0;
curVar->SetCount(cnt);
if (cnt==0)
curVar->SetVariableLength(true);
dbgStr += xtl::format("Name=%s[%d]", curVar->GetName(), cnt).c_str();
}
//
// optional tokens: DEFAULT, INTERNAL
//
while (stream->GetToken(token, kTokenLen))
{
if (!strcmp(token, "DEFAULT"))
{
hsAssert(curVar, xtl::format("Syntax problem with .sdl file, fileName=%s", fileName).c_str());
// read state var type
std::string defaultStr;
plSimpleVarDescriptor* sVar=(plSimpleVarDescriptor*)curVar;
if (sVar)
{
int i;
for(i=0;i<sVar->GetAtomicCount();i++)
{
if (stream->GetToken(token, kTokenLen))
{
defaultStr += token;
if (i!=sVar->GetAtomicCount()-1)
defaultStr += ",";
}
}
}
if (defaultStr.size())
{
curVar->SetDefault(defaultStr.c_str());
dbgStr += std::string(" DEFAULT=") + defaultStr;
}
}
else
if (!strcmp(token, "DISPLAYOPTION"))
{
hsAssert(curVar, xtl::format("Syntax problem with .sdl file, fileName=%s", fileName).c_str());
dbgStr += std::string(" ") + token;
hsBool read=stream->GetToken(token, kTokenLen);
if (read)
{
std::string oldOptions=curVar->GetDisplayOptions();
if (oldOptions.size())
oldOptions += std::string(",");
oldOptions += token;
curVar->SetDisplayOptions(oldOptions.c_str());
dbgStr += std::string("=") + token;
if (!stricmp(token, "hidden"))
curVar->SetInternal(true);
}
else
{
hsAssert(false, xtl::format("missing displayOption string, fileName=%s", fileName).c_str());
}
}
else
if (!strcmp(token, "DEFAULTOPTION"))
{
hsAssert(curVar, xtl::format("Syntax problem with .sdl file, fileName=%s", fileName).c_str());
dbgStr += std::string(" ") + token;
hsBool read=stream->GetToken(token, kTokenLen);
if (read)
{
dbgStr += std::string("=") + token;
if (!stricmp(token, "vault"))
curVar->SetAlwaysNew(true);
}
else
{
hsAssert(false, xtl::format("missing defaultOption string, fileName=%s", fileName).c_str());
}
}
#if 1 // delete me in May 2003
else
if (!strcmp(token, "INTERNAL"))
{
hsAssert(curVar, xtl::format("Syntax problem with .sdl file, fileName=%s", fileName).c_str());
curVar->SetInternal(true);
dbgStr += std::string(" ") + token;
}
else
if (!strcmp(token, "PHASED"))
{
hsAssert(curVar, xtl::format("Syntax problem with .sdl file, fileName=%s", fileName).c_str());
curVar->SetAlwaysNew(true);
dbgStr += std::string(" ") + token;
}
#endif
else
{
skipNext=true;
break;
}
}
DebugMsg((char*)dbgStr.c_str());
return skipNext;
}
//
// create state descriptor from sdl file.
// return false on err.
//
bool plSDLParser::ILoadSDLFile(const char* fileName) const
{
DebugMsg("Parsing SDL file %s", fileName);
wchar_t* temp = hsStringToWString(fileName);
hsStream* stream = plStreamSource::GetInstance()->GetFile(temp);
delete [] temp;
if (!stream)
return false;
stream->Rewind();
plVarDescriptor* curVar=nil;
plStateDescriptor* curDesc=nil;
char token[kTokenLen];
bool parsingStateDesc=false;
bool skip=false;
while (1)
{
if (!skip)
{
if (!stream->GetToken(token, kTokenLen))
break;
}
skip=false;
if (!strcmp(token, "VAR"))
{
parsingStateDesc=false;
curVar=nil; // start fresh
continue;
}
if (!strcmp(token, "STATEDESC"))
{
parsingStateDesc=true;
curDesc=nil; // start fresh
continue;
}
if (!strcmp(token, "}"))
{
if ( curDesc )
curDesc->SetFilename( fileName );
parsingStateDesc=false;
continue;
}
if (parsingStateDesc)
{
skip=IParseStateDesc(fileName, stream, token, curDesc);
if ( !curDesc )
break; // failed to parse state desc
}
else
{
skip=IParseVarDesc(fileName, stream, token, curDesc, curVar);
}
}
// If the very last char is a } without a \n, then it won't be handled above for some reason, so we have to catch it here.
if ( curDesc )
curDesc->SetFilename( fileName );
// do not close or delete the stream, we do not own it
return true;
}
//
// load all .sdl files in sdl directory, and create descriptors for each.
// return false on error
//
bool plSDLParser::IReadDescriptors() const
{
std::string sdlDir = plSDLMgr::GetInstance()->GetSDLDir();
DebugMsg("SDL: Reading latest descriptors from directory %s", sdlDir.c_str());
wchar_t* temp = hsStringToWString(sdlDir.c_str());
std::wstring wSDLDir = temp;
delete [] temp;
// Get the names of all the sdl files
std::vector<std::wstring> files = plStreamSource::GetInstance()->GetListOfNames(wSDLDir, L".sdl");
bool ret=true;
int cnt=0;
for (int i = 0; i < files.size(); i++)
{
char* str = hsWStringToString(files[i].c_str());
if (!ILoadSDLFile(str))
{
plNetApp* netApp = plSDLMgr::GetInstance()->GetNetApp();
if (netApp)
netApp->ErrorMsg("Error loading SDL file %s", str);
else
hsStatusMessageF("Error loading SDL file %s", str);
ret=false;
}
else
cnt++;
delete [] str;
}
DebugMsg("Done reading SDL files");
if (!cnt)
ret=false;
return ret;
}
//
// reads sdl folder, creates descriptor list
//
bool plSDLParser::Parse() const
{
return IReadDescriptors();
}

View File

@ -0,0 +1,125 @@
/*==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 "plSDL.h"
#include "../pnMessage/plSDLNotificationMsg.h"
#include "algorithm"
// static
UInt32 plStateChangeNotifier::fCurrentPlayerID = 0;
plStateChangeNotifier::plStateChangeNotifier() :
fDelta(0)
{
}
plStateChangeNotifier::plStateChangeNotifier(float i, plKey k)
{
SetValue(i);
IAddKey(k);
}
void plStateChangeNotifier::IAddKey(plKey k)
{
KeyList::iterator it = std::find(fKeys.begin(), fKeys.end(), k);
if (it==fKeys.end())
fKeys.push_back(k);
}
int plStateChangeNotifier::IRemoveKey(plKey k)
{
KeyList::iterator it = std::find(fKeys.begin(), fKeys.end(), k);
if (it!=fKeys.end())
fKeys.erase(it);
return fKeys.size();
}
//
// returns number of keys left after removal
//
int plStateChangeNotifier::RemoveNotificationKey(plKey k)
{
return IRemoveKey(k);
}
//
// returns number of keys left after removal
//
int plStateChangeNotifier::RemoveNotificationKeys(KeyList keys)
{
KeyList::iterator it=keys.begin();
for( ; it != keys.end(); it++)
IRemoveKey(*it);
return fKeys.size();
}
void plStateChangeNotifier::AddNotificationKeys(KeyList keys)
{
KeyList::iterator it=keys.begin();
for( ; it != keys.end(); it++)
IAddKey(*it);
}
bool plStateChangeNotifier::GetValue(float* i) const
{
*i=fDelta;
return true;
}
bool plStateChangeNotifier::SetValue(float i)
{
fDelta=i;
return true;
}
bool plStateChangeNotifier::operator==(const plStateChangeNotifier &other) const
{
return (other.fDelta==fDelta && other.fKeys==fKeys);
}
//
// send notification msg to all registered recipients
//
void plStateChangeNotifier::SendNotificationMsg(const plSimpleStateVariable* srcVar, const plSimpleStateVariable* dstVar,
const char* sdlName)
{
plSDLNotificationMsg* m = TRACKED_NEW plSDLNotificationMsg;
// add receivers
KeyList::iterator kit=fKeys.begin();
for(; kit != fKeys.end(); kit++)
m->AddReceiver(*kit);
m->fDelta=fDelta;
m->fVar=dstVar;
m->fSDLName = sdlName;
m->fPlayerID = GetCurrentPlayerID();
m->fHintString = srcVar->GetNotificationInfo().GetHintString();
m->Send();
}

View File

@ -0,0 +1,831 @@
/*==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 <algorithm>
#include "hsTimer.h"
#include "hsTemplates.h"
#include "hsStream.h"
#include "hsStlUtils.h"
#include "plSDL.h"
#include "../plNetMessage/plNetMessage.h"
#include "../pnNetCommon/plNetApp.h"
const char* plSDL::kAgeSDLObjectName = {"AgeSDLHook"};
// static
const UInt8 plStateDataRecord::kIOVersion=6;
//
// helper
//
void plSDL::VariableLengthRead(hsStream* s, int size, int* val)
{
// hsAssert(size, "unexpected size");
if (size < (1<<8))
*val = s->ReadByte();
else
if (size < (1<<16))
*val = s->ReadSwap16();
else
*val = s->ReadSwap32();
}
//
// helper
//
void plSDL::VariableLengthWrite(hsStream* s, int size, int val)
{
// hsAssert(size, "unexpected size");
if (size < (1<<8))
{
hsAssert(val < (1<<8), "SDL data loss");
s->WriteByte(val);
}
else
if (size < (1<<16))
{
hsAssert(val < (1<<16), "SDL data loss");
s->WriteSwap16(val);
}
else
s->WriteSwap32(val);
}
/////////////////////////////////////////////////////////////////////////////////
// State Data
/////////////////////////////////////////////////////////////////////////////////
plStateDataRecord::plStateDataRecord(const char* name, int version) : fFlags(0)
, fDescriptor( nil )
{
SetDescriptor(name, version);
}
plStateDataRecord::plStateDataRecord(plStateDescriptor* sd) : fFlags(0)
, fDescriptor( nil )
{
IInitDescriptor(sd);
}
plStateDataRecord::~plStateDataRecord()
{
IDeleteVarsList(fVarsList);
IDeleteVarsList(fSDVarsList);
}
void plStateDataRecord::SetDescriptor(const char* name, int version)
{
IInitDescriptor(name, version);
}
void plStateDataRecord::IDeleteVarsList(VarsList& vars)
{
std::for_each( vars.begin(), vars.end(), xtl::delete_ptr() );
vars.clear();
}
void plStateDataRecord::IInitDescriptor(const char* name, int version)
{
plStateDescriptor* sd = plSDLMgr::GetInstance()->FindDescriptor(name, version);
//hsAssert( sd, xtl::format("Failed to find sdl descriptor: %s,%d. Missing legacy descriptor?", name, version ).c_str() );
if (sd)
IInitDescriptor(sd);
}
//
// Point to descriptor.
// setup state variables which correspond to the state descriptor.
//
void plStateDataRecord::IInitDescriptor(const plStateDescriptor* sd)
{
// pt to state desc
fDescriptor=sd;
// delete old vars
IDeleteVarsList(fVarsList);
IDeleteVarsList(fSDVarsList);
// create vars defined by state desc
if (sd)
{
for(int i = 0; i < sd->GetNumVars(); ++i)
{
if (plVarDescriptor* vd = sd->GetVar(i))
{
if (vd->GetAsSDVarDescriptor())
{ // it's a var which references another state descriptor.
fSDVarsList.push_back(TRACKED_NEW plSDStateVariable(vd->GetAsSDVarDescriptor()));
}
else
{
hsAssert(vd->GetAsSimpleVarDescriptor(), "var class problem");
fVarsList.push_back(TRACKED_NEW plSimpleStateVariable(vd->GetAsSimpleVarDescriptor()));
}
}
}
}
}
///////////////////
// DIRTY VARS
///////////////////
int plStateDataRecord::IGetNumDirtyVars(const VarsList& vars) const
{
int i, cnt=0;
for(i=0;i<vars.size();i++)
if (vars[i]->IsDirty())
cnt++;
return cnt;
}
int plStateDataRecord::IGetDirtyVars(const VarsList& varsIn, VarsList* varsOut) const
{
int i;
for(i=0;i<varsIn.size();i++)
if (varsIn[i]->IsDirty())
varsOut->push_back(varsIn[i]);
return varsOut->size();
}
bool plStateDataRecord::IHasDirtyVars(const VarsList& vars) const
{
int i;
for(i=0;i<vars.size();i++)
if (vars[i]->IsDirty())
return true;
return false;
}
////////////////
// USED VARS
////////////////
int plStateDataRecord::IGetNumUsedVars(const VarsList& vars) const
{
int i, cnt=0;
for(i=0;i<vars.size();i++)
if (vars[i]->IsUsed())
cnt++;
return cnt;
}
int plStateDataRecord::IGetUsedVars(const VarsList& varsIn, VarsList* varsOut) const
{
int i;
for(i=0;i<varsIn.size();i++)
if (varsIn[i]->IsUsed())
varsOut->push_back(varsIn[i]);
return varsOut->size();
}
bool plStateDataRecord::IHasUsedVars(const VarsList& vars) const
{
int i;
for(i=0;i<vars.size();i++)
if (vars[i]->IsUsed())
return true;
return false;
}
///////////////////////////////////////
// IO
///////////////////////////////////////
//
// read state vars and indices, return true on success
//
bool plStateDataRecord::Read(hsStream* s, float timeConvert, UInt32 readOptions)
{
fFlags = s->ReadSwap16();
UInt8 ioVersion = s->ReadByte();
if (ioVersion != kIOVersion)
return false;
//
// read simple var data
//
hsAssert(fDescriptor, "State Data Record has nil SDL descriptor");
if (!fDescriptor)
return false;
int num;
plSDL::VariableLengthRead(s, fDescriptor->GetNumVars(), &num );
// if we are readeing the entire list, we don't need to read each index
bool all = (num==fVarsList.size());
int i;
try
{
for(i=0;i<num;i++)
{
int idx;
if (!all)
plSDL::VariableLengthRead(s, fDescriptor->GetNumVars(), &idx );
else
idx=i;
if (idx>=fVarsList.size() || !fVarsList[idx]->ReadData(s, timeConvert, readOptions))
{
if (plSDLMgr::GetInstance()->GetNetApp())
plSDLMgr::GetInstance()->GetNetApp()->ErrorMsg("Failed reading SDL, desc %s",
fDescriptor && fDescriptor->GetName() ? fDescriptor->GetName() : "?");
return false;
}
}
}
catch(...)
{
hsAssert( false,
xtl::format("Something bad happened while reading simple var data, desc:%s",
fDescriptor && fDescriptor->GetName() ? fDescriptor->GetName() : "?").c_str());
return false;
}
//
// read nested var data
//
plSDL::VariableLengthRead(s, fDescriptor->GetNumVars(), &num );
// if we are readeing the entire list, we don't need to write each index
all = (num==fSDVarsList.size());
try
{
for(i=0;i<num;i++)
{
int idx;
if (!all)
plSDL::VariableLengthRead(s, fDescriptor->GetNumVars(), &idx );
else
idx=i;
if (idx>=fSDVarsList.size() || !fSDVarsList[idx]->ReadData(s, timeConvert, readOptions)) // calls plStateDataRecord::Read recursively
{
if (plSDLMgr::GetInstance()->GetNetApp())
plSDLMgr::GetInstance()->GetNetApp()->ErrorMsg("Failed reading nested SDL, desc %s",
fDescriptor && fDescriptor->GetName() ? fDescriptor->GetName() : "?");
return false;
}
}
}
catch(...)
{
hsAssert( false,
xtl::format("Something bad happened while reading nested var data, desc:%s",
fDescriptor && fDescriptor->GetName() ? fDescriptor->GetName() : "?").c_str());
return false;
}
// convert to latest descriptor
// Only really need to do this the first time this descriptor is read...
plStateDescriptor* latestDesc=plSDLMgr::GetInstance()->FindDescriptor(fDescriptor->GetName(), plSDL::kLatestVersion);
hsAssert( latestDesc, xtl::format("Failed to find latest sdl descriptor for: %s", fDescriptor->GetName() ).c_str() );
bool forceConvert = (readOptions&plSDL::kForceConvert)!=0;
if ( latestDesc && ( forceConvert || ( fDescriptor->GetVersion()!=latestDesc->GetVersion() ) ) )
{
DumpToObjectDebugger( "PreConvert" );
ConvertTo( latestDesc, forceConvert );
DumpToObjectDebugger( "PostConvert" );
}
return true; // ok
}
//
// write out the state vars, along with their index
//
void plStateDataRecord::Write(hsStream* s, float timeConvert, UInt32 writeOptions) const
{
#ifdef HS_DEBUGGING
if ( !plSDLMgr::GetInstance()->AllowTimeStamping() && (writeOptions & plSDL::kWriteTimeStamps) )
{
hsAssert( false, "SDL behavior flags disallow var timestamping on write.\nRemoving kWriteTimeStamps flag from writeOptions..." );
writeOptions &= ~plSDL::kWriteTimeStamps;
}
#endif
s->WriteSwap16((UInt16)fFlags);
s->WriteByte(kIOVersion);
//
// write simple vars
//
bool dirtyOnly = (writeOptions & plSDL::kDirtyOnly) != 0;
int num = dirtyOnly ? GetNumDirtyVars() : GetNumUsedVars();
plSDL::VariableLengthWrite(s, fDescriptor->GetNumVars(), num ); // write affected vars count
// if we are writing he entire list, we don't need to write each index
bool all = (num==fVarsList.size());
int i;
for(i=0;i<fVarsList.size(); i++)
{
if ( (dirtyOnly && fVarsList[i]->IsDirty()) ||
(!dirtyOnly && fVarsList[i]->IsUsed()) )
{
if (!all)
plSDL::VariableLengthWrite(s, fDescriptor->GetNumVars(), i ); // index
fVarsList[i]->WriteData(s, timeConvert, writeOptions); // data
}
}
//
// write nested vars
//
num = dirtyOnly ? GetNumDirtySDVars() : GetNumUsedSDVars();
plSDL::VariableLengthWrite(s, fDescriptor->GetNumVars(), num ); // write affected vars count
// if we are writing he entire list, we don't need to write each index
all = (num==fSDVarsList.size());
for(i=0;i<fSDVarsList.size(); i++)
{
if ( (dirtyOnly && fSDVarsList[i]->IsDirty()) ||
(!dirtyOnly && fSDVarsList[i]->IsUsed()) )
{
if (!all)
plSDL::VariableLengthWrite(s, fDescriptor->GetNumVars(), i ); // index
fSDVarsList[i]->WriteData(s, timeConvert, writeOptions); // data, calls plStateDataRecord::Write recursively
}
}
}
//
// STATIC - read prefix header. returns true on success
//
bool plStateDataRecord::ReadStreamHeader(hsStream* s, char** name, int* version, plUoid* objUoid)
{
UInt16 savFlags;
s->ReadSwap(&savFlags);
if (!(savFlags & plSDL::kAddedVarLengthIO)) // using to establish a new version in the header, can delete in 8/03
{
*name = nil;
return false; // bad version
}
*name = s->ReadSafeString();
*version = s->ReadSwap16();
if (objUoid)
{
hsAssert(savFlags & plSDL::kHasUoid, "SDL state data rec expecting to read a uoid, but there isn't one");
}
if (savFlags & plSDL::kHasUoid)
{
if (objUoid)
objUoid->Read(s);
else
{
plUoid tmp;
tmp.Read(s);
}
}
return true; // ok
}
//
// non-static - write prefix header. helper fxn
//
void plStateDataRecord::WriteStreamHeader(hsStream* s, plUoid* objUoid) const
{
UInt16 savFlags=plSDL::kAddedVarLengthIO; // using to establish a new version in the header, can delete in 8/03
if (objUoid)
savFlags |= plSDL::kHasUoid;
s->WriteSwap(savFlags);
s->WriteSafeString(GetDescriptor()->GetName());
s->WriteSwap16((Int16)GetDescriptor()->GetVersion());
if (objUoid)
objUoid->Write(s);
}
//
// create and prepare a net msg with this data
//
plNetMsgSDLState* plStateDataRecord::PrepNetMsg(float timeConvert, UInt32 writeOptions) const
{
// save to stream
hsRAMStream stream;
WriteStreamHeader(&stream);
Write(&stream, timeConvert, writeOptions);
// fill in net msg
plNetMsgSDLState* msg;
if (writeOptions & plSDL::kBroadcast)
msg = TRACKED_NEW plNetMsgSDLStateBCast;
else
msg = TRACKED_NEW plNetMsgSDLState;
msg->StreamInfo()->CopyStream(&stream);
return msg;
}
//
// Destroys 'this' and makes a total copy of other
//
void plStateDataRecord::CopyFrom(const plStateDataRecord& other, UInt32 writeOptions/*=0*/)
{
fFlags = other.GetFlags();
IInitDescriptor(other.GetDescriptor());
int i;
for(i=0;i<other.GetNumVars();i++)
{
if (other.GetVar(i)->IsUsed())
GetVar(i)->CopyData(other.GetVar(i),writeOptions);
}
for(i=0;i<other.GetNumSDVars();i++)
{
if (other.GetSDVar(i)->IsUsed())
GetSDVar(i)->CopyFrom(other.GetSDVar(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 plStateDataRecord::UpdateFrom(const plStateDataRecord& other, UInt32 writeOptions/*=0*/)
{
if ( GetDescriptor()->GetVersion()!=other.GetDescriptor()->GetVersion() )
{
plStateDescriptor* sd=plSDLMgr::GetInstance()->FindDescriptor( other.GetDescriptor()->GetName(), other.GetDescriptor()->GetVersion() );
hsAssert( sd, xtl::format( "Failed to find sdl descriptor %s,%d. Missing legacy descriptor?", other.GetDescriptor()->GetName(), other.GetDescriptor()->GetVersion() ).c_str() );
ConvertTo( sd );
}
hsAssert(other.GetDescriptor()==fDescriptor,
xtl::format("descriptor mismatch in UpdateFromDirty, SDL=%s,%s version %d %d",
GetDescriptor()->GetName(), other.GetDescriptor()->GetName(),
GetDescriptor()->GetVersion(), other.GetDescriptor()->GetVersion()).c_str());
bool dirtyOnly = (writeOptions & plSDL::kDirtyOnly);
int i;
for(i=0;i<other.GetNumVars();i++)
{
if ( (dirtyOnly && other.GetVar(i)->IsDirty()) || (!dirtyOnly && other.GetVar(i)->IsUsed()) )
{
GetVar(i)->NotifyStateChange(other.GetVar(i), GetDescriptor()->GetName()); // see if there is enough difference to send state chg notification
GetVar(i)->CopyData(other.GetVar(i), writeOptions ); // simple vars get copied completely, non-partial
}
}
for(i=0;i<other.GetNumSDVars();i++)
{
if ( (dirtyOnly && other.GetSDVar(i)->IsDirty()) || (!dirtyOnly && other.GetSDVar(i)->IsUsed()) )
GetSDVar(i)->UpdateFrom(other.GetSDVar(i), writeOptions);
}
}
//
// dirty my items which are different from the corresponding one in 'other'.
// Requires that records have the same descriptor.
//
void plStateDataRecord::FlagDifferentState(const plStateDataRecord& other)
{
if (other.GetDescriptor()==fDescriptor)
{
int i;
for(i=0;i<other.GetNumVars();i++)
{
bool diff = (GetVar(i)->IsUsed() && ! (*other.GetVar(i) == *GetVar(i)) );
GetVar(i)->SetDirty(diff);
}
for(i=0;i<other.GetNumSDVars();i++)
{
bool diff = (GetSDVar(i)->IsUsed() && ! (*other.GetSDVar(i) == *GetSDVar(i)) );
GetSDVar(i)->SetDirty(diff);
}
}
else
{
hsAssert(false, xtl::format("descriptor mismatch in FlagDifferentState, mine %s %d, other %s %d",
fDescriptor->GetName(), fDescriptor->GetVersion(),
other.GetDescriptor()->GetName(), other.GetDescriptor()->GetVersion()).c_str());
}
}
//
// dirty my items which are flagged as alwaysNew.
//
void plStateDataRecord::FlagAlwaysNewState()
{
int i;
for(i=0;i<GetNumVars();i++)
{
bool newer= (GetVar(i)->IsUsed() && GetVar(i)->GetVarDescriptor()->IsAlwaysNew()); // flagged to be always new
GetVar(i)->SetDirty(newer);
}
for(i=0;i<GetNumSDVars();i++)
{
if (GetSDVar(i)->IsUsed())
{
GetSDVar(i)->FlagAlwaysNewState();
}
}
}
//
// dirty my items which are newer than the corresponding one in 'other'.
// Requires that records have the same descriptor.
//
void plStateDataRecord::FlagNewerState(const plStateDataRecord& other, bool respectAlwaysNew)
{
if (other.GetDescriptor()==fDescriptor)
{
int i;
for(i=0;i<other.GetNumVars();i++)
{
bool newer= (GetVar(i)->IsUsed() &&
(GetVar(i)->GetTimeStamp() > other.GetVar(i)->GetTimeStamp() || // later timestamp
(respectAlwaysNew && GetVar(i)->GetVarDescriptor()->IsAlwaysNew())) ); // flagged to be always new
GetVar(i)->SetDirty(newer);
}
for(i=0;i<other.GetNumSDVars();i++)
{
if (GetSDVar(i)->IsUsed())
{
GetSDVar(i)->FlagNewerState(*other.GetSDVar(i), respectAlwaysNew);
}
}
}
else
{
hsAssert(false, xtl::format("descriptor mismatch in FlagNewerState, mine %s %d, other %s %d",
fDescriptor->GetName(), fDescriptor->GetVersion(),
other.GetDescriptor()->GetName(), other.GetDescriptor()->GetVersion()).c_str());
}
}
//
// assumes matching state descriptors
//
bool plStateDataRecord::operator==(const plStateDataRecord &other) const
{
// hsAssert(other.GetDescriptor()==fDescriptor, "descriptor mismatch in equality check");
if (other.GetDescriptor()!=fDescriptor)
return false;
int i;
for(i=0;i<other.GetNumVars();i++)
{
if (! (*other.GetVar(i) == *GetVar(i)) )
return false;
}
for(i=0;i<other.GetNumSDVars();i++)
{
if (! (*other.GetSDVar(i) == *GetSDVar(i)) )
return false;
}
return true;
}
//
// Converting from a var in an older dtor to a corresponding var in a newer dtor.
// If possible, use the value from fromVar (type converted, if necessary, to the type of toVar),
// o/wise use toVar's default value.
// Also handle the possiblity of different counts.
// Put the final value in the otherData buffer.
// return false on err
//
bool plStateDataRecord::IConvertVar(plSimpleStateVariable* fromVar, plSimpleStateVariable* toVar /* empty */, bool force)
{
// first fill the dst using it's default value
toVar->SetFromDefaults(false);
if (!fromVar)
return true; // no corresponding var in the old state, done
// Copy the value to the dst, converting if necessary
fromVar->ConvertTo(toVar->GetSimpleVarDescriptor(),force);
toVar->CopyData(fromVar, plSDL::kWriteTimeStamps | plSDL::kKeepDirty);
return true; // ok
}
plStateVariable* plStateDataRecord::IFindVar(const VarsList& vars, const char* name) const
{
for (int i = 0; i < vars.size(); i++)
{
if (!stricmp(vars[i]->GetVarDescriptor()->GetName(), name))
return vars[i];
}
if (plSDLMgr::GetInstance()->GetNetApp())
plSDLMgr::GetInstance()->GetNetApp()->ErrorMsg("Failed to find SDL var %s", name);
return nil;
}
//
// try to convert our data (old version) to other's (new) version.
// return false on err.
//
bool plStateDataRecord::ConvertTo( plStateDescriptor* other, bool force )
{
if (!other && !force)
return false; // err
hsAssert(!stricmp(fDescriptor->GetName(), other->GetName()), "descriptor mismatch");
if ( !force && (other == fDescriptor || other->GetVersion()==fDescriptor->GetVersion()))
return true; // ok, nothing to do
hsAssert(other->GetVersion()>=fDescriptor->GetVersion(), "converting to an older state descriptor version?");
hsLogEntry( plNetApp::StaticDebugMsg( "SDR(%p) converting sdl record %s from version %d to %d (force:%d)",
this, fDescriptor->GetName(), fDescriptor->GetVersion(), other->GetVersion(), force ) );
// make other StateData to represent other descriptor,
// this will be the destination for the convert operation
plStateDataRecord otherStateData(other);
// for each var in the other dtor,
// use the corresponding value in mine (type converted if necessary),
// or use other's default value. Put the final value in the otherData buffer
int i;
for(i=0;i<otherStateData.GetNumVars(); i++)
{
// get other var info
plSimpleStateVariable* otherVar = otherStateData.GetVar(i);
const char* otherVarName = otherVar->GetVarDescriptor()->GetName();
// find corresponding var in my data
plSimpleStateVariable* myVar=FindVar(otherVarName);
IConvertVar(myVar /* fromVar */, otherVar /* toVar */, force);
}
// for each nested stateDesc in the other guy,
// run the convert operation on it recursively.
for(i=0;i<otherStateData.GetNumSDVars(); i++)
{
plSDStateVariable* otherSDVar = otherStateData.GetSDVar(i);
const char* otherSDVarName = otherSDVar->GetVarDescriptor()->GetName();
// find corresponding var in my data
plSDStateVariable* mySDVar=FindSDVar(otherSDVarName);
if (mySDVar)
{
mySDVar->ConvertTo( otherSDVar, force );
otherSDVar->CopyFrom( mySDVar );
}
}
// adopt new descriptor and data
CopyFrom(otherStateData, plSDL::kWriteTimeStamps | plSDL::kKeepDirty);
return true;
}
//
//
//
void plStateDataRecord::DumpToObjectDebugger(const char* msg, 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 numVars = dirtyOnly ? GetNumDirtyVars() : GetNumUsedVars();
int numSDVars = dirtyOnly ? GetNumDirtySDVars() : GetNumUsedSDVars();
dbg->LogMsg(xtl::format("%s", fAssocObject.IsValid() ? fAssocObject.GetObjectName() : " ").c_str());
if (msg)
dbg->LogMsg(xtl::format("%s%s", pad.c_str(),msg).c_str());
dbg->LogMsg(xtl::format("%sSDR(%p), desc=%s, showDirty=%d, numVars=%d, vol=%d",
pad.c_str(), this, fDescriptor->GetName(), dirtyOnly, numVars+numSDVars, fFlags&kVolatile).c_str());
// dump simple vars
for(i=0;i<fVarsList.size(); i++)
{
if ( (dirtyOnly && fVarsList[i]->IsDirty()) || (!dirtyOnly && fVarsList[i]->IsUsed()) )
{
fVarsList[i]->DumpToObjectDebugger(dirtyOnly, level+1);
}
}
// dump nested vars
for(i=0;i<fSDVarsList.size(); i++)
{
if ( (dirtyOnly && fSDVarsList[i]->IsDirty()) || (!dirtyOnly && fSDVarsList[i]->IsUsed()) )
{
fSDVarsList[i]->DumpToObjectDebugger(dirtyOnly, level+1);
}
}
}
void plStateDataRecord::DumpToStream(hsStream* stream, const char* msg, bool dirtyOnly, int level) const
{
std::string pad;
int i;
for(i=0;i<level; i++)
pad += " ";
int numVars = dirtyOnly ? GetNumDirtyVars() : GetNumUsedVars();
int numSDVars = dirtyOnly ? GetNumDirtySDVars() : GetNumUsedSDVars();
std::string logStr = xtl::format("%s", fAssocObject.IsValid() ? fAssocObject.GetObjectName() : " ");
stream->Write(logStr.length(), logStr.c_str());
if (msg)
{
logStr = xtl::format("%s%s", pad.c_str(),msg);
stream->Write(logStr.length(), logStr.c_str());
}
logStr = xtl::format("%sSDR(%p), desc=%s, showDirty=%d, numVars=%d, vol=%d", pad.c_str(), this, fDescriptor->GetName(), dirtyOnly, numVars+numSDVars, fFlags&kVolatile);
stream->Write(logStr.length(), logStr.c_str());
// dump simple vars
for(i=0;i<fVarsList.size(); i++)
{
if ( (dirtyOnly && fVarsList[i]->IsDirty()) || (!dirtyOnly && fVarsList[i]->IsUsed()) )
{
fVarsList[i]->DumpToStream(stream, dirtyOnly, level+1);
}
}
// dump nested vars
for(i=0;i<fSDVarsList.size(); i++)
{
if ( (dirtyOnly && fSDVarsList[i]->IsDirty()) || (!dirtyOnly && fSDVarsList[i]->IsUsed()) )
{
fSDVarsList[i]->DumpToStream(stream, dirtyOnly, level+1);
}
}
logStr = '\n';
stream->Write(logStr.length(), logStr.c_str());
}
void plStateDataRecord::SetFromDefaults(bool timeStampNow)
{
int i;
// set simple vars
for(i=0;i<fVarsList.size(); i++)
{
fVarsList[i]->SetFromDefaults(timeStampNow);
}
// set nested vars
for(i=0;i<fSDVarsList.size(); i++)
{
fSDVarsList[i]->SetFromDefaults(timeStampNow);
}
}
void plStateDataRecord::TimeStampDirtyVars()
{
int i;
// set simple vars
for(i=0;i<fVarsList.size(); i++)
{
if ( fVarsList[i]->IsDirty() )
fVarsList[i]->TimeStamp();
}
// set nested vars
for(i=0;i<fSDVarsList.size(); i++)
{
if ( fVarsList[i]->IsDirty() )
fSDVarsList[i]->TimeStamp();
}
}

View File

@ -0,0 +1,131 @@
/*==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 "hsStream.h"
#include "plSDL.h"
#include "../pnNetCommon/plNetApp.h"
const UInt8 plStateDescriptor::kVersion=1; // for Read/Write format
/////////////////////////////////////////////////////////////////////////////////
// STATE DESC
/////////////////////////////////////////////////////////////////////////////////
plStateDescriptor::~plStateDescriptor()
{
IDeInit();
}
void plStateDescriptor::IDeInit()
{
delete [] fName;
int i;
for(i=0;i<fVarsList.size();i++)
delete fVarsList[i];
fVarsList.clear();
}
plVarDescriptor* plStateDescriptor::FindVar(const char* name, int* idx) const
{
VarsList::const_iterator it;
for(it=fVarsList.begin(); it != fVarsList.end(); it++)
{
if (!stricmp((*it)->GetName(), name))
{
if (idx)
*idx = it-fVarsList.begin();
return *it;
}
}
return nil;
}
//
// Usage: The GameServer reads and write state descriptors along with each saved game
//
bool plStateDescriptor::Read(hsStream* s)
{
UInt8 rwVersion;
s->ReadSwap(&rwVersion);
if (rwVersion != kVersion)
{
plNetApp::StaticWarningMsg("StateDescriptor Read/Write version mismatch, mine %d, read %d", kVersion, rwVersion);
return false;
}
IDeInit();
delete [] fName;
fName = s->ReadSafeString();
UInt16 version=s->ReadSwap16();
fVersion=version;
UInt16 numVars=s->ReadSwap16();
fVarsList.reserve(numVars);
int i;
for(i=0;i<numVars; i++)
{
UInt8 SDVar=s->ReadByte();
plVarDescriptor* var = nil;
if (SDVar)
var = TRACKED_NEW plSDVarDescriptor;
else
var = TRACKED_NEW plSimpleVarDescriptor;
if (var->Read(s))
fVarsList.push_back(var);
else
return false;
}
return true;
}
//
// Usage: The GameServer reads and write state descriptors alon with each saved game
//
void plStateDescriptor::Write(hsStream* s) const
{
s->WriteSwap(kVersion);
s->WriteSafeString(fName);
UInt16 version=fVersion;
s->WriteSwap(version);
UInt16 numVars=fVarsList.size();
s->WriteSwap(numVars);
VarsList::const_iterator it;
for(it=fVarsList.begin(); it!=fVarsList.end(); it++)
{
UInt8 SDVar = ((*it)->GetAsSDVarDescriptor() != nil);
s->WriteByte(SDVar);
(*it)->Write(s);
}
}

View File

@ -0,0 +1,404 @@
/*==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 "hsStream.h"
#include "plSDL.h"
#include "hsStlUtils.h"
#include "../pnKeyedObject/plUoid.h"
#include "../pnNetCommon/plNetApp.h"
#include "../pnMessage/plMessage.h"
#include "../plUnifiedTime/plUnifiedTime.h"
const UInt8 plVarDescriptor::kVersion=3; // for Read/Write format
/////////////////////////////////////////////////////////////////////////////////
// State Var
/////////////////////////////////////////////////////////////////////////////////
plVarDescriptor::plVarDescriptor() :
fName(nil),
fCount(1),
fType(kNone),
fTypeString(nil),
fDefault(nil),
fFlags(0)
{
}
plVarDescriptor::~plVarDescriptor()
{
delete [] fName;
delete [] fDefault;
delete [] fTypeString;
}
//
// Set type from a string. Return false on err.
//
bool plVarDescriptor::SetType(const char* type)
{
if (!type)
return false;
if (!stricmp(type, "vector3"))
fType=kVector3;
else
if (!stricmp(type, "point3"))
fType=kPoint3;
else
if (!stricmp(type, "rgb"))
fType=kRGB;
else
if (!stricmp(type, "rgba"))
fType=kRGBA;
else
if (!stricmp(type, "rgb8"))
fType=kRGB8;
else
if (!stricmp(type, "rgba8"))
fType=kRGBA8;
else
if (!strnicmp(type, "quat",4))
fType=kQuaternion;
else
if (!stricmp(type, "rgba"))
fType=kRGBA;
else
if (!stricmp(type, "int"))
fType=kInt;
else
if (!stricmp(type, "byte"))
fType=kByte;
else
if (!stricmp(type, "short"))
fType=kShort;
else
if (!stricmp(type, "float"))
fType=kFloat;
else
if (!stricmp(type, "double"))
fType=kDouble;
else
if (!stricmp(type, "time"))
fType=kTime;
else
if (!stricmp(type, "ageTimeOfDay"))
fType=kAgeTimeOfDay;
else
if (!stricmp(type, "bool"))
fType=kBool;
else
if (!stricmp(type, "string32"))
fType=kString32;
else
if (!stricmp(type, "plKey"))
fType=kKey;
else
if (!stricmp(type, "message") || !stricmp(type, "creatable") )
fType=kCreatable;
else
if (*type=='$')
fType=kStateDescriptor;
else
return false; // err
delete [] fTypeString;
fTypeString = hsStrcpy(type);
return true; // ok
}
void plVarDescriptor::CopyFrom(const plVarDescriptor* other)
{
SetName(other->GetName());
SetDefault(other->GetDefault());
SetCount(other->GetCount());
SetDisplayOptions(other->GetDisplayOptions());
delete [] fTypeString;
fTypeString=hsStrcpy(other->GetTypeString());
fType = other->GetType();
fFlags = other->fFlags;
}
//
// Var descriptors are read and written by state descriptors
//
bool plVarDescriptor::Read(hsStream* s)
{
UInt8 version;
s->ReadSwap(&version);
if (version != kVersion)
{
if (plSDLMgr::GetInstance()->GetNetApp())
plSDLMgr::GetInstance()->GetNetApp()->WarningMsg("SDL VarDescriptor version mismatch, read %d, should be %d - ignoring",
version, kVersion);
return false;
}
delete [] fName;
fName=s->ReadSafeString();
plMsgStdStringHelper::Peek(fDisplayOptions, s);
fCount=s->ReadSwap32();
fType=(Type)s->ReadByte();
delete [] fDefault;
fDefault = s->ReadSafeString();
fFlags = s->ReadSwap32();
return true;
}
//
// Var descriptors are read and written by state descriptors
//
void plVarDescriptor::Write(hsStream* s) const
{
s->WriteSwap(kVersion);
s->WriteSafeString(fName);
plMsgStdStringHelper::Poke(fDisplayOptions, s);
s->WriteSwap32(fCount);
s->WriteByte((UInt8)fType);
s->WriteSafeString(fDefault);
s->WriteSwap32(fFlags);
}
/////////////////////////////////////////////////////////////////////////////////
// plSimpleVarDescriptor
/////////////////////////////////////////////////////////////////////////////////
plSimpleVarDescriptor::plSimpleVarDescriptor() :
fAtomicType(kNone),
fAtomicCount(1)
{
}
// size in bytes
int plSimpleVarDescriptor::GetAtomicSize() const
{
switch(fAtomicType)
{
case kInt:
return sizeof(int)*GetAtomicCount();
case kByte:
return sizeof(byte)*GetAtomicCount();
case kShort:
return sizeof(short)*GetAtomicCount();
case kAgeTimeOfDay:
case kFloat:
return sizeof(float)*GetAtomicCount();
case kTime:
return sizeof(plUnifiedTime)*GetAtomicCount();
case kDouble:
return sizeof(double)*GetAtomicCount();
case kBool:
return sizeof(bool)*GetAtomicCount();
case kString32:
return sizeof(String32)*GetAtomicCount();
case kKey:
return sizeof(plUoid)*GetAtomicCount();
default:
return -1; // err
}
}
// size of var in bytes
int plSimpleVarDescriptor::GetSize() const
{
int size=GetAtomicSize();
return size>=0 ? size*GetCount() : size;
}
//
// Set type from a string. Return false on err.
// Sets atomicCount and atomicType
//
bool plSimpleVarDescriptor::SetType(const char* type)
{
if (!type)
return false;
if (!plVarDescriptor::SetType(type))
return false;
if (!stricmp(type, "vector3"))
{
fAtomicCount = 3;
fAtomicType=kFloat;
}
else
if (!stricmp(type, "point3"))
{
fAtomicCount = 3;
fAtomicType=kFloat;
}
else
if (!stricmp(type, "rgb"))
{
fAtomicCount = 3;
fAtomicType=kFloat;
}
else
if (!stricmp(type, "rgba"))
{
fAtomicCount = 4;
fAtomicType=kFloat;
}
else
if (!stricmp(type, "rgb8"))
{
fAtomicCount = 3;
fAtomicType=kByte;
}
else
if (!stricmp(type, "rgba8"))
{
fAtomicCount = 4;
fAtomicType=kByte;
}
else
if (!strnicmp(type, "quat",4))
{
fAtomicCount = 4;
fAtomicType=kFloat;
}
else
if (!stricmp(type, "int"))
fAtomicType=kInt;
else
if (!stricmp(type, "byte"))
fAtomicType=kByte;
else
if (!stricmp(type, "short"))
fAtomicType=kShort;
else
if (!stricmp(type, "float"))
fAtomicType=kFloat;
else
if (!stricmp(type, "double"))
fAtomicType=kDouble;
else
if (!stricmp(type, "time"))
fAtomicType=kTime;
else
if (!stricmp(type, "ageTimeOfDay"))
fAtomicType=kAgeTimeOfDay;
else
if (!stricmp(type, "bool"))
fAtomicType=kBool;
else
if (!stricmp(type, "string32"))
fAtomicType=kString32;
else
if (!stricmp(type, "plKey"))
fAtomicType=kKey;
else
if (!stricmp(type, "message") || !stricmp(type, "creatable"))
fAtomicType=kCreatable;
else
return false; // err
return true; // ok
}
void plSimpleVarDescriptor::CopyFrom(const plSimpleVarDescriptor* other)
{
plVarDescriptor::CopyFrom(other);
fAtomicCount=other->GetAtomicCount();
fAtomicType=other->GetAtomicType();
}
//
// Var descriptors are read and written by state descriptors
//
bool plSimpleVarDescriptor::Read(hsStream* s)
{
if (!plVarDescriptor::Read(s))
return false;
fAtomicCount=s->ReadSwap16();
fAtomicType=(Type)s->ReadByte();
return true;
}
//
// Var descriptors are read and written by state descriptors
//
void plSimpleVarDescriptor::Write(hsStream* s) const
{
plVarDescriptor::Write(s);
s->WriteSwap16((Int16)fAtomicCount);
s->WriteByte((UInt8)fAtomicType);
}
/////////////////////////////////////////////////////////////////////////////////
// plSDVarDescriptor
// A var which references another state descriptor
/////////////////////////////////////////////////////////////////////////////////
void plSDVarDescriptor::CopyFrom(const plSDVarDescriptor* other)
{
plVarDescriptor::CopyFrom(other);
SetStateDesc(other->GetStateDescriptor());
}
//
// Var descriptors are read and written by state descriptors
//
bool plSDVarDescriptor::Read(hsStream* s)
{
if (!plVarDescriptor::Read(s))
return false;
char* sdName=s->ReadSafeString();
UInt16 version = s->ReadSwap16();
plStateDescriptor* sd=plSDLMgr::GetInstance()->FindDescriptor(sdName, version);
hsAssert( sd, xtl::format("Failed to find sdl descriptor: %s,%d. Missing legacy descriptor?", sdName, version ).c_str() );
SetStateDesc(sd);
delete [] sdName;
return true;
}
//
// Var descriptors are read and written by state descriptors
//
void plSDVarDescriptor::Write(hsStream* s) const
{
plVarDescriptor::Write(s);
s->WriteSafeString(GetStateDescriptor()->GetName());
UInt16 version=GetStateDescriptor()->GetVersion();
s->WriteSwap(version);
}