From 40ecbb8765b2e7b7dd8ca253c1c33bc886d7c272 Mon Sep 17 00:00:00 2001 From: collett Date: Mon, 9 Aug 2021 02:38:20 +0900 Subject: [PATCH] public content support and wedding prep work --- .../RegFstEternalCeremonyGuideRoom.cpp | 29 ++ .../instances/wedding/SanctumOfTheTwelve.cpp | 51 ++++ src/world/Actor/Actor.cpp | 11 +- src/world/Actor/Actor.h | 2 + src/world/Event/Director.cpp | 2 +- src/world/Event/EventHandler.h | 1 + src/world/ForwardsZone.h | 1 + src/world/Manager/DebugCommandMgr.cpp | 111 ++++++++ src/world/Manager/DebugCommandMgr.h | 1 + src/world/Manager/EventMgr.cpp | 7 + src/world/Manager/TerritoryMgr.cpp | 93 ++++++- src/world/Manager/TerritoryMgr.h | 9 +- src/world/Network/Handlers/EventHandlers.cpp | 16 +- src/world/Script/NativeScriptApi.cpp | 30 ++ src/world/Script/NativeScriptApi.h | 19 ++ src/world/Script/NativeScriptMgr.cpp | 12 + src/world/Script/NativeScriptMgr.h | 2 + src/world/Script/ScriptMgr.cpp | 70 +++++ src/world/Script/ScriptMgr.h | 12 + src/world/Territory/InstanceContent.cpp | 2 + src/world/Territory/PublicContent.cpp | 261 ++++++++++++++++++ src/world/Territory/PublicContent.h | 70 +++++ src/world/Territory/Territory.cpp | 6 + src/world/Territory/Territory.h | 2 + 24 files changed, 809 insertions(+), 11 deletions(-) create mode 100644 src/scripts/instances/wedding/RegFstEternalCeremonyGuideRoom.cpp create mode 100644 src/scripts/instances/wedding/SanctumOfTheTwelve.cpp create mode 100644 src/world/Territory/PublicContent.cpp create mode 100644 src/world/Territory/PublicContent.h diff --git a/src/scripts/instances/wedding/RegFstEternalCeremonyGuideRoom.cpp b/src/scripts/instances/wedding/RegFstEternalCeremonyGuideRoom.cpp new file mode 100644 index 00000000..e0537417 --- /dev/null +++ b/src/scripts/instances/wedding/RegFstEternalCeremonyGuideRoom.cpp @@ -0,0 +1,29 @@ +#include +#include + +using namespace Sapphire; + +class RegFstEternalCeremonyGuideRoom : public Sapphire::ScriptAPI::EventScript +{ +public: + RegFstEternalCeremonyGuideRoom() : Sapphire::ScriptAPI::EventScript( 720912 ) + { + } + + void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override + { + Scene00000( player ); + } + + void Scene00000( Entity::Player& player ) + { + player.playSceneChain( getId(), 0, HIDE_HOTBAR, bindScene( &RegFstEternalCeremonyGuideRoom::Scene00001 ) ); + } + + void Scene00001( Entity::Player& player ) + { + player.playScene( getId(), 1, HIDE_HOTBAR ); + } +}; + +EXPOSE_SCRIPT( RegFstEternalCeremonyGuideRoom ); \ No newline at end of file diff --git a/src/scripts/instances/wedding/SanctumOfTheTwelve.cpp b/src/scripts/instances/wedding/SanctumOfTheTwelve.cpp new file mode 100644 index 00000000..123bd75f --- /dev/null +++ b/src/scripts/instances/wedding/SanctumOfTheTwelve.cpp @@ -0,0 +1,51 @@ +#include +#include + +#include "Actor/Player.h" +#include "Territory/PublicContent.h" + +using namespace Sapphire; + +class SanctumOfTheTwelve : public Sapphire::ScriptAPI::PublicContentScript +{ +public: + SanctumOfTheTwelve() : Sapphire::ScriptAPI::PublicContentScript( 1 ) { } + + void onInit( PublicContent& instance ) override + { + + } + + void onUpdate( PublicContent& instance, uint64_t tickCount ) override + { + + } + + void onPlayerZoneIn( PublicContent& instance, Entity::Player& player ) override + { + player.setPosAndSendActorMove( 0, 250, -50, player.getRot() ); + } + + void onLeaveTerritory( PublicContent& instance, Entity::Player& player ) override + { + } + + void onEnterTerritory( PublicContent& instance, Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override + { + player.directorPlayScene( instance.getDirectorId(), 1, NONE, 0, 0, 0 ); + } + + void onDebug( Entity::Player& player, uint32_t param ) override + { + auto instance = player.getCurrentPublicContent(); + if( !instance || instance->getDirectorId() != getId() ) + return; + player.sendUrgent( "SanctumOfTheTwelve: debug {}", param ); + + player.eventStart( player.getId(), instance->getDirectorId(), Event::EventHandler::EnterTerritory, 1, player.getZoneId() ); + player.directorPlayScene( instance->getDirectorId(), 3, FADE_OUT | CONDITION_CUTSCENE | HIDE_UI, 0, 1, param ); + } + +}; + +EXPOSE_SCRIPT( SanctumOfTheTwelve ); \ No newline at end of file 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/Event/Director.cpp b/src/world/Event/Director.cpp index 864bf0e3..8798f656 100644 --- a/src/world/Event/Director.cpp +++ b/src/world/Event/Director.cpp @@ -59,7 +59,7 @@ void Sapphire::Event::Director::sendDirectorVars( Sapphire::Entity::Player& play void Sapphire::Event::Director::sendDirectorInit( Sapphire::Entity::Player& player ) const { - Logger::debug( "DirectorID#{}, QuestBattleID#{}", m_directorId, m_contentId ); + Logger::debug( "DirectorID#{}, ContentId#{}", m_directorId, m_contentId ); player.queuePacket( makeActorControlSelf( player.getId(), DirectorInit, m_directorId, m_contentId ) ); } 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 02da544b..84539c06 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 ); } @@ -670,6 +673,12 @@ void Sapphire::World::Manager::DebugCommandMgr::get( char* data, Entity::Player& 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 { @@ -890,6 +899,12 @@ void Sapphire::World::Manager::DebugCommandMgr::script( char* data, Entity::Play player.sendDebug( "Queued script reload for script: {0}", params ); } } + else if ( subCommand == "debug" ) + { + uint32_t id, param; + sscanf( params.c_str(), "%u %u", &id, ¶m ); + scriptMgr.onDebug( id, player, param ); + } else { player.sendDebug( "Unknown script subcommand: {0}", subCommand ); @@ -1375,3 +1390,99 @@ 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 ); + } +} 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 50cd0c53..e006e301 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" @@ -111,7 +112,13 @@ bool Sapphire::World::Manager::TerritoryMgr::isInstanceContentTerritory( uint32_ intendedUse == TerritoryIntendedUse::RaidFights || intendedUse == TerritoryIntendedUse::Raids || intendedUse == TerritoryIntendedUse::TreasureMapInstance || - intendedUse == TerritoryIntendedUse::EventTrial; + intendedUse == TerritoryIntendedUse::EventTrial || + intendedUse == TerritoryIntendedUse::DiademV1 || + intendedUse == TerritoryIntendedUse::DiademV2 || + intendedUse == TerritoryIntendedUse::DiademV3 || + intendedUse == TerritoryIntendedUse::Eureka || + intendedUse == TerritoryIntendedUse::Bozja || + intendedUse == TerritoryIntendedUse::Wedding; } bool Sapphire::World::Manager::TerritoryMgr::isPrivateTerritory( uint32_t territoryTypeId ) const @@ -306,8 +313,8 @@ Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::createQuestBattle if( !pQuestInfo ) return nullptr; - if( !isInstanceContentTerritory( pContentFinderCondition->territoryType ) ) - return nullptr; + //if( !isInstanceContentTerritory( pContentFinderCondition->territoryType ) ) + // return nullptr; auto pTeri = getTerritoryDetail( pContentFinderCondition->territoryType ); @@ -340,8 +347,8 @@ Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::createInstanceCon if( !pInstanceContent ) return nullptr; - if( !isInstanceContentTerritory( pContentFinderCondition->territoryType ) ) - return nullptr; + //if( !isInstanceContentTerritory( pContentFinderCondition->territoryType ) ) + // return nullptr; auto pTeri = getTerritoryDetail( pContentFinderCondition->territoryType ); @@ -361,6 +368,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 ); + 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 ); + 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 @@ -445,11 +514,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() ); @@ -617,7 +696,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 807aa1ec..d55b9528 100644 --- a/src/world/Manager/TerritoryMgr.h +++ b/src/world/Manager/TerritoryMgr.h @@ -120,6 +120,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 ); @@ -181,6 +184,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 >; @@ -198,9 +202,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/Handlers/EventHandlers.cpp b/src/world/Network/Handlers/EventHandlers.cpp index 45a9776d..19c9b3d0 100644 --- a/src/world/Network/Handlers/EventHandlers.cpp +++ b/src/world/Network/Handlers/EventHandlers.cpp @@ -24,6 +24,7 @@ #include "Territory/InstanceContent.h" #include "Territory/QuestBattle.h" +#include "Territory/PublicContent.h" #include "Session.h" @@ -58,7 +59,15 @@ void Sapphire::Network::GameConnection::eventHandlerTalk( const Packets::FFXIVAR if( auto instance = player.getCurrentInstance() ) { - instance->onTalk( player, eventId, actorId ); + 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 ); } bool eventCalled = false; @@ -196,6 +205,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() ); diff --git a/src/world/Script/NativeScriptApi.cpp b/src/world/Script/NativeScriptApi.cpp index bf21522c..4c04f36e 100644 --- a/src/world/Script/NativeScriptApi.cpp +++ b/src/world/Script/NativeScriptApi.cpp @@ -31,6 +31,10 @@ namespace Sapphire::ScriptAPI return m_type; } + void ScriptObject::onDebug( Entity::Player& player, uint32_t param ) + { + } + /////////////////////////////////////////////////////////////////// StatusEffectScript::StatusEffectScript( uint32_t effectId ) : @@ -232,5 +236,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 09fbd7db..e01bd15c 100644 --- a/src/world/Script/NativeScriptApi.h +++ b/src/world/Script/NativeScriptApi.h @@ -46,6 +46,8 @@ namespace Sapphire::ScriptAPI * @return The hash_code of the script */ virtual std::size_t getType() const; + + virtual void onDebug( Sapphire::Entity::Player& player, uint32_t param ); }; @@ -245,6 +247,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/NativeScriptMgr.cpp b/src/world/Script/NativeScriptMgr.cpp index 6db51a39..063b280c 100644 --- a/src/world/Script/NativeScriptMgr.cpp +++ b/src/world/Script/NativeScriptMgr.cpp @@ -130,5 +130,17 @@ namespace Sapphire::Scripting { return std::make_shared< NativeScriptMgr >(); } + + Sapphire::ScriptAPI::ScriptObject* NativeScriptMgr::getScript( uint32_t scriptId ) + { + for( auto typedMap : m_scripts ) + { + auto script = typedMap.second.find( scriptId ); + if( script == typedMap.second.end() ) + continue; + return script->second; + } + return nullptr; + } } diff --git a/src/world/Script/NativeScriptMgr.h b/src/world/Script/NativeScriptMgr.h index 668408a0..a58f20aa 100644 --- a/src/world/Script/NativeScriptMgr.h +++ b/src/world/Script/NativeScriptMgr.h @@ -116,6 +116,8 @@ namespace Sapphire::Scripting return dynamic_cast< T* >( script->second ); } + + Sapphire::ScriptAPI::ScriptObject* getScript( uint32_t scriptId ); }; diff --git a/src/world/Script/ScriptMgr.cpp b/src/world/Script/ScriptMgr.cpp index f3a8a9f6..6313eb01 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" @@ -147,6 +148,13 @@ bool Sapphire::Scripting::ScriptMgr::loadDir( const std::string& dirname, std::s } } +void Sapphire::Scripting::ScriptMgr::onDebug( uint32_t id, Entity::Player& player, uint32_t param ) +{ + auto script = m_nativeScriptMgr->getScript( id ); + if( script ) + script->onDebug( player, param ); +} + void Sapphire::Scripting::ScriptMgr::onPlayerFirstEnterWorld( Entity::Player& player ) { // try @@ -587,5 +595,67 @@ bool Sapphire::Scripting::ScriptMgr::onSaveData( Sapphire::Entity::Player& playe 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 676ab6ac..08066519 100644 --- a/src/world/Script/ScriptMgr.h +++ b/src/world/Script/ScriptMgr.h @@ -52,6 +52,8 @@ namespace Sapphire::Scripting */ void watchDirectories(); + void onDebug( uint32_t id, Entity::Player& player, uint32_t param ); + void onPlayerFirstEnterWorld( Entity::Player& player ); bool onTalk( Entity::Player& player, uint64_t actorId, uint32_t eventId ); @@ -120,6 +122,16 @@ namespace Sapphire::Scripting bool onSaveData( Entity::Player& player, const Common::EventSaveData& data ); + 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..cd2a3455 100644 --- a/src/world/Territory/InstanceContent.cpp +++ b/src/world/Territory/InstanceContent.cpp @@ -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( object->getName() == "Entrance" ) + m_pEntranceEObj = object; auto& exdData = Common::Service< Data::ExdDataGenerated >::ref(); auto objData = exdData.get< Sapphire::Data::EObj >( object->getObjectId() ); diff --git a/src/world/Territory/PublicContent.cpp b/src/world/Territory/PublicContent.cpp new file mode 100644 index 00000000..e6c49b0e --- /dev/null +++ b/src/world/Territory/PublicContent.cpp @@ -0,0 +1,261 @@ +#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 ) : + Territory( static_cast< uint16_t >( territoryType ), guId, internalName, contentName ), + Director( Event::Director::PublicContent, contentId ), + 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 ) +{ + 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( 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() ) ); +} + +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(), 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..4af79a09 --- /dev/null +++ b/src/world/Territory/PublicContent.h @@ -0,0 +1,70 @@ +#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 ); + + 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; + + 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/Territory.cpp b/src/world/Territory/Territory.cpp index a2e71d4d..d39d9124 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" @@ -790,6 +791,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; diff --git a/src/world/Territory/Territory.h b/src/world/Territory/Territory.h index 47aa51ae..34cbf576 100644 --- a/src/world/Territory/Territory.h +++ b/src/world/Territory/Territory.h @@ -170,6 +170,8 @@ namespace Sapphire QuestBattlePtr getAsQuestBattle(); + PublicContentPtr getAsPublicContent(); + void updateSpawnPoints(); uint32_t getNextEffectSequence();