1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-27 06:47:45 +00:00

remove WorldInteractionHandler as it turns out it's just another ClientTrigger.

handler merged and values used by WorldInteractionHandler fit perfectly in ClientTriggerType(name picked up from 3.x).
also update the packet and rename params to be more consistent
This commit is contained in:
collett 2024-06-17 02:14:12 +09:00
parent 24fb38c40e
commit 06d6f4db30
8 changed files with 189 additions and 248 deletions

View file

@ -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

View file

@ -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
};

View file

@ -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 >
{

View file

@ -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()

View file

@ -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();

View file

@ -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 );

View file

@ -8,8 +8,12 @@
#include <Network/PacketDef/Zone/ClientZoneDef.h>
#include <Util/Util.h>
#include <datReader/DatCategories/bg/LgbTypes.h>
#include <datReader/DatCategories/bg/lgb.h>
#include "Territory/Territory.h"
#include "Territory/ZonePosition.h"
#include <Territory/InstanceObjectCache.h>
#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 );

View file

@ -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 );