diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index b08ec3d0..4c9caf2f 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -259,13 +259,13 @@ struct FFXIVIpcYieldEventSceneString8 : { }; -struct YieldEventSceneString16 : +struct FFXIVIpcYieldEventSceneString16 : FFXIVIpcBasePacket< YieldEventSceneString16 >, YieldEventSceneStringN< 16 > { }; -struct YieldEventSceneString32 : +struct FFXIVIpcYieldEventSceneString32 : FFXIVIpcBasePacket< YieldEventSceneString32 >, YieldEventSceneStringN< 32 > { diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 327ea543..0b6e4cb1 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1494,17 +1494,13 @@ namespace Sapphire::Network::Packets::WorldPackets::Server * Structural representation of the packet sent by the server * to respond to a linkshell creation event */ - struct FFXIVIpcEventLinkshell : FFXIVIpcBasePacket< ResumeEventScene2 > + struct FFXIVIpcResumeEventScene2 : FFXIVIpcBasePacket< ResumeEventScene2 > { - uint32_t eventId; - uint8_t scene; - uint8_t param1; - uint8_t param2; - uint8_t param3; - uint32_t unknown1; - uint32_t unknown2; - uint32_t unknown3; - uint32_t unknown4; + uint32_t handlerId; + uint16_t sceneId; + uint8_t resumeId; + uint8_t numOfArgs; + uint32_t args[4]; }; /** @@ -2165,5 +2161,4 @@ struct FFXIVIpcEorzeaTimeOffset : FFXIVIpcBasePacket< TimeOffset > { ZoneProtoDownMemberPos Member[8]; }; - } diff --git a/src/scripts/ScriptLoader.cpp.in b/src/scripts/ScriptLoader.cpp.in index e0fe6f4b..c3a220b7 100644 --- a/src/scripts/ScriptLoader.cpp.in +++ b/src/scripts/ScriptLoader.cpp.in @@ -22,6 +22,7 @@ namespace Sapphire::Data namespace Sapphire::World::Manager { class TerritoryMgr; + class LinkshellMgr; } extern "C" EXPORT void win32initExd( std::shared_ptr< Sapphire::Data::ExdData > exdData ) @@ -33,6 +34,10 @@ extern "C" EXPORT void win32initTeri( std::shared_ptr< Sapphire::World::Manager: { Sapphire::Common::Service< Sapphire::World::Manager::TerritoryMgr >::set( teriMgr ); } +extern "C" EXPORT void win32initLinkshell( std::shared_ptr< Sapphire::World::Manager::LinkshellMgr > lsMgr ) +{ + Sapphire::Common::Service< Sapphire::World::Manager::LinkshellMgr >::set( lsMgr ); +} #endif extern "C" EXPORT const Sapphire::ScriptAPI::ScriptObject** getScripts() diff --git a/src/scripts/common/CmnDefLinkShell.cpp b/src/scripts/common/CmnDefLinkShell.cpp index 053e0e35..1fa14686 100644 --- a/src/scripts/common/CmnDefLinkShell.cpp +++ b/src/scripts/common/CmnDefLinkShell.cpp @@ -42,7 +42,13 @@ public: // create linkshell void Scene00002( Entity::Player& player ) { - eventMgr().playScene( player, getId(), 2, 0 ); + auto callback = [ this ]( Entity::Player& player, const Event::SceneResult& result ) + { + linkshellMgr().createLinkshell( result.resultString, player ); + eventMgr().resumeScene( player, result.eventId, result.sceneId, { 0x15a } ); + }; + + eventMgr().playScene( player, getId(), 2, 0, callback ); } // rename linkshell diff --git a/src/world/Event/EventHandler.h b/src/world/Event/EventHandler.h index a75d5d3a..924d1b58 100644 --- a/src/world/Event/EventHandler.h +++ b/src/world/Event/EventHandler.h @@ -14,6 +14,7 @@ namespace Sapphire::Event uint8_t errorCode; uint8_t numOfResults; std::vector< uint32_t > results; + std::string resultString; uint32_t getResult( uint32_t index ) const; }; diff --git a/src/world/Manager/EventMgr.cpp b/src/world/Manager/EventMgr.cpp index 44db6568..0fcf150f 100644 --- a/src/world/Manager/EventMgr.cpp +++ b/src/world/Manager/EventMgr.cpp @@ -314,6 +314,40 @@ void Sapphire::World::Manager::EventMgr::handleReturnEventScene( Entity::Player& checkEvent( player, eventId ); } +void EventMgr::handleReturnStringEventScene( Entity::Player& player, uint32_t eventId, uint16_t sceneId, const std::string& resultString ) +{ + std::string eventName = getEventName( eventId ); + + PlayerMgr::sendDebug( player, "eventId: {0} ({0:08X}) scene: {1}, string: {2} ", eventId, sceneId, resultString ); + + auto eventType = static_cast< uint16_t >( eventId >> 16 ); + auto pEvent = player.getEvent( eventId ); + + if( pEvent ) + { + pEvent->setPlayedScene( false ); + // try to retrieve a stored callback + // if there is one, proceed to call it + Event::SceneResult result; + result.actorId = pEvent->getActorId(); + result.eventId = eventId; + result.sceneId = sceneId; + result.resultString = resultString; + + auto eventCallback = pEvent->getEventReturnCallback(); + if( eventCallback ) + { + eventCallback( player, result ); + } + + // we might have a scene chain callback instead so check for that too + else if( auto chainCallback = pEvent->getSceneChainCallback() ) + chainCallback( player ); + + } + +} + void EventMgr::checkEvent( Sapphire::Entity::Player &player, uint32_t eventId ) { auto pEvent = player.getEvent( eventId ); @@ -508,6 +542,25 @@ void EventMgr::playScene( Entity::Player& player, uint32_t eventId, uint32_t sce sendEventPlay( player, eventId, scene, flags ); } +void EventMgr::resumeScene( Entity::Player& player, uint32_t eventId, uint32_t scene, std::vector< uint32_t > values ) +{ + auto pEvent = bootstrapSceneEvent( player, eventId, 0 ); + if( !pEvent ) + return; + + auto linkshellEvent = makeZonePacket< FFXIVIpcResumeEventScene2 >( player.getId() ); + linkshellEvent->data().handlerId = eventId; + linkshellEvent->data().sceneId = static_cast< uint8_t >( scene ); + linkshellEvent->data().numOfArgs = values.size(); + int i = 0; + for( auto& val : values ) + { + linkshellEvent->data().args[ i++ ] = val; + } + auto& server = Common::Service< World::WorldServer >::ref(); + server.queueForPlayer( player.getCharacterId(), linkshellEvent ); +} + void EventMgr::playScene( Entity::Player& player, uint32_t eventId, uint32_t scene, uint32_t flags, Event::EventHandler::SceneReturnCallback eventCallback ) { auto pEvent = bootstrapSceneEvent( player, eventId, flags ); diff --git a/src/world/Manager/EventMgr.h b/src/world/Manager/EventMgr.h index d569dd62..2354bae1 100644 --- a/src/world/Manager/EventMgr.h +++ b/src/world/Manager/EventMgr.h @@ -21,6 +21,8 @@ namespace Sapphire::World::Manager void handleReturnEventScene( Entity::Player& player, uint32_t eventId, uint16_t sceneId, uint8_t errorCode, uint8_t numOfResults, const std::vector< uint32_t >& results ); + void handleReturnStringEventScene( Entity::Player& player, uint32_t eventId, uint16_t sceneId, const std::string& resultString ); + void checkEvent( Entity::Player& player, uint32_t eventId ); void eventFinish( Entity::Player& player, uint32_t eventId, uint32_t freePlayer ); @@ -38,6 +40,9 @@ namespace Sapphire::World::Manager void playScene( Entity::Player& player, uint32_t eventId, uint32_t scene, uint32_t flags, std::vector< uint32_t > values, Event::EventHandler::SceneReturnCallback eventReturnCallback = nullptr ); + /*! resume a subevent */ + void resumeScene( Entity::Player& player, uint32_t eventId, uint32_t scene, std::vector< uint32_t > values ); + /*! play a subevent */ void playScene( Entity::Player& player, uint32_t eventId, uint32_t scene, uint32_t flags, Event::EventHandler::SceneReturnCallback eventReturnCallback = nullptr ); diff --git a/src/world/Network/GameConnection.cpp b/src/world/Network/GameConnection.cpp index d566fb99..67f8a425 100644 --- a/src/world/Network/GameConnection.cpp +++ b/src/world/Network/GameConnection.cpp @@ -107,9 +107,9 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH setZoneHandler( StartUIEvent, "StartUIEvent", &GameConnection::startUiEvent ); - setZoneHandler( YieldEventSceneString8, "YieldEventSceneString8", &GameConnection::eventHandlerLinkshell ); - - setZoneHandler( YieldEventSceneString16, "YieldEventSceneString16", &GameConnection::eventHandlerLinkshell ); + setZoneHandler( YieldEventSceneString8, "YieldEventSceneString8", &GameConnection::yieldEventString ); + setZoneHandler( YieldEventSceneString16, "YieldEventSceneString16", &GameConnection::yieldEventString ); + setZoneHandler( YieldEventSceneString32, "YieldEventSceneString32", &GameConnection::yieldEventString ); setZoneHandler( RequestPenalties, "RequestPenalties", &GameConnection::cfRequestPenalties ); setZoneHandler( FindContent, "FindContent", &GameConnection::findContent ); diff --git a/src/world/Network/GameConnection.h b/src/world/Network/GameConnection.h index e67b52b5..39d775ce 100644 --- a/src/world/Network/GameConnection.h +++ b/src/world/Network/GameConnection.h @@ -160,6 +160,8 @@ namespace Sapphire::Network DECLARE_HANDLER( eventHandlerLinkshell ); + DECLARE_HANDLER( yieldEventString ); + DECLARE_HANDLER( logoutHandler ); DECLARE_HANDLER( cfRequestPenalties ); diff --git a/src/world/Network/Handlers/EventHandlers.cpp b/src/world/Network/Handlers/EventHandlers.cpp index 8f24ae41..1a098956 100644 --- a/src/world/Network/Handlers/EventHandlers.cpp +++ b/src/world/Network/Handlers/EventHandlers.cpp @@ -22,6 +22,7 @@ #include "Territory/QuestBattle.h" #include "Session.h" +#include using namespace Sapphire::Common; using namespace Sapphire::Network::Packets; @@ -291,15 +292,51 @@ void Sapphire::Network::GameConnection::eventHandlerLinkshell( const Packets::FF auto& server = Common::Service< World::WorldServer >::ref(); const auto packet = ZoneChannelPacket< FFXIVIpcYieldEventSceneString8 >( inPacket ); - auto linkshellEvent = makeZonePacket< FFXIVIpcEventLinkshell >( player.getId() ); - linkshellEvent->data().eventId = packet.data().handlerId; - linkshellEvent->data().scene = static_cast< uint8_t >( packet.data().sceneId ); - linkshellEvent->data().param3 = 1; - linkshellEvent->data().unknown1 = 0x15a; + auto linkshellEvent = makeZonePacket< FFXIVIpcResumeEventScene2 >( player.getId() ); + linkshellEvent->data().handlerId = packet.data().handlerId; + linkshellEvent->data().sceneId = static_cast< uint8_t >( packet.data().sceneId ); + linkshellEvent->data().numOfArgs = 1; + linkshellEvent->data().args[ 0 ] = 0x15a; server.queueForPlayer( player.getCharacterId(), linkshellEvent ); } +void Sapphire::Network::GameConnection::yieldEventString( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player ) +{ + auto& server = Common::Service< World::WorldServer >::ref(); + auto& eventMgr = Common::Service< World::Manager::EventMgr >::ref(); + + std::string inString; + + uint16_t type = *( ( uint16_t* ) ( &inPacket.data[ 2 ] ) ); + switch( type ) + { + case Packets::WorldPackets::Client::ClientZoneIpcType::YieldEventSceneString8: + { + const auto packet = ZoneChannelPacket< FFXIVIpcYieldEventSceneString8 >( inPacket ); + inString = std::string( packet.data().result ); + break; + } + case Packets::WorldPackets::Client::ClientZoneIpcType::YieldEventSceneString16: + { + const auto packet = ZoneChannelPacket< FFXIVIpcYieldEventSceneString16 >( inPacket ); + inString = std::string( packet.data().result ); + break; + } + case Packets::WorldPackets::Client::ClientZoneIpcType::YieldEventSceneString32: + { + const auto packet = ZoneChannelPacket< FFXIVIpcYieldEventSceneString32 >( inPacket ); + inString = std::string( packet.data().result ); + break; + } + } + + const auto packet = ZoneChannelPacket< FFXIVIpcYieldEventSceneString8 >( inPacket ); + auto& data = packet.data(); + eventMgr.handleReturnStringEventScene( player, data.handlerId, data.sceneId, inString ); + +} + void Sapphire::Network::GameConnection::startUiEvent( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player ) { diff --git a/src/world/Script/NativeScriptApi.h b/src/world/Script/NativeScriptApi.h index aabe195f..ab1aff49 100644 --- a/src/world/Script/NativeScriptApi.h +++ b/src/world/Script/NativeScriptApi.h @@ -5,6 +5,7 @@ #include "ForwardsZone.h" #include "Event/EventHandler.h" #include "Manager/EventMgr.h" +#include "Manager/LinkshellMgr.h" #include "Service.h" #ifdef _MSC_VER @@ -174,6 +175,11 @@ namespace Sapphire::ScriptAPI { return Common::Service< World::Manager::EventMgr >::ref(); } + + World::Manager::LinkshellMgr& linkshellMgr() + { + return Common::Service< World::Manager::LinkshellMgr >::ref(); + } }; class QuestScript : public ScriptObject diff --git a/src/world/Script/ScriptLoader.cpp b/src/world/Script/ScriptLoader.cpp index 131a549a..a188bf36 100644 --- a/src/world/Script/ScriptLoader.cpp +++ b/src/world/Script/ScriptLoader.cpp @@ -113,10 +113,12 @@ Sapphire::ScriptAPI::ScriptObject** Sapphire::Scripting::ScriptLoader::getScript #ifdef _WIN32 auto func = reinterpret_cast< getScripts >( GetProcAddress( handle, "getScripts" ) ); - using win32initFunc = void(*)( std::shared_ptr< Sapphire::Data::ExdData >); - using win32initFuncTeri = void(*)( std::shared_ptr< Sapphire::World::Manager::TerritoryMgr >); + using win32initFunc = void(*)( std::shared_ptr< Sapphire::Data::ExdData > ); + using win32initFuncTeri = void(*)( std::shared_ptr< Sapphire::World::Manager::TerritoryMgr > ); + using win32initFuncLinkshell = void(*)( std::shared_ptr< Sapphire::World::Manager::LinkshellMgr > ); auto win32init = reinterpret_cast< win32initFunc >( GetProcAddress( handle, "win32initExd" ) ); auto win32initTeri = reinterpret_cast< win32initFuncTeri >( GetProcAddress( handle, "win32initTeri" ) ); + auto win32initLinkshell = reinterpret_cast< win32initFuncLinkshell >( GetProcAddress( handle, "win32initLinkshell" ) ); if( win32init ) { @@ -138,7 +140,18 @@ Sapphire::ScriptAPI::ScriptObject** Sapphire::Scripting::ScriptLoader::getScript } else { - Logger::warn( "did not find a win32init1 export on a windows script target - the server will likely crash!" ); + Logger::warn( "did not find a win32initTeri export on a windows script target - the server will likely crash!" ); + } + + if( win32initLinkshell ) + { + auto linkshellMgr = Common::Service< Sapphire::World::Manager::LinkshellMgr >::get(); + auto tptr = linkshellMgr.lock(); + win32initLinkshell( tptr ); + } + else + { + Logger::warn( "did not find a win32initLinkshell export on a windows script target - the server will likely crash!" ); } #else auto func = reinterpret_cast< getScripts >( dlsym( handle, "getScripts" ) );