mirror of
https://github.com/SWG-Source/src.git
synced 2026-07-13 21:01:08 -04:00
Merge branch 'master' of github.com:SWG-Source/src
This commit is contained in:
@@ -52,6 +52,18 @@ if(DEFINED ENV{ORACLE_HOME})
|
||||
/usr/share/oracle/12.2/client64
|
||||
/usr/lib/oracle/12.2/client
|
||||
/usr/share/oracle/12.2/client
|
||||
/usr/include/oracle/18.3/client64
|
||||
/usr/include/oracle/18.3/client
|
||||
/usr/lib/oracle/18.3/client64
|
||||
/usr/share/oracle/18.3/client64
|
||||
/usr/lib/oracle/18.3/client
|
||||
/usr/share/oracle/18.3/client
|
||||
/usr/include/oracle/19.6/client64
|
||||
/usr/include/oracle/19.6/client
|
||||
/usr/lib/oracle/19.6/client64
|
||||
/usr/share/oracle/19.6/client64
|
||||
/usr/lib/oracle/19.6/client
|
||||
/usr/share/oracle/19.6/client
|
||||
${ORACLE_HOME}/rdbms/public
|
||||
${ORACLE_HOME}/include
|
||||
${ORACLE_HOME}/sdk/include # Oracle SDK
|
||||
@@ -59,8 +71,8 @@ if(DEFINED ENV{ORACLE_HOME})
|
||||
|
||||
|
||||
set(ORACLE_OCI_NAMES clntsh libclntsh oci)
|
||||
set(ORACLE_NNZ_NAMES nnz10 libnnz10 nnz11 libnnz11 nnz12 libnnz12 ociw32)
|
||||
set(ORACLE_OCCI_NAMES libocci occi oraocci10 oraocci11 oraocci12)
|
||||
set(ORACLE_NNZ_NAMES nnz10 libnnz10 nnz11 libnnz11 nnz12 libnnz12 nnz18 libnnz18 nnz19 libnnz19 ociw32)
|
||||
set(ORACLE_OCCI_NAMES libocci occi oraocci10 oraocci11 oraocci12 libocci.so.19.1 oraocci19)
|
||||
|
||||
|
||||
set(ORACLE_LIB_DIR
|
||||
|
||||
@@ -275,9 +275,9 @@ m_timeCharacterMatchStatisticsNextRefresh(0)
|
||||
connectToMessage("TaskConnectionOpened");
|
||||
connectToMessage("RandomNameRequest"); // from connection server
|
||||
connectToMessage("RandomNameResponse"); // from game server
|
||||
connectToMessage("VerifyAndLockNameRequest"); // from connection server
|
||||
connectToMessage("VerifyAndLockNameResponse"); // from game server
|
||||
|
||||
connectToMessage("VerifyAndLockNameRequest"); // from connection server
|
||||
connectToMessage("VerifyAndLockNameResponse"); // from game server
|
||||
|
||||
//Object Messages
|
||||
connectToMessage("RequestObjectMessage");
|
||||
connectToMessage("RequestChunkMessage");
|
||||
@@ -386,7 +386,7 @@ m_timeCharacterMatchStatisticsNextRefresh(0)
|
||||
connectToMessage("RestartServerByRoleMessage");
|
||||
connectToMessage("ExcommunicateGameServerMessage");
|
||||
connectToMessage("RestartPlanetMessage");
|
||||
|
||||
|
||||
// Cluster state
|
||||
connectToMessage("UpdateClusterLockedAndSecretState");
|
||||
|
||||
@@ -432,7 +432,7 @@ m_timeCharacterMatchStatisticsNextRefresh(0)
|
||||
CentralServer::~CentralServer()
|
||||
{
|
||||
ConsoleManager::remove();
|
||||
|
||||
|
||||
CentralCSHandler::remove();
|
||||
|
||||
ms_sceneToHostMap.clear();
|
||||
@@ -1315,7 +1315,7 @@ void CentralServer::receiveMessage(const MessageDispatch::Emitter & source, cons
|
||||
Archive::ReadIterator ri = static_cast<const GameNetworkMessage &>(message).getByteStream().begin();
|
||||
GenericValueTypeMessage <TransferCharacterData> reply(ri);
|
||||
// If this request has a CS Tool Id associated with it, it is an admin request for the CSTool,
|
||||
// and so we should send it directly to the connection server, and not depend on a
|
||||
// and so we should send it directly to the connection server, and not depend on a
|
||||
// transfer server existing.
|
||||
|
||||
if (reply.getValue().getCSToolId() > 0) {
|
||||
@@ -2634,7 +2634,7 @@ void CentralServer::removeGameServer(GameServerConnection const *gameServer)
|
||||
ExcommunicateGameServerMessage const excommunicateMessage(pid, 0, "");
|
||||
sendToAllGameServersExceptDBProcess(excommunicateMessage, true);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
DEBUG_WARNING(true, ("A game server crashed but our process ID ptr is nullptr."));
|
||||
}
|
||||
@@ -2697,7 +2697,7 @@ void CentralServer::run(void)
|
||||
setup.port = ConfigCentralServer::getCommodityServerServicePort();
|
||||
setup.bindInterface = ConfigCentralServer::getCommodityServerServiceBindInterface();
|
||||
s_commodityServerService = new Service(ConnectionAllocator<ServerConnection>(), setup);
|
||||
|
||||
|
||||
setup.port = ConfigCentralServer::getLoginServicePort();
|
||||
if (ConfigCentralServer::getDevelopmentMode())
|
||||
cserver.connectToLoginServer();
|
||||
@@ -2709,7 +2709,7 @@ void CentralServer::run(void)
|
||||
|
||||
// connect to the task manager
|
||||
cserver.m_taskManager = new TaskConnection("127.0.0.1", ConfigCentralServer::getTaskManagerPort());
|
||||
|
||||
|
||||
unsigned long startTime = Clock::timeMs();
|
||||
unsigned long nextLoadingLogTime=0;
|
||||
unsigned long nextPingTime=0;
|
||||
@@ -2743,7 +2743,7 @@ void CentralServer::run(void)
|
||||
{
|
||||
unsigned long lastFrameTime = 0;
|
||||
unsigned long frameStartTime = Clock::timeMs();
|
||||
|
||||
|
||||
PROFILER_AUTO_BLOCK_DEFINE("main loop");
|
||||
|
||||
bool barrierReached = true;
|
||||
@@ -2847,7 +2847,7 @@ void CentralServer::update()
|
||||
static int shutdownCheckLoopCount = 0;
|
||||
|
||||
m_curTime = static_cast<uint32>(time(0));
|
||||
|
||||
|
||||
// Tell the LoginServers if necessary
|
||||
if ((++loopCount > ConfigCentralServer::getUpdatePlayerCountFrequency()))
|
||||
{
|
||||
@@ -2877,7 +2877,7 @@ void CentralServer::update()
|
||||
const short port[1] = { (short)ConfigCentralServer::getAuctionPort() };
|
||||
|
||||
std::string s_id = ConfigCentralServer::getAuctionIDPrefix();
|
||||
s_id += ConfigCentralServer::getClusterName();
|
||||
s_id += ConfigCentralServer::getClusterName();
|
||||
|
||||
const char *identifier[1];
|
||||
identifier[ 0 ] = s_id.c_str();
|
||||
@@ -2914,7 +2914,7 @@ void CentralServer::sendPopulationUpdateToLoginServer()
|
||||
m_totalTutorialSceneCount = 0;
|
||||
m_totalFalconSceneCount = 0;
|
||||
|
||||
|
||||
|
||||
ConnectionServerConnectionList::const_iterator i;
|
||||
for (i=m_connectionServerConnections.begin(); i!=m_connectionServerConnections.end(); ++i)
|
||||
{
|
||||
@@ -2939,7 +2939,7 @@ void CentralServer::sendPopulationUpdateToLoginServer()
|
||||
void CentralServer::sendMetricsToWebAPI()
|
||||
{
|
||||
static const std::string metricsURL(ConfigCentralServer::getMetricsDataURL());
|
||||
|
||||
|
||||
if (!metricsURL.empty())
|
||||
{
|
||||
StellaBellum::webAPI api(metricsURL);
|
||||
@@ -2952,23 +2952,25 @@ void CentralServer::sendMetricsToWebAPI()
|
||||
api.addJsonData<int>("lastLoadingStateTime", m_lastLoadingStateTime);
|
||||
api.addJsonData<int>("clusterStartupTime", m_clusterStartupTime);
|
||||
api.addJsonData<int>("timeClusterWentIntoLoadingState", m_timeClusterWentIntoLoadingState);
|
||||
|
||||
api.addJsonData<int>("webUpdateIntervalSeconds", ConfigCentralServer::getWebUpdateIntervalSeconds());
|
||||
api.addJsonData<std::string>("secretKey", ConfigCentralServer::getMetricsSecretKey());
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (api.submit()) {
|
||||
bool status = api.getNullableValue<bool>("status");
|
||||
|
||||
|
||||
if (status)
|
||||
{
|
||||
std::string message = api.getString("message");
|
||||
|
||||
|
||||
if (message.empty())
|
||||
{
|
||||
message = "No message returned.";
|
||||
}
|
||||
|
||||
|
||||
WARNING(true, ("Error sending stats: %s", message.c_str()));
|
||||
}
|
||||
|
||||
|
||||
WARNING(true, ("Success sending server stats to API."));
|
||||
}
|
||||
else
|
||||
@@ -3200,7 +3202,7 @@ void CentralServer::startPlanetServer(const std::string & host, const std::strin
|
||||
portBase += 100;
|
||||
options += " gameServerDebuggingPortBase=";
|
||||
options += buffer;
|
||||
|
||||
|
||||
TaskSpawnProcess spawn(host.empty() ? std::string("any") : host, "PlanetServer", options, spawnDelay);
|
||||
CentralServer::getInstance().sendTaskMessage(spawn);
|
||||
m_pendingPlanetServers[sceneId] = std::make_pair(std::make_pair(host, options), ::time(nullptr));
|
||||
@@ -3218,7 +3220,7 @@ void CentralServer::startPlanetServer(const std::string & host, const std::strin
|
||||
getInstance().m_transferServerConnection = 0;
|
||||
s_retryTransferServerConnection = false;
|
||||
}
|
||||
|
||||
|
||||
if(getInstance().m_stationPlayersCollectorConnection != nullptr && ! isPreloadFinished())
|
||||
{
|
||||
getInstance().m_stationPlayersCollectorConnection->disconnect();
|
||||
@@ -3923,7 +3925,7 @@ void CentralServer::checkShutdownProcess()
|
||||
if( m_curTime>=m_shutdownTotalTime && !warn30 )
|
||||
{
|
||||
LOG("CentralServerShutdown",("Shutdown Phase %d: Broadcasting 30sec disconnect warning message to players.", m_shutdownPhase));
|
||||
ConGenericMessage const msg("game any systemMessage You will be disconnected in 30sec so the server can perform a final save before shutting down. Please find a safe place to logout now.", 0);
|
||||
ConGenericMessage const msg("game any systemMessage You will be disconnected in 30 seconds so the server can perform a final save before shutting down. Please find a safe place to logout now.", 0);
|
||||
IGNORE_RETURN(sendToRandomGameServer(msg));
|
||||
warn30 = true;
|
||||
|
||||
@@ -3931,7 +3933,7 @@ void CentralServer::checkShutdownProcess()
|
||||
else if( m_curTime >= (m_shutdownTotalTime+20) && !warn10 )
|
||||
{
|
||||
LOG("CentralServerShutdown",("Shutdown Phase %d: Broadcasting 10sec disconnect warning message to players.", m_shutdownPhase));
|
||||
ConGenericMessage const msg("game any systemMessage You will be disconnected in 10sec so the server can perform a final save before shutting down. Please find a safe place to logout now.", 0);
|
||||
ConGenericMessage const msg("game any systemMessage You will be disconnected in 10 seconds so the server can perform a final save before shutting down. Please find a safe place to logout now.", 0);
|
||||
IGNORE_RETURN(sendToRandomGameServer(msg));
|
||||
warn10 = true;
|
||||
}
|
||||
@@ -4133,7 +4135,7 @@ std::pair<std::map<int, std::pair<std::string, int> > const *, std::map<int, std
|
||||
}
|
||||
|
||||
refreshTime = m_timeLastLoginTimeStatisticsRefresh;
|
||||
|
||||
|
||||
return std::make_pair(&m_lastLoginTimeStatistics, &m_createTimeStatistics);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
ConfigCentralServer::Data * ConfigCentralServer::data = 0;
|
||||
|
||||
#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("CentralServer", #a, b))
|
||||
#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("CentralServer", #a, b))
|
||||
#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("CentralServer", #a, b))
|
||||
#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("CentralServer", #a, b))
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@@ -110,7 +110,7 @@ void ConfigCentralServer::install(void)
|
||||
KEY_STRING (transferServerAddress, "127.0.0.1");
|
||||
KEY_INT (transferServerPort, 0); // TransferServer listens on 50005, default to "off"
|
||||
KEY_STRING (stationPlayersCollectorAddress, "127.0.0.1");
|
||||
KEY_INT (stationPlayersCollectorPort, 0); // StationPlayersCollector listens on 50010, default to "off"
|
||||
KEY_INT (stationPlayersCollectorPort, 0); // StationPlayersCollector listens on 50010, default to "off"
|
||||
KEY_BOOL (allowZeroConnectionServerPort, true);
|
||||
KEY_INT (clusterWideDataLockTimeout, 300); // seconds
|
||||
KEY_STRING (commodityServerServiceBindInterface, "");
|
||||
@@ -129,6 +129,7 @@ void ConfigCentralServer::install(void)
|
||||
KEY_INT (maxTimeToWaitForPlanetServerStartSeconds, 5*60); // seconds
|
||||
KEY_STRING (metricsDataURL, "");
|
||||
KEY_INT (webUpdateIntervalSeconds, 5);
|
||||
KEY_STRING (metricsSecretKey, "");
|
||||
|
||||
int index = 0;
|
||||
char const * result = 0;
|
||||
|
||||
@@ -74,6 +74,7 @@ public:
|
||||
|
||||
const char * metricsDataURL;
|
||||
int webUpdateIntervalSeconds;
|
||||
const char * metricsSecretKey;
|
||||
};
|
||||
|
||||
static const unsigned short getChatServicePort ();
|
||||
@@ -137,7 +138,7 @@ public:
|
||||
static const char * getAuctionServer();
|
||||
static int getAuctionPort();
|
||||
static const char * getAuctionIDPrefix();
|
||||
|
||||
|
||||
static bool getDisconnectDuplicateConnectionsOnOtherGalaxies();
|
||||
|
||||
static bool getRequestDbSaveOnPlanetServerCrash();
|
||||
@@ -146,13 +147,14 @@ public:
|
||||
|
||||
static const char * getMetricsDataURL();
|
||||
static int getWebUpdateIntervalSeconds();
|
||||
static const char * getMetricsSecretKey();
|
||||
private:
|
||||
static Data * data;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
inline const unsigned short ConfigCentralServer::getChatServicePort()
|
||||
inline const unsigned short ConfigCentralServer::getChatServicePort()
|
||||
{
|
||||
return static_cast<unsigned short>(data->chatServicePort);
|
||||
}
|
||||
@@ -173,7 +175,7 @@ inline const unsigned short ConfigCentralServer::getConnectionServicePort()
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
inline const unsigned short ConfigCentralServer::getCustomerServicePort()
|
||||
inline const unsigned short ConfigCentralServer::getCustomerServicePort()
|
||||
{
|
||||
return static_cast<unsigned short>(data->customerServicePort);
|
||||
}
|
||||
@@ -529,6 +531,13 @@ inline int ConfigCentralServer::getWebUpdateIntervalSeconds()
|
||||
return data->webUpdateIntervalSeconds;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline const char * ConfigCentralServer::getMetricsSecretKey()
|
||||
{
|
||||
return data->metricsSecretKey;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif // _ConfigCentralServer_H
|
||||
|
||||
+2
-2
@@ -9,9 +9,9 @@
|
||||
#include "sharedFoundation/NetworkId.h"
|
||||
#include "sharedNetworkMessages/CustomerServiceCategory.h"
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
#include "libxml/parser.h"
|
||||
extern "C" {
|
||||
|
||||
}
|
||||
|
||||
using namespace CSAssist;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "sharedFoundation/CrcConstexpr.hpp"
|
||||
|
||||
#include "Session/CommonAPI/CommonAPI.h"
|
||||
#include "webAPI.h"
|
||||
#include "jsonWebAPI.h"
|
||||
|
||||
@@ -170,7 +171,7 @@ void ClientConnection::validateClient(const std::string & id, const std::string
|
||||
}
|
||||
|
||||
// hash username into station id
|
||||
StationId suid = atoi(lcaseId.c_str());
|
||||
StationId suid = atoi(lcaseId.c_str());
|
||||
if (suid == 0)
|
||||
{
|
||||
std::hash<std::string> h;
|
||||
@@ -181,7 +182,7 @@ void ClientConnection::validateClient(const std::string & id, const std::string
|
||||
|
||||
int authOK = 0;
|
||||
std::string authURL(ConfigLoginServer::getExternalAuthUrl());
|
||||
if (!authURL.empty())
|
||||
if (!authURL.empty())
|
||||
{
|
||||
if(ConfigLoginServer::getUseJsonWebApi())
|
||||
{
|
||||
@@ -191,6 +192,7 @@ void ClientConnection::validateClient(const std::string & id, const std::string
|
||||
api.addJsonData<std::string>("user_password", trimmedKey);
|
||||
api.addJsonData<long>("stationID", suid);
|
||||
api.addJsonData<std::string>("ip", getRemoteAddress());
|
||||
api.addJsonData<std::string>("secretKey", ConfigLoginServer::getExternalAuthSecretKey());
|
||||
|
||||
if (api.submit())
|
||||
{
|
||||
@@ -206,15 +208,15 @@ void ClientConnection::validateClient(const std::string & id, const std::string
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
ErrorMessage err("Login Failed", "request failed");
|
||||
this->send(err, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream postBuf;
|
||||
postBuf << "user_name=" << trimmedId << "&user_password=" << trimmedKey << "&stationID=" << suid << "&ip=" << getRemoteAddress();
|
||||
postBuf << "user_name=" << trimmedId << "&user_password=" << trimmedKey << "&stationID=" << suid << "&ip=" << getRemoteAddress() << "&secretKey=" << ConfigLoginServer::getExternalAuthSecretKey();
|
||||
std::string response = webAPI::simplePost(authURL, std::string(postBuf.str()), "");
|
||||
|
||||
if (response == "success") {
|
||||
@@ -232,7 +234,7 @@ void ClientConnection::validateClient(const std::string & id, const std::string
|
||||
authOK = 1;
|
||||
}
|
||||
|
||||
if (authOK)
|
||||
if (authOK)
|
||||
{
|
||||
LoginServer::getInstance().onValidateClient(suid, lcaseId, this, true, NULL, 0xFFFFFFFF, 0xFFFFFFFF);
|
||||
}
|
||||
@@ -285,4 +287,3 @@ StationId ClientConnection::getRequestedAdminSuid() const {
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
|
||||
@@ -118,6 +118,7 @@ void ConfigLoginServer::install(void)
|
||||
KEY_BOOL(useJsonWebApi, false);
|
||||
KEY_BOOL(useExternalAuth, false);
|
||||
KEY_STRING(externalAuthURL, "");
|
||||
KEY_STRING(externalAuthSecretKey, "");
|
||||
KEY_BOOL(useOldSuidGenerator, false);
|
||||
|
||||
int index = 0;
|
||||
|
||||
@@ -66,11 +66,12 @@ class ConfigLoginServer
|
||||
int csToolPort;
|
||||
|
||||
bool requireSecureLoginForCsTool;
|
||||
|
||||
|
||||
bool useOldSuidGenerator;
|
||||
bool useExternalAuth;
|
||||
bool useJsonWebApi;
|
||||
const char * externalAuthURL;
|
||||
const char * externalAuthSecretKey;
|
||||
};
|
||||
|
||||
static const uint16 getCentralServicePort();
|
||||
@@ -137,6 +138,7 @@ class ConfigLoginServer
|
||||
static bool getUseExternalAuth();
|
||||
static bool getUseJsonWebApi();
|
||||
static const char * getExternalAuthUrl();
|
||||
static const char * getExternalAuthSecretKey();
|
||||
static bool getUseOldSuidGenerator();
|
||||
|
||||
// has character creation for this cluster been disabled through config option
|
||||
@@ -502,6 +504,10 @@ inline const char * ConfigLoginServer::getExternalAuthUrl()
|
||||
return data->externalAuthURL;
|
||||
}
|
||||
|
||||
inline const char * ConfigLoginServer::getExternalAuthSecretKey()
|
||||
{
|
||||
return data->externalAuthSecretKey;
|
||||
}
|
||||
|
||||
inline bool ConfigLoginServer::getUseOldSuidGenerator()
|
||||
{
|
||||
|
||||
@@ -82,6 +82,7 @@ void ConfigTaskManager::install(void)
|
||||
KEY_INT (maximumClockDriftToleranceSeconds, 10); // seconds
|
||||
KEY_INT (systemTimeCheckIntervalSeconds, 60); // seconds
|
||||
KEY_INT (clockDriftFatalIntervalSeconds, 1*60*60); // seconds
|
||||
KEY_BOOL (allowPreferredServerOnMasterNode, false);
|
||||
|
||||
int index = 0;
|
||||
char const * result = 0;
|
||||
|
||||
@@ -39,6 +39,7 @@ class ConfigTaskManager
|
||||
int maximumClockDriftToleranceSeconds;
|
||||
int systemTimeCheckIntervalSeconds;
|
||||
int clockDriftFatalIntervalSeconds;
|
||||
bool allowPreferredServerOnMasterNode;
|
||||
};
|
||||
|
||||
static const bool getAutoStart ();
|
||||
@@ -68,7 +69,7 @@ class ConfigTaskManager
|
||||
static int getMaximumClockDriftToleranceSeconds();
|
||||
static int getSystemTimeCheckIntervalSeconds();
|
||||
static int getClockDriftFatalIntervalSeconds();
|
||||
|
||||
static const bool getAllowPreferredServerOnMasterNode();
|
||||
static void install ();
|
||||
static void remove ();
|
||||
|
||||
@@ -270,4 +271,11 @@ inline int ConfigTaskManager::getClockDriftFatalIntervalSeconds()
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline const bool ConfigTaskManager::getAllowPreferredServerOnMasterNode()
|
||||
{
|
||||
return data->allowPreferredServerOnMasterNode;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
#endif // _ConfigTaskManager_H
|
||||
|
||||
@@ -146,19 +146,33 @@ ManagerConnection *LocatorNamespace::getPreferredServer(std::string const &proce
|
||||
{
|
||||
ServerEntry &e = *i;
|
||||
if ((e.m_label != s_masterNodeLabel) && (e.hasAvailableLoad(cost)))
|
||||
{
|
||||
{
|
||||
for (std::vector<PreferredNode>::const_iterator j = s_preferredNodes.begin(); j != s_preferredNodes.end(); ++j)
|
||||
if ((*j).m_nodeLabel == e.m_label && (*j).match(processName, options))
|
||||
return e.m_connection;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
ManagerConnection *LocatorNamespace::getUnpreferredServer(float cost)
|
||||
bool Locator::isMasterNodePreferred(std::string const &processName, std::string const &options, float cost)
|
||||
{
|
||||
if(!ConfigTaskManager::getAllowPreferredServerOnMasterNode())
|
||||
return false;
|
||||
|
||||
for (std::vector<PreferredNode>::const_iterator j = s_preferredNodes.begin(); j != s_preferredNodes.end(); ++j)
|
||||
if ((*j).m_nodeLabel == s_masterNodeLabel && (*j).match(processName, options))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
ManagerConnection *LocatorNamespace::getUnpreferredServer(float cost)
|
||||
{
|
||||
// Find a node other than the master node that can afford to run the process
|
||||
// and is a not marked as a preferred node for anything; if more than one
|
||||
// node qualifies, return the node with the lowest load
|
||||
@@ -190,8 +204,8 @@ ManagerConnection *LocatorNamespace::getUnpreferredServer(float cost)
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
ManagerConnection *Locator::getBestServer(std::string const &processName, std::string const &options, float cost)
|
||||
{
|
||||
if (s_serverList.empty())
|
||||
{
|
||||
if (s_serverList.empty())
|
||||
return 0;
|
||||
|
||||
// first, look for a preferred node for this process
|
||||
|
||||
@@ -24,6 +24,7 @@ public:
|
||||
static void install();
|
||||
static void closed(std::string const &label, ManagerConnection const *oldConnection);
|
||||
static ManagerConnection *getBestServer(std::string const &processName, std::string const &options, float cost);
|
||||
static bool isMasterNodePreferred(std::string const &processName, std::string const &options, float cost);
|
||||
static float getMyLoad();
|
||||
static float getMyMaximumLoad();
|
||||
static float getServerLoad(std::string const &label);
|
||||
|
||||
@@ -84,7 +84,7 @@ void ManagerConnection::onConnectionClosed()
|
||||
|
||||
void ManagerConnection::onConnectionOpened()
|
||||
{
|
||||
DEBUG_REPORT_LOG(true, ("Manager connection opened\n"));
|
||||
DEBUG_REPORT_LOG(true, ("Manager connection opened for %s \n", getRemoteAddress().c_str()));
|
||||
TaskConnectionIdMessage id(TaskConnectionIdMessage::TaskManager, TaskManager::getNodeLabel(), ConfigTaskManager::getClusterName());
|
||||
send(id);
|
||||
s_managerConnectionCount++;
|
||||
|
||||
@@ -613,7 +613,6 @@ unsigned long TaskManager::startServer(const std::string & processName, const st
|
||||
}
|
||||
|
||||
const ProcessEntry pe = (*f).second;
|
||||
|
||||
// does the process run on this box?
|
||||
if(pe.targetHost == "local" || pe.targetHost == getNodeLabel() || nodeLabel == getNodeLabel() || nodeLabel == "local")
|
||||
{
|
||||
@@ -646,10 +645,14 @@ unsigned long TaskManager::startServer(const std::string & processName, const st
|
||||
// select a task manager on which to spawn the server
|
||||
// find the best target
|
||||
float cost = getLoadForProcess(pe.processName);
|
||||
ManagerConnection * conn = Locator::getBestServer(pe.processName, options, cost);
|
||||
if(!conn)
|
||||
if(Locator::isMasterNodePreferred(pe.processName, options, cost))
|
||||
{
|
||||
|
||||
pid = startServerLocal(pe, options);
|
||||
}
|
||||
ManagerConnection * conn = Locator::getBestServer(pe.processName, options, cost);
|
||||
if(!conn && !pid)
|
||||
{
|
||||
|
||||
if(ManagerConnection::getConnectionCount() < 1)
|
||||
pid = startServerLocal(pe, options);
|
||||
else
|
||||
@@ -666,7 +669,7 @@ unsigned long TaskManager::startServer(const std::string & processName, const st
|
||||
s_queuedSpawnRequests.push_back(r);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if(!pid)
|
||||
{
|
||||
std::string label = "uninitialized label";
|
||||
if(conn->getNodeLabel())
|
||||
|
||||
@@ -491,6 +491,8 @@ void ConfigServerGame::install(void)
|
||||
|
||||
KEY_BOOL (useOldSuidGenerator, false);
|
||||
|
||||
KEY_STRING (serverLoadLevel, "heavy");
|
||||
|
||||
if (data->baseDecayRate <= 1.0f)
|
||||
data->baseDecayRate = 1.0f;
|
||||
|
||||
|
||||
@@ -575,6 +575,8 @@ class ConfigServerGame
|
||||
int gcwDaysRequiredForGcwRegionDefenderBonus;
|
||||
|
||||
bool useOldSuidGenerator;
|
||||
|
||||
const char * serverLoadLevel;
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -1061,6 +1063,8 @@ class ConfigServerGame
|
||||
static int getGcwDaysRequiredForGcwRegionDefenderBonus();
|
||||
|
||||
static bool getUseOldSuidGenerator();
|
||||
|
||||
static const char * getServerLoadLevel();
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@@ -3696,6 +3700,11 @@ inline bool ConfigServerGame::getUseOldSuidGenerator() {
|
||||
return data->useOldSuidGenerator;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline const char *ConfigServerGame::getServerLoadLevel()
|
||||
{
|
||||
return data->serverLoadLevel;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace ServerBuildoutManagerNamespace
|
||||
struct BuildoutRow
|
||||
{
|
||||
BuildoutRow();
|
||||
BuildoutRow(int64 id, int64 containerId, int cellIndex, Transform const &transform_p, ServerObjectTemplate const *serverTemplate, std::string const &scripts, std::string const &objvars, std::string const & eventRequired);
|
||||
BuildoutRow(int64 id, int64 containerId, int cellIndex, Transform const &transform_p, ServerObjectTemplate const *serverTemplate, std::string const &scripts, std::string const &objvars, std::string const & eventRequired, std::string const & requiredLoadLevel);
|
||||
BuildoutRow(BuildoutRow const &rhs);
|
||||
~BuildoutRow();
|
||||
BuildoutRow &operator=(BuildoutRow const &rhs);
|
||||
@@ -65,6 +65,7 @@ namespace ServerBuildoutManagerNamespace
|
||||
std::string m_objvars;
|
||||
int m_cellIndex;
|
||||
std::string m_eventRequired;
|
||||
std::string m_requiredLoadLevel;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
@@ -145,6 +146,7 @@ void ServerBuildoutManager::install()
|
||||
|
||||
void ServerBuildoutManager::onChunkComplete(int nodeX, int nodeZ)
|
||||
{
|
||||
std::string configuredLoadLevel = ConfigServerGame::getServerLoadLevel();
|
||||
for (std::vector<AreaInfo>::iterator i = s_areas.begin(); i != s_areas.end(); ++i)
|
||||
{
|
||||
AreaInfo &areaInfo = *i;
|
||||
@@ -155,6 +157,24 @@ void ServerBuildoutManager::onChunkComplete(int nodeX, int nodeZ)
|
||||
{
|
||||
if (!areaInfo.loaded)
|
||||
loadArea(areaInfo);
|
||||
|
||||
// Before we decide to instantiate the area, make sure we need to actually load it based on the configured server load level.
|
||||
std::string areaRequiredLevel = areaInfo.buildoutArea.requiredLoadLevel;
|
||||
if (configuredLoadLevel != "heavy" && !areaRequiredLevel.empty()) {
|
||||
if(configuredLoadLevel == "medium"){
|
||||
// If our configured level is medium, then our area level must be medium or light.
|
||||
if(areaRequiredLevel != "medium" && areaRequiredLevel != "light") {
|
||||
DEBUG_REPORT_LOG(true,("Skipping Area %s (index %d) because its load level is %s and the configured load level is %s\n", areaInfo.buildoutArea.areaName.c_str(), areaInfo.buildoutArea.areaIndex, areaRequiredLevel.c_str(), configuredLoadLevel.c_str()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if(configuredLoadLevel == "light"){
|
||||
if(areaRequiredLevel != "light") {
|
||||
DEBUG_REPORT_LOG(true,("Skipping Area %s (index %d) because its load level is %s and the configured load level is %s\n", areaInfo.buildoutArea.areaName.c_str(), areaInfo.buildoutArea.areaIndex, areaRequiredLevel.c_str(), configuredLoadLevel.c_str()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
instantiateAreaNode(areaInfo, nodeX, nodeZ);
|
||||
}
|
||||
}
|
||||
@@ -580,6 +600,7 @@ void ServerBuildoutManagerNamespace::loadArea(AreaInfo &areaInfo)
|
||||
filename[sizeof(filename) - 1] = '\0';
|
||||
|
||||
std::string const & eventRequired = areaInfo.buildoutArea.getRequiredEventName();
|
||||
std::string const & requiredLoadLevel = areaInfo.buildoutArea.getRequiredLoadLevel();
|
||||
|
||||
if (!eventRequired.empty())
|
||||
{
|
||||
@@ -764,7 +785,8 @@ void ServerBuildoutManagerNamespace::loadArea(AreaInfo &areaInfo)
|
||||
serverTemplate,
|
||||
areaBuildoutTable.getStringValue(scriptsColumn, buildoutRow),
|
||||
areaBuildoutTable.getStringValue(objvarsColumn, buildoutRow),
|
||||
eventRequired));
|
||||
eventRequired,
|
||||
requiredLoadLevel));
|
||||
}
|
||||
|
||||
objects.insert(objId);
|
||||
@@ -1106,7 +1128,7 @@ ServerBuildoutManagerNamespace::BuildoutRow::BuildoutRow() :
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
ServerBuildoutManagerNamespace::BuildoutRow::BuildoutRow(int64 id, int64 containerId, int cellIndex, Transform const &transform_p, ServerObjectTemplate const *serverTemplate, std::string const &scripts, std::string const &objvars, std::string const & eventRequired) :
|
||||
ServerBuildoutManagerNamespace::BuildoutRow::BuildoutRow(int64 id, int64 containerId, int cellIndex, Transform const &transform_p, ServerObjectTemplate const *serverTemplate, std::string const &scripts, std::string const &objvars, std::string const & eventRequired, std::string const & requiredLoadLevel) :
|
||||
m_id(id),
|
||||
m_containerId(containerId),
|
||||
m_transform_p(transform_p),
|
||||
@@ -1114,7 +1136,8 @@ ServerBuildoutManagerNamespace::BuildoutRow::BuildoutRow(int64 id, int64 contain
|
||||
m_scripts(scripts),
|
||||
m_objvars(objvars),
|
||||
m_cellIndex(cellIndex),
|
||||
m_eventRequired(eventRequired)
|
||||
m_eventRequired(eventRequired),
|
||||
m_requiredLoadLevel(requiredLoadLevel)
|
||||
{
|
||||
if (serverTemplate)
|
||||
serverTemplate->addReference();
|
||||
@@ -1130,7 +1153,8 @@ ServerBuildoutManagerNamespace::BuildoutRow::BuildoutRow(BuildoutRow const &rhs)
|
||||
m_scripts(rhs.m_scripts),
|
||||
m_objvars(rhs.m_objvars),
|
||||
m_cellIndex(rhs.m_cellIndex),
|
||||
m_eventRequired(rhs.m_eventRequired)
|
||||
m_eventRequired(rhs.m_eventRequired),
|
||||
m_requiredLoadLevel(rhs.m_requiredLoadLevel)
|
||||
{
|
||||
if (m_serverTemplate)
|
||||
m_serverTemplate->addReference();
|
||||
@@ -1157,6 +1181,7 @@ ServerBuildoutManagerNamespace::BuildoutRow &ServerBuildoutManagerNamespace::Bui
|
||||
m_objvars = rhs.m_objvars;
|
||||
m_cellIndex = rhs.m_cellIndex;
|
||||
m_eventRequired = rhs.m_eventRequired;
|
||||
m_requiredLoadLevel = rhs.m_requiredLoadLevel;
|
||||
|
||||
if (m_serverTemplate)
|
||||
m_serverTemplate->releaseReference();
|
||||
|
||||
@@ -13392,18 +13392,11 @@ void CreatureObject::setGroupMissionCriticalObjects(GroupMissionCriticalObjectSe
|
||||
DEBUG_FATAL(!isAuthoritative(), ("CreatureObject::setGroupMissionCriticalObjects: called on non-authoritative object %s", getDebugInformation(true).c_str()));
|
||||
if (isAuthoritative())
|
||||
{
|
||||
m_groupMissionCriticalObjectSet.clear();
|
||||
//-- Anything that is not in our set, we need to add
|
||||
{
|
||||
for (GroupMissionCriticalObjectSet::const_iterator iter = groupMissionCriticalObjectSet.begin(); iter != groupMissionCriticalObjectSet.end(); ++iter)
|
||||
if (!m_groupMissionCriticalObjectSet.contains(*iter))
|
||||
m_groupMissionCriticalObjectSet.insert(*iter);
|
||||
}
|
||||
|
||||
//-- Anything that is not in the original set, we need to remove
|
||||
{
|
||||
for (GroupMissionCriticalObjectSet::const_iterator iter(m_groupMissionCriticalObjectSet.begin()); iter != m_groupMissionCriticalObjectSet.end(); ++iter)
|
||||
if (groupMissionCriticalObjectSet.find(*iter) == groupMissionCriticalObjectSet.end())
|
||||
m_groupMissionCriticalObjectSet.erase(*iter);
|
||||
m_groupMissionCriticalObjectSet.insert(*iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ include_directories(
|
||||
${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/sharedMessageDispatch/include/public
|
||||
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetwork/include/public
|
||||
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetworkMessages/include/public
|
||||
@@ -60,6 +60,7 @@ include_directories(
|
||||
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/localizationArchive/include/public
|
||||
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicode/include
|
||||
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicodeArchive/include/public
|
||||
${SWG_EXTERNALS_SOURCE_DIR}/3rd/library/webAPI
|
||||
)
|
||||
|
||||
add_library(serverUtility STATIC
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "ConfigServerUtility.h"
|
||||
|
||||
#include "serverUtility/FirstServerUtility.h"
|
||||
#include "serverUtility/AdminAccountManager.h"
|
||||
|
||||
@@ -10,6 +12,8 @@
|
||||
#include "sharedUtility/DataTable.h"
|
||||
#include "sharedUtility/DataTableManager.h"
|
||||
|
||||
#include "webAPI.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@@ -69,6 +73,14 @@ int AdminAccountManager::getAdminLevel(const std::string & account)
|
||||
int level = 0;
|
||||
DEBUG_FATAL(!ms_installed, ("AdminAccountManager not installed"));
|
||||
|
||||
if(ConfigServerUtility::isExternalAdminLevelsEnabled()){
|
||||
std::ostringstream postBuffer;
|
||||
postBuffer << "user_name=" << account << "&secretKey=" << ConfigServerUtility::getExternalAdminLevelsSecretKey();
|
||||
std::string response = webAPI::simplePost(ConfigServerUtility::getExternalAdminLevelsURL(), std::string(postBuffer.str()), "");
|
||||
level = std::stoi(response);
|
||||
return level;
|
||||
}
|
||||
|
||||
int columnNumber = ms_adminTable->findColumnNumber("AdminAccounts");
|
||||
DEBUG_FATAL(columnNumber == -1, ("Error loading admin table...no account column"));
|
||||
int row = ms_adminTable->searchColumnString( columnNumber, account);
|
||||
@@ -113,8 +125,8 @@ bool AdminAccountManager::isInternalIp(const std::string & addr)
|
||||
size_t xpos = ipAddr.find ('x');
|
||||
|
||||
//if no X is found, do a straight compare
|
||||
if ( (xpos == 0 || xpos == std::string::npos)
|
||||
&& ipAddr.compare(addr) == 0
|
||||
if ( (xpos == 0 || xpos == std::string::npos)
|
||||
&& ipAddr.compare(addr) == 0
|
||||
)
|
||||
{
|
||||
retval = true;
|
||||
@@ -125,7 +137,7 @@ bool AdminAccountManager::isInternalIp(const std::string & addr)
|
||||
else if (xpos - 1 > addr.size())
|
||||
retval = false;
|
||||
|
||||
//compare substring
|
||||
//compare substring
|
||||
else if (ipAddr.compare(0, xpos - 1, addr, 0, xpos - 1) == 0)
|
||||
{
|
||||
retval = true;
|
||||
@@ -148,6 +160,7 @@ void AdminAccountManager::reload()
|
||||
DEBUG_FATAL(!ms_installed, ("AdminAccountManager not installed"));
|
||||
NOT_NULL(ms_dataTableName);
|
||||
DataTableManager::reload(*ms_dataTableName);
|
||||
ms_adminTable = DataTableManager::getTable (ms_dataTableName->c_str(), true);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -17,6 +17,9 @@ namespace ConfigServerUtilityNamespace
|
||||
int serverMaxChatLogLines;
|
||||
int playerMaxChatLogLines;
|
||||
bool chatLogManagerLoggingEnabled;
|
||||
bool externalAdminLevelsEnabled;
|
||||
const char * externalAdminLevelsURL;
|
||||
const char * externalAdminLevelsSecretKey;
|
||||
}
|
||||
|
||||
using namespace ConfigServerUtilityNamespace;
|
||||
@@ -75,6 +78,27 @@ bool ConfigServerUtility::isChatLogManagerLoggingEnabled()
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigServerUtility::isExternalAdminLevelsEnabled()
|
||||
{
|
||||
return externalAdminLevelsEnabled;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const char * ConfigServerUtility::getExternalAdminLevelsURL()
|
||||
{
|
||||
return externalAdminLevelsURL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const char * ConfigServerUtility::getExternalAdminLevelsSecretKey()
|
||||
{
|
||||
return externalAdminLevelsSecretKey;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void ConfigServerUtility::install()
|
||||
{
|
||||
KEY_INT(spawnCookie, 0);
|
||||
@@ -82,6 +106,9 @@ void ConfigServerUtility::install()
|
||||
KEY_INT(serverMaxChatLogLines, 5000);
|
||||
KEY_INT(playerMaxChatLogLines, 200);
|
||||
KEY_BOOL(chatLogManagerLoggingEnabled, false);
|
||||
KEY_BOOL(externalAdminLevelsEnabled, false);
|
||||
KEY_STRING(externalAdminLevelsURL, "http://localhost/");
|
||||
KEY_STRING(externalAdminLevelsSecretKey, "");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@@ -91,4 +118,3 @@ void ConfigServerUtility::remove()
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@ public:
|
||||
static int getServerMaxChatLogLines();
|
||||
static int getPlayerMaxChatLogLines();
|
||||
static bool isChatLogManagerLoggingEnabled();
|
||||
static bool isExternalAdminLevelsEnabled();
|
||||
static const char * getExternalAdminLevelsURL();
|
||||
static const char * getExternalAdminLevelsSecretKey();
|
||||
|
||||
static void install();
|
||||
static void remove();
|
||||
|
||||
@@ -158,6 +158,13 @@ std::string const & BuildoutArea::getRequiredEventName() const
|
||||
return requiredEventName;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
std::string const & BuildoutArea::getRequiredLoadLevel() const
|
||||
{
|
||||
return requiredLoadLevel;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
bool SharedBuildoutAreaManager::isBuildoutScene(std::string const & sceneName)
|
||||
@@ -263,6 +270,8 @@ void SharedBuildoutAreaManager::install()
|
||||
buildoutArea.internalBuildoutArea = areaListTable.getIntValue("internal", areaRow) != 0;
|
||||
|
||||
buildoutArea.requiredEventName = areaListTable.getStringValue("eventRequired", areaRow);
|
||||
|
||||
buildoutArea.requiredLoadLevel = areaListTable.getStringValue("requiredLoadLevel", areaRow);
|
||||
}
|
||||
|
||||
s_buildoutAreas[buildoutScene] = areasForScene;
|
||||
@@ -347,6 +356,9 @@ Vector SharedBuildoutAreaManager::getRelativePositionInArea(std::string const &
|
||||
|
||||
if(ignoreNonActiveEvents && !boa.requiredEventName.empty()) // Eventually this needs to query the scheduler system and see if the event is currently active.
|
||||
continue;
|
||||
|
||||
if(ignoreNonActiveEvents && !boa.requiredLoadLevel.empty())
|
||||
continue;
|
||||
|
||||
if(boa.isLocationInside(location_w.x, location_w.z) && boa.areaName == sceneAndArea.second)
|
||||
{
|
||||
@@ -561,6 +573,9 @@ BuildoutArea const * SharedBuildoutAreaManager::findBuildoutAreaAtPosition(std::
|
||||
if(ignoreNonActiveEvents && !buildoutArea.requiredEventName.empty())
|
||||
continue;
|
||||
|
||||
if(ignoreNonActiveEvents && !buildoutArea.requiredLoadLevel.empty())
|
||||
continue;
|
||||
|
||||
if (buildoutArea.isLocationInside(x, z))
|
||||
{
|
||||
return &buildoutArea;
|
||||
@@ -585,6 +600,9 @@ BuildoutArea const * SharedBuildoutAreaManager::findBuildoutAreaAtPosition(float
|
||||
if(ignoreNonActiveEvents && !buildoutArea.requiredEventName.empty())
|
||||
return nullptr;
|
||||
|
||||
if(ignoreNonActiveEvents && !buildoutArea.requiredLoadLevel.empty())
|
||||
return nullptr;
|
||||
|
||||
if (buildoutArea.isLocationInside(x, z))
|
||||
{
|
||||
return &buildoutArea;
|
||||
|
||||
@@ -38,6 +38,7 @@ public:
|
||||
Vector getRelativePosition(Vector const & pos_w, bool allowComposite) const;
|
||||
|
||||
std::string const & getRequiredEventName() const;
|
||||
std::string const & getRequiredLoadLevel() const;
|
||||
|
||||
int areaIndex;
|
||||
std::string areaName;
|
||||
@@ -63,6 +64,9 @@ public:
|
||||
|
||||
// Required Event name for a particular buildout
|
||||
std::string requiredEventName;
|
||||
|
||||
// Required Server level for a particular buildout
|
||||
std::string requiredLoadLevel;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user