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

428 lines
11 KiB
C++
Raw Normal View History

2017-08-08 13:53:47 +02:00
#include "ServerZone.h"
2018-03-06 22:22:19 +01:00
#include <Version.h>
#include <Logging/Logger.h>
#include <Config/ConfigMgr.h>
2017-08-08 13:53:47 +02:00
2017-09-25 14:44:15 +02:00
#include <MySqlBase.h>
#include <Connection.h>
2018-03-06 22:22:19 +01:00
#include <Network/Connection.h>
#include <Network/Hive.h>
2017-08-08 13:53:47 +02:00
2018-03-06 22:22:19 +01:00
#include <Exd/ExdDataGenerated.h>
#include <Network/PacketContainer.h>
#include <Database/DatabaseDef.h>
2018-03-06 22:22:19 +01:00
#include <Util/Util.h>
2017-08-08 13:53:47 +02:00
2018-02-28 11:14:25 +01:00
#include "Actor/Player.h"
#include "Actor/BNpcTemplate.h"
2018-02-28 11:14:25 +01:00
#include "Network/GameConnection.h"
2017-08-08 13:53:47 +02:00
#include "Session.h"
2018-01-27 23:52:49 +01:00
#include "Zone/TerritoryMgr.h"
2017-08-08 13:53:47 +02:00
#include "Script/ScriptMgr.h"
#include "Linkshell/LinkshellMgr.h"
2017-08-08 13:53:47 +02:00
#include "ForwardsZone.h"
2018-06-02 13:38:00 +02:00
2018-09-26 09:11:59 -04:00
#include <boost/lexical_cast.hpp>
2018-09-26 09:25:19 -04:00
#include <boost/algorithm/string/case_conv.hpp>
#include <thread>
2017-08-08 13:53:47 +02:00
#include "Framework.h"
2018-03-09 00:06:44 +01:00
extern Core::Framework g_fw;
2017-08-08 13:53:47 +02:00
Core::ServerZone::ServerZone( const std::string& configName ) :
m_configName( configName ),
m_bRunning( true ),
m_lastDBPingTime( 0 )
2017-08-08 13:53:47 +02:00
{
}
Core::ServerZone::~ServerZone()
{
}
2017-09-14 17:07:58 +02:00
size_t Core::ServerZone::getSessionCount() const
{
return m_sessionMapById.size();
2017-09-14 17:07:58 +02:00
}
bool Core::ServerZone::loadSettings( int32_t argc, char* argv[] )
2017-08-08 13:53:47 +02:00
{
auto pLog = g_fw.get< Core::Logger >();
auto pConfig = g_fw.get< Core::ConfigMgr >();
auto pExd = g_fw.get< Data::ExdDataGenerated >();
auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
pLog->info( "Loading config " + m_configName );
if( !pConfig->loadConfig( m_configName ) )
{
pLog->fatal( "Error loading config " + m_configName );
return false;
}
std::vector< std::string > args( argv + 1, argv + argc );
for( uint32_t i = 0; i + 1 < args.size(); i += 2 )
{
std::string arg( "" );
std::string val( "" );
try
{
arg = boost::to_lower_copy( std::string( args[ i ] ) );
val = std::string( args[ i + 1 ] );
// trim '-' from start of arg
arg = arg.erase( 0, arg.find_first_not_of( '-' ) );
if( arg == "ip" )
2017-08-08 13:53:47 +02:00
{
// todo: ip addr in config
pConfig->setValue< std::string >( "ZoneNetwork.ListenIp", val );
2017-08-08 13:53:47 +02:00
}
else if( arg == "p" || arg == "port" )
2017-08-08 13:53:47 +02:00
{
pConfig->setValue< std::string >( "ZoneNetwork.ListenPort", val );
2017-08-08 13:53:47 +02:00
}
else if( arg == "exdpath" || arg == "datapath" )
{
pConfig->setValue< std::string >( "GlobalParameters.DataPath", val );
}
else if( arg == "h" || arg == "dbhost" )
{
pConfig->setValue< std::string >( "Database.Host", val );
}
else if( arg == "dbport" )
{
pConfig->setValue< std::string >( "Database.Port", val );
}
else if( arg == "u" || arg == "user" || arg == "dbuser" )
{
pConfig->setValue< std::string >( "Database.Username", val );
}
else if( arg == "pass" || arg == "dbpass" )
{
pConfig->setValue< std::string >( "Database.Password", val );
}
else if( arg == "d" || arg == "db" || arg == "database" )
{
pConfig->setValue< std::string >( "Database.Database", val );
}
}
catch( ... )
{
pLog->error( "Error parsing argument: " + arg + " " + "value: " + val + "\n" );
pLog->error( "Usage: <arg> <val> \n" );
}
}
pLog->info( "Setting up generated EXD data" );
if( !pExd->init( pConfig->getValue< std::string >( "GlobalParameters", "DataPath", "" ) ) )
{
pLog->fatal( "Error setting up generated EXD data " );
return false;
}
Core::Db::DbLoader loader;
Core::Db::ConnectionInfo info;
info.password = pConfig->getValue< std::string >( "Database", "Password", "" );
info.host = pConfig->getValue< std::string >( "Database", "Host", "127.0.0.1" );
info.database = pConfig->getValue< std::string >( "Database", "Database", "sapphire" );
info.port = pConfig->getValue< uint16_t >( "Database", "Port", 3306 );
info.user = pConfig->getValue< std::string >( "Database", "Username", "root" );
info.syncThreads = pConfig->getValue< uint8_t >( "Database", "SyncThreads", 2 );
info.asyncThreads = pConfig->getValue< uint8_t >( "Database", "AsyncThreads", 2 );
loader.addDb( *pDb, info );
if( !loader.initDbs() )
return false;
m_port = pConfig->getValue< uint16_t >( "ZoneNetwork", "ListenPort", 54992 );
m_ip = pConfig->getValue< std::string >( "ZoneNetwork", "ListenIp", "0.0.0.0" );
return true;
2017-08-08 13:53:47 +02:00
}
void Core::ServerZone::run( int32_t argc, char* argv[] )
2017-08-08 13:53:47 +02:00
{
auto pLog = g_fw.get< Core::Logger >();
auto pScript = g_fw.get< Scripting::ScriptMgr >();
auto pLsMgr = g_fw.get< LinkshellMgr >();
auto pTeriMgr = g_fw.get< TerritoryMgr >();
2017-08-08 13:53:47 +02:00
printBanner();
2017-08-08 13:53:47 +02:00
if( !loadSettings( argc, argv ) )
{
pLog->fatal( "Unable to load settings!" );
return;
}
2017-08-08 13:53:47 +02:00
pLog->info( "LinkshellMgr: Caching linkshells" );
if( !pLsMgr->loadLinkshells() )
{
pLog->fatal( "Unable to load linkshells!" );
return;
}
Network::HivePtr hive( new Network::Hive() );
Network::addServerToHive< Network::GameConnection >( m_ip, m_port, hive );
2017-08-08 13:53:47 +02:00
pScript->init();
pLog->info( "TerritoryMgr: Setting up zones" );
pTeriMgr->init();
2017-08-08 13:53:47 +02:00
loadBNpcTemplates();
std::vector< std::thread > thread_list;
thread_list.emplace_back( std::thread( std::bind( &Network::Hive::Run, hive.get() ) ) );
pLog->info( "Zone server running on " + m_ip + ":" + std::to_string( m_port ) );
2017-08-08 13:53:47 +02:00
mainLoop();
2017-10-01 17:58:11 +02:00
for( auto& thread_entry : thread_list )
{
thread_entry.join();
}
2017-10-01 17:58:11 +02:00
}
void Core::ServerZone::printBanner() const
{
auto pLog = g_fw.get< Core::Logger >();
pLog->info( "===========================================================" );
pLog->info( "Sapphire Server Project " );
pLog->info( "Version: " + Version::VERSION );
pLog->info( "Git Hash: " + Version::GIT_HASH );
pLog->info( "Compiled: " __DATE__ " " __TIME__ );
pLog->info( "===========================================================" );
}
2017-10-01 17:58:11 +02:00
void Core::ServerZone::mainLoop()
{
auto pLog = g_fw.get< Logger >();
auto pTeriMgr = g_fw.get< TerritoryMgr >();
auto pScriptMgr = g_fw.get< Scripting::ScriptMgr >();
auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
2018-03-09 00:06:44 +01:00
while( isRunning() )
{
2018-09-26 08:47:22 -04:00
std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) );
2017-08-08 13:53:47 +02:00
auto currTime = Util::getTimeSeconds();
2018-01-27 23:52:49 +01:00
pTeriMgr->updateTerritoryInstances( currTime );
2017-12-14 22:30:06 +11:00
pScriptMgr->update();
2017-10-01 17:58:11 +02:00
2018-09-26 08:47:22 -04:00
std::lock_guard< std::mutex > lock( m_sessionMutex );
for( auto sessionIt : m_sessionMapById )
{
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-08-08 13:53:47 +02:00
if( currTime - m_lastDBPingTime > 3 )
{
pDb->keepAlive();
m_lastDBPingTime = currTime;
}
auto it = m_sessionMapById.begin();
for( ; it != m_sessionMapById.end(); )
{
auto diff = std::difftime( currTime, it->second->getLastDataTime() );
2017-11-20 23:24:50 +01:00
auto pPlayer = it->second->getPlayer();
2017-10-01 17:58:11 +02:00
// remove session of players marked for removel ( logoff / kick )
if( pPlayer->isMarkedForRemoval() && diff > 5 )
2017-08-08 13:53:47 +02:00
{
it->second->close();
// if( it->second.unique() )
{
pLog->info( "[" + std::to_string( it->second->getId() ) + "] Session removal" );
it = m_sessionMapById.erase( it );
removeSession( pPlayer->getName() );
continue;
}
}
2017-08-08 13:53:47 +02:00
// remove sessions that simply timed out
if( diff > 20 )
{
pLog->info( "[" + std::to_string( it->second->getId() ) + "] Session time out" );
it->second->close();
// if( it->second.unique() )
{
it = m_sessionMapById.erase( it );
removeSession( pPlayer->getName() );
}
2017-08-08 13:53:47 +02:00
}
else
{
++it;
}
}
2017-08-08 13:53:47 +02:00
}
2017-08-08 13:53:47 +02:00
}
bool Core::ServerZone::createSession( uint32_t sessionId )
{
auto pLog = g_fw.get< Core::Logger >();
2018-03-09 00:06:44 +01:00
std::lock_guard< std::mutex > lock( m_sessionMutex );
2017-08-08 13:53:47 +02:00
const std::string session_id_str = std::to_string( sessionId );
2017-08-08 13:53:47 +02:00
auto it = m_sessionMapById.find( sessionId );
2017-08-08 13:53:47 +02:00
if( it != m_sessionMapById.end() )
{
pLog->error( "[" + session_id_str + "] Error creating session" );
return false;
}
2017-08-08 13:53:47 +02:00
pLog->info( "[" + session_id_str + "] Creating new session" );
2017-08-08 13:53:47 +02:00
2018-10-25 12:44:51 +11:00
std::shared_ptr< Session > newSession( new Session( sessionId ) );
m_sessionMapById[ sessionId ] = newSession;
2017-08-08 13:53:47 +02:00
if( !newSession->loadPlayer() )
{
pLog->error( "[" + session_id_str + "] Error loading player " + session_id_str );
return false;
}
2017-08-08 13:53:47 +02:00
m_sessionMapByName[ newSession->getPlayer()->getName() ] = newSession;
2017-08-08 13:53:47 +02:00
return true;
2017-08-08 13:53:47 +02:00
}
void Core::ServerZone::removeSession( uint32_t sessionId )
{
m_sessionMapById.erase( sessionId );
2017-08-08 13:53:47 +02:00
}
Core::SessionPtr Core::ServerZone::getSession( uint32_t id )
{
//std::lock_guard<std::mutex> lock( m_sessionMutex );
2017-08-08 13:53:47 +02:00
auto it = m_sessionMapById.find( id );
2017-08-08 13:53:47 +02:00
if( it != m_sessionMapById.end() )
return ( it->second );
2017-08-08 13:53:47 +02:00
return nullptr;
2017-08-08 13:53:47 +02:00
}
Core::SessionPtr Core::ServerZone::getSession( const std::string& playerName )
2017-08-08 13:53:47 +02:00
{
//std::lock_guard<std::mutex> lock( m_sessionMutex );
2017-08-08 13:53:47 +02:00
auto it = m_sessionMapByName.find( playerName );
2017-08-08 13:53:47 +02:00
if( it != m_sessionMapByName.end() )
return ( it->second );
2017-08-08 13:53:47 +02:00
return nullptr;
2017-08-08 13:53:47 +02:00
}
void Core::ServerZone::removeSession( const std::string& playerName )
2017-08-08 13:53:47 +02:00
{
m_sessionMapByName.erase( playerName );
2017-08-08 13:53:47 +02:00
}
2017-10-01 17:58:11 +02:00
bool Core::ServerZone::isRunning() const
{
return m_bRunning;
2017-10-01 17:58:11 +02:00
}
void Core::ServerZone::loadBNpcTemplates()
{
auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
auto pTeriMgr = g_fw.get< TerritoryMgr >();
auto pLog = g_fw.get< Logger >();
auto stmt = pDb->getPreparedStatement( Db::ZoneDbStatements::ZONE_SEL_BNPCTEMPLATES );
auto res = pDb->query( stmt );
while( res->next() )
{
//Id, Name, bNPCBaseId, bNPCNameId, mainWeaponModel,
//secWeaponModel, aggressionMode, enemyType, pose,
//modelChara, displayFlags, Look, Models
auto id = res->getUInt( 1 );
auto name = res->getString( 2 );
auto bNPCBaseId = res->getUInt( 3 );
auto bNPCNameId = res->getUInt( 4 );
auto mainWeaponModel = res->getUInt64( 5 );
auto secWeaponModel = res->getUInt64( 6 );
auto aggressionMode = res->getUInt8( 7 );
auto enemyType = res->getUInt8( 8 );
auto pose = res->getUInt8( 9 );
auto modelChara = res->getUInt( 10 );
auto displayFlags = res->getUInt( 11 );
auto look = res->getBlobVector( 12 );
auto models = res->getBlobVector( 13 );
2018-10-25 12:44:51 +11:00
auto bnpcTemplate = std::make_shared< Entity::BNpcTemplate >(
id, bNPCBaseId, bNPCNameId, mainWeaponModel, secWeaponModel,
aggressionMode, enemyType, 0, pose, modelChara, displayFlags,
reinterpret_cast< uint32_t* >( &models[ 0 ] ),
reinterpret_cast< uint8_t* >( &look[ 0 ] ) );
m_bNpcTemplateMap[ name ] = bnpcTemplate;
}
pLog->debug( "BNpc Templates loaded: " + std::to_string( m_bNpcTemplateMap.size() ) );
}
Core::Entity::BNpcTemplatePtr Core::ServerZone::getBNpcTemplate( const std::string& key )
{
auto it = m_bNpcTemplateMap.find( key );
if( it == m_bNpcTemplateMap.end() )
return nullptr;
return it->second;
}
Core::Entity::BNpcTemplatePtr Core::ServerZone::getBNpcTemplate( uint32_t id )
{
for( auto entry : m_bNpcTemplateMap )
{
if( entry.second->getId() == id )
return entry.second;
}
return nullptr;
2018-09-26 08:47:22 -04:00
}