Files
src-1.2/engine/server/library/serverGame/src/shared/object/ServerObject_Synchronization.cpp
T
2014-01-15 03:59:18 -07:00

1108 lines
42 KiB
C++

// ======================================================================
//
// ServerObject_Synchronization.cpp
//
// Copyright 2004 Sony Online Entertainment
//
// ======================================================================
#include "serverGame/FirstServerGame.h"
#include "serverGame/ServerObject.h"
#include "serverGame/BaselineDistributionListPool.h"
#include "serverGame/ConfigServerGame.h"
#include "serverGame/ConnectionServerConnection.h"
#include "serverGame/ContainerInterface.h"
#include "serverGame/ContainmentMessageManager.h"
#include "serverGame/DestroyMessageManager.h"
#include "serverGame/DistributionListStack.h"
#include "serverGame/GameServer.h"
#include "serverGame/ServerMessageForwarding.h"
#include "serverGame/ServerObjectBaselinesManager.h"
#include "serverGame/ServerWorld.h"
#include "serverNetworkMessages/CreateObjectMessage.h"
#include "serverNetworkMessages/EndBaselinesMessage.h"
#include "serverNetworkMessages/GameConnectionServerMessages.h"
#include "serverNetworkMessages/SynchronizeScriptVarsMessage.h"
#include "serverNetworkMessages/UnloadObjectMessage.h"
#include "serverNetworkMessages/UpdateObjectPositionMessage.h"
#include "serverScript/GameScriptObject.h"
#include "sharedDebug/Profiler.h"
#include "sharedFoundation/ConstCharCrcString.h"
#include "sharedLog/Log.h"
#include "sharedObject/ContainedByProperty.h"
#include "sharedObject/NetworkIdManager.h"
#include "sharedObject/ObjectTemplateList.h"
#include "sharedObject/PortalProperty.h"
#include "sharedObject/SlottedContainmentProperty.h"
#include "sharedNetworkMessages/BaselinesMessage.h"
#include "sharedNetworkMessages/DeltasMessage.h"
#include "sharedNetworkMessages/GenericValueTypeMessage.h"
#include "sharedNetworkMessages/SceneChannelMessages.h"
#include "sharedNetworkMessages/UpdateContainmentMessage.h"
// ======================================================================
namespace ServerObject_SynchronizationNamespace
{
// ----------------------------------------------------------------------
Client const *getParentPlayerClient(ServerObject const *o)
{
while (o && !o->isInWorld() && !o->isPlayerControlled())
o = safe_cast<ServerObject const *>(ContainerInterface::getContainedByObject(*o));
return o ? o->getClient() : 0;
}
// ----------------------------------------------------------------------
void logBaselines(NetworkId const &senderId, char const *messageType, std::vector<NetworkId> const & clients)
{
if (!ConfigServerGame::getLogBaselines())
return;
for (std::vector<NetworkId>::const_iterator i = clients.begin(); i != clients.end(); ++i)
{
DEBUG_REPORT_LOG(true, ("Baselines: %s for object %s to client %s\n", messageType, senderId.getValueString().c_str(), (*i).getValueString().c_str()));
LOG(
"Baselines",
(
"%s for object %s to client %s",
messageType,
senderId.getValueString().c_str(),
(*i).getValueString().c_str()));
}
}
// ----------------------------------------------------------------------
}
using namespace ServerObject_SynchronizationNamespace;
// ======================================================================
void ServerObject::synchronizationOnConstruct()
{
m_dirtyArchiveCallback.set(*this, &ServerObject::onAutoDeltaChanged);
m_authClientServerPackage.addOnDirtyCallback(&m_dirtyArchiveCallback);
m_authClientServerPackage_np.addOnDirtyCallback(&m_dirtyArchiveCallback);
m_firstParentAuthClientServerPackage.addOnDirtyCallback(&m_dirtyArchiveCallback);
m_firstParentAuthClientServerPackage_np.addOnDirtyCallback(&m_dirtyArchiveCallback);
m_serverPackage.addOnDirtyCallback(&m_dirtyArchiveCallback);
m_serverPackage_np.addOnDirtyCallback(&m_dirtyArchiveCallback);
m_sharedPackage.addOnDirtyCallback(&m_dirtyArchiveCallback);
m_sharedPackage_np.addOnDirtyCallback(&m_dirtyArchiveCallback);
}
// ----------------------------------------------------------------------
void ServerObject::synchronizationOnDestruct()
{
BaselineDistributionListPool::free(*this);
m_authClientServerPackage.removeOnDirtyCallback();
m_authClientServerPackage_np.removeOnDirtyCallback();
m_firstParentAuthClientServerPackage.removeOnDirtyCallback();
m_firstParentAuthClientServerPackage_np.removeOnDirtyCallback();
m_serverPackage.removeOnDirtyCallback();
m_serverPackage_np.removeOnDirtyCallback();
m_sharedPackage.removeOnDirtyCallback();
m_sharedPackage_np.removeOnDirtyCallback();
ServerObjectBaselinesManager::serverObjDestroyed(*this);
}
// ----------------------------------------------------------------------
void ServerObject::synchronizationOnContainerChange(ServerObject const *oldContainer, ServerObject const *newContainer) const
{
ServerObjectBaselinesManager::onContainerChanged(*this, oldContainer, newContainer);
}
// ----------------------------------------------------------------------
void ServerObject::synchronizationOnLoadedInContainer()
{
ServerObject * const containingObject = safe_cast<ServerObject *>(ContainerInterface::getContainedByObject(*this));
FATAL(!containingObject, ("ServerObject::synchronizationOnLoadedInContainer: obj %s with unresolvable container", getDebugInformation().c_str()));
if (containingObject->isInitialized() && containingObject->isAuthoritative())
{
ProxyList const &proxyList = containingObject->getExposedProxyList();
if (!proxyList.empty())
{
ServerMessageForwarding::begin(std::vector<uint32>(proxyList.begin(), proxyList.end()));
forwardServerCreateAndBaselines();
ServerMessageForwarding::end();
}
}
}
// ----------------------------------------------------------------------
void ServerObject::synchronizationOnUnload() const
{
if (isAuthoritative())
{
ProxyList const &proxyList = getExposedProxyList();
if (!proxyList.empty())
{
ServerMessageForwarding::begin(std::vector<uint32>(proxyList.begin(), proxyList.end()));
UnloadObjectMessage const unloadMessage(getNetworkId());
ServerMessageForwarding::send(unloadMessage);
ServerMessageForwarding::end();
}
}
}
// ----------------------------------------------------------------------
void ServerObject::onAutoDeltaChanged()
{
setLocalFlag(LocalObjectFlags::ServerObject_AutoDeltaChanged, true);
addObjectToConcludeList();
}
// ----------------------------------------------------------------------
void ServerObject::addAuthClientServerVariable(Archive::AutoDeltaVariableBase &source)
{
m_authClientServerPackage.addVariable(source);
}
// ----------------------------------------------------------------------
void ServerObject::addAuthClientServerVariable_np(Archive::AutoDeltaVariableBase &source)
{
m_authClientServerPackage_np.addVariable(source);
}
// ----------------------------------------------------------------------
void ServerObject::addFirstParentAuthClientServerVariable(Archive::AutoDeltaVariableBase &source)
{
m_firstParentAuthClientServerPackage.addVariable(source);
}
// ----------------------------------------------------------------------
void ServerObject::addFirstParentAuthClientServerVariable_np(Archive::AutoDeltaVariableBase &source)
{
m_firstParentAuthClientServerPackage_np.addVariable(source);
}
// ----------------------------------------------------------------------
void ServerObject::addServerVariable(Archive::AutoDeltaVariableBase &source)
{
m_serverPackage.addVariable(source);
}
// ----------------------------------------------------------------------
void ServerObject::addServerVariable_np(Archive::AutoDeltaVariableBase &source)
{
m_serverPackage_np.addVariable(source);
}
// ----------------------------------------------------------------------
void ServerObject::addSharedVariable(Archive::AutoDeltaVariableBase &source)
{
m_sharedPackage.addVariable(source);
}
// ----------------------------------------------------------------------
void ServerObject::addSharedVariable_np(Archive::AutoDeltaVariableBase &source)
{
m_sharedPackage_np.addVariable(source);
}
// ----------------------------------------------------------------------
void ServerObject::sendCreateAndBaselinesToClient(Client &client) const
{
if (getSendToClient() && !isBeingDestroyed())
{
if (!DestroyMessageManager::remove(&client, getNetworkId()))
{
std::vector<Watcher<Client> > *baselineDistributionList = BaselineDistributionListPool::get(*this, true);
if (baselineDistributionList->empty())
ServerObjectBaselinesManager::add(*this);
baselineDistributionList->push_back(Watcher<Client>(&client));
}
}
}
// ----------------------------------------------------------------------
void ServerObject::sendCreateAndBaselinesToDatabaseServer() const
{
if (isBeingDestroyed())
return;
FATAL(!isAuthoritative(), ("ServerObject::sendCreateAndBaselinesToDatabaseServer: obj %s, while non-auth", getDebugInformation().c_str()));
FATAL(!isPersisted(), ("ServerObject::sendCreateAndBaselinesToDatabaseServer: obj %s, while nonpersisted", getDebugInformation().c_str()));
GameServer::incrementTotalObjectCreatesSent();
NetworkId const &containedById = ContainerInterface::getContainedByProperty(*this)->getContainedByNetworkId();
NetworkId const &loadWithId = ContainerInterface::getLoadWithContainerId(*this);
int const currentArrangement = ContainerInterface::getSlottedContainmentProperty(*this)->getCurrentArrangement();
CreateObjectByCrcMessage const createMessage(getNetworkId(), getTemplateCrc(), getObjectType(), false, containedById);
//Vector vp = getTransform_o2p().getPosition_p();
//Vector vw = getTransform_o2w().getPosition_p();
//LOG("ServerObject",("Baseline PS XYZ (%f %f %f) WS XYZ (%f %f %f)",vp.x, vp.y, vp.z, vw.x, vw.y, vw.z));
Transform worldspaceTransformForDatabase(getTransform_o2w());
// if it's a player inside a container, the world space coordinate
// that should be saved is the world space coordinate of the topmost
// container; this way, player logging out of a house will get
// loaded back into the same game server as the house, thus maximizing
// that chance that the player will loaded back into the house
if (isPlayerControlled() && asCreatureObject())
{
Object const *containerObj = ContainerInterface::getTopmostContainer(*this);
if (containerObj && (containerObj != this))
{
worldspaceTransformForDatabase = containerObj->getTransform_o2w();
}
}
UpdateObjectPositionMessage const uop(getNetworkId(), getTransform_o2p(), worldspaceTransformForDatabase, containedById, currentArrangement, loadWithId, isPlayerControlled(), asCreatureObject() ? true : false);
BaselinesMessage const shared(getNetworkId(), getObjectType(), m_sharedPackage, BaselinesMessage::BASELINES_SHARED);
BaselinesMessage const authClient(getNetworkId(), getObjectType(), m_authClientServerPackage, BaselinesMessage::BASELINES_CLIENT_SERVER);
BaselinesMessage const servers(getNetworkId(), getObjectType(), m_serverPackage, BaselinesMessage::BASELINES_SERVER);
BaselinesMessage const firstParentAuthClient(getNetworkId(), getObjectType(), m_firstParentAuthClientServerPackage, BaselinesMessage::BASELINES_FIRST_PARENT_CLIENT_SERVER);
GameServer::getInstance().sendToDatabaseServer(createMessage);
GameServer::getInstance().sendToDatabaseServer(uop);
GameServer::getInstance().sendToDatabaseServer(shared);
GameServer::getInstance().sendToDatabaseServer(authClient);
GameServer::getInstance().sendToDatabaseServer(servers);
GameServer::getInstance().sendToDatabaseServer(firstParentAuthClient);
Container const * const container = ContainerInterface::getContainer(*this);
if (container)
{
for (ContainerConstIterator containerIterator = container->begin(); containerIterator != container->end(); ++containerIterator)
{
ServerObject const * const containedObject = safe_cast<ServerObject const *>((*containerIterator).getObject());
if (containedObject && containedObject->isPersisted())
containedObject->sendCreateAndBaselinesToDatabaseServer();
}
}
EndBaselinesMessage const endBaselinesMessage(getNetworkId());
GameServer::getInstance().sendToDatabaseServer(endBaselinesMessage);
}
// ----------------------------------------------------------------------
void ServerObject::forwardServerCreateAndBaselines() const
{
if (isBeingDestroyed())
return;
FATAL(!isAuthoritative(), ("ServerObject::forwardServerCreateAndBaselines: obj %s, while non-auth", getDebugInformation().c_str()));
GameServer::incrementTotalObjectCreatesSent();
NetworkId const &containedById = ContainerInterface::getContainedByProperty(*this)->getContainedByNetworkId();
NetworkId const &loadWithId = ContainerInterface::getLoadWithContainerId(*this);
int const currentArrangement = ContainerInterface::getSlottedContainmentProperty(*this)->getCurrentArrangement();
CreateObjectByCrcMessage const createMessage(getNetworkId(), getTemplateCrc(), getObjectType(), false, containedById);
//Vector vp = getTransform_o2p().getPosition_p();
//Vector vw = getTransform_o2w().getPosition_p();
//LOG("ServerObject",("forwardServerCreateAndBaselines PS XYZ (%f %f %f) WS XYZ (%f %f %f)",vp.x, vp.y, vp.z, vw.x, vw.y, vw.z));
UpdateObjectPositionMessage const uop(getNetworkId(), getTransform_o2p(), getTransform_o2w(), containedById, currentArrangement, loadWithId, isPlayerControlled(), asCreatureObject() ? true : false);
BaselinesMessage const shared(getNetworkId(), getObjectType(), m_sharedPackage, BaselinesMessage::BASELINES_SHARED);
BaselinesMessage const authClient(getNetworkId(), getObjectType(), m_authClientServerPackage, BaselinesMessage::BASELINES_CLIENT_SERVER);
BaselinesMessage const servers(getNetworkId(), getObjectType(), m_serverPackage, BaselinesMessage::BASELINES_SERVER);
BaselinesMessage const sharedNp(getNetworkId(), getObjectType(), m_sharedPackage_np, BaselinesMessage::BASELINES_SHARED_NP);
BaselinesMessage const authClientNp(getNetworkId(), getObjectType(), m_authClientServerPackage_np, BaselinesMessage::BASELINES_CLIENT_SERVER_NP);
BaselinesMessage const serversNp(getNetworkId(), getObjectType(), m_serverPackage_np, BaselinesMessage::BASELINES_SERVER_NP);
BaselinesMessage const firstParentAuthClient(getNetworkId(), getObjectType(), m_firstParentAuthClientServerPackage, BaselinesMessage::BASELINES_FIRST_PARENT_CLIENT_SERVER);
BaselinesMessage const firstParentAuthClientNp(getNetworkId(), getObjectType(), m_firstParentAuthClientServerPackage_np, BaselinesMessage::BASELINES_FIRST_PARENT_CLIENT_SERVER_NP);
ServerMessageForwarding::send(createMessage);
ServerMessageForwarding::send(uop);
ServerMessageForwarding::send(shared);
ServerMessageForwarding::send(authClient);
ServerMessageForwarding::send(servers);
ServerMessageForwarding::send(sharedNp);
ServerMessageForwarding::send(authClientNp);
ServerMessageForwarding::send(firstParentAuthClient);
ServerMessageForwarding::send(firstParentAuthClientNp);
ServerMessageForwarding::send(serversNp);
if (m_scriptObject)
{
std::vector<int8> scriptVars;
m_scriptObject->packScriptVars(scriptVars);
if (!scriptVars.empty())
{
SynchronizeScriptVarsMessage const scriptVarsMessage(getNetworkId(), scriptVars);
ServerMessageForwarding::send(scriptVarsMessage);
}
}
forwardServerObjectSpecificBaselines();
Container const * const container = ContainerInterface::getContainer(*this);
if (container)
{
for (ContainerConstIterator containerIterator = container->begin(); containerIterator != container->end(); ++containerIterator)
{
ServerObject const * const containedObject = safe_cast<ServerObject const *>((*containerIterator).getObject());
if (containedObject)
containedObject->forwardServerCreateAndBaselines();
}
}
EndBaselinesMessage const endBaselinesMessage(getNetworkId());
ServerMessageForwarding::send(endBaselinesMessage);
}
// ----------------------------------------------------------------------
void ServerObject::sendDeltasForSelfAndContents(ProxyList const *proxyList) const
{
sendDeltas(proxyList);
Container const * const container = ContainerInterface::getContainer(*this);
if (container)
{
for (ContainerConstIterator i = container->begin(); i != container->end(); ++i)
{
ServerObject const * const containedObject = safe_cast<ServerObject const *>((*i).getObject());
if (containedObject)
containedObject->sendDeltasForSelfAndContents(proxyList);
}
}
}
// ----------------------------------------------------------------------
void ServerObject::sendDeltas(ProxyList const *proxyList) const
{
FATAL(!isInitialized(), ("ServerObject::sendDeltas: %s while uninitialized.", getDebugInformation().c_str()));
if (!getLocalFlag(LocalObjectFlags::ServerObject_AutoDeltaChanged) || isBeingDestroyed())
return;
PROFILER_AUTO_BLOCK_DEFINE("ServerObject::sendDeltas");
ProxyList const * const proxyServers = proxyList ? proxyList : &getExposedProxyList();
bool const sendServerDeltas = !proxyServers->empty();
if (sendServerDeltas)
ServerMessageForwarding::begin(std::vector<uint32>(proxyServers->begin(), proxyServers->end()));
// sync auth client data (if we have an auth client)
if ( m_authClientServerPackage.getItemCount() > 0
|| m_authClientServerPackage_np.getItemCount() > 0)
{
static std::set<Client const *> authClients;
{
PROFILER_AUTO_BLOCK_DEFINE("getAuthClients");
getAuthClients(authClients);
}
if (m_authClientServerPackage.getItemCount() > 0)
{
PROFILER_AUTO_BLOCK_DEFINE("authClientServerPackage");
DeltasMessage const cdm(getNetworkId(), getObjectType(), m_authClientServerPackage, DeltasMessage::DELTAS_CLIENT_SERVER);
for (std::set<Client const *>::const_iterator i = authClients.begin(); i != authClients.end(); ++i)
(*i)->send(cdm, true);
if (isAuthoritative())
{
if (sendServerDeltas)
ServerMessageForwarding::send(cdm);
if (isPersisted())
GameServer::getInstance().sendToDatabaseServer(cdm);
}
}
if (m_authClientServerPackage_np.getItemCount() > 0)
{
PROFILER_AUTO_BLOCK_DEFINE("authClientServerPackage_np");
DeltasMessage const cdm(getNetworkId(), getObjectType(), m_authClientServerPackage_np, DeltasMessage::DELTAS_CLIENT_SERVER_NP);
for (std::set<Client const *>::const_iterator i = authClients.begin(); i != authClients.end(); ++i)
(*i)->send(cdm, true);
if (isAuthoritative() && sendServerDeltas)
ServerMessageForwarding::send(cdm);
}
authClients.clear();
}
// first parent auth client data
{
Client const * const parentPlayerClient = getParentPlayerClient(this);
if (m_firstParentAuthClientServerPackage.getItemCount() > 0)
{
PROFILER_AUTO_BLOCK_DEFINE("firstParentAuthClientServerPackage");
DeltasMessage const cdm(getNetworkId(), getObjectType(), m_firstParentAuthClientServerPackage, DeltasMessage::DELTAS_FIRST_PARENT_CLIENT_SERVER);
if (parentPlayerClient)
parentPlayerClient->send(cdm, true);
if (isAuthoritative())
{
if (sendServerDeltas)
ServerMessageForwarding::send(cdm);
if (isPersisted())
GameServer::getInstance().sendToDatabaseServer(cdm);
}
}
if (m_firstParentAuthClientServerPackage_np.getItemCount() > 0)
{
PROFILER_AUTO_BLOCK_DEFINE("firstParentAuthClientServerPackage_np");
DeltasMessage const cdm(getNetworkId(), getObjectType(), m_firstParentAuthClientServerPackage_np, DeltasMessage::DELTAS_FIRST_PARENT_CLIENT_SERVER_NP);
if (parentPlayerClient)
parentPlayerClient->send(cdm, true);
if (isAuthoritative() && sendServerDeltas)
ServerMessageForwarding::send(cdm);
}
}
// sync shared data
if (m_sharedPackage.getItemCount() > 0)
{
PROFILER_AUTO_BLOCK_DEFINE("sharedPackage");
DeltasMessage const sharedPkg(getNetworkId(), getObjectType(), m_sharedPackage, DeltasMessage::DELTAS_SHARED);
sendToClientsInUpdateRange(sharedPkg, true);
if (isAuthoritative())
{
if (sendServerDeltas)
ServerMessageForwarding::send(sharedPkg);
if (isPersisted())
GameServer::getInstance().sendToDatabaseServer(sharedPkg);
}
}
if (m_sharedPackage_np.getItemCount() > 0)
{
PROFILER_AUTO_BLOCK_DEFINE("sharedPackage_np");
DeltasMessage const sharedPkgNp(getNetworkId(), getObjectType(), m_sharedPackage_np, DeltasMessage::DELTAS_SHARED_NP);
sendToClientsInUpdateRange(sharedPkgNp, true);
if (isAuthoritative() && sendServerDeltas)
ServerMessageForwarding::send(sharedPkgNp);
}
// sync server data (if we are authoritative)
if (isAuthoritative())
{
if (m_serverPackage.getItemCount() > 0)
{
PROFILER_AUTO_BLOCK_DEFINE("serverPackage");
DeltasMessage const server(getNetworkId(), getObjectType(), m_serverPackage, DeltasMessage::DELTAS_SERVER);
if (sendServerDeltas)
ServerMessageForwarding::send(server);
if (isPersisted())
GameServer::getInstance().sendToDatabaseServer(server);
}
if (sendServerDeltas && m_serverPackage_np.getItemCount() > 0)
{
PROFILER_AUTO_BLOCK_DEFINE("serverPackage_np");
DeltasMessage const serverNp(getNetworkId(), getObjectType(), m_serverPackage_np, DeltasMessage::DELTAS_SERVER_NP);
ServerMessageForwarding::send(serverNp);
}
}
clearDeltas();
if (sendServerDeltas)
ServerMessageForwarding::end();
// sync any real time UI
if (m_synchronizedUi.getPointer())
m_synchronizedUi->sendDeltas();
}
// ----------------------------------------------------------------------
void ServerObject::applyObjectPositionUpdate(UpdateObjectPositionMessage const &source)
{
FATAL(isInitialized(), ("ServerObject::applyObjectPositionUpdate: obj %s, while initialized", getDebugInformation().c_str()));
// catch the situation where we are trying to put the
// (authoritative) object into a proxy container;
// there are bad contained_by/load_with data in the DB
// that can cause this situation
ServerObject * const container = safe_cast<ServerObject *>(NetworkIdManager::getObjectById(source.getContainerId()));
if (container && !container->isAuthoritative() && isAuthoritative())
{
// it's OK if this happens to a character object;
// fix it by moving the character outside of the container
if (source.getPlayerControlled() && !ServerWorld::isSpaceScene())
{
DEBUG_REPORT_LOG(true,("Ejecting player %s from container %s, because the container is not authoritative\n",getNetworkId().getValueString().c_str(), container->getNetworkId().getValueString().c_str()));
LOG("CustomerService",("Login: Ejecting player %s from container %s, because the container is not authoritative",getNetworkId().getValueString().c_str(), container->getNetworkId().getValueString().c_str()));
// attempt to put the character at the ejection point of the building
Object * const topmostObject = ContainerInterface::getTopmostContainer(*container);
if (topmostObject)
{
PortalProperty * const portalProperty = topmostObject->getPortalProperty();
if (portalProperty)
{
Transform destinationTransform(Transform::IF_none);
destinationTransform.multiply(topmostObject->getTransform_o2w(), portalProperty->getEjectionLocationTransform());
setTransform_o2p(destinationTransform);
}
else
{
// put the character at the location of the building
setTransform_o2p(topmostObject->getTransform_o2w());
}
}
else
{
// last resort, just leave him where he is, out
// in the world, which will most likely put him
// near the origin
setTransform_o2p(source.getTransform());
}
getContainedByProperty()->setContainedBy(NetworkId::cms_invalid, false);
ContainerInterface::getSlottedContainmentProperty(*this)->setCurrentArrangement(-1, false);
}
else
{
ServerObject const * const loadWith = safe_cast<ServerObject const *>(NetworkIdManager::getObjectById(source.getLoadWith()));
LOG("CustomerService", ("BadContainerDepersist: Tried to depersist auth object %s (load with %s) into non-auth container %s.", getDebugInformation().c_str(), (loadWith ? loadWith->getDebugInformation().c_str() : source.getLoadWith().getValueString().c_str()) , container->getDebugInformation().c_str()));
unload();
}
return;
}
setTransform_o2p(source.getTransform());
getContainedByProperty()->setContainedBy(source.getContainerId(), false);
ContainerInterface::getSlottedContainmentProperty(*this)->setCurrentArrangement(source.getSlotArrangement(), false);
}
// ----------------------------------------------------------------------
void ServerObject::updateContainment(NetworkId const &containerId, int slotArrangement)
{
FATAL(isAuthoritative(), ("ServerObject::updateContainment: obj %s, container %s, arrangement %d, while auth", getDebugInformation().c_str(), containerId.getValueString().c_str(), slotArrangement));
getContainedByProperty()->setContainedBy(containerId, false);
ContainerInterface::getSlottedContainmentProperty(*this)->setCurrentArrangement(slotArrangement, false);
ContainmentMessageManager::addContainmentMessage(*this);
}
// ----------------------------------------------------------------------
void ServerObject::containerHandleUpdateProxies(ServerObject *oldContainer, ServerObject *newContainer)
{
FATAL(!isAuthoritative(), ("ServerObject::containerHandleUpdateProxies: obj %s, while non-auth", getDebugInformation().c_str()));
// Queue containment update to be sent to local clients - proxy clients will get the update from the change on their server.
ContainmentMessageManager::addContainmentMessage(*this);
// determine old and new topmost containers
ServerObject * const oldTopmost = oldContainer ? NON_NULL(safe_cast<ServerObject *>(ContainerInterface::getTopmostContainer(*oldContainer))) : this;
ServerObject * const newTopmost = newContainer ? NON_NULL(safe_cast<ServerObject *>(ContainerInterface::getTopmostContainer(*newContainer))) : this;
// determine old and new proxy lists
ProxyList const &oldProxyList = oldTopmost->getPrivateProxyList();
ProxyList const &newProxyList = newContainer ? newTopmost->getPrivateProxyList() : oldProxyList;
// send unloads to servers only in old proxy lists
// send baselines to servers only in new proxy lists
// send containment update to servers in both old and new proxy lists
if (oldTopmost == newTopmost)
{
// If we have not changed topmost containers, our proxy list has not changed,
// so send containment updates to everything in our proxy list.
if (!newProxyList.empty())
{
ServerMessageForwarding::begin(std::vector<uint32>(newProxyList.begin(), newProxyList.end()));
UpdateContainmentMessage const ucm(
getNetworkId(),
newContainer ? newContainer->getNetworkId() : NetworkId::cms_invalid,
ContainerInterface::getSlottedContainmentProperty(*this)->getCurrentArrangement());
ServerMessageForwarding::send(ucm);
ServerMessageForwarding::end();
}
}
else
{
std::vector<uint32> addedProxies;
std::vector<uint32> removedProxies;
std::vector<uint32> sustainedProxies;
for (ProxyList::const_iterator i = oldProxyList.begin(); i != oldProxyList.end(); ++i)
{
if (!newProxyList.count(*i))
removedProxies.push_back(*i);
else
sustainedProxies.push_back(*i);
}
for (ProxyList::const_iterator j = newProxyList.begin(); j != newProxyList.end(); ++j)
if (!oldProxyList.count(*j))
addedProxies.push_back(*j);
if (!removedProxies.empty())
{
ServerMessageForwarding::begin(removedProxies);
UnloadObjectMessage const unloadMessage(getNetworkId());
ServerMessageForwarding::send(unloadMessage);
ServerMessageForwarding::end();
}
if (!sustainedProxies.empty())
{
ServerMessageForwarding::begin(sustainedProxies);
UpdateContainmentMessage const ucm(
getNetworkId(),
newContainer ? newContainer->getNetworkId() : NetworkId::cms_invalid,
ContainerInterface::getSlottedContainmentProperty(*this)->getCurrentArrangement());
ServerMessageForwarding::send(ucm);
ServerMessageForwarding::end();
}
if (!addedProxies.empty())
{
ServerMessageForwarding::begin(addedProxies);
forwardServerCreateAndBaselines();
ServerMessageForwarding::end();
}
}
if (newContainer)
m_proxyServerProcessIds.clear();
else
copyProxyList(*oldTopmost);
}
// ----------------------------------------------------------------------
void ServerObject::applyBaselines(BaselinesMessage const &source)
{
applyBaselines(source.getPackageId(), source.getPackage());
}
// ----------------------------------------------------------------------
void ServerObject::applyBaselines(char type, Archive::ByteStream const & package)
{
Archive::ReadIterator ri = package.begin();
switch (type)
{
case BaselinesMessage::BASELINES_CLIENT_SERVER:
m_authClientServerPackage.unpack(ri);
break;
case BaselinesMessage::BASELINES_SERVER:
m_serverPackage.unpack(ri);
break;
case BaselinesMessage::BASELINES_SHARED:
m_sharedPackage.unpack(ri);
break;
case BaselinesMessage::BASELINES_CLIENT_SERVER_NP:
m_authClientServerPackage_np.unpack(ri);
break;
case BaselinesMessage::BASELINES_SERVER_NP:
m_serverPackage_np.unpack(ri);
break;
case BaselinesMessage::BASELINES_SHARED_NP:
m_sharedPackage_np.unpack(ri);
break;
case BaselinesMessage::BASELINES_FIRST_PARENT_CLIENT_SERVER:
m_firstParentAuthClientServerPackage.unpack(ri);
break;
case BaselinesMessage::BASELINES_FIRST_PARENT_CLIENT_SERVER_NP:
m_firstParentAuthClientServerPackage_np.unpack(ri);
break;
case BaselinesMessage::BASELINES_UI:
#ifdef _DEBUG
WARNING_STRICT_FATAL(!m_synchronizedUi, ("Got UI package for %s with no UI object", getNetworkId().getValueString().c_str()));
#endif
if (m_synchronizedUi.getPointer())
m_synchronizedUi->applyBaselines(ri);
break;
default:
FATAL(true, ("ServerObject::applyBaselines on %s with unknown package %d", getDebugInformation().c_str(), static_cast<int>(type)));
break;
}
}
// ----------------------------------------------------------------------
void ServerObject::applyDeltas(DeltasMessage const &source)
{
FATAL(!isInitialized(), ("ServerObject::applyDeltas on unitinialized object %s.", getDebugInformation().c_str()));
WARNING(isAuthoritative(), ("ServerObject::applyDeltas on auth object %s.", getDebugInformation().c_str()));
unsigned char const type = source.getPackageId();
Archive::ReadIterator ri = source.getPackage().begin();
switch (type)
{
case DeltasMessage::DELTAS_CLIENT_SERVER:
m_authClientServerPackage.unpackDeltas(ri);
break;
case DeltasMessage::DELTAS_SERVER:
m_serverPackage.unpackDeltas(ri);
break;
case DeltasMessage::DELTAS_SHARED:
m_sharedPackage.unpackDeltas(ri);
break;
case DeltasMessage::DELTAS_CLIENT_SERVER_NP:
m_authClientServerPackage_np.unpackDeltas(ri);
break;
case DeltasMessage::DELTAS_SERVER_NP:
m_serverPackage_np.unpackDeltas(ri);
break;
case DeltasMessage::DELTAS_SHARED_NP:
m_sharedPackage_np.unpackDeltas(ri);
break;
case DeltasMessage::DELTAS_FIRST_PARENT_CLIENT_SERVER:
m_firstParentAuthClientServerPackage.unpackDeltas(ri);
break;
case DeltasMessage::DELTAS_FIRST_PARENT_CLIENT_SERVER_NP:
m_firstParentAuthClientServerPackage_np.unpackDeltas(ri);
break;
case DeltasMessage::DELTAS_UI:
#ifdef _DEBUG
WARNING_STRICT_FATAL(!m_synchronizedUi, ("Got UI delta package for %s with no UI object", getNetworkId().getValueString().c_str()));
#endif
if (m_synchronizedUi.getPointer())
m_synchronizedUi->applyDeltas(source);
break;
default:
FATAL(true, ("ServerObject::applyDeltas on %s with unknown package %d", getDebugInformation().c_str(), static_cast<int>(type)));
break;
}
}
// ----------------------------------------------------------------------
bool ServerObject::removeFromBaselineDistributionList(Client const &client) const
{
std::vector<Watcher<Client> > *baselineDistributionList = BaselineDistributionListPool::get(*this, false);
if (baselineDistributionList)
{
std::vector<Watcher<Client> >::iterator i = std::find(baselineDistributionList->begin(), baselineDistributionList->end(), &client);
if (i != baselineDistributionList->end())
{
IGNORE_RETURN(baselineDistributionList->erase(i));
return true;
}
}
return false;
}
// ----------------------------------------------------------------------
void ServerObject::sendAuthClientBaselines(Client const &client) const
{
BaselinesMessage const authClientSvrPkg(getNetworkId(), getObjectType(), m_authClientServerPackage, BaselinesMessage::BASELINES_CLIENT_SERVER);
BaselinesMessage const authClientSvrPkgNp(getNetworkId(), getObjectType(), m_authClientServerPackage_np, BaselinesMessage::BASELINES_CLIENT_SERVER_NP);
client.send(authClientSvrPkg, true);
client.send(authClientSvrPkgNp, true);
}
// ----------------------------------------------------------------------
void ServerObject::sendFirstParentBaselines(Client const &client) const
{
BaselinesMessage const firstParentAuthClientSvrPkg(getNetworkId(), getObjectType(), m_firstParentAuthClientServerPackage, BaselinesMessage::BASELINES_FIRST_PARENT_CLIENT_SERVER);
BaselinesMessage const firstParentAuthClientSvrPkgNp(getNetworkId(), getObjectType(), m_firstParentAuthClientServerPackage_np, BaselinesMessage::BASELINES_FIRST_PARENT_CLIENT_SERVER_NP);
client.send(firstParentAuthClientSvrPkg, true);
client.send(firstParentAuthClientSvrPkgNp, true);
}
// ----------------------------------------------------------------------
void ServerObject::flushCreateMessages() const
{
PROFILER_AUTO_BLOCK_DEFINE("ServerObject::flushCreateMessages");
// Validate this object's transform prior to sending baseline messages.
checkAndLogInvalidTransform();
std::map<ConnectionServerConnection *, std::vector<NetworkId> > &tmpDistributionList = DistributionListStack::alloc();
std::vector<Watcher<Client> > * const baselineDistributionList = BaselineDistributionListPool::get(*this, false);
if (baselineDistributionList && !baselineDistributionList->empty())
{
ContainmentMessageManager::addFrameBaselines(getNetworkId(), *baselineDistributionList);
{
PROFILER_AUTO_BLOCK_DEFINE("ServerObject::flushCreateMessages.buildConnectionList");
for (std::vector<Watcher<Client> >::const_iterator i = baselineDistributionList->begin(); i != baselineDistributionList->end(); ++i)
{
// build connection list
Client * const c = *i;
if (c)
{
ConnectionServerConnection * const n = c->getConnection();
if (n)
{
std::vector<NetworkId> &list = tmpDistributionList[n];
list.push_back(c->getCharacterObjectId());
}
}
}
}
{
PROFILER_AUTO_BLOCK_DEFINE("ServerObject::flushCreateMessages.send");
//-- build client object creation messages
GameNetworkMessage *com = 0;
ConstCharCrcString const clientSharedTemplateNameCrcString = ObjectTemplateList::lookUp(getClientSharedTemplateName());
if (clientSharedTemplateNameCrcString.isEmpty())
com = new SceneCreateObjectByName(getNetworkId(), getTransform_o2p(), getClientSharedTemplateName(), getLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnCreate));
else
com = new SceneCreateObjectByCrc(getNetworkId(), getTransform_o2p(), clientSharedTemplateNameCrcString.getCrc(), getLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnCreate));
UpdateContainmentMessage const ucm(
getNetworkId(),
ContainerInterface::getContainedByProperty(*this)->getContainedByNetworkId(),
ContainerInterface::getSlottedContainmentProperty(*this)->getCurrentArrangement());
bool sendContainmentUpdate = (ucm.getContainerId() != NetworkId::cms_invalid || ucm.getSlotArrangement() != -1);
BaselinesMessage const sharedPkg(getNetworkId(), getObjectType(), m_sharedPackage, BaselinesMessage::BASELINES_SHARED);
BaselinesMessage const sharedPkgNp(getNetworkId(), getObjectType(), m_sharedPackage_np, BaselinesMessage::BASELINES_SHARED_NP);
for (std::map<ConnectionServerConnection *, std::vector<NetworkId> >::const_iterator i = tmpDistributionList.begin(); i != tmpDistributionList.end(); ++i)
{
GameClientMessage const msgCom((*i).second, true, *com);
(*i).first->send(msgCom, true);
logBaselines(getNetworkId(), com->getCmdName().c_str(), (*i).second);
// send containment updates
if (sendContainmentUpdate)
{
GameClientMessage const msgUpdateContainment((*i).second, true, ucm);
(*i).first->send(msgUpdateContainment, true);
}
// send shared data baselines
GameClientMessage const msgSharedPkg((*i).second, true, sharedPkg);
(*i).first->send(msgSharedPkg, true);
GameClientMessage const msgSharedPkgNp((*i).second, true, sharedPkgNp);
(*i).first->send(msgSharedPkgNp, true);
}
delete com;
}
// send auth client data
{
static std::set<Client const *> authClients;
getAuthClients(authClients);
for (std::set<Client const *>::const_iterator i = authClients.begin(); i != authClients.end(); ++i)
if ((*i) && std::find(baselineDistributionList->begin(), baselineDistributionList->end(), (*i)) != baselineDistributionList->end())
sendAuthClientBaselines(**i);
authClients.clear();
Client const * const parentPlayerClient = getParentPlayerClient(this);
if (parentPlayerClient && std::find(baselineDistributionList->begin(), baselineDistributionList->end(), parentPlayerClient) != baselineDistributionList->end())
sendFirstParentBaselines(*parentPlayerClient);
}
}
// Flush create messages for contents
Container const * const container = ContainerInterface::getContainer(*this);
if (container)
{
PROFILER_AUTO_BLOCK_DEFINE("ServerObject::flushCreateMessages.flushContents");
for (ContainerConstIterator i = container->begin(); i != container->end(); ++i)
{
ServerObject const * const containedObject = safe_cast<ServerObject const *>((*i).getObject());
if (containedObject)
containedObject->flushCreateMessages();
}
}
if (baselineDistributionList && !baselineDistributionList->empty())
{
{
PROFILER_AUTO_BLOCK_DEFINE("ServerObject::flushCreateMessages.sendObjectSpecificBaselinesToClient");
for (std::vector<Watcher<Client> >::const_iterator i = baselineDistributionList->begin(); i != baselineDistributionList->end(); ++i)
if ((*i).getPointer())
sendObjectSpecificBaselinesToClient(**i);
}
{
PROFILER_AUTO_BLOCK_DEFINE("ServerObject::flushCreateMessages.sendEndBaselines");
SceneEndBaselines const ebm(getNetworkId());
for (std::map<ConnectionServerConnection *, std::vector<NetworkId> >::const_iterator i = tmpDistributionList.begin(); i != tmpDistributionList.end(); ++i)
{
GameClientMessage const msgEbm((*i).second, true, ebm);
(*i).first->send(msgEbm, true);
logBaselines(getNetworkId(), "SceneEndBaselines", (*i).second);
}
}
baselineDistributionList->clear();
}
if (baselineDistributionList)
BaselineDistributionListPool::free(*this);
DistributionListStack::release();
}
// ----------------------------------------------------------------------
void ServerObject::clearDeltas() const
{
m_authClientServerPackage.clearDeltas();
m_authClientServerPackage_np.clearDeltas();
m_firstParentAuthClientServerPackage.clearDeltas();
m_firstParentAuthClientServerPackage_np.clearDeltas();
m_serverPackage.clearDeltas();
m_serverPackage_np.clearDeltas();
m_sharedPackage.clearDeltas();
m_sharedPackage_np.clearDeltas();
}
// ----------------------------------------------------------------------
void ServerObject::addServerToProxyList(uint32 proxyServerProcessId)
{
FATAL(!isAuthoritative(), ("ServerObject::addServerToProxyList: obj %s, processId %lu, while non-auth", getDebugInformation().c_str(), proxyServerProcessId));
if (isProxiedOnServer(proxyServerProcessId))
return;
m_proxyServerProcessIds.insert(proxyServerProcessId);
if (ContainerInterface::getTopmostContainer(*this) == this)
{
ServerMessageForwarding::begin(proxyServerProcessId);
forwardServerCreateAndBaselines();
ServerMessageForwarding::end();
}
}
// ----------------------------------------------------------------------
void ServerObject::removeServerFromProxyList(uint32 proxyServerProcessId)
{
if (!isProxiedOnServer(proxyServerProcessId))
return;
if (getAuthServerProcessId() != proxyServerProcessId)
{
FATAL(!isAuthoritative(), ("ServerObject::removeServerFromProxyList: obj %s, processId %lu, while non-auth", getDebugInformation().c_str(), proxyServerProcessId));
ServerMessageForwarding::begin(proxyServerProcessId);
UnloadObjectMessage const unloadMessage(getNetworkId());
ServerMessageForwarding::send(unloadMessage);
ServerMessageForwarding::end();
}
m_proxyServerProcessIds.erase(proxyServerProcessId);
}
// ----------------------------------------------------------------------
void ServerObject::clearProxyList()
{
if (!m_proxyServerProcessIds.empty())
{
ProxyList const proxyList = m_proxyServerProcessIds.get();
for (ProxyList::const_iterator i = proxyList.begin(); i != proxyList.end(); ++i)
removeServerFromProxyList(*i);
}
}
// ----------------------------------------------------------------------
void ServerObject::copyProxyList(ServerObject const &source)
{
m_proxyServerProcessIds.clear();
ProxyList const &sourceList = source.getPrivateProxyList();
for (ProxyList::const_iterator i = sourceList.begin(); i != sourceList.end(); ++i)
m_proxyServerProcessIds.insert(*i);
}
// ----------------------------------------------------------------------
size_t ServerObject::getProxyCount() const
{
return m_proxyServerProcessIds.get().size();
}
// ----------------------------------------------------------------------
uint32 ServerObject::getAuthServerProcessId() const
{
return m_authServerProcessId.get();
}
// ----------------------------------------------------------------------
void ServerObject::setAuthServerProcessId(uint32 processId)
{
if (processId)
{
m_authServerProcessId = processId;
removeServerFromProxyList(processId);
Container * const container = ContainerInterface::getContainer(*this);
if (container)
{
for (ContainerIterator containerIterator = container->begin(); containerIterator != container->end(); ++containerIterator)
{
ServerObject * const containedObject = safe_cast<ServerObject *>((*containerIterator).getObject());
if (containedObject)
containedObject->setAuthServerProcessId(processId);
}
}
}
}
// ----------------------------------------------------------------------
ProxyList const &ServerObject::getExposedProxyList() const
{
ServerObject const * const topmost = NON_NULL(safe_cast<ServerObject const *>(ContainerInterface::getTopmostContainer(*this)));
return topmost->getPrivateProxyList();
}
// ----------------------------------------------------------------------
bool ServerObject::isProxiedOnServer(uint32 processId) const
{
return m_proxyServerProcessIds.contains(processId);
}
// ======================================================================