1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-26 22:37:45 +00:00
sapphire/src/servers/Server_Zone/ServerZone.cpp

413 lines
11 KiB
C++
Raw Normal View History

2017-08-08 13:53:47 +02:00
#include "ServerZone.h"
#include <src/servers/Server_Common/Version.h>
2017-08-19 00:18:40 +02:00
#include <src/servers/Server_Common/Logging/Logger.h>
#include <src/servers/Server_Common/Config/XMLConfig.h>
#include <src/servers/Server_Common/Version.h>
2017-08-08 13:53:47 +02:00
2017-09-25 14:44:15 +02:00
#include <MySqlBase.h>
#include <Connection.h>
#include <Server_Common/Network/Connection.h>
#include <Server_Common/Network/Hive.h>
2017-08-08 13:53:47 +02:00
#include <Server_Common/Exd/ExdData.h>
#include <Server_Common/Network/PacketContainer.h>
#include <Server_Common/Database/DbLoader.h>
#include <Server_Common/Database/CharaDbConnection.h>
#include <Server_Common/Database/DbWorkerPool.h>
#include <Server_Common/Database/PreparedStatement.h>
2017-08-08 13:53:47 +02:00
#include "Network/GameConnection.h"
2017-08-08 13:53:47 +02:00
#include "Session.h"
#include "Zone/ZoneMgr.h"
2017-08-08 13:53:47 +02:00
#include "DebugCommand/DebugCommandHandler.h"
2017-08-08 13:53:47 +02:00
#include "Script/ScriptManager.h"
#include "Linkshell/LinkshellMgr.h"
2017-08-08 13:53:47 +02:00
#include "Forwards.h"
#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>
#include <boost/algorithm/string.hpp>
#include <thread>
2017-08-08 13:53:47 +02:00
Core::Logger g_log;
Core::DebugCommandHandler g_gameCommandMgr;
2017-08-08 13:53:47 +02:00
Core::Scripting::ScriptManager g_scriptMgr;
Core::Data::ExdData g_exdData;
Core::ZoneMgr g_zoneMgr;
Core::LinkshellMgr g_linkshellMgr;
Core::Db::DbWorkerPool< Core::Db::CharaDbConnection > g_charaDb;
2017-08-08 13:53:47 +02:00
Core::ServerZone::ServerZone( const std::string& configPath )
2017-10-01 17:58:11 +02:00
: m_configPath( configPath ),
2017-11-20 23:24:50 +01:00
m_bRunning( true ),
m_lastDBPingTime( 0 )
2017-08-08 13:53:47 +02:00
{
m_pConfig = XMLConfigPtr( new XMLConfig );
}
Core::ServerZone::~ServerZone()
{
}
Core::XMLConfigPtr Core::ServerZone::getConfig() const
{
return m_pConfig;
}
2017-09-14 17:07:58 +02:00
size_t Core::ServerZone::getSessionCount() const
{
return m_sessionMap.size();
}
2017-08-08 13:53:47 +02:00
bool Core::ServerZone::registerBnpcTemplate( std::string templateName, uint32_t bnpcBaseId,
uint32_t bnpcNameId, uint32_t modelId, std::string aiName )
{
auto it = m_bnpcTemplates.find( templateName );
if( it != m_bnpcTemplates.end() )
{
g_log.error( templateName + " already registered, skipping..." );
return false;
}
Entity::BattleNpcTemplatePtr pNpcTemplate( new Entity::BattleNpcTemplate( templateName, bnpcBaseId, bnpcNameId, modelId, aiName ) );
m_bnpcTemplates[templateName] = pNpcTemplate;
return true;
}
Core::Entity::BattleNpcTemplatePtr Core::ServerZone::getBnpcTemplate( std::string templateName )
{
auto it = m_bnpcTemplates.find( templateName );
2017-08-08 13:53:47 +02:00
if (it != m_bnpcTemplates.end())
return nullptr;
return it->second;
}
bool Core::ServerZone::loadSettings( int32_t argc, char* argv[] )
2017-08-08 13:53:47 +02:00
{
g_log.info( "Loading config " + m_configPath );
if( !m_pConfig->loadConfig( m_configPath ) )
{
g_log.fatal( "Error loading config " + m_configPath );
return false;
}
std::vector<std::string> args( argv + 1, argv + argc );
for( uint32_t i = 0; i + 1 < args.size(); i += 2 )
2017-08-08 13:53:47 +02:00
{
std::string arg( "" );
std::string val( "" );
try
{
2017-08-11 23:15:55 +01:00
arg = boost::to_lower_copy( std::string( args[i] ) );
2017-08-08 13:53:47 +02:00
val = std::string( args[i + 1] );
// trim '-' from start of arg
arg = arg.erase( 0, arg.find_first_not_of( '-' ) );
if( arg == "ip" )
{
// todo: ip addr in config
m_pConfig->setValue< std::string >( "Settings.General.ListenIP", val );
}
else if( arg == "p" || arg == "port" )
{
m_pConfig->setValue< std::string >( "Settings.General.ListenPort", val );
}
else if( arg == "exdpath" || arg == "datapath" )
2017-08-08 13:53:47 +02:00
{
m_pConfig->setValue< std::string >( "Settings.General.DataPath", val );
}
2017-11-26 00:38:33 +11:00
else if( arg == "s" || arg == "scriptpath" )
{
m_pConfig->setValue< std::string >( "Settings.General.ScriptPath", val );
}
2017-08-08 13:53:47 +02:00
else if( arg == "h" || arg == "dbhost" )
{
m_pConfig->setValue< std::string >( "Settings.General.Mysql.Host", val );
}
else if( arg == "dbport" )
{
m_pConfig->setValue< std::string >( "Settings.General.Mysql.Port", val );
}
else if( arg == "u" || arg == "user" || arg == "dbuser" )
{
m_pConfig->setValue< std::string >( "Settings.General.Mysql.Username", val );
}
else if( arg == "pass" || arg == "dbpass" )
{
m_pConfig->setValue< std::string >( "Settings.General.Mysql.Pass", val );
}
else if( arg == "d" || arg == "db" || arg == "database" )
{
m_pConfig->setValue< std::string >( "Settings.General.Mysql.Database", val );
}
}
catch( ... )
{
g_log.error( "Error parsing argument: " + arg + " " + "value: " + val + "\n" );
g_log.error( "Usage: <arg> <val> \n" );
}
}
g_log.info( "Setting up EXD data" );
if( !g_exdData.init( m_pConfig->getValue< std::string >( "Settings.General.DataPath", "" ) ) )
{
g_log.fatal( "Error setting up EXD data " );
return false;
}
Core::Db::DbLoader loader;
Core::Db::ConnectionInfo info;
info.password = m_pConfig->getValue< std::string >( "Settings.General.Mysql.Pass", "" );
info.host = m_pConfig->getValue< std::string >( "Settings.General.Mysql.Host", "127.0.0.1" );
info.database = m_pConfig->getValue< std::string >( "Settings.General.Mysql.Database", "sapphire" );
info.port = m_pConfig->getValue< uint16_t >( "Settings.General.Mysql.Port", 3306 );
info.user = m_pConfig->getValue< std::string >( "Settings.General.Mysql.Username", "root" );
info.syncThreads = m_pConfig->getValue< uint8_t >( "Settings.General.Mysql.SyncThreads", 2 );
info.asyncThreads = m_pConfig->getValue< uint8_t >( "Settings.General.Mysql.AsyncThreads", 2 );
loader.addDb( g_charaDb, info );
if( !loader.initDbs() )
return false;
m_port = m_pConfig->getValue< uint16_t >( "Settings.General.ListenPort", 54992 );
m_ip = m_pConfig->getValue< std::string >( "Settings.General.ListenIp", "0.0.0.0" );
2017-08-08 13:53:47 +02:00
return true;
}
void Core::ServerZone::run( int32_t argc, char* argv[] )
2017-08-08 13:53:47 +02:00
{
// TODO: add more error checks for the entire initialisation
g_log.setLogPath( "log\\SapphireZone_" );
2017-08-08 13:53:47 +02:00
g_log.init();
printBanner();
2017-08-08 13:53:47 +02:00
if( !loadSettings( argc, argv ) )
{
g_log.fatal( "Unable to load settings!" );
return;
}
g_exdData.loadZoneInfo();
g_exdData.loadClassJobInfo();
g_exdData.loadParamGrowInfo();
g_exdData.loadEventActionInfo();
g_exdData.loadActionInfo();
g_exdData.loadStatusEffectInfo();
g_exdData.loadAetheryteInfo();
g_exdData.loadTribeInfo();
g_log.info( "LinkshellMgr: Caching linkshells" );
if( !g_linkshellMgr.loadLinkshells() )
{
g_log.fatal( "Unable to load linkshells!" );
return;
}
2017-08-08 13:53:47 +02:00
Network::HivePtr hive( new Network::Hive() );
Network::addServerToHive< Network::GameConnection >( m_ip, m_port, hive );
g_log.info( "ZoneMgr: Setting up zones" );
2017-08-08 13:53:47 +02:00
g_zoneMgr.createZones();
g_scriptMgr.init();
2017-08-08 13:53:47 +02:00
std::vector< std::thread > thread_list;
2017-10-01 17:58:11 +02:00
thread_list.emplace_back( std::thread( std::bind( &Network::Hive::Run, hive.get() ) ) );
2017-08-08 13:53:47 +02:00
g_log.info( "Server listening on port: " + std::to_string( m_port ) );
g_log.info( "Ready for connections..." );
2017-10-01 17:58:11 +02:00
mainLoop();
for( auto& thread_entry : thread_list )
2017-08-08 13:53:47 +02:00
{
2017-10-01 17:58:11 +02:00
thread_entry.join();
}
}
void Core::ServerZone::printBanner() const
{
g_log.info("===========================================================" );
g_log.info( "Sapphire Server Project " );
g_log.info( "Version: " + Version::VERSION );
g_log.info( "Git Hash: " + Version::GIT_HASH );
g_log.info( "Compiled: " __DATE__ " " __TIME__ );
g_log.info( "===========================================================" );
}
2017-10-01 17:58:11 +02:00
void Core::ServerZone::mainLoop()
{
while( isRunning() )
{
this_thread::sleep_for( chrono::milliseconds( 50 ) );
2017-08-08 13:53:47 +02:00
g_zoneMgr.updateZones();
2017-10-01 17:58:11 +02:00
auto currTime = static_cast< uint32_t >( time( nullptr ) );
lock_guard< std::mutex > lock( this->m_sessionMutex );
for( auto sessionIt : this->m_sessionMap )
2017-08-08 13:53:47 +02:00
{
auto session = sessionIt.second;
if( session && session->getPlayer() )
{
2017-08-08 13:53:47 +02:00
// if the player is in a zone, let the zone handler take care of his updates
// else do it here.
if( !session->getPlayer()->getCurrentZone() )
session->update();
2017-08-08 13:53:47 +02:00
}
}
2017-11-20 23:24:50 +01:00
if( currTime - m_lastDBPingTime > 3 )
{
g_charaDb.keepAlive();
m_lastDBPingTime = currTime;
}
2017-10-01 17:58:11 +02:00
auto it = this->m_sessionMap.begin();
for( ; it != this->m_sessionMap.end(); )
2017-08-08 13:53:47 +02:00
{
uint32_t diff = currTime - it->second->getLastDataTime();
auto pPlayer = it->second->getPlayer();
// remove session of players marked for removel ( logoff / kick )
if( pPlayer->isMarkedForRemoval() && diff > 1 )
{
// if( it->second.unique() )
{
g_log.info("[" + std::to_string(it->second->getId() ) + "] Session removal" );
it = this->m_sessionMap.erase( it );
continue;
}
}
// remove sessions that simply timed out
2017-08-08 13:53:47 +02:00
if( diff > 20 )
{
2017-10-01 17:58:11 +02:00
g_log.info("[" + std::to_string(it->second->getId() ) + "] Session time out" );
2017-08-08 13:53:47 +02:00
it->second->close();
// if( it->second.unique() )
{
2017-10-01 17:58:11 +02:00
it = this->m_sessionMap.erase(it );
2017-08-08 13:53:47 +02:00
}
}
else
{
++it;
}
}
}
}
bool Core::ServerZone::createSession( uint32_t sessionId )
{
std::lock_guard< std::mutex > lock( m_sessionMutex );
const std::string session_id_str = std::to_string( sessionId );
auto it = m_sessionMap.find( sessionId );
if( it != m_sessionMap.end() )
{
g_log.error( "[" + session_id_str + "] Error creating session" );
return false;
}
g_log.info( "[" + session_id_str + "] Creating new session" );
boost::shared_ptr<Session> newSession( new Session( sessionId ) );
m_sessionMap[sessionId] = newSession;
if( !newSession->loadPlayer() )
{
g_log.error( "[" + session_id_str + "] Error loading player " + session_id_str );
return false;
}
m_playerSessionMap[newSession->getPlayer()->getName()] = newSession;
return true;
}
void Core::ServerZone::removeSession( uint32_t sessionId )
{
m_sessionMap.erase( sessionId );
}
void Core::ServerZone::updateSession( uint32_t id )
{
std::lock_guard< std::mutex > lock( m_sessionMutex );
auto it = m_sessionMap.find( id );
if( it != m_sessionMap.end() )
it->second->loadPlayer();
}
Core::SessionPtr Core::ServerZone::getSession( uint32_t id )
{
//std::lock_guard<std::mutex> lock( m_sessionMutex );
auto it = m_sessionMap.find( id );
if( it != m_sessionMap.end() )
return ( it->second );
return nullptr;
}
Core::SessionPtr Core::ServerZone::getSession( std::string playerName )
{
//std::lock_guard<std::mutex> lock( m_sessionMutex );
auto it = m_playerSessionMap.find( playerName );
if (it != m_playerSessionMap.end())
return (it->second);
return nullptr;
}
void Core::ServerZone::removeSession( std::string playerName )
{
m_playerSessionMap.erase( playerName );
}
void Core::ServerZone::updateSession( std::string playerName )
{
std::lock_guard< std::mutex > lock( m_sessionMutex );
auto it = m_playerSessionMap.find( playerName );
if( it != m_playerSessionMap.end() )
it->second->loadPlayer();
}
2017-10-01 17:58:11 +02:00
bool Core::ServerZone::isRunning() const
{
return m_bRunning;
}