From 598dd50ff22684b9fdc735d67e27be50e324b702 Mon Sep 17 00:00:00 2001 From: Mordred Date: Tue, 2 Apr 2019 00:00:58 +0200 Subject: [PATCH 1/2] More simplifications of the questbattle handling, exposing a script function to init player position --- .../instances/questbattles/ChasingShadows.cpp | 7 + src/world/Manager/DebugCommandMgr.cpp | 39 ------ src/world/Network/Handlers/EventHandlers.cpp | 2 +- src/world/Script/NativeScriptApi.cpp | 4 + src/world/Script/NativeScriptApi.h | 2 + src/world/Script/ScriptMgr.cpp | 12 ++ src/world/Script/ScriptMgr.h | 2 + src/world/Territory/QuestBattle.cpp | 127 ++++-------------- src/world/Territory/QuestBattle.h | 24 +--- 9 files changed, 54 insertions(+), 165 deletions(-) diff --git a/src/scripts/instances/questbattles/ChasingShadows.cpp b/src/scripts/instances/questbattles/ChasingShadows.cpp index 9556d87e..fb41d969 100644 --- a/src/scripts/instances/questbattles/ChasingShadows.cpp +++ b/src/scripts/instances/questbattles/ChasingShadows.cpp @@ -1,5 +1,6 @@ #include #include +#include using namespace Sapphire; @@ -28,6 +29,12 @@ public: ChasingShadows() : Sapphire::ScriptAPI::QuestBattleScript( 11 ) { } + void onPlayerSetup( Sapphire::QuestBattle& instance, Entity::Player& player ) + { + player.setRot( 3.f ); + player.setPos( { 323.f, -1.28f, -320.f } ); + } + void onInit( QuestBattle& instance ) override { instance.registerEObj( "unknown_0", 2005192, 5760474, 4, { -51.493111f, 0.309087f, 71.436897f }, 1.000000f, -0.000006f ); diff --git a/src/world/Manager/DebugCommandMgr.cpp b/src/world/Manager/DebugCommandMgr.cpp index 6ace74fc..27000355 100644 --- a/src/world/Manager/DebugCommandMgr.cpp +++ b/src/world/Manager/DebugCommandMgr.cpp @@ -1030,45 +1030,6 @@ void Sapphire::World::Manager::DebugCommandMgr::questBattle( char* data, Entity: else player.sendDebug( "Failed to create instance with id#{0}", contentFinderConditionId ); } - else if( subCommand == "bind" ) - { - uint32_t instanceId; - sscanf( params.c_str(), "%d", &instanceId ); - - auto instance = pTeriMgr->getInstanceZonePtr( instanceId ); - if( instance ) - { - auto pInstanceContent = instance->getAsQuestBattle(); - pInstanceContent->bindPlayer( player.getId() ); - player.sendDebug( - "Now bound to instance with id: " + std::to_string( pInstanceContent->getGuId() ) + - " -> " + pInstanceContent->getName() ); - } - else - player.sendDebug( "Unknown instance with id#{0}", instanceId ); - } - else if( subCommand == "unbind" ) - { - uint32_t instanceId; - sscanf( params.c_str(), "%d", &instanceId ); - - auto instance = pTeriMgr->getInstanceZonePtr( instanceId ); - if( !instance ) - { - player.sendDebug( "Unknown instance with id#{0} ", instanceId ); - return; - } - - auto pInstanceContent = instance->getAsQuestBattle(); - if( pInstanceContent->isPlayerBound( player.getId() ) ) - { - pInstanceContent->unbindPlayer( player.getId() ); - player.sendDebug( "Now unbound from instance with id#{0} -> {1}", pInstanceContent->getGuId(), pInstanceContent->getName() ); - } - else - player.sendDebug( "Player not bound to instance with id#{0}", instanceId ); - - } else if( subCommand == "createzone" || subCommand == "crz" ) { uint32_t zoneId; diff --git a/src/world/Network/Handlers/EventHandlers.cpp b/src/world/Network/Handlers/EventHandlers.cpp index b74be7ea..5c60ed7f 100644 --- a/src/world/Network/Handlers/EventHandlers.cpp +++ b/src/world/Network/Handlers/EventHandlers.cpp @@ -174,7 +174,7 @@ void Sapphire::Network::GameConnection::eventHandlerEnterTerritory( FrameworkPtr std::string objName = pEventMgr->getEventName( eventId ); - player.sendDebug( "Calling: {0}.{1} - {2}", objName, eventName, eventId && 0xFFFF ); + player.sendDebug( "Calling: {0}.{1} - {2}", objName, eventName, eventId & 0xFFFF ); if( auto instance = player.getCurrentInstance() ) { diff --git a/src/world/Script/NativeScriptApi.cpp b/src/world/Script/NativeScriptApi.cpp index b1bfef51..471f48e2 100644 --- a/src/world/Script/NativeScriptApi.cpp +++ b/src/world/Script/NativeScriptApi.cpp @@ -201,6 +201,10 @@ namespace Sapphire::ScriptAPI { } + void QuestBattleScript::onPlayerSetup( Sapphire::QuestBattle& instance, Entity::Player& player ) + { + } + void QuestBattleScript::onInit( QuestBattle& instance ) { } diff --git a/src/world/Script/NativeScriptApi.h b/src/world/Script/NativeScriptApi.h index 426230d1..a18b3cc9 100644 --- a/src/world/Script/NativeScriptApi.h +++ b/src/world/Script/NativeScriptApi.h @@ -239,6 +239,8 @@ namespace Sapphire::ScriptAPI public: explicit QuestBattleScript( uint32_t questBattleId ); + virtual void onPlayerSetup( Sapphire::QuestBattle& instance, Entity::Player& player ); + virtual void onInit( Sapphire::QuestBattle& instance ); virtual void onUpdate( Sapphire::QuestBattle& instance, uint32_t currTime ); diff --git a/src/world/Script/ScriptMgr.cpp b/src/world/Script/ScriptMgr.cpp index 9e7e85f5..27f373d0 100644 --- a/src/world/Script/ScriptMgr.cpp +++ b/src/world/Script/ScriptMgr.cpp @@ -462,6 +462,18 @@ bool Sapphire::Scripting::ScriptMgr::onInstanceEnterTerritory( InstanceContentPt return false; } +bool Sapphire::Scripting::ScriptMgr::onPlayerSetup( QuestBattle& instance, Entity::Player& player ) +{ + auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::QuestBattleScript >( instance.getDirectorId() ); + if( script ) + { + script->onPlayerSetup( instance, player ); + return true; + } + + return false; +} + bool Sapphire::Scripting::ScriptMgr::onInstanceInit( QuestBattlePtr instance ) { auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::QuestBattleScript >( instance->getDirectorId() ); diff --git a/src/world/Script/ScriptMgr.h b/src/world/Script/ScriptMgr.h index 97e3b345..b5faffc5 100644 --- a/src/world/Script/ScriptMgr.h +++ b/src/world/Script/ScriptMgr.h @@ -100,6 +100,8 @@ namespace Sapphire::Scripting onInstanceEnterTerritory( InstanceContentPtr instance, Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ); + bool onPlayerSetup( QuestBattle& instance, Entity::Player& player ); + bool onInstanceInit( QuestBattlePtr instance ); bool onInstanceUpdate( QuestBattlePtr instance, uint32_t currTime ); diff --git a/src/world/Territory/QuestBattle.cpp b/src/world/Territory/QuestBattle.cpp index feb316a4..4e65dd99 100644 --- a/src/world/Territory/QuestBattle.cpp +++ b/src/world/Territory/QuestBattle.cpp @@ -74,6 +74,8 @@ void Sapphire::QuestBattle::onPlayerZoneIn( Entity::Player& player ) Logger::debug( "QuestBattle::onPlayerZoneIn: Zone#{0}|{1}, Entity#{2}", getGuId(), getTerritoryTypeId(), player.getId() ); + m_pPlayer = player.getAsPlayer(); + // mark player as "bound by duty" player.setStateFlag( PlayerStateFlag::BoundByDuty ); @@ -92,24 +94,26 @@ void Sapphire::QuestBattle::onLeaveTerritory( Entity::Player& player ) clearDirector( player ); } +void Sapphire::QuestBattle::onEnterSceneFinish( Entity::Player& player ) +{ + player.eventStart( player.getId(), getDirectorId(), Event::EventHandler::GameProgress, 1, 0 ); + player.playScene( getDirectorId(), 60000, 0x40000 /*unmapped*/ ); + setSequence( 2 ); +} + void Sapphire::QuestBattle::onUpdate( uint32_t currTime ) { switch( m_state ) { case Created: { - if( m_boundPlayerId == 0 ) + if( !m_pPlayer ) return; - auto it = m_playerMap.find( m_boundPlayerId ); - if( it == m_playerMap.end() ) - return; - - auto player = it->second; - if( !player->isLoadingComplete() || - !player->isDirectorInitialized() || - !player->isOnEnterEventDone() || - player->hasStateFlag( PlayerStateFlag::WatchingCutscene ) ) + if( !m_pPlayer->isLoadingComplete() || + !m_pPlayer->isDirectorInitialized() || + !m_pPlayer->isOnEnterEventDone() || + m_pPlayer->hasStateFlag( PlayerStateFlag::WatchingCutscene ) ) return; if( m_instanceCommenceTime == 0 ) @@ -120,19 +124,13 @@ void Sapphire::QuestBattle::onUpdate( uint32_t currTime ) else if( Util::getTimeMs() < m_instanceCommenceTime ) return; - // TODO: we do not have a list of players for questbattles... just one - for( const auto& playerIt : m_playerMap ) - { - auto pPlayer = playerIt.second; - pPlayer->sendDebug( " ALL DONE LOADING " ); - } + onEnterSceneFinish( *m_pPlayer ); m_state = DutyInProgress; m_instanceExpireTime = Util::getTimeSeconds() + ( m_pBattleDetails->timeLimit * 60u ); break; } - case DutyReset: break; @@ -141,7 +139,6 @@ void Sapphire::QuestBattle::onUpdate( uint32_t currTime ) break; } - case DutyFinished: break; } @@ -237,59 +234,35 @@ void Sapphire::QuestBattle::setVar( uint8_t index, uint8_t value ) } - // todo: genericise this? - for( const auto& playerIt : m_playerMap ) - { - sendDirectorVars( *playerIt.second ); - } + sendDirectorVars( *m_pPlayer ); } void Sapphire::QuestBattle::setSequence( uint8_t value ) { setDirectorSequence( value ); - - for( const auto& playerIt : m_playerMap ) - { - sendDirectorVars( *playerIt.second ); - } + sendDirectorVars( *m_pPlayer ); } void Sapphire::QuestBattle::setBranch( uint8_t value ) { setDirectorBranch( value ); + sendDirectorVars( *m_pPlayer ); - for( const auto& playerIt : m_playerMap ) - { - sendDirectorVars( *playerIt.second ); - } } void Sapphire::QuestBattle::startQte() { - for( const auto& playerIt : m_playerMap ) - { - auto player = playerIt.second; - player->queuePacket( makeActorControl143( player->getId(), DirectorUpdate, getDirectorId(), 0x8000000A ) ); - } + m_pPlayer->queuePacket( makeActorControl143( m_pPlayer->getId(), DirectorUpdate, getDirectorId(), 0x8000000A ) ); } void Sapphire::QuestBattle::startEventCutscene() { - // TODO: lock player movement - for( const auto& playerIt : m_playerMap ) - { - auto player = playerIt.second; - player->queuePacket( makeActorControl143( player->getId(), DirectorUpdate, getDirectorId(), 0x80000008 ) ); - } + m_pPlayer->queuePacket( makeActorControl143( m_pPlayer->getId(), DirectorUpdate, getDirectorId(), 0x80000008 ) ); } void Sapphire::QuestBattle::endEventCutscene() { - for( const auto& playerIt : m_playerMap ) - { - auto player = playerIt.second; - player->queuePacket( makeActorControl143( player->getId(), DirectorUpdate, getDirectorId(), 0x80000009 ) ); - } + m_pPlayer->queuePacket( makeActorControl143( m_pPlayer->getId(), DirectorUpdate, getDirectorId(), 0x80000009 ) ); } void Sapphire::QuestBattle::onRegisterEObj( Entity::EventObjectPtr object ) @@ -315,14 +288,10 @@ Sapphire::Event::Director::DirectorState Sapphire::QuestBattle::getState() const void Sapphire::QuestBattle::onBeforePlayerZoneIn( Sapphire::Entity::Player& player ) { - // remove any players from the instance who aren't bound on zone in - if( !isPlayerBound( player.getId() ) ) - player.exitInstance(); - - // TODO: let script set start position?? player.setRot( PI ); player.setPos( { 0.f, 0.f, 0.f } ); - + auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >(); + pScriptMgr->onPlayerSetup( *this, player ); player.resetObjSpawnIndex(); } @@ -366,56 +335,6 @@ Sapphire::QuestBattle::onEnterTerritory( Entity::Player& player, uint32_t eventI } -void Sapphire::QuestBattle::setCurrentBGM( uint16_t bgmIndex ) -{ - m_currentBgm = bgmIndex; - - for( const auto& playerIt : m_playerMap ) - { - auto player = playerIt.second; - // note: retail do send a BGM_MUTE(1) first before any BGM transition, but YOLO in this case. - // also do note that this code can't control the bgm granularly. (i.e. per player for WoD submap.) oops. - // player->queuePacket( ActorControlPacket143( player->getId(), DirectorUpdate, getDirectorId(), 0x80000001, 1 ) ); - player->queuePacket( - makeActorControl143( player->getId(), DirectorUpdate, getDirectorId(), 0x80000001, bgmIndex ) ); - } -} - -void Sapphire::QuestBattle::setPlayerBGM( Sapphire::Entity::Player& player, uint16_t bgmId ) -{ - player.queuePacket( makeActorControl143( player.getId(), DirectorUpdate, getDirectorId(), 0x80000001, bgmId ) ); -} - -uint16_t Sapphire::QuestBattle::getCurrentBGM() const -{ - return m_currentBgm; -} - -bool Sapphire::QuestBattle::bindPlayer( uint32_t playerId ) -{ - // if player already bound, return false - if( m_boundPlayerId != 0 ) - return false; - - m_boundPlayerId = playerId; - return true; -} - -bool Sapphire::QuestBattle::isPlayerBound( uint32_t playerId ) const -{ - return m_boundPlayerId == playerId; -} - -void Sapphire::QuestBattle::unbindPlayer( uint32_t playerId ) -{ - if( m_boundPlayerId != playerId ) - return; - - auto it = m_playerMap.find( playerId ); - if( it != m_playerMap.end() ) - it->second->exitInstance(); -} - void Sapphire::QuestBattle::clearDirector( Entity::Player& player ) { sendDirectorClear( player ); diff --git a/src/world/Territory/QuestBattle.h b/src/world/Territory/QuestBattle.h index e954a60c..87b888ad 100644 --- a/src/world/Territory/QuestBattle.h +++ b/src/world/Territory/QuestBattle.h @@ -47,6 +47,8 @@ namespace Sapphire void onRegisterEObj( Entity::EventObjectPtr object ) override; + void onEnterSceneFinish( Entity::Player& player ); + void setVar( uint8_t index, uint8_t value ); void setSequence( uint8_t value ); @@ -61,15 +63,6 @@ namespace Sapphire void clearDirector( Entity::Player& player ); - /*! set the current bgm index (inside bgm.exd) */ - void setCurrentBGM( uint16_t bgmId ); - - /*! set the current bgm for a specific player */ - void setPlayerBGM( Entity::Player& player, uint16_t bgmId ); - - /*! get the currently playing bgm index */ - uint16_t getCurrentBGM() const; - Event::Director::DirectorState getState() const; std::shared_ptr< Sapphire::Data::QuestBattle > getQuestBattleDetails() const; @@ -78,15 +71,6 @@ namespace Sapphire Entity::EventObjectPtr getEObjByName( const std::string& name ); - /*! binds a player to the instance */ - bool bindPlayer( uint32_t playerId ); - - /*! removes bind of player from the instance */ - void unbindPlayer( uint32_t playerId ); - - /*! return true if the player is bound to the instance */ - bool isPlayerBound( uint32_t playerId ) const; - /*! number of milliseconds after all players are ready for the instance to commence (spawn circle removed) */ const uint32_t instanceStartDelay = 1250; @@ -94,16 +78,14 @@ namespace Sapphire std::shared_ptr< Sapphire::Data::QuestBattle > m_pBattleDetails; uint32_t m_questBattleId; Event::Director::DirectorState m_state; - uint16_t m_currentBgm; int64_t m_instanceExpireTime; uint64_t m_instanceCommenceTime; std::map< std::string, Entity::EventObjectPtr > m_eventObjectMap; std::unordered_map< uint32_t, Entity::EventObjectPtr > m_eventIdToObjectMap; - std::set< uint32_t > m_spawnedPlayers; + Entity::PlayerPtr m_pPlayer; - uint32_t m_boundPlayerId; }; } From 8a7406565ea8749c72bc3916d0ead745c6bbfe84 Mon Sep 17 00:00:00 2001 From: Mordred <30826167+SapphireMordred@users.noreply.github.com> Date: Tue, 2 Apr 2019 09:00:36 +0200 Subject: [PATCH 2/2] Added Biscuits findings to servernotices --- .../Network/PacketDef/Zone/ServerZoneDef.h | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 950c20c3..b8b4cdd0 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -137,14 +137,34 @@ namespace Sapphire::Network::Packets::Server char searchComment[195]; char padding; }; - + + /** + * Structural representation of the packet sent by the server + * to display a server notice message + */ + struct FFXIVIpcServerNoticeShort : FFXIVIpcBasePacket< ServerNoticeShort > + { + // these are actually display flags + /* 0000 */ uint8_t padding; + // 0 = chat log + // 2 = nothing + // 4 = on screen message + // 5 = on screen message + chat log + char message[538]; + }; + /** * Structural representation of the packet sent by the server * to display a server notice message */ struct FFXIVIpcServerNotice : FFXIVIpcBasePacket< ServerNotice > { + // these are actually display flags /* 0000 */ uint8_t padding; + // 0 = chat log + // 2 = nothing + // 4 = on screen message + // 5 = on screen message + chat log char message[775]; };