diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index cb62d9f7..7b19e94a 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -2246,6 +2246,12 @@ namespace Sapphire::Network::Packets::Server uint16_t unknown; uint64_t unknown2; }; + + struct FFXIVDirectorUnk4 : FFXIVIpcBasePacket< SomeDirectorUnk4 > + { + uint32_t param[4]; + uint64_t unknown; + }; } #endif /*_CORE_NETWORK_PACKETS_SERVER_IPC_H*/ diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index 90f5d996..9fe99177 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -25,6 +25,8 @@ #include "Territory/Territory.h" #include "Territory/ZonePosition.h" #include "Territory/InstanceContent.h" +#include "Territory/QuestBattle.h" +#include "Territory/PublicContent.h" #include "Territory/InstanceObjectCache.h" #include "Territory/Land.h" @@ -83,7 +85,8 @@ Sapphire::Entity::Player::Player() : m_directorInitialized( false ), m_onEnterEventDone( false ), m_falling( false ), - m_pQueuedAction( nullptr ) + m_pQueuedAction( nullptr ), + m_cfNotifiedContent( 0 ) { m_id = 0; m_currentStance = Stance::Passive; @@ -245,13 +248,16 @@ uint64_t Sapphire::Entity::Player::getOnlineStatusMask() const return m_onlineStatus; } -void Sapphire::Entity::Player::prepareZoning( uint16_t targetZone, bool fadeOut, uint8_t fadeOutTime, uint16_t animation ) +void Sapphire::Entity::Player::prepareZoning( uint16_t targetZone, bool fadeOut, uint8_t fadeOutTime, uint16_t animation, uint8_t param4, uint8_t param7, uint8_t unknown ) { auto preparePacket = makeZonePacket< FFXIVIpcPrepareZoning >( getId() ); preparePacket->data().targetZone = targetZone; preparePacket->data().fadeOutTime = fadeOutTime; preparePacket->data().animation = animation; preparePacket->data().fadeOut = static_cast< uint8_t >( fadeOut ? 1 : 0 ); + preparePacket->data().param4 = param4; + preparePacket->data().param7 = param7; + preparePacket->data().unknown = unknown; queuePacket( preparePacket ); } @@ -532,8 +538,34 @@ bool Sapphire::Entity::Player::exitInstance() { auto& teriMgr = Common::Service< TerritoryMgr >::ref(); - auto pZone = getCurrentTerritory(); - auto pInstance = pZone->getAsInstanceContent(); + if( auto d = getCurrentTerritory()->getAsDirector() ) + if( d->getContentFinderConditionId() > 0 ) + { + auto p = makeZonePacket< FFXIVDirectorUnk4 >( getId() ); + p->data().param[0] = d->getDirectorId(); + p->data().param[1] = 1534; + p->data().param[2] = 1; + p->data().param[3] = d->getContentFinderConditionId(); + queuePacket( p ); + + struct UNK038D : FFXIVIpcBasePacket< 0x038D > + { + uint32_t unknown[2]; + }; + auto p3 = makeZonePacket< UNK038D >( getId() ); + queuePacket( p3 ); + + struct UNK00EA : FFXIVIpcBasePacket< 0x00EA > + { + uint32_t unknown[4]; + }; + auto p2 = makeZonePacket< UNK00EA >( getId() ); + p2->data().unknown[0] = d->getContentFinderConditionId(); + p2->data().unknown[1] = 5; + queuePacket( p2 ); + + prepareZoning( 0, 1, 1, 0, 0, 1, 9 ); + } resetHp(); resetMp(); @@ -1856,8 +1888,30 @@ void Sapphire::Entity::Player::sendZonePackets() initZonePacket->data().pos.x = getPos().x; initZonePacket->data().pos.y = getPos().y; initZonePacket->data().pos.z = getPos().z; + if( auto d = getCurrentTerritory()->getAsDirector() ) + { + initZonePacket->data().contentfinderConditionId = d->getContentFinderConditionId(); + initZonePacket->data().bitmask = 0xFF; + initZonePacket->data().bitmask1 = 0x2A; + } queuePacket( initZonePacket ); + if( auto d = getCurrentTerritory()->getAsDirector() ) + { + struct UNK00EA : FFXIVIpcBasePacket< 0x00EA > + { + uint32_t unknown[4]; + }; + auto p = makeZonePacket< UNK00EA >( getId() ); + p->data().unknown[0] = d->getContentFinderConditionId(); + p->data().unknown[2] = 1082270818; + queuePacket( p ); + auto p2 = makeZonePacket< UNK00EA >( getId() ); + p2->data().unknown[0] = d->getContentFinderConditionId(); + p2->data().unknown[1] = 4; + queuePacket( p2 ); + } + getCurrentTerritory()->onPlayerZoneIn( *this ); if( isLogin() ) diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index cc6966a2..3b600750 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -547,7 +547,7 @@ namespace Sapphire::Entity void dyeItemFromDyeingInfo(); /*! prepares zoning / fades out the screen */ - void prepareZoning( uint16_t targetZone, bool fadeOut, uint8_t fadeOutTime = 0, uint16_t animation = 0 ); + void prepareZoning( uint16_t targetZone, bool fadeOut, uint8_t fadeOutTime = 0, uint16_t animation = 0, uint8_t param4 = 0, uint8_t param7 = 9, uint8_t unknown = 0 ); /*! get player's title list (available titles) */ uint8_t* getTitleList(); @@ -1065,6 +1065,7 @@ namespace Sapphire::Entity uint64_t m_lastMoveTime; uint8_t m_lastMoveflag; bool m_falling; + uint16_t m_cfNotifiedContent; std::vector< ShopBuyBackEntry >& getBuyBackListForShop( uint32_t shopId ); void addBuyBackItemForShop( uint32_t shopId, const ShopBuyBackEntry& entry ); diff --git a/src/world/Event/Director.cpp b/src/world/Event/Director.cpp index aa20fa3a..48a313d4 100644 --- a/src/world/Event/Director.cpp +++ b/src/world/Event/Director.cpp @@ -16,9 +16,10 @@ using namespace Sapphire::Network::Packets; using namespace Sapphire::Network::Packets::Server; using namespace Sapphire::Network::ActorControl; -Sapphire::Event::Director::Director( Sapphire::Event::Director::DirectorType type, uint16_t contentId ) : +Sapphire::Event::Director::Director( Sapphire::Event::Director::DirectorType type, uint16_t contentId, uint16_t contentFinderConditionId ) : m_contentId( contentId ), m_type( type ), + m_contentFinderConditionId( contentFinderConditionId ), m_directorId( ( static_cast< uint32_t >( type ) << 16 ) | contentId ), m_sequence( 1 ), m_branch( 0 ), @@ -37,6 +38,11 @@ uint16_t Sapphire::Event::Director::getContentId() const return m_contentId; } +uint16_t Sapphire::Event::Director::getContentFinderConditionId() const +{ + return m_contentFinderConditionId; +} + uint8_t Sapphire::Event::Director::getSequence() const { return m_sequence; @@ -46,7 +52,7 @@ void Sapphire::Event::Director::sendDirectorClear( Sapphire::Entity::Player& pla { player.queuePacket( makeActorControlSelf( player.getId(), DirectorClear, m_directorId ) ); auto varPacket = makeZonePacket< FFXIVIpcDirectorVars >( player.getId() ); - varPacket->data().m_directorId = getDirectorId(); + varPacket->data().m_directorId = m_directorId; varPacket->data().m_sequence = 0; varPacket->data().m_branch = 0; player.queuePacket( varPacket ); @@ -57,17 +63,18 @@ void Sapphire::Event::Director::sendDirectorVars( Sapphire::Entity::Player& play auto varPacket = makeZonePacket< FFXIVIpcDirectorVars >( player.getId() ); varPacket->data().m_directorId = getDirectorId(); varPacket->data().m_sequence = getSequence(); - varPacket->data().m_branch = 0; + varPacket->data().m_branch = getBranch(); memcpy( varPacket->data().m_unionData, m_unionData.arrData, sizeof( varPacket->data().m_unionData ) ); player.queuePacket( varPacket ); - player.sendDebug( "DirectorVar#{}: {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}", getDirectorId(), + player.sendDebug( "DirectorVar#{}: {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X} seq{}, b{}", getDirectorId(), m_unionData.ui8.UI8A, m_unionData.ui8.UI8B, m_unionData.ui8.UI8C, m_unionData.ui8.UI8D, m_unionData.ui8.UI8E, - m_unionData.ui8.UI8F, m_unionData.ui8.UI8G, m_unionData.ui8.UI8H, m_unionData.ui8.UI8I, m_unionData.ui8.UI8J ); + m_unionData.ui8.UI8F, m_unionData.ui8.UI8G, m_unionData.ui8.UI8H, m_unionData.ui8.UI8I, m_unionData.ui8.UI8J, + getSequence(), getBranch() ); } void Sapphire::Event::Director::sendDirectorInit( Sapphire::Entity::Player& player ) const { - Logger::debug( "DirectorID#{}, ContentId#{}", m_directorId, m_contentId ); + Logger::debug( "DirectorID#{}, ContentId#{}, ContentFinderConditionId#{}", m_directorId, m_contentId, m_contentFinderConditionId ); player.queuePacket( makeActorControlSelf( player.getId(), DirectorInit, m_directorId, m_contentId ) ); } diff --git a/src/world/Event/Director.h b/src/world/Event/Director.h index 38970984..123865ad 100644 --- a/src/world/Event/Director.h +++ b/src/world/Event/Director.h @@ -42,12 +42,14 @@ namespace Sapphire::Event DutyFailed }; - Director( DirectorType type, uint16_t contentId ); + Director( DirectorType type, uint16_t contentId, uint16_t contentFinderConditionId = 0 ); uint32_t getDirectorId() const; uint16_t getContentId() const; + uint16_t getContentFinderConditionId() const; + DirectorType getType() const; uint8_t getSequence() const; @@ -114,6 +116,8 @@ namespace Sapphire::Event /*! DirectorType | ContentId */ uint32_t m_directorId; + uint16_t m_contentFinderConditionId; + /*! currect sequence */ uint8_t m_sequence; diff --git a/src/world/Manager/DebugCommandMgr.cpp b/src/world/Manager/DebugCommandMgr.cpp index 84539c06..fb8061e7 100644 --- a/src/world/Manager/DebugCommandMgr.cpp +++ b/src/world/Manager/DebugCommandMgr.cpp @@ -903,6 +903,11 @@ void Sapphire::World::Manager::DebugCommandMgr::script( char* data, Entity::Play { uint32_t id, param; sscanf( params.c_str(), "%u %u", &id, ¶m ); + if( id == 0 ) + { + if( auto d = player.getCurrentTerritory()->getAsDirector() ) + id = d->getDirectorId(); + } scriptMgr.onDebug( id, player, param ); } else diff --git a/src/world/Manager/TerritoryMgr.cpp b/src/world/Manager/TerritoryMgr.cpp index e006e301..d7b658db 100644 --- a/src/world/Manager/TerritoryMgr.cpp +++ b/src/world/Manager/TerritoryMgr.cpp @@ -324,7 +324,7 @@ Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::createQuestBattle Logger::debug( "Starting instance for QuestBattle id: {0} ({1})", questBattleId, pQuestInfo->name ); auto pZone = make_QuestBattle( pQuestBattleInfo, pContentFinderCondition->territoryType, getNextInstanceId(), - pTeri->name, pQuestInfo->name, questBattleId ); + pTeri->name, pQuestInfo->name, questBattleId, contentFinderConditionId ); pZone->init(); m_questBattleIdToInstanceMap[ questBattleId ][ pZone->getGuId() ] = pZone; @@ -358,7 +358,7 @@ Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::createInstanceCon Logger::debug( "Starting instance for InstanceContent id: {0} ({1})", instanceContentId, pContentFinderCondition->name ); auto pZone = make_InstanceContent( pInstanceContent, pContentFinderCondition->territoryType, getNextInstanceId(), - pTeri->name, pContentFinderCondition->name, instanceContentId ); + pTeri->name, pContentFinderCondition->name, instanceContentId, contentFinderConditionId ); pZone->init(); m_instanceContentIdToInstanceMap[ instanceContentId ][ pZone->getGuId() ] = pZone; @@ -389,7 +389,7 @@ Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::createPublicConte Logger::debug( "Starting instance for PublicContent id: {0} ({1})", contentId, pContentFinderCondition->name ); auto pZone = make_PublicContent( pPublicContent, pContentFinderCondition->territoryType, getNextInstanceId(), - pTeri->name, pContentFinderCondition->name, contentId ); + pTeri->name, pContentFinderCondition->name, contentId, contentFinderConditionId ); pZone->init(); m_publicContentIdToInstanceMap[ contentId ][ pZone->getGuId() ] = pZone; @@ -420,7 +420,7 @@ Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::createPublicConte Logger::debug( "Starting instance for PublicContent id: {0} ({1})", contentId, pPublicContent->name ); - auto pZone = make_PublicContent( pPublicContent, territoryId, getNextInstanceId(), pTeri->name, pPublicContent->name, contentId ); + auto pZone = make_PublicContent( pPublicContent, territoryId, getNextInstanceId(), pTeri->name, pPublicContent->name, contentId, 0 ); pZone->init(); m_publicContentIdToInstanceMap[ contentId ][ pZone->getGuId() ] = pZone; diff --git a/src/world/Script/ScriptMgr.cpp b/src/world/Script/ScriptMgr.cpp index 6313eb01..d7e9cb2e 100644 --- a/src/world/Script/ScriptMgr.cpp +++ b/src/world/Script/ScriptMgr.cpp @@ -153,6 +153,8 @@ void Sapphire::Scripting::ScriptMgr::onDebug( uint32_t id, Entity::Player& playe auto script = m_nativeScriptMgr->getScript( id ); if( script ) script->onDebug( player, param ); + else + player.sendUrgent( "{script {} not found.}", id ); } void Sapphire::Scripting::ScriptMgr::onPlayerFirstEnterWorld( Entity::Player& player ) diff --git a/src/world/Territory/InstanceContent.cpp b/src/world/Territory/InstanceContent.cpp index cd2a3455..8559014a 100644 --- a/src/world/Territory/InstanceContent.cpp +++ b/src/world/Territory/InstanceContent.cpp @@ -32,9 +32,9 @@ Sapphire::InstanceContent::InstanceContent( std::shared_ptr< Sapphire::Data::Ins uint32_t guId, const std::string& internalName, const std::string& contentName, - uint32_t instanceContentId ) : + uint32_t instanceContentId, uint16_t contentFinderConditionId ) : Territory( static_cast< uint16_t >( territoryType ), guId, internalName, contentName ), - Director( Event::Director::InstanceContent, instanceContentId ), + Director( Event::Director::InstanceContent, instanceContentId, contentFinderConditionId ), m_instanceConfiguration( pInstanceConfiguration ), m_instanceContentId( instanceContentId ), m_state( Created ), @@ -310,7 +310,7 @@ void Sapphire::InstanceContent::onRegisterEObj( Entity::EventObjectPtr object ) m_eventObjectMap[ object->getName() ] = object; if( object->getObjectId() == 2000182 ) // start m_pEntranceEObj = object; - if( object->getName() == "Entrance" ) + if( m_pEntranceEObj == nullptr && object->getName() == "Entrance" ) m_pEntranceEObj = object; auto& exdData = Common::Service< Data::ExdDataGenerated >::ref(); diff --git a/src/world/Territory/InstanceContent.h b/src/world/Territory/InstanceContent.h index 37af2446..cc8600a4 100644 --- a/src/world/Territory/InstanceContent.h +++ b/src/world/Territory/InstanceContent.h @@ -28,7 +28,7 @@ namespace Sapphire uint32_t guId, const std::string& internalName, const std::string& contentName, - uint32_t instanceContentId ); + uint32_t instanceContentId, uint16_t contentFinderConditionId = 0 ); virtual ~InstanceContent(); diff --git a/src/world/Territory/PublicContent.cpp b/src/world/Territory/PublicContent.cpp index e6c49b0e..55fc26e1 100644 --- a/src/world/Territory/PublicContent.cpp +++ b/src/world/Territory/PublicContent.cpp @@ -28,9 +28,9 @@ Sapphire::PublicContent::PublicContent( std::shared_ptr< Sapphire::Data::PublicC uint32_t guId, const std::string& internalName, const std::string& contentName, - uint32_t contentId ) : + uint32_t contentId, uint16_t contentFinderConditionId ) : Territory( static_cast< uint16_t >( territoryType ), guId, internalName, contentName ), - Director( Event::Director::PublicContent, contentId ), + Director( Event::Director::PublicContent, contentId, contentFinderConditionId ), m_Configuration( pConfiguration ), m_ContentId( contentId ) { @@ -131,7 +131,7 @@ void Sapphire::PublicContent::onRegisterEObj( Entity::EventObjectPtr object ) m_eventObjectMap[ object->getName() ] = object; if( object->getObjectId() == 2000182 ) // start m_pEntranceEObj = object; - if( object->getName() == "Entrance" ) + if( m_pEntranceEObj == nullptr && object->getName() == "Entrance" ) m_pEntranceEObj = object; auto& exdData = Common::Service< Data::ExdDataGenerated >::ref(); diff --git a/src/world/Territory/PublicContent.h b/src/world/Territory/PublicContent.h index 4af79a09..b9d62b07 100644 --- a/src/world/Territory/PublicContent.h +++ b/src/world/Territory/PublicContent.h @@ -20,7 +20,7 @@ namespace Sapphire uint32_t guId, const std::string& internalName, const std::string& contentName, - uint32_t contentId ); + uint32_t contentId, uint16_t contentFinderConditionId = 0 ); virtual ~PublicContent(); diff --git a/src/world/Territory/QuestBattle.cpp b/src/world/Territory/QuestBattle.cpp index 7db97014..675d00b3 100644 --- a/src/world/Territory/QuestBattle.cpp +++ b/src/world/Territory/QuestBattle.cpp @@ -34,9 +34,9 @@ Sapphire::QuestBattle::QuestBattle( std::shared_ptr< Sapphire::Data::QuestBattle uint32_t guId, const std::string& internalName, const std::string& contentName, - uint32_t questBattleId ) : + uint32_t questBattleId, uint16_t contentFinderConditionId ) : Territory( static_cast< uint16_t >( territoryType ), guId, internalName, contentName ), - Director( Event::Director::QuestBattle, questBattleId ), + Director( Event::Director::QuestBattle, questBattleId, contentFinderConditionId ), m_pBattleDetails( pBattleDetails ), m_questBattleId( questBattleId ), m_state( Created ), diff --git a/src/world/Territory/QuestBattle.h b/src/world/Territory/QuestBattle.h index 899a6c6a..4009b62a 100644 --- a/src/world/Territory/QuestBattle.h +++ b/src/world/Territory/QuestBattle.h @@ -20,7 +20,7 @@ namespace Sapphire uint32_t guId, const std::string& internalName, const std::string& contentName, - uint32_t questBattleId ); + uint32_t questBattleId, uint16_t contentFinderConditionId = 0 ); virtual ~QuestBattle() = default; diff --git a/src/world/Territory/Territory.cpp b/src/world/Territory/Territory.cpp index d39d9124..8a5e74a6 100644 --- a/src/world/Territory/Territory.cpp +++ b/src/world/Territory/Territory.cpp @@ -781,6 +781,11 @@ Sapphire::Entity::EventObjectPtr Sapphire::Territory::getEObj( uint32_t objId ) return obj->second; } +Sapphire::Event::DirectorPtr Sapphire::Territory::getAsDirector() +{ + return std::dynamic_pointer_cast< Event::Director, Territory >( shared_from_this() ); +} + Sapphire::InstanceContentPtr Sapphire::Territory::getAsInstanceContent() { return std::dynamic_pointer_cast< InstanceContent, Territory >( shared_from_this() ); diff --git a/src/world/Territory/Territory.h b/src/world/Territory/Territory.h index 34cbf576..16ea2195 100644 --- a/src/world/Territory/Territory.h +++ b/src/world/Territory/Territory.h @@ -166,6 +166,8 @@ namespace Sapphire Entity::EventObjectPtr getEObj( uint32_t objId ); + Event::DirectorPtr getAsDirector(); + InstanceContentPtr getAsInstanceContent(); QuestBattlePtr getAsQuestBattle();