// ====================================================================== // // 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(ContainerInterface::getContainedByObject(*o)); return o ? o->getClient() : 0; } // ---------------------------------------------------------------------- void logBaselines(NetworkId const &senderId, char const *messageType, std::vector const & clients) { if (!ConfigServerGame::getLogBaselines()) return; for (std::vector::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(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(proxyList.begin(), proxyList.end())); forwardServerCreateAndBaselines(); ServerMessageForwarding::end(); } } } // ---------------------------------------------------------------------- void ServerObject::synchronizationOnUnload() const { if (isAuthoritative()) { ProxyList const &proxyList = getExposedProxyList(); if (!proxyList.empty()) { ServerMessageForwarding::begin(std::vector(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 > *baselineDistributionList = BaselineDistributionListPool::get(*this, true); if (baselineDistributionList->empty()) ServerObjectBaselinesManager::add(*this); baselineDistributionList->push_back(Watcher(&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((*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 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((*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((*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(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 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::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::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(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(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(ContainerInterface::getTopmostContainer(*oldContainer))) : this; ServerObject * const newTopmost = newContainer ? NON_NULL(safe_cast(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(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 addedProxies; std::vector removedProxies; std::vector 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(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(type))); break; } } // ---------------------------------------------------------------------- bool ServerObject::removeFromBaselineDistributionList(Client const &client) const { std::vector > *baselineDistributionList = BaselineDistributionListPool::get(*this, false); if (baselineDistributionList) { std::vector >::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 > &tmpDistributionList = DistributionListStack::alloc(); std::vector > * const baselineDistributionList = BaselineDistributionListPool::get(*this, false); if (baselineDistributionList && !baselineDistributionList->empty()) { ContainmentMessageManager::addFrameBaselines(getNetworkId(), *baselineDistributionList); { PROFILER_AUTO_BLOCK_DEFINE("ServerObject::flushCreateMessages.buildConnectionList"); for (std::vector >::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 &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 >::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 authClients; getAuthClients(authClients); for (std::set::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((*i).getObject()); if (containedObject) containedObject->flushCreateMessages(); } } if (baselineDistributionList && !baselineDistributionList->empty()) { { PROFILER_AUTO_BLOCK_DEFINE("ServerObject::flushCreateMessages.sendObjectSpecificBaselinesToClient"); for (std::vector >::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 >::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((*containerIterator).getObject()); if (containedObject) containedObject->setAuthServerProcessId(processId); } } } } // ---------------------------------------------------------------------- ProxyList const &ServerObject::getExposedProxyList() const { ServerObject const * const topmost = NON_NULL(safe_cast(ContainerInterface::getTopmostContainer(*this))); return topmost->getPrivateProxyList(); } // ---------------------------------------------------------------------- bool ServerObject::isProxiedOnServer(uint32 processId) const { return m_proxyServerProcessIds.contains(processId); } // ======================================================================