mirror of
https://github.com/redstrate/Kawari.git
synced 2025-04-25 16:27:46 +00:00
Send ActorControl and StatusEffectList packets in vain
This was hopefully supposed to show the player spawned by !spawnactor, but it still doesn't work...
This commit is contained in:
parent
da0860cdd7
commit
4927fa9119
8 changed files with 126 additions and 27 deletions
|
@ -7,7 +7,7 @@ use kawari::world::ipc::{
|
||||||
use kawari::world::{
|
use kawari::world::{
|
||||||
ChatHandler, Zone, ZoneConnection,
|
ChatHandler, Zone, ZoneConnection,
|
||||||
ipc::{
|
ipc::{
|
||||||
ActorControlSelf, ActorControlType, PlayerEntry, PlayerSetup, PlayerSpawn, PlayerStats,
|
ActorControlCategory, ActorControlSelf, PlayerEntry, PlayerSetup, PlayerSpawn, PlayerStats,
|
||||||
Position, SocialList,
|
Position, SocialList,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -171,7 +171,7 @@ async fn main() {
|
||||||
data: ServerZoneIpcData::ActorControlSelf(
|
data: ServerZoneIpcData::ActorControlSelf(
|
||||||
ActorControlSelf {
|
ActorControlSelf {
|
||||||
category:
|
category:
|
||||||
ActorControlType::SetCharaGearParamUI,
|
ActorControlCategory::SetCharaGearParamUI,
|
||||||
param1: 1,
|
param1: 1,
|
||||||
param2: 1,
|
param2: 1,
|
||||||
param3: 0,
|
param3: 0,
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
CHAR_NAME, CUSTOMIZE_DATA, INVALID_OBJECT_ID, WORLD_ID,
|
CHAR_NAME, CUSTOMIZE_DATA, INVALID_OBJECT_ID, WORLD_ID,
|
||||||
common::timestamp_secs,
|
common::timestamp_secs,
|
||||||
packet::{PacketSegment, SegmentType},
|
packet::{PacketSegment, SegmentType},
|
||||||
world::ipc::{
|
world::ipc::{
|
||||||
CommonSpawn, NpcSpawn, ObjectKind, PlayerSpawn, ServerZoneIpcData, ServerZoneIpcSegment,
|
ActorControl, ActorControlCategory, CommonSpawn, NpcSpawn, ObjectKind, PlayerSpawn,
|
||||||
ServerZoneIpcType,
|
ServerZoneIpcData, ServerZoneIpcSegment, ServerZoneIpcType, StatusEffectList,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,6 +38,35 @@ impl ChatHandler {
|
||||||
"!spawnactor" => {
|
"!spawnactor" => {
|
||||||
tracing::info!("Spawning actor...");
|
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_id,
|
||||||
|
segment_type: SegmentType::Ipc { data: ipc },
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
// send player spawn
|
// send player spawn
|
||||||
{
|
{
|
||||||
let ipc = ServerZoneIpcSegment {
|
let ipc = ServerZoneIpcSegment {
|
||||||
|
@ -63,6 +93,7 @@ impl ChatHandler {
|
||||||
spawn_index: connection.get_free_spawn_index(),
|
spawn_index: connection.get_free_spawn_index(),
|
||||||
look: CUSTOMIZE_DATA,
|
look: CUSTOMIZE_DATA,
|
||||||
fc_tag: "LOCAL".to_string(),
|
fc_tag: "LOCAL".to_string(),
|
||||||
|
subtype: 4,
|
||||||
models: [
|
models: [
|
||||||
0, // head
|
0, // head
|
||||||
89, // body
|
89, // body
|
||||||
|
@ -90,6 +121,29 @@ impl ChatHandler {
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// zone in
|
||||||
|
{
|
||||||
|
let ipc = ServerZoneIpcSegment {
|
||||||
|
unk1: 20,
|
||||||
|
unk2: 0,
|
||||||
|
op_code: ServerZoneIpcType::ActorControl,
|
||||||
|
server_id: 0,
|
||||||
|
timestamp: timestamp_secs(),
|
||||||
|
data: ServerZoneIpcData::ActorControl(ActorControl {
|
||||||
|
category: ActorControlCategory::ZoneIn,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
connection
|
||||||
|
.send_segment(PacketSegment {
|
||||||
|
source_actor: 0x106ad804,
|
||||||
|
target_actor: connection.player_id,
|
||||||
|
segment_type: SegmentType::Ipc { data: ipc },
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"!spawnnpc" => {
|
"!spawnnpc" => {
|
||||||
// spawn another one of us
|
// spawn another one of us
|
||||||
|
|
23
src/world/ipc/actor_control.rs
Normal file
23
src/world/ipc/actor_control.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
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)]
|
||||||
|
pub enum ActorControlCategory {
|
||||||
|
#[default]
|
||||||
|
ZoneIn = 0xC8,
|
||||||
|
SetCharaGearParamUI = 0x260,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[binrw]
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct ActorControl {
|
||||||
|
#[brw(pad_after = 2)]
|
||||||
|
pub category: ActorControlCategory,
|
||||||
|
pub param1: u32,
|
||||||
|
pub param2: u32,
|
||||||
|
pub param3: u32,
|
||||||
|
#[brw(pad_after = 4)] // maybe not always empty?
|
||||||
|
pub param4: u32,
|
||||||
|
}
|
|
@ -1,18 +1,12 @@
|
||||||
use binrw::binrw;
|
use binrw::binrw;
|
||||||
|
|
||||||
#[binrw]
|
use super::ActorControlCategory;
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Default)]
|
|
||||||
#[brw(repr = u16)]
|
|
||||||
pub enum ActorControlType {
|
|
||||||
#[default]
|
|
||||||
SetCharaGearParamUI = 0x260,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct ActorControlSelf {
|
pub struct ActorControlSelf {
|
||||||
#[brw(pad_after = 2)]
|
#[brw(pad_after = 2)]
|
||||||
pub category: ActorControlType,
|
pub category: ActorControlCategory,
|
||||||
pub param1: u32,
|
pub param1: u32,
|
||||||
pub param2: u32,
|
pub param2: u32,
|
||||||
pub param3: u32,
|
pub param3: u32,
|
||||||
|
|
|
@ -28,7 +28,9 @@ pub use player_stats::PlayerStats;
|
||||||
|
|
||||||
mod actor_control_self;
|
mod actor_control_self;
|
||||||
pub use actor_control_self::ActorControlSelf;
|
pub use actor_control_self::ActorControlSelf;
|
||||||
pub use actor_control_self::ActorControlType;
|
|
||||||
|
mod actor_control;
|
||||||
|
pub use actor_control::{ActorControl, ActorControlCategory};
|
||||||
|
|
||||||
mod init_zone;
|
mod init_zone;
|
||||||
pub use init_zone::InitZone;
|
pub use init_zone::InitZone;
|
||||||
|
@ -39,6 +41,9 @@ pub use npc_spawn::NpcSpawn;
|
||||||
mod common_spawn;
|
mod common_spawn;
|
||||||
pub use common_spawn::{CharacterMode, CommonSpawn, ObjectKind};
|
pub use common_spawn::{CharacterMode, CommonSpawn, ObjectKind};
|
||||||
|
|
||||||
|
mod status_effect_list;
|
||||||
|
pub use status_effect_list::StatusEffectList;
|
||||||
|
|
||||||
use crate::common::read_string;
|
use crate::common::read_string;
|
||||||
use crate::common::write_string;
|
use crate::common::write_string;
|
||||||
use crate::packet::IpcSegment;
|
use crate::packet::IpcSegment;
|
||||||
|
@ -92,6 +97,7 @@ impl ReadWriteIpcSegment for ServerZoneIpcSegment {
|
||||||
ServerZoneIpcType::SocialList => 1136,
|
ServerZoneIpcType::SocialList => 1136,
|
||||||
ServerZoneIpcType::PrepareZoning => 16,
|
ServerZoneIpcType::PrepareZoning => 16,
|
||||||
ServerZoneIpcType::NpcSpawn => 648,
|
ServerZoneIpcType::NpcSpawn => 648,
|
||||||
|
ServerZoneIpcType::StatusEffectList => 384,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,7 +177,7 @@ pub enum ServerZoneIpcType {
|
||||||
// Sent by the server before init zone???
|
// Sent by the server before init zone???
|
||||||
Unk16 = 0x3AB,
|
Unk16 = 0x3AB,
|
||||||
// Sent by the server
|
// Sent by the server
|
||||||
ActorControl = 0x1B9,
|
ActorControl = 0x38E,
|
||||||
// Sent by the server
|
// Sent by the server
|
||||||
ActorMove = 0x3D8,
|
ActorMove = 0x3D8,
|
||||||
// Sent by the server
|
// Sent by the server
|
||||||
|
@ -180,6 +186,8 @@ pub enum ServerZoneIpcType {
|
||||||
SocialList = 0x36C,
|
SocialList = 0x36C,
|
||||||
// Sent by the server to spawn an NPC
|
// Sent by the server to spawn an NPC
|
||||||
NpcSpawn = 0x100,
|
NpcSpawn = 0x100,
|
||||||
|
// Sent by the server to update an actor's status effect list
|
||||||
|
StatusEffectList = 0xBB,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
|
@ -283,10 +291,7 @@ pub enum ServerZoneIpcData {
|
||||||
Unk16 {
|
Unk16 {
|
||||||
unk: [u8; 136],
|
unk: [u8; 136],
|
||||||
},
|
},
|
||||||
ActorControl {
|
ActorControl(ActorControl),
|
||||||
#[brw(pad_after = 20)] // empty
|
|
||||||
unk: u32,
|
|
||||||
},
|
|
||||||
ActorMove {
|
ActorMove {
|
||||||
#[brw(pad_after = 4)] // empty
|
#[brw(pad_after = 4)] // empty
|
||||||
pos: Position,
|
pos: Position,
|
||||||
|
@ -296,6 +301,7 @@ pub enum ServerZoneIpcData {
|
||||||
},
|
},
|
||||||
SocialList(SocialList),
|
SocialList(SocialList),
|
||||||
NpcSpawn(NpcSpawn),
|
NpcSpawn(NpcSpawn),
|
||||||
|
StatusEffectList(StatusEffectList),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
|
@ -442,6 +448,14 @@ mod tests {
|
||||||
ServerZoneIpcType::NpcSpawn,
|
ServerZoneIpcType::NpcSpawn,
|
||||||
ServerZoneIpcData::NpcSpawn(NpcSpawn::default()),
|
ServerZoneIpcData::NpcSpawn(NpcSpawn::default()),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
ServerZoneIpcType::ActorControl,
|
||||||
|
ServerZoneIpcData::ActorControl(ActorControl::default()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ServerZoneIpcType::StatusEffectList,
|
||||||
|
ServerZoneIpcData::StatusEffectList(StatusEffectList::default()),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (opcode, data) in &ipc_types {
|
for (opcode, data) in &ipc_types {
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
use binrw::binrw;
|
use binrw::binrw;
|
||||||
|
|
||||||
use crate::CHAR_NAME_MAX_LENGTH;
|
|
||||||
use crate::common::{CustomizeData, read_string, write_string};
|
|
||||||
|
|
||||||
use super::position::Position;
|
use super::CommonSpawn;
|
||||||
use super::{CharacterMode, CommonSpawn, ObjectKind, StatusEffect};
|
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
#[brw(little)]
|
#[brw(little)]
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
use binrw::binrw;
|
use binrw::binrw;
|
||||||
|
|
||||||
use crate::CHAR_NAME_MAX_LENGTH;
|
|
||||||
use crate::common::{CustomizeData, read_string, write_string};
|
|
||||||
|
|
||||||
use super::position::Position;
|
use super::CommonSpawn;
|
||||||
use super::status_effect::StatusEffect;
|
|
||||||
use super::{CommonSpawn, ObjectKind};
|
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
#[brw(little)]
|
#[brw(little)]
|
||||||
|
@ -63,5 +59,6 @@ mod tests {
|
||||||
assert_eq!(player_spawn.common.subtype, 4);
|
assert_eq!(player_spawn.common.subtype, 4);
|
||||||
assert_eq!(player_spawn.common.model_chara, 0);
|
assert_eq!(player_spawn.common.model_chara, 0);
|
||||||
assert_eq!(player_spawn.common.object_kind, ObjectKind::Player);
|
assert_eq!(player_spawn.common.object_kind, ObjectKind::Player);
|
||||||
|
assert_eq!(player_spawn.common.display_flags, 262144);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
20
src/world/ipc/status_effect_list.rs
Normal file
20
src/world/ipc/status_effect_list.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
use binrw::binrw;
|
||||||
|
|
||||||
|
use super::StatusEffect;
|
||||||
|
|
||||||
|
#[binrw]
|
||||||
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
pub struct StatusEffectList {
|
||||||
|
pub classjob_id: u8,
|
||||||
|
pub level: u8,
|
||||||
|
pub unk1: u8,
|
||||||
|
pub unk2: u8,
|
||||||
|
pub curr_hp: u32,
|
||||||
|
pub max_hp: u32,
|
||||||
|
pub curr_mp: u16,
|
||||||
|
pub max_mp: u16,
|
||||||
|
pub shield: u16,
|
||||||
|
pub unk3: u16,
|
||||||
|
pub statues: [StatusEffect; 30],
|
||||||
|
pub unk4: u32,
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue