Added PlanetServer project

This commit is contained in:
Anonymous
2014-01-17 06:50:59 -07:00
parent 7759ffd3c0
commit 63ccf4eb43
35 changed files with 6618 additions and 0 deletions
+1
View File
@@ -4,4 +4,5 @@ add_subdirectory(ChatServer)
add_subdirectory(ConnectionServer)
add_subdirectory(LoginServer)
add_subdirectory(LogServer)
add_subdirectory(PlanetServer)
add_subdirectory(TaskManager)
@@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 2.8)
project(PlanetServer)
add_subdirectory(src)
@@ -0,0 +1,114 @@
set(SHARED_SOURCES
shared/CentralServerConnection.cpp
shared/CentralServerConnection.h
shared/ConfigPlanetServer.cpp
shared/ConfigPlanetServer.h
shared/ConsoleManager.cpp
shared/ConsoleManager.h
shared/ConsoleCommandParser.cpp
shared/ConsoleCommandParser.h
shared/FirstPlanetServer.h
shared/GameServerConnection.cpp
shared/GameServerConnection.h
shared/GameServerData.cpp
shared/GameServerData.h
shared/PlanetProxyObject.cpp
shared/PlanetProxyObject.h
shared/PlanetServer.cpp
shared/PlanetServer.h
shared/PlanetServerMetricsData.cpp
shared/PlanetServerMetricsData.h
shared/PreloadManager.cpp
shared/PreloadManager.h
shared/QuadtreeNode.cpp
shared/QuadtreeNode.h
shared/Scene.cpp
shared/Scene.h
shared/TaskConnection.cpp
shared/TaskConnection.h
shared/WatcherConnection.cpp
shared/WatcherConnection.h
)
if(WIN32)
set(PLATFORM_SOURCES
win32/FirstPlanetServer.cpp
win32/WinMain.cpp
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/win32)
else()
set(PLATFORM_SOURCES
linux/main.cpp
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/linux)
endif()
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/shared
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedCommandParser/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedCompression/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDebug/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFile/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedLog/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMath/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMathArchive/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMessageDispatch/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetwork/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetworkMessages/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedRandom/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedThread/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedUtility/include/public
${SWG_ENGINE_SOURCE_DIR}/server/library/serverMetrics/include/public
${SWG_ENGINE_SOURCE_DIR}/server/library/serverNetworkMessages/include/public
${SWG_ENGINE_SOURCE_DIR}/server/library/serverUtility/include/public
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/archive/include
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/singleton/include
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicode/include
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicodeArchive/include/public
)
link_directories(${STLPORT_LIBDIR})
add_executable(PlanetServer
${SHARED_SOURCES}
${PLATFORM_SOURCES}
)
target_link_libraries(PlanetServer
sharedCommandParser
sharedCompression
sharedDebug
sharedFile
sharedFoundation
sharedLog
sharedMath
sharedMemoryManager
sharedMessageDispatch
sharedNetwork
sharedNetworkMessages
sharedRandom
sharedSynchronization
sharedThread
sharedUtility
serverMetrics
serverNetworkMessages
serverUtility
archive
fileInterface
localization
localizationArchive
unicode
unicodeArchive
udplibrary
${ZLIB_LIBRARY}
)
if(WIN32)
target_link_libraries(PlanetServer mswsock ws2_32)
endif()
@@ -0,0 +1,70 @@
#include "FirstPlanetServer.h"
#include "ConfigPlanetServer.h"
#include "PlanetServer.h"
#include "sharedCompression/SetupSharedCompression.h"
#include "sharedDebug/SetupSharedDebug.h"
#include "sharedFile/SetupSharedFile.h"
#include "sharedFoundation/Os.h"
#include "sharedFoundation/SetupSharedFoundation.h"
#include "sharedLog/SetupSharedLog.h"
#include "sharedNetwork/SetupSharedNetwork.h"
#include "sharedNetworkMessages/SetupSharedNetworkMessages.h"
#include "sharedRandom/SetupSharedRandom.h"
#include "sharedThread/SetupSharedThread.h"
#include "sharedUtility/SetupSharedUtility.h"
// ======================================================================
void dumpPid(const char * argv)
{
pid_t p = getpid();
char fileName[1024];
sprintf(fileName, "%s.%d", argv, p);
FILE * f = fopen(fileName, "w+");
fclose(f); //lint !e668
}
int main(int argc, char ** argv)
{
// dumpPid(argv[0]);
SetupSharedThread::install();
SetupSharedDebug::install(1024);
//-- setup foundation
SetupSharedFoundation::Data setupFoundationData(SetupSharedFoundation::Data::D_game);
setupFoundationData.lpCmdLine = ConvertCommandLine(argc,argv);
SetupSharedFoundation::install (setupFoundationData);
SetupSharedCompression::install();
SetupSharedFile::install(false);
SetupSharedNetwork::SetupData networkSetupData;
SetupSharedNetwork::getDefaultServerSetupData(networkSetupData);
SetupSharedNetwork::install(networkSetupData);
SetupSharedNetworkMessages::install();
SetupSharedRandom::install(time(NULL)); //lint !e732 loss of sign (of 0!)
SetupSharedUtility::Data sharedUtilityData;
SetupSharedUtility::setupGameData (sharedUtilityData);
SetupSharedUtility::install (sharedUtilityData);
Os::setProgramName("PlanetServer");
ConfigPlanetServer::install();
char tmp[92];
sprintf(tmp, "PlanetServer:%d", Os::getProcessId());
SetupSharedLog::install(tmp);
//-- run game
PlanetServer::run();
SetupSharedLog::remove();
SetupSharedFoundation::remove();
SetupSharedThread::remove();
return 0;
}
@@ -0,0 +1,80 @@
// ======================================================================
//
// CentralServerConnection.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "FirstPlanetServer.h"
#include "CentralServerConnection.h"
#include "ConsoleManager.h"
#include "serverNetworkMessages/CentralPlanetServerConnect.h"
#include "sharedFoundation/NetworkId.h"
#include "sharedNetworkMessages/ConsoleChannelMessages.h"
#include "sharedNetwork/NetworkSetupData.h"
#include "sharedNetwork/Service.h"
#include "ConfigPlanetServer.h"
#include "PlanetServer.h"
//-----------------------------------------------------------------------
CentralServerConnection::CentralServerConnection(const std::string & a, const unsigned short p) :
ServerConnection(a, p, NetworkSetupData())
{
}
//-----------------------------------------------------------------------
CentralServerConnection::~CentralServerConnection()
{
}
//-----------------------------------------------------------------------
void CentralServerConnection::onConnectionClosed()
{
ServerConnection::onConnectionClosed();
static MessageConnectionCallback m("CentralConnectionClosed");
emitMessage(m);
}
//-----------------------------------------------------------------------
void CentralServerConnection::onConnectionOpened()
{
ServerConnection::onConnectionOpened();
DEBUG_REPORT_LOG(true,("Connection to Central opened.\n"));
CentralPlanetServerConnect msg(ConfigPlanetServer::getSceneID(), PlanetServer::getInstance().getGameService()->getBindAddress(), PlanetServer::getInstance().getGameServicePort());
send(msg,true);
PlanetServer::getInstance().onCentralConnected(this);
static MessageConnectionCallback m("CentralConnectionOpened");
emitMessage(m);
}
//-----------------------------------------------------------------------
void CentralServerConnection::onReceive(const Archive::ByteStream & message)
{
Archive::ReadIterator ri = message.begin();
const GameNetworkMessage msg(ri);
ri = message.begin();
if(msg.isType("ConGenericMessage"))
{
const ConGenericMessage cm(ri);
std::string result;
ConsoleManager::processString(cm.getMsg(), cm.getMsgId(), result);
const ConGenericMessage response(result, cm.getMsgId());
send(response, true);
}
ServerConnection::onReceive(message);
}
//-----------------------------------------------------------------------
@@ -0,0 +1,35 @@
// ======================================================================
//
// CentralServerConnection.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_CentralServerConnection_H
#define INCLUDED_CentralServerConnection_H
// ======================================================================
#include "serverUtility/ServerConnection.h"
// ======================================================================
class CentralServerConnection : public ServerConnection
{
public:
CentralServerConnection (const std::string & remoteAddress, const unsigned short port);
~CentralServerConnection ();
void onConnectionClosed ();
void onConnectionOpened ();
const std::string & getClusterName () const;
virtual void onReceive (const Archive::ByteStream & message);
private:
CentralServerConnection (const CentralServerConnection&);
CentralServerConnection& operator= (const CentralServerConnection&);
CentralServerConnection();
};
// ======================================================================
#endif
@@ -0,0 +1,97 @@
// ======================================================================
//
// ConfigPlanetServer.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "FirstPlanetServer.h"
#include "ConfigPlanetServer.h"
#include "QuadtreeNode.h"
#include "serverUtility/ConfigServerUtility.h"
#include "sharedFoundation/ConfigFile.h"
#include "sharedFoundation/ExitChain.h"
//-----------------------------------------------------------------------
ConfigPlanetServer::Data * ConfigPlanetServer::data = 0;
#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("PlanetServer", #a, b))
#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("PlanetServer", #a, b))
//#define KEY_FLOAT(a,b) (data->a = ConfigFile::getKeyFloat("PlanetServer", #a, b)) // commented out for Lint. Uncomment if you need this macro again
#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("PlanetServer", #a, b))
// ======================================================================
void ConfigPlanetServer::install(void)
{
ConfigServerUtility::install();
ExitChain::add(&remove, "ConfigPlanetServer::remove");
data = new ConfigPlanetServer::Data;
KEY_STRING (centralServerAddress, "swo-dev1.station.sony.com");
KEY_INT (centralServerPort, 44455);
KEY_STRING (sceneID, "default");
KEY_INT (gameServicePort, 0);
KEY_INT (taskManagerPort, 60001);
KEY_INT (watcherServicePort, 60002);
KEY_INT (maxWatcherConnections, 1);
KEY_INT (watcherOverflowLimit, 1024 * 1024 * 8); // 8MB overflow for CS PlanetWatcher tool
KEY_BOOL (logObjectLoading, false);
KEY_INT (maxWatcherUpdatesPerMessage,500); // Max object updates to send to the watcher in a single message
KEY_STRING (gameServiceBindInterface, "");
KEY_STRING (watcherServiceBindInterface, "");
KEY_BOOL (loadWholePlanet, false);
KEY_BOOL (loadWholePlanetMultiserver, false);
KEY_BOOL (logPreloading, false);
KEY_INT (numTutorialServers, 1);
KEY_INT (maxInterestRadius, Node::getNodeSize());
KEY_INT (populationCountTime, 60); // seconds
KEY_BOOL (logChunkLoading, false);
KEY_INT (preloadBailoutTime, 0); // seconds
KEY_STRING (preloadDataTableName, "datatables/planet_server/preload_list.iff");
KEY_INT (authTransferSanityCheckTimeMs, 15000);
KEY_INT (gameServerRestartDelayTimeSeconds, 60);
KEY_BOOL (enableContentsChecking, false);
KEY_INT (maxGameServers, 0);
KEY_BOOL (enableStartupCreateProxies, true);
KEY_BOOL (requestDbSaveOnGameServerCrash, true);
KEY_BOOL (gameServerProfiling, false);
KEY_BOOL (gameServerDebugging, false);
KEY_INT (gameServerDebuggingPortBase, 0);
KEY_INT (maxTimeToWaitForGameServerStartSeconds, 5*60); // seconds
}
//-----------------------------------------------------------------------
bool ConfigPlanetServer::getGameServerProfiling()
{
return data->gameServerProfiling;
}
//-----------------------------------------------------------------------
bool ConfigPlanetServer::getGameServerDebugging()
{
return data->gameServerDebugging;
}
//-----------------------------------------------------------------------
void ConfigPlanetServer::remove(void)
{
delete data;
data = 0;
ConfigServerUtility::remove();
}
//-----------------------------------------------------------------------
int ConfigPlanetServer::getGameServerDebuggingPortBase()
{
return data->gameServerDebuggingPortBase;
}
//-----------------------------------------------------------------------
@@ -0,0 +1,287 @@
// ======================================================================
//
// ConfigPlanetServer.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_ConfigPlanetServer_H
#define INCLUDED_ConfigPlanetServer_H
// ======================================================================
class ConfigPlanetServer
{
public:
struct Data
{
const char * centralServerAddress;
int centralServerPort;
const char * sceneID;
int gameServicePort;
int watcherServicePort;
int taskManagerPort;
int maxWatcherConnections;
int watcherOverflowLimit;
bool logObjectLoading;
int maxWatcherUpdatesPerMessage;
const char * gameServiceBindInterface;
const char * watcherServiceBindInterface;
bool loadWholePlanet;
bool loadWholePlanetMultiserver;
bool logPreloading;
int numTutorialServers;
int maxInterestRadius;
int populationCountTime;
bool logChunkLoading;
int preloadBailoutTime;
const char * preloadDataTableName;
int authTransferSanityCheckTimeMs;
int gameServerRestartDelayTimeSeconds;
bool enableContentsChecking;
int maxGameServers;
bool enableStartupCreateProxies;
bool requestDbSaveOnGameServerCrash;
bool gameServerDebugging;
bool gameServerProfiling;
int gameServerDebuggingPortBase;
int maxTimeToWaitForGameServerStartSeconds;
};
static void install ();
static void remove ();
static const char * getCentralServerAddress ();
static const uint16 getCentralServerPort ();
static const char * getSceneID ();
static const uint16 getGameServicePort ();
static const uint16 getWatcherServicePort ();
static const uint16 getTaskManagerPort ();
static const int getMaxWatcherConnections();
static const int getWatcherOverflowLimit ();
static const bool getLogObjectLoading ();
static const int getMaxWatcherUpdatesPerMessage();
static const char * getGameServiceBindInterface();
static const char * getWatcherServiceBindInterface();
static const bool getLoadWholePlanet();
static const bool getLoadWholePlanetMultiserver();
static const bool getLogPreloading();
static const int getNumTutorialServers();
static const int getMaxInterestRadius();
static const int getPopulationCountTime();
static const bool getLogChunkLoading();
static const int getPreloadBailoutTime();
static const char * getPreloadDataTableName();
static const int getAuthTransferSanityCheckTimeMs();
static const unsigned int getGameServerRestartDelayTimeSeconds();
static bool getEnableContentsChecking();
static int getMaxGameServers();
static bool getEnableStartupCreateProxies();
static bool getRequestDbSaveOnGameServerCrash();
static bool getGameServerDebugging();
static bool getGameServerProfiling();
static int getGameServerDebuggingPortBase();
static int getMaxTimeToWaitForGameServerStartSeconds();
private:
static Data * data;
};
// ======================================================================
inline const char * ConfigPlanetServer::getCentralServerAddress()
{
return data->centralServerAddress;
}
//-----------------------------------------------------------------------
inline const uint16 ConfigPlanetServer::getCentralServerPort()
{
return static_cast<const uint16>(data->centralServerPort);
}
//-----------------------------------------------------------------------
inline const char * ConfigPlanetServer::getSceneID()
{
return data->sceneID;
}
//-----------------------------------------------------------------------
inline const uint16 ConfigPlanetServer::getGameServicePort()
{
return static_cast<uint16>(data->gameServicePort);
}
//-----------------------------------------------------------------------
inline const uint16 ConfigPlanetServer::getTaskManagerPort()
{
return static_cast<uint16>(data->taskManagerPort);
}
// ----------------------------------------------------------------------
inline const uint16 ConfigPlanetServer::getWatcherServicePort()
{
return static_cast<uint16>(data->watcherServicePort);
}
// ----------------------------------------------------------------------
inline const int ConfigPlanetServer::getMaxWatcherConnections()
{
return data->maxWatcherConnections;
}
//-----------------------------------------------------------------------
inline const int ConfigPlanetServer::getWatcherOverflowLimit()
{
return data->watcherOverflowLimit;
}
// ----------------------------------------------------------------------
inline const bool ConfigPlanetServer::getLogObjectLoading()
{
return data->logObjectLoading;
}
// ----------------------------------------------------------------------
inline const int ConfigPlanetServer::getMaxWatcherUpdatesPerMessage()
{
return data->maxWatcherUpdatesPerMessage;
}
// ----------------------------------------------------------------------
inline const char * ConfigPlanetServer::getGameServiceBindInterface()
{
return data->gameServiceBindInterface;
}
// ----------------------------------------------------------------------
inline const char * ConfigPlanetServer::getWatcherServiceBindInterface()
{
return data->watcherServiceBindInterface;
}
// ----------------------------------------------------------------------
inline const bool ConfigPlanetServer::getLoadWholePlanet()
{
return data->loadWholePlanet;
}
// ----------------------------------------------------------------------
inline const bool ConfigPlanetServer::getLoadWholePlanetMultiserver()
{
return data->loadWholePlanetMultiserver;
}
// ----------------------------------------------------------------------
inline const bool ConfigPlanetServer::getLogPreloading()
{
return data->logPreloading;
}
// ----------------------------------------------------------------------
inline const int ConfigPlanetServer::getNumTutorialServers()
{
return data->numTutorialServers;
}
// ----------------------------------------------------------------------
inline const int ConfigPlanetServer::getMaxInterestRadius()
{
return data->maxInterestRadius;
}
// ----------------------------------------------------------------------
inline const int ConfigPlanetServer::getPopulationCountTime()
{
return data->populationCountTime;
}
// ----------------------------------------------------------------------
inline const bool ConfigPlanetServer::getLogChunkLoading()
{
return data->logChunkLoading;
}
// ----------------------------------------------------------------------
inline const int ConfigPlanetServer::getPreloadBailoutTime()
{
return data->preloadBailoutTime;
}
// ----------------------------------------------------------------------
inline const char * ConfigPlanetServer::getPreloadDataTableName()
{
return data->preloadDataTableName;
}
// ----------------------------------------------------------------------
inline const int ConfigPlanetServer::getAuthTransferSanityCheckTimeMs()
{
return data->authTransferSanityCheckTimeMs;
}
// ----------------------------------------------------------------------
inline const unsigned int ConfigPlanetServer::getGameServerRestartDelayTimeSeconds()
{
return static_cast<unsigned int>(data->gameServerRestartDelayTimeSeconds);
}
// ----------------------------------------------------------------------
inline bool ConfigPlanetServer::getEnableContentsChecking()
{
return data->enableContentsChecking;
}
// ----------------------------------------------------------------------
inline int ConfigPlanetServer::getMaxGameServers()
{
return data->maxGameServers;
}
// ----------------------------------------------------------------------
inline bool ConfigPlanetServer::getEnableStartupCreateProxies()
{
return data->enableStartupCreateProxies;
}
// ----------------------------------------------------------------------
inline bool ConfigPlanetServer::getRequestDbSaveOnGameServerCrash()
{
return data->requestDbSaveOnGameServerCrash;
}
// ----------------------------------------------------------------------
inline int ConfigPlanetServer::getMaxTimeToWaitForGameServerStartSeconds()
{
return data->maxTimeToWaitForGameServerStartSeconds;
}
// ======================================================================
#endif
@@ -0,0 +1,66 @@
// ConsoleCommandParser.cpp
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
// Author: Justin Randall
//-----------------------------------------------------------------------
#include "FirstPlanetServer.h"
#include "sharedFoundation/NetworkId.h"
#include "sharedLog/Log.h"
#include "ConsoleCommandParser.h"
#include "UnicodeUtils.h"
#include <vector>
#include "Unicode.h"
#pragma warning(disable:4355) // Passing "this" as a parameter to the base class constructor
//-----------------------------------------------------------------------
namespace CommandNames
{
#define MAKE_COMMAND(a) const char * const a = #a
#undef MAKE_COMMAND
}
const CommandParser::CmdInfo cmds[] =
{
{"planet", 0, "", ""},
{"", 0, "", ""} // this must be last
};
//-----------------------------------------------------------------------
ConsoleCommandParser::ConsoleCommandParser() :
CommandParser ("", 0, "...", "console commands", NULL)
{
createDelegateCommands(cmds);
}
//-----------------------------------------------------------------------
ConsoleCommandParser::~ConsoleCommandParser()
{
}
//-----------------------------------------------------------------------
bool ConsoleCommandParser::performParsing(const NetworkId & /* track */, const StringVector_t & argv, const String_t &, String_t & result, const CommandParser *)
{
bool successResult = false;
if(isCommand(argv[0], "planet"))
{
if(argv.size() > 2)
{
if(isCommand(argv[2], "runState"))
{
successResult = true;
result += Unicode::narrowToWide("running");
}
}
}
return successResult;
}
//-----------------------------------------------------------------------
@@ -0,0 +1,29 @@
// ConsoleCommandParser.h
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
// Author: Justin Randall
#ifndef _INCLUDED_ConsoleCommandParser_H
#define _INCLUDED_ConsoleCommandParser_H
//-----------------------------------------------------------------------
#include "sharedCommandParser/CommandParser.h"
//-----------------------------------------------------------------------
class ConsoleCommandParser : public CommandParser
{
public:
ConsoleCommandParser();
~ConsoleCommandParser();
virtual bool performParsing(const NetworkId & userId, const StringVector_t & argv,const String_t & originalCommand,String_t & result,const CommandParser * node);
private:
ConsoleCommandParser & operator = (const ConsoleCommandParser & rhs);
ConsoleCommandParser(const ConsoleCommandParser & source);
};
//-----------------------------------------------------------------------
#endif // _INCLUDED_ConsoleCommandParser_H
@@ -0,0 +1,58 @@
// ConsoleManager.cpp
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
// Author: Justin Randall
//-----------------------------------------------------------------------
#include "FirstPlanetServer.h"
#include "sharedFoundation/NetworkId.h"
#include "ConsoleManager.h"
#include "ConsoleCommandParser.h"
#include "UnicodeUtils.h"
//-----------------------------------------------------------------------
namespace ConsoleManagerNamespace
{
ConsoleCommandParser * s_consoleCommandParserRoot = NULL;
}
using namespace ConsoleManagerNamespace;
//-----------------------------------------------------------------------
ConsoleManager::ConsoleManager()
{
}
//-----------------------------------------------------------------------
ConsoleManager::~ConsoleManager()
{
}
//-----------------------------------------------------------------------
void ConsoleManager::install()
{
s_consoleCommandParserRoot = new ConsoleCommandParser;
}
//-----------------------------------------------------------------------
void ConsoleManager::remove()
{
delete s_consoleCommandParserRoot;
}
//-----------------------------------------------------------------------
void ConsoleManager::processString(const std::string & msg, int const track, std::string & result)
{
Unicode::String wideResult;
IGNORE_RETURN(s_consoleCommandParserRoot->parse(NetworkId(static_cast<NetworkId::NetworkIdType>(track)), Unicode::narrowToWide(msg), wideResult));
result = Unicode::wideToNarrow(wideResult);
}
//-----------------------------------------------------------------------
@@ -0,0 +1,29 @@
// ConsoleManager.h
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
// Author: Justin Randall
#ifndef _INCLUDED_ConsoleManager_H
#define _INCLUDED_ConsoleManager_H
#include "sharedFoundation/NetworkId.h"
#include <string>
//-----------------------------------------------------------------------
class ConsoleManager
{
public:
static void install();
static void remove();
static void processString(const std::string & msg, int track, std::string & result);
private:
ConsoleManager & operator = (const ConsoleManager & rhs);
ConsoleManager(const ConsoleManager & source);
ConsoleManager();
~ConsoleManager();
};
//-----------------------------------------------------------------------
#endif // _INCLUDED_ConsoleManager_H
@@ -0,0 +1,24 @@
// ======================================================================
//
// FirstPlanetServer.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_FirstPlanetServer_H
#define INCLUDED_FirstPlanetServer_H
// ======================================================================
#include "sharedFoundation/FirstSharedFoundation.h"
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedMemoryManager/FirstSharedMemoryManager.h"
#include "sharedFoundation/NetworkIdArchive.h"
#include "PlanetServer.h"
#include "sharedNetworkMessages/GameNetworkMessage.h"
// ======================================================================
#endif
@@ -0,0 +1,177 @@
// ======================================================================
//
// GameServerConnection.cpp
//
// Copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "FirstPlanetServer.h"
#include "GameServerConnection.h"
#include "ConfigPlanetServer.h"
#include "PlanetProxyObject.h"
#include "Scene.h"
#include "sharedLog/Log.h"
#include "sharedNetworkMessages/GenericValueTypeMessage.h"
// ======================================================================
GameServerConnection::GameServerConnection(UdpConnectionMT *u, TcpClient *t) :
ServerConnection(u, t),
m_preloadNumber(0),
m_forwardCounts(),
m_forwardDestinationServers(),
m_forwardMessages()
{
}
// ----------------------------------------------------------------------
GameServerConnection::~GameServerConnection()
{
}
// ----------------------------------------------------------------------
void GameServerConnection::onConnectionClosed()
{
ServerConnection::onConnectionClosed();
static MessageConnectionCallback m("GameConnectionClosed");
emitMessage(m);
}
// ----------------------------------------------------------------------
void GameServerConnection::onConnectionOpened()
{
ServerConnection::onConnectionOpened();
LOG("PlanetServerConnections", ("%s got a connection from a GameServer", ConfigPlanetServer::getSceneID()));
static MessageConnectionCallback m("GameConnectionOpened");
emitMessage(m);
}
// ----------------------------------------------------------------------
void GameServerConnection::onReceive(Archive::ByteStream const &message)
{
Archive::ReadIterator ri = message.begin();
GameNetworkMessage msg(ri);
ri = message.begin();
if (!m_forwardDestinationServers.empty())
{
if (isMessageForwardable(msg.getType()))
{
m_forwardMessages.push_back(std::make_pair(message, m_forwardDestinationServers.back()));
return;
}
else if (msg.isType("EndForward"))
{
if (--m_forwardCounts.back() == 0)
{
m_forwardCounts.pop_back();
m_forwardDestinationServers.pop_back();
if (m_forwardDestinationServers.empty())
pushAndClearObjectForwarding();
}
return;
}
else if (msg.isType("BeginForward"))
{
GenericValueTypeMessage<std::vector<uint32> > const beginForwardMessage(ri);
if (beginForwardMessage.getValue() == m_forwardDestinationServers.back())
++m_forwardCounts.back();
else
{
m_forwardCounts.push_back(1);
m_forwardDestinationServers.push_back(beginForwardMessage.getValue());
}
return;
}
}
if (msg.isType("BeginForward"))
{
GenericValueTypeMessage<std::vector<uint32> > const beginForwardMessage(ri);
m_forwardCounts.push_back(1);
m_forwardDestinationServers.push_back(beginForwardMessage.getValue());
return;
}
ServerConnection::onReceive(message);
}
// ----------------------------------------------------------------------
void GameServerConnection::pushAndClearObjectForwarding()
{
GameNetworkMessage const endForwardMessage("EndForward");
std::vector<std::pair<Archive::ByteStream, std::vector<uint32> > > centralForwardMessages;
{
for (std::vector<std::pair<Archive::ByteStream, std::vector<uint32> > >::const_iterator i = m_forwardMessages.begin(); i != m_forwardMessages.end(); ++i)
{
Archive::ByteStream const &msg = (*i).first;
std::vector<uint32> const &destinationServers = (*i).second;
std::vector<uint32> centralForwardPids;
for (std::vector<uint32>::const_iterator j = destinationServers.begin(); j != destinationServers.end(); ++j)
{
GameServerConnection * const conn = PlanetServer::getInstance().getGameServerConnection(*j);
if (conn)
conn->Connection::send(msg, true);
else
centralForwardPids.push_back(*j);
}
if (!centralForwardPids.empty())
centralForwardMessages.push_back(std::make_pair(msg, centralForwardPids));
}
}
if (!centralForwardMessages.empty())
{
ServerConnection * const conn = PlanetServer::getInstance().getCentralServerConnection();
if (conn)
{
std::vector<uint32> const *lastDestinationServers = &(*centralForwardMessages.begin()).second;
bool subBlock = false;
GenericValueTypeMessage<std::vector<uint32> > const beginForwardMessage("BeginForward", *lastDestinationServers);
conn->send(beginForwardMessage, true);
for (std::vector<std::pair<Archive::ByteStream, std::vector<uint32> > >::const_iterator i = centralForwardMessages.begin(); i != centralForwardMessages.end(); ++i)
{
Archive::ByteStream const &msg = (*i).first;
std::vector<uint32> const &destinationServers = (*i).second;
if (destinationServers != *lastDestinationServers)
{
if (subBlock)
conn->send(endForwardMessage, true);
GenericValueTypeMessage<std::vector<uint32> > const beginForwardMessage("BeginForward", destinationServers);
conn->send(beginForwardMessage, true);
subBlock = true;
lastDestinationServers = &destinationServers;
}
conn->Connection::send(msg, true);
}
if (subBlock)
conn->send(endForwardMessage, true);
conn->send(endForwardMessage, true);
}
}
m_forwardMessages.clear();
}
// ======================================================================
@@ -0,0 +1,59 @@
// ======================================================================
//
// GameServerConnection.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_GameServerConnection_H
#define INCLUDED_GameServerConnection_H
// ======================================================================
#include "serverUtility/ServerConnection.h"
#include "sharedFoundation/NetworkId.h"
// ======================================================================
class GameServerConnection: public ServerConnection
{
public:
GameServerConnection(UdpConnectionMT *, TcpClient *);
virtual ~GameServerConnection();
virtual void onConnectionClosed();
virtual void onConnectionOpened();
virtual void onReceive(Archive::ByteStream const &message);
void setPreloadNumber(int preloadNumber);
int getPreloadNumber() const;
private:
GameServerConnection(GameServerConnection const &);
GameServerConnection &operator=(GameServerConnection const &);
GameServerConnection();
void pushAndClearObjectForwarding();
int m_preloadNumber;
std::vector<int> m_forwardCounts;
std::vector<std::vector<uint32> > m_forwardDestinationServers;
std::vector<std::pair<Archive::ByteStream, std::vector<uint32> > > m_forwardMessages;
};
//-----------------------------------------------------------------------
inline void GameServerConnection::setPreloadNumber(int preloadNumber)
{
m_preloadNumber = preloadNumber;
}
//-----------------------------------------------------------------------
inline int GameServerConnection::getPreloadNumber() const
{
return m_preloadNumber;
}
// ======================================================================
#endif
@@ -0,0 +1,103 @@
// ======================================================================
//
// GameServerData.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "FirstPlanetServer.h"
#include "GameServerData.h"
#include "ConfigPlanetServer.h"
#include "GameServerConnection.h"
#include "PlanetServer.h"
#include "sharedLog/Log.h"
// ======================================================================
GameServerData::GameServerData(GameServerConnection *connection) :
m_connection(connection),
m_objectCount(0),
m_interestObjectCount(0),
m_interestCreatureObjectCount(0),
m_serverStatus(SS_unready)
{
}
// ----------------------------------------------------------------------
GameServerData::GameServerData(const GameServerData &rhs) :
m_connection(NULL), // connection pointer is not copied when we copy GameServerDatas
m_objectCount(rhs.m_objectCount),
m_interestObjectCount(rhs.m_interestObjectCount),
m_interestCreatureObjectCount(rhs.m_interestCreatureObjectCount),
m_serverStatus(rhs.m_serverStatus)
{
}
// ----------------------------------------------------------------------
GameServerData::GameServerData() :
m_connection(NULL),
m_objectCount(0),
m_interestObjectCount(0),
m_interestCreatureObjectCount(0),
m_serverStatus(SS_unready)
{
}
// ----------------------------------------------------------------------
GameServerData &GameServerData::operator=(const GameServerData &rhs)
{
if (&rhs == this)
return *this;
m_connection=NULL; // connection pointer is not copied when we copy GameServerDatas
m_objectCount=rhs.m_objectCount;
m_interestObjectCount=rhs.m_interestObjectCount;
m_interestCreatureObjectCount=rhs.m_interestCreatureObjectCount;
m_serverStatus=rhs.m_serverStatus;
return *this;
}
// ----------------------------------------------------------------------
void GameServerData::universeLoaded()
{
WARNING_DEBUG_FATAL(m_serverStatus != SS_readyForObjects,("Got UniverseLoaded for server %d when it was not in the \"readyForObjects\" state.",getProcessId()));
m_serverStatus = SS_loadedUniverseObjects;
}
// ----------------------------------------------------------------------
void GameServerData::ready()
{
WARNING_DEBUG_FATAL(m_serverStatus != SS_unready,("Got GameServerReady for server %d when it was not in the \"unready\" state.",getProcessId()));
m_serverStatus = SS_readyForObjects;
}
// ----------------------------------------------------------------------
void GameServerData::preloadComplete()
{
WARNING_DEBUG_FATAL(PlanetServer::getInstance().getEnablePreload() && (m_serverStatus != SS_loadedUniverseObjects),("Got prelaod complete for server %d when it was not in the \"loadedUniverseObjects\" state.",getProcessId()));
m_serverStatus = SS_running;
}
// ----------------------------------------------------------------------
uint32 GameServerData::getProcessId() const
{
NOT_NULL(m_connection);
return m_connection->getProcessId();
}
// ----------------------------------------------------------------------
void GameServerData::debugOutputData() const
{
LOG("LoadBalancing", ("Server %d: %i objects, %i interest objects",getProcessId(),getObjectCount(),getInterestObjectCount()));
}
// ======================================================================
@@ -0,0 +1,119 @@
// ======================================================================
//
// GameServerData.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_GameServerData_H
#define INCLUDED_GameServerData_H
// ======================================================================
class GameServerConnection;
// ======================================================================
class GameServerData
{
public:
explicit GameServerData(GameServerConnection *connection);
GameServerData(const GameServerData &rhs);
GameServerData();
GameServerData &operator=(const GameServerData &rhs);
public:
enum ServerStatus {SS_unready, SS_readyForObjects, SS_loadedUniverseObjects, SS_running};
public:
GameServerConnection * getConnection ();
int getObjectCount () const;
int getInterestObjectCount () const;
int getInterestCreatureObjectCount() const;
ServerStatus getServerStatus () const;
uint32 getProcessId () const;
void debugOutputData () const;
void adjustObjectCount (int adjustment);
void adjustInterestObjectCount (int adjustment);
void adjustInterestCreatureObjectCount (int adjustment);
void universeLoaded ();
void ready ();
void preloadComplete ();
bool isRunning () const;
private:
GameServerConnection * m_connection;
int m_objectCount;
int m_interestObjectCount;
int m_interestCreatureObjectCount;
ServerStatus m_serverStatus;
};
// ======================================================================
inline GameServerConnection *GameServerData::getConnection()
{
return m_connection;
}
// ----------------------------------------------------------------------
inline int GameServerData::getObjectCount() const
{
return m_objectCount;
}
// ----------------------------------------------------------------------
inline void GameServerData::adjustObjectCount(int adjustment)
{
m_objectCount+=adjustment;
}
// ----------------------------------------------------------------------
inline void GameServerData::adjustInterestObjectCount(int adjustment)
{
m_interestObjectCount+=adjustment;
}
// ----------------------------------------------------------------------
inline GameServerData::ServerStatus GameServerData::getServerStatus() const
{
return m_serverStatus;
}
// ----------------------------------------------------------------------
inline int GameServerData::getInterestObjectCount() const
{
return m_interestObjectCount;
}
// ----------------------------------------------------------------------
inline bool GameServerData::isRunning() const
{
return m_serverStatus == SS_running;
}
// ----------------------------------------------------------------------
inline int GameServerData::getInterestCreatureObjectCount() const
{
return m_interestCreatureObjectCount;
}
// ----------------------------------------------------------------------
inline void GameServerData::adjustInterestCreatureObjectCount (int adjustment)
{
m_interestCreatureObjectCount+=adjustment;
}
// ======================================================================
#endif
@@ -0,0 +1,701 @@
// ======================================================================
//
// PlanetProxyObject.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "FirstPlanetServer.h"
#include "PlanetProxyObject.h"
#include "ConfigPlanetServer.h"
#include "GameServerData.h"
#include "PlanetServer.h"
#include "QuadtreeNode.h"
#include "Scene.h"
#include "WatcherConnection.h"
#include "serverNetworkMessages/LoadObjectMessage.h"
#include "serverNetworkMessages/SetAuthoritativeMessage.h"
#include "serverNetworkMessages/UnloadProxyMessage.h"
#include "sharedFoundation/Clock.h"
#include "sharedFoundation/ExitChain.h"
#include "sharedFoundation/MemoryBlockManager.h"
#include "sharedFoundation/Tag.h"
#include "sharedLog/Log.h"
#include "sharedMathArchive/TransformArchive.h"
#include <algorithm>
// ======================================================================
MemoryBlockManager* PlanetProxyObject::memoryBlockManager;
// ======================================================================
PlanetProxyObject::PlanetProxyObject (const NetworkId &objectId) :
m_objectId(objectId),
m_containedBy(NetworkId::cms_invalid),
m_x(0),
m_y(0),
m_z(0),
m_authoritativeServer(0),
m_lastReportedServer(0),
m_interestRadius(0),
m_quadtreeNode(NULL),
m_authTransferTimeMs(Clock::timeMs()),
m_contents(NULL),
m_level(0),
m_hibernating(false),
m_templateCrc(0),
m_aiActivity(-1),
m_creationType(-1)
{
}
// ----------------------------------------------------------------------
PlanetProxyObject::~PlanetProxyObject ()
{
if (PlanetServer::getInstance().isWatcherPresent())
{
outputStatusToAll(true);
}
m_quadtreeNode=0;
if (m_contents)
{
for (std::vector<NetworkId>::const_iterator i=m_contents->begin(); i!=m_contents->end(); ++i)
WARNING(true,("Object %s was deleted without removing contained object %s first",m_objectId.getValueString().c_str(), i->getValueString().c_str()));
delete m_contents;
m_contents=0;
}
}
// ----------------------------------------------------------------------
/**
* Update an object with new data sent from a game server.
* Checks to see what changed, then takes appropriate actions.
*/
void PlanetProxyObject::update(int x, int y, int z, NetworkId containedBy, uint32 authoritativeServer, int interestRadius, int objectTypeTag, int const level, bool const hibernating, uint32 const templateCrc, int const aiActivity, int const creationType)
{
WARNING_DEBUG_FATAL(m_objectId==NetworkId::cms_invalid,("Object ID was 0."));
bool watcherUpdateNeeded = false;
m_level = level;
m_hibernating = hibernating;
m_templateCrc = templateCrc;
m_aiActivity = aiActivity;
m_creationType = creationType;
if ((m_authoritativeServer != 0 ) && (authoritativeServer != m_authoritativeServer) && (containedBy == NetworkId::cms_invalid))
{
static unsigned long authTransferSanityCheckTimeMs = ConfigPlanetServer::getAuthTransferSanityCheckTimeMs();
if (Clock::timeMs()-m_authTransferTimeMs > authTransferSanityCheckTimeMs)
{
WARNING(true, ("Resending auth transfer for %s to %lu due to receiving a stale position update.", m_objectId.getValueString().c_str(), authoritativeServer));
sendAuthorityChange(authoritativeServer, m_authoritativeServer, false);
return;
}
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",("Ignoring update for %s from %lu because server was not authoritative.",m_objectId.getValueString().c_str(),authoritativeServer));
return;
}
if (interestRadius>ConfigPlanetServer::getMaxInterestRadius())
interestRadius = ConfigPlanetServer::getMaxInterestRadius();
if (interestRadius>0 && PlanetServer::getInstance().isInTutorialMode())
interestRadius = 1;
if (containedBy!=NetworkId::cms_invalid)
{
// get coordinates from container
PlanetProxyObject *container = Scene::getInstance().findObjectByID(containedBy);
if (container)
{
x=container->getX();
y=container->getY();
z=container->getZ();
}
else
{
LOG("PlanetUpdate",("Game server said object %s was contained by object %s, but we could not find the container.",m_objectId.getValueString().c_str(),containedBy.getValueString().c_str()));
containedBy = NetworkId::cms_invalid; // so that we'll try again when the object moves again, in case we just got objects out-of-order from the game server
}
}
std::vector<uint32> oldProxyList;
Node *newNode=Scene::getInstance().findNodeByPosition(x,z);
NOT_NULL(newNode);
if (newNode!=m_quadtreeNode || m_interestRadius != interestRadius || m_authoritativeServer != authoritativeServer || m_containedBy != containedBy)
{
watcherUpdateNeeded = true;
// For debugging, update the contents of the containers
if (ConfigPlanetServer::getEnableContentsChecking() && (m_containedBy!=containedBy))
updateContentsTracking(containedBy);
bool const firstUpdate = (m_quadtreeNode == NULL);
if (m_quadtreeNode!=NULL) // if this is the first update for this object, m_quadtreeNode will be NULL because it hasn't been placed anywhere yet
{
removeServerStatistics();
// remember old list of proxies
getServers(oldProxyList);
// remove from the old location
m_quadtreeNode->removeObject(this);
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading", ("unsubscribing nodes for object id=[%s]", m_objectId.getValueString().c_str()));
unsubscribeSurroundingNodes(false);
}
// update data
m_quadtreeNode=newNode;
m_x=x;
m_y=y;
m_z=z;
m_interestRadius=interestRadius;
m_objectTypeTag = objectTypeTag;
m_authoritativeServer=authoritativeServer;
m_containedBy=containedBy;
// make sure the destination is loaded
if (!newNode->isLoaded())
{
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",("Loading node %s because object %s entered it.",newNode->getDebugNodeString().c_str(), m_objectId.getValueString().c_str()));
newNode->load();
}
// check if we're on the right server
if (!isAuthorityOk())
{
uint32 preferredServer = m_quadtreeNode->getPreferredServer();
if (m_containedBy==NetworkId::cms_invalid)
{
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",("Changing authority for object %s from %lu to %lu because node %s is authoritative on that server.",
m_objectId.getValueString().c_str(),m_authoritativeServer,preferredServer,m_quadtreeNode->getDebugNodeString().c_str()));
changeAuthority(preferredServer, false, false); // changes m_authoritativeServer and sends message
// we received the object for the first time, and we had to
// transfer the object's authority, so we need to make sure
// to unload the object on the current authoritative server,
// if necessary
if (firstUpdate)
oldProxyList.push_back(authoritativeServer);
}
else
{
WARNING(true,("Programmer bug: Object %s is in container %s, which is node %s. The object should be authoritative on server %i but it is authoritative on server %i.",
m_objectId.getValueString().c_str(),m_containedBy.getValueString().c_str(),m_quadtreeNode->getDebugNodeString().c_str(), m_authoritativeServer, preferredServer));
}
}
// place in the new location
newNode->addObject(this);
if (interestRadius > 0)
{
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading", ("subscribing nodes for object id=[%s]", m_objectId.getValueString().c_str()));
subscribeSurroundingNodes();
}
// check against new interested servers, and send proxy/unproxy as needed
if (m_containedBy==NetworkId::cms_invalid) // we don't manage proxies for containers
{
std::vector<uint32> newProxyList;
getServers(newProxyList);
changeProxies(oldProxyList,newProxyList);
}
addServerStatistics();
}
else
{
if (m_interestRadius > 0 || (abs(m_x - x) > 25) || (abs(m_z - z) > 25))
watcherUpdateNeeded = true;
}
if (PlanetServer::getInstance().isWatcherPresent() && watcherUpdateNeeded)
{
m_x=x;
m_y=y;
m_z=z;
m_objectTypeTag = objectTypeTag;
outputStatusToAll(false);
}
}
// ----------------------------------------------------------------------
void PlanetProxyObject::unsubscribeSurroundingNodes(bool clearZeroSubscriptions)
{
if (m_interestRadius <= 0)
return;
Scene::NodeListType nodelist;
Scene::getInstance().findIntersection(nodelist,m_x,m_z,m_interestRadius);
for (Scene::NodeListType::iterator i=nodelist.begin(); i!=nodelist.end(); ++i)
{
(*i)->unsubscribeServer(m_authoritativeServer, 1, clearZeroSubscriptions);
}
}
// ----------------------------------------------------------------------
void PlanetProxyObject::subscribeSurroundingNodes()
{
if (m_interestRadius <= 0)
return;
NOT_NULL(m_quadtreeNode);
Scene::NodeListType nodelist;
Scene::getInstance().findIntersection(nodelist,m_x,m_z,m_interestRadius);
for (Scene::NodeListType::iterator i=nodelist.begin(); i!=nodelist.end(); ++i)
{
(*i)->subscribeServer(m_authoritativeServer, 1);
uint32 serverId = (*i)->getPreferredServer();
if (serverId != m_authoritativeServer)
m_quadtreeNode->subscribeServer(serverId,0); // make sure if we can see them, they can see us
}
}
// ----------------------------------------------------------------------
/**
* Restore the object's authority to the specified game server.
*/
void PlanetProxyObject::restoreAuthority(uint32 gameServer)
{
m_authoritativeServer = gameServer;
m_lastReportedServer = gameServer;
// Send queued messages
PlanetServer::getInstance().sendQueuedMessagesForObject(*this);
}
// ----------------------------------------------------------------------
/**
* Make the object authortiative on a different game server. Sends a
* message to the game servers to change authority and updates
* m_authoritativeServer.
*/
void PlanetProxyObject::changeAuthority(uint32 newGameServer, bool handlingCrash, bool forcedByGame)
{
if (handlingCrash)
sendAuthorityChange(newGameServer, newGameServer, true);
else if (!forcedByGame)
sendAuthorityChange(m_authoritativeServer, newGameServer, false);
m_authoritativeServer = newGameServer;
}
// ----------------------------------------------------------------------
/**
* Make the object authoritative on a different game server and adjust the
* subscription counts.
*/
void PlanetProxyObject::changeAuthorityAndSubscriptions(uint32 newGameServer)
{
unsubscribeSurroundingNodes(false);
changeAuthority(newGameServer, false, false);
subscribeSurroundingNodes();
}
// ----------------------------------------------------------------------
/**
* Called when an object should be unloaded from the world. The object
* should be removed from the active game servers, but not deleted from
* the database.
*
* This function also removes the PlanetProxyObject from all data structures.
* On exit, it is legal to delete the PlanetProxyObject.
*
* @param sendToGameServer Set to true if ForceUnloadObjectMessage should be
* sent to the game server. In some cases there is no need to tell the game
* server to unload the object (such as when handling a crash, for example).
*/
void PlanetProxyObject::unload(bool tellGameServer)
{
if (m_quadtreeNode)
m_quadtreeNode->removeObject(this);
Scene::getInstance().removeObjectFromMap(m_objectId,tellGameServer);
if (tellGameServer)
{
PlanetServer::getInstance().unloadObject(m_objectId,m_authoritativeServer);
}
removeServerStatistics();
if (ConfigPlanetServer::getEnableContentsChecking() && m_containedBy!=NetworkId::cms_invalid)
{
PlanetProxyObject *container = Scene::getInstance().findObjectByID(m_containedBy);
if (container)
container->removeContainedObject(m_objectId);
else
WARNING(true,("Unloading object %s in container %s, but the container could not be found.",m_objectId.getValueString().c_str(), m_containedBy.getValueString().c_str()));
}
}
// ----------------------------------------------------------------------
/**
* Output the object's position to a watcher.
* @param conn the watcher
* @param deleteObject if true, tell the watcher to delete this object.
*/
void PlanetProxyObject::outputStatus(WatcherConnection &conn, bool deleteObject) const
{
conn.addObjectUpdate(m_objectId, m_x, m_z, m_authoritativeServer, m_interestRadius, deleteObject, m_objectTypeTag, m_level, m_hibernating, m_templateCrc, m_aiActivity, m_creationType);
}
// ----------------------------------------------------------------------
void PlanetProxyObject::outputStatusToAll(bool deleteObject) const
{
const PlanetServer::WatcherList &connections = PlanetServer::getInstance().getWatchers();
for (PlanetServer::WatcherList::const_iterator i= connections.begin(); i!=connections.end(); ++i)
{
outputStatus(**i, deleteObject);
}
}
// ----------------------------------------------------------------------
/**
* Update the GameServerData with statistics about this object.
*/
void PlanetProxyObject::addServerStatistics() const
{
GameServerData *data=PlanetServer::getInstance().getGameServerData(m_authoritativeServer);
if (data)
{
data->adjustObjectCount(1);
if (m_interestRadius!=0)
{
data->adjustInterestObjectCount(1);
if (isCreature())
data->adjustInterestCreatureObjectCount(1);
}
}
}
// ----------------------------------------------------------------------
/**
* Remove statistics about this object from the GameServerData.
* Should exactly undo addServerStatistics().
*/
void PlanetProxyObject::removeServerStatistics() const
{
GameServerData *data=PlanetServer::getInstance().getGameServerData(m_authoritativeServer);
if (data)
{
data->adjustObjectCount(-1);
if (m_interestRadius!=0)
{
data->adjustInterestObjectCount(-1);
if (isCreature())
data->adjustInterestCreatureObjectCount(-1);
}
}
}
// ----------------------------------------------------------------------
/**
* Set up memory pool
*/
void PlanetProxyObject::install()
{
memoryBlockManager = new MemoryBlockManager("PlanetProxyObject::memoryBlockManager", true, sizeof(PlanetProxyObject), 0, 0, 0);
ExitChain::add(&remove, "PlanetProxyObject::remove");
}
// ----------------------------------------------------------------------
void PlanetProxyObject::remove()
{
WARNING_DEBUG_FATAL(!memoryBlockManager, ("PlanetProxyObject is not installed"));
delete memoryBlockManager;
memoryBlockManager = 0;
}
// ----------------------------------------------------------------------
void * PlanetProxyObject::operator new(size_t size)
{
UNREF(size);
WARNING_DEBUG_FATAL(!memoryBlockManager, ("PlanetProxyObject is not installed"));
// do not try to alloc a descendant class with this allocator
WARNING_DEBUG_FATAL(size != sizeof(PlanetProxyObject), ("bad size"));
return memoryBlockManager->allocate();
}
// ----------------------------------------------------------------------
void PlanetProxyObject::operator delete(void* pointer)
{
WARNING_DEBUG_FATAL(!memoryBlockManager, ("PlanetProxyObject is not installed"));
memoryBlockManager->free(pointer);
}
// ----------------------------------------------------------------------
void PlanetProxyObject::sendAuthorityChange(uint32 currentAuthServer, uint32 newAuthServer, bool handlingCrash)
{
DEBUG_WARNING(!isAuthorityClean(), ("Object %s attempted to change authority before previous authority change was complete.",getObjectId().getValueString().c_str()));
SetAuthoritativeMessage const auth(getObjectId(), newAuthServer, false, handlingCrash, NetworkId::cms_invalid, Transform::identity, false);
PlanetServer::getInstance().sendToGameServer(currentAuthServer, auth);
m_authTransferTimeMs = Clock::timeMs();
}
// ----------------------------------------------------------------------
void PlanetProxyObject::sendAddProxy(uint32 proxyServer)
{
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",("Gameserver %lu needs a proxy of object %s",proxyServer,m_objectId.getValueString().c_str()));
if (isAuthorityClean())
{
LoadObjectMessage const loadMsg(getObjectId(), proxyServer);
PlanetServer::getInstance().sendToGameServer(m_authoritativeServer, loadMsg);
}
else
{
LoadObjectMessage * const loadMsg = new LoadObjectMessage(getObjectId(), proxyServer);
PlanetServer::getInstance().queueMessageForObject(getObjectId(), loadMsg);
}
}
// ----------------------------------------------------------------------
void PlanetProxyObject::sendRemoveProxy(uint32 proxyServer)
{
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",("Gameserver %lu no longer needs a proxy of object %s",proxyServer,m_objectId.getValueString().c_str()));
if (isAuthorityClean())
{
UnloadProxyMessage msg(getObjectId(),proxyServer);
PlanetServer::getInstance().sendToGameServer(m_authoritativeServer, msg);
}
else
{
UnloadProxyMessage *msg = new UnloadProxyMessage(getObjectId(),proxyServer);
PlanetServer::getInstance().queueMessageForObject(getObjectId(), msg);
}
}
// ----------------------------------------------------------------------
/**
* Called when we receieve a message about the object from a game server.
* Used to keep track of which server is sending us updates, and to send
* any messages that were waiting for an authority change.
*/
void PlanetProxyObject::onReceivedMessageFromServer(uint32 server)
{
if (m_lastReportedServer != m_authoritativeServer && server == m_authoritativeServer)
// we've received a message from the new authoritative server. Send queued messages:
PlanetServer::getInstance().sendQueuedMessagesForObject(*this);
m_lastReportedServer = server;
}
// ----------------------------------------------------------------------
/**
* Get the list of servers that should have proxies of this object.
*/
void PlanetProxyObject::getServers(std::vector<uint32> &serverList) const
{
Node *effectiveNode;
if (m_containedBy == NetworkId::cms_invalid)
{
effectiveNode = m_quadtreeNode;
}
else
{
PlanetProxyObject *container=Scene::getInstance().findObjectByID(m_containedBy);
WARNING_STRICT_FATAL(!container,("Object %s is in container %s, which couldn't be found",m_objectId.getValueString().c_str(),m_containedBy.getValueString().c_str()));
if (container)
effectiveNode = container->getNode();
else
effectiveNode = m_quadtreeNode;
}
if (effectiveNode)
effectiveNode->getServers(serverList);
}
// ----------------------------------------------------------------------
/**
* Given a list of servers that have a proxy and a list of servers
* that should have a proxy, send messages to update the servers.
* Note: O(n^2), assumes both lists are small, otherwise it would be better
* to sort them first.
*/
void PlanetProxyObject::changeProxies(const std::vector<uint32> &oldServers, const std::vector<uint32> &newServers)
{
{
for (std::vector<uint32>::const_iterator i=oldServers.begin(); i!=oldServers.end(); ++i)
{
if (*i != m_authoritativeServer)
{
bool removeNeeded = true;
for (std::vector<uint32>::const_iterator j=newServers.begin(); j!=newServers.end(); ++j)
{
if (*i == *j)
{
removeNeeded = false;
break;
}
}
if (removeNeeded)
sendRemoveProxy(*i);
}
}
}
{
for (std::vector<uint32>::const_iterator i=newServers.begin(); i!=newServers.end(); ++i)
{
if (*i != m_authoritativeServer)
{
bool addNeeded = true;
for (std::vector<uint32>::const_iterator j=oldServers.begin(); j!=oldServers.end(); ++j)
{
if (*i == *j)
{
addNeeded = false;
break;
}
}
if (addNeeded)
sendAddProxy(*i);
}
}
}
}
// ----------------------------------------------------------------------
/**
* Check whether we are on a server that's acceptable for where we are.
*/
bool PlanetProxyObject::isAuthorityOk() const
{
if (m_authoritativeServer == m_quadtreeNode->getPreferredServer())
return true;
if (m_quadtreeNode->isBorderNode() && m_quadtreeNode->isServerSubscribed(m_authoritativeServer))
return true;
else
return false;
}
// ----------------------------------------------------------------------
/**
* Check for whether a desired server would be OK for where we are.
* The server is OK if it is the preferred server. If the object is
* a creature, the server is also OK if the node is a border node and
* the server has a subscription to the node. Non-creatures must always
* be on the preferred server.
*/
bool PlanetProxyObject::wouldAuthorityBeOk(uint32 possibleServer) const
{
if (possibleServer == m_quadtreeNode->getPreferredServer())
return true;
if (isCreature() && m_quadtreeNode->isBorderNode() && m_quadtreeNode->isServerSubscribed(possibleServer))
return true;
else
return false;
}
// ----------------------------------------------------------------------
void PlanetProxyObject::addContainedObject(const NetworkId &theObject)
{
if (!m_contents)
{
m_contents = new std::vector<NetworkId>;
}
for (std::vector<NetworkId>::const_iterator i=m_contents->begin(); i!=m_contents->end(); ++i)
{
if (*i==theObject)
WARNING(true,("Object %s was placed in container %s twice.", theObject.getValueString().c_str(), m_objectId.getValueString().c_str()));
}
m_contents->push_back(theObject);
}
// ----------------------------------------------------------------------
void PlanetProxyObject::removeContainedObject(const NetworkId &theObject)
{
if (!m_contents)
{
WARNING(true,("Attempted to remove object %s from object %s, but that object has no contents.", theObject.getValueString().c_str(), m_objectId.getValueString().c_str()));
return;
}
std::vector<NetworkId>::iterator newEnd=std::remove(m_contents->begin(), m_contents->end(), theObject);
if (newEnd==m_contents->end())
{
WARNING(true,("Attempted to remove object %s from object %s, but it was not in the container.", theObject.getValueString().c_str(), m_objectId.getValueString().c_str()));
return;
}
m_contents->erase(newEnd, m_contents->end());
}
// ----------------------------------------------------------------------
/**
* Helper function to update the contents tracking lists, in order to
* debug various authority problems
*/
void PlanetProxyObject::updateContentsTracking(const NetworkId &newContainedBy)
{
if (m_containedBy!=NetworkId::cms_invalid)
{
PlanetProxyObject *container = Scene::getInstance().findObjectByID(m_containedBy);
if (container)
container->removeContainedObject(m_objectId);
else
WARNING(true,("Removing object %s from container %s, but the container could not be found.",m_objectId.getValueString().c_str(), m_containedBy.getValueString().c_str()));
}
if (newContainedBy!=NetworkId::cms_invalid)
{
PlanetProxyObject *container = Scene::getInstance().findObjectByID(newContainedBy);
if (container)
container->addContainedObject(m_objectId);
else
WARNING(true,("Adding object %s to container %s, but the container could not be found.",m_objectId.getValueString().c_str(), newContainedBy.getValueString().c_str()));
}
}
// ----------------------------------------------------------------------
bool PlanetProxyObject::isCreature() const
{
return m_objectTypeTag==TAG(C,R,E,O);
}
// ======================================================================
@@ -0,0 +1,237 @@
// ======================================================================
//
// PlanetProxyObject.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_PlanetProxyObject_H
#define INCLUDED_PlanetProxyObject_H
// ======================================================================
#include "sharedFoundation/NetworkId.h"
#include "sharedMath/Vector.h"
class Node;
class MemoryBlockManager;
class WatcherConnection;
// ======================================================================
/**
* Lightweight proxy of an object, containing just the data the planet server
* cares about.
*
* Coordinates are made into integers because none of the Planet Server's
* algorithms care about sub-meter distances.
*/
class PlanetProxyObject
{
public:
explicit PlanetProxyObject (const NetworkId &objectId);
~PlanetProxyObject ();
public:
void addServerStatistics () const;
void changeAuthority (uint32 newGameServer, bool handlingCrash, bool forcedByGame);
void changeAuthorityAndSubscriptions(uint32 newGameServer);
void onReceivedMessageFromServer (uint32 server);
void outputStatus (WatcherConnection &conn, bool deleteObject) const;
void outputStatusToAll (bool deleteObject) const;
void removeServerStatistics () const;
void restoreAuthority (uint32 gameServer);
void sendAddProxy (uint32 proxyServer);
void sendRemoveProxy (uint32 proxyServer);
void setNode (Node *node);
void subscribeSurroundingNodes ();
void unload (bool tellGameServer);
void unsubscribeSurroundingNodes (bool clearZeroSubscriptions);
void update (int x, int y, int z, NetworkId containedBy, uint32 authoritativeServer, int interestRadius, int objectTypeTag, int level, bool hibernating, uint32 templateCrc, int aiActivity, int creationType);
public:
int getX () const;
int getY () const;
int getZ () const;
uint32 getAuthoritativeServer () const;
int getInterestRadius () const;
bool isContained () const;
bool isAuthorityClean () const;
const NetworkId & getObjectId () const;
const NetworkId & getContainedBy () const;
Node * getNode () const;
bool wouldAuthorityBeOk (uint32 possibleServer) const;
bool isCreature () const;
int getLevel () const;
bool getHibernating () const;
uint32 getTemplateCrc () const;
int getAiActivity () const;
int getCreationType () const;
public:
static void * operator new (size_t size);
static void operator delete (void* pointer);
static void install ();
static void remove ();
private:
void getServers (std::vector<uint32> &serverList) const;
void changeProxies (const std::vector<uint32> &oldServers, const std::vector<uint32> &newServers);
void sendAuthorityChange (uint32 currentAuthServer, uint32 newAuthServer, bool handlingCrash);
bool isAuthorityOk () const;
void addContainedObject (const NetworkId & theObject);
void removeContainedObject (const NetworkId & theObject);
void updateContentsTracking (const NetworkId & newContainedBy);
private:
typedef stdvector<std::pair<uint32, GameNetworkMessage*> > MessageListType;
private:
const NetworkId m_objectId;
NetworkId m_containedBy;
int m_x;
int m_y;
int m_z;
uint32 m_authoritativeServer;
uint32 m_lastReportedServer;
int m_interestRadius;
int m_objectTypeTag;
Node * m_quadtreeNode;
unsigned long m_authTransferTimeMs;
stdvector<NetworkId>::fwd * m_contents;
int m_level;
bool m_hibernating;
uint32 m_templateCrc;
int m_aiActivity;
int m_creationType;
static MemoryBlockManager* memoryBlockManager;
private:
PlanetProxyObject(); //disable
PlanetProxyObject &operator=(const PlanetProxyObject&); //disable
PlanetProxyObject(const PlanetProxyObject&); //disable
};
// ======================================================================
inline const NetworkId &PlanetProxyObject::getObjectId() const
{
return m_objectId;
}
// ----------------------------------------------------------------------
inline int PlanetProxyObject::getX() const
{
return m_x;
}
// ----------------------------------------------------------------------
inline int PlanetProxyObject::getY() const
{
return m_y;
}
// ----------------------------------------------------------------------
inline int PlanetProxyObject::getZ() const
{
return m_z;
}
// ----------------------------------------------------------------------
inline int PlanetProxyObject::getLevel() const
{
return m_level;
}
// ----------------------------------------------------------------------
inline bool PlanetProxyObject::getHibernating() const
{
return m_hibernating;
}
// ----------------------------------------------------------------------
inline uint32 PlanetProxyObject::getTemplateCrc() const
{
return m_templateCrc;
}
// ----------------------------------------------------------------------
inline int PlanetProxyObject::getAiActivity() const
{
return m_aiActivity;
}
// ----------------------------------------------------------------------
inline int PlanetProxyObject::getCreationType() const
{
return m_creationType;
}
// ----------------------------------------------------------------------
inline uint32 PlanetProxyObject::getAuthoritativeServer() const
{
return m_authoritativeServer;
}
// ----------------------------------------------------------------------
inline int PlanetProxyObject::getInterestRadius() const
{
return m_interestRadius;
}
// ----------------------------------------------------------------------
inline void PlanetProxyObject::setNode(Node *node)
{
m_quadtreeNode=node;
}
// ----------------------------------------------------------------------
/**
* Returns true if the object's authority is "clean", i.e. the Game Servers
* think it is authoritative on the same server the Planet Server does.
* This returns false when we've changed the object's authority until the
* newly authoritative server sends us an update, at which point we know
* that it thinks it is authoritative.
*/
inline bool PlanetProxyObject::isAuthorityClean() const
{
return m_lastReportedServer == m_authoritativeServer;
}
// ----------------------------------------------------------------------
inline Node *PlanetProxyObject::getNode() const
{
return m_quadtreeNode;
} //lint !e1763
// ----------------------------------------------------------------------
inline const NetworkId &PlanetProxyObject::getContainedBy() const
{
return m_containedBy;
}
// ----------------------------------------------------------------------
inline bool PlanetProxyObject::isContained() const
{
return (m_containedBy != NetworkId::cms_invalid);
}
// ======================================================================
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,190 @@
// ======================================================================
//
// PlanetServer.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_PlanetServer_H
#define INCLUDED_PlanetServer_H
// ======================================================================
#include <map>
#include <set>
#include <vector>
#include "sharedMessageDispatch/Receiver.h"
#include "Singleton/Singleton.h"
#include "PreloadManager.h"
#include "TaskConnection.h"
class CentralServerConnection;
class ChunkCompleteMessage;
class GameNetworkMessage;
class GameServerConnection;
class GameServerData;
class PlanetProxyObject;
class PlanetServerMetricsData;
class PreloadListData;
class RequestGameServerForLoginMessage;
class RequestSceneTransfer;
class Service;
class Vector;
class WatcherConnection;
struct CharacterFindInfo;
//-----------------------------------------------------------------------
class PlanetServer : public Singleton<PlanetServer>, public MessageDispatch::Receiver
{
public:
typedef std::vector<WatcherConnection*> WatcherList;
typedef unsigned int GameServerSpawnDelaySeconds;
public:
PlanetServer();
~PlanetServer();
static void run(void);
void mainLoop(void);
void setDone(char const *reasonfmt, ...);
const unsigned short getGameServicePort() const;
const Service * getGameService() const;
int getNumberOfGameServers() const;
int getObjectCountForServer(uint32 serverId) const;
int getInterestObjectCountForServer(uint32 serverId) const;
int getInterestCreatureObjectCountForServer(uint32 serverId) const;
void getObjectCountsForAllServers(stdmap<uint32, GameServerData>::fwd &counts) const;
virtual void receiveMessage(const MessageDispatch::Emitter & source, const MessageDispatch::MessageBase & message);
void sendToCentral(const GameNetworkMessage & message, const bool reliable);
void sendToGameServer(const uint32 processId, const GameNetworkMessage & message);
void setTaskManager(TaskConnection*);
void startGameServer(const std::set<PreloadServerId> & preloadServerId, GameServerSpawnDelaySeconds spawnDelay);
GameServerData * getGameServerData(uint32 serverId) const;
void preloadCompleteOnAllServers();
int getCurrentServerInterestObjectLimit() const;
void queueMessageForObject(const NetworkId &networkId, GameNetworkMessage *theMessage);
void sendQueuedMessagesForObject(const PlanetProxyObject &theObject);
void unloadObject (const NetworkId &object, uint32 authServer);
void sendChunkRequest(uint32 server, int x, int z);
void sendPreloadRequestCompleteMessage(uint32 realServerId, uint32 preloadServerId);
void requestAndWaitForSave();
void onCentralConnected(CentralServerConnection *connection);
const WatcherList & getWatchers() const;
bool isWatcherPresent() const;
bool isInTutorialMode() const;
bool getEnablePreload() const;
bool isInSpaceMode() const;
GameServerConnection *getGameServerConnection(uint32 serverId);
ServerConnection *getCentralServerConnection();
private:
typedef std::map<uint32, GameServerData*> GameServerMapType;
private:
void handleRequestGameServerForLoginMessage (const RequestGameServerForLoginMessage *&msg);
void loadCharacterForLogin(NetworkId const &characterId, Vector const &coords, unsigned long gameServerId);
void handleRequestSceneTransfer(const RequestSceneTransfer *& msg);
void handleChunkComplete(const ChunkCompleteMessage &msg, const GameServerConnection *conn);
void flushWaitingMessages();
void findOrLoadCharacter(NetworkId const &characterId, NetworkId const &containerId, Vector const &coords, uint32 stationId, bool forCtsSourceCharacter);
void handleFindAuthObjectResponse(NetworkId const &characterId, unsigned int sequence, bool found, uint32 gameServerId);
void forceLoadCharacter(NetworkId const &characterId, NetworkId const &containerId, Vector const &coords, uint32 stationId, bool forCtsSourceCharacter);
void handleDatabaseSaveComplete(int newSaveCounter);
private:
CentralServerConnection * m_pendingCentralServerConnection;
CentralServerConnection * m_centralServerConnection;
Service * m_gameService;
Service * m_watcherService;
GameServerMapType m_gameServers;
TaskConnection * m_taskConnection;
bool m_done;
int m_roundRobinGameServer;
stdmap<PreloadServerId, GameServerSpawnDelaySeconds>::fwd * m_pendingServerStarts; // number of game servers to start when central & task manager are ready
stdmap<int, std::pair<std::string, time_t> >::fwd * m_startingGameServers; // number of game servers we've started that haven't connected to us yet
uint32 m_firstGameServer;
bool m_tutorialMode;
bool m_spaceMode;
std::set<GameServerConnection *> m_pendingGameServerDisconnects;
std::vector<const GameNetworkMessage *> m_messagesWaitingForGameServer;
PlanetServerMetricsData* m_metricsData;
TaskConnection* m_taskManagerConnection;
stdlist<const RequestSceneTransfer *>::fwd *m_sceneTransferChunkLoads;
stdmap<NetworkId, uint32>::fwd *m_pendingCharacterSaves;
WatcherList m_watchers;
bool m_watcherIsPresent;
typedef std::map<NetworkId, std::vector<GameNetworkMessage*> > QueuedMessagesType;
QueuedMessagesType m_queuedMessages;
stdmap<NetworkId, CharacterFindInfo>::fwd *m_characterFindMap;
unsigned int m_characterFindSequence;
int m_waitForSaveCounter;
int m_lastSaveCounter;
private:
//disable:
PlanetServer(const PlanetServer&);
PlanetServer &operator=(const PlanetServer&);
};
// ----------------------------------------------------------------------
inline int PlanetServer::getNumberOfGameServers() const
{
return static_cast<int>(m_gameServers.size());
}
// ----------------------------------------------------------------------
inline void PlanetServer::onCentralConnected(CentralServerConnection *connection)
{
m_pendingCentralServerConnection=NULL;
m_centralServerConnection=connection;
}
// ----------------------------------------------------------------------
inline void PlanetServer::setTaskManager(TaskConnection* con)
{
m_taskManagerConnection = con;
}
// ----------------------------------------------------------------------
inline bool PlanetServer::isWatcherPresent() const
{
return m_watcherIsPresent;
}
// ----------------------------------------------------------------------
inline const PlanetServer::WatcherList & PlanetServer::getWatchers() const
{
return m_watchers;
}
// ----------------------------------------------------------------------
inline bool PlanetServer::isInTutorialMode() const
{
return m_tutorialMode;
}
// ----------------------------------------------------------------------
inline bool PlanetServer::isInSpaceMode() const
{
return m_spaceMode;
}
// ======================================================================
#endif //_CentralServer_H
@@ -0,0 +1,102 @@
//PlanetServerMetricsData.cpp
//Copyright 2002 Sony Online Entertainment
#include "FirstPlanetServer.h"
#include "PlanetServerMetricsData.h"
#include "PlanetServer.h"
#include "ConfigPlanetServer.h"
#ifndef WIN32
#include "MonAPI2/MonitorData.h"
#endif
#include "serverNetworkMessages/MetricsDataMessage.h"
#include "sharedFoundation/Os.h"
#include "sharedNetworkMessages/GameNetworkMessage.h"
//-----------------------------------------------------------------------
PlanetServerMetricsData::PlanetServerMetricsData() :
MetricsData(),
m_numGameServers(0),
m_watcherPort(0),
m_gameServerLoadTime()
{
MetricsPair p;
ADD_METRICS_DATA(numGameServers, 0, false); //lint !e713 loss of precision, couldn't figure out a cast that made Lint happy
ADD_METRICS_DATA(watcherPort, ConfigPlanetServer::getWatcherServicePort(), false);
std::string label = NetworkHandler::getHostName();
for (std::string::iterator i = label.begin(); i != label.end(); ++i)
{
if (*i == '.')
{
*i = '+';
}
}
label += ":";
char tmp[256];
label += _itoa(Os::getProcessId(), tmp, 10);
m_data[m_watcherPort].m_description = label;
}
//-----------------------------------------------------------------------
PlanetServerMetricsData::~PlanetServerMetricsData()
{
}
//-----------------------------------------------------------------------
void PlanetServerMetricsData::updateData()
{
MetricsData::updateData();
m_data[m_numGameServers].m_value = PlanetServer::getInstance().getNumberOfGameServers(); //lint !e732 !e713
#ifndef WIN32
// if all game servers for planet has not finished loading,
// set value to "loading" to cause the planet node to appear
// yellow to help figure out which planet is still loading
if (!PreloadManager::getInstance().isPreloadComplete())
m_data[m_watcherPort].m_value = STATUS_LOADING;
else
#endif
m_data[m_watcherPort].m_value = ConfigPlanetServer::getWatcherServicePort();
// report load time of each game server
PreloadManager::ServerMapType const * serverMap = PreloadManager::getInstance().getServerMap();
if (serverMap && !serverMap->empty())
{
std::map<uint32, unsigned long>::const_iterator iter2;
MetricsPair p;
char buffer[128];
for (PreloadManager::ServerMapType::const_iterator iter = serverMap->begin(); iter != serverMap->end(); ++iter)
{
iter2 = m_gameServerLoadTime.find(iter->first);
if (iter2 == m_gameServerLoadTime.end())
{
// create a node to report load time for this game server
snprintf(buffer, sizeof(buffer)-1, "loadTime_%s_%lu", ConfigPlanetServer::getSceneID(), iter->first);
buffer[sizeof(buffer)-1] = '\0';
p.m_label = buffer;
p.m_value = std::max(static_cast<int>(0), static_cast<int>((iter->second.m_loadTime != -1) ? iter->second.m_loadTime : (time(0) - iter->second.m_timeLoadStarted)));
p.m_description = "seconds";
p.m_persistData = true;
p.m_summary = false;
m_gameServerLoadTime[iter->first] = m_data.size();
m_data.push_back(p);
}
else
{
m_data[iter2->second].m_value = std::max(static_cast<int>(0), static_cast<int>((iter->second.m_loadTime != -1) ? iter->second.m_loadTime : (time(0) - iter->second.m_timeLoadStarted)));
}
}
}
}
//-----------------------------------------------------------------------
@@ -0,0 +1,38 @@
//PlanetServerMetricsData.h
//Copyright 2002 Sony Online Entertainment
#ifndef _PlanetServerMetricsData_H
#define _PlanetServerMetricsData_H
//-----------------------------------------------------------------------
#include "serverMetrics/MetricsData.h"
//-----------------------------------------------------------------------
class PlanetServerMetricsData : public MetricsData
{
public:
PlanetServerMetricsData();
~PlanetServerMetricsData();
virtual void updateData();
private:
unsigned long m_numGameServers;
unsigned long m_watcherPort;
// used for reporting load time of each game server
stdmap<uint32, unsigned long>::fwd m_gameServerLoadTime;
private:
// Disabled.
PlanetServerMetricsData(const PlanetServerMetricsData&);
PlanetServerMetricsData &operator =(const PlanetServerMetricsData&);
};
//-----------------------------------------------------------------------
#endif
@@ -0,0 +1,492 @@
// ======================================================================
//
// PreloadManager.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "FirstPlanetServer.h"
#include "PreloadManager.h"
#include "ConfigPlanetServer.h"
#include "GameServerData.h"
#include "PlanetProxyObject.h"
#include "QuadtreeNode.h"
#include "Scene.h"
#include "serverUtility/PopulationList.h"
#include "sharedFoundation/ExitChain.h"
#include "sharedUtility/DataTable.h"
#include "sharedUtility/DataTableManager.h"
#include <cstdio>
#include <map>
#include <set>
#include <vector>
// ======================================================================
PreloadManager::PreloadManager() :
Singleton2<PreloadManager>(),
m_serverMap(new ServerMapType),
m_preloadList(new PreloadListType),
m_serversWaiting(new ServersWaitingType),
m_listReceived(false)
{
ExitChain::add(&remove, "PreloadManager::remove");
}
// ----------------------------------------------------------------------
PreloadManager::~PreloadManager()
{
delete m_serverMap;
delete m_preloadList;
delete m_serversWaiting;
m_serverMap=0;
m_preloadList=0;
m_serversWaiting=0;
}
// ----------------------------------------------------------------------
/**
* Set up the preload list, based on the scene and config options.
*/
void PreloadManager::handlePreloadList()
{
m_listReceived=true;
WARNING(ConfigPlanetServer::getLoadWholePlanet() && ConfigPlanetServer::getLoadWholePlanetMultiserver(),("You have specified both loadWholePlanet and loadWholePlanetMultiserver. LoadWholePlanet (single-server) will take precedence."));
if (ConfigPlanetServer::getLoadWholePlanet() || PlanetServer::getInstance().isInSpaceMode() || !PlanetServer::getInstance().getEnablePreload())
{
// Set up a single server to handle the whole planet
PreloadListData fakeBeacon;
fakeBeacon.m_topLeftChunkX = 0;
fakeBeacon.m_topLeftChunkZ = 0;
fakeBeacon.m_bottomRightChunkX = 100;
fakeBeacon.m_bottomRightChunkZ = 100;
fakeBeacon.m_cityServerId = 1;
fakeBeacon.m_wildernessServerId = 1;
m_preloadList->clear();
m_preloadList->push_back(fakeBeacon);
m_serversWaiting->insert(1);
PreloadServerInformation & psi = (*m_serverMap)[1];
psi.m_actualServerId = 0;
psi.m_timeLoadStarted = time(0);
psi.m_loadTime = -1;
}
// WTF is this ... the tutorial planet bypasses the preload multiserver setting in favor of this pie slice algorithm
// We should not need this anymore with the NPE tutorial
// NPE will use the preload tables for multiserver and the 'NewbieTutorial' manager for placing the tutotial instances
/*
else if(PlanetServer::getInstance().isInTutorialMode())
{
m_preloadList->clear();
int n=ConfigPlanetServer::getNumTutorialServers();
if ((ConfigPlanetServer::getMaxGameServers() != 0) && (n > ConfigPlanetServer::getMaxGameServers()))
n=ConfigPlanetServer::getMaxGameServers();
for (int i=0 ; i<n; ++i)
{
float angle = PI_TIMES_2 * (static_cast<float>(i)/static_cast<float>(n));
// Make a circle of load beacons. The effect will be to divide the map into wedges
PreloadListData fakeBeacon;
fakeBeacon.m_topLeftChunkX = Node::roundToNode(static_cast<int>(cos(angle) * 1000.0f));
fakeBeacon.m_topLeftChunkZ = Node::roundToNode(static_cast<int>(sin(angle) * 1000.0f));
fakeBeacon.m_bottomRightChunkX = fakeBeacon.m_topLeftChunkX + Node::getNodeSize();
fakeBeacon.m_bottomRightChunkZ = fakeBeacon.m_topLeftChunkZ + Node::getNodeSize();
fakeBeacon.m_cityServerId = i+1;
fakeBeacon.m_wildernessServerId = i+1;
DEBUG_REPORT_LOG(true,("Loadbeacon at %i, %i\n",fakeBeacon.m_topLeftChunkX, fakeBeacon.m_topLeftChunkZ));
m_preloadList->push_back(fakeBeacon);
PreloadServerInformation & psi = (*m_serverMap)[i+1];
psi.m_actualServerId = 0;
psi.m_timeLoadStarted = time(0);
psi.m_loadTime = -1;
m_serversWaiting->insert(i+1);
}
}*/
else
{
if (PlanetServer::getInstance().getEnablePreload())
{
DataTable * data = DataTableManager::getTable(ConfigPlanetServer::getPreloadDataTableName(),true);
FATAL(data==NULL,("Could not find data table %s, needed for preload",ConfigPlanetServer::getPreloadDataTableName()));
int numRows = data->getNumRows();
for (int row=0; row<numRows; ++row)
{
if (data->getStringValue("Scene",row)==Scene::getInstance().getSceneId())
{
PreloadListData item;
item.m_topLeftChunkX=data->getIntValue("Top Left Chunk X",row);
item.m_topLeftChunkZ=data->getIntValue("Top Left Chunk Z",row);
item.m_bottomRightChunkX=data->getIntValue("Bottom Right Chunk X",row);
item.m_bottomRightChunkZ=data->getIntValue("Bottom Right Chunk Z",row);
item.m_cityServerId=data->getIntValue("City Server Id",row);
item.m_wildernessServerId=data->getIntValue("Wilderness Server Id",row);
if (ConfigPlanetServer::getMaxGameServers() != 0)
{
// Reduce the total number of game servers
item.m_cityServerId = ((item.m_cityServerId - 1) % ConfigPlanetServer::getMaxGameServers()) + 1;
if (item.m_wildernessServerId != 0)
item.m_wildernessServerId = ((item.m_wildernessServerId - 1) % ConfigPlanetServer::getMaxGameServers()) + 1;
}
m_preloadList->push_back(item);
ServerMapType::iterator mapIter = m_serverMap->find(item.m_cityServerId);
if (mapIter == m_serverMap->end())
{
PreloadServerInformation & psi = (*m_serverMap)[item.m_cityServerId];
psi.m_actualServerId = 0;
psi.m_timeLoadStarted = time(0);
psi.m_loadTime = -1;
m_serversWaiting->insert(item.m_cityServerId);
}
if (item.m_wildernessServerId != 0)
{
mapIter = m_serverMap->find(item.m_wildernessServerId);
if (mapIter == m_serverMap->end())
{
PreloadServerInformation & psi = (*m_serverMap)[item.m_wildernessServerId];
psi.m_actualServerId = 0;
psi.m_timeLoadStarted = time(0);
psi.m_loadTime = -1;
m_serversWaiting->insert(item.m_wildernessServerId);
}
}
}
}
}
}
FATAL(PlanetServer::getInstance().getEnablePreload() && m_serversWaiting->size()==0,("Planet server started for scene %s, which was not listed in the preload data table",
Scene::getInstance().getSceneId().c_str()));
std::set<PreloadServerId> startGameServerList;
if (m_serversWaiting->size() < 1)
{
IGNORE_RETURN(startGameServerList.insert(1));
}
else
{
for (ServersWaitingType::const_iterator i = m_serversWaiting->begin(); i != m_serversWaiting->end(); ++i)
IGNORE_RETURN(startGameServerList.insert(*i));
}
Scene::getInstance().assignPreloadsToNodes();
PlanetServer::getInstance().startGameServer(startGameServerList, 0);
}
// ----------------------------------------------------------------------
/**
* Called when a game server reports that it is ready to receive objects
*/
bool PreloadManager::onGameServerReady(uint32 serverId, PreloadServerId preloadServerId)
{
bool result = true;
bool noPreload = true;
// attempt to assign the game server the specified role in the preload list, if possible
bool assigned = false;
for (ServerMapType::iterator i=m_serverMap->begin(); i!=m_serverMap->end(); ++i)
{
if (i->first == preloadServerId)
{
if (i->second.m_actualServerId == 0)
{
i->second.m_actualServerId = serverId;
sendPreloadsToGameServer(serverId, i->first);
noPreload = false;
assigned = true;
}
break;
}
}
if (!assigned)
{
for (ServerMapType::iterator j=m_serverMap->begin(); j!=m_serverMap->end(); ++j)
{
if (j->second.m_actualServerId == 0)
{
// assign the new game server to this role in the preload list
j->second.m_actualServerId = serverId;
sendPreloadsToGameServer(serverId, j->first);
noPreload = false;
break;
}
}
}
if (noPreload)
{
// this server has nothing to preload, so advance its status right away
GameServerData *data = PlanetServer::getInstance().getGameServerData(serverId);
if(! PlanetServer::getInstance().getEnablePreload())
{
if (data)
data->preloadComplete();
// send PreloadRequestCompleteMessage, because things on the game server wait for it
PlanetServer::getInstance().sendPreloadRequestCompleteMessage(serverId, 0);
}
else
{
if(! PlanetServer::getInstance().isInTutorialMode())
{
result = false; // disconnect the game server, it's extraneous.
}
}
}
// if the preload list is empty, preloading is finished as soon as at least 1 game server is up
if (m_serverMap->empty())
{
DEBUG_REPORT_LOG(ConfigPlanetServer::getLogPreloading(),("Preloading is finished on %s because there was nothing to preload.\n",Scene::getInstance().getSceneId().c_str()));
PlanetServer::getInstance().preloadCompleteOnAllServers();
}
return result;
}
// ----------------------------------------------------------------------
void PreloadManager::sendPreloadsToGameServer(uint32 realServerId, PreloadServerId preloadServerId) const
{
if (PlanetServer::getInstance().getEnablePreload())
Scene::getInstance().loadAllNodesForServer(realServerId, preloadServerId);
PlanetServer::getInstance().sendPreloadRequestCompleteMessage(realServerId, preloadServerId);
}
// ----------------------------------------------------------------------
/**
* Called when a game server drops connection. Remove it from the preload assignments.
*/
void PreloadManager::removeGameServer(uint32 serverId)
{
for (ServerMapType::iterator i=m_serverMap->begin(); i!=m_serverMap->end(); ++i)
{
if (i->second.m_actualServerId == serverId)
{
i->second.m_actualServerId = 0;
i->second.m_timeLoadStarted = time(0);
i->second.m_loadTime = -1;
m_serversWaiting->insert(i->first);
break;
}
}
}
// ----------------------------------------------------------------------
/**
* Called when a game server indicates it has all the preload objects
*/
void PreloadManager::preloadCompleteOnServer(uint32 serverId)
{
DEBUG_REPORT_LOG(ConfigPlanetServer::getLogPreloading(),("Preload is finished on server %lu (planet %s)\n",serverId, Scene::getInstance().getSceneId().c_str()));
PreloadServerId const preloadId = getPreloadServerId(serverId);
m_serversWaiting->erase(preloadId);
// mark how long it took the server to load
ServerMapType::iterator i = m_serverMap->find(preloadId);
if ((i != m_serverMap->end()) && (i->second.m_loadTime == -1))
i->second.m_loadTime = std::max(static_cast<int>(0), static_cast<int>(time(0) - i->second.m_timeLoadStarted));
if (isPreloadComplete())
{
if (ConfigPlanetServer::getEnableStartupCreateProxies())
{
Scene::getInstance().createAllProxies();
}
DEBUG_REPORT_LOG(ConfigPlanetServer::getLogPreloading(),("Preloading is finished on all servers for %s.\n", Scene::getInstance().getSceneId().c_str()));
PlanetServer::getInstance().preloadCompleteOnAllServers();
}
}
// ----------------------------------------------------------------------
/**
* Finds the preload game server for the specified spot.
*/
PreloadServerId PreloadManager::getPreloadGameServer(int x, int z)
{
PreloadServerId bestSoFar = 0;
int bestDistance = 0;
for (std::vector<PreloadListData>::const_iterator item=m_preloadList->begin(); item!=m_preloadList->end(); ++item)
{
if (item->m_cityServerId != 0)
{
int minX=Node::roundToNode(item->m_topLeftChunkX);
int minZ=Node::roundToNode(item->m_topLeftChunkZ);
int maxX=Node::roundToNode(item->m_bottomRightChunkX);
int maxZ=Node::roundToNode(item->m_bottomRightChunkZ);
if ((x >= minX) && (x < maxX) && (z >= minZ) && (z < maxZ))
return item->m_cityServerId;
}
if (item->m_wildernessServerId != 0)
{
// Pretend there is a "beacon" in the middle of the preload area
int beaconX=(item->m_topLeftChunkX + item->m_bottomRightChunkX) / 2;
int beaconZ=(item->m_topLeftChunkZ + item->m_bottomRightChunkZ) / 2;
int distanceToBeacon = ((x-beaconX)*(x-beaconX) + (z-beaconZ)*(z-beaconZ));
if (bestSoFar == 0 || distanceToBeacon < bestDistance)
{
bestDistance = distanceToBeacon;
bestSoFar = item->m_wildernessServerId;
}
}
}
return bestSoFar;
}
// ----------------------------------------------------------------------
/**
* Finds the closest operational game server to the specified spot. Used
* when the server specified in the preload list isn't available, because
* either it crashed or it hasn't started yet.
* Considers wilderness first, because city servers are probably more
* heavily loaded.
*/
uint32 PreloadManager::getClosestGameServer (int x, int z)
{
uint32 bestSoFar = 0;
int bestDistance = 0;
std::vector<PreloadListData>::const_iterator item;
for (item=m_preloadList->begin(); item!=m_preloadList->end(); ++item)
{
if (item->m_wildernessServerId != 0)
{
int beaconX=(item->m_topLeftChunkX + item->m_bottomRightChunkX) / 2;
int beaconZ=(item->m_topLeftChunkZ + item->m_bottomRightChunkZ) / 2;
int distanceToBeacon = ((x-beaconX)*(x-beaconX) + (z-beaconZ)*(z-beaconZ));
uint32 realServerId = getRealServerId(item->m_wildernessServerId);
if ((realServerId != 0) && (bestSoFar == 0 || distanceToBeacon < bestDistance))
{
bestDistance = distanceToBeacon;
bestSoFar = realServerId;
}
}
}
if (bestSoFar==0)
{
// No wilderness servers. Try city servers
for (item=m_preloadList->begin(); item!=m_preloadList->end(); ++item)
{
if (item->m_cityServerId != 0)
{
int beaconX=(item->m_topLeftChunkX + item->m_bottomRightChunkX) / 2;
int beaconZ=(item->m_topLeftChunkZ + item->m_bottomRightChunkZ) / 2;
int distanceToBeacon = ((x-beaconX)*(x-beaconX) + (z-beaconZ)*(z-beaconZ));
uint32 realServerId = getRealServerId(item->m_cityServerId);
if ((realServerId != 0) && (bestSoFar == 0 || distanceToBeacon < bestDistance))
{
bestDistance = distanceToBeacon;
bestSoFar = realServerId;
}
}
}
}
return bestSoFar; // returning 0 is possible
}
// ----------------------------------------------------------------------
/**
* Adds the loadbeacon locations to a PopulationList structure.
*/
void PreloadManager::updatePopulationList(PopulationList &theList) const
{
for (std::vector<PreloadListData>::const_iterator item=m_preloadList->begin(); item!=m_preloadList->end(); ++item)
{
int chunkX=(item->m_topLeftChunkX + item->m_bottomRightChunkX) / 2;
int chunkZ=(item->m_topLeftChunkZ + item->m_bottomRightChunkZ) / 2;
theList.setPopulation(Scene::getInstance().getSceneId(),chunkX, chunkZ, Scene::getInstance().getServerPopulationByLocation(chunkX, chunkZ));
}
}
// ----------------------------------------------------------------------
PreloadServerId PreloadManager::getPreloadServerId(uint32 realServerId) const
{
for (ServerMapType::iterator i=m_serverMap->begin(); i!=m_serverMap->end(); ++i)
if (i->second.m_actualServerId == realServerId)
return i->first;
return 0;
}
// ----------------------------------------------------------------------
bool PreloadManager::isPreloadComplete() const
{
return (m_listReceived && m_serversWaiting->empty());
}
// ----------------------------------------------------------------------
void PreloadManager::getDebugString(std::string &output) const
{
if (isPreloadComplete())
output="finished";
else
{
output="loading";
for (ServersWaitingType::const_iterator i=m_serversWaiting->begin(); i!=m_serversWaiting->end(); ++i)
{
uint32 realServerId=0;
int loadTime=0;
ServerMapType::const_iterator j=m_serverMap->find(*i);
if (j!=m_serverMap->end())
{
realServerId=j->second.m_actualServerId;
if (j->second.m_loadTime != -1)
loadTime = j->second.m_loadTime;
else
loadTime = time(0) - j->second.m_timeLoadStarted;
}
char temp[100];
sprintf(temp," %lu-%ds (%lu)",*i,loadTime,realServerId);
output+=temp;
}
}
}
// ----------------------------------------------------------------------
uint32 PreloadManager::getRealServerId(PreloadServerId preloadServerId) const
{
ServerMapType::iterator i=m_serverMap->find(preloadServerId);
if (i!=m_serverMap->end())
return i->second.m_actualServerId;
return 0;
}
// ======================================================================
@@ -0,0 +1,88 @@
// ======================================================================
//
// PreloadManager.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_PreloadManager_H
#define INCLUDED_PreloadManager_H
// ======================================================================
#include "Singleton/Singleton2.h"
// ======================================================================
class PopulationList;
typedef uint32 PreloadServerId; // each server has a id from the preload list, which isn't the same as its processid. Typedef to make the code easier to read.
class PreloadListData
{
public:
int m_topLeftChunkX;
int m_topLeftChunkZ;
int m_bottomRightChunkX;
int m_bottomRightChunkZ;
PreloadServerId m_cityServerId;
PreloadServerId m_wildernessServerId;
};
class PreloadServerInformation
{
public:
uint32 m_actualServerId;
time_t m_timeLoadStarted;
int m_loadTime;
};
// ======================================================================
class PreloadManager : public Singleton2<PreloadManager>
{
public:
PreloadManager();
virtual ~PreloadManager();
public:
bool onGameServerReady (uint32 serverId, PreloadServerId preloadServerId);
void handlePreloadList ();
void removeGameServer (uint32 serverId);
void preloadCompleteOnServer (uint32 serverId);
uint32 getClosestGameServer (int x, int z);
PreloadServerId getPreloadGameServer (int x, int z);
void updatePopulationList (PopulationList &theList) const;
bool isPreloadComplete () const;
PreloadServerId getPreloadServerId (uint32 realServerId) const;
uint32 getRealServerId (PreloadServerId preloadServerId) const;
void getDebugString (std::string &output) const;
typedef stdmap<PreloadServerId, PreloadServerInformation>::fwd ServerMapType;
ServerMapType const * getServerMap () const;
private:
void sendPreloadsToGameServer (uint32 realServerId, PreloadServerId preloadServerId) const;
private:
ServerMapType *m_serverMap; // map of server id in preload list ---> actual server id
typedef stdvector<PreloadListData>::fwd PreloadListType;
PreloadListType *m_preloadList;
typedef stdset<PreloadServerId>::fwd ServersWaitingType;
ServersWaitingType *m_serversWaiting; // set of servers (by list id, not actual id) that still need preloads.
bool m_listReceived;
};
//-----------------------------------------------------------------------
inline PreloadManager::ServerMapType const * PreloadManager::getServerMap () const
{
return m_serverMap;
}
// ======================================================================
#endif
@@ -0,0 +1,582 @@
// ======================================================================
//
// Node.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "FirstPlanetServer.h"
#include "QuadtreeNode.h"
#include <stdio.h>
#include "ConfigPlanetServer.h"
#include "PlanetProxyObject.h"
#include "PlanetServer.h"
#include "PreloadManager.h"
#include "Scene.h"
#include "WatcherConnection.h"
#include "sharedFoundation/ExitChain.h"
#include "sharedFoundation/MemoryBlockManager.h"
#include "sharedNetworkMessages/PlanetNodeStatusMessage.h"
#include "sharedLog/Log.h"
//===================================================================
MemoryBlockManager* Node::memoryBlockManager;
// ======================================================================
/**
* Create a new spatial subdivision node.
*/
Node::Node(int x, int z) :
m_objectList(),
m_subscriptionList(),
m_preferredServer(0),
m_preloadServerId(0),
m_loaded(false),
m_isBorder(false),
m_x(x),
m_z(z)
{
WARNING_DEBUG_FATAL((x!=roundToNode(x)) || (z!=roundToNode(z)),("Creating node %s, coordinates not on a node boundary.",getDebugNodeString().c_str()));
}
// ----------------------------------------------------------------------
/**
* Places the object in this node and notifies servers as appropriate.
*
* @param newObject The object to add
*/
void Node::addObject(PlanetProxyObject *newObject)
{
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",("Adding object %s to node %s",newObject->getObjectId().getValueString().c_str(),getDebugNodeString().c_str()));
WARNING_DEBUG_FATAL(!m_loaded,("Attempt to place an object in an unloaded node."));
WARNING_DEBUG_FATAL(newObject->getObjectId() == NetworkId::cms_invalid,("Attempt to place object 0 in a node."));
m_objectList.push_back(newObject);
// We don't send add proxy messages here, because PlanetProxyObject::move() does that.
}
// ----------------------------------------------------------------------
/**
* Remove an object from the node.
*/
void Node::removeObject(const PlanetProxyObject *oldObject)
{
NOT_NULL(oldObject);
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",("Removing object %s from node %s",oldObject->getObjectId().getValueString().c_str(),getDebugNodeString().c_str()));
ObjectListType::iterator i;
for (i=m_objectList.begin();i!=m_objectList.end();++i)
if (*i==oldObject)
break;
if (i==m_objectList.end())
{
WARNING_DEBUG_FATAL(true,("Attempted to remove object %s that was not in the node.", oldObject->getObjectId().getValueString().c_str()));
return; //lint !e527 Unreachable (in debug mode only)
}
IGNORE_RETURN(m_objectList.erase(i));
}
// ----------------------------------------------------------------------
/**
* Subscribe a server to this node.
* Makes sure that the specifed server has proxies of the objects in the
* node and gets updates when new objects enter the node.
* @param serverId the server
* @param count How many objects are interested (Note: 0 is a legal value.
* It means that we want the server to know about this node, but there
* aren't any interested objects nearby yet.)
*/
void Node::subscribeServer(uint32 serverId, int count)
{
WARNING_DEBUG_FATAL(serverId==0,("Programmer bug: Server 0 passed to subscribeServer"));
WARNING_DEBUG_FATAL(count < 0,("Programmer bug: Passed negative count to subscribeServer"));
bool newSub=false;
if (!m_loaded)
{
load();
}
SubscriptionListType::iterator i=m_subscriptionList.find(serverId);
if (i!=m_subscriptionList.end())
{
((*i).second)+=count;
}
else
{
newSub = true;
m_subscriptionList[serverId]=count;
for (ObjectListType::iterator j=m_objectList.begin(); j!=m_objectList.end(); ++j)
{
if (serverId!=(*j)->getAuthoritativeServer() && (*j)->getContainedBy() == NetworkId::cms_invalid)
{
(*j)->sendAddProxy(serverId);
}
}
}
if (PlanetServer::getInstance().isWatcherPresent())
{
outputStatusToAll();
}
if (ConfigPlanetServer::getLogChunkLoading())
{
if (newSub)
LOG("ChunkLoading",("Node %s Server %lu new subscription, count %i",getDebugNodeString().c_str(), serverId, m_subscriptionList[serverId]));
else
LOG("ChunkLoading",("Node %s Server %lu subscription count changed by %i to %i",getDebugNodeString().c_str(), serverId, count, m_subscriptionList[serverId]));
}
}
// ----------------------------------------------------------------------
/**
* Decrease the count of objects on a server that are interested in this
* node. If the count reaches 0, the subscription is kept, but
* the load balancing algorithms may remove it later.
*/
void Node::unsubscribeServer(uint32 serverId, int count, bool clearIfZero)
{
WARNING_DEBUG_FATAL(serverId==0,("Programmer bug: Server 0 passed to unsubscribeServer"));
WARNING_DEBUG_FATAL(count < 0,("Programmer bug: Passed negative count to unsubscribeServer"));
bool cleared=false;
SubscriptionListType::iterator i=m_subscriptionList.find(serverId);
WARNING(i==m_subscriptionList.end(),("Attempted to unsubscribe server %i that was not subscribed to node %s.",serverId,getDebugNodeString().c_str()));
if (i!=m_subscriptionList.end())
{
i->second-=count;
if (i->second < 0)
{
WARNING(true,("Programmer bug: Subscription count for server %i on node %s went negative.",serverId,getDebugNodeString().c_str()));
i->second = 0;
}
if (clearIfZero && i->second == 0 && m_preferredServer != serverId)
{
cleared=true;
unproxyAllObjects(serverId);
m_subscriptionList.erase(i);
if (PlanetServer::getInstance().isWatcherPresent())
{
outputStatusToAll();
}
}
}
if (ConfigPlanetServer::getLogChunkLoading())
{
if (cleared)
LOG("ChunkLoading",("Node %s Server %lu unsubscribed",getDebugNodeString().c_str(), serverId));
else
LOG("ChunkLoading",("Node %s Server %lu subscription count changed by -%i to %i",getDebugNodeString().c_str(), serverId, count, m_subscriptionList[serverId]));
}
}
// ----------------------------------------------------------------------
/**
* Helper function. Removes the proxies on the specified server.
* Does not update the subscription list.
*/
void Node::unproxyAllObjects(uint32 serverId)
{
for (ObjectListType::iterator j=m_objectList.begin(); j!=m_objectList.end(); ++j)
(*j)->sendRemoveProxy(serverId);
}
// ----------------------------------------------------------------------
/**
* Load a node from the database.
* Marks the node as loaded, and instructs the database to put the objects
* in the node on a particular game server. The game server will report
* the objects back to us after they get loaded.
*/
void Node::load()
{
if (m_loaded)
return;
if (m_preferredServer == 0)
pickPreferredServer();
if (m_preferredServer == 0)
{
WARNING_DEBUG_FATAL(true, ("load failed for node %s because m_preferredServer is 0",getDebugNodeString().c_str()));
return;
}
m_loaded=true;
bool sendRequest=true; // in certain modes, we don't need to check the DB for objects
if (PlanetServer::getInstance().isInTutorialMode())
sendRequest=false;
if (PlanetServer::getInstance().isInSpaceMode() && !(m_x == 0 && m_z == 0)) // only load (0,0) in space
sendRequest=false;
if (sendRequest)
{
PlanetServer::getInstance().sendChunkRequest(m_preferredServer, m_x,m_z);
if (ConfigPlanetServer::getLogChunkLoading())
LOG("ChunkLoading", ("RequestChunk: Node %s Server %i",getDebugNodeString().c_str(),m_preferredServer));
}
subscribeServer(m_preferredServer,0);
}
// ----------------------------------------------------------------------
/**
* Helper function: picks the best server for this node and puts it
* into m_preferredServer.
*/
void Node::pickPreferredServer()
{
m_preferredServer = PreloadManager::getInstance().getRealServerId(m_preloadServerId);
if (m_preferredServer == 0)
m_preferredServer = PreloadManager::getInstance().getClosestGameServer(m_x, m_z);
WARNING_DEBUG_FATAL(m_preferredServer==0,("Programmer bug: Node::pickPreferredServer could not pick a server"));
}
// ----------------------------------------------------------------------
/**
* Get a string listing the coordinates of this node.
* For debugging, FATALs, etc.
*/
std::string Node::getDebugNodeString() const
{
char buffer[100];
snprintf(buffer,sizeof(buffer)-1,"%s (%i,%i)",Scene::getInstance().getSceneId().c_str(),m_x,m_z);
buffer[sizeof(buffer)-1]='\0';
return std::string(buffer);
}
// ----------------------------------------------------------------------
/**
* Output the status of the node to the PlanetWatch tool.
*/
void Node::outputStatus(WatcherConnection &conn) const
{
std::vector<uint32> servers;
std::vector<int> subscriptionCount;
for (SubscriptionListType::const_iterator i=m_subscriptionList.begin(); i!=m_subscriptionList.end(); ++i)
{
servers.push_back((*i).first);
subscriptionCount.push_back((*i).second);
WARNING_DEBUG_FATAL((*i).first==0,("Found a 0 in subscrption list (where did it come from?)"));
}
conn.addNodeUpdate(m_x,m_z,m_loaded, servers, subscriptionCount);
}
// ----------------------------------------------------------------------
void Node::outputStatusToAll() const
{
const PlanetServer::WatcherList &connections = PlanetServer::getInstance().getWatchers();
for (PlanetServer::WatcherList::const_iterator i= connections.begin(); i!=connections.end(); ++i)
{
outputStatus(**i);
}
}
// ----------------------------------------------------------------------
/**
* Set up a memory pool for QuadTreeNodes.
*/
void Node::install()
{
memoryBlockManager = new MemoryBlockManager("Node::memoryBlockManager", true, sizeof(Node), 0, 0, 0);
ExitChain::add(&remove, "Node::remove");
}
// ----------------------------------------------------------------------
void Node::remove()
{
WARNING_DEBUG_FATAL(!memoryBlockManager,("Node is not installed"));
delete memoryBlockManager;
memoryBlockManager = 0;
}
// ----------------------------------------------------------------------
void * Node::operator new(size_t size)
{
UNREF(size);
WARNING_DEBUG_FATAL(!memoryBlockManager,("Node is not installed"));
// do not try to alloc a descendant class with this allocator
WARNING_DEBUG_FATAL(size != sizeof(Node),("bad size"));
return memoryBlockManager->allocate();
}
// ----------------------------------------------------------------------
void Node::operator delete(void* pointer)
{
WARNING_DEBUG_FATAL(!memoryBlockManager,("Node is not installed"));
memoryBlockManager->free(pointer);
}
// ----------------------------------------------------------------------
/**
* Load the node onto the specified server.
*/
void Node::load(uint32 serverId)
{
if (m_loaded)
{
WARNING_DEBUG_FATAL(m_loaded,("Programmer bug: called load on Node %s,.which was already loaded",getDebugNodeString().c_str()));
return;
}
m_preferredServer = serverId;
load();
}
// ----------------------------------------------------------------------
void Node::getServers(std::vector<uint32> &serverList) const
{
for (SubscriptionListType::const_iterator i=m_subscriptionList.begin(); i!=m_subscriptionList.end(); ++i)
{
serverList.push_back(i->first);
}
}
// ----------------------------------------------------------------------
/**
* Migrate the objects to the specfied server, and get rid of any subscribed
* servers that aren't interested in the node anymore
*/
void Node::migrateToServer(uint32 newServer)
{
WARNING_DEBUG_FATAL (!m_loaded,("Programmer bug: called migrateToServer(%i) on unloaded node %s",newServer,getDebugNodeString().c_str()));
if (m_preferredServer == newServer)
return;
subscribeServer(newServer,0);
m_preferredServer = newServer;
for (ObjectListType::iterator i=m_objectList.begin(); i!=m_objectList.end(); ++i)
{
(*i)->unsubscribeSurroundingNodes(true);
(*i)->changeAuthority(newServer, false, false);
(*i)->subscribeSurroundingNodes();
}
// remove any zero subscriptions:
std::vector<uint32> unsubscribeList;
for (SubscriptionListType::iterator subscription=m_subscriptionList.begin(); subscription!=m_subscriptionList.end(); ++subscription)
if (subscription->second == 0 && subscription->first != newServer)
unsubscribeList.push_back(subscription->first);
for (std::vector<uint32>::iterator s=unsubscribeList.begin(); s!=unsubscribeList.end(); ++s)
{
unproxyAllObjects(*s);
IGNORE_RETURN(m_subscriptionList.erase(*s));
}
if (PlanetServer::getInstance().isWatcherPresent())
{
outputStatusToAll();
}
if (ConfigPlanetServer::getLogChunkLoading())
LOG("ChunkLoading",("Node %s Migrate to server %lu",getDebugNodeString().c_str(), newServer));
}
// ----------------------------------------------------------------------
/**
* Check that this node is assigned to the right server, and fix it if
* it isn't.
*/
void Node::checkServerAssignment()
{
if (!m_loaded)
return;
uint32 bestServer = PreloadManager::getInstance().getRealServerId(m_preloadServerId);
if (bestServer==0)
return;
if (m_preferredServer != bestServer)
migrateToServer(bestServer);
}
// ----------------------------------------------------------------------
void Node::handleCrash(uint32 crashedServer, std::vector<PlanetProxyObject*> &subscriptionFixups)
{
bool wasSubscribed = false;
{
for (SubscriptionListType::iterator i=m_subscriptionList.begin(); i!=m_subscriptionList.end();)
{
if (i->first == crashedServer)
{
m_subscriptionList.erase(i++);
wasSubscribed = true;
}
else
{
++i;
}
}
}
if (m_preferredServer == crashedServer)
{
if (!m_subscriptionList.empty())
{
// pick a new server for this node and move the objects
uint32 newServer = m_subscriptionList.begin()->first;
m_preferredServer = newServer;
WARNING_DEBUG_FATAL(newServer == crashedServer,("Programmer bug: crashed server was still in the subscription list after it was supposedly removed."));
}
else
{
// no other server has proxies. Unload the node.
m_loaded = false;
m_preferredServer = 0;
for (ObjectListType::iterator i=m_objectList.begin(); i!=m_objectList.end(); ++i)
{
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",
("Handling crash: Dropping object %s because node %s was dropped",
(*i)->getObjectId().getValueString().c_str(),getDebugNodeString().c_str()));
Scene::getInstance().removeObjectFromMap((*i)->getObjectId(),false);
delete *i;
}
m_objectList.clear();
}
}
{
for (ObjectListType::iterator i=m_objectList.begin(); i!=m_objectList.end(); ++i)
{
if ((*i)->getContainedBy() == NetworkId::cms_invalid)
{
if (crashedServer==(*i)->getAuthoritativeServer())
{
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",
("Handling crash: moving object %s from server %lu to server %lu",
(*i)->getObjectId().getValueString().c_str(),crashedServer,m_preferredServer));
(*i)->changeAuthority(m_preferredServer, true, false);
(*i)->sendRemoveProxy(crashedServer);
if ((*i)->getInterestRadius() > 0)
subscriptionFixups.push_back(*i);
}
else
{
// tell objects they don't have a proxy on this server anymore
if (wasSubscribed)
(*i)->sendRemoveProxy(crashedServer);
}
}
}
}
if (PlanetServer::getInstance().isWatcherPresent())
{
outputStatusToAll();
}
}
// ----------------------------------------------------------------------
bool Node::isBorderNode() const
{
WARNING_DEBUG_FATAL(getPreferredServer()==0,("Programmer bug: called isBorderNode() on node %s, which has 0 for its preferred server.",getDebugNodeString().c_str()));
if (m_subscriptionList.size() < 2)
{
m_isBorder = false;
return false;
}
if (m_isBorder)
return true;
int maxX=m_x+getNodeSize();
int maxZ=m_z+getNodeSize();
for (int x=m_x-getNodeSize();x<=maxX;x+=getNodeSize())
for (int z=m_z-getNodeSize();z<=maxZ;z+=getNodeSize())
if (!(x==m_x && z==m_z))
{
const Node *node = Scene::getInstance().findNodeByRoundedPositionConst(x,z);
if (node && node->getPreferredServer()!=0 && node->getPreferredServer() != getPreferredServer())
{
m_isBorder = true;
return true;
}
}
return false;
}
// ----------------------------------------------------------------------
bool Node::isServerSubscribed(uint32 serverId) const
{
return (m_subscriptionList.find(serverId)!=m_subscriptionList.end());
}
// ----------------------------------------------------------------------
void Node::setPreloadServerId(PreloadServerId preloadServerId)
{
m_preloadServerId = preloadServerId;
}
// ----------------------------------------------------------------------
PreloadServerId Node::getPreloadServerId() const
{
return m_preloadServerId;
}
// ======================================================================
@@ -0,0 +1,119 @@
// ======================================================================
//
// Node.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_Node_H
#define INCLUDED_Node_H
// ======================================================================
#include <list>
#include <map>
#include <vector>
#include <set>
class PlanetProxyObject;
class MemoryBlockManager;
class WatcherConnection;
// ======================================================================
class Node
{
public:
typedef std::map<uint32, int> SubscriptionListType;
public:
Node(int x, int z);
public:
void addObject (PlanetProxyObject *newObject);
void checkServerAssignment();
void handleCrash (uint32 crashedServer, stdvector<PlanetProxyObject*>::fwd &subscriptionFixups);
void load ();
void migrateToServer (uint32 newServerId);
void load (uint32 serverId);
void removeObject (const PlanetProxyObject *object);
void subscribeServer (uint32 serverId, int count);
void unsubscribeServer (uint32 serverId, int count, bool clearIfZero);
void setPreloadServerId(PreloadServerId preloadServerId);
public:
static int getNodeSize ();
static int roundToNode (int coordinate);
bool isBorderNode () const;
bool isLoaded () const;
bool isServerSubscribed(uint32 serverId) const;
std::string getDebugNodeString() const;
uint32 getPreferredServer() const;
PreloadServerId getPreloadServerId() const;
void getServers (std::vector<uint32> &serverList) const;
void outputStatus (WatcherConnection &conn) const;
void outputStatusToAll () const;
public:
static void install ();
static void remove ();
static void* operator new (size_t size);
static void operator delete (void* pointer);
private:
void pickPreferredServer();
void unproxyAllObjects (uint32 serverId);
private:
typedef std::vector<PlanetProxyObject*> ObjectListType;
private:
ObjectListType m_objectList;
SubscriptionListType m_subscriptionList;
uint32 m_preferredServer;
PreloadServerId m_preloadServerId;
bool m_loaded;
mutable bool m_isBorder;
/**
* Coordinates of the node are represented by the minimum X and minimum Z coordinates.
*/
int m_x, m_z;
static MemoryBlockManager* memoryBlockManager;
private:
Node(); //disable
};
// ======================================================================
inline bool Node::isLoaded() const
{
return m_loaded;
}
// ----------------------------------------------------------------------
inline int Node::roundToNode(int coordinate)
{
return (coordinate >= 0) ? (coordinate/getNodeSize())*getNodeSize() : ((coordinate-getNodeSize()+1)/getNodeSize())*getNodeSize(); //lint !e834 // Lint doesn't like a-b+c
}
// ----------------------------------------------------------------------
inline int Node::getNodeSize()
{
return 100;
}
// ----------------------------------------------------------------------
inline uint32 Node::getPreferredServer() const
{
return m_preferredServer;
}
// ======================================================================
#endif
@@ -0,0 +1,674 @@
// ======================================================================
//
// Scene.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "FirstPlanetServer.h"
#include "Scene.h"
#include "ConfigPlanetServer.h"
#include "GameServerConnection.h"
#include "GameServerData.h"
#include "PlanetProxyObject.h"
#include "PreloadManager.h"
#include "QuadtreeNode.h"
#include "serverNetworkMessages/PlanetRemoveObject.h"
#include "serverNetworkMessages/PopulationListMessage.h"
#include "serverNetworkMessages/UpdateObjectOnPlanetMessage.h"
#include "serverUtility/PopulationList.h"
#include "sharedFoundation/ExitChain.h"
#include "sharedLog/Log.h"
#include "sharedNetworkMessages/GenericValueTypeMessage.h"
#include "sharedUtility/LocationManager.h"
// ======================================================================
Scene::Scene() :
Singleton2<Scene>(),
MessageDispatch::Receiver(),
m_sceneId(),
m_objects(),
m_deletedObjects(),
m_nodeMap(),
m_populationList(new PopulationList),
m_populationCountTimer(static_cast<float>(ConfigPlanetServer::getPopulationCountTime())),
m_maxCoordinate(0)
{
ExitChain::add(&remove, "Scene::remove");
connectToMessage("GameConnectionClosed");
connectToMessage("UpdateObjectOnPlanetMessage");
connectToMessage("PlanetRemoveObject");
connectToMessage("ForceLoadArea");
}
// ----------------------------------------------------------------------
/**
* Set the scene ID. Make this part of the constructor if we ever make
* this a non-singleton class.
*/
void Scene::setSceneId(const std::string &sceneId)
{
m_sceneId=sceneId;
//-- tell the LocationManager what planet we're on
LocationManager::setPlanetName (sceneId.c_str ());
}
// ----------------------------------------------------------------------
/**
* Called to add an object to the scene. Scene takes ownership
* of the object and will be resposible for deleting it.
*/
void Scene::addObject(PlanetProxyObject *newObject)
{
m_objects[newObject->getObjectId()]=newObject;
newObject->addServerStatistics();
}
// ----------------------------------------------------------------------
PlanetProxyObject *Scene::findObjectByID(const NetworkId &objectID) const
{
ObjectMapType::const_iterator i=m_objects.find(objectID);
if (i==m_objects.end())
return NULL;
else
return ((*i).second);
}
// ----------------------------------------------------------------------
bool Scene::isObjectLoaded(const NetworkId &networkId) const
{
return m_objects.find(networkId) != m_objects.end();
}
// ----------------------------------------------------------------------
void Scene::receiveMessage(const MessageDispatch::Emitter & source, const MessageDispatch::MessageBase & message)
{
const GameServerConnection *gameServer=dynamic_cast<const GameServerConnection*>(&source);
WARNING_DEBUG_FATAL(gameServer==0,("Source was NULL or source was not a GameServerConnection."));
if (message.isType("GameConnectionClosed"))
{
DEBUG_REPORT_LOG(true, ("Handling a game server crash for server %lu\n", gameServer->getProcessId()));
handleCrash(gameServer->getProcessId());
}
else if (message.isType("UpdateObjectOnPlanetMessage"))
{
Archive::ReadIterator ri = static_cast<const GameNetworkMessage &>(message).getByteStream().begin();
UpdateObjectOnPlanetMessage msg(ri);
int interestRadius = msg.getInterestRadius();
if(msg.getWatched() && interestRadius == 0)
interestRadius = 1;
if (m_deletedObjects.find(msg.getObjectId())!=m_deletedObjects.end())
{
DEBUG_REPORT_LOG(true,("Ignoring update for object %s which has been removed.\n",msg.getObjectId().getValueString().c_str()));
}
else
{
NetworkId container(msg.getTopmostContainer());
if (container==msg.getObjectId()) // game server sends container == objectId if the object is not contained
container=NetworkId::cms_invalid;
bool processUpdate = true;
if (container != NetworkId::cms_invalid)
{
PlanetProxyObject const *const containerObject = findObjectByID(container);
if (containerObject)
{
if (containerObject->getAuthoritativeServer() != gameServer->getProcessId())
{
// This update message came from a server that is not
// authoritative for the container of this object. This
// can happen when the planet server is in control of
// switching the container's authority but is not in
// charge of changing the container content's authority.
// This happens to the rider of a mount when the mount
// switches authority.
processUpdate = false;
}
}
}
if (processUpdate)
{
PlanetProxyObject *theObject=findObjectByID(msg.getObjectId());
if (!theObject)
{
// this is a new object
theObject=new PlanetProxyObject(msg.getObjectId());
addObject(theObject);
}
theObject->onReceivedMessageFromServer(gameServer->getProcessId());
theObject->update(msg.getX(), msg.getY(), msg.getZ(), container, gameServer->getProcessId(), interestRadius, msg.getObjectTypeTag(), msg.getLevel(), msg.getHibernating(), msg.getTemplateCrc(), msg.getAiActivity(), msg.getCreationType());
//-- handle updating LocationManager
if (msg.getLocationReservationRadius () > 0.f)
LocationManager::updateObject (msg.getObjectId (), msg.getX (), msg.getZ (), msg.getLocationReservationRadius ());
}
}
}
else if (message.isType("PlanetRemoveObject"))
{
Archive::ReadIterator ri = static_cast<const GameNetworkMessage &>(message).getByteStream().begin();
PlanetRemoveObject msg(ri);
handleRemoveObject(msg.getObjectId());
//-- handle updating LocationManager
LocationManager::removeObject (msg.getObjectId ());
}
else if (message.isType("ForceLoadArea"))
{
Archive::ReadIterator ri = static_cast<const GameNetworkMessage &>(message).getByteStream().begin();
GenericValueTypeMessage<std::pair<uint32, std::pair<std::pair<float, float>, std::pair<float, float> > > > const msg(ri);
handleForceLoadArea(
msg.getValue().first,
static_cast<int>(msg.getValue().second.first.first),
static_cast<int>(msg.getValue().second.first.second),
static_cast<int>(msg.getValue().second.second.first),
static_cast<int>(msg.getValue().second.second.second));
}
else
{
DEBUG_REPORT_LOG(true,("Scene.cpp received an unidentified message.\n"));
}
}
// ----------------------------------------------------------------------
void Scene::subscribeServer(uint32 server, int x, int z, int interestRadius, int count)
{
NodeListType nodelist;
findIntersection(nodelist,x,z,interestRadius);
for (NodeListType::iterator i=nodelist.begin(); i!=nodelist.end(); ++i)
{
(*i)->subscribeServer(server, count);
}
}
// ----------------------------------------------------------------------
/**
* Given coordinates, return the node that encloses those coordinates.
* Creates the node if it doesn't exist already.
*/
Node *Scene::findNodeByPosition(int x, int z)
{
return findNodeByRoundedPosition(Node::roundToNode(x),Node::roundToNode(z));
}
// ----------------------------------------------------------------------
/**
* Given coordinates, return a const pointer to the node that encloses
* those coordinates. Will not create new nodes, so it may return NULL.
*/
const Node *Scene::findNodeByPositionConst(int x, int z) const
{
return findNodeByRoundedPositionConst(Node::roundToNode(x),Node::roundToNode(z));
}
// ----------------------------------------------------------------------
/**
* Given coordinates that are known to be a node boundary, return the node.
* Creates the node if it doesn't exist already.
*/
Node *Scene::findNodeByRoundedPosition(int x, int z)
{
DEBUG_FATAL((x!=Node::roundToNode(x)) || (z!=Node::roundToNode(z)),("Parameters to findNodeByRoundedPosistion weren't rounded."));
Node *result=m_nodeMap[Coordinates(x,z)];
if (!result)
{
result=new Node(x,z);
m_nodeMap[Coordinates(x,z)]=result;
}
return result;
}
// ----------------------------------------------------------------------
/**
* Given coordinates that are known to be a node boundary, return a const pointer
* to the node. Does not create new nodes, so may return NULL.
*/
const Node *Scene::findNodeByRoundedPositionConst(int x, int z) const
{
WARNING_DEBUG_FATAL((x!=Node::roundToNode(x)) || (z!=Node::roundToNode(z)),("Parameters to findNodeByRoundedPosistionConst weren't rounded."));
NodeMapType::const_iterator i=m_nodeMap.find(Coordinates(x,z));
if (i!=m_nodeMap.end())
return (*i).second;
else
return NULL;
}
// ----------------------------------------------------------------------
/**
* Given coordinates and a radius, find a set of nodes that contains the circle.
*
* May return some nodes that don't contain any part of the circle, but
* is guaranteed to return at least every node that the circle intersects.
* Will add nodes if they don't exist.
*/
void Scene::findIntersection(NodeListType &results,int x, int z, int radius)
{
int minX=Node::roundToNode(x-radius);
int minZ=Node::roundToNode(z-radius);
int maxX=Node::roundToNode(x+radius);
int maxZ=Node::roundToNode(z+radius);
int nodeSize=Node::getNodeSize();
for (int loopX=minX; loopX <= maxX; loopX+=nodeSize)
for (int loopZ=minZ; loopZ <= maxZ; loopZ+=nodeSize)
results.push_back(findNodeByRoundedPosition(loopX,loopZ));
}
// ----------------------------------------------------------------------
/**
* Removes an object from the list of objects.
*
* Places the object in a list of pending deletes. Further updates to
* this object will be ignored.
* Doesn't remove the object from the quadtree or notify any servers.
* This function should only be called by PlanetProxyObject::unload().
*
* @param objectId Object to remove.
* @param addToDeletedList true if we should remember that we deleted the object,
* false if not. Generally, we don't need to put the object in the deleted map
* if the game server initated the removal. If we initated it, we remember
* the object in the deleted map so that we ignore all updates to it until
* the game server acknowledges the removal.
*/
void Scene::removeObjectFromMap(const NetworkId &objectId, bool addToDeletedList)
{
ObjectMapType::iterator i=m_objects.find(objectId);
if (i==m_objects.end())
{
DEBUG_REPORT_LOG(true,("Requested removing object %s, but it was not in the list.\n",objectId.getValueString().c_str()));
}
else
{
m_objects.erase(i);
}
if (addToDeletedList)
IGNORE_RETURN(m_deletedObjects.insert(objectId));
}
// ----------------------------------------------------------------------
/**
* Handler for the PlanetRemoveObject message.
*/
void Scene::handleRemoveObject(const NetworkId &objectId)
{
DeletedSetType::iterator i=m_deletedObjects.find(objectId);
if (i!=m_deletedObjects.end())
{
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",("Removal of object %s confirmed.",objectId.getValueString().c_str()));
m_deletedObjects.erase(i);
}
else
{
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",("Removal of object %s initiated by GameServer.",objectId.getValueString().c_str()));
PlanetProxyObject *theObject=findObjectByID(objectId);
if (theObject)
{
theObject->unload(false);
if (theObject->getInterestRadius()>0)
theObject->unsubscribeSurroundingNodes(false);
delete theObject;
}
else
{
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",("Object %s was unknown. Removal request ignored.",objectId.getValueString().c_str()));
}
}
}
// ----------------------------------------------------------------------
/**
* Given an object, find which server it is on.
* Used by the login process, for example, to find where the building
* a player is in is loaded.
*/
uint32 Scene::getGameServerForObject(const NetworkId &object) const
{
ObjectMapType::const_iterator i=m_objects.find(object);
if (i!=m_objects.end())
{
const PlanetProxyObject *obj=(*i).second;
NOT_NULL(obj);
return obj->getAuthoritativeServer();
}
else
return 0;
}
// ----------------------------------------------------------------------
/**
* Output the status of the scene to a Watcher. (Call when a new watcher
* connects, for example.)
*/
void Scene::outputStatus(WatcherConnection &conn) const
{
for (NodeMapType::const_iterator i=m_nodeMap.begin(); i!=m_nodeMap.end(); ++i)
{
(*i).second->outputStatus(conn);
}
for (ObjectMapType::const_iterator j=m_objects.begin(); j!=m_objects.end(); ++j)
{
(*j).second->outputStatus(conn, false);
}
}
// ----------------------------------------------------------------------
Scene::~Scene()
{
for (NodeMapType::iterator i=m_nodeMap.begin(); i!=m_nodeMap.end(); ++i)
{
delete (*i).second;
(*i).second=0;
}
for (ObjectMapType::iterator j=m_objects.begin(); j!=m_objects.end(); ++j)
{
delete (*j).second;
(*j).second = 0;
}
}
// ----------------------------------------------------------------------
/**
* Every so often, check for nodes that can be unloaded. If any are found,
* unload one node each frame to avoid sending too many unloads to the
* game servers at the same time.
*/
void Scene::update(float time)
{
//-- Update population count
if (m_populationCountTimer.updateSubtract(time))
{
PreloadManager::getInstance().updatePopulationList(*m_populationList);
PopulationListMessage msg(*m_populationList);
PlanetServer::getInstance().sendToCentral(msg, true);
}
}
// ----------------------------------------------------------------------
/**
* For each node, record the preload server id.
*/
void Scene::assignPreloadsToNodes()
{
for (int x=-getMaxCoordinate(); x<= getMaxCoordinate(); x+=Node::getNodeSize())
{
for (int z=-getMaxCoordinate(); z<= getMaxCoordinate(); z+=Node::getNodeSize())
{
Node *node = findNodeByRoundedPosition(x,z);
node->setPreloadServerId(PreloadManager::getInstance().getPreloadGameServer(x,z));
}
}
}
// ----------------------------------------------------------------------
/**
* Check the map for any nodes that belong to the specified server, and
* load them. If they are already loaded, move them to the right server.
*/
void Scene::loadAllNodesForServer(uint32 server, PreloadServerId preloadServerId)
{
for (int x=-getMaxCoordinate(); x<= getMaxCoordinate(); x+=Node::getNodeSize())
{
for (int z=-getMaxCoordinate(); z<= getMaxCoordinate(); z+=Node::getNodeSize())
{
Node *node = findNodeByRoundedPosition(x,z);
if (node->getPreloadServerId()==preloadServerId)
{
if (ConfigPlanetServer::getLogChunkLoading())
LOG("ChunkLoading",("Node %s preload to server %lu",node->getDebugNodeString().c_str(), server));
if (!node->isLoaded())
node->load(server);
else
node->migrateToServer(server);
}
}
}
}
// ----------------------------------------------------------------------
/**
* Make sure that all nodes are on the server that they should be.
* Move any nodes that aren't. They could be on the wrong server due
* to server crashes, etc.
*/
void Scene::checkServerAssignments()
{
for (NodeMapType::iterator i=m_nodeMap.begin(); i!=m_nodeMap.end(); ++i)
i->second->checkServerAssignment();
}
// ----------------------------------------------------------------------
void Scene::handleCrash(uint32 gameServerId)
{
// wait for the next save before allowing new loads
if (ConfigPlanetServer::getRequestDbSaveOnGameServerCrash())
PlanetServer::getInstance().requestAndWaitForSave();
PreloadManager::getInstance().removeGameServer(gameServerId);
std::vector<PlanetProxyObject*> subscriptionFixups;
for (NodeMapType::iterator nodeMapIter = m_nodeMap.begin(); nodeMapIter != m_nodeMap.end(); ++nodeMapIter)
{
nodeMapIter->second->handleCrash(gameServerId, subscriptionFixups);
}
// These have to be done after all the nodes are examined, because otherwise it might think
// a server has proxies of the objects on a crashed node when it really doesn't
for (std::vector<PlanetProxyObject*>::iterator j=subscriptionFixups.begin(); j!=subscriptionFixups.end(); ++j)
(*j)->subscribeSurroundingNodes();
}
// ----------------------------------------------------------------------
int Scene::getServerPopulationByLocation(int x, int z) const
{
const Node *node=findNodeByPositionConst(x,z);
if (node && node->isLoaded())
{
uint32 server = node->getPreferredServer();
return PlanetServer::getInstance().getInterestCreatureObjectCountForServer(server);
}
else
return 0;
}
// ----------------------------------------------------------------------
bool Scene::requestSameServer(const NetworkId &id1, const NetworkId &id2)
{
PlanetProxyObject *obj1 = findObjectByID(id1);
PlanetProxyObject *obj2 = findObjectByID(id2);
if (!obj1 || !obj2)
return false;
if (!obj1->isAuthorityClean() || !obj2->isAuthorityClean())
return false;
uint32 server1 = obj1->getAuthoritativeServer();
uint32 server2 = obj2->getAuthoritativeServer();
if (server1 == server2)
return true;
if (!obj1->getNode() || !obj2->getNode())
return false;
uint32 preferredServer = obj1->getNode()->getPreferredServer();
if (obj2->getNode()->getPreferredServer() == preferredServer)
{
if (server1 == preferredServer)
{
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",("Moving object %s to server %lu, so that it is on the same server as %s",id2.getValueString().c_str(),server1,id1.getValueString().c_str()));
obj2->changeAuthorityAndSubscriptions(server1);
return true;
}
else if (server2 == preferredServer)
{
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",("Moving object %s to server %lu, so that it is on the same server as %s",id1.getValueString().c_str(),server2,id2.getValueString().c_str()));
obj1->changeAuthorityAndSubscriptions(server2);
return true;
}
}
if (obj2->wouldAuthorityBeOk(server1))
{
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",("Moving object %s to server %lu, so that it is on the same server as %s",id2.getValueString().c_str(),server1,id1.getValueString().c_str()));
obj2->changeAuthorityAndSubscriptions(server1);
return true;
}
if (obj1->wouldAuthorityBeOk(server2))
{
if (ConfigPlanetServer::getLogObjectLoading())
LOG("ObjectLoading",("Moving object %s to server %lu, so that it is on the same server as %s",id1.getValueString().c_str(),server2,id2.getValueString().c_str()));
obj1->changeAuthorityAndSubscriptions(server2);
return true;
}
// Neither server will work.
return false;
}
//------------------------------------------------------------------------------------------
bool Scene::requestAuthTransfer(const NetworkId &id1, uint32 newServer)
{
PlanetProxyObject *obj1 = findObjectByID(id1);
if (!obj1)
return false;
uint32 server1 = obj1->getAuthoritativeServer();
if (server1 == newServer)
return true;
if (obj1->wouldAuthorityBeOk(newServer))
{
obj1->changeAuthorityAndSubscriptions(newServer);
return true;
}
// Requested server cannot be used.
return false;
}
// ----------------------------------------------------------------------
void Scene::handleForceLoadArea(uint32 gameServerId, int x1, int z1, int x2, int z2)
{
typedef Node QuadTreeNode;
int const zStart = QuadTreeNode::roundToNode(static_cast<int>(z1));
int const xStart = QuadTreeNode::roundToNode(static_cast<int>(x1));
for (int nz = zStart; nz <= z2; nz += 100)
{
for (int nx = xStart; nx <= x2; nx += 100)
{
Node * const node = findNodeByPosition(nx, nz);
node->subscribeServer(gameServerId, 1);
}
}
}
// ----------------------------------------------------------------------
int Scene::getMaxCoordinate() const
{
if (m_maxCoordinate==0)
return 8000; // Assume largest possible map until m_maxCoordiate is set
return m_maxCoordinate;
}
// ----------------------------------------------------------------------
void Scene::setMapSize(int mapSize)
{
int maxCoordinate = Node::roundToNode(mapSize/2) + Node::getNodeSize();
if (m_maxCoordinate == 0)
m_maxCoordinate = maxCoordinate;
else
FATAL(m_maxCoordinate!=maxCoordinate,("Game servers for planet %s sent different sizes for the maps. Possible sizes are %i and %i", m_sceneId.c_str(), m_maxCoordinate, maxCoordinate));
}
// ----------------------------------------------------------------------
/**
* Create all the proxies that would ever be needed, in a single pass
*/
void Scene::createAllProxies()
{
static int const subscriptionRange = ConfigPlanetServer::getMaxInterestRadius() + Node::getNodeSize(); // The logic in PlanetProxyObject effectively creates an overlap area of interestRadius + nodeSize, so don't change this without changing the logic in PlanetProxyObject
for (int x=-getMaxCoordinate(); x<= getMaxCoordinate(); x+=Node::getNodeSize())
{
for (int z=-getMaxCoordinate(); z<= getMaxCoordinate(); z+=Node::getNodeSize())
{
Node * const node = findNodeByRoundedPosition(x,z);
uint32 serverId = NON_NULL(node)->getPreferredServer();
if (serverId!=0)
{
for (int subX=x-subscriptionRange; subX<= x+subscriptionRange; subX+=Node::getNodeSize())
{
for (int subZ=z-subscriptionRange; subZ<= z+subscriptionRange; subZ+=Node::getNodeSize())
{
NON_NULL(findNodeByRoundedPosition(subX, subZ))->subscribeServer(serverId, 0);
}
}
}
}
}
}
// ======================================================================
@@ -0,0 +1,142 @@
// ======================================================================
//
// Scene.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_Scene_H
#define INCLUDED_Scene_H
// ======================================================================
#include <hash_map>
#include <hash_set>
#include <string>
#include <set>
#include "sharedFoundation/NetworkId.h"
#include "sharedFoundation/Timer.h"
#include "sharedMessageDispatch/Receiver.h"
#include "Singleton/Singleton2.h"
#include "sharedMath/Vector.h"
class PlanetProxyObject;
class PopulationList;
class Node;
// ======================================================================
/**
* Organizes all data on the Planet server relating to a particular scene.
*/
class Scene : public Singleton2<Scene>, public MessageDispatch::Receiver
{
public:
// Some functions return lists of nodes
typedef std::vector<Node*> NodeListType;
public:
Scene();
~Scene();
public:
virtual void receiveMessage (const MessageDispatch::Emitter & source, const MessageDispatch::MessageBase & message);
Node * findNodeByPosition (int x, int z);
Node * findNodeByRoundedPosition (int x, int z);
void addObject (PlanetProxyObject *newObject);
void findIntersection (NodeListType &results,int x, int z, int radius);
void assignPreloadsToNodes ();
void loadAllNodesForServer (uint32 server, PreloadServerId preloadServerId);
void checkServerAssignments ();
void removeObjectFromMap (const NetworkId &objectId, bool addToDeletedList);
void setSceneId (const std::string &sceneId);
void subscribeServer (uint32 server, int x, int z, int interestRadius, int count=1);
void update (float time);
bool requestSameServer (const NetworkId &id1, const NetworkId &id2);
bool requestAuthTransfer (const NetworkId &id1, uint32 newServer);
void setMapSize (int mapSize);
void createAllProxies ();
public:
const Node * findNodeByPositionConst (int x, int z) const;
const Node * findNodeByRoundedPositionConst (int x, int z) const;
bool isObjectLoaded (const NetworkId &networkId) const;
PlanetProxyObject * findObjectByID (const NetworkId &objectID) const;
const std::string & getSceneId () const;
uint32 getGameServerForObject (const NetworkId &object) const;
void outputStatus (WatcherConnection &conn) const;
int getServerPopulationByLocation (int x, int z) const;
int getMaxCoordinate () const;
private:
void handleRemoveObject (const NetworkId &objectId);
void handleCrash (uint32 gameServerId);
void handleForceLoadArea (uint32 gameServerId, int x1, int z1, int x2, int z2);
private:
struct Coordinates
{
public:
int m_x;
int m_z;
Coordinates(int x, int z);
bool operator==(const Coordinates &rhs) const;
class Hasher
{
public:
size_t operator()(const Coordinates &c) const;
};
private:
Coordinates();
};
typedef std::hash_map<NetworkId, PlanetProxyObject*, NetworkId::Hash> ObjectMapType;
typedef std::hash_set<NetworkId, NetworkId::Hash> DeletedSetType;
typedef std::hash_map<Coordinates, Node*, Coordinates::Hasher> NodeMapType;
private:
std::string m_sceneId;
ObjectMapType m_objects;
DeletedSetType m_deletedObjects;
NodeMapType m_nodeMap;
PopulationList * m_populationList;
Timer m_populationCountTimer;
int m_maxCoordinate;
};
// ======================================================================
inline Scene::Coordinates::Coordinates(int x, int z) :
m_x(x),
m_z(z)
{
}
// ----------------------------------------------------------------------
inline bool Scene::Coordinates::operator==(const Coordinates &rhs) const
{
return ((m_x==rhs.m_x) && (m_z==rhs.m_z));
}
// ----------------------------------------------------------------------
inline size_t Scene::Coordinates::Hasher::operator()(const Coordinates &c) const
{
// will need to change this if we make planets bigger than 32k * 32k
return (c.m_x<<16 | c.m_z); //lint !e701 shift left of signed
}
// ----------------------------------------------------------------------
inline const std::string &Scene::getSceneId() const
{
return m_sceneId;
}
// ======================================================================
#endif
@@ -0,0 +1,93 @@
// TaskConnection.cpp
// copyright 2000 Verant Interactive
// Author: Justin Randall
//-----------------------------------------------------------------------
#include "FirstPlanetServer.h"
#include "serverNetworkMessages/TaskConnectionIdMessage.h"
#include "serverNetworkMessages/TaskUtilization.h"
#include "sharedFoundation/ConfigFile.h"
#include "sharedNetwork/NetworkSetupData.h"
#include "TaskConnection.h"
//-----------------------------------------------------------------------
TaskConnection::TaskConnection(const std::string & a, const unsigned short p) :
ServerConnection(a, p, NetworkSetupData())
{
}
//-----------------------------------------------------------------------
TaskConnection::TaskConnection(UdpConnectionMT * u, TcpClient * t) :
ServerConnection(u, t)
{
}
//-----------------------------------------------------------------------
TaskConnection::~TaskConnection()
{
}
//-----------------------------------------------------------------------
void TaskConnection::onConnectionClosed()
{
static MessageConnectionCallback m("TaskConnectionClosed");
emitMessage(m);
PlanetServer::getInstance().setTaskManager(0);
}
//-----------------------------------------------------------------------
void TaskConnection::onConnectionOpened()
{
PlanetServer::getInstance().setTaskManager(this);
// get cluster name
std::string clusterName;
ConfigFile::Section const * const sec = ConfigFile::getSection("TaskManager");
if (sec)
{
ConfigFile::Key const * const ky = sec->findKey("clusterName");
if (ky)
{
clusterName = ky->getAsString(ky->getCount()-1, "");
}
}
TaskConnectionIdMessage id(TaskConnectionIdMessage::Planet, "", clusterName);
send(id, true);
static MessageConnectionCallback m("TaskConnectionOpened");
emitMessage(m);
}
//-----------------------------------------------------------------------
void TaskConnection::onReceive(const Archive::ByteStream & message)
{
Archive::ReadIterator r(message);
GameNetworkMessage m(r);
if(m.isType("TaskUtilization"))
{
// generate utilization messages for the task manager
TaskUtilization sysCpu(static_cast<int>(TaskUtilization::SYSTEM_CPU), 0.5f);
TaskUtilization sysMem(static_cast<int>(TaskUtilization::SYSTEM_MEMORY), 0.5f);
TaskUtilization sysNet(static_cast<int>(TaskUtilization::SYSTEM_NETWORK_IO), 50000.0f);
TaskUtilization procCpu(static_cast<int>(TaskUtilization::PROCESS_CPU), 0.5f);
TaskUtilization procMem(static_cast<int>(TaskUtilization::PROCESS_MEMORY), 0.5f);
TaskUtilization procNet(static_cast<int>(TaskUtilization::PROCESS_NETWORK_IO), 50000.0f);
send(sysCpu, true);
send(sysMem, true);
send(sysNet, true);
send(procCpu, true);
send(procMem, true);
send(procNet, true);
}
}
//-----------------------------------------------------------------------
@@ -0,0 +1,39 @@
// TaskConnection.h
// copyright 2001 Verant Interactive
// Author: Justin Randall
#ifndef _TaskConnection_H
#define _TaskConnection_H
//-----------------------------------------------------------------------
class TaskCommandChannel;
//-----------------------------------------------------------------------
#include "serverUtility/ServerConnection.h"
//-----------------------------------------------------------------------
class TaskConnection : public ServerConnection
{
public:
TaskConnection(const std::string & remoteAddress, const unsigned short remotePort);
TaskConnection(UdpConnectionMT * u, TcpClient *);
~TaskConnection();
void onConnectionClosed();
void onConnectionOpened();
void onReceive(const Archive::ByteStream & message);
private:
TaskConnection(const TaskConnection&);
TaskConnection& operator= (const TaskConnection&);
TaskConnection();
};
//-----------------------------------------------------------------------
#endif // _TaskConnection_H
@@ -0,0 +1,110 @@
// ======================================================================
//
// WatcherConnection.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "FirstPlanetServer.h"
#include "WatcherConnection.h"
#include "ConfigPlanetServer.h"
#include "sharedNetworkMessages/PlanetNodeStatusMessage.h"
#include "sharedNetworkMessages/PlanetObjectStatusMessage.h"
//-----------------------------------------------------------------------
WatcherConnection::WatcherConnection(UdpConnectionMT * u, TcpClient * t) :
ServerConnection(u, t),
m_objectData(new ObjectDataList),
m_nodeData(new NodeDataList)
{
}
//-----------------------------------------------------------------------
WatcherConnection::~WatcherConnection()
{
delete m_objectData;
delete m_nodeData;
m_objectData = 0;
m_nodeData = 0;
} //lint !e1740 // thinks we didn't delete m_objectData and m_nodeData, but clearly we did
//-----------------------------------------------------------------------
void WatcherConnection::onConnectionClosed()
{
DEBUG_REPORT_LOG(true,("WatcherConnection closed.\n"));
ServerConnection::onConnectionClosed();
static MessageConnectionCallback m("WatcherConnectionClosed");
emitMessage(m);
}
//-----------------------------------------------------------------------
void WatcherConnection::onConnectionOpened()
{
DEBUG_REPORT_LOG(true,("WatcherConnection opened.\n"));
ServerConnection::onConnectionOpened();
static MessageConnectionCallback m("WatcherConnectionOpened");
emitMessage(m);
setOverflowLimit(ConfigPlanetServer::getWatcherOverflowLimit());
}
// ----------------------------------------------------------------------
void WatcherConnection::addObjectUpdate(const NetworkId &objectId, int x, int z, uint32 authoritativeServer, int interestRadius, bool deleteObject, int objectTypeTag, int const level, bool const hibernating, uint32 const templateCrc, int const aiActivity, int const creationType)
{
NOT_NULL(m_objectData);
m_objectData->push_back(PlanetObjectStatusMessageData(objectId, x,z, authoritativeServer, interestRadius, static_cast<int>(deleteObject), objectTypeTag, level, hibernating, templateCrc, aiActivity, creationType));
if (static_cast<int>(m_objectData->size()) > ConfigPlanetServer::getMaxWatcherUpdatesPerMessage())
{
flushQueuedObjectData();
}
}
//-----------------------------------------------------------------------
void WatcherConnection::flushQueuedObjectData()
{
NOT_NULL(m_objectData);
if (m_objectData->size() != 0)
{
PlanetObjectStatusMessage msg(*m_objectData);
send(msg,true);
m_objectData->clear();
}
}
// ----------------------------------------------------------------------
void WatcherConnection::addNodeUpdate(int x, int z, bool loaded, const stdvector<uint32>::fwd &servers, const stdvector<int>::fwd &subscriptionCounts)
{
NOT_NULL(m_nodeData);
m_nodeData->push_back(PlanetNodeStatusMessageData(x,z,loaded,servers,subscriptionCounts));
if (static_cast<int>(m_objectData->size()) > ConfigPlanetServer::getMaxWatcherUpdatesPerMessage())
{
flushQueuedNodeData();
}
}
// ----------------------------------------------------------------------
void WatcherConnection::flushQueuedNodeData()
{
NOT_NULL(m_nodeData);
if (m_nodeData->size() != 0)
{
PlanetNodeStatusMessage msg(*m_nodeData);
send(msg,true);
m_nodeData->clear();
}
}
// ----------------------------------------------------------------------
@@ -0,0 +1,59 @@
// ======================================================================
//
// WatcherConnection.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_WatcherConnection_H
#define INCLUDED_WatcherConnection_H
// ======================================================================
#include "serverUtility/ServerConnection.h"
class PlanetObjectStatusMessageData;
class PlanetNodeStatusMessageData;
// ======================================================================
class WatcherConnection : public ServerConnection
{
public:
WatcherConnection(UdpConnectionMT *, TcpClient *);
~WatcherConnection();
void onConnectionClosed ();
void onConnectionOpened ();
void addObjectUpdate (const NetworkId &objectId, int x, int z, uint32 authoritativeServer, int interestRadius, bool deleteObject, int objectTypeTag, int level, bool hibernating, uint32 templateCrc, int aiActivity, int creationType);
void addNodeUpdate (int x, int z, bool loaded, const stdvector<uint32>::fwd &servers, const stdvector<int>::fwd &subscriptionCounts);
void flushQueuedData ();
private:
void flushQueuedObjectData();
void flushQueuedNodeData();
private:
typedef stdvector<PlanetObjectStatusMessageData>::fwd ObjectDataList;
ObjectDataList *m_objectData;
typedef stdvector<PlanetNodeStatusMessageData>::fwd NodeDataList;
NodeDataList *m_nodeData;
private:
WatcherConnection (const WatcherConnection&);
WatcherConnection& operator= (const WatcherConnection&);
WatcherConnection();
};
// ----------------------------------------------------------------------
inline void WatcherConnection::flushQueuedData()
{
flushQueuedObjectData();
flushQueuedNodeData();
}
// ======================================================================
#endif
@@ -0,0 +1,8 @@
// ======================================================================
//
// FirstPlanetServer.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "FirstPlanetServer.h"
@@ -0,0 +1,67 @@
#include "FirstPlanetServer.h"
#include "ConfigPlanetServer.h"
#include "PlanetServer.h"
#include "sharedCompression/SetupSharedCompression.h"
#include "sharedDebug/SetupSharedDebug.h"
#include "sharedFile/SetupSharedFile.h"
#include "sharedFoundation/Os.h"
#include "sharedFoundation/SetupSharedFoundation.h"
#include "sharedLog/SetupSharedLog.h"
#include "sharedNetwork/SetupSharedNetwork.h"
#include "sharedNetworkMessages/SetupSharedNetworkMessages.h"
#include "sharedRandom/SetupSharedRandom.h"
#include "sharedThread/SetupSharedThread.h"
#include "sharedUtility/SetupSharedUtility.h"
#include <cstdio>
//_____________________________________________________________________
int main(int argc, char ** argv)
{
SetupSharedThread::install();
SetupSharedDebug::install(1024);
//-- setup foundation
SetupSharedFoundation::Data setupFoundationData(SetupSharedFoundation::Data::D_game);
setupFoundationData.argc = argc;
setupFoundationData.argv = argv;
setupFoundationData.createWindow = false;
setupFoundationData.clockUsesSleep = true;
SetupSharedFoundation::install (setupFoundationData);
SetupSharedCompression::install();
SetupSharedFile::install(false);
SetupSharedNetwork::SetupData networkSetupData;
SetupSharedNetwork::getDefaultServerSetupData(networkSetupData);
SetupSharedNetwork::install(networkSetupData);
SetupSharedNetworkMessages::install();
SetupSharedRandom::install(int(time(NULL)));
SetupSharedUtility::Data sharedUtilityData;
SetupSharedUtility::setupGameData (sharedUtilityData);
SetupSharedUtility::install (sharedUtilityData);
//-- setup server
ConfigPlanetServer::install ();
char tmp[92];
sprintf(tmp, "PlanetServer:%d", Os::getProcessId());
SetupSharedLog::install(tmp);
//-- run server
SetupSharedFoundation::callbackWithExceptionHandling(PlanetServer::run);
SetupSharedLog::remove();
SetupSharedFoundation::remove();
SetupSharedThread::remove();
return 0;
}
//_____________________________________________________________________