|
|
|
/*==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/>.
|
|
|
|
|
|
|
|
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==*/
|
|
|
|
#include "plSynchedObject.h"
|
|
|
|
#include "plSynchedValue.h"
|
|
|
|
#include "plNetApp.h"
|
|
|
|
#include "plNetGroup.h"
|
|
|
|
#include "hsResMgr.h"
|
|
|
|
#include "pnSceneObject/plSceneObject.h"
|
|
|
|
#include "pnKeyedObject/plKey.h"
|
|
|
|
#include "pnMessage/plSDLModifierMsg.h"
|
|
|
|
#include "pnMessage/plSetNetGroupIDMsg.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
// statics
|
|
|
|
plSynchedObject* plSynchedObject::fStaticSynchedObj=nil;
|
|
|
|
std::vector<plSynchedObject::StateDefn> plSynchedObject::fDirtyStates;
|
|
|
|
std::vector<bool> plSynchedObject::fSynchStateStack;
|
|
|
|
|
|
|
|
plSynchedObject::plSynchedObject() :
|
|
|
|
fSynchFlags(0),
|
|
|
|
#ifdef USE_SYNCHED_VALUES
|
|
|
|
fSynchedValueAddrOffsets(nil),
|
|
|
|
fNumSynchedValues(0),
|
|
|
|
fSynchedValueFriends(nil),
|
|
|
|
fNumSynchedValueFriends(0),
|
|
|
|
#endif
|
|
|
|
fNetGroup(plNetGroup::kNetGroupUnknown)
|
|
|
|
{
|
|
|
|
fStaticSynchedObj=this;
|
|
|
|
}
|
|
|
|
|
|
|
|
plSynchedObject::~plSynchedObject()
|
|
|
|
{
|
|
|
|
#ifdef USE_SYNCHED_VALUES
|
|
|
|
delete [] fSynchedValueAddrOffsets;
|
|
|
|
delete [] fSynchedValueFriends;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool plSynchedObject::MsgReceive(plMessage* msg)
|
|
|
|
{
|
|
|
|
plSetNetGroupIDMsg* setNetGroupID = plSetNetGroupIDMsg::ConvertNoRef(msg);
|
|
|
|
if (setNetGroupID)
|
|
|
|
{
|
|
|
|
SetNetGroupConstant(setNetGroupID->fId);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hsKeyedObject::MsgReceive(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_SYNCHED_VALUES
|
|
|
|
plSynchedValueBase* plSynchedObject::GetSynchedValue(int i) const
|
|
|
|
{
|
|
|
|
if (i<fNumSynchedValues)
|
|
|
|
return IGetSynchedValue((NumSynchedValuesType)i);
|
|
|
|
return IGetSynchedValueFriend((NumSynchedValuesType)(i-fNumSynchedValues));
|
|
|
|
}
|
|
|
|
|
|
|
|
// realloc and add
|
|
|
|
void plSynchedObject::IAppendSynchedValueAddrOffset(AddrOffsetType synchedValueAddrOffset)
|
|
|
|
{
|
|
|
|
// copy to new larger array
|
|
|
|
AddrOffsetType* tmp = new AddrOffsetType[fNumSynchedValues+1];
|
|
|
|
int32_t i;
|
|
|
|
for(i=0;i<fNumSynchedValues;i++)
|
|
|
|
tmp[i] = fSynchedValueAddrOffsets[i];
|
|
|
|
|
|
|
|
// delete old one
|
|
|
|
delete [] fSynchedValueAddrOffsets;
|
|
|
|
|
|
|
|
// point to new array and append value
|
|
|
|
fSynchedValueAddrOffsets=tmp;
|
|
|
|
tmp[fNumSynchedValues++]=synchedValueAddrOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
void plSynchedObject::IAppendSynchedValueFriend(plSynchedValueBase* v)
|
|
|
|
{
|
|
|
|
// copy to new larger array
|
|
|
|
plSynchedValueBase** tmp = new plSynchedValueBase*[fNumSynchedValueFriends+1];
|
|
|
|
int32_t i;
|
|
|
|
for(i=0;i<fNumSynchedValueFriends;i++)
|
|
|
|
tmp[i] = fSynchedValueFriends[i];
|
|
|
|
|
|
|
|
// delete old one
|
|
|
|
delete [] fSynchedValueFriends;
|
|
|
|
|
|
|
|
// point to new array and append value
|
|
|
|
fSynchedValueFriends=tmp;
|
|
|
|
tmp[fNumSynchedValueFriends++]=v;
|
|
|
|
}
|
|
|
|
|
|
|
|
// adds synchedValue and returns index
|
|
|
|
uint8_t plSynchedObject::RegisterSynchedValue(plSynchedValueBase* v)
|
|
|
|
{
|
|
|
|
int32_t addrOff = ((int32_t)v - (int32_t)this)>>2;
|
|
|
|
hsAssert(hsABS(addrOff) < (uint32_t)(1<<(sizeof(AddrOffsetType)<<3)), "address offset overflow");
|
|
|
|
IAppendSynchedValueAddrOffset((AddrOffsetType)addrOff);
|
|
|
|
int32_t idx = fNumSynchedValues-1;
|
|
|
|
hsAssert(idx<256, "index too big");
|
|
|
|
return (uint8_t)idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool plSynchedObject::RemoveSynchedValue(plSynchedValueBase* v)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for(i=0;i<GetNumSynchedValues(); i++)
|
|
|
|
if (GetSynchedValue(i)==v)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// couldn't find it
|
|
|
|
if (i==GetNumSynchedValues())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
int idx=i;
|
|
|
|
if (idx<fNumSynchedValues)
|
|
|
|
{
|
|
|
|
AddrOffsetType* tmp = new AddrOffsetType[fNumSynchedValues-1];
|
|
|
|
for(i=0;i<idx;i++)
|
|
|
|
tmp[i] = fSynchedValueAddrOffsets[i];
|
|
|
|
for(i=idx+1;i<fNumSynchedValues;i++)
|
|
|
|
tmp[i-1] = fSynchedValueAddrOffsets[i];
|
|
|
|
delete [] fSynchedValueAddrOffsets;
|
|
|
|
fSynchedValueAddrOffsets=tmp;
|
|
|
|
fNumSynchedValues--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
idx -= fNumSynchedValues;
|
|
|
|
plSynchedValueBase** tmp = new plSynchedValueBase*[fNumSynchedValueFriends-1];
|
|
|
|
for(i=0;i<idx;i++)
|
|
|
|
tmp[i] = fSynchedValueFriends[i];
|
|
|
|
for(i=idx+1;i<fNumSynchedValueFriends;i++)
|
|
|
|
tmp[i-1] = fSynchedValueFriends[i];
|
|
|
|
delete [] fSynchedValueFriends;
|
|
|
|
fSynchedValueFriends=tmp;
|
|
|
|
fNumSynchedValueFriends--;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// adds synchedValueFriend
|
|
|
|
void plSynchedObject::RegisterSynchedValueFriend(plSynchedValueBase* v)
|
|
|
|
{
|
|
|
|
IAppendSynchedValueFriend(v);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
|
|
// send sdl state msg immediately
|
|
|
|
//
|
|
|
|
void plSynchedObject::SendSDLStateMsg(const char* SDLStateName, uint32_t synchFlags /*SendSDLStateFlags*/)
|
|
|
|
{
|
|
|
|
plSDLModifierMsg* sdlMsg = new plSDLModifierMsg(SDLStateName,
|
|
|
|
(synchFlags & kBCastToClients) ? plSDLModifierMsg::kSendToServerAndClients : plSDLModifierMsg::kSendToServer /* action */);
|
|
|
|
sdlMsg->SetFlags(synchFlags);
|
|
|
|
hsAssert(GetKey(), "nil key on synchedObject?");
|
|
|
|
sdlMsg->Send(GetKey());
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Tell an object to send an sdl state update.
|
|
|
|
// The request will get queued (returns true)
|
|
|
|
//
|
|
|
|
bool plSynchedObject::DirtySynchState(const char* SDLStateName, uint32_t synchFlags /*SendSDLStateFlags*/)
|
|
|
|
{
|
|
|
|
if (!IOKToDirty(SDLStateName))
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
if (plNetClientApp::GetInstance())
|
|
|
|
plNetClientApp::GetInstance()->DebugMsg("NotOKToDirty - Not queueing SDL state, obj %s, sdl %s",
|
|
|
|
GetKeyName(), SDLStateName);
|
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IOKToNetwork(SDLStateName, &synchFlags))
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
if (plNetClientApp::GetInstance())
|
|
|
|
plNetClientApp::GetInstance()->DebugMsg("LocalOnly Object - Not queueing SDL msg, obj %s, sdl %s",
|
|
|
|
GetKeyName(), SDLStateName);
|
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(synchFlags & kSkipLocalOwnershipCheck))
|
|
|
|
{
|
|
|
|
int localOwned=IsLocallyOwned();
|
|
|
|
if (localOwned==plSynchedObject::kNo)
|
|
|
|
return false;
|
|
|
|
if (localOwned==plSynchedObject::kYes)
|
|
|
|
synchFlags |= kSkipLocalOwnershipCheck; // don't have to check again
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (plNetClientApp::GetInstance())
|
|
|
|
plNetClientApp::GetInstance()->DebugMsg("Queueing SDL state with 'maybe' ownership, obj %s, sdl %s",
|
|
|
|
GetKeyName().c_str(), SDLStateName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (synchFlags & kSendImmediately)
|
|
|
|
{
|
|
|
|
SendSDLStateMsg(SDLStateName, synchFlags);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IAddDirtyState(GetKey(), SDLStateName, synchFlags);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// STATIC
|
|
|
|
// add state defn if not already there.
|
|
|
|
// if there adjust flags if necessary
|
|
|
|
//
|
|
|
|
void plSynchedObject::IAddDirtyState(plKey objKey, const char* sdlName, uint32_t sendFlags)
|
|
|
|
{
|
|
|
|
bool found=false;
|
|
|
|
std::vector<StateDefn>::iterator it=fDirtyStates.begin();
|
|
|
|
for( ; it != fDirtyStates.end(); it++)
|
|
|
|
{
|
|
|
|
if ((*it).fObjKey==objKey && !stricmp((*it).fSDLName.c_str(), sdlName))
|
|
|
|
{
|
|
|
|
if (sendFlags & kForceFullSend)
|
|
|
|
(*it).fSendFlags |= kForceFullSend;
|
|
|
|
if (sendFlags & kBCastToClients)
|
|
|
|
(*it).fSendFlags |= kBCastToClients;
|
|
|
|
found=true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
{
|
|
|
|
StateDefn state(objKey, sendFlags, sdlName);
|
|
|
|
fDirtyStates.push_back(state);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
plNetClientApp::GetInstance()->DebugMsg("Not queueing diplicate request for SDL state, obj %s, sdl %s",
|
|
|
|
objKey->GetName(), sdlName);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// STATIC
|
|
|
|
//
|
|
|
|
void plSynchedObject::IRemoveDirtyState(plKey objKey, const char* sdlName)
|
|
|
|
{
|
|
|
|
std::vector<StateDefn>::iterator it=fDirtyStates.begin();
|
|
|
|
for( ; it != fDirtyStates.end(); it++)
|
|
|
|
{
|
|
|
|
if ((*it).fObjKey==objKey && !stricmp((*it).fSDLName.c_str(), sdlName))
|
|
|
|
{
|
|
|
|
fDirtyStates.erase(it);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void plSynchedObject::SetNetGroupConstant(plNetGroupId netGroup)
|
|
|
|
{
|
|
|
|
ClearSynchFlagsBit(kHasConstantNetGroup);
|
|
|
|
SetNetGroup(netGroup); // may recurse
|
|
|
|
SetSynchFlagsBit(kHasConstantNetGroup);
|
|
|
|
}
|
|
|
|
|
|
|
|
plNetGroupId plSynchedObject::SelectNetGroup(plKey rmKey)
|
|
|
|
{
|
|
|
|
return plNetClientApp::GetInstance() ?
|
|
|
|
plNetClientApp::GetInstance()->SelectNetGroup(this, rmKey) : plNetGroup::kNetGroupUnknown;
|
|
|
|
}
|
|
|
|
|
|
|
|
plNetGroupId plSynchedObject::GetEffectiveNetGroup() const
|
|
|
|
{
|
|
|
|
return plNetClientApp::GetInstance() ?
|
|
|
|
plNetClientApp::GetInstance()->GetEffectiveNetGroup(this) : plNetGroup::kNetGroupLocalPlayer;
|
|
|
|
}
|
|
|
|
|
|
|
|
int plSynchedObject::IsLocallyOwned() const
|
|
|
|
{
|
|
|
|
return plNetClientApp::GetInstance() ?
|
|
|
|
plNetClientApp::GetInstance()->IsLocallyOwned(this) : kYes;
|
|
|
|
}
|
|
|
|
|
|
|
|
void plSynchedObject::Read(hsStream* stream, hsResMgr* mgr)
|
|
|
|
{
|
|
|
|
hsKeyedObject::Read(stream, mgr);
|
|
|
|
fNetGroup = GetKey()->GetUoid().GetLocation();
|
|
|
|
|
|
|
|
stream->ReadLE(&fSynchFlags);
|
|
|
|
if (fSynchFlags & kExcludePersistentState)
|
|
|
|
{
|
|
|
|
int16_t num;
|
|
|
|
stream->ReadLE(&num);
|
|
|
|
fSDLExcludeList.clear();
|
|
|
|
int i;
|
|
|
|
for(i=0;i<num;i++)
|
|
|
|
{
|
|
|
|
std::string s;
|
|
|
|
plMsgStdStringHelper::Peek(s, stream);
|
|
|
|
fSDLExcludeList.push_back(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fSynchFlags & kHasVolatileState)
|
|
|
|
{
|
|
|
|
int16_t num;
|
|
|
|
stream->ReadLE(&num);
|
|
|
|
fSDLVolatileList.clear();
|
|
|
|
int i;
|
|
|
|
for(i=0;i<num;i++)
|
|
|
|
{
|
|
|
|
std::string s;
|
|
|
|
plMsgStdStringHelper::Peek(s, stream);
|
|
|
|
fSDLVolatileList.push_back(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void plSynchedObject::Write(hsStream* stream, hsResMgr* mgr)
|
|
|
|
{
|
|
|
|
hsKeyedObject::Write(stream, mgr);
|
|
|
|
stream->WriteLE(fSynchFlags);
|
|
|
|
|
|
|
|
if (fSynchFlags & kExcludePersistentState)
|
|
|
|
{
|
|
|
|
int16_t num=fSDLExcludeList.size();
|
|
|
|
stream->WriteLE(num);
|
|
|
|
|
|
|
|
SDLStateList::iterator it=fSDLExcludeList.begin();
|
|
|
|
for(; it != fSDLExcludeList.end(); it++)
|
|
|
|
{
|
|
|
|
plMsgStdStringHelper::Poke(*it, stream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fSynchFlags & kHasVolatileState)
|
|
|
|
{
|
|
|
|
int16_t num=fSDLVolatileList.size();
|
|
|
|
stream->WriteLE(num);
|
|
|
|
|
|
|
|
SDLStateList::iterator it=fSDLVolatileList.begin();
|
|
|
|
for(; it != fSDLVolatileList.end(); it++)
|
|
|
|
{
|
|
|
|
plMsgStdStringHelper::Poke(*it, stream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// static
|
|
|
|
//
|
|
|
|
bool plSynchedObject::PopSynchDisabled()
|
|
|
|
{
|
|
|
|
if (fSynchStateStack.size())
|
|
|
|
{
|
|
|
|
bool ret=fSynchStateStack.back();
|
|
|
|
fSynchStateStack.pop_back();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hsAssert(false, "invalid stack size?");
|
|
|
|
}
|
|
|
|
return true; // disabled
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_DIRTY_NOTIFIERS
|
|
|
|
void plSynchedObject::AddDirtyNotifier(plDirtyNotifier* dn)
|
|
|
|
{
|
|
|
|
if (dn)
|
|
|
|
{
|
|
|
|
std::vector<plDirtyNotifier*>::iterator it=std::find(fDirtyNotifiers.begin(), fDirtyNotifiers.end(), dn);
|
|
|
|
if (it == fDirtyNotifiers.end()) // not there
|
|
|
|
{
|
|
|
|
dn->SetSynchedObjKey(GetKey());
|
|
|
|
fDirtyNotifiers.push_back(dn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void plSynchedObject::RemoveDirtyNotifier(plDirtyNotifier* dn)
|
|
|
|
{
|
|
|
|
if (dn)
|
|
|
|
{
|
|
|
|
std::vector<plDirtyNotifier*>::iterator it=std::find(fDirtyNotifiers.begin(), fDirtyNotifiers.end(), dn);
|
|
|
|
if (it != fDirtyNotifiers.end()) // its there
|
|
|
|
fDirtyNotifiers.erase(it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void plSynchedObject::CallDirtyNotifiers()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for(i=0;i<fDirtyNotifiers.size();i++)
|
|
|
|
fDirtyNotifiers[i]->Callback();
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
void plSynchedObject::CallDirtyNotifiers() {}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
|
|
// return true if it's ok to dirty this object
|
|
|
|
//
|
|
|
|
bool plSynchedObject::IOKToDirty(const char* SDLStateName) const
|
|
|
|
{
|
|
|
|
// is synching disabled?
|
|
|
|
bool synchDisabled = (GetSynchDisabled()!=0);
|
|
|
|
if (synchDisabled)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// is object dirtyAble?
|
|
|
|
bool dontDirty = (fSynchFlags & kDontDirty) != 0;
|
|
|
|
if (dontDirty)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// is object in a LocalOnly age?
|
|
|
|
if (plNetClientApp::GetConstInstance() && plNetClientApp::GetConstInstance()->ObjectInLocalAge(this))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true; // OK to dirty
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// return true if this object should send his SDL msg (for persistence or synch) over the net
|
|
|
|
//
|
|
|
|
bool plSynchedObject::IOKToNetwork(const char* sdlName, uint32_t* synchFlags) const
|
|
|
|
{
|
|
|
|
// determine destination
|
|
|
|
bool dstServerOnly=false, dstClientsOnly=false, dstClientsAndServer=false;
|
|
|
|
|
|
|
|
if ((*synchFlags) & kBCastToClients)
|
|
|
|
{ // bcasting to clients and server
|
|
|
|
if ((*synchFlags) & kDontPersistOnServer)
|
|
|
|
dstClientsOnly=true;
|
|
|
|
else
|
|
|
|
dstClientsAndServer=true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // not bcasting, must be sending to server only
|
|
|
|
hsAssert( ((*synchFlags) & kDontPersistOnServer)==0, "invalid synchedObject msg flag");
|
|
|
|
dstServerOnly=true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool netSynched = IsNetSynched();
|
|
|
|
bool inExcludeList = IsInSDLExcludeList(sdlName);
|
|
|
|
|
|
|
|
//
|
|
|
|
// check if ok to network based on destination
|
|
|
|
//
|
|
|
|
if (dstClientsOnly)
|
|
|
|
{
|
|
|
|
return netSynched;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dstClientsAndServer)
|
|
|
|
{
|
|
|
|
if ( !netSynched )
|
|
|
|
{
|
|
|
|
*synchFlags &= ~kBCastToClients; // don't send to clients
|
|
|
|
}
|
|
|
|
if ( inExcludeList )
|
|
|
|
{
|
|
|
|
*synchFlags |= kDontPersistOnServer; // don't store on server
|
|
|
|
}
|
|
|
|
|
|
|
|
return !inExcludeList || netSynched;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dstServerOnly)
|
|
|
|
{
|
|
|
|
return !inExcludeList;
|
|
|
|
}
|
|
|
|
|
|
|
|
hsAssert(false, "how did I get here");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
plSynchedObject::SDLStateList::const_iterator plSynchedObject::IFindInSDLStateList(const SDLStateList& list, const char* sdlName) const
|
|
|
|
{
|
|
|
|
if (!sdlName)
|
|
|
|
return list.end(); // false
|
|
|
|
|
|
|
|
SDLStateList::const_iterator it = list.begin();
|
|
|
|
for(; it != list.end(); it++)
|
|
|
|
if (!stricmp((*it).c_str(), sdlName))
|
|
|
|
return it;
|
|
|
|
|
|
|
|
return it; // .end(), false
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////
|
|
|
|
// EXCLUDE LIST
|
|
|
|
///////////////////////////
|
|
|
|
|
|
|
|
void plSynchedObject::AddToSDLExcludeList(const char* sdlName)
|
|
|
|
{
|
|
|
|
if (sdlName)
|
|
|
|
{
|
|
|
|
if (IFindInSDLStateList(fSDLExcludeList, sdlName)==fSDLExcludeList.end())
|
|
|
|
{
|
|
|
|
fSDLExcludeList.push_back(sdlName); // Don't dupe sdlName, std::string will copy
|
|
|
|
fSynchFlags |= kExcludePersistentState;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void plSynchedObject::RemoveFromSDLExcludeList(const char* sdlName)
|
|
|
|
{
|
|
|
|
SDLStateList::const_iterator it=IFindInSDLStateList(fSDLExcludeList, sdlName);
|
|
|
|
if (it != fSDLExcludeList.end())
|
|
|
|
{
|
|
|
|
fSDLExcludeList.erase(fSDLExcludeList.begin()+(it-fSDLExcludeList.begin()));
|
|
|
|
if (fSDLExcludeList.size()==0)
|
|
|
|
fSynchFlags &= ~kExcludePersistentState;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool plSynchedObject::IsInSDLExcludeList(const char* sdlName) const
|
|
|
|
{
|
|
|
|
if ((fSynchFlags & kExcludeAllPersistentState) != 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if ((fSynchFlags & kExcludePersistentState) == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SDLStateList::const_iterator it=IFindInSDLStateList(fSDLExcludeList, sdlName);
|
|
|
|
return (it != fSDLExcludeList.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////
|
|
|
|
// VOLATILE LIST
|
|
|
|
///////////////////////////
|
|
|
|
|
|
|
|
void plSynchedObject::AddToSDLVolatileList(const char* sdlName)
|
|
|
|
{
|
|
|
|
if (sdlName)
|
|
|
|
{
|
|
|
|
if (IFindInSDLStateList(fSDLVolatileList,sdlName)==fSDLVolatileList.end())
|
|
|
|
{
|
|
|
|
fSDLVolatileList.push_back(sdlName); // Don't dupe sdlName, std::string will copy
|
|
|
|
fSynchFlags |= kHasVolatileState;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void plSynchedObject::RemoveFromSDLVolatileList(const char* sdlName)
|
|
|
|
{
|
|
|
|
SDLStateList::const_iterator it=IFindInSDLStateList(fSDLVolatileList,sdlName);
|
|
|
|
if (it != fSDLVolatileList.end())
|
|
|
|
{
|
|
|
|
fSDLVolatileList.erase(fSDLVolatileList.begin()+(it-fSDLVolatileList.begin()));
|
|
|
|
if (fSDLVolatileList.size()==0)
|
|
|
|
fSynchFlags &= ~kHasVolatileState;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool plSynchedObject::IsInSDLVolatileList(const char* sdlName) const
|
|
|
|
{
|
|
|
|
if ((fSynchFlags & kAllStateIsVolatile) != 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if ((fSynchFlags & kHasVolatileState) == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SDLStateList::const_iterator it=IFindInSDLStateList(fSDLVolatileList,sdlName);
|
|
|
|
return (it != fSDLVolatileList.end());
|
|
|
|
}
|
|
|
|
|