diff --git a/src/common/Common.h b/src/common/Common.h index 749ef112..8f9c258b 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -1248,9 +1248,6 @@ namespace Sapphire::Common GetGil = 9, // p1: gil EmptyCoffer = 11, // seems like no param }; - - using PlayerStateFlagList = std::vector< PlayerStateFlag >; - } #endif diff --git a/src/common/Network/CommonActorControl.h b/src/common/Network/CommonActorControl.h index 6ead8897..27657d42 100644 --- a/src/common/Network/CommonActorControl.h +++ b/src/common/Network/CommonActorControl.h @@ -111,6 +111,8 @@ namespace Sapphire::Network::ActorControl ScreenFadeOut = 0xAA, + CeremonyDecoration = 0xB9, + ZoneIn = 0xC8, ZoneInDefaultPos = 0xC9, @@ -364,6 +366,7 @@ namespace Sapphire::Network::ActorControl TitleList = 0x12F, UpdatedSeenHowTos = 0x133, + CutscenePlayed = 0x134, // param1 = cutscene id AllotAttribute = 0x135, ClearFieldMarkers = 0x13A, diff --git a/src/common/Network/PacketDef/Ipcs.h b/src/common/Network/PacketDef/Ipcs.h index c33cfad6..7bce247e 100644 --- a/src/common/Network/PacketDef/Ipcs.h +++ b/src/common/Network/PacketDef/Ipcs.h @@ -194,14 +194,7 @@ namespace Sapphire::Network::Packets EventPlay128 = 0x026E, // updated 5.58 EventPlay255 = 0x039E, // updated 5.58 - EventYield = 0x0123, // updated 5.58 - //EventYield4 = 0x0000, - //EventYield8 = 0x0000, - //EventYield16 = 0x0000, - //EventYield32 = 0x0000, - //EventYield64 = 0x0000, - //EventYield128 = 0x0000, - //EventYield255 = 0x0000, + EventContinue = 0x0123, // updated 5.58 EventStart = 0x01CC, // updated 5.58 EventFinish = 0x0180, // updated 5.58 @@ -274,6 +267,8 @@ namespace Sapphire::Network::Packets LandSetMap = 0x02F6, // updated 5.58 + CeremonySetActorAppearance = 0x00EB, // updated 5.58 + ////////////////////////////////////////////////// DuelChallenge = 0x0277, // 4.2; this is responsible for opening the ui @@ -390,7 +385,7 @@ namespace Sapphire::Network::Packets BuildPresetHandler = 0x00DC, // updated 5.58 TalkEventHandler = 0x012D, // updated 5.58 - EmoteEventHandler = 0xF35A, // updated 5.55 hotfix + EmoteEventHandler = 0x039E, // updated 5.58 WithinRangeEventHandler = 0x022C, // updated 5.58 OutOfRangeEventHandler = 0x0294, // updated 5.58 EnterTeriEventHandler = 0x00C1, // updated 5.58 @@ -398,7 +393,8 @@ namespace Sapphire::Network::Packets EventYieldHandler = 0x03A2, // updated 5.58 ReturnEventHandler = 0x0333, // updated 5.58 TradeReturnEventHandler = 0x0179, // updated 5.58 - TradeReturnEventHandler2 = 0x0169, // updated 5.55 hotfix + TradeReturnEventHandler2 = 0x02E1, // updated 5.58 + EventYield16Handler = 0x03D7, // updated 5.58 LinkshellEventHandler = 0x016B, // updated 4.5 LinkshellEventHandler1 = 0x016C, // updated 4.5 diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index 0d67ea61..903abf90 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -446,6 +446,24 @@ struct FFXIVIpcHousingEditInterior : uint16_t slot[10]; }; +struct FFXIVIpcEventYieldHandler : + FFXIVIpcBasePacket< EventYieldHandler > +{ + uint32_t eventId; + uint16_t scene; + uint16_t padding; + uint64_t unknown; +}; + +struct FFXIVIpcEventYield16Handler : + FFXIVIpcBasePacket< EventYield16Handler > +{ + uint32_t eventId; + uint16_t scene; + uint16_t padding; + uint32_t params[16]; +}; + struct FFXIVIpcCFCommenceHandler : FFXIVIpcBasePacket< CFCommenceHandler > { diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index bd1049e2..c0899b1e 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1439,6 +1439,20 @@ namespace Sapphire::Network::Packets::Server uint8_t unknown[8]; }; + struct FFXIVIpcEventPlay16 : FFXIVIpcBasePacket< EventPlay16 > + { + uint64_t actorId; + uint32_t eventId; + uint16_t scene; + uint16_t padding; + uint32_t flags; + uint32_t param3; + uint8_t paramSize; + uint8_t padding1[3]; + uint32_t param[16]; + uint32_t padding2; + }; + template< int ArgCount > struct FFXIVIpcEventPlayN { @@ -1835,7 +1849,7 @@ namespace Sapphire::Network::Packets::Server uint32_t bNPCName; uint32_t textId; uint32_t popupTimeMs; - uint32_t pad3[4]; + uint32_t param[6]; }; @@ -2238,6 +2252,43 @@ namespace Sapphire::Network::Packets::Server char memberName[32]; uint8_t padding[3]; }; + + struct FFXIVIpcEventContinue : FFXIVIpcBasePacket< EventContinue > + { + uint32_t eventId; + uint16_t scene; + uint16_t unknown; + uint64_t unknown2; + }; + + struct FFXIVDirectorUnk4 : FFXIVIpcBasePacket< SomeDirectorUnk4 > + { + uint32_t param[4]; + uint64_t unknown; + }; + + struct FFXIVCeremonySetActorAppearance : FFXIVIpcBasePacket< CeremonySetActorAppearance > + { + uint8_t u1; + uint8_t questBL; + uint16_t padding1; + uint32_t u3; + struct + { + uint64_t mainWeaponModel; + uint64_t secWeaponModel; + uint64_t craftToolModel; + uint32_t c_u6; + uint32_t c_u7; + uint32_t charId; + uint16_t u4; + uint16_t guardianDeity; + uint32_t u5; + uint32_t models[10]; + uint8_t look[26]; + uint16_t padding3; + } actors[2]; + }; } #endif /*_CORE_NETWORK_PACKETS_SERVER_IPC_H*/ diff --git a/src/common/Util/UtilMath.cpp b/src/common/Util/UtilMath.cpp index ae61e171..d81a2f62 100644 --- a/src/common/Util/UtilMath.cpp +++ b/src/common/Util/UtilMath.cpp @@ -76,4 +76,9 @@ uint16_t Util::floatToUInt16Rot( float val ) uint8_t Util::floatToUInt8Rot( float val ) { return static_cast< uint8_t >( 0x80 * ( ( val + PI ) ) / PI ); +} + +float Util::floatFromUInt16Rot( uint16_t rot ) +{ + return rot / 32768.0f * PI - PI; } \ No newline at end of file diff --git a/src/common/Util/UtilMath.h b/src/common/Util/UtilMath.h index c35ef6be..1168d71b 100644 --- a/src/common/Util/UtilMath.h +++ b/src/common/Util/UtilMath.h @@ -25,6 +25,8 @@ namespace Sapphire::Common::Util uint16_t floatToUInt16Rot( float val ); + float floatFromUInt16Rot( uint16_t rot ); + uint8_t floatToUInt8Rot( float val ); template < typename T > diff --git a/src/scripts/common/CmnDefCutSceneReplay.cpp b/src/scripts/common/CmnDefCutSceneReplay.cpp index 2ccfab69..11c9b80b 100644 --- a/src/scripts/common/CmnDefCutSceneReplay.cpp +++ b/src/scripts/common/CmnDefCutSceneReplay.cpp @@ -32,7 +32,7 @@ public: // todo: this is fucked }; - player.playScene( getId(), 1, 0xFB2EC8F8, 0, 1, returnScene, callback ); + player.playScene( getId(), 1, FADE_OUT | CONDITION_CUTSCENE | HIDE_UI, 0, 1, returnScene, callback ); } void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override diff --git a/src/scripts/common/eobj/HousingEstateEntrance.cpp b/src/scripts/common/eobj/HousingEstateEntrance.cpp index 2abc371b..bb280288 100644 --- a/src/scripts/common/eobj/HousingEstateEntrance.cpp +++ b/src/scripts/common/eobj/HousingEstateEntrance.cpp @@ -78,7 +78,7 @@ public: return; } - player.setInstance( internalZone, pos ); + player.setInstance( internalZone, pos, player.getRot() ); } ); } }; diff --git a/src/world/Actor/Actor.cpp b/src/world/Actor/Actor.cpp index efaf0e51..43ba0900 100644 --- a/src/world/Actor/Actor.cpp +++ b/src/world/Actor/Actor.cpp @@ -351,7 +351,7 @@ Sapphire::InstanceContentPtr Sapphire::Entity::Actor::getCurrentInstance() const return nullptr; } -/*! \return QuestBattlePtr to the current instance, nullptr if not an instance or not set */ +/*! \return QuestBattlePtr to the current instance, nullptr if not a quest battle or not set */ Sapphire::QuestBattlePtr Sapphire::Entity::Actor::getCurrentQuestBattle() const { if( m_pCurrentTerritory ) @@ -360,6 +360,15 @@ Sapphire::QuestBattlePtr Sapphire::Entity::Actor::getCurrentQuestBattle() const return nullptr; } +/*! \return PublicContentPtr to the current instance, nullptr if not a public content or not set */ +Sapphire::PublicContentPtr Sapphire::Entity::Actor::getCurrentPublicContent() const +{ + if( m_pCurrentTerritory ) + return m_pCurrentTerritory->getAsPublicContent(); + + return nullptr; +} + /*! Get the current cell of a region the actor is in diff --git a/src/world/Actor/Actor.h b/src/world/Actor/Actor.h index 80bd066e..cf8f7479 100644 --- a/src/world/Actor/Actor.h +++ b/src/world/Actor/Actor.h @@ -130,6 +130,8 @@ namespace Sapphire::Entity QuestBattlePtr getCurrentQuestBattle() const; + PublicContentPtr getCurrentPublicContent() const; + // get the current cell of a region the actor is in Cell* getCellPtr(); diff --git a/src/world/Actor/EventObject.h b/src/world/Actor/EventObject.h index f2ae6d05..c497bf1f 100644 --- a/src/world/Actor/EventObject.h +++ b/src/world/Actor/EventObject.h @@ -13,7 +13,7 @@ namespace Sapphire::Entity Common::FFXIVARR_POSITION3 pos, float rotation, const std::string& givenName = "none" ); using OnTalkEventHandler = std::function< void( Entity::Player&, Entity::EventObjectPtr, - TerritoryPtr, uint64_t ) >; + TerritoryPtr, uint32_t, uint64_t ) >; uint32_t getGimmickId() const; diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index 7f089e92..a71184a5 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -23,6 +23,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" @@ -472,7 +474,7 @@ bool Sapphire::Entity::Player::setInstance( TerritoryPtr instance ) return teriMgr.movePlayer( instance, getAsPlayer() ); } -bool Sapphire::Entity::Player::setInstance( TerritoryPtr instance, Common::FFXIVARR_POSITION3 pos ) +bool Sapphire::Entity::Player::setInstance( TerritoryPtr instance, Common::FFXIVARR_POSITION3 pos, float rot ) { m_onEnterEventDone = false; if( !instance ) @@ -490,11 +492,17 @@ bool Sapphire::Entity::Player::setInstance( TerritoryPtr instance, Common::FFXIV m_prevTerritoryId = getTerritoryId(); } + m_pos = pos; + m_rot = rot; if( teriMgr.movePlayer( instance, getAsPlayer() ) ) { - m_pos = pos; return true; } + else + { + m_pos = m_prevPos; + m_rot= m_prevRot; + } return false; } @@ -503,8 +511,18 @@ bool Sapphire::Entity::Player::exitInstance() { auto& teriMgr = Common::Service< TerritoryMgr >::ref(); - auto pZone = getCurrentTerritory(); - auto pInstance = pZone->getAsInstanceContent(); + auto d = getCurrentTerritory()->getAsDirector(); + if( d && 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 ); + + prepareZoning( 0, 1, 1, 0, 0, 1, 9 ); + } resetHp(); resetMp(); @@ -1755,14 +1773,14 @@ void Sapphire::Entity::Player::sendZonePackets() //setStateFlag( PlayerStateFlag::BetweenAreas ); //setStateFlag( PlayerStateFlag::BetweenAreas1 ); - if( isActionLearned( static_cast< uint8_t >( Common::UnlockEntry::HuntingLog ) ) ) - sendHuntingLog(); - sendStats(); // only initialize the UI if the player in fact just logged in. if( isLogin() ) { + if( isActionLearned( static_cast< uint8_t >( Common::UnlockEntry::HuntingLog ) ) ) + sendHuntingLog(); + auto contentFinderList = makeZonePacket< FFXIVIpcCFAvailableContents >( getId() ); for( auto i = 0; i < sizeof( contentFinderList->data().contents ); i++ ) @@ -1812,6 +1830,12 @@ 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 ); getCurrentTerritory()->onPlayerZoneIn( *this ); diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index 0b95ab24..63f41eb6 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -111,6 +111,8 @@ namespace Sapphire::Entity void playSceneChain( uint32_t eventId, uint32_t scene, uint32_t flags, Event::EventHandler::SceneChainCallback sceneChainCallback ); + void playScene16( uint32_t eventId, uint32_t scene, uint32_t flags, uint32_t param3, std::vector< uint32_t > paramList, Event::EventHandler::SceneReturnCallback eventReturnCallback ); + /*! setup the event and return a ptr to it */ Event::EventHandlerPtr bootstrapSceneEvent( uint32_t eventId, uint32_t flags ); @@ -490,7 +492,7 @@ namespace Sapphire::Entity bool setInstance( TerritoryPtr instance ); /*! sets the players instance & initiates zoning process */ - bool setInstance( Sapphire::TerritoryPtr instance, Sapphire::Common::FFXIVARR_POSITION3 pos ); + bool setInstance( Sapphire::TerritoryPtr instance, Sapphire::Common::FFXIVARR_POSITION3 pos, float rot ); /*! returns the player to their position before zoning into an instance */ bool exitInstance(); @@ -992,6 +994,8 @@ namespace Sapphire::Entity ////////////////////////////////////////////////////////////////////////////////////////////////////// + void setPosAndNotifyClient( float x, float y, float z, float rot ); + Common::HuntingLogEntry& getHuntingLogEntry( uint8_t index ); void sendHuntingLog(); diff --git a/src/world/Actor/PlayerEvent.cpp b/src/world/Actor/PlayerEvent.cpp index 12f8c626..eb9659e0 100644 --- a/src/world/Actor/PlayerEvent.cpp +++ b/src/world/Actor/PlayerEvent.cpp @@ -323,6 +323,33 @@ void Sapphire::Entity::Player::eventFinish( uint32_t eventId, uint32_t freePlaye unsetStateFlag( PlayerStateFlag::InNpcEvent ); } +void Sapphire::Entity::Player::playScene16( uint32_t eventId, uint32_t scene, uint32_t flags, uint32_t param3, std::vector< uint32_t > paramList, Event::EventHandler::SceneReturnCallback eventReturnCallback ) +{ + auto pEvent = bootstrapSceneEvent( eventId, flags ); + if( !pEvent ) + return; + + pEvent->setPlayedScene( true ); + pEvent->setEventReturnCallback( eventReturnCallback ); + pEvent->setSceneChainCallback( nullptr ); + auto eventPlay16 = makeZonePacket< FFXIVIpcEventPlay16 >( getId() ); + eventPlay16->data().actorId = pEvent->getActorId(); + eventPlay16->data().eventId = pEvent->getId(); + eventPlay16->data().scene = scene; + eventPlay16->data().flags = flags; + eventPlay16->data().param3 = param3; + eventPlay16->data().paramSize = paramList.size(); + int i = 0; + for( auto p : paramList ) + { + assert( i < 16 ); + eventPlay16->data().param[ i ] = paramList.at( i ); + i++; + } + + queuePacket( eventPlay16 ); +} + void Sapphire::Entity::Player::eventActionStart( uint32_t eventId, uint32_t action, World::Action::ActionCallback finishCallback, diff --git a/src/world/Event/Director.cpp b/src/world/Event/Director.cpp index 864bf0e3..5bde5992 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; @@ -52,14 +58,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} 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, + getSequence(), getBranch() ); } void Sapphire::Event::Director::sendDirectorInit( Sapphire::Entity::Player& player ) const { - Logger::debug( "DirectorID#{}, QuestBattleID#{}", 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 ) ); } @@ -183,12 +193,12 @@ void Sapphire::Event::Director::setDirectorSequence( uint8_t value ) m_sequence = value; } -void Sapphire::Event::Director::setCustomVar( uint32_t varId, uint32_t value ) +void Sapphire::Event::Director::setCustomVar( uint32_t varId, uint64_t value ) { m_customVarMap[ varId ] = value; } -uint32_t Sapphire::Event::Director::getCustomVar( uint32_t varId ) +uint64_t Sapphire::Event::Director::getCustomVar( uint32_t varId ) { auto it = m_customVarMap.find( varId ); if( it != m_customVarMap.end() ) diff --git a/src/world/Event/Director.h b/src/world/Event/Director.h index 38970984..3bc9efaa 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; @@ -104,8 +106,8 @@ namespace Sapphire::Event void setDirectorBranch( uint8_t value ); - void setCustomVar( uint32_t varId, uint32_t value ); - uint32_t getCustomVar( uint32_t varId ); + void setCustomVar( uint32_t varId, uint64_t value ); + uint64_t getCustomVar( uint32_t varId ); private: /*! Id of the content of the director */ @@ -114,6 +116,8 @@ namespace Sapphire::Event /*! DirectorType | ContentId */ uint32_t m_directorId; + uint16_t m_contentFinderConditionId; + /*! currect sequence */ uint8_t m_sequence; @@ -183,7 +187,7 @@ namespace Sapphire::Event uint32_t m_elapsedTime; - std::unordered_map< uint32_t, uint32_t > m_customVarMap; + std::unordered_map< uint32_t, uint64_t > m_customVarMap; }; diff --git a/src/world/Event/EventHandler.h b/src/world/Event/EventHandler.h index 9bec90a4..4afc4480 100644 --- a/src/world/Event/EventHandler.h +++ b/src/world/Event/EventHandler.h @@ -79,6 +79,7 @@ namespace Sapphire::Event Adventure = 0x0021, DailyQuestSupply = 0x0022, ICDirector = 0x8003, + PublicContentDirector = 0x8004, QuestBattleDirector = 0x8006, }; diff --git a/src/world/ForwardsZone.h b/src/world/ForwardsZone.h index 13b6b489..4592c320 100644 --- a/src/world/ForwardsZone.h +++ b/src/world/ForwardsZone.h @@ -24,6 +24,7 @@ TYPE_FORWARD( HousingZone ); TYPE_FORWARD( House ); TYPE_FORWARD( InstanceContent ); TYPE_FORWARD( QuestBattle ); +TYPE_FORWARD( PublicContent ); TYPE_FORWARD( Item ); TYPE_FORWARD( ItemContainer ); TYPE_FORWARD( ZonePosition ); diff --git a/src/world/Manager/DebugCommandMgr.cpp b/src/world/Manager/DebugCommandMgr.cpp index 85aeeed9..5daafd7f 100644 --- a/src/world/Manager/DebugCommandMgr.cpp +++ b/src/world/Manager/DebugCommandMgr.cpp @@ -32,6 +32,7 @@ #include "Territory/HousingZone.h" #include "Territory/InstanceContent.h" #include "Territory/QuestBattle.h" +#include "Territory/PublicContent.h" #include "Manager/TerritoryMgr.h" #include "Event/EventDefs.h" @@ -60,6 +61,8 @@ Sapphire::World::Manager::DebugCommandMgr::DebugCommandMgr() registerCommand( "script", &DebugCommandMgr::script, "Server script utilities.", 1 ); registerCommand( "instance", &DebugCommandMgr::instance, "Instance utilities", 1 ); registerCommand( "questbattle", &DebugCommandMgr::questBattle, "Quest battle utilities", 1 ); + registerCommand( "pc", &DebugCommandMgr::pc, "Public content utilities", 1 ); + registerCommand( "publiccontent", &DebugCommandMgr::pc, "Public content utilities", 1 ); registerCommand( "qb", &DebugCommandMgr::questBattle, "Quest battle utilities", 1 ); registerCommand( "housing", &DebugCommandMgr::housing, "Housing utilities", 1 ); } @@ -583,9 +586,23 @@ void Sapphire::World::Manager::DebugCommandMgr::get( char* data, Entity::Player& int16_t map_id = exdData.get< Sapphire::Data::TerritoryType >( player.getCurrentTerritory()->getTerritoryTypeId() )->map; - player.sendNotice( "Pos:\n {0}\n {1}\n {2}\n {3}\n MapId: {4}\n ZoneId:{5}", + player.sendNotice( "Pos: x: {0}, y: {1}, z: {2}, r: {3}\n MapId: {4}, ZoneId:{5}, Weather:{6}, Festival:{7}, {8}", player.getPos().x, player.getPos().y, player.getPos().z, - player.getRot(), map_id, player.getCurrentTerritory()->getTerritoryTypeId() ); + player.getRot(), map_id, player.getCurrentTerritory()->getTerritoryTypeId(), + static_cast< uint8_t >( player.getCurrentTerritory()->getCurrentWeather() ), player.getCurrentTerritory()->getCurrentFestival().first, + player.getCurrentTerritory()->getCurrentFestival().second ); + if( auto instance = player.getCurrentInstance() ) + { + player.sendNotice( "Instance info:\nContentId: {}, DirectorId: {}\nSequence: {}, Branch: {}, BGM: {}", + instance->getInstanceContentId(), instance->getDirectorId(), instance->getSequence(), + instance->getBranch(), instance->getCurrentBGM() ); + } + else if( auto instance = player.getCurrentPublicContent() ) + { + player.sendNotice( "Public content info:\nContentId: {}, DirectorId: {}\nSequence: {}, Branch: {}", + instance->getContentId(), instance->getDirectorId(), instance->getSequence(), + instance->getBranch() ); + } } else { @@ -1282,3 +1299,137 @@ void Sapphire::World::Manager::DebugCommandMgr::housing( char* data, Entity::Pla player.sendDebug( "Unknown sub command." ); } } + +void Sapphire::World::Manager::DebugCommandMgr::pc( char* data, Entity::Player& player, std::shared_ptr< DebugCommand > command ) +{ + auto& terriMgr = Common::Service< TerritoryMgr >::ref(); + std::string cmd( data ), params, subCommand; + auto cmdPos = cmd.find_first_of( ' ' ); + + if( cmdPos != std::string::npos ) + { + params = cmd.substr( cmdPos + 1 ); + + auto p = params.find_first_of( ' ' ); + + if( p != std::string::npos ) + { + subCommand = params.substr( 0, p ); + params = params.substr( subCommand.length() + 1 ); + } + else + subCommand = params; + } + + if( subCommand == "create" || subCommand == "cr" ) + { + uint32_t contentFinderConditionId; + sscanf( params.c_str(), "%d", &contentFinderConditionId ); + + auto instance = terriMgr.createPublicContent( contentFinderConditionId ); + if( instance ) + player.sendDebug( "Created instance with id#{0} -> {1}", instance->getGuId(), instance->getName() ); + else + player.sendDebug( "Failed to create instance with id#{0}", contentFinderConditionId ); + } + else if ( subCommand == "create2" || subCommand == "cr2" ) + { + uint16_t contentId, terriId; + sscanf( params.c_str(), "%hu %hu", &contentId, &terriId ); + + auto instance = terriMgr.createPublicContent( contentId, terriId ); + if( instance ) + player.sendDebug( "Created instance with id#{0} -> {1}", instance->getGuId(), instance->getName() ); + else + player.sendDebug( "Failed to create instance with id#{0}, territory#{1}. Server console output may contain additional info.", contentId, terriId ); + } + else if( subCommand == "remove" || subCommand == "rm" ) + { + uint32_t terriId; + sscanf( params.c_str(), "%d", &terriId ); + + if( terriMgr.removeTerritoryInstance( terriId ) ) + player.sendDebug( "Removed instance with id#{0}", terriId ); + else + player.sendDebug( "Failed to remove instance with id#{0}", terriId ); + } + else if( subCommand == "return" || subCommand == "ret" ) + { + player.exitInstance(); + } + else if( subCommand == "set" ) + { + uint32_t index; + uint32_t value; + sscanf( params.c_str(), "%d %d", &index, &value ); + + + auto instance = std::dynamic_pointer_cast< PublicContent >( player.getCurrentTerritory() ); + if( !instance ) + return; + + instance->setVar( static_cast< uint8_t >( index ), static_cast< uint8_t >( value ) ); + } + else if( subCommand == "seq" ) + { + uint8_t seq; + + sscanf( params.c_str(), "%hhu", &seq ); + + auto instance = std::dynamic_pointer_cast< PublicContent >( player.getCurrentTerritory() ); + if( !instance ) + return; + + instance->setSequence( seq ); + } + else if( subCommand == "branch" ) + { + uint8_t branch; + + sscanf( params.c_str(), "%hhu", &branch ); + + auto instance = std::dynamic_pointer_cast< PublicContent >( player.getCurrentTerritory() ); + if( !instance ) + return; + + instance->setBranch( branch ); + } + else if( subCommand == "objstate" ) + { + char objName[128]; + uint8_t state; + + sscanf( params.c_str(), "%s %hhu", objName, &state ); + + auto instance = std::dynamic_pointer_cast< PublicContent >( player.getCurrentTerritory() ); + if( !instance ) + return; + + auto obj = instance->getEObjByName( objName ); + if( !obj ) + return; + + obj->setState( state ); + } + else if( subCommand == "objflag" ) + { + char objName[256]; + uint32_t state1; + uint32_t state2; + + sscanf( params.c_str(), "%s %i %i", objName, &state1, &state2 ); + + auto instance = std::dynamic_pointer_cast< PublicContent >( player.getCurrentTerritory() ); + if( !instance ) + return; + + auto obj = instance->getEObjByName( objName ); + if( !obj ) + { + player.sendDebug( "No eobj found." ); + return; + } + + obj->setAnimationFlag( state1, state2 ); + } +} diff --git a/src/world/Manager/DebugCommandMgr.h b/src/world/Manager/DebugCommandMgr.h index 25921312..2607f6ab 100644 --- a/src/world/Manager/DebugCommandMgr.h +++ b/src/world/Manager/DebugCommandMgr.h @@ -53,6 +53,7 @@ namespace Sapphire::World::Manager void instance( char* data, Entity::Player& player, std::shared_ptr< DebugCommand > command ); void questBattle( char* data, Entity::Player& player, std::shared_ptr< DebugCommand > command ); + void pc( char* data, Entity::Player& player, std::shared_ptr< DebugCommand > command ); void housing( char* data, Entity::Player& player, std::shared_ptr< DebugCommand > command) ; diff --git a/src/world/Manager/EventMgr.cpp b/src/world/Manager/EventMgr.cpp index 00505a41..bc417c11 100644 --- a/src/world/Manager/EventMgr.cpp +++ b/src/world/Manager/EventMgr.cpp @@ -74,6 +74,13 @@ std::string Sapphire::World::Manager::EventMgr::getEventName( uint32_t eventId ) name[ 0 ] = toupper( name[ 0 ] ); return name; } + case Event::EventHandler::EventHandlerType::PublicContentDirector: + { + auto pcInfo = exdData.get< Sapphire::Data::PublicContent >( eventId & 0x0000FFFF ); + if( !pcInfo ) + return "unknown"; + return pcInfo->name; + } case Event::EventHandler::EventHandlerType::Warp: diff --git a/src/world/Manager/TerritoryMgr.cpp b/src/world/Manager/TerritoryMgr.cpp index 50711549..825af480 100644 --- a/src/world/Manager/TerritoryMgr.cpp +++ b/src/world/Manager/TerritoryMgr.cpp @@ -13,6 +13,7 @@ #include "Territory/ZonePosition.h" #include "Territory/InstanceContent.h" #include "Territory/QuestBattle.h" +#include "Territory/PublicContent.h" #include "TerritoryMgr.h" #include "HousingMgr.h" @@ -316,7 +317,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; @@ -350,7 +351,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; @@ -360,6 +361,68 @@ Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::createInstanceCon return pZone; } +Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::createPublicContent( uint32_t contentFinderConditionId ) +{ + auto& exdData = Common::Service< Data::ExdDataGenerated >::ref(); + + auto pContentFinderCondition = exdData.get< Sapphire::Data::ContentFinderCondition >( contentFinderConditionId ); + if( !pContentFinderCondition ) + return nullptr; + auto contentId = pContentFinderCondition->content; + + auto pPublicContent = exdData.get< Sapphire::Data::PublicContent >( contentId ); + if( !pPublicContent ) + return nullptr; + + auto pTeri = getTerritoryDetail( pContentFinderCondition->territoryType ); + + if( !pTeri || pContentFinderCondition->name.empty() ) + return nullptr; + + 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, contentFinderConditionId ); + pZone->init(); + + m_publicContentIdToInstanceMap[ contentId ][ pZone->getGuId() ] = pZone; + m_guIdToTerritoryPtrMap[ pZone->getGuId() ] = pZone; + m_instanceZoneSet.insert( pZone ); + + return pZone; +} + +Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::createPublicContent( uint16_t contentId, uint16_t territoryId ) +{ + auto& exdData = Common::Service< Data::ExdDataGenerated >::ref(); + + auto pPublicContent = exdData.get< Sapphire::Data::PublicContent >( contentId ); + if( !pPublicContent ) + return nullptr; + + if( pPublicContent->contentFinderCondition > 0 ) + { + Logger::warn( "the public content {} has a ContentFinderCondition value of {}, create the instance using it instead.", contentId, pPublicContent->contentFinderCondition ); + return nullptr; + } + + auto pTeri = getTerritoryDetail( territoryId ); + + if( !pTeri ) + return nullptr; + + Logger::debug( "Starting instance for PublicContent id: {0} ({1})", contentId, pPublicContent->name ); + + auto pZone = make_PublicContent( pPublicContent, territoryId, getNextInstanceId(), pTeri->name, pPublicContent->name, contentId, 0 ); + pZone->init(); + + m_publicContentIdToInstanceMap[ contentId ][ pZone->getGuId() ] = pZone; + m_guIdToTerritoryPtrMap[ pZone->getGuId() ] = pZone; + m_instanceZoneSet.insert( pZone ); + + return pZone; +} + Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::findOrCreateHousingInterior( const Common::LandIdent landIdent ) { // check if zone already spawned first @@ -444,11 +507,21 @@ bool Sapphire::World::Manager::TerritoryMgr::removeTerritoryInstance( uint32_t g m_instanceZoneSet.erase( pZone ); m_territorySet.erase( pZone ); - if( isInstanceContentTerritory( pZone->getTerritoryTypeId() ) ) + if( pZone->getAsInstanceContent() ) { auto instance = std::dynamic_pointer_cast< InstanceContent >( pZone ); m_instanceContentIdToInstanceMap[ instance->getInstanceContentId() ].erase( pZone->getGuId() ); } + else if( pZone->getAsPublicContent() ) + { + auto instance = std::dynamic_pointer_cast< PublicContent >( pZone ); + m_publicContentIdToInstanceMap[ instance->getContentId() ].erase( pZone->getGuId() ); + } + else if( pZone->getAsQuestBattle() ) + { + auto instance = std::dynamic_pointer_cast< QuestBattle >( pZone ); + m_questBattleIdToInstanceMap[ instance->getQuestBattleId() ].erase( pZone->getGuId() ); + } else m_territoryTypeIdToInstanceGuidMap[ pZone->getTerritoryTypeId() ].erase( pZone->getGuId() ); @@ -616,7 +689,7 @@ bool Sapphire::World::Manager::TerritoryMgr::movePlayer( TerritoryPtr pZone, Sap if( pHousing ) pPlayer->setTerritoryId( pHousing->getLandSetId() ); } - else if( isInstanceContentTerritory( pZone->getTerritoryTypeId() ) ) + else if( pZone->getAsInstanceContent() || pZone->getAsQuestBattle() || pZone->getAsPublicContent() ) { pPlayer->setTerritoryId( pZone->getGuId() ); } diff --git a/src/world/Manager/TerritoryMgr.h b/src/world/Manager/TerritoryMgr.h index 9401a6a9..ff9dd285 100644 --- a/src/world/Manager/TerritoryMgr.h +++ b/src/world/Manager/TerritoryMgr.h @@ -118,6 +118,9 @@ namespace Sapphire::World::Manager TerritoryPtr createQuestBattle( uint32_t contentFinderConditionId ); + TerritoryPtr createPublicContent( uint32_t contentFinderConditionId ); + TerritoryPtr createPublicContent( uint16_t contentId, uint16_t territoryId ); + void createAndJoinQuestBattle( Entity::Player& player, uint16_t contentFinderConditionId ); TerritoryPtr findOrCreateHousingInterior( const Common::LandIdent landIdent ); @@ -179,6 +182,7 @@ namespace Sapphire::World::Manager using InstanceContentIdToInstanceMap = std::unordered_map< uint16_t, InstanceIdToTerritoryPtrMap >; using QuestBattleIdToInstanceMap = std::unordered_map< uint16_t, InstanceIdToTerritoryPtrMap >; using QuestBattleIdToContentFinderCondMap = std::unordered_map< uint16_t, uint16_t >; + using PublicContentIdToInstanceMap = std::unordered_map< uint16_t, InstanceIdToTerritoryPtrMap >; using PlayerIdToInstanceIdMap = std::unordered_map< uint32_t, uint32_t >; using PositionMap = std::unordered_map< int32_t, ZonePositionPtr >; using InstanceIdList = std::vector< uint32_t >; @@ -196,9 +200,12 @@ namespace Sapphire::World::Manager /*! map holding actual instances of InstanceContent */ InstanceContentIdToInstanceMap m_instanceContentIdToInstanceMap; - /*! map holding actual instances of InstanceContent */ + /*! map holding actual instances of QuestBattle */ QuestBattleIdToInstanceMap m_questBattleIdToInstanceMap; + /*! map holding actual instances of PublicContent */ + PublicContentIdToInstanceMap m_publicContentIdToInstanceMap; + /*! flat map for easier lookup of instances by guid */ InstanceIdToTerritoryPtrMap m_guIdToTerritoryPtrMap; diff --git a/src/world/Network/GameConnection.cpp b/src/world/Network/GameConnection.cpp index 17907571..7309004d 100644 --- a/src/world/Network/GameConnection.cpp +++ b/src/world/Network/GameConnection.cpp @@ -106,6 +106,8 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH setZoneHandler( ClientZoneIpcType::TradeReturnEventHandler, "TradeReturnEventHandler", &GameConnection::eventHandlerReturn ); setZoneHandler( ClientZoneIpcType::TradeReturnEventHandler2, "TradeReturnEventHandler2", &GameConnection::eventHandlerReturn ); + setZoneHandler( ClientZoneIpcType::EventYieldHandler, "EventYieldHandler", &GameConnection::eventYieldHandler ); + setZoneHandler( ClientZoneIpcType::EventYield16Handler, "EventYield16Handler", &GameConnection::eventYieldHandler ); setZoneHandler( ClientZoneIpcType::ShopEventHandler, "ShopEventHandler", &GameConnection::eventHandlerShop ); diff --git a/src/world/Network/GameConnection.h b/src/world/Network/GameConnection.h index 0e1da4cb..92e1d661 100644 --- a/src/world/Network/GameConnection.h +++ b/src/world/Network/GameConnection.h @@ -194,6 +194,8 @@ namespace Sapphire::Network DECLARE_HANDLER( worldInteractionhandler ); DECLARE_HANDLER( diveHandler ); + + DECLARE_HANDLER( eventYieldHandler ); }; } diff --git a/src/world/Network/Handlers/CFHandlers.cpp b/src/world/Network/Handlers/CFHandlers.cpp index 08e53124..9778d37c 100644 --- a/src/world/Network/Handlers/CFHandlers.cpp +++ b/src/world/Network/Handlers/CFHandlers.cpp @@ -103,7 +103,6 @@ void Sapphire::Network::GameConnection::cfDutyAccepted( const Packets::FFXIVARR_ player.prepareZoning( pInstance->getTerritoryTypeId(), true, 1, 0, 0, 1, 9 ); - auto sourceZoneGuId = player.getCurrentTerritory()->getGuId(); player.setInstance( instance ); } } diff --git a/src/world/Network/Handlers/ClientTriggerHandler.cpp b/src/world/Network/Handlers/ClientTriggerHandler.cpp index 3cd9517d..c2bedc37 100644 --- a/src/world/Network/Handlers/ClientTriggerHandler.cpp +++ b/src/world/Network/Handlers/ClientTriggerHandler.cpp @@ -494,6 +494,11 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX player.sendDebug( "event battle p1: {0}, p11: {1}, p12: {2}, p2: {3}, p3: {4}, p4: {5}, p5: {6}", param1, param11, param12, param2, param3, param4, param5 ); break; } + case ClientTriggerType::CutscenePlayed: + { + player.sendDebug( "cutscene: {}", param1 ); + break; + } case ClientTriggerType::OpenPerformInstrumentUI: { //param11 = instrument, 0 = end diff --git a/src/world/Network/Handlers/EventHandlers.cpp b/src/world/Network/Handlers/EventHandlers.cpp index 929bc90b..d869c62a 100644 --- a/src/world/Network/Handlers/EventHandlers.cpp +++ b/src/world/Network/Handlers/EventHandlers.cpp @@ -23,6 +23,7 @@ #include "Territory/InstanceContent.h" #include "Territory/QuestBattle.h" +#include "Territory/PublicContent.h" #include "Session.h" @@ -59,6 +60,14 @@ void Sapphire::Network::GameConnection::eventHandlerTalk( const Packets::FFXIVAR { instance->onTalk( player, eventId, actorId ); } + else if( auto instance = player.getCurrentQuestBattle() ) + { + instance->onTalk( player, eventId, actorId ); + } + else if( auto instance = player.getCurrentPublicContent() ) + { + instance->onTalk( player, eventId, actorId ); + } else if( !scriptMgr.onTalk( player, actorId, eventId ) && eventType == Event::EventHandler::EventHandlerType::Quest ) { @@ -180,6 +189,11 @@ void Sapphire::Network::GameConnection::eventHandlerEnterTerritory( const Packet player.eventStart( player.getId(), eventId, Event::EventHandler::EnterTerritory, 1, player.getZoneId() ); instance->onEnterTerritory( player, eventId, param1, param2 ); } + else if( auto instance = player.getCurrentPublicContent() ) + { + player.eventStart( player.getId(), eventId, Event::EventHandler::EnterTerritory, 1, player.getZoneId() ); + instance->onEnterTerritory( player, eventId, param1, param2 ); + } else { player.eventStart( player.getId(), eventId, Event::EventHandler::EnterTerritory, 0, player.getZoneId() ); @@ -273,5 +287,39 @@ void Sapphire::Network::GameConnection::eventHandlerShop( const Packets::FFXIVAR scriptMgr.onTalk( player, player.getId(), eventId ); } +void Sapphire::Network::GameConnection::eventYieldHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player ) +{ + auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref(); + auto& eventMgr = Common::Service< World::Manager::EventMgr >::ref(); + auto opcode = *reinterpret_cast< const uint16_t* >( &inPacket.data[ 2 ] ); + auto eventId = *reinterpret_cast< const uint32_t* >( &inPacket.data[ 0x10 + 0 ] ); + auto scene = *reinterpret_cast< const uint16_t* >( &inPacket.data[ 0x10 + 4 ] ); + auto pParam = reinterpret_cast< const uint32_t* >( &inPacket.data[ 0x10 + 8 ] ); + + std::vector< uint32_t > param; + + switch( opcode ) + { + case EventYield16Handler: + { + for( int i = 0; i < 16; i++ ) + { + param.push_back( pParam[ i ] ); + } + break; + } + } + + std::string eventName = "onEventYield"; + std::string objName = eventMgr.getEventName( eventId ); + player.sendDebug( "Calling: {0}.{1} - {2} scene: {3}", objName, eventName, eventId, scene ); + + scriptMgr.onEventYield( player, eventId, scene, param ); + + auto response = makeZonePacket< FFXIVIpcEventContinue >( player.getId() ); + response->data().eventId = eventId; + response->data().scene = scene; + player.queuePacket( response ); +} diff --git a/src/world/Network/Handlers/PacketHandlers.cpp b/src/world/Network/Handlers/PacketHandlers.cpp index 86387a2a..1daf63f7 100644 --- a/src/world/Network/Handlers/PacketHandlers.cpp +++ b/src/world/Network/Handlers/PacketHandlers.cpp @@ -387,15 +387,18 @@ void Sapphire::Network::GameConnection::pingHandler( const Packets::FFXIVARR_PAC void Sapphire::Network::GameConnection::finishLoadingHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player ) { - player.sendQuestInfo(); + if( player.isLogin() ) + { + 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 ); + // 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.getCurrentTerritory()->onFinishLoading( player ); diff --git a/src/world/Network/PacketWrappers/ActorControlSelfPacket.h b/src/world/Network/PacketWrappers/ActorControlSelfPacket.h index bfd343a5..0ce5b4fc 100644 --- a/src/world/Network/PacketWrappers/ActorControlSelfPacket.h +++ b/src/world/Network/PacketWrappers/ActorControlSelfPacket.h @@ -22,15 +22,15 @@ namespace Sapphire::Network::Packets::Server uint32_t param3 = 0, uint32_t param4 = 0, uint32_t param5 = 0, - uint32_t padding1 = 0 ) : + uint32_t param6 = 0 ) : ZoneChannelPacket< FFXIVIpcActorControlSelf >( actorId, actorId ) { - initialize( category, param1, param2, param3, param4, param5 ); + initialize( category, param1, param2, param3, param4, param5, param6 ); }; private: void initialize( uint16_t category, uint32_t param1, uint32_t param2, uint32_t param3, uint32_t param4, - uint32_t param5 ) + uint32_t param5, uint32_t param6 ) { m_data.padding = 0; m_data.category = category; @@ -39,6 +39,7 @@ namespace Sapphire::Network::Packets::Server m_data.param3 = param3; m_data.param4 = param4; m_data.param5 = param5; + m_data.param6 = param6; }; }; diff --git a/src/world/Network/PacketWrappers/PlayerSpawnPacket.h b/src/world/Network/PacketWrappers/PlayerSpawnPacket.h index 7ddbe23d..9e8df9e0 100644 --- a/src/world/Network/PacketWrappers/PlayerSpawnPacket.h +++ b/src/world/Network/PacketWrappers/PlayerSpawnPacket.h @@ -8,6 +8,8 @@ #include "Forwards.h" #include "Inventory/Item.h" #include "StatusEffect/StatusEffect.h" +#include "Territory/Territory.h" +#include "Event/Director.h" namespace Sapphire::Network::Packets::Server { @@ -143,6 +145,10 @@ namespace Sapphire::Network::Packets::Server m_data.effect[ effect.first ].param = effect.second->getParam(); } + if( auto d = player.getCurrentTerritory()->getAsDirector() ) + { + m_data.directorId = d->getDirectorId(); + } }; }; diff --git a/src/world/Script/NativeScriptApi.cpp b/src/world/Script/NativeScriptApi.cpp index b8945223..5238af65 100644 --- a/src/world/Script/NativeScriptApi.cpp +++ b/src/world/Script/NativeScriptApi.cpp @@ -134,6 +134,10 @@ namespace Sapphire::ScriptAPI { } + void EventScript::onEventYield( Sapphire::Entity::Player& player, uint16_t scene, std::vector< uint32_t > param ) + { + } + /////////////////////////////////////////////////////////////////// EventObjectScript::EventObjectScript( uint32_t eobjId ) : @@ -216,5 +220,31 @@ namespace Sapphire::ScriptAPI { } + PublicContentScript::PublicContentScript( uint32_t contentId ) : + ScriptObject( uint32_t{ 0x8004 } << 16 | contentId, typeid( PublicContentScript ).hash_code() ) + { + } + + void PublicContentScript::onInit( PublicContent& instance ) + { + } + + void PublicContentScript::onUpdate( PublicContent& instance, uint64_t tickCount ) + { + } + + void PublicContentScript::onPlayerZoneIn( PublicContent& instance, Entity::Player& player ) + { + } + + void PublicContentScript::onLeaveTerritory( PublicContent& instance, Entity::Player& player ) + { + } + + void PublicContentScript::onEnterTerritory( PublicContent& instance, Entity::Player& player, uint32_t eventId, + uint16_t param1, uint16_t param2 ) + { + } + } diff --git a/src/world/Script/NativeScriptApi.h b/src/world/Script/NativeScriptApi.h index aad02c5a..f1ea4ba7 100644 --- a/src/world/Script/NativeScriptApi.h +++ b/src/world/Script/NativeScriptApi.h @@ -166,6 +166,8 @@ namespace Sapphire::ScriptAPI uint32_t catalogId ); virtual void onEObjHit( Sapphire::Entity::Player& player, uint64_t actorId, uint32_t actionId ); + + virtual void onEventYield( Sapphire::Entity::Player& player, uint16_t scene, std::vector< uint32_t > param ); }; /*! @@ -237,6 +239,23 @@ namespace Sapphire::ScriptAPI uint16_t param1, uint16_t param2 ); }; + class PublicContentScript : public ScriptObject + { + public: + explicit PublicContentScript( uint32_t contentId ); + + virtual void onInit( Sapphire::PublicContent& instance ); + + virtual void onUpdate( Sapphire::PublicContent& instance, uint64_t tickCount ); + + virtual void onPlayerZoneIn( Sapphire::PublicContent& instance, Sapphire::Entity::Player& player ); + + virtual void onLeaveTerritory( Sapphire::PublicContent& instance, Sapphire::Entity::Player& player ); + + virtual void onEnterTerritory( Sapphire::PublicContent& instance, Sapphire::Entity::Player& player, uint32_t eventId, + uint16_t param1, uint16_t param2 ); + }; + } #endif diff --git a/src/world/Script/ScriptMgr.cpp b/src/world/Script/ScriptMgr.cpp index e9f9a2a5..718c72be 100644 --- a/src/world/Script/ScriptMgr.cpp +++ b/src/world/Script/ScriptMgr.cpp @@ -7,6 +7,7 @@ #include "Territory/Territory.h" #include "Territory/InstanceContent.h" #include "Territory/QuestBattle.h" +#include "Territory/PublicContent.h" #include "Actor/Player.h" #include "Actor/EventObject.h" #include "ServerMgr.h" @@ -530,8 +531,7 @@ Sapphire::Scripting::NativeScriptMgr& Sapphire::Scripting::ScriptMgr::getNativeS return *m_nativeScriptMgr; } -bool -Sapphire::Scripting::ScriptMgr::onDutyComplete( Sapphire::QuestBattlePtr instance, Sapphire::Entity::Player& player ) +bool Sapphire::Scripting::ScriptMgr::onDutyComplete( Sapphire::QuestBattlePtr instance, Sapphire::Entity::Player& player ) { auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::QuestBattleScript >( instance->getDirectorId() ); if( script ) @@ -542,3 +542,77 @@ Sapphire::Scripting::ScriptMgr::onDutyComplete( Sapphire::QuestBattlePtr instanc return false; } + +bool Sapphire::Scripting::ScriptMgr::onEventYield( Sapphire::Entity::Player& player, uint32_t eventId, uint16_t scene, std::vector< uint32_t > param ) +{ + auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::EventScript >( eventId ); + if( script ) + { + script->onEventYield( player, scene, param ); + return true; + } + + return false; +} + +bool Sapphire::Scripting::ScriptMgr::onPublicContentInit( PublicContentPtr instance ) +{ + auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::PublicContentScript >( instance->getDirectorId() ); + if( script ) + { + script->onInit( *instance ); + return true; + } + + return false; +} + +bool Sapphire::Scripting::ScriptMgr::onPublicContentUpdate( PublicContentPtr instance, uint64_t tickCount ) +{ + auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::PublicContentScript >( instance->getDirectorId() ); + + if( script ) + { + script->onUpdate( *instance, tickCount ); + return true; + } + + return false; +} + +bool Sapphire::Scripting::ScriptMgr::onPublicContentPlayerZoneIn( PublicContentPtr instance, Entity::Player& player ) +{ + auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::PublicContentScript >( instance->getDirectorId() ); + if( script ) + { + script->onPlayerZoneIn( *instance, player ); + return true; + } + + return false; +} + +bool Sapphire::Scripting::ScriptMgr::onPublicContentLeaveTerritory( PublicContentPtr instance, Entity::Player& player ) +{ + auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::PublicContentScript >( instance->getDirectorId() ); + if( script ) + { + script->onLeaveTerritory( *instance, player ); + return true; + } + + return false; +} + +bool Sapphire::Scripting::ScriptMgr::onPublicContentEnterTerritory( PublicContentPtr instance, Entity::Player& player, + uint32_t eventId, uint16_t param1, uint16_t param2 ) +{ + auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::PublicContentScript >( instance->getDirectorId() ); + if( script ) + { + script->onEnterTerritory( *instance, player, eventId, param1, param2 ); + return true; + } + + return false; +} \ No newline at end of file diff --git a/src/world/Script/ScriptMgr.h b/src/world/Script/ScriptMgr.h index ea9b5d80..b0a5cb5f 100644 --- a/src/world/Script/ScriptMgr.h +++ b/src/world/Script/ScriptMgr.h @@ -112,6 +112,18 @@ namespace Sapphire::Scripting bool onDutyComplete( QuestBattlePtr instance, Entity::Player& player ); + bool onEventYield( Entity::Player& player, uint32_t eventId, uint16_t scene, std::vector< uint32_t > param ); + + bool onPublicContentInit( PublicContentPtr instance ); + + bool onPublicContentUpdate( PublicContentPtr instance, uint64_t tickCount ); + + bool onPublicContentPlayerZoneIn( PublicContentPtr instance, Entity::Player& player ); + + bool onPublicContentLeaveTerritory( PublicContentPtr instance, Entity::Player& player ); + + bool onPublicContentEnterTerritory( PublicContentPtr instance, Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ); + bool loadDir( const std::string& dirname, std::set< std::string >& files, const std::string& ext ); NativeScriptMgr& getNativeScriptHandler(); diff --git a/src/world/Territory/InstanceContent.cpp b/src/world/Territory/InstanceContent.cpp index 2bdd3bf8..ad9e08fb 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,6 +310,8 @@ void Sapphire::InstanceContent::onRegisterEObj( Entity::EventObjectPtr object ) m_eventObjectMap[ object->getName() ] = object; if( object->getObjectId() == 2000182 ) // start m_pEntranceEObj = object; + if( m_pEntranceEObj == nullptr && object->getName() == "Entrance" ) + m_pEntranceEObj = object; auto& exdData = Common::Service< Data::ExdDataGenerated >::ref(); auto objData = exdData.get< Sapphire::Data::EObj >( object->getObjectId() ); @@ -375,7 +377,7 @@ void Sapphire::InstanceContent::onTalk( Sapphire::Entity::Player& player, uint32 return; if( auto onTalk = it->second->getOnTalkHandler() ) - onTalk( player, it->second, getAsInstanceContent(), actorId ); + onTalk( player, it->second, getAsInstanceContent(), eventId, actorId ); else player.sendDebug( "No onTalk handler found for interactable eobj with EObjID#{0}, eventId#{1} ", it->second->getObjectId(), eventId ); 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 new file mode 100644 index 00000000..a74f15dd --- /dev/null +++ b/src/world/Territory/PublicContent.cpp @@ -0,0 +1,271 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "Actor/Player.h" +#include "Actor/EventObject.h" +#include "Event/Director.h" +#include "Event/EventDefs.h" +#include "Event/EventHandler.h" +#include "Script/ScriptMgr.h" + +#include "Network/PacketWrappers/ActorControlPacket.h" +#include "Network/PacketWrappers/ActorControlSelfPacket.h" + +#include "PublicContent.h" + +using namespace Sapphire::Common; +using namespace Sapphire::Network::Packets; +using namespace Sapphire::Network::Packets::Server; +using namespace Sapphire::Network::ActorControl; + +Sapphire::PublicContent::PublicContent( std::shared_ptr< Sapphire::Data::PublicContent > pConfiguration, + uint16_t territoryType, + uint32_t guId, + const std::string& internalName, + const std::string& contentName, + uint32_t contentId, uint16_t contentFinderConditionId ) : + Territory( static_cast< uint16_t >( territoryType ), guId, internalName, contentName ), + Director( Event::Director::PublicContent, contentId, contentFinderConditionId ), + m_Configuration( pConfiguration ), + m_ContentId( contentId ) +{ + +} + +bool Sapphire::PublicContent::init() +{ + if( !Territory::init() ) + return false; + + auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref(); + scriptMgr.onPublicContentInit( getAsPublicContent() ); + + return true; +} + + +Sapphire::PublicContent::~PublicContent() +{ + +} + +uint32_t Sapphire::PublicContent::getContentId() const +{ + return m_ContentId; +} + +Sapphire::Data::ExdDataGenerated::PublicContentPtr Sapphire::PublicContent::getConfiguration() const +{ + return m_Configuration; +} + +void Sapphire::PublicContent::onPlayerZoneIn( Entity::Player& player ) +{ + Logger::debug( "PublicContent::onPlayerZoneIn: Territory#{0}|{1}, Entity#{2}", getGuId(), getTerritoryTypeId(), player.getId() ); + sendDirectorInit( player ); + + auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref(); + scriptMgr.onPublicContentPlayerZoneIn( getAsPublicContent(), player ); +} + +void Sapphire::PublicContent::onLeaveTerritory( Entity::Player& player ) +{ + Logger::debug( "PublicContent::onLeaveTerritory: Territory#{0}|{1}, Entity#{2}", getGuId(), getTerritoryTypeId(), player.getId() ); + clearDirector( player ); + + auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref(); + scriptMgr.onPublicContentLeaveTerritory( getAsPublicContent(), player ); +} + +void Sapphire::PublicContent::onUpdate( uint64_t tickCount ) +{ + updateBNpcs( tickCount ); + auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref(); + scriptMgr.onPublicContentUpdate( getAsPublicContent(), tickCount ); +} + +void Sapphire::PublicContent::onFinishLoading( Entity::Player& player ) +{ + sendDirectorInit( player ); +} + +void Sapphire::PublicContent::onInitDirector( Entity::Player& player ) +{ + sendDirectorVars( player ); + player.setDirectorInitialized( true ); +} + +void Sapphire::PublicContent::onDirectorSync( Entity::Player& player ) +{ + player.queuePacket( makeActorControlSelf( player.getId(), DirectorUpdate, 0x00110001, 0x80000000, 1 ) ); +} + +void Sapphire::PublicContent::onBeforePlayerZoneIn( Sapphire::Entity::Player& player ) +{ + /*if( m_pEntranceEObj != nullptr ) + { + player.setRot( PI ); + player.setPos( m_pEntranceEObj->getPos() ); + } + else + { + player.setRot( PI ); + player.setPos( { 0.f, 0.f, 0.f } ); + }*/ + player.resetObjSpawnIndex(); +} + +void Sapphire::PublicContent::onEnterTerritory( Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ) +{ + auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref(); + scriptMgr.onPublicContentEnterTerritory( getAsPublicContent(), player, eventId, param1, param2 ); +} + +void Sapphire::PublicContent::onRegisterEObj( Entity::EventObjectPtr object ) +{ + if( object->getName() != "none" ) + m_eventObjectMap[ object->getName() ] = object; + if( object->getObjectId() == 2000182 ) // start + m_pEntranceEObj = object; + if( m_pEntranceEObj == nullptr && object->getName() == "Entrance" ) + m_pEntranceEObj = object; + + auto& exdData = Common::Service< Data::ExdDataGenerated >::ref(); + auto objData = exdData.get< Sapphire::Data::EObj >( object->getObjectId() ); + if( objData ) + m_eventIdToObjectMap[ objData->data ] = object; + else + Logger::error( "PublicContent::onRegisterEObj Territory " + + m_internalName + ": No EObj data found for EObj with ID: " + + std::to_string( object->getObjectId() ) ); +} + +Sapphire::Entity::EventObjectPtr Sapphire::PublicContent::getEObjByName( const std::string& name ) +{ + auto it = m_eventObjectMap.find( name ); + if( it == m_eventObjectMap.end() ) + return nullptr; + + return it->second; +} + +void Sapphire::PublicContent::clearDirector( Entity::Player& player ) +{ + sendDirectorClear( player ); + player.setDirectorInitialized( false ); +} + +void Sapphire::PublicContent::onTalk( Sapphire::Entity::Player& player, uint32_t eventId, uint64_t actorId ) +{ + auto it = m_eventIdToObjectMap.find( eventId ); + if( it == m_eventIdToObjectMap.end() ) + return; + + if( auto onTalk = it->second->getOnTalkHandler() ) + onTalk( player, it->second, getAsPublicContent(), eventId, actorId ); + else + player.sendDebug( "No onTalk handler found for interactable eobj with EObjID#{0}, eventId#{1} ", + it->second->getObjectId(), eventId ); +} + +void Sapphire::PublicContent::setVar( uint8_t index, uint8_t value ) +{ + if( index > 19 ) + return; + + switch( index ) + { + case 0: + setDirectorUI8AL( value ); + break; + case 1: + setDirectorUI8AH( value ); + break; + case 2: + setDirectorUI8BL( value ); + break; + case 3: + setDirectorUI8BH( value ); + break; + case 4: + setDirectorUI8CL( value ); + break; + case 5: + setDirectorUI8CH( value ); + break; + case 6: + setDirectorUI8DL( value ); + break; + case 7: + setDirectorUI8DH( value ); + break; + case 8: + setDirectorUI8EL( value ); + break; + case 9: + setDirectorUI8EH( value ); + break; + case 10: + setDirectorUI8FL( value ); + break; + case 11: + setDirectorUI8FH( value ); + break; + case 12: + setDirectorUI8GL( value ); + break; + case 13: + setDirectorUI8GH( value ); + break; + case 14: + setDirectorUI8HL( value ); + break; + case 15: + setDirectorUI8HH( value ); + break; + case 16: + setDirectorUI8IL( value ); + break; + case 17: + setDirectorUI8IH( value ); + break; + case 18: + setDirectorUI8JL( value ); + break; + case 19: + setDirectorUI8JH( value ); + break; + + } + + // todo: genericise this? + for( const auto& playerIt : m_playerMap ) + { + sendDirectorVars( *playerIt.second ); + } +} + +void Sapphire::PublicContent::setSequence( uint8_t value ) +{ + setDirectorSequence( value ); + + for( const auto& playerIt : m_playerMap ) + { + sendDirectorVars( *playerIt.second ); + } +} + +void Sapphire::PublicContent::setBranch( uint8_t value ) +{ + setDirectorBranch( value ); + + for( const auto& playerIt : m_playerMap ) + { + sendDirectorVars( *playerIt.second ); + } +} \ No newline at end of file diff --git a/src/world/Territory/PublicContent.h b/src/world/Territory/PublicContent.h new file mode 100644 index 00000000..e765cf3a --- /dev/null +++ b/src/world/Territory/PublicContent.h @@ -0,0 +1,72 @@ +#ifndef SAPPHIRE_PUBLICCONTENT_H +#define SAPPHIRE_PUBLICCONTENT_H + +#include "Territory.h" +#include "Event/Director.h" +#include "Forwards.h" + +namespace Sapphire::Data +{ + struct PublicContent; +} + +namespace Sapphire +{ + class PublicContent : public Event::Director, public Territory + { + public: + PublicContent( std::shared_ptr< Sapphire::Data::PublicContent > pConfiguration, + uint16_t territoryType, + uint32_t guId, + const std::string& internalName, + const std::string& contentName, + uint32_t contentId, uint16_t contentFinderConditionId = 0 ); + + virtual ~PublicContent(); + + bool init() override; + + void onBeforePlayerZoneIn( Entity::Player& player ) override; + + void onPlayerZoneIn( Entity::Player& player ) override; + + void onLeaveTerritory( Entity::Player& player ) override; + + void onUpdate( uint64_t tickCount ) override; + + void onFinishLoading( Entity::Player& player ) override; + + void onInitDirector( Entity::Player& player ) override; + + void onDirectorSync( Entity::Player& player ) override; + + void onEnterTerritory( Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override; + + void onRegisterEObj( Entity::EventObjectPtr object ) override; + + std::shared_ptr< Sapphire::Data::PublicContent > getConfiguration() const; + + uint32_t getContentId() const; + + Entity::EventObjectPtr getEObjByName( const std::string& name ); + + void clearDirector( Entity::Player& player ); + + void onTalk( Entity::Player& player, uint32_t eventId, uint64_t actorId ); + + void setSequence( uint8_t value ); + + void setBranch( uint8_t value ); + + void setVar( uint8_t index, uint8_t value ); + + private: + std::shared_ptr< Sapphire::Data::PublicContent > m_Configuration; + uint32_t m_ContentId; + Entity::EventObjectPtr m_pEntranceEObj; + std::map< std::string, Entity::EventObjectPtr > m_eventObjectMap; + std::unordered_map< uint32_t, Entity::EventObjectPtr > m_eventIdToObjectMap; + }; + +} +#endif //SAPPHIRE_PUBLICCONTENT_H diff --git a/src/world/Territory/QuestBattle.cpp b/src/world/Territory/QuestBattle.cpp index 7db97014..5db5aeec 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 ), @@ -330,7 +330,7 @@ void Sapphire::QuestBattle::onTalk( Sapphire::Entity::Player& player, uint32_t e return; if( auto onTalkHandler = it->second->getOnTalkHandler() ) - onTalkHandler( player, it->second, getAsQuestBattle(), actorId ); + onTalkHandler( player, it->second, getAsQuestBattle(), eventId, actorId ); else player.sendDebug( "No onTalk handler found for interactable eobj with EObjID#{0}, eventId#{1} ", it->second->getObjectId(), eventId ); 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 a2e71d4d..fe14175b 100644 --- a/src/world/Territory/Territory.cpp +++ b/src/world/Territory/Territory.cpp @@ -19,6 +19,7 @@ #include "Territory.h" #include "InstanceContent.h" #include "QuestBattle.h" +#include "PublicContent.h" #include "Manager/TerritoryMgr.h" #include "Navi/NaviProvider.h" @@ -780,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() ); @@ -790,6 +796,11 @@ Sapphire::QuestBattlePtr Sapphire::Territory::getAsQuestBattle() return std::dynamic_pointer_cast< QuestBattle, Territory >( shared_from_this() ); } +Sapphire::PublicContentPtr Sapphire::Territory::getAsPublicContent() +{ + return std::dynamic_pointer_cast< PublicContent, Territory >( shared_from_this() ); +} + uint32_t Sapphire::Territory::getNextEObjId() { return ++m_nextEObjId; @@ -1043,4 +1054,19 @@ void Sapphire::Territory::processEffectResults( uint64_t tickCount ) it = m_effectResults.erase( it ); } +} + +Sapphire::Entity::PlayerPtr Sapphire::Territory::getPlayer( uint32_t charId ) +{ + return m_playerMap[ charId ]; +} + +void Sapphire::Territory::foreachPlayer( std::function< void( Sapphire::Entity::PlayerPtr player ) > callback ) +{ + if( !callback ) + return; + for( auto entry : m_playerMap ) + { + callback( entry.second ); + } } \ No newline at end of file diff --git a/src/world/Territory/Territory.h b/src/world/Territory/Territory.h index 47aa51ae..23b1f505 100644 --- a/src/world/Territory/Territory.h +++ b/src/world/Territory/Territory.h @@ -166,10 +166,14 @@ namespace Sapphire Entity::EventObjectPtr getEObj( uint32_t objId ); + Event::DirectorPtr getAsDirector(); + InstanceContentPtr getAsInstanceContent(); QuestBattlePtr getAsQuestBattle(); + PublicContentPtr getAsPublicContent(); + void updateSpawnPoints(); uint32_t getNextEffectSequence(); @@ -179,6 +183,10 @@ namespace Sapphire void addEffectResult( World::Action::EffectResultPtr result ); void processEffectResults( uint64_t tickCount ); + + Entity::PlayerPtr getPlayer( uint32_t charId ); + + void foreachPlayer( std::function< void( Entity::PlayerPtr player ) > callback ); }; }