From 6aa7102b4ee98c237f346e3848644586ef11d58a Mon Sep 17 00:00:00 2001 From: Mordred Date: Thu, 1 Nov 2018 12:49:51 +0100 Subject: [PATCH 1/7] Char creation will no longer crash lobby/api --- src/servers/sapphire_api/SapphireAPI.cpp | 11 +++++++---- src/servers/sapphire_api/main.cpp | 4 +--- src/servers/sapphire_lobby/RestConnector.cpp | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/servers/sapphire_api/SapphireAPI.cpp b/src/servers/sapphire_api/SapphireAPI.cpp index 33602b13..1f981514 100644 --- a/src/servers/sapphire_api/SapphireAPI.cpp +++ b/src/servers/sapphire_api/SapphireAPI.cpp @@ -133,13 +133,16 @@ Core::Network::SapphireAPI::createCharacter( const int& accountId, const std::st for( auto& v : json["content"] ) { - for( auto& vs : v ) + if( v.is_array() ) { - tmpVector.push_back( vs.get< int >() ); + for( auto& vs : v ) + { + tmpVector.push_back( std::stoi( std::string( vs ) ) ); + } } - if( !v.empty() ) - tmpVector2.push_back( v.get< int >() ); + if( !v.empty() && !v.is_array() ) + tmpVector2.push_back( std::stoi( std::string( v ) ) ); } // leaving this in for now for reference diff --git a/src/servers/sapphire_api/main.cpp b/src/servers/sapphire_api/main.cpp index 5d627b64..90edbd05 100644 --- a/src/servers/sapphire_api/main.cpp +++ b/src/servers/sapphire_api/main.cpp @@ -488,9 +488,7 @@ void checkSession( shared_ptr< HttpServer::Response > response, shared_ptr< Http else { std::string json_string = nlohmann::json( { - { "result", result }, - { "result2", "penis" }, - { "result3", "wtf" } + { "result", result } } ).dump() ; *response << buildHttpResponse( 200, json_string, JSON ); diff --git a/src/servers/sapphire_lobby/RestConnector.cpp b/src/servers/sapphire_lobby/RestConnector.cpp index d17fe938..96ac9c6f 100644 --- a/src/servers/sapphire_lobby/RestConnector.cpp +++ b/src/servers/sapphire_lobby/RestConnector.cpp @@ -143,7 +143,7 @@ uint32_t Core::Network::RestConnector::getNextCharId() if( content.find( "invalid" ) == std::string::npos ) { - return json["result"].get< uint32_t >(); + return std::stoi( std::string( json["result"] ) ); } else { @@ -182,7 +182,7 @@ uint64_t Core::Network::RestConnector::getNextContentId() if( content.find( "invalid" ) == std::string::npos ) { - return json["result"].get< uint64_t >(); + return std::stoll( std::string( json["result"] ) ); } else { @@ -313,7 +313,7 @@ int Core::Network::RestConnector::createCharacter( char* sId, std::string name, } if( content.find( "invalid" ) == std::string::npos ) - return json["result"].get< int >(); + return std::stoi( json["result"].get< std::string >() ); return -1; } else From 10a38756c3b31389007c1174ce6d804a8891aee2 Mon Sep 17 00:00:00 2001 From: Mordred Date: Thu, 1 Nov 2018 13:05:10 +0100 Subject: [PATCH 2/7] Sync chardata on session close --- src/servers/sapphire_zone/Session.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/servers/sapphire_zone/Session.cpp b/src/servers/sapphire_zone/Session.cpp index 66e0b06b..3d5070de 100644 --- a/src/servers/sapphire_zone/Session.cpp +++ b/src/servers/sapphire_zone/Session.cpp @@ -77,8 +77,12 @@ void Core::Session::close() // remove the session from the player if( m_pPlayer ) + { + // do one last update to db + m_pPlayer->updateSql(); // reset the zone, so the zone handler knows to remove the actor m_pPlayer->setCurrentZone( nullptr ); + } } uint32_t Core::Session::getId() const From d51cb0740f31b77ee3316e585846ed751bbcb31b Mon Sep 17 00:00:00 2001 From: Mordred Date: Thu, 1 Nov 2018 15:19:07 +0100 Subject: [PATCH 3/7] Return min instead of max for itemlevel --- src/servers/sapphire_zone/Actor/PlayerInventory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp index 812a2f1e..c7cf8ea5 100644 --- a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp @@ -848,7 +848,7 @@ uint16_t Core::Entity::Player::calculateEquippedGearItemLevel() it++; } - return std::max( static_cast< int32_t >( iLvlResult / 13 ), 9999 ); + return std::min( static_cast< int32_t >( iLvlResult / 13 ), 9999 ); } From 5b2ab139596f1d6ce81063a533c564942739fe6b Mon Sep 17 00:00:00 2001 From: Mordred Date: Fri, 2 Nov 2018 21:33:25 +0100 Subject: [PATCH 4/7] Missing log-folder will now be created atomatically --- src/common/Logging/Logger.cpp | 123 ++++++++++--------- src/servers/sapphire_zone/mainGameServer.cpp | 2 +- 2 files changed, 67 insertions(+), 58 deletions(-) diff --git a/src/common/Logging/Logger.cpp b/src/common/Logging/Logger.cpp index 96225ebd..22534330 100644 --- a/src/common/Logging/Logger.cpp +++ b/src/common/Logging/Logger.cpp @@ -6,67 +6,76 @@ #include // #include +#include // or #include + +namespace fs = std::experimental::filesystem; namespace Core { + Logger::Logger() + { -Logger::Logger() -{ - -} - -Logger::~Logger() -{ - -} - -void Logger::setLogPath( const std::string& logPath ) -{ - m_logFile = logPath; -} - -void Logger::init() -{ - spdlog::init_thread_pool( 8192, 1 ); - - auto stdout_sink = std::make_shared< spdlog::sinks::stdout_color_sink_mt >(); - auto daily_sink = std::make_shared< spdlog::sinks::daily_file_sink_mt >( m_logFile + ".log", 0, 0 ); - - std::vector sinks { stdout_sink, daily_sink }; - - auto logger = std::make_shared< spdlog::async_logger >( "logger", sinks.begin(), sinks.end(), - spdlog::thread_pool(), spdlog::async_overflow_policy::block ); - - - spdlog::register_logger( logger ); - spdlog::set_pattern( "[%H:%M:%S.%e] [%^%l%$] %v" ); - spdlog::set_level( spdlog::level::debug ); - // always flush the log on criticial messages, otherwise it's done by libc - // see: https://github.com/gabime/spdlog/wiki/7.-Flush-policy - // nb: if the server crashes, log data can be missing from the file unless something logs critical just before it does - spdlog::flush_on( spdlog::level::critical ); -} - -void Logger::error( const std::string& text ) -{ - spdlog::get( "logger" )->error( text ); -} - -void Logger::info( const std::string& text ) -{ - spdlog::get( "logger" )->info( text ); -} - -void Logger::debug( const std::string& text ) -{ - spdlog::get( "logger" )->debug( text ); -} - -void Logger::fatal( const std::string& text ) -{ - spdlog::get( "logger" )->critical( text ); -} - + } + + Logger::~Logger() + { + + } + + void Logger::setLogPath( const std::string& logPath ) + { + auto pos = logPath.find_last_of( '/' ); + + if( pos != std::string::npos ) + { + std::string realPath = logPath.substr( 0, pos ); + fs::create_directories( realPath ); + } + + m_logFile = logPath; + } + + void Logger::init() + { + spdlog::init_thread_pool( 8192, 1 ); + + auto stdout_sink = std::make_shared< spdlog::sinks::stdout_color_sink_mt >(); + auto daily_sink = std::make_shared< spdlog::sinks::daily_file_sink_mt >( m_logFile + ".log", 0, 0 ); + + std::vector< spdlog::sink_ptr > sinks { stdout_sink, daily_sink }; + + auto logger = std::make_shared< spdlog::async_logger >( "logger", sinks.begin(), sinks.end(), + spdlog::thread_pool(), spdlog::async_overflow_policy::block ); + + + spdlog::register_logger( logger ); + spdlog::set_pattern( "[%H:%M:%S.%e] [%^%l%$] %v" ); + spdlog::set_level( spdlog::level::debug ); + // always flush the log on criticial messages, otherwise it's done by libc + // see: https://github.com/gabime/spdlog/wiki/7.-Flush-policy + // nb: if the server crashes, log data can be missing from the file unless something logs critical just before it does + spdlog::flush_on( spdlog::level::critical ); + } + + void Logger::error( const std::string& text ) + { + spdlog::get( "logger" )->error( text ); + } + + void Logger::info( const std::string& text ) + { + spdlog::get( "logger" )->info( text ); + } + + void Logger::debug( const std::string& text ) + { + spdlog::get( "logger" )->debug( text ); + } + + void Logger::fatal( const std::string& text ) + { + spdlog::get( "logger" )->critical( text ); + } } diff --git a/src/servers/sapphire_zone/mainGameServer.cpp b/src/servers/sapphire_zone/mainGameServer.cpp index b45e71b0..f9a07c4a 100644 --- a/src/servers/sapphire_zone/mainGameServer.cpp +++ b/src/servers/sapphire_zone/mainGameServer.cpp @@ -29,7 +29,7 @@ bool setupFramework() auto pDebugCom = std::make_shared< DebugCommandHandler >(); auto pConfig = std::make_shared< ConfigMgr >(); - pLogger->setLogPath( "log/SapphireZone_" ); + pLogger->setLogPath( "log/SapphireZone" ); pLogger->init(); g_fw.set< ServerZone >( pServer ); From 8e23292e82e6fef5600853fd55e0de16399b338d Mon Sep 17 00:00:00 2001 From: NotAdam Date: Tue, 6 Nov 2018 18:35:02 +1100 Subject: [PATCH 5/7] correctly copy default config file if it doesn't exist --- src/common/Config/ConfigMgr.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/common/Config/ConfigMgr.cpp b/src/common/Config/ConfigMgr.cpp index 91f8ff42..1fdc9af0 100644 --- a/src/common/Config/ConfigMgr.cpp +++ b/src/common/Config/ConfigMgr.cpp @@ -3,6 +3,8 @@ #include #include +namespace fs = std::experimental::filesystem; + /** * Loads an ini file and parses it * @param configName the name of ini file relative to m_configFolderRoot to load alongside global.ini @@ -11,10 +13,14 @@ bool Core::ConfigMgr::loadConfig( const std::string& configName ) { // get global config - auto configDir = std::experimental::filesystem::path( m_configFolderRoot ); + auto configFile = fs::path( fs::path( m_configFolderRoot ) / configName ); - m_pInih = std::unique_ptr< INIReader >( new INIReader( - std::experimental::filesystem::path( configDir / configName ).string() ) ); + if( !fs::exists( configFile ) ) + { + copyDefaultConfig( configName ); + } + + m_pInih = std::unique_ptr< INIReader >( new INIReader( configFile.string() ) ); if( m_pInih->ParseError() < 0 ) return false; @@ -24,16 +30,16 @@ bool Core::ConfigMgr::loadConfig( const std::string& configName ) bool Core::ConfigMgr::copyDefaultConfig( const std::string& configName ) { - std::experimental::filesystem::path configPath( m_configFolderRoot ); + fs::path configPath( m_configFolderRoot ); configPath /= configName; - if( !std::experimental::filesystem::exists( configPath.string() + m_configDefaultSuffix ) ) + if( !fs::exists( configPath.string() + m_configDefaultSuffix ) ) { // no default file :( return false; } - std::experimental::filesystem::copy_file( configPath.string() + m_configDefaultSuffix, configPath ); + fs::copy_file( configPath.string() + m_configDefaultSuffix, configPath ); return true; } From 61edc8248b8243a1cf076c1191e5dd03ad26e766 Mon Sep 17 00:00:00 2001 From: Mordred Date: Fri, 9 Nov 2018 21:36:40 +0100 Subject: [PATCH 6/7] Actually send gc information, too --- src/common/CommonGen.h | 8 +++----- .../sapphire_zone/Network/Handlers/PacketHandlers.cpp | 9 +++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/common/CommonGen.h b/src/common/CommonGen.h index dc99925d..63988bbc 100644 --- a/src/common/CommonGen.h +++ b/src/common/CommonGen.h @@ -148,10 +148,9 @@ enum class ExVersion : /////////////////////////////////////////////////////////// //GrandCompany.exd -enum class GrandCompany : - uint8_t +enum GrandCompany : uint8_t { - None = 0, + NoGc = 0, Maelstrom = 1, OrderoftheTwinAdder = 2, ImmortalFlames = 3, @@ -159,8 +158,7 @@ enum class GrandCompany : /////////////////////////////////////////////////////////// //GuardianDeity.exd -enum class GuardianDeity : - uint8_t +enum class GuardianDeity : uint8_t { HalonetheFury = 1, MenphinatheLover = 2, diff --git a/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp b/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp index c61c7730..80ee5f85 100644 --- a/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp @@ -434,6 +434,15 @@ void Core::Network::GameConnection::finishLoadingHandler( const Core::Network::P Entity::Player& player ) { player.sendQuestInfo(); + + // TODO: load and save this data instead of hardcoding + auto gcPacket = makeZonePacket< FFXIVGCAffiliation >( player.getId() ); + gcPacket->data().gcId = player.getGc(); + gcPacket->data().gcRank[ 0 ] = player.getGcRankArray()[ 0 ]; + gcPacket->data().gcRank[ 1 ] = player.getGcRankArray()[ 1 ]; + gcPacket->data().gcRank[ 2 ] = player.getGcRankArray()[ 2 ]; + player.queuePacket( gcPacket ); + player.getCurrentZone()->onFinishLoading( player ); // player is done zoning From 155b59785b5784445fbd7d9d23ba65d1e40b8301 Mon Sep 17 00:00:00 2001 From: Mordred Date: Sat, 10 Nov 2018 12:48:19 +0100 Subject: [PATCH 7/7] Start of land interaction --- src/common/Common.h | 8 ++++++- .../Scripts/common/CmnDefHousingSignboard.cpp | 24 +++++++++++++++---- src/servers/sapphire_zone/Actor/Player.cpp | 24 +++++++++---------- src/servers/sapphire_zone/Actor/Player.h | 8 ++++++- .../sapphire_zone/Actor/PlayerInventory.cpp | 11 +++++++++ .../Network/Handlers/ClientTriggerHandler.cpp | 3 +++ .../Network/Handlers/PacketHandlers.cpp | 2 +- 7 files changed, 60 insertions(+), 20 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index 1596cfe4..e43829f1 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -26,6 +26,12 @@ namespace Core::Common float z; }; + struct ActiveLand + { + uint8_t ward; + uint8_t plot; + }; + enum InventoryOperation : uint8_t { Discard = 0x07, @@ -770,7 +776,7 @@ namespace Core::Common struct LandPermissionSet { - int16_t landSetId; //00 + int16_t landId; //00 int16_t wardNum; //02 int16_t zoneId; //04 int16_t worldId; //06 diff --git a/src/servers/Scripts/common/CmnDefHousingSignboard.cpp b/src/servers/Scripts/common/CmnDefHousingSignboard.cpp index 54cb765e..04325bc9 100644 --- a/src/servers/Scripts/common/CmnDefHousingSignboard.cpp +++ b/src/servers/Scripts/common/CmnDefHousingSignboard.cpp @@ -1,20 +1,34 @@ #include #include +#include +#include using namespace Core; -class CmnDefHousingSignboard : - public EventScript +class CmnDefHousingSignboard : public EventScript { public: - CmnDefHousingSignboard() : - EventScript( 721031 ) + CmnDefHousingSignboard() : EventScript( 721031 ) { } void Scene00000( Entity::Player& player ) { - player.playScene( getId(), 0, HIDE_HOTBAR, 0, 0 ); + auto callback = [ this ]( Entity::Player& player, const Event::SceneResult& result ) + { + // Purchase Land + if( result.param2 == 2 ) + { + auto activeLand = player.getActiveLand(); + auto territoryId = player.getTerritoryId(); + + auto pTerritory = player.getCurrentZone(); + auto pHousing = std::dynamic_pointer_cast< HousingZone >( pTerritory ); + } + }; + + player.playScene( getId(), 0, HIDE_HOTBAR, 0, 0, callback ); + } void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override diff --git a/src/servers/sapphire_zone/Actor/Player.cpp b/src/servers/sapphire_zone/Actor/Player.cpp index e989149f..05f455cf 100644 --- a/src/servers/sapphire_zone/Actor/Player.cpp +++ b/src/servers/sapphire_zone/Actor/Player.cpp @@ -91,8 +91,8 @@ Core::Entity::Player::Player() : for ( uint8_t i = 0; i < 5; i++ ) { - memset( &m_housePermission[i], 0xFF, 8 ); - memset( &m_housePermission[i].permissionMask, 0, 8 ); + memset( &m_landPermission[i], 0xFF, 8 ); + memset( &m_landPermission[i].permissionMask, 0, 8 ); } m_objSpawnIndexAllocator.init( MAX_DISPLAYED_EOBJS ); @@ -1754,22 +1754,22 @@ bool Core::Entity::Player::isOnEnterEventDone() const void Core::Entity::Player::setLandPermissions( uint8_t permissionSet, uint32_t permissionMask, int16_t landSetId, int16_t wardNum, int16_t zoneId ) { - m_housePermission[permissionSet].landSetId = landSetId; - m_housePermission[permissionSet].permissionMask = permissionMask; - m_housePermission[permissionSet].wardNum = wardNum; - m_housePermission[permissionSet].worldId = 67; - m_housePermission[permissionSet].unkown1 = 0; + m_landPermission[permissionSet].landId = landSetId; + m_landPermission[permissionSet].permissionMask = permissionMask; + m_landPermission[permissionSet].wardNum = wardNum; + m_landPermission[permissionSet].worldId = 67; + m_landPermission[permissionSet].unkown1 = 0; } void Core::Entity::Player::sendLandPermissions() { auto landPermissions = makeZonePacket< FFXIVIpcLandPermission >( getId() ); - landPermissions->data().freeCompanyHouse = m_housePermission[Common::LandPermissionSlot::FreeCompany]; - landPermissions->data().privateHouse = m_housePermission[Common::LandPermissionSlot::Private]; - landPermissions->data().apartment = m_housePermission[Common::LandPermissionSlot::Apartment]; - landPermissions->data().sharedHouse[0] = m_housePermission[Common::LandPermissionSlot::SharedHouse1]; - landPermissions->data().sharedHouse[1] = m_housePermission[Common::LandPermissionSlot::SharedHouse2]; + landPermissions->data().freeCompanyHouse = m_landPermission[Common::LandPermissionSlot::FreeCompany]; + landPermissions->data().privateHouse = m_landPermission[Common::LandPermissionSlot::Private]; + landPermissions->data().apartment = m_landPermission[Common::LandPermissionSlot::Apartment]; + landPermissions->data().sharedHouse[0] = m_landPermission[Common::LandPermissionSlot::SharedHouse1]; + landPermissions->data().sharedHouse[1] = m_landPermission[Common::LandPermissionSlot::SharedHouse2]; memset( &landPermissions->data().unkownHouse, 0xFF, 8 ); memset( &landPermissions->data().unkownHouse.permissionMask, 0, 8 ); landPermissions->data().unkownHouse.permissionMask = 2; diff --git a/src/servers/sapphire_zone/Actor/Player.h b/src/servers/sapphire_zone/Actor/Player.h index f0aefd21..3c4c5242 100644 --- a/src/servers/sapphire_zone/Actor/Player.h +++ b/src/servers/sapphire_zone/Actor/Player.h @@ -911,6 +911,10 @@ namespace Core::Entity uint8_t getFreeSlotsInBags(); + void setActiveLand( uint8_t land, uint8_t ward ); + Common::ActiveLand getActiveLand() const; + + ////////////////////////////////////////////////////////////////////////////////////////////////////// uint64_t m_lastMoveTime; @@ -1020,7 +1024,9 @@ namespace Core::Entity uint8_t m_searchSelectClass; // class selected to show up in profile // housing info - Common::LandPermissionSet m_housePermission[5]; + Common::LandPermissionSet m_landPermission[5]; + + Common::ActiveLand m_activeLand; // gc info uint8_t m_gc; diff --git a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp index 630dcc39..11fa3f08 100644 --- a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp @@ -822,6 +822,17 @@ void Core::Entity::Player::discardItem( uint16_t fromInventoryId, uint8_t fromSl queuePacket( invTransFinPacket ); } +void Core::Entity::Player::setActiveLand( uint8_t land, uint8_t ward ) +{ + m_activeLand.plot = land; + m_activeLand.ward = ward; +} + +Core::Common::ActiveLand Core::Entity::Player::getActiveLand() const +{ + return m_activeLand; +} + uint16_t Core::Entity::Player::calculateEquippedGearItemLevel() { uint32_t iLvlResult = 0; diff --git a/src/servers/sapphire_zone/Network/Handlers/ClientTriggerHandler.cpp b/src/servers/sapphire_zone/Network/Handlers/ClientTriggerHandler.cpp index cb30f491..cbd7873a 100644 --- a/src/servers/sapphire_zone/Network/Handlers/ClientTriggerHandler.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/ClientTriggerHandler.cpp @@ -311,12 +311,15 @@ void Core::Network::GameConnection::clientTriggerHandler( const Packets::FFXIVAR } case ClientTriggerType::RequestHousingSign: { + auto plotPricePacket = makeZonePacket< Server::FFXIVIpcLandPriceUpdate >( player.getId() ); uint8_t ward = ( param12 & 0xFF00 ) >> 8; uint8_t plot = ( param12 & 0xFF ); pLog->debug( " Ward: " + std::to_string( ward ) + " Plot: " + std::to_string( plot ) ); + player.setActiveLand( plot, ward ); + auto zone = player.getCurrentZone(); auto hZone = std::dynamic_pointer_cast< HousingZone >( zone ); diff --git a/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp b/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp index 80ee5f85..34293a13 100644 --- a/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp @@ -442,7 +442,7 @@ void Core::Network::GameConnection::finishLoadingHandler( const Core::Network::P gcPacket->data().gcRank[ 1 ] = player.getGcRankArray()[ 1 ]; gcPacket->data().gcRank[ 2 ] = player.getGcRankArray()[ 2 ]; player.queuePacket( gcPacket ); - + player.getCurrentZone()->onFinishLoading( player ); // player is done zoning