From d4afee03a6208593582e3e2e9a5bc0babd892500 Mon Sep 17 00:00:00 2001 From: collett Date: Thu, 23 Jan 2020 22:36:01 +0900 Subject: [PATCH 1/4] Implement mount action. --- src/common/Common.h | 5 +- src/common/Network/PacketDef/Ipcs.h | 2 +- .../Network/PacketDef/Zone/ServerZoneDef.h | 5 +- src/world/Action/Action.cpp | 3 +- src/world/Action/Action.h | 2 +- src/world/Action/EffectBuilder.cpp | 7 ++ src/world/Action/EffectBuilder.h | 2 + src/world/Action/EffectResult.cpp | 16 +++++ src/world/Action/EffectResult.h | 1 + src/world/Action/MountAction.cpp | 68 +++++++++++++++++++ src/world/Action/MountAction.h | 25 +++++++ src/world/ForwardsZone.h | 1 + src/world/Manager/ActionMgr.cpp | 17 +++++ src/world/Manager/ActionMgr.h | 3 + src/world/Network/Handlers/ActionHandler.cpp | 4 +- 15 files changed, 153 insertions(+), 8 deletions(-) create mode 100644 src/world/Action/MountAction.cpp create mode 100644 src/world/Action/MountAction.h diff --git a/src/common/Common.h b/src/common/Common.h index 543d5cd1..15b98084 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -632,10 +632,10 @@ namespace Sapphire::Common * @param flags Required to be 128, doesn't show combo rings on hotbars otherwise * @param value The actionid that starts/continues the combo. eg, 3617 will start a spinning slash and/or syphon strike combo */ - StartActionCombo = 28, + StartActionCombo = 28, // actually this is more likely "ActionComplete" or something like that ComboSucceed = 29, Knockback = 33, - Mount = 38, + Mount = 39, VFX = 59, // links to VFX sheet }; @@ -1009,6 +1009,7 @@ namespace Sapphire::Common { SingleTarget = 1, CircularAOE = 2, + Type3 = 3, // another single target? no idea how to call it RectangularAOE = 4, CircularAoEPlaced = 7 }; diff --git a/src/common/Network/PacketDef/Ipcs.h b/src/common/Network/PacketDef/Ipcs.h index 97dba6ba..19651f7b 100644 --- a/src/common/Network/PacketDef/Ipcs.h +++ b/src/common/Network/PacketDef/Ipcs.h @@ -207,7 +207,7 @@ namespace Sapphire::Network::Packets QuestTracker = 0x0289, // updated 5.18 - Mount = 0x02F0, // updated 5.18 + Mount = 0x038F, // updated 5.18 DirectorVars = 0x00E6, // updated 5.18 SomeDirectorUnk1 = 0x0084, // updated 5.18 diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 8a06167b..b2f844c7 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -835,10 +835,11 @@ namespace Sapphire::Network::Packets::Server uint16_t action_id; Common::SkillType skillType; uint8_t unknown; - uint32_t unknown_1; // Also action id + uint32_t unknown_1; // action id or mount id float cast_time; uint32_t target_id; - float rotation; // In radians + uint16_t rotation; + uint16_t flag; // 1 = interruptible blinking cast bar uint32_t unknown_2; uint16_t posX; uint16_t posY; diff --git a/src/world/Action/Action.cpp b/src/world/Action/Action.cpp index 9a89c249..aa9a3b28 100644 --- a/src/world/Action/Action.cpp +++ b/src/world/Action/Action.cpp @@ -275,7 +275,7 @@ void Action::Action::start() data.posX = Common::Util::floatToUInt16( pos.x ); data.posY = Common::Util::floatToUInt16( pos.y ); data.posZ = Common::Util::floatToUInt16( pos.z ); - data.rotation = m_pSource->getRot(); + data.rotation = Common::Util::floatToUInt16Rot( m_pSource->getRot() ); m_pSource->sendToInRangeSet( castPacket, true ); @@ -736,6 +736,7 @@ void Action::Action::addDefaultActorFilters() switch( m_castType ) { case Common::CastType::SingleTarget: + case Common::CastType::Type3: { auto filter = std::make_shared< World::Util::ActorFilterSingleTarget >( static_cast< uint32_t >( m_targetId ) ); diff --git a/src/world/Action/Action.h b/src/world/Action/Action.h index 355514b5..04142f3b 100644 --- a/src/world/Action/Action.h +++ b/src/world/Action/Action.h @@ -80,7 +80,7 @@ namespace Sapphire::World::Action * @brief Tests if an action is castable by the current source chara * @return true if castable, false if the caster doesn't meet the requirements */ - bool preCheck(); + virtual bool preCheck(); /*! * @brief Snapshots characters affected by a cast. diff --git a/src/world/Action/EffectBuilder.cpp b/src/world/Action/EffectBuilder.cpp index 64af6932..447ef48b 100644 --- a/src/world/Action/EffectBuilder.cpp +++ b/src/world/Action/EffectBuilder.cpp @@ -91,6 +91,13 @@ void EffectBuilder::applyStatusEffect( Entity::CharaPtr& target, uint16_t status moveToResultList( target, nextResult ); } +void EffectBuilder::mount( Entity::CharaPtr& target, uint16_t mountId ) +{ + EffectResultPtr nextResult = make_EffectResult( target, getResultDelayMs() ); + nextResult->mount( mountId ); + moveToResultList( target, nextResult ); +} + void EffectBuilder::buildAndSendPackets() { auto targetCount = m_resolvedEffects.size(); diff --git a/src/world/Action/EffectBuilder.h b/src/world/Action/EffectBuilder.h index 6a4aa240..3ed70dfc 100644 --- a/src/world/Action/EffectBuilder.h +++ b/src/world/Action/EffectBuilder.h @@ -28,6 +28,8 @@ namespace Sapphire::World::Action void applyStatusEffect( Entity::CharaPtr& target, uint16_t statusId, uint8_t param ); + void mount( Entity::CharaPtr& target, uint16_t mountId ); + void buildAndSendPackets(); diff --git a/src/world/Action/EffectResult.cpp b/src/world/Action/EffectResult.cpp index f8feeafb..6497985b 100644 --- a/src/world/Action/EffectResult.cpp +++ b/src/world/Action/EffectResult.cpp @@ -3,6 +3,7 @@ #include #include "Actor/Chara.h" +#include "Actor/Player.h" using namespace Sapphire; using namespace Sapphire::World::Action; @@ -84,6 +85,14 @@ void EffectResult::applyStatusEffect( uint16_t statusId, uint8_t param ) m_type = Common::ActionEffectType::ApplyStatusEffect; } +void EffectResult::mount( uint16_t moundId ) +{ + m_value = moundId; + m_param0 = 1; + + m_type = Common::ActionEffectType::Mount; +} + Common::EffectEntry EffectResult::buildEffectEntry() const { Common::EffectEntry entry{}; @@ -121,6 +130,13 @@ void EffectResult::execute() break; } + case Common::ActionEffectType::Mount: + { + auto pPlayer = m_target->getAsPlayer(); + pPlayer->mount( m_value ); + break; + } + default: break; } diff --git a/src/world/Action/EffectResult.h b/src/world/Action/EffectResult.h index ad69f205..b61cb039 100644 --- a/src/world/Action/EffectResult.h +++ b/src/world/Action/EffectResult.h @@ -21,6 +21,7 @@ namespace Sapphire::World::Action void startCombo( uint16_t actionId ); void comboSucceed(); void applyStatusEffect( uint16_t statusId, uint8_t param ); + void mount( uint16_t moundId ); Entity::CharaPtr getTarget() const; diff --git a/src/world/Action/MountAction.cpp b/src/world/Action/MountAction.cpp new file mode 100644 index 00000000..94d13202 --- /dev/null +++ b/src/world/Action/MountAction.cpp @@ -0,0 +1,68 @@ +#include "MountAction.h" + +#include + +#include "Actor/Player.h" + +#include +#include "Network/PacketWrappers/ActorControlSelfPacket.h" + +#include + +using namespace Sapphire; +using namespace Sapphire::Network::Packets; +using namespace Sapphire::Network::Packets::Server; +using namespace Sapphire::Network::ActorControl; +using namespace Sapphire::World::Action; + +MountAction::MountAction( Sapphire::Entity::CharaPtr source, uint32_t mountId, uint16_t sequence, Data::ActionPtr actionData, Sapphire::FrameworkPtr fw ) : + Action::Action( source, 4, sequence, actionData, fw ), + m_mountId( mountId ) +{ +} + +bool MountAction::preCheck() +{ + // todo: check if mount is unlocked + return m_pSource->isPlayer(); +} + +void MountAction::start() +{ + assert( m_pSource ); + + m_startTime = Common::Util::getTimeMs(); + + auto player = m_pSource->getAsPlayer(); + + auto castPacket = makeZonePacket< Server::FFXIVIpcActorCast >( getId() ); + auto& data = castPacket->data(); + + data.action_id = static_cast< uint16_t >( m_id ); + data.skillType = Common::SkillType::MountSkill; + data.unknown_1 = m_mountId; + data.cast_time = m_castTimeMs / 1000.f; + data.target_id = static_cast< uint32_t >( m_targetId ); + data.unknown_2 = 0xE0000000; + + auto pos = m_pSource->getPos(); + data.posX = Common::Util::floatToUInt16( pos.x ); + data.posY = Common::Util::floatToUInt16( pos.y ); + data.posZ = Common::Util::floatToUInt16( pos.z ); + data.rotation = Common::Util::floatToUInt16Rot( m_pSource->getRot() ); + + m_pSource->sendToInRangeSet( castPacket, true ); + + player->setStateFlag( Common::PlayerStateFlag::Casting ); + + auto actionStartPkt = makeActorControlSelf( m_pSource->getId(), ActorControlType::ActionStart, 1, getId(), m_recastTimeMs / 10 ); + player->queuePacket( actionStartPkt ); +} + +void MountAction::execute() +{ + assert( m_pSource ); + + m_effectBuilder->mount( m_pSource, m_mountId ); + m_effectBuilder->buildAndSendPackets(); +} \ No newline at end of file diff --git a/src/world/Action/MountAction.h b/src/world/Action/MountAction.h new file mode 100644 index 00000000..37c0595a --- /dev/null +++ b/src/world/Action/MountAction.h @@ -0,0 +1,25 @@ +#ifndef SAPPHIRE_MOUNTACTION_H +#define SAPPHIRE_MOUNTACTION_H + +#include "Action.h" + +namespace Sapphire::World::Action +{ + class MountAction : public Action + { + public: + MountAction( Entity::CharaPtr source, uint32_t mountId, uint16_t sequence, Data::ActionPtr actionData, FrameworkPtr fw ); + virtual ~MountAction() = default; + + bool preCheck() override; + + void start() override; + + void execute() override; + + private: + uint32_t m_mountId; + }; +} + +#endif //SAPPHIRE_MOUNTACTION_H diff --git a/src/world/ForwardsZone.h b/src/world/ForwardsZone.h index 4ff4af79..db366d35 100644 --- a/src/world/ForwardsZone.h +++ b/src/world/ForwardsZone.h @@ -87,6 +87,7 @@ namespace World::Action TYPE_FORWARD( Action ); TYPE_FORWARD( EventAction ); TYPE_FORWARD( ItemAction ); +TYPE_FORWARD( MountAction ); TYPE_FORWARD( EffectBuilder ); TYPE_FORWARD( EffectResult ); diff --git a/src/world/Manager/ActionMgr.cpp b/src/world/Manager/ActionMgr.cpp index 2356d7b3..f9859170 100644 --- a/src/world/Manager/ActionMgr.cpp +++ b/src/world/Manager/ActionMgr.cpp @@ -2,6 +2,7 @@ #include "Action/Action.h" #include "Action/ItemAction.h" +#include "Action/MountAction.h" #include "Script/ScriptMgr.h" #include "Actor/Player.h" @@ -78,6 +79,22 @@ void World::Manager::ActionMgr::handleItemAction( Sapphire::Entity::Player& play action->start(); } +void World::Manager::ActionMgr::handleMountAction( Entity::Player& player, uint32_t mountId, + Data::ActionPtr actionData, uint64_t targetId, + uint16_t sequence ) +{ + player.sendDebug( "mount: {0}", mountId ); + + auto action = Action::make_MountAction( player.getAsPlayer(), mountId, sequence, actionData, framework() ); + + action->setTargetId( targetId ); + + if( !action->init() ) + return; + + bootstrapAction( player, action, *actionData ); +} + void World::Manager::ActionMgr::bootstrapAction( Entity::Player& player, Action::ActionPtr currentAction, Data::Action& actionData ) diff --git a/src/world/Manager/ActionMgr.h b/src/world/Manager/ActionMgr.h index 75e238e9..a8cf49df 100644 --- a/src/world/Manager/ActionMgr.h +++ b/src/world/Manager/ActionMgr.h @@ -29,6 +29,9 @@ namespace Sapphire::World::Manager void handleItemAction( Entity::Player& player, uint32_t itemId, Data::ItemActionPtr itemActionData, uint16_t itemSourceSlot, uint16_t itemSourceContainer ); + void handleMountAction( Entity::Player& player, uint32_t mountId, + Data::ActionPtr actionData, uint64_t targetId, uint16_t sequence ); + private: void bootstrapAction( Entity::Player& player, Action::ActionPtr currentAction, Data::Action& actionData ); diff --git a/src/world/Network/Handlers/ActionHandler.cpp b/src/world/Network/Handlers/ActionHandler.cpp index dd365b9b..78bf55d8 100644 --- a/src/world/Network/Handlers/ActionHandler.cpp +++ b/src/world/Network/Handlers/ActionHandler.cpp @@ -72,7 +72,9 @@ void Sapphire::Network::GameConnection::actionHandler( FrameworkPtr pFw, case Common::SkillType::MountSkill: { - + auto action = exdData->get< Data::Action >( 4 ); + assert( action ); + actionMgr->handleMountAction( player, actionId, action, targetId, sequence ); break; } } From 29da401de77cf4a1734a2a90f1dcb071a0f12eef Mon Sep 17 00:00:00 2001 From: collett Date: Thu, 23 Jan 2020 22:43:16 +0900 Subject: [PATCH 2/4] Fix moundId type. --- src/world/Action/MountAction.cpp | 2 +- src/world/Action/MountAction.h | 4 ++-- src/world/Manager/ActionMgr.cpp | 2 +- src/world/Manager/ActionMgr.h | 2 +- src/world/Network/Handlers/ActionHandler.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/world/Action/MountAction.cpp b/src/world/Action/MountAction.cpp index 94d13202..1c0170b7 100644 --- a/src/world/Action/MountAction.cpp +++ b/src/world/Action/MountAction.cpp @@ -15,7 +15,7 @@ using namespace Sapphire::Network::Packets::Server; using namespace Sapphire::Network::ActorControl; using namespace Sapphire::World::Action; -MountAction::MountAction( Sapphire::Entity::CharaPtr source, uint32_t mountId, uint16_t sequence, Data::ActionPtr actionData, Sapphire::FrameworkPtr fw ) : +MountAction::MountAction( Sapphire::Entity::CharaPtr source, uint16_t mountId, uint16_t sequence, Data::ActionPtr actionData, Sapphire::FrameworkPtr fw ) : Action::Action( source, 4, sequence, actionData, fw ), m_mountId( mountId ) { diff --git a/src/world/Action/MountAction.h b/src/world/Action/MountAction.h index 37c0595a..1b095b47 100644 --- a/src/world/Action/MountAction.h +++ b/src/world/Action/MountAction.h @@ -8,7 +8,7 @@ namespace Sapphire::World::Action class MountAction : public Action { public: - MountAction( Entity::CharaPtr source, uint32_t mountId, uint16_t sequence, Data::ActionPtr actionData, FrameworkPtr fw ); + MountAction( Entity::CharaPtr source, uint16_t mountId, uint16_t sequence, Data::ActionPtr actionData, FrameworkPtr fw ); virtual ~MountAction() = default; bool preCheck() override; @@ -18,7 +18,7 @@ namespace Sapphire::World::Action void execute() override; private: - uint32_t m_mountId; + uint16_t m_mountId; }; } diff --git a/src/world/Manager/ActionMgr.cpp b/src/world/Manager/ActionMgr.cpp index f9859170..aaa723c9 100644 --- a/src/world/Manager/ActionMgr.cpp +++ b/src/world/Manager/ActionMgr.cpp @@ -79,7 +79,7 @@ void World::Manager::ActionMgr::handleItemAction( Sapphire::Entity::Player& play action->start(); } -void World::Manager::ActionMgr::handleMountAction( Entity::Player& player, uint32_t mountId, +void World::Manager::ActionMgr::handleMountAction( Entity::Player& player, uint16_t mountId, Data::ActionPtr actionData, uint64_t targetId, uint16_t sequence ) { diff --git a/src/world/Manager/ActionMgr.h b/src/world/Manager/ActionMgr.h index a8cf49df..dd1d5f40 100644 --- a/src/world/Manager/ActionMgr.h +++ b/src/world/Manager/ActionMgr.h @@ -29,7 +29,7 @@ namespace Sapphire::World::Manager void handleItemAction( Entity::Player& player, uint32_t itemId, Data::ItemActionPtr itemActionData, uint16_t itemSourceSlot, uint16_t itemSourceContainer ); - void handleMountAction( Entity::Player& player, uint32_t mountId, + void handleMountAction( Entity::Player& player, uint16_t mountId, Data::ActionPtr actionData, uint64_t targetId, uint16_t sequence ); private: diff --git a/src/world/Network/Handlers/ActionHandler.cpp b/src/world/Network/Handlers/ActionHandler.cpp index 78bf55d8..2b9f81dd 100644 --- a/src/world/Network/Handlers/ActionHandler.cpp +++ b/src/world/Network/Handlers/ActionHandler.cpp @@ -74,7 +74,7 @@ void Sapphire::Network::GameConnection::actionHandler( FrameworkPtr pFw, { auto action = exdData->get< Data::Action >( 4 ); assert( action ); - actionMgr->handleMountAction( player, actionId, action, targetId, sequence ); + actionMgr->handleMountAction( player, static_cast< uint16_t >( actionId ), action, targetId, sequence ); break; } } From 66a2021e95e3181a6c142299df941aa9106f37a7 Mon Sep 17 00:00:00 2001 From: collett Date: Thu, 23 Jan 2020 23:23:13 +0900 Subject: [PATCH 3/4] these bytes are mounts as well. --- src/common/Network/PacketDef/Zone/ServerZoneDef.h | 3 +-- src/world/Actor/Player.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index b2f844c7..6b7883f3 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1024,8 +1024,7 @@ namespace Sapphire::Network::Packets::Server unsigned char companionAttRank; unsigned char companionHealRank; unsigned char u19[2]; - unsigned char mountGuideMask[19]; - uint8_t unk1[9]; + unsigned char mountGuideMask[28]; char name[32]; unsigned char unknownOword[16]; unsigned char unknownOw; diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index fc2020e4..422e5bff 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -1045,7 +1045,7 @@ namespace Sapphire::Entity uint8_t m_titleList[48]; uint8_t m_howTo[34]; uint8_t m_minions[40]; - uint8_t m_mountGuide[19]; + uint8_t m_mountGuide[28]; uint8_t m_homePoint; uint8_t m_startTown; uint16_t m_townWarpFstFlags; From 264f4bd459dc24e4914901a70c00de4fb76bdd9c Mon Sep 17 00:00:00 2001 From: collett Date: Fri, 24 Jan 2020 08:08:51 +0900 Subject: [PATCH 4/4] fix derp --- src/common/Network/PacketDef/Zone/ServerZoneDef.h | 4 ++-- src/world/Actor/Player.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 6b7883f3..6e715282 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1023,8 +1023,8 @@ namespace Sapphire::Network::Packets::Server unsigned char companionDefRank; unsigned char companionAttRank; unsigned char companionHealRank; - unsigned char u19[2]; - unsigned char mountGuideMask[28]; + unsigned char u19[8]; + unsigned char mountGuideMask[22]; char name[32]; unsigned char unknownOword[16]; unsigned char unknownOw; diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index 422e5bff..26984e17 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -1045,7 +1045,7 @@ namespace Sapphire::Entity uint8_t m_titleList[48]; uint8_t m_howTo[34]; uint8_t m_minions[40]; - uint8_t m_mountGuide[28]; + uint8_t m_mountGuide[22]; uint8_t m_homePoint; uint8_t m_startTown; uint16_t m_townWarpFstFlags;