/*==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 "hsTypes.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 fSynchedObjectAddrOffset; // this could represent dwords instead of byte offsets UInt16 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 off = (Int32)plSynchedObject::GetStaticSynchedObject() - (Int32)this; if ( hsABS(off) < (1<<(sizeof(fSynchedObjectAddrOffset)<<3)) ) fSynchedObjectAddrOffset = (Int16)off; else fSynchedObjectAddrOffset=-1; } hsBool32 IOKToDirty() { if (fFlags & (kDontDirty | kValueIsDirty)) return false; return GetSynchedObject() ? GetSynchedObject()->IOKToDirty() : false; } virtual void ISaveOrLoad(hsBool32 save, hsStream* stream, hsResMgr* mgr) = 0; // save/load methods for different types const plKey ISaveOrLoad(const plKey key, hsBool32 save, hsStream* stream, hsResMgr* mgr); hsKeyedObject* ISaveOrLoad(hsKeyedObject* obj, hsBool32 save, hsStream* stream, hsResMgr* mgr); plSceneNode* ISaveOrLoad(plSceneNode* obj, hsBool32 save, hsStream* stream, hsResMgr* mgr); plSceneObject* ISaveOrLoad(plSceneObject* obj, hsBool32 save, hsStream* stream, hsResMgr* mgr); Int32 ISaveOrLoad(Int32 v, hsBool32 save, hsStream* stream, hsResMgr* mgr); UInt32 ISaveOrLoad(UInt32 v, hsBool32 save, hsStream* stream, hsResMgr* mgr); bool ISaveOrLoad(bool v, hsBool32 save, hsStream* stream, hsResMgr* mgr); int ISaveOrLoad(int v, hsBool32 save, hsStream* stream, hsResMgr* mgr); // or hsBool32 hsScalar ISaveOrLoad(hsScalar v, hsBool32 save, hsStream* stream, hsResMgr* mgr); double ISaveOrLoad(double v, hsBool32 save, hsStream* stream, hsResMgr* mgr); hsBitVector ISaveOrLoad(hsBitVector& v, hsBool32 save, hsStream* stream, hsResMgr* mgr); plCoordinateInterface* ISaveOrLoad(const plCoordinateInterface* cInt, hsBool32 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)this+fSynchedObjectAddrOffset); if (!(fFlags & kRegistered) && so) { so->RegisterSynchedValue(this); fFlags |= kRegistered; } return so; } UInt16 GetFlags() { return fFlags; } // setters void SetFlags(UInt16 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(hsBool32 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 hsBool32 operator==(const T& other) const { return fValue==(T)other; } hsBool32 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 hsBool32 IsBitSet(UInt32 which) const { return fValue.IsBitSet(which); } hsBool32 SetBit(UInt32 which, hsBool32 on = true) { hsBool32 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(); } hsBool32 ClearBit(UInt32 which) { if (fValue.IsBitSet(which)) DirtyIfNecessary(); return fValue.ClearBit(which); } void Reset() { if (fValue.GetSize()!=0) DirtyIfNecessary(); fValue.Reset(); } hsBool32 ToggleBit(UInt32 which) { DirtyIfNecessary(); return fValue.ToggleBit(which); } UInt32 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(hsBool32 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(hsBool32 save, hsStream* stream, hsResMgr* mgr) { if (save) { // write out size of array Int32 i, num = fValueList.GetCount(); stream->WriteSwap(num); for(i=0;iReadSwap(&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