2018-10-26 19:12:55 +02:00
|
|
|
|
|
|
|
#include <Connection.h>
|
|
|
|
#include <Network/Connection.h>
|
|
|
|
#include <Network/Hive.h>
|
|
|
|
#include <Network/PacketContainer.h>
|
|
|
|
|
|
|
|
#include "Network/GameConnection.h"
|
2021-11-27 00:53:57 +01:00
|
|
|
#include "WorldServer.h"
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-03-06 22:22:19 +01:00
|
|
|
#include <Version.h>
|
|
|
|
#include <Logging/Logger.h>
|
2018-06-10 16:34:26 +00:00
|
|
|
#include <Config/ConfigMgr.h>
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
#include <Exd/ExdData.h>
|
2018-09-09 23:56:22 +02:00
|
|
|
#include <Database/DatabaseDef.h>
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-02-28 11:14:25 +01:00
|
|
|
#include "Actor/Player.h"
|
2018-10-26 19:12:55 +02:00
|
|
|
|
2017-08-08 13:53:47 +02:00
|
|
|
#include "Session.h"
|
|
|
|
|
2018-12-01 00:27:16 +11:00
|
|
|
#include "Manager/TerritoryMgr.h"
|
2018-12-02 02:01:41 +01:00
|
|
|
#include "Manager/LinkshellMgr.h"
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-03-02 07:22:25 -03:00
|
|
|
#include "Script/ScriptMgr.h"
|
2018-12-02 02:01:41 +01:00
|
|
|
|
2018-12-16 14:26:38 +01:00
|
|
|
#include <Database/ZoneDbConnection.h>
|
|
|
|
#include <Database/DbWorkerPool.h>
|
2020-02-29 22:30:10 +11:00
|
|
|
#include <Service.h>
|
2018-12-16 14:26:38 +01:00
|
|
|
#include "Manager/LinkshellMgr.h"
|
|
|
|
#include "Manager/TerritoryMgr.h"
|
|
|
|
#include "Manager/HousingMgr.h"
|
2018-12-22 22:25:03 +01:00
|
|
|
#include "Manager/DebugCommandMgr.h"
|
2018-12-16 14:26:38 +01:00
|
|
|
#include "Manager/PlayerMgr.h"
|
|
|
|
#include "Manager/ShopMgr.h"
|
2018-12-18 22:59:01 +11:00
|
|
|
#include "Manager/InventoryMgr.h"
|
2018-12-23 03:53:08 +01:00
|
|
|
#include "Manager/EventMgr.h"
|
2018-12-23 13:26:33 +01:00
|
|
|
#include "Manager/ItemMgr.h"
|
2018-12-31 23:20:36 +11:00
|
|
|
#include "Manager/MarketMgr.h"
|
2019-01-19 21:20:23 -02:00
|
|
|
#include "Manager/RNGMgr.h"
|
2019-01-23 19:23:49 +01:00
|
|
|
#include "Manager/NaviMgr.h"
|
2019-02-03 19:38:04 +11:00
|
|
|
#include "Manager/ActionMgr.h"
|
2021-11-27 00:53:57 +01:00
|
|
|
#include "Manager/ChatChannelMgr.h"
|
|
|
|
#include "Manager/QuestMgr.h"
|
|
|
|
#include "Manager/PartyMgr.h"
|
|
|
|
|
|
|
|
#include "ContentFinder/ContentFinder.h"
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-10-21 23:24:26 +02:00
|
|
|
#include "Territory/InstanceObjectCache.h"
|
|
|
|
|
2018-12-01 00:27:16 +11:00
|
|
|
using namespace Sapphire::World::Manager;
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
Sapphire::World::WorldServer::WorldServer( const std::string& configName ) :
|
2018-08-29 21:40:59 +02:00
|
|
|
m_configName( configName ),
|
|
|
|
m_bRunning( true ),
|
2018-11-14 09:22:17 +01:00
|
|
|
m_lastDBPingTime( 0 ),
|
|
|
|
m_worldId( 67 )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
Sapphire::World::WorldServer::~WorldServer()
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
size_t Sapphire::World::WorldServer::getSessionCount() const
|
2017-09-14 17:07:58 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
return m_sessionMapById.size();
|
2017-09-14 17:07:58 +02:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
bool Sapphire::World::WorldServer::loadSettings( int32_t argc, char* argv[] )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2020-02-29 22:30:10 +11:00
|
|
|
auto& configMgr = Common::Service< Common::ConfigMgr >::ref();
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2019-01-04 21:46:37 +11:00
|
|
|
Logger::info( "Loading config {0}", m_configName );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2019-01-07 23:00:09 +11:00
|
|
|
bool failedLoad = false;
|
|
|
|
|
|
|
|
// load global cfg first
|
2020-02-29 22:30:10 +11:00
|
|
|
if( !configMgr.loadGlobalConfig( m_config.global ) )
|
2019-01-07 23:00:09 +11:00
|
|
|
{
|
|
|
|
Logger::fatal( "Error loading config global.ini, copying default..." );
|
|
|
|
failedLoad = true;
|
|
|
|
}
|
|
|
|
|
2020-02-29 22:30:10 +11:00
|
|
|
if( !configMgr.loadConfig( m_configName ) )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2019-01-04 21:46:37 +11:00
|
|
|
Logger::fatal( "Error loading config {0}", m_configName );
|
2019-01-07 23:00:09 +11:00
|
|
|
failedLoad = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( failedLoad )
|
|
|
|
{
|
|
|
|
Logger::fatal( "If this is the first time starting the server, "
|
|
|
|
"we've copied the default configs for your editing pleasure." );
|
2018-08-29 21:40:59 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-01-07 23:00:09 +11:00
|
|
|
// load world specific config
|
2020-02-29 22:30:10 +11:00
|
|
|
m_config.scripts.hotSwap = configMgr.getValue( "Scripts", "HotSwap", true );
|
|
|
|
m_config.scripts.path = configMgr.getValue< std::string >( "Scripts", "Path", "./compiledscripts/" );
|
|
|
|
m_config.scripts.cachePath = configMgr.getValue< std::string >( "Scripts", "CachePath", "./cache/" );
|
2019-01-07 23:00:09 +11:00
|
|
|
|
2020-02-29 22:30:10 +11:00
|
|
|
m_config.navigation.meshPath = configMgr.getValue< std::string >( "Navigation", "MeshPath", "navi" );
|
2019-01-25 12:23:38 +11:00
|
|
|
|
2020-02-29 22:30:10 +11:00
|
|
|
m_config.network.disconnectTimeout = configMgr.getValue< uint16_t >( "Network", "DisconnectTimeout", 20 );
|
|
|
|
m_config.network.listenIp = configMgr.getValue< std::string >( "Network", "ListenIp", "0.0.0.0" );
|
|
|
|
m_config.network.listenPort = configMgr.getValue< uint16_t >( "Network", "ListenPort", 54992 );
|
|
|
|
m_config.network.inRangeDistance = configMgr.getValue< float >( "Network", "InRangeDistance", 80.f );
|
2019-01-07 23:00:09 +11:00
|
|
|
|
2020-02-29 22:30:10 +11:00
|
|
|
m_config.motd = configMgr.getValue< std::string >( "General", "MotD", "" );
|
2019-01-07 23:00:09 +11:00
|
|
|
|
2020-02-29 22:30:10 +11:00
|
|
|
m_config.housing.defaultEstateName = configMgr.getValue< std::string >( "Housing", "DefaultEstateName", "Estate #{}" );
|
2019-01-07 23:00:09 +11:00
|
|
|
|
|
|
|
m_port = m_config.network.listenPort;
|
|
|
|
m_ip = m_config.network.listenIp;
|
2018-12-16 14:26:38 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
void Sapphire::World::WorldServer::run( int32_t argc, char* argv[] )
|
2018-12-16 14:26:38 +01:00
|
|
|
{
|
|
|
|
using namespace Sapphire;
|
|
|
|
using namespace Sapphire::World;
|
|
|
|
|
2018-12-23 03:53:08 +01:00
|
|
|
Logger::init( "log/world" );
|
2018-12-16 14:26:38 +01:00
|
|
|
|
|
|
|
printBanner();
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
Common::Service< Common::ConfigMgr >::set();
|
2018-12-16 14:26:38 +01:00
|
|
|
if( !loadSettings( argc, argv ) )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2018-12-23 03:53:08 +01:00
|
|
|
Logger::fatal( "Unable to load settings!" );
|
2018-12-16 14:26:38 +01:00
|
|
|
return;
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
|
|
|
|
2019-01-25 19:00:21 +11:00
|
|
|
Logger::setLogLevel( m_config.global.general.logLevel );
|
|
|
|
|
2018-12-23 03:53:08 +01:00
|
|
|
Logger::info( "Setting up generated EXD data" );
|
2021-11-27 00:53:57 +01:00
|
|
|
auto pExdData = std::make_shared< Data::ExdData >();
|
2019-01-07 23:26:34 +11:00
|
|
|
auto dataPath = m_config.global.general.dataPath;
|
2018-12-18 21:40:44 +11:00
|
|
|
if( !pExdData->init( dataPath ) )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2019-01-07 23:08:43 +11:00
|
|
|
Logger::fatal( "Error setting up generated EXD data. Make sure that DataPath is set correctly in global.ini" );
|
2019-01-04 21:46:37 +11:00
|
|
|
Logger::fatal( "DataPath: {0}", dataPath );
|
2018-12-16 14:26:38 +01:00
|
|
|
return;
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2021-11-27 00:53:57 +01:00
|
|
|
Common::Service< Data::ExdData >::set( pExdData );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2021-11-28 23:56:36 +01:00
|
|
|
// auto aetherInfo = pExdData->getRow< Component::Excel::ClassJob >( 2 );
|
|
|
|
// auto aetherInfo1 = pExdData->getRow< Component::Excel::ClassJob >( 3 );
|
|
|
|
|
2018-12-16 14:26:38 +01:00
|
|
|
auto pDb = std::make_shared< Db::DbWorkerPool< Db::ZoneDbConnection > >();
|
|
|
|
Sapphire::Db::DbLoader loader;
|
2019-01-07 23:16:01 +11:00
|
|
|
loader.addDb( *pDb, m_config.global.database );
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !loader.initDbs() )
|
|
|
|
{
|
2018-12-23 03:53:08 +01:00
|
|
|
Logger::fatal( "Database not initialized properly!" );
|
2018-08-29 21:40:59 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-03-01 01:00:57 +11:00
|
|
|
Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::set( pDb );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
Logger::info( "Loading all players" );
|
|
|
|
if( !loadPlayers() )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
Logger::fatal( "Failed to load players!" );
|
2018-08-29 21:40:59 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-08-28 18:36:51 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
auto pChatChannelMgr = std::make_shared< Manager::ChatChannelMgr >();
|
|
|
|
Common::Service< Manager::ChatChannelMgr >::set( pChatChannelMgr );
|
|
|
|
|
|
|
|
auto pLsMgr = std::make_shared< Manager::LinkshellMgr >();
|
|
|
|
|
|
|
|
Logger::info( "LinkshellMgr: Caching linkshells" );
|
|
|
|
if( !pLsMgr->loadLinkshells() )
|
2018-12-16 14:26:38 +01:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
Logger::fatal( "Unable to load linkshells!" );
|
2018-12-16 14:26:38 +01:00
|
|
|
return;
|
|
|
|
}
|
2021-11-27 00:53:57 +01:00
|
|
|
Common::Service< Manager::LinkshellMgr >::set( pLsMgr );
|
2017-12-10 23:51:06 +11:00
|
|
|
|
2019-10-21 23:24:26 +02:00
|
|
|
Logger::info( "Setting up InstanceObjectCache" );
|
2020-03-01 01:00:57 +11:00
|
|
|
auto pInstanceObjCache = std::make_shared< Sapphire::InstanceObjectCache >();
|
|
|
|
Common::Service< Sapphire::InstanceObjectCache >::set( pInstanceObjCache );
|
2019-10-21 23:24:26 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto pActionMgr = std::make_shared< Manager::ActionMgr >();
|
|
|
|
Common::Service< Manager::ActionMgr >::set( pActionMgr );
|
2019-02-03 19:38:04 +11:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto pNaviMgr = std::make_shared< Manager::NaviMgr >();
|
|
|
|
Common::Service< Manager::NaviMgr >::set( pNaviMgr );
|
2019-01-23 19:23:49 +01:00
|
|
|
|
2018-12-23 03:53:08 +01:00
|
|
|
Logger::info( "TerritoryMgr: Setting up zones" );
|
2020-03-01 01:00:57 +11:00
|
|
|
auto pTeriMgr = std::make_shared< Manager::TerritoryMgr >();
|
|
|
|
auto pHousingMgr = std::make_shared< Manager::HousingMgr >();
|
|
|
|
Common::Service< Manager::HousingMgr >::set( pHousingMgr );
|
|
|
|
Common::Service< Manager::TerritoryMgr >::set( pTeriMgr );
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
auto pScript = std::make_shared< Scripting::ScriptMgr >();
|
|
|
|
if( !pScript->init() )
|
|
|
|
{
|
|
|
|
Logger::fatal( "Failed to setup scripts!" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Common::Service< Scripting::ScriptMgr >::set( pScript );
|
|
|
|
|
2018-12-22 11:33:21 +11:00
|
|
|
if( !pHousingMgr->init() )
|
|
|
|
{
|
2018-12-29 13:05:13 +11:00
|
|
|
Logger::fatal( "Failed to setup housing!" );
|
2018-12-22 11:33:21 +11:00
|
|
|
return;
|
|
|
|
}
|
2018-12-16 14:26:38 +01:00
|
|
|
if( !pTeriMgr->init() )
|
|
|
|
{
|
2018-12-23 03:53:08 +01:00
|
|
|
Logger::fatal( "Failed to setup zones!" );
|
2018-12-16 14:26:38 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto pMarketMgr = std::make_shared< Manager::MarketMgr >();
|
|
|
|
Common::Service< Manager::MarketMgr >::set( pMarketMgr );
|
2018-12-31 23:20:36 +11:00
|
|
|
|
|
|
|
if( !pMarketMgr->init() )
|
|
|
|
{
|
|
|
|
Logger::fatal( "Failed to setup market manager!" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-08 17:08:48 +01:00
|
|
|
|
2018-12-16 14:26:38 +01:00
|
|
|
Network::HivePtr hive( new Network::Hive() );
|
2020-03-01 01:00:57 +11:00
|
|
|
Network::addServerToHive< Network::GameConnection >( m_ip, m_port, hive );
|
2018-12-16 14:26:38 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
std::vector< std::thread > thread_list;
|
2019-03-08 09:43:56 +01:00
|
|
|
thread_list.emplace_back( std::thread( std::bind( &Network::Hive::run, hive.get() ) ) );
|
2017-12-10 01:52:03 +11:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto pDebugCom = std::make_shared< DebugCommandMgr >();
|
|
|
|
auto pPlayerMgr = std::make_shared< Manager::PlayerMgr >();
|
|
|
|
auto pShopMgr = std::make_shared< Manager::ShopMgr >();
|
|
|
|
auto pInventoryMgr = std::make_shared< Manager::InventoryMgr >();
|
|
|
|
auto pEventMgr = std::make_shared< Manager::EventMgr >();
|
|
|
|
auto pItemMgr = std::make_shared< Manager::ItemMgr >();
|
|
|
|
auto pRNGMgr = std::make_shared< Manager::RNGMgr >();
|
2021-11-27 00:53:57 +01:00
|
|
|
auto pQuestMgr = std::make_shared< Manager::QuestMgr >();
|
|
|
|
auto pPartyMgr = std::make_shared< Manager::PartyMgr >();
|
|
|
|
auto contentFinder = std::make_shared< ContentFinder >();
|
2020-03-01 01:00:57 +11:00
|
|
|
|
|
|
|
Common::Service< DebugCommandMgr >::set( pDebugCom );
|
|
|
|
Common::Service< Manager::PlayerMgr >::set( pPlayerMgr );
|
|
|
|
Common::Service< Manager::ShopMgr >::set( pShopMgr );
|
|
|
|
Common::Service< Manager::InventoryMgr >::set( pInventoryMgr );
|
|
|
|
Common::Service< Manager::EventMgr >::set( pEventMgr );
|
|
|
|
Common::Service< Manager::ItemMgr >::set( pItemMgr );
|
|
|
|
Common::Service< Manager::RNGMgr >::set( pRNGMgr );
|
2021-11-27 00:53:57 +01:00
|
|
|
Common::Service< Manager::QuestMgr >::set( pQuestMgr );
|
|
|
|
Common::Service< Manager::PartyMgr >::set( pPartyMgr );
|
|
|
|
Common::Service< ContentFinder >::set( contentFinder );
|
|
|
|
|
|
|
|
auto& exdData = Common::Service< Sapphire::Data::ExdData >::ref();
|
2018-12-16 14:26:38 +01:00
|
|
|
|
2019-01-04 21:46:37 +11:00
|
|
|
Logger::info( "World server running on {0}:{1}", m_ip, m_port );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
mainLoop();
|
2017-10-01 17:58:11 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
for( auto& thread_entry : thread_list )
|
|
|
|
{
|
|
|
|
thread_entry.join();
|
|
|
|
}
|
2017-10-01 17:58:11 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
uint16_t Sapphire::World::WorldServer::getWorldId() const
|
2018-11-14 09:22:17 +01:00
|
|
|
{
|
|
|
|
return m_worldId;
|
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
void Sapphire::World::WorldServer::setWorldId( uint16_t worldId )
|
2018-11-14 09:22:17 +01:00
|
|
|
{
|
|
|
|
m_worldId = worldId;
|
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
void Sapphire::World::WorldServer::printBanner() const
|
2017-10-03 12:09:51 +02:00
|
|
|
{
|
2018-12-23 03:53:08 +01:00
|
|
|
Logger::info( "===========================================================" );
|
|
|
|
Logger::info( "Sapphire Server Project " );
|
2019-01-05 12:32:10 +01:00
|
|
|
Logger::info( "Version: {0}", Version::VERSION );
|
|
|
|
Logger::info( "Git Hash: {0}", Version::GIT_HASH );
|
2018-12-23 03:53:08 +01:00
|
|
|
Logger::info( "Compiled: " __DATE__ " " __TIME__ );
|
|
|
|
Logger::info( "===========================================================" );
|
2017-10-03 12:09:51 +02:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
void Sapphire::World::WorldServer::mainLoop()
|
2017-10-01 17:58:11 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& terriMgr = Common::Service< TerritoryMgr >::ref();
|
|
|
|
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
2021-11-27 00:53:57 +01:00
|
|
|
auto& contentFinder = Common::Service< ContentFinder >::ref();
|
2018-03-09 00:06:44 +01:00
|
|
|
|
2018-08-29 21:40:59 +02: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
|
|
|
|
2019-06-02 00:34:22 +10:00
|
|
|
auto currTime = Common::Util::getTimeSeconds();
|
|
|
|
auto tickCount = Common::Util::getTimeMs();
|
2018-01-27 23:52:49 +01:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
terriMgr.updateTerritoryInstances( tickCount );
|
2017-12-14 22:30:06 +11:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
scriptMgr.update();
|
2017-10-01 17:58:11 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
contentFinder.update();
|
|
|
|
|
2018-09-26 08:47:22 -04:00
|
|
|
std::lock_guard< std::mutex > lock( m_sessionMutex );
|
2018-09-09 23:56:22 +02:00
|
|
|
for( auto sessionIt : m_sessionMapById )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
|
|
|
auto session = sessionIt.second;
|
|
|
|
if( session && session->getPlayer() )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2017-11-14 23:55:38 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// if the player is in a zone, let the zone handler take care of his updates
|
|
|
|
// else do it here.
|
2019-07-21 22:50:11 +10:00
|
|
|
if( !session->getPlayer()->getCurrentTerritory() )
|
2018-08-29 21:40:59 +02:00
|
|
|
session->update();
|
2017-11-14 23:55:38 +01:00
|
|
|
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( currTime - m_lastDBPingTime > 3 )
|
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
db.keepAlive();
|
2018-08-29 21:40:59 +02:00
|
|
|
m_lastDBPingTime = currTime;
|
|
|
|
}
|
|
|
|
|
2018-09-09 23:56:22 +02:00
|
|
|
auto it = m_sessionMapById.begin();
|
|
|
|
for( ; it != m_sessionMapById.end(); )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
|
|
|
auto diff = std::difftime( currTime, it->second->getLastDataTime() );
|
2017-11-20 23:24:50 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto pPlayer = it->second->getPlayer();
|
2017-10-01 17:58:11 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// remove session of players marked for removel ( logoff / kick )
|
|
|
|
if( pPlayer->isMarkedForRemoval() && diff > 5 )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
it->second->close();
|
|
|
|
// if( it->second.unique() )
|
|
|
|
{
|
2019-01-04 12:34:19 +01:00
|
|
|
Logger::info( "[{0}] Session removal", it->second->getId() );
|
2018-09-09 23:56:22 +02:00
|
|
|
it = m_sessionMapById.erase( it );
|
2021-11-27 00:53:57 +01:00
|
|
|
removeSession( pPlayer->getCharacterId() );
|
2018-08-29 21:40:59 +02:00
|
|
|
removeSession( pPlayer->getName() );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// remove sessions that simply timed out
|
|
|
|
if( diff > 20 )
|
|
|
|
{
|
2019-01-04 12:34:19 +01:00
|
|
|
Logger::info( "[{0}] Session time out", it->second->getId() );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
it->second->close();
|
|
|
|
// if( it->second.unique() )
|
|
|
|
{
|
2018-09-09 23:56:22 +02:00
|
|
|
it = m_sessionMapById.erase( it );
|
2021-11-27 00:53:57 +01:00
|
|
|
removeSession( pPlayer->getCharacterId() );
|
2018-08-29 21:40:59 +02:00
|
|
|
removeSession( pPlayer->getName() );
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
bool Sapphire::World::WorldServer::createSession( uint32_t sessionId )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
std::lock_guard< std::mutex > lock( m_sessionMutex );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-12-22 22:25:03 +01:00
|
|
|
const auto session_id_str = std::to_string( sessionId );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto it = m_sessionMapById.find( sessionId );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( it != m_sessionMapById.end() )
|
|
|
|
{
|
2019-01-04 12:34:19 +01:00
|
|
|
Logger::error( "[{0}] Error creating session", session_id_str );
|
2018-08-29 21:40:59 +02:00
|
|
|
return false;
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-01-04 12:34:19 +01:00
|
|
|
Logger::info( "[{0}] Creating new session", session_id_str );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
std::shared_ptr< Session > newSession( new Session( sessionId ) );
|
2021-11-27 00:53:57 +01:00
|
|
|
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !newSession->loadPlayer() )
|
|
|
|
{
|
2019-01-04 12:34:19 +01:00
|
|
|
Logger::error( "[{0}] Error loading player {0}", session_id_str );
|
2018-08-29 21:40:59 +02:00
|
|
|
return false;
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
m_sessionMapById[ sessionId ] = newSession;
|
2019-01-23 21:36:26 +01:00
|
|
|
m_sessionMapByName[ newSession->getPlayer()->getName() ] = newSession;
|
2021-11-27 00:53:57 +01:00
|
|
|
m_sessionMapByCharacterId[ newSession->getPlayer()->getCharacterId() ] = newSession;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return true;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
void Sapphire::World::WorldServer::removeSession( uint32_t sessionId )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto pSession = getSession( sessionId );
|
|
|
|
if( !pSession )
|
|
|
|
return;
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_sessionMapById.erase( sessionId );
|
2021-11-27 00:53:57 +01:00
|
|
|
m_sessionMapByName.erase( pSession->getPlayer()->getName() );
|
|
|
|
m_sessionMapByCharacterId.erase( pSession->getPlayer()->getCharacterId() );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
Sapphire::World::SessionPtr Sapphire::World::WorldServer::getSession( uint32_t id )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
//std::lock_guard<std::mutex> lock( m_sessionMutex );
|
|
|
|
auto it = m_sessionMapById.find( id );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( it != m_sessionMapById.end() )
|
|
|
|
return ( it->second );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return nullptr;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
Sapphire::World::SessionPtr Sapphire::World::WorldServer::getSession( uint64_t id )
|
|
|
|
{
|
|
|
|
//std::lock_guard<std::mutex> lock( m_sessionMutex );
|
|
|
|
auto it = m_sessionMapByCharacterId.find( id );
|
|
|
|
|
|
|
|
if( it != m_sessionMapByCharacterId.end() )
|
|
|
|
return ( it->second );
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Sapphire::World::SessionPtr Sapphire::World::WorldServer::getSession( const std::string& playerName )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
//std::lock_guard<std::mutex> lock( m_sessionMutex );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto it = m_sessionMapByName.find( playerName );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( it != m_sessionMapByName.end() )
|
|
|
|
return ( it->second );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return nullptr;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
void Sapphire::World::WorldServer::removeSession( const std::string& playerName )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
m_sessionMapByName.erase( playerName );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
void Sapphire::World::WorldServer::removeSession( uint64_t characterId )
|
|
|
|
{
|
|
|
|
m_sessionMapByCharacterId.erase( characterId );
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
bool Sapphire::World::WorldServer::isRunning() const
|
2017-10-01 17:58:11 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
return m_bRunning;
|
2017-10-01 17:58:11 +02:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
std::vector< Sapphire::World::SessionPtr > Sapphire::World::WorldServer::searchSessionByName(const std::string& playerName)
|
|
|
|
{
|
|
|
|
//std::lock_guard<std::mutex> lock( m_sessionMutex );
|
|
|
|
|
|
|
|
std::vector< Sapphire::World::SessionPtr > results{};
|
|
|
|
|
|
|
|
for( auto it = m_sessionMapByName.begin(); it != m_sessionMapByName.end(); ++it ) {
|
|
|
|
if( it->first.find( playerName ) != std::string::npos ) {
|
|
|
|
results.push_back( it->second );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
Sapphire::Entity::PlayerPtr Sapphire::World::WorldServer::getPlayer( uint32_t entityId )
|
|
|
|
{
|
|
|
|
//std::lock_guard<std::mutex> lock( m_sessionMutex );
|
|
|
|
auto it = m_playerMapById.find( entityId );
|
|
|
|
|
|
|
|
if( it != m_playerMapById.end() )
|
|
|
|
return ( it->second );
|
|
|
|
|
|
|
|
// not found (new character?) - we'll load from DB and hope it's there
|
|
|
|
return loadPlayer( entityId );
|
|
|
|
}
|
|
|
|
|
|
|
|
Sapphire::Entity::PlayerPtr Sapphire::World::WorldServer::getPlayer( uint64_t characterId )
|
|
|
|
{
|
|
|
|
//std::lock_guard<std::mutex> lock( m_sessionMutex );
|
|
|
|
auto it = m_playerMapByCharacterId.find( characterId );
|
|
|
|
|
|
|
|
if( it != m_playerMapByCharacterId.end() )
|
|
|
|
return ( it->second );
|
|
|
|
|
|
|
|
// not found (new character?) - we'll load from DB and hope it's there
|
|
|
|
return loadPlayer( characterId );
|
|
|
|
}
|
|
|
|
|
|
|
|
Sapphire::Entity::PlayerPtr Sapphire::World::WorldServer::getPlayer( const std::string& playerName )
|
|
|
|
{
|
|
|
|
//std::lock_guard<std::mutex> lock( m_sessionMutex );
|
|
|
|
auto it = m_playerMapByName.find( playerName );
|
|
|
|
|
|
|
|
if( it != m_playerMapByName.end() )
|
|
|
|
return ( it->second );
|
|
|
|
|
|
|
|
// not found (new character?) - we'll load from DB and hope it's there
|
|
|
|
return loadPlayer( playerName );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string Sapphire::World::WorldServer::getPlayerNameFromDb( uint64_t characterId, bool forceDbLoad )
|
2018-11-13 00:03:09 +01:00
|
|
|
{
|
2018-11-23 11:46:39 +01:00
|
|
|
if( !forceDbLoad )
|
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto it = m_playerMapByCharacterId.find( characterId );
|
2018-11-23 09:19:49 +01:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
if( it != m_playerMapByCharacterId.end() )
|
|
|
|
return ( it->second->getName() );
|
2018-11-23 11:46:39 +01:00
|
|
|
}
|
2018-11-23 09:19:49 +01:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
2021-11-27 00:53:57 +01:00
|
|
|
auto res = db.query( "SELECT name FROM charainfo WHERE characterid = " + std::to_string( characterId ) );
|
2018-11-13 00:03:09 +01:00
|
|
|
|
|
|
|
if( !res->next() )
|
|
|
|
return "Unknown";
|
|
|
|
|
2018-11-23 09:19:49 +01:00
|
|
|
std::string playerName = res->getString( 1 );
|
|
|
|
|
|
|
|
return playerName;
|
2018-11-13 00:03:09 +01:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
Sapphire::Entity::PlayerPtr Sapphire::World::WorldServer::addPlayer( uint64_t characterId )
|
2018-11-23 09:42:51 +01:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto pPlayer = Entity::make_Player();
|
|
|
|
|
|
|
|
if( !pPlayer->loadFromDb( characterId ) )
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
m_playerMapById[ pPlayer->getId() ] = pPlayer;
|
|
|
|
m_playerMapByCharacterId[ pPlayer->getCharacterId() ] = pPlayer;
|
|
|
|
m_playerMapByName[ pPlayer->getName() ] = pPlayer;
|
|
|
|
|
|
|
|
return pPlayer;
|
2018-11-23 09:42:51 +01:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
Sapphire::Entity::PlayerPtr Sapphire::World::WorldServer::loadPlayer( uint32_t entityId )
|
2018-09-09 23:56:22 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
2021-11-27 00:53:57 +01:00
|
|
|
auto res = db.query( "SELECT CharacterId FROM charainfo WHERE EntityId = " + std::to_string( entityId ) );
|
|
|
|
if( !res->next() )
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
uint64_t characterId = res->getUInt64( 1 );
|
|
|
|
|
|
|
|
return addPlayer( characterId );
|
|
|
|
}
|
2018-09-09 23:56:22 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
Sapphire::Entity::PlayerPtr Sapphire::World::WorldServer::loadPlayer( uint64_t characterId )
|
|
|
|
{
|
|
|
|
return addPlayer( characterId );
|
|
|
|
}
|
|
|
|
|
|
|
|
Sapphire::Entity::PlayerPtr Sapphire::World::WorldServer::loadPlayer( const std::string& playerName )
|
|
|
|
{
|
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto res = db.query( "SELECT CharacterId FROM charainfo WHERE Name = " + playerName );
|
|
|
|
if( !res->next() )
|
|
|
|
return nullptr;
|
2018-09-09 23:56:22 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
uint64_t characterId = res->getUInt64( 1 );
|
|
|
|
|
|
|
|
return addPlayer( characterId );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Sapphire::World::WorldServer::loadPlayers()
|
|
|
|
{
|
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto res = db.query( "SELECT CharacterId FROM charainfo" );
|
|
|
|
|
|
|
|
// no players or failed
|
2018-09-09 23:56:22 +02:00
|
|
|
while( res->next() )
|
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
uint64_t characterId = res->getUInt64( 1 );
|
|
|
|
if( !addPlayer( characterId ) )
|
|
|
|
return false;
|
2018-09-09 23:56:22 +02:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
return true;
|
2018-09-09 23:56:22 +02:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
Sapphire::Entity::PlayerPtr Sapphire::World::WorldServer::syncPlayer( uint64_t characterId )
|
2018-09-09 23:56:22 +02:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto pPlayer = getPlayer( characterId );
|
|
|
|
if( !pPlayer )
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
// get our cached last db write
|
|
|
|
auto lastCacheSync = pPlayer->getLastDBWrite();
|
2018-09-09 23:56:22 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
// update this player's last db write
|
|
|
|
if( !pPlayer->syncLastDBWrite() )
|
2018-09-09 23:56:22 +02:00
|
|
|
return nullptr;
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
// get db last write
|
|
|
|
auto dbSync = pPlayer->getLastDBWrite();
|
2018-09-09 23:56:22 +02:00
|
|
|
|
2021-12-02 00:08:33 +01:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
// db was updated and we lost track of it - update
|
2021-12-02 00:08:33 +01:00
|
|
|
// @todo for now, always reload the player on login.
|
|
|
|
//if( dbSync != lastCacheSync )
|
2018-09-09 23:56:22 +02:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
// clear current maps
|
|
|
|
m_playerMapById[ pPlayer->getId() ] = nullptr;
|
|
|
|
m_playerMapByName[ pPlayer->getName() ] = nullptr;
|
|
|
|
m_playerMapByCharacterId[ pPlayer->getCharacterId() ] = nullptr;
|
|
|
|
|
|
|
|
if( !pPlayer->loadFromDb( characterId ) )
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
m_playerMapById[ pPlayer->getId() ] = pPlayer;
|
|
|
|
m_playerMapByCharacterId[ pPlayer->getCharacterId() ] = pPlayer;
|
|
|
|
m_playerMapByName[ pPlayer->getName() ] = pPlayer;
|
2018-09-09 23:56:22 +02:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
return pPlayer;
|
2018-09-26 08:47:22 -04:00
|
|
|
}
|
2019-01-07 23:00:09 +11:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
std::map< int32_t, Sapphire::World::WorldServer::BNPCMap >& Sapphire::World::WorldServer::getBNpcTeriMap()
|
|
|
|
{
|
|
|
|
return m_bNpcTerritoryMap;
|
|
|
|
}
|
|
|
|
|
|
|
|
Sapphire::Common::Config::WorldConfig& Sapphire::World::WorldServer::getConfig()
|
2019-01-07 23:00:09 +11:00
|
|
|
{
|
|
|
|
return m_config;
|
|
|
|
}
|
2021-11-27 00:53:57 +01:00
|
|
|
|
|
|
|
void Sapphire::World::WorldServer::queueForPlayer( uint64_t characterId, Sapphire::Network::Packets::FFXIVPacketBasePtr pPacket )
|
|
|
|
{
|
|
|
|
auto pSession = getSession( characterId );
|
|
|
|
if( !pSession )
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto pZoneCon = pSession->getZoneConnection();
|
|
|
|
if( pZoneCon )
|
|
|
|
pZoneCon->queueOutPacket( pPacket );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sapphire::World::WorldServer::queueForPlayer( uint64_t characterId, std::vector< Sapphire::Network::Packets::FFXIVPacketBasePtr > packets )
|
|
|
|
{
|
|
|
|
auto pSession = getSession( characterId );
|
|
|
|
if( !pSession )
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto pZoneCon = pSession->getZoneConnection();
|
|
|
|
if( pZoneCon )
|
|
|
|
for( auto& packet : packets )
|
|
|
|
{
|
|
|
|
pZoneCon->queueOutPacket( packet );
|
|
|
|
}
|
|
|
|
}
|