diff --git a/src/common/Network/CommonActorControl.h b/src/common/Network/CommonActorControl.h index 456d2fdf..76f1c510 100644 --- a/src/common/Network/CommonActorControl.h +++ b/src/common/Network/CommonActorControl.h @@ -382,11 +382,11 @@ namespace Sapphire::Network::ActorControl TitleList = 0x12F, UpdatedSeenHowTos = 0x132, - CutscenePlayed = 0x134, // param1 = cutscene id + CutscenePlayed = 0x134, // p1 = cutscene id AllotAttribute = 0x135, //ClearFieldMarkers = 0x13A, - CameraMode = 0x13A, // param11 (only read lowest byte), 1 = enable, 0 = disable + CameraMode = 0x13A, // p1 (only read lowest byte), 1 = enable, 0 = disable CharaNameReq = 0x13D, // requests character name by content id HuntingLogDetails = 0x194, @@ -397,10 +397,12 @@ namespace Sapphire::Network::ActorControl RequestChocoboInventory = 0x1C4, EmoteReq = 0x1F4, + EmoteWithWarp = 0x1F5, EmoteCancel = 0x1F6, PersistentEmoteCancel = 0x1F7, + EmoteCancelWithWarp = 0x1F8, /*! - * param2 = pose ID + * p2 = pose ID * 0 = idle pose 0 (just standing) * 1 = idle pose 1 * 2-4 = idle poses 2-4 @@ -430,9 +432,9 @@ namespace Sapphire::Network::ActorControl AchievementCritReq = 0x3E8, AchievementList = 0x3E9, - SetEstateLightingLevel = 0x40B, // param1 = light level 0 - 5 maps to UI val 5-0 + SetEstateLightingLevel = 0x40B, // p1 = light level 0 - 5 maps to UI val 5-0 RequestHousingBuildPreset = 0x44C, - RequestEstateExteriorRemodel = 0x044D, // param11 = land id + RequestEstateExteriorRemodel = 0x044D, // p1 = land id RequestEstateInteriorRemodel = 0x44E, RequestEstateHallRemoval = 0x44F, RequestBuildPreset = 0x450, // no idea what this is, it gets sent with BuildPresetHandler and has the plot id in param1 diff --git a/src/common/Network/PacketDef/Ipcs.h b/src/common/Network/PacketDef/Ipcs.h index 44481fa1..4b0389ee 100644 --- a/src/common/Network/PacketDef/Ipcs.h +++ b/src/common/Network/PacketDef/Ipcs.h @@ -392,6 +392,7 @@ enum ClientZoneIpcType : ZoneLineHandler = 0x326, // updated 6.58 hotfix 2 ClientTrigger = 0x035C, // updated 6.58 hotfix 2 + ClientTriggerEnvironment = 0x0295, // updated 6.58 hotfix 2 DiscoveryHandler = 0x0129, // updated 6.58 hotfix 2 SkillHandler = 0x07C, // updated 6.58 hotfix 2 @@ -436,8 +437,6 @@ enum ClientZoneIpcType : UpdatePositionInstance = 0x0227, // updated 6.58 hotfix 2 PerformNoteHandler = 0x0243, // updated 5.58h - - WorldInteractionHandler = 0x0295, // updated 6.58 hotfix 2 Dive = 0x018C, // updated 6.30h }; diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index baa0944c..5bfcee7b 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -37,12 +37,11 @@ struct FFXIVIpcClientTrigger : { /* 0000 */ uint16_t commandId; /* 0002 */ uint8_t unk_2[2]; - /* 0004 */ uint32_t param11; - /* 0008 */ uint32_t param12; - /* 000C */ uint32_t param2; - /* 0010 */ uint32_t param4; // todo: really? - /* 0014 */ uint32_t param5; - /* 0018 */ uint64_t param3; + /* 0004 */ uint32_t param1; + /* 0008 */ uint32_t param2; + /* 000C */ uint32_t param3; + /* 0010 */ uint32_t param4; + /* 0014 */ Common::FFXIVARR_POSITION3 position; }; struct FFXIVIpcUpdatePosition : @@ -351,17 +350,6 @@ struct FFXIVIpcFreeCompanyUpdateShortMessageHandler : uint16_t unknown2; }; -struct FFXIVIpcWorldInteractionHandler : - FFXIVIpcBasePacket< WorldInteractionHandler > -{ - uint32_t action; - uint32_t param1; - uint32_t param2; - uint32_t param3; - uint32_t param4; - Common::FFXIVARR_POSITION3 position; -}; - struct FFXIVIpcSocialInviteHandler : FFXIVIpcBasePacket< SocialInviteHandler > { diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index e104c28a..ff88d2ee 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -2020,10 +2020,10 @@ void Sapphire::Entity::Player::finishZoning() } } -void Sapphire::Entity::Player::emote( uint32_t emoteId, uint64_t targetId, bool isSilent ) +void Sapphire::Entity::Player::emote( uint32_t emoteId, uint64_t targetId, bool isSilent, uint32_t rotation ) { sendToInRangeSet( makeActorControlTarget( getId(), ActorControlType::Emote, - emoteId, 0, isSilent ? 1 : 0, 0, targetId ) ); + emoteId, 0, isSilent ? 1 : 0, rotation, targetId ) ); } void Sapphire::Entity::Player::emoteInterrupt() diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index ed53f3d1..ad96a2c0 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -791,7 +791,7 @@ namespace Sapphire::Entity /*! return true if the player is marked for zoning */ bool isMarkedForZoning() const; - void emote( uint32_t emoteId, uint64_t targetId, bool isSilent ); + void emote( uint32_t emoteId, uint64_t targetId, bool isSilent, uint32_t rotation = 0 ); void emoteInterrupt(); diff --git a/src/world/Network/GameConnection.cpp b/src/world/Network/GameConnection.cpp index 90e5d7cf..38c944dd 100644 --- a/src/world/Network/GameConnection.cpp +++ b/src/world/Network/GameConnection.cpp @@ -70,7 +70,7 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH setZoneHandler( ClientZoneIpcType::ReqExamineFcInfo, "ReqExamineFcInfo", &GameConnection::reqExamineFcInfo ); setZoneHandler( ClientZoneIpcType::ZoneLineHandler, "ZoneLineHandler", &GameConnection::zoneLineHandler ); setZoneHandler( ClientZoneIpcType::ClientTrigger, "ClientTrigger", &GameConnection::clientTriggerHandler ); - + setZoneHandler( ClientZoneIpcType::ClientTriggerEnvironment, "ClientTriggerEnvironment", &GameConnection::clientTriggerHandler ); setZoneHandler( ClientZoneIpcType::DiscoveryHandler, "DiscoveryHandler", &GameConnection::discoveryHandler ); setZoneHandler( ClientZoneIpcType::SkillHandler, "ActionHandler", &GameConnection::actionHandler ); @@ -137,7 +137,6 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH setZoneHandler( ClientZoneIpcType::MarketBoardRequestItemListings, "MarketBoardRequestItemListings", &GameConnection::marketBoardRequestItemListings ); - setZoneHandler( ClientZoneIpcType::WorldInteractionHandler, "WorldInteractionHandler", &GameConnection::worldInteractionhandler ); setZoneHandler( ClientZoneIpcType::Dive, "Dive", &GameConnection::diveHandler ); setZoneHandler( ClientZoneIpcType::InventoryEquipRecommendedItems, "InventoryEquipRecommendedItemsHandler", &GameConnection::inventoryEquipRecommendedItemsHandler ); diff --git a/src/world/Network/Handlers/ClientTriggerHandler.cpp b/src/world/Network/Handlers/ClientTriggerHandler.cpp index f43874ab..78409999 100644 --- a/src/world/Network/Handlers/ClientTriggerHandler.cpp +++ b/src/world/Network/Handlers/ClientTriggerHandler.cpp @@ -8,8 +8,12 @@ #include #include +#include +#include + #include "Territory/Territory.h" #include "Territory/ZonePosition.h" +#include #include "Manager/HousingMgr.h" #include "Network/GameConnection.h" @@ -70,16 +74,15 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX const auto packet = ZoneChannelPacket< Client::FFXIVIpcClientTrigger >( inPacket ); const auto commandId = packet.data().commandId; - const auto param1 = *reinterpret_cast< const uint64_t* >( &packet.data().param11 ); - const auto param11 = packet.data().param11; - const auto param12 = packet.data().param12; - const auto param2 = packet.data().param2; - const auto param3 = packet.data().param3; - const auto param4 = packet.data().param4; - const auto param5 = packet.data().param5; + const auto p1u64 = *reinterpret_cast< const uint64_t* >( &packet.data().param1 ); + const auto p1 = packet.data().param1; + const auto p2 = packet.data().param2; + const auto p3 = packet.data().param3; + const auto p4 = packet.data().param4; + const auto pos = packet.data().position; - Logger::debug( "[{0}] Incoming action: {1:X} ( p1:{2:X} p2:{3:X} p3:{4:X} )", - m_pSession->getId(), commandId, param1, param2, param3 ); + Logger::debug( "[{0}] Type: {1:X} (p1u64:{2:X} p1:{3} p2:{4} p3:{5} p4:{6} x:{7} y:{8} z:{9}", + m_pSession->getId(), commandId, p1u64, p1, p2, p3, p4, pos.x, pos.y, pos.z ); //Logger::Log(LoggingSeverity::debug, "[" + std::to_string(m_pSession->getId()) + "] " + pInPacket->toString()); @@ -87,7 +90,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX { case ClientTriggerType::ToggleSheathe: // Toggle sheathe { - if( param11 == 1 ) + if( p1 == 1 ) player.setStance( Common::Stance::Active ); else { @@ -95,13 +98,13 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX player.setAutoattack( false ); } - player.sendToInRangeSet( makeActorControl( player.getId(), 0, param11, 1 ) ); + player.sendToInRangeSet( makeActorControl( player.getId(), 0, p1, 1 ) ); break; } case ClientTriggerType::ToggleAutoAttack: // Toggle auto-attack { - if( param11 == 1 ) + if( p1 == 1 ) { player.setAutoattack( true ); player.setStance( Common::Stance::Active ); @@ -110,15 +113,15 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX player.setAutoattack( false ); // the client seems to ignore source actor of this packet and always set auto-attack on itself. causing everyone on screen take their weapons out - player.queuePacket( makeActorControl( player.getId(), 1, param11, 1 ) ); - //player.sendToInRangeSet( makeActorControl( player.getId(), 1, param11, 1 ) ); + player.queuePacket( makeActorControl( player.getId(), 1, p1, 1 ) ); + //player.sendToInRangeSet( makeActorControl( player.getId(), 1, p1, 1 ) ); break; } case ClientTriggerType::ChangeTarget: // Change target { - uint64_t targetId = param1; + uint64_t targetId = p1u64; player.changeTarget( targetId ); break; } @@ -129,7 +132,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX } case ClientTriggerType::SpawnCompanionReq: { - player.spawnCompanion( static_cast< uint16_t >( param1 ) ); + player.spawnCompanion( static_cast< uint16_t >( p1 ) ); break; } case ClientTriggerType::DespawnCompanionReq: @@ -140,7 +143,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX case ClientTriggerType::RemoveStatusEffect: // Remove status (clicking it off) { // todo: check if status can be removed by client from exd - player.removeSingleStatusEffectById( static_cast< uint32_t >( param1 ) ); + player.removeSingleStatusEffectById( static_cast< uint32_t >( p1 ) ); break; } case ClientTriggerType::CastCancel: // Cancel cast @@ -151,7 +154,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX } case ClientTriggerType::Examine: { - uint32_t targetId = param11; + uint32_t targetId = p1u64; examineHandler( player, targetId ); break; } @@ -161,7 +164,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX } case ClientTriggerType::SetTitleReq: // Set player title { - player.setTitle( static_cast< uint16_t >( param1 ) ); + player.setTitle( static_cast< uint16_t >( p1 ) ); break; } case ClientTriggerType::TitleList: // Get title list @@ -171,13 +174,13 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX } case ClientTriggerType::UpdatedSeenHowTos: // Update howtos seen { - uint32_t howToId = param11; + uint32_t howToId = p1; player.updateHowtosSeen( howToId ); break; } case ClientTriggerType::CharaNameReq: { - uint64_t targetContentId = param1; + uint64_t targetContentId = p1u64; // todo: look up player by content id /* auto packet = makeZonePacket< FFXIVIpcCharaNameReq >( player.getId() ); @@ -192,10 +195,11 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX break; } case ClientTriggerType::EmoteReq: // emote + case ClientTriggerType::EmoteWithWarp: { uint64_t targetId = player.getTargetId(); - uint32_t emoteId = param11; - bool isSilent = param2 == 1; + uint32_t emoteId = p1; + bool isSilent = p3 == 1; auto& exdData = Common::Service< Data::ExdDataGenerated >::ref(); auto emoteData = exdData.get< Data::Emote >( emoteId ); @@ -203,7 +207,23 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX if( !emoteData ) return; - player.emote( emoteId, targetId, isSilent ); + if( commandId == ClientTriggerType::EmoteWithWarp ) + { + player.setPos( packet.data().position ); + player.setRot( Util::floatFromUInt16Rot( p4 ) ); + if( player.hasInRangeActor() ) + { + auto setpos = makeZonePacket< FFXIVIpcActorSetPos >( player.getId() ); + setpos->data().r16 = p4; + setpos->data().waitForLoad = 18; + setpos->data().x = packet.data().position.x; + setpos->data().y = packet.data().position.y; + setpos->data().z = packet.data().position.z; + player.sendToInRangeSet( setpos, false ); + } + } + + player.emote( emoteId, targetId, isSilent, commandId == ClientTriggerType::EmoteWithWarp ? p4 : 0 ); bool isPersistent = emoteData->emoteMode != 0; @@ -213,10 +233,6 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX player.setAutoattack( false ); player.setPersistentEmote( emoteData->emoteMode ); player.setStatus( Common::ActorStatus::EmoteMode ); - - player.sendToInRangeSet( makeActorControl( player.getId(), ActorControlType::SetStatus, - static_cast< uint8_t >( Common::ActorStatus::EmoteMode ), - emoteData->hasCancelEmote ? 1 : 0 ), true ); } if( emoteData->drawsWeapon ) @@ -226,38 +242,52 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX break; } - case ClientTriggerType::EmoteCancel: // emote - { - player.emoteInterrupt(); - break; - } + case ClientTriggerType::EmoteCancel: // emote cancel case ClientTriggerType::PersistentEmoteCancel: // cancel persistent emote + case ClientTriggerType::EmoteCancelWithWarp: { - player.setPersistentEmote( 0 ); + if( commandId == ClientTriggerType::EmoteCancelWithWarp ) + { + player.setPos( packet.data().position ); + if( player.hasInRangeActor() ) + { + auto setpos = makeZonePacket< FFXIVIpcActorSetPos >( player.getId() ); + setpos->data().r16 = p2; + setpos->data().waitForLoad = 18; + setpos->data().x = packet.data().position.x; + setpos->data().y = packet.data().position.y; + setpos->data().z = packet.data().position.z; + player.sendToInRangeSet( setpos, false ); + } + } player.emoteInterrupt(); - player.setStatus( Common::ActorStatus::Idle ); - auto pSetStatusPacket = makeActorControl( player.getId(), SetStatus, static_cast< uint8_t >( Common::ActorStatus::Idle ) ); - player.sendToInRangeSet( pSetStatusPacket ); + if( player.getPersistentEmote() ) + { + player.setPersistentEmote( 0 ); + player.setStatus( Common::ActorStatus::Idle ); + auto pSetStatusPacket = makeActorControl( player.getId(), SetStatus, static_cast< uint8_t >( Common::ActorStatus::Idle ) ); + player.sendToInRangeSet( pSetStatusPacket ); + } break; } case ClientTriggerType::PoseChange: // change pose case ClientTriggerType::PoseReapply: // reapply pose { - player.setPose( static_cast< uint8_t >( param12 ) ); - auto pSetStatusPacket = makeActorControl( player.getId(), SetPose, param11, param12 ); + player.setPose( static_cast< uint8_t >( p2 ) ); + auto pSetStatusPacket = makeActorControl( player.getId(), SetPose, p1, p2 ); player.sendToInRangeSet( pSetStatusPacket, true ); break; } case ClientTriggerType::PoseCancel: // cancel pose { - player.setPose( static_cast< uint8_t >( param12 ) ); - auto pSetStatusPacket = makeActorControl( player.getId(), SetPose, param11, param12 ); + player.setPose( static_cast< uint8_t >( p2 ) ); + auto pSetStatusPacket = makeActorControl( player.getId(), SetPose, p1, p2 ); player.sendToInRangeSet( pSetStatusPacket, false ); break; } case ClientTriggerType::Return: // return dead / accept raise { - switch( static_cast < ResurrectType >( param1 ) ) + switch( static_cast < ResurrectType >( p1 ) ) { case ResurrectType::RaiseSpell: // todo: handle raise case (set position to raiser, apply weakness status, set hp/mp/tp as well as packet) @@ -280,16 +310,16 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX case ClientTriggerType::Teleport: // Teleport { - player.teleportQuery( static_cast< uint16_t >( param11 ) ); + player.teleportQuery( static_cast< uint16_t >( p1 ) ); break; } case ClientTriggerType::DyeItem: // Dye item { - // param11 = item to dye container - // param12 = item to dye slot - // param2 = dye bag container - // param4 = dye bag slot - player.setDyeingInfo( param11, param12, param2, param4 ); + // p1 = item to dye container + // p2 = item to dye slot + // p3 = dye bag container + // p4 = dye bag slot + player.setDyeingInfo( p1, p2, p3, p4 ); break; } case ClientTriggerType::DirectorInitFinish: // Director init finish @@ -315,7 +345,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX } case ClientTriggerType::AbandonQuest: { - player.removeQuest( static_cast< uint16_t >( param1 ) ); + player.removeQuest( static_cast< uint16_t >( p1 ) ); break; } case ClientTriggerType::RequestHousingBuildPreset: @@ -325,9 +355,9 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX if (!hZone) return; - player.setActiveLand( static_cast< uint8_t >( param11 ), hZone->getWardNum() ); + player.setActiveLand( static_cast< uint8_t >( p1 ), hZone->getWardNum() ); - auto pShowBuildPresetUIPacket = makeActorControl( player.getId(), ShowBuildPresetUI, param11 ); + auto pShowBuildPresetUIPacket = makeActorControl( player.getId(), ShowBuildPresetUI, p1 ); player.queuePacket( pShowBuildPresetUIPacket ); break; @@ -336,7 +366,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX { auto& housingMgr = Common::Service< HousingMgr >::ref(); - auto ident = housingMgr.clientTriggerParamsToLandIdent( param11, param12 ); + auto ident = housingMgr.clientTriggerParamsToLandIdent( p1, p2 ); housingMgr.sendLandSignFree( player, ident ); break; @@ -345,7 +375,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX { auto& housingMgr = Common::Service< HousingMgr >::ref(); - auto ident = housingMgr.clientTriggerParamsToLandIdent( param11, param12, false ); + auto ident = housingMgr.clientTriggerParamsToLandIdent( p1, p2, false ); housingMgr.sendLandSignOwned( player, ident ); break; @@ -354,7 +384,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX { auto& housingMgr = Common::Service< HousingMgr >::ref(); - housingMgr.sendWardLandInfo( player, static_cast< uint8_t >( param12 ), static_cast< uint8_t >( param11 ) ); + housingMgr.sendWardLandInfo( player, static_cast< uint8_t >( p2 ), static_cast< uint8_t >( p1 ) ); break; } @@ -362,7 +392,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX { auto& housingMgr = Common::Service< HousingMgr >::ref(); - auto plot = static_cast< uint8_t >( param12 & 0xFF ); + auto plot = static_cast< uint8_t >( p2 & 0xFF ); housingMgr.relinquishLand( player, plot ); break; @@ -371,7 +401,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX { auto& housingMgr = Common::Service< HousingMgr >::ref(); - auto ident = housingMgr.clientTriggerParamsToLandIdent( param11, param12 ); + auto ident = housingMgr.clientTriggerParamsToLandIdent( p1, p2 ); housingMgr.requestEstateRename( player, ident ); break; @@ -380,7 +410,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX { auto& housingMgr = Common::Service< HousingMgr >::ref(); - auto ident = housingMgr.clientTriggerParamsToLandIdent( param11, param12 ); + auto ident = housingMgr.clientTriggerParamsToLandIdent( p1, p2 ); housingMgr.requestEstateEditGreeting( player, ident ); break; @@ -389,7 +419,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX { auto& housingMgr = Common::Service< HousingMgr >::ref(); - auto ident = housingMgr.clientTriggerParamsToLandIdent( param11, param12 ); + auto ident = housingMgr.clientTriggerParamsToLandIdent( p1, p2 ); housingMgr.requestEstateEditGuestAccess( player, ident ); break; @@ -397,13 +427,13 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX case ClientTriggerType::RequestHousingItemUI: { // close ui - if( param11 == 1 ) + if( p1 == 1 ) break; - // param12 is 0 when inside a house + // p2 is 0 when inside a house - uint8_t ward = ( param12 >> 16 ) & 0xFF; - uint8_t plot = ( param12 & 0xFF ); + uint8_t ward = ( p2 >> 16 ) & 0xFF; + uint8_t plot = ( p2 & 0xFF ); auto pShowHousingItemUIPacket = makeActorControl( player.getId(), ShowHousingItemUI, 0, plot ); player.queuePacket( pShowHousingItemUIPacket ); @@ -416,19 +446,19 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX { auto& housingMgr = Common::Service< HousingMgr >::ref(); - auto ident = housingMgr.clientTriggerParamsToLandIdent( param11, param12 ); + auto ident = housingMgr.clientTriggerParamsToLandIdent( p1, p2 ); housingMgr.sendEstateGreeting( player, ident ); break; } case ClientTriggerType::RequestLandInventory: { - uint8_t plot = ( param12 & 0xFF ); + uint8_t plot = ( p2 & 0xFF ); auto& housingMgr = Common::Service< HousingMgr >::ref(); uint16_t inventoryType = Common::InventoryType::HousingExteriorPlacedItems; - if( param2 == 1 ) + if( p3 == 1 ) inventoryType = Common::InventoryType::HousingExteriorStoreroom; housingMgr.sendEstateInventory( player, inventoryType, plot ); @@ -439,10 +469,10 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX { auto& housingMgr = Common::Service< HousingMgr >::ref(); - // param1 = 1 - storeroom - // param1 = 0 - placed items + // p1 = 1 - storeroom + // p1 = 0 - placed items - if( param1 == 1 ) + if( p1 == 1 ) housingMgr.sendInternalEstateInventoryBatch( player, true ); else housingMgr.sendInternalEstateInventoryBatch( player ); @@ -453,11 +483,11 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX { auto& housingMgr = Common::Service< HousingMgr >::ref(); - auto slot = param4 & 0xFF; - auto sendToStoreroom = ( param4 >> 16 ) != 0; + auto slot = p4 & 0xFF; + auto sendToStoreroom = ( p4 >> 16 ) != 0; //player, plot, containerId, slot, sendToStoreroom - housingMgr.reqRemoveHousingItem( player, static_cast< uint16_t >( param12 ), static_cast< uint16_t >( param2 ), static_cast< uint8_t >( slot ), sendToStoreroom ); + housingMgr.reqRemoveHousingItem( player, static_cast< uint16_t >( p2 ), static_cast< uint16_t >( p3 ), static_cast< uint8_t >( slot ), sendToStoreroom ); break; } @@ -465,7 +495,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX { auto& housingMgr = Common::Service< HousingMgr >::ref(); - housingMgr.reqEstateExteriorRemodel( player, static_cast< uint16_t >( param11 ) ); + housingMgr.reqEstateExteriorRemodel( player, static_cast< uint16_t >( p1 ) ); break; } @@ -481,16 +511,16 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX { auto& housingMgr = Common::Service< HousingMgr >::ref(); - housingMgr.removeHouse( player, static_cast< uint16_t >( param11 ) ); + housingMgr.removeHouse( player, static_cast< uint16_t >( p1 ) ); break; } case ClientTriggerType::UpdateEstateGuestAccess: { - auto canTeleport = ( param2 & 0xFF ) == 1; - auto unk1 = ( param2 >> 8 & 0xFF ) == 1; // todo: related to fc? or unused? - auto privateEstateAccess = ( param2 >> 16 & 0xFF ) == 1; - auto unk = ( param2 >> 24 & 0xFF ) == 1; // todo: related to fc? or unused? + auto canTeleport = ( p3 & 0xFF ) == 1; + auto unk1 = ( p3 >> 8 & 0xFF ) == 1; // todo: related to fc? or unused? + auto privateEstateAccess = ( p3 >> 16 & 0xFF ) == 1; + auto unk = ( p3 >> 24 & 0xFF ) == 1; // todo: related to fc? or unused? player.sendDebug( "can teleport: {0}, unk: {1}, privateEstateAccess: {2}, unk: {3}", canTeleport, unk1, privateEstateAccess, unk ); @@ -498,36 +528,34 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX } case ClientTriggerType::RequestEventBattle: { - auto packet = makeActorControlSelf( player.getId(), ActorControl::EventBattleDialog, 0, param12, param2 ); + auto packet = makeActorControlSelf( player.getId(), ActorControl::EventBattleDialog, 0, p2, p3 ); player.queuePacket( packet ); - - 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 ); + player.sendDebug( "cutscene: {}", p1 ); break; } case ClientTriggerType::OpenPerformInstrumentUI: { - //param11 = instrument, 0 = end - player.sendDebug( "perform: {}", param11 ); - if( param11 == 0 ) + //p1 = instrument, 0 = end + player.sendDebug( "perform: {}", p1 ); + if( p1 == 0 ) { player.sendToInRangeSet( makeActorControl( player.getId(), ActorControl::SetStatus, 1, 0, 0, 0 ), true ); player.unsetStateFlag( PlayerStateFlag::Performing ); } else { - player.sendToInRangeSet( makeActorControl( player.getId(), ActorControl::SetStatus, 16, param11, 0, 0 ), true ); + player.sendToInRangeSet( makeActorControl( player.getId(), ActorControl::SetStatus, 16, p1, 0, 0 ), true ); player.setStateFlag( PlayerStateFlag::Performing ); } break; } case ClientTriggerType::CameraMode: { - if( ( param11 & 0xFF ) == 1 ) + if( ( p1 & 0xFF ) == 1 ) { player.setOnlineStatusMask( player.getOnlineStatusMask() | 0x0000000000040000 ); } @@ -537,6 +565,64 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX } break; } + case 0x25E: // coming out from water (no 3.x name) + case 0xD1: // underwater town portal (3.x NEWBIE_TELEPO_INQUIRY) + { + auto p = makeZonePacket< FFXIVIpcPrepareZoning >( player.getId() ); + p->data().targetZone = player.getCurrentTerritory()->getTerritoryTypeId(); + p->data().param4 = commandId == 0xD1 ? 14 : 227; + p->data().hideChar = commandId == 0xD1 ? 2 : 1; + p->data().fadeOut = commandId == 0xD1 ? 24 : 25; + p->data().fadeOutTime = 1; + p->data().unknown = commandId == 0xD1 ? 4 : 6; + auto x = pos.x; + auto y = pos.y; + auto z = pos.z; + auto rot = player.getRot(); + if( commandId == 0xD1 ) + { + auto& instanceObjectCache = Common::Service< InstanceObjectCache >::ref(); + auto exit = instanceObjectCache.getExitRange( p->data().targetZone, p1 ); + if( exit ) + { + player.sendDebug( "exitRange {0} found!", p1 ); + auto destZone = exit->data.destTerritoryType; + if( destZone == 0 ) + destZone = p->data().targetZone; + else + p->data().targetZone = destZone; + auto pop = instanceObjectCache.getPopRange( destZone, exit->data.destInstanceObjectId ); + if( pop ) + { + player.sendDebug( "popRange {0} found!", exit->data.destInstanceObjectId ); + x = pop->header.transform.translation.x; + y = pop->header.transform.translation.y; + z = pop->header.transform.translation.z; + //rot = pop->header.transform.rotation.y; all x/y/z not correct, maybe we don't need it since we have to be facing the portal anyway? + } + else + { + player.sendUrgent( "popRange {0} not found in {1}!", exit->data.destInstanceObjectId, destZone ); + } + } + else + { + player.sendUrgent( "exitRange {0} not found in {1}!", p1, p->data().targetZone ); + } + } + player.queuePacket( p ); + player.setPos( x, y, z, true ); + player.setRot( rot ); + auto setPos = makeZonePacket< FFXIVIpcActorSetPos >( player.getId() ); + setPos->data().r16 = Common::Util::floatToUInt16Rot( player.getRot() ); + setPos->data().x = x; + setPos->data().y = y; + setPos->data().z = z; + setPos->data().waitForLoad = commandId == 0xD1 ? 24 : 25; + setPos->data().unknown1 = 0; + player.queuePacket( setPos ); // this packet needs a delay of 0.8 second to wait for the client finishing its water animation otherwise it looks odd. + break; + } default: { Logger::debug( "[{0}] Unhandled action: {1:04X}", m_pSession->getId(), commandId ); diff --git a/src/world/Network/Handlers/PacketHandlers.cpp b/src/world/Network/Handlers/PacketHandlers.cpp index 68d01fb2..f0a5c5fc 100644 --- a/src/world/Network/Handlers/PacketHandlers.cpp +++ b/src/world/Network/Handlers/PacketHandlers.cpp @@ -805,139 +805,6 @@ void Sapphire::Network::GameConnection::marketBoardRequestItemListings( const Pa marketMgr.requestItemListings( player, packet.data().itemCatalogId ); } -void Sapphire::Network::GameConnection::worldInteractionhandler( const Packets::FFXIVARR_PACKET_RAW& inPacket, - Entity::Player& player ) -{ - const auto packet = ZoneChannelPacket< Client::FFXIVIpcWorldInteractionHandler >( inPacket ); - auto action = packet.data().action; - player.sendDebug( "WorldInteraction {}", action ); - switch( action ) - { - case 0x1F5: // emote - { - auto emote = packet.data().param1; - if( emote == 0x32 || emote == 0x33 ) // "/sit" - { - auto param4 = packet.data().param4; - auto& exdData = Common::Service< Data::ExdDataGenerated >::ref(); - auto emoteData = exdData.get< Data::Emote >( emote ); - - if( !emoteData ) - break; - - player.setPos( packet.data().position ); - player.setRot( Util::floatFromUInt16Rot( param4 ) ); - if( emote == 0x32 && player.hasInRangeActor() ) - { - auto setpos = makeZonePacket< FFXIVIpcActorSetPos >( player.getId() ); - setpos->data().r16 = param4; - setpos->data().waitForLoad = 18; - setpos->data().x = packet.data().position.x; - setpos->data().y = packet.data().position.y; - setpos->data().z = packet.data().position.z; - player.sendToInRangeSet( setpos, false ); - } - player.sendToInRangeSet( makeActorControlTarget( player.getId(), ActorControl::ActorControlType::Emote, emote, 0, 0, param4, 0xE0000000 ), true ); - - if( emote == 0x32 && emoteData->emoteMode != 0 ) - { - player.setStance( Common::Stance::Passive ); - player.setAutoattack( false ); - player.setPersistentEmote( emoteData->emoteMode ); - player.setStatus( Common::ActorStatus::EmoteMode ); - } - } - break; - } - case 0x1F8: - { - if( player.getPersistentEmote() > 0 ) - { - auto param2 = packet.data().param2; - - player.setPos( packet.data().position ); - if( player.hasInRangeActor() ) - { - auto setpos = makeZonePacket< FFXIVIpcActorSetPos >( player.getId() ); - setpos->data().r16 = param2; - setpos->data().waitForLoad = 18; - setpos->data().x = packet.data().position.x; - setpos->data().y = packet.data().position.y; - setpos->data().z = packet.data().position.z; - player.sendToInRangeSet( setpos, false ); - } - - player.setPersistentEmote( 0 ); - player.emoteInterrupt(); - player.setStatus( Common::ActorStatus::Idle ); - auto pSetStatusPacket = makeActorControl( player.getId(), SetStatus, static_cast< uint8_t >( Common::ActorStatus::Idle ) ); - player.sendToInRangeSet( pSetStatusPacket ); - } - break; - } - case 0x25E: // coming out from water - case 0xD1: // underwater town portal - { - auto p = makeZonePacket< FFXIVIpcPrepareZoning >( player.getId() ); - p->data().targetZone = player.getCurrentTerritory()->getTerritoryTypeId(); - p->data().param4 = action == 0xD1 ? 14 : 227; - p->data().hideChar = action == 0xD1 ? 2 : 1; - p->data().fadeOut = action == 0xD1 ? 24 : 25; - p->data().fadeOutTime = 1; - p->data().unknown = action == 0xD1 ? 4 : 6; - auto x = packet.data().position.x; - auto y = packet.data().position.y; - auto z = packet.data().position.z; - auto rot = player.getRot(); - if( action == 0xD1 ) - { - auto exitRange = packet.data().param1; - - auto& instanceObjectCache = Common::Service< InstanceObjectCache >::ref(); - auto exit = instanceObjectCache.getExitRange( p->data().targetZone, exitRange ); - if( exit ) - { - player.sendDebug( "exitRange {0} found!", exitRange ); - auto destZone = exit->data.destTerritoryType; - if( destZone == 0 ) - destZone = p->data().targetZone; - else - p->data().targetZone = destZone; - auto pop = instanceObjectCache.getPopRange( destZone, exit->data.destInstanceObjectId ); - if( pop ) - { - player.sendDebug( "popRange {0} found!", exit->data.destInstanceObjectId ); - x = pop->header.transform.translation.x; - y = pop->header.transform.translation.y; - z = pop->header.transform.translation.z; - //rot = pop->header.transform.rotation.y; all x/y/z not correct, maybe we don't need it since we have to be facing the portal anyway? - } - else - { - player.sendUrgent( "popRange {0} not found in {1}!", exit->data.destInstanceObjectId, destZone ); - } - } - else - { - player.sendUrgent( "exitRange {0} not found in {1}!", exitRange, p->data().targetZone ); - } - } - player.queuePacket( p ); - player.setPos( x, y, z, true ); - player.setRot( rot ); - auto setPos = makeZonePacket< FFXIVIpcActorSetPos >( player.getId() ); - setPos->data().r16 = Common::Util::floatToUInt16Rot( player.getRot() ); - setPos->data().x = x; - setPos->data().y = y; - setPos->data().z = z; - setPos->data().waitForLoad = action == 0xD1 ? 24 : 25; - setPos->data().unknown1 = 0; - player.queuePacket( setPos ); // this packet needs a delay of 0.8 second to wait for the client finishing its water animation otherwise it looks odd. - break; - } - } -} - void Sapphire::Network::GameConnection::diveHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player ) { const auto packetIn = ZoneChannelPacket< Client::FFXIVIpcDive >( inPacket );