/*==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 . 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. 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_SYNCHEDVALUE_inc #define PL_SYNCHEDVALUE_inc #include "plSynchedObject.h" #ifdef USE_SYNCHED_VALUES #include "HeadSpin.h" #include "hsStream.h" #include "hsBitVector.h" #include "hsMemory.h" // // Defines a class for variable types which need to automatically be synchronized // (replicated) over the network. // current size is 8 bytes // // // ----------------------------------------------------- // SYNCHED VALUE BASE CLASS // ----------------------------------------------------- // class hsResMgr; class plSceneNode; class plSceneObject; class plCoordinateInterface; class plSynchedValueBase { public: enum Flags // 16 bits { kValueIsDirty = 0x1, kValueSendOnlyOnce = 0x2, // perm flag kValueHasBeenSent = 0x4, // perm flag kRegistered = 0x8, // perm flag kDontDirty = 0x10 // perm flag }; protected: int16_t fSynchedObjectAddrOffset; // this could represent uint32_ts instead of uint8_t offsets uint16_t fFlags; void IConstruct() // too bad this can't be virtual (because it's called from ctor) { // The synchMgr for the class that owns us is constructed first and the staticMgr // is set to his address so we can automatically get at it during construction. fFlags=0; int32_t off = (int32_t)plSynchedObject::GetStaticSynchedObject() - (int32_t)this; if ( hsABS(off) < (1<<(sizeof(fSynchedObjectAddrOffset)<<3)) ) fSynchedObjectAddrOffset = (int16_t)off; else fSynchedObjectAddrOffset=-1; } bool32 IOKToDirty() { if (fFlags & (kDontDirty | kValueIsDirty)) return false; return GetSynchedObject() ? GetSynchedObject()->IOKToDirty() : false; } virtual void ISaveOrLoad(bool32 save, hsStream* stream, hsResMgr* mgr) = 0; // save/load methods for different types const plKey ISaveOrLoad(const plKey key, bool32 save, hsStream* stream, hsResMgr* mgr); hsKeyedObject* ISaveOrLoad(hsKeyedObject* obj, bool32 save, hsStream* stream, hsResMgr* mgr); plSceneNode* ISaveOrLoad(plSceneNode* obj, bool32 save, hsStream* stream, hsResMgr* mgr); plSceneObject* ISaveOrLoad(plSceneObject* obj, bool32 save, hsStream* stream, hsResMgr* mgr); int32_t ISaveOrLoad(int32_t v, bool32 save, hsStream* stream, hsResMgr* mgr); uint32_t ISaveOrLoad(uint32_t v, bool32 save, hsStream* stream, hsResMgr* mgr); bool ISaveOrLoad(bool v, bool32 save, hsStream* stream, hsResMgr* mgr); int ISaveOrLoad(int v, bool32 save, hsStream* stream, hsResMgr* mgr); // or bool32 float ISaveOrLoad(float v, bool32 save, hsStream* stream, hsResMgr* mgr); double ISaveOrLoad(double v, bool32 save, hsStream* stream, hsResMgr* mgr); hsBitVector ISaveOrLoad(hsBitVector& v, bool32 save, hsStream* stream, hsResMgr* mgr); plCoordinateInterface* ISaveOrLoad(const plCoordinateInterface* cInt, bool32 save, hsStream* stream, hsResMgr* mgr); public: plSynchedValueBase() { IConstruct(); } virtual ~plSynchedValueBase() {} // getters virtual plSynchedObject* GetSynchedObject() { hsAssert(fSynchedObjectAddrOffset!=-1, "invalid synchedObject address offset"); plSynchedObject* so = fSynchedObjectAddrOffset == -1 ? nil : (plSynchedObject*)((int32_t)this+fSynchedObjectAddrOffset); if (!(fFlags & kRegistered) && so) { so->RegisterSynchedValue(this); fFlags |= kRegistered; } return so; } uint16_t GetFlags() { return fFlags; } // setters void SetFlags(uint16_t f) { fFlags=f; } void MakeDirty() { SetFlags(GetFlags() | kValueIsDirty); } void MakeClean() { SetFlags(GetFlags() & ~kValueIsDirty); } void DirtyIfNecessary() { if (IOKToDirty()) { MakeDirty(); // dirty value if (GetSynchedObject()) GetSynchedObject()->DirtySynchState(nil, 0); // dirty owner } } // save/load static void Save(plSynchedValueBase& obj, hsStream* stream, hsResMgr* mgr) { obj.ISaveOrLoad(true, stream, mgr); } static void Load(plSynchedValueBase& obj, hsStream* stream, hsResMgr* mgr) { obj.ISaveOrLoad(false, stream, mgr); } }; // // ----------------------------------- // SYNCHED VALUE TEMPLATE // ----------------------------------- // template class plSynchedValue : public plSynchedValueBase { protected: T fValue; void ISaveOrLoad(bool32 save, hsStream* stream, hsResMgr* mgr) { fValue=(T)plSynchedValueBase::ISaveOrLoad(fValue, save, stream, mgr); } // default method public: plSynchedValue() {} plSynchedValue(const T& v) : plSynchedValueBase() { fValue=v; } plSynchedValue(const plSynchedValue& pRHS) : plSynchedValueBase() { fValue=pRHS.GetValue(); } // copy ctor // conversion operators operator T() const { return fValue; } T* operator &() const { return &fValue; } T* operator &() { return &fValue; } // equality bool32 operator==(const T& other) const { return fValue==(T)other; } bool32 operator!=(const T& other) const { return !(*this == other); } // other operators T operator++() { DirtyIfNecessary(); return ++fValue; } T operator++(int) { DirtyIfNecessary(); return fValue++; } // postfix T operator--() { DirtyIfNecessary(); return --fValue; } T operator--(int) { DirtyIfNecessary(); return fValue--; } // postfix T operator+=(const T& other) { return SetValue(fValue+other); } T operator*=(const T& other) { return SetValue(fValue*other); } T operator/=(const T& other) { return SetValue(fValue/other); } // these return reference in the event they are bitvector types T& operator&=(const T& other) { return SetValue(fValue&other); } T& operator|=(const T& other) { return SetValue(fValue|other); } T& operator^=(const T& other) { return SetValue(fValue^other); } T& operator-=(const T& other) { return SetValue(fValue-other); } const T& operator=(const T& v){ return SetValue(v); } #if HS_BUILD_FOR_WIN32 #pragma warning( push ) #pragma warning( disable : 4284 ) // disable annoying warnings in release build for non pointer types #endif // for pointer types, which are allowed to change the object pointed to T operator->(void) { return fValue; } #if HS_BUILD_FOR_WIN32 #pragma warning( pop ) #endif // asignment, can use instead of setvalue const T& operator=(const plSynchedValue& pRHS ) { return SetValue(pRHS.GetValue()); } // setters T& SetValue(const T& v) // return true if changed value { if (v != fValue) // dont dirty unless value changes { fValue=v; DirtyIfNecessary(); } return fValue; } // getters const T& GetValue() const { return fValue; } // for hsBitVector bool32 IsBitSet(uint32_t which) const { return fValue.IsBitSet(which); } bool32 SetBit(uint32_t which, bool32 on = true) { bool32 bitSet = IsBitSet(which); if ( (on && !bitSet) || (!on && bitSet) ) DirtyIfNecessary(); return fValue.SetBit(which, on); } void Read(hsStream* s) { fValue.Read(s); } void Write(hsStream* s) const { fValue.Write(s); } void Clear() { DirtyIfNecessary(); fValue.Clear(); } bool32 ClearBit(uint32_t which) { if (fValue.IsBitSet(which)) DirtyIfNecessary(); return fValue.ClearBit(which); } void Reset() { if (fValue.GetSize()!=0) DirtyIfNecessary(); fValue.Reset(); } bool32 ToggleBit(uint32_t which) { DirtyIfNecessary(); return fValue.ToggleBit(which); } uint32_t GetSize() { return fValue.GetSize(); } }; ////////////////////////////////////// // Synched Value Friend - allows a synched value to be contained // in an object which is not a synchedObject. Uses a pointer instead // of an computer the addr offset of it's associated synchedObject. // This one is 4 bytes bigger than regular synched values. ////////////////////////////////////// template class plSynchedValueFriend : public plSynchedValue { protected: plSynchedObject** fSynchedObject; public: plSynchedValueFriend() : fSynchedObject(nil) { } // this is explicit so it won't be invoked instead of operator()= explicit plSynchedValueFriend(const T& v) : plSynchedValue(v),fSynchedObject(nil) { } plSynchedValueFriend(const plSynchedValueFriend& pRHS) : plSynchedValue(pRHS) { fSynchedObject = pRHS.fSynchedObject; } ~plSynchedValueFriend() { if (GetSynchedObject()) GetSynchedObject()->RemoveSynchedValue(this); } // this isn't inherited for some reason const T& operator=(const T& v) { return SetValue(v); } plSynchedObject* GetSynchedObject() { hsAssert(fSynchedObject, "nil synched object, need to SetSynchedObjectPtrAddr?"); if (*fSynchedObject && !(fFlags & kRegistered)) { (*fSynchedObject)->RegisterSynchedValueFriend(this); fFlags |= kRegistered; } return *fSynchedObject; } void SetSynchedObjectPtrAddr(plSynchedObject** so) { hsAssert(!(fFlags & kRegistered), "SynchedValueFriend already registered?"); fSynchedObject=so; } }; ///////////////////////////////////// // Synched TArray Template ///////////////////////////////////// #include "hsTemplates.h" template class plSynchedTArray : public plSynchedValueBase { private: hsTArray fValueList; void ISaveOrLoad(bool32 save, hsStream* stream, hsResMgr* mgr); public: enum { kMissingIndex = hsTArray::kMissingIndex }; plSynchedTArray() {} ~plSynchedTArray() {} // conversion operators operator T() const { return fValueList; } // common methods const T& operator[](int i) const { return Get(i); } const T& Get(int i) const { return fValueList.Get(i); } void Set(int i, const T& item) { if (fValueList[i] != item) DirtyIfNecessary(); fValueList[i]=item; } void Append(const T& item) { fValueList.Append(item); DirtyIfNecessary(); } T* Insert(int index) { fValueList.Insert(index); DirtyIfNecessary(); } void Remove(int index) { fValueList.Remove(index); DirtyIfNecessary(); } int Count() const { return fValueList.Count(); } int GetCount() const { return Count(); } void Reset() { if (fValueList.GetCount() != 0) DirtyIfNecessary(); fValueList.Reset(); } void SetCountAndZero(int count) { if (count || GetCount()) DirtyIfNecessary(); fValueList.SetCountAndZero(count); } void SetCount(int count) { if (count || GetCount()) DirtyIfNecessary(); fValueList.SetCount(count); } void ExpandAndZero(int count) { if (count || GetCount()) DirtyIfNecessary(); fValueList.ExpandAndZero(count); } int Find(const T& item) const { return fValueList.Find(item); } T* Push() { DirtyIfNecessary(); return fValueList.Push(); } void Push(const T& item) { DirtyIfNecessary(); return fValueList.Push(item); } T Pop() { DirtyIfNecessary(); return fValueList.Pop(); } const T& Peek() const { return fValue.Peek(); } T* DetachArray() { DirtyIfNecessary(); return fValueList.DetachArray(); } T* AcquireArray() { DirtyIfNecessary(); return fValueList.AcquireArray(); } }; // // inlines // template inline void plSynchedTArray::ISaveOrLoad(bool32 save, hsStream* stream, hsResMgr* mgr) { if (save) { // write out size of array int32_t i, num = fValueList.GetCount(); stream->WriteLE(num); for(i=0;iReadLE(&num); for(i=0;i class plSynchedTArrayFriend : public plSynchedTArray { protected: plSynchedObject** fSynchedObject; public: plSynchedTArrayFriend() : fSynchedObject(nil) { } plSynchedObject* GetSynchedObject() { hsAssert(fSynchedObject, "nil synched object, need to SetSynchedObjectPtrAddr?"); if (*fSynchedObject && !(fFlags & kRegistered)) { (*fSynchedObject)->RegisterSynchedValueFriend(this); fFlags |= kRegistered; } return *fSynchedObject; } void SetSynchedObjectPtrAddr(plSynchedObject** so) { hsAssert(!(fFlags & kRegistered), "SynchedValueTArrayFriend already registered?"); fSynchedObject=so; } #if 0 // // redefine operators since they are not inherited // // conversion operators operator T() const { return fValueList; } // common methods const T& operator[](int i) const { return Get(i); } #endif }; #endif // USE_SYNCHED_VALUES #endif // PL_SYNCHEDVALUE_inc