mirror of
https://github.com/redstrate/Kawari.git
synced 2025-04-24 08:07:45 +00:00
ActorControl and ActorMove packet fixes, add support for //gm invis
I don't think this is the right kind of invisibility, but it's more of a test of ActorControlSelf really. I have also been trying (and failing) to make the client show another player.
This commit is contained in:
parent
d47779c8d6
commit
90a78fcaa8
6 changed files with 133 additions and 79 deletions
|
@ -11,13 +11,15 @@ use kawari::packet::{
|
|||
send_packet,
|
||||
};
|
||||
use kawari::world::ipc::{
|
||||
ClientZoneIpcData, CommonSpawn, DisplayFlag, GameMasterCommandType, GameMasterRank, ObjectKind, OnlineStatus, PlayerSubKind, ServerZoneIpcData, ServerZoneIpcSegment, ServerZoneIpcType, SocialListRequestType, StatusEffect
|
||||
ClientZoneIpcData, CommonSpawn, DisplayFlag, GameMasterCommandType, GameMasterRank, ObjectKind,
|
||||
OnlineStatus, PlayerSubKind, ServerZoneIpcData, ServerZoneIpcSegment, ServerZoneIpcType,
|
||||
SocialListRequestType, StatusEffect,
|
||||
};
|
||||
use kawari::world::{
|
||||
ChatHandler, Zone, ZoneConnection,
|
||||
ipc::{
|
||||
ActorControlCategory, ActorControlSelf, PlayerEntry, PlayerSetup, PlayerSpawn, PlayerStats,
|
||||
SocialList,
|
||||
ActorControl, ActorControlCategory, ActorControlSelf, PlayerEntry, PlayerSetup,
|
||||
PlayerSpawn, PlayerStats, SocialList,
|
||||
},
|
||||
};
|
||||
use kawari::world::{PlayerData, WorldDatabase};
|
||||
|
@ -194,13 +196,10 @@ async fn main() {
|
|||
data: ServerZoneIpcData::ActorControlSelf(
|
||||
ActorControlSelf {
|
||||
category:
|
||||
ActorControlCategory::SetCharaGearParamUI,
|
||||
param1: 1,
|
||||
param2: 1,
|
||||
param3: 0,
|
||||
param4: 0,
|
||||
param5: 0,
|
||||
param6: 0,
|
||||
ActorControlCategory::SetCharaGearParamUI {
|
||||
unk1: 1,
|
||||
unk2: 1,
|
||||
}
|
||||
},
|
||||
),
|
||||
..Default::default()
|
||||
|
@ -571,6 +570,38 @@ async fn main() {
|
|||
GameMasterCommandType::ChangeTerritory => {
|
||||
connection.change_zone(*arg as u16).await
|
||||
}
|
||||
GameMasterCommandType::ToggleInvisibility => {
|
||||
// Control Data
|
||||
{
|
||||
let ipc = ServerZoneIpcSegment {
|
||||
op_code: ServerZoneIpcType::ActorControlSelf,
|
||||
timestamp: timestamp_secs(),
|
||||
data: ServerZoneIpcData::ActorControlSelf(
|
||||
ActorControlSelf {
|
||||
category:
|
||||
ActorControlCategory::ToggleInvisibility {
|
||||
invisible: 1
|
||||
},
|
||||
},
|
||||
),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
connection
|
||||
.send_segment(PacketSegment {
|
||||
source_actor: connection
|
||||
.player_data
|
||||
.actor_id,
|
||||
target_actor: connection
|
||||
.player_data
|
||||
.actor_id,
|
||||
segment_type: SegmentType::Ipc {
|
||||
data: ipc,
|
||||
},
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ClientZoneIpcData::Unk12 { .. } => {
|
||||
|
|
|
@ -3,9 +3,9 @@ use crate::{
|
|||
config::get_config,
|
||||
packet::{PacketSegment, SegmentType},
|
||||
world::ipc::{
|
||||
ActorControl, ActorControlCategory, BattleNpcSubKind, CommonSpawn, NpcSpawn, ObjectKind,
|
||||
PlayerSpawn, PlayerSubKind, ServerZoneIpcData, ServerZoneIpcSegment, ServerZoneIpcType,
|
||||
StatusEffectList,
|
||||
ActorControl, ActorControlCategory, BattleNpcSubKind, CommonSpawn, DisplayFlag, NpcSpawn,
|
||||
ObjectKind, PlayerSpawn, PlayerSubKind, ServerZoneIpcData, ServerZoneIpcSegment,
|
||||
ServerZoneIpcType, StatusEffectList,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -64,35 +64,6 @@ impl ChatHandler {
|
|||
"!spawnactor" => {
|
||||
tracing::info!("Spawning actor...");
|
||||
|
||||
// status effect
|
||||
{
|
||||
let ipc = ServerZoneIpcSegment {
|
||||
unk1: 20,
|
||||
unk2: 0,
|
||||
op_code: ServerZoneIpcType::StatusEffectList,
|
||||
server_id: 0,
|
||||
timestamp: timestamp_secs(),
|
||||
data: ServerZoneIpcData::StatusEffectList(StatusEffectList {
|
||||
classjob_id: 3,
|
||||
level: 10,
|
||||
unk1: 10,
|
||||
curr_hp: 241,
|
||||
max_hp: 241,
|
||||
curr_mp: 10000,
|
||||
max_mp: 10000,
|
||||
..Default::default()
|
||||
}),
|
||||
};
|
||||
|
||||
connection
|
||||
.send_segment(PacketSegment {
|
||||
source_actor: 0x106ad804,
|
||||
target_actor: connection.player_data.actor_id,
|
||||
segment_type: SegmentType::Ipc { data: ipc },
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
let config = get_config();
|
||||
|
||||
// send player spawn
|
||||
|
@ -104,8 +75,8 @@ impl ChatHandler {
|
|||
server_id: 0,
|
||||
timestamp: timestamp_secs(),
|
||||
data: ServerZoneIpcData::PlayerSpawn(PlayerSpawn {
|
||||
account_id: 1,
|
||||
content_id: 1,
|
||||
account_id: 1000000,
|
||||
content_id: 1000000,
|
||||
current_world_id: config.world.world_id,
|
||||
home_world_id: config.world.world_id,
|
||||
common: CommonSpawn {
|
||||
|
@ -120,6 +91,9 @@ impl ChatHandler {
|
|||
spawn_index: connection.get_free_spawn_index(),
|
||||
look: CUSTOMIZE_DATA,
|
||||
fc_tag: "LOCAL".to_string(),
|
||||
display_flags: DisplayFlag::INVISIBLE
|
||||
| DisplayFlag::HIDE_HEAD
|
||||
| DisplayFlag::UNK,
|
||||
models: [
|
||||
0, // head
|
||||
89, // body
|
||||
|
@ -157,7 +131,10 @@ impl ChatHandler {
|
|||
server_id: 0,
|
||||
timestamp: timestamp_secs(),
|
||||
data: ServerZoneIpcData::ActorControl(ActorControl {
|
||||
category: ActorControlCategory::ZoneIn,
|
||||
category: ActorControlCategory::ZoneIn {
|
||||
warp_finish_anim: 0x0,
|
||||
raise_anim: 0x0,
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
};
|
||||
|
@ -170,6 +147,32 @@ impl ChatHandler {
|
|||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
// move
|
||||
{
|
||||
let ipc = ServerZoneIpcSegment {
|
||||
unk1: 20,
|
||||
unk2: 0,
|
||||
op_code: ServerZoneIpcType::ActorMove,
|
||||
server_id: 0,
|
||||
timestamp: timestamp_secs(),
|
||||
data: ServerZoneIpcData::ActorMove {
|
||||
pos: Position {
|
||||
x: 1.0,
|
||||
y: 0.0,
|
||||
z: 1.0,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
connection
|
||||
.send_segment(PacketSegment {
|
||||
source_actor: 0x106ad804,
|
||||
target_actor: connection.player_data.actor_id,
|
||||
segment_type: SegmentType::Ipc { data: ipc },
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
"!spawnnpc" => {
|
||||
// spawn another one of us
|
||||
|
|
|
@ -2,22 +2,56 @@ use binrw::binrw;
|
|||
|
||||
// See https://github.com/awgil/ffxiv_reverse/blob/f35b6226c1478234ca2b7149f82d251cffca2f56/vnetlog/vnetlog/ServerIPC.cs#L266 for a REALLY useful list of known values
|
||||
#[binrw]
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default)]
|
||||
#[brw(repr = u16)]
|
||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||
pub enum ActorControlCategory {
|
||||
#[default]
|
||||
ZoneIn = 0xC8,
|
||||
SetCharaGearParamUI = 0x260,
|
||||
#[brw(magic = 0x26u16)]
|
||||
ToggleInvisibility {
|
||||
#[brw(pad_before = 2)]
|
||||
invisible: u32, // FIXME: change to bool
|
||||
},
|
||||
#[brw(magic = 0xC8u16)]
|
||||
ZoneIn {
|
||||
#[brw(pad_before = 2)]
|
||||
warp_finish_anim: u32,
|
||||
raise_anim: u32,
|
||||
},
|
||||
#[brw(magic = 0x260u16)]
|
||||
SetCharaGearParamUI {
|
||||
#[brw(pad_before = 2)]
|
||||
unk1: u32,
|
||||
unk2: u32,
|
||||
},
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ActorControl {
|
||||
#[brw(pad_after = 2)]
|
||||
#[brw(pad_after = 4)]
|
||||
#[brw(pad_size_to = 20)] // take into account categories without params
|
||||
pub category: ActorControlCategory,
|
||||
pub param1: u32,
|
||||
pub param2: u32,
|
||||
pub param3: u32,
|
||||
#[brw(pad_after = 4)] // maybe not always empty?
|
||||
pub param4: u32,
|
||||
}
|
||||
|
||||
impl Default for ActorControl {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
category: ActorControlCategory::ToggleInvisibility { invisible: 1 },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Has more padding than ActorControl?
|
||||
#[binrw]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ActorControlSelf {
|
||||
#[brw(pad_after = 12)]
|
||||
#[brw(pad_size_to = 20)] // take into account categories without params
|
||||
pub category: ActorControlCategory,
|
||||
}
|
||||
|
||||
impl Default for ActorControlSelf {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
category: ActorControlCategory::ToggleInvisibility { invisible: 1 },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
use binrw::binrw;
|
||||
|
||||
use super::ActorControlCategory;
|
||||
|
||||
#[binrw]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ActorControlSelf {
|
||||
#[brw(pad_after = 2)]
|
||||
pub category: ActorControlCategory,
|
||||
pub param1: u32,
|
||||
pub param2: u32,
|
||||
pub param3: u32,
|
||||
pub param4: u32,
|
||||
pub param5: u32,
|
||||
#[brw(pad_after = 4)]
|
||||
pub param6: u32,
|
||||
}
|
|
@ -93,6 +93,7 @@ pub enum OnlineStatus {
|
|||
GameMaster = 2,
|
||||
GameMasterBlue = 3,
|
||||
EventParticipant = 4,
|
||||
NewAdventurer = 32, // TODO: This is actually a flag!
|
||||
#[default]
|
||||
Online = 47,
|
||||
}
|
||||
|
|
|
@ -23,11 +23,8 @@ pub use player_setup::PlayerSetup;
|
|||
mod player_stats;
|
||||
pub use player_stats::PlayerStats;
|
||||
|
||||
mod actor_control_self;
|
||||
pub use actor_control_self::ActorControlSelf;
|
||||
|
||||
mod actor_control;
|
||||
pub use actor_control::{ActorControl, ActorControlCategory};
|
||||
pub use actor_control::{ActorControl, ActorControlCategory, ActorControlSelf};
|
||||
|
||||
mod init_zone;
|
||||
pub use init_zone::InitZone;
|
||||
|
@ -138,6 +135,7 @@ pub struct ActorSetPos {
|
|||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum GameMasterCommandType {
|
||||
ChangeWeather = 0x6,
|
||||
ToggleInvisibility = 0xD,
|
||||
ChangeTerritory = 0x58,
|
||||
}
|
||||
|
||||
|
@ -184,7 +182,7 @@ pub enum ServerZoneIpcType {
|
|||
// Sent by the server
|
||||
ActorControl = 0x38E,
|
||||
// Sent by the server
|
||||
ActorMove = 0x3D8,
|
||||
ActorMove = 0x31C,
|
||||
// Sent by the server
|
||||
Unk17 = 0x2A1,
|
||||
// Sent by the server in response to SocialListRequest
|
||||
|
@ -475,6 +473,10 @@ mod tests {
|
|||
ServerZoneIpcType::WeatherChange,
|
||||
ServerZoneIpcData::WeatherChange(WeatherChange::default()),
|
||||
),
|
||||
(
|
||||
ServerZoneIpcType::ActorControl,
|
||||
ServerZoneIpcData::ActorControl(ActorControl::default()),
|
||||
),
|
||||
];
|
||||
|
||||
for (opcode, data) in &ipc_types {
|
||||
|
|
Loading…
Add table
Reference in a new issue