mirror of
https://github.com/redstrate/Kawari.git
synced 2025-04-27 08:57:45 +00:00
More CommonSpawn, PlayerSpawn and NPCSpawn struct improvements
This is just a barrage of random stuff I needed to fix, along with finally figuring out what subkinds are.
This commit is contained in:
parent
45f92e9e54
commit
37dbef99db
6 changed files with 134 additions and 69 deletions
|
@ -12,7 +12,7 @@ use kawari::packet::{
|
|||
};
|
||||
use kawari::world::ipc::{
|
||||
ClientZoneIpcData, CommonSpawn, GameMasterCommandType, GameMasterRank, ObjectKind,
|
||||
OnlineStatus, ServerZoneIpcData, ServerZoneIpcSegment, ServerZoneIpcType,
|
||||
OnlineStatus, PlayerSubKind, ServerZoneIpcData, ServerZoneIpcSegment, ServerZoneIpcType,
|
||||
SocialListRequestType, StatusEffect,
|
||||
};
|
||||
use kawari::world::{
|
||||
|
@ -326,22 +326,24 @@ async fn main() {
|
|||
op_code: ServerZoneIpcType::PlayerSpawn,
|
||||
timestamp: timestamp_secs(),
|
||||
data: ServerZoneIpcData::PlayerSpawn(PlayerSpawn {
|
||||
account_id: connection.player_data.account_id,
|
||||
content_id: connection.player_data.content_id,
|
||||
current_world_id: config.world.world_id,
|
||||
home_world_id: config.world.world_id,
|
||||
gm_rank: GameMasterRank::Debug,
|
||||
online_status: OnlineStatus::GameMasterBlue,
|
||||
common: CommonSpawn {
|
||||
current_world_id: config.world.world_id,
|
||||
home_world_id: config.world.world_id,
|
||||
class_job: 35,
|
||||
name: chara_details.name,
|
||||
hp_curr: 100,
|
||||
hp_max: 100,
|
||||
mp_curr: 100,
|
||||
mp_max: 100,
|
||||
object_kind: ObjectKind::Player,
|
||||
gm_rank: GameMasterRank::Debug,
|
||||
online_status: OnlineStatus::GameMasterBlue,
|
||||
object_kind: ObjectKind::Player(
|
||||
PlayerSubKind::Player,
|
||||
),
|
||||
look: chara_details.chara_make.customize,
|
||||
fc_tag: "LOCAL".to_string(),
|
||||
subtype: 4,
|
||||
models: [
|
||||
0, // head
|
||||
89, // body
|
||||
|
|
|
@ -3,8 +3,9 @@ use crate::{
|
|||
config::get_config,
|
||||
packet::{PacketSegment, SegmentType},
|
||||
world::ipc::{
|
||||
ActorControl, ActorControlCategory, CommonSpawn, NpcSpawn, ObjectKind, PlayerSpawn,
|
||||
ServerZoneIpcData, ServerZoneIpcSegment, ServerZoneIpcType, StatusEffectList,
|
||||
ActorControl, ActorControlCategory, BattleNpcSubKind, CommonSpawn, NpcSpawn, ObjectKind,
|
||||
PlayerSpawn, PlayerSubKind, ServerZoneIpcData, ServerZoneIpcSegment, ServerZoneIpcType,
|
||||
StatusEffectList,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -103,22 +104,21 @@ impl ChatHandler {
|
|||
server_id: 0,
|
||||
timestamp: timestamp_secs(),
|
||||
data: ServerZoneIpcData::PlayerSpawn(PlayerSpawn {
|
||||
some_unique_id: 1,
|
||||
account_id: 1,
|
||||
content_id: 1,
|
||||
current_world_id: config.world.world_id,
|
||||
home_world_id: config.world.world_id,
|
||||
common: CommonSpawn {
|
||||
current_world_id: config.world.world_id,
|
||||
home_world_id: config.world.world_id,
|
||||
class_job: 35,
|
||||
name: "Test Actor".to_string(),
|
||||
hp_curr: 100,
|
||||
hp_max: 100,
|
||||
mp_curr: 100,
|
||||
mp_max: 100,
|
||||
object_kind: ObjectKind::Player,
|
||||
object_kind: ObjectKind::Player(PlayerSubKind::Player),
|
||||
spawn_index: connection.get_free_spawn_index(),
|
||||
look: CUSTOMIZE_DATA,
|
||||
fc_tag: "LOCAL".to_string(),
|
||||
subtype: 4,
|
||||
models: [
|
||||
0, // head
|
||||
89, // body
|
||||
|
@ -189,7 +189,7 @@ impl ChatHandler {
|
|||
spawn_index: connection.get_free_spawn_index(),
|
||||
bnpc_base: 13498,
|
||||
bnpc_name: 10261,
|
||||
object_kind: ObjectKind::BattleNpc,
|
||||
object_kind: ObjectKind::BattleNpc(BattleNpcSubKind::Enemy),
|
||||
target_id: ObjectTypeId {
|
||||
object_id: ObjectId(connection.player_data.actor_id),
|
||||
object_type: 0,
|
||||
|
@ -233,6 +233,7 @@ impl ChatHandler {
|
|||
server_id: 0,
|
||||
timestamp: timestamp_secs(),
|
||||
data: ServerZoneIpcData::NpcSpawn(NpcSpawn {
|
||||
aggression_mode: 1,
|
||||
common: CommonSpawn {
|
||||
hp_curr: 91,
|
||||
hp_max: 91,
|
||||
|
@ -241,7 +242,7 @@ impl ChatHandler {
|
|||
spawn_index: connection.get_free_spawn_index(),
|
||||
bnpc_base: 13498, // TODO: changing this prevents it from spawning...
|
||||
bnpc_name: 405,
|
||||
object_kind: ObjectKind::BattleNpc,
|
||||
object_kind: ObjectKind::BattleNpc(BattleNpcSubKind::Enemy),
|
||||
level: 1,
|
||||
battalion: 4,
|
||||
model_chara: 297,
|
||||
|
|
|
@ -10,25 +10,63 @@ use super::StatusEffect;
|
|||
#[binrw]
|
||||
#[brw(repr = u8)]
|
||||
#[derive(Clone, PartialEq, Debug, Default)]
|
||||
pub enum ObjectKind {
|
||||
pub enum PlayerSubKind {
|
||||
#[default]
|
||||
Player = 4,
|
||||
}
|
||||
|
||||
// See https://github.com/Caraxi/Dalamud/blob/e6017f96c09b8cde20e02371914ec25cfa989ef7/Dalamud/Game/ClientState/Objects/Enums/BattleNpcSubKind.cs#L6
|
||||
#[binrw]
|
||||
#[brw(repr = u8)]
|
||||
#[derive(Clone, PartialEq, Debug, Default)]
|
||||
pub enum BattleNpcSubKind {
|
||||
#[default]
|
||||
None = 0,
|
||||
Player = 1,
|
||||
BattleNpc = 2,
|
||||
EventNpc = 3,
|
||||
Treasure = 4,
|
||||
Aetheryte = 5,
|
||||
GatheringPoint = 6,
|
||||
EventObj = 7,
|
||||
Mount = 8,
|
||||
Companion = 9,
|
||||
Retainer = 10,
|
||||
AreaObject = 11,
|
||||
HousingEventObject = 12,
|
||||
Cutscene = 13,
|
||||
MjiObject = 14,
|
||||
Ornament = 15,
|
||||
CardStand = 16,
|
||||
Part = 1,
|
||||
Pet = 2,
|
||||
Chocobo = 3,
|
||||
Enemy = 5,
|
||||
NpcPartyMember = 9,
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
#[derive(Clone, PartialEq, Debug, Default)]
|
||||
pub enum ObjectKind {
|
||||
#[default]
|
||||
#[brw(magic = 0u8)]
|
||||
None,
|
||||
#[brw(magic = 1u8)]
|
||||
Player(PlayerSubKind),
|
||||
#[brw(magic = 2u8)]
|
||||
BattleNpc(BattleNpcSubKind),
|
||||
#[brw(magic = 3u8)]
|
||||
EventNpc,
|
||||
#[brw(magic = 4u8)]
|
||||
Treasure,
|
||||
#[brw(magic = 5u8)]
|
||||
Aetheryte,
|
||||
#[brw(magic = 6u8)]
|
||||
GatheringPoint,
|
||||
#[brw(magic = 7u8)]
|
||||
EventObj,
|
||||
#[brw(magic = 8u8)]
|
||||
Mount,
|
||||
#[brw(magic = 9u8)]
|
||||
Companion,
|
||||
#[brw(magic = 10u8)]
|
||||
Retainer,
|
||||
#[brw(magic = 11u8)]
|
||||
AreaObject,
|
||||
#[brw(magic = 12u8)]
|
||||
HousingEventObject,
|
||||
#[brw(magic = 13u8)]
|
||||
Cutscene,
|
||||
#[brw(magic = 14u8)]
|
||||
MjiObject,
|
||||
#[brw(magic = 15u8)]
|
||||
Ornament,
|
||||
#[brw(magic = 16u8)]
|
||||
CardStand,
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
|
@ -52,7 +90,7 @@ pub enum OnlineStatus {
|
|||
GameQA = 1,
|
||||
GameMaster = 2,
|
||||
GameMasterBlue = 3,
|
||||
EventParticipant = 4, // used by NPCs?
|
||||
EventParticipant = 4,
|
||||
#[default]
|
||||
Online = 47,
|
||||
}
|
||||
|
@ -78,22 +116,6 @@ pub enum GameMasterRank {
|
|||
#[brw(little)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct CommonSpawn {
|
||||
/// See Title Excel sheet
|
||||
pub title_id: u16,
|
||||
pub u1b: u16,
|
||||
pub current_world_id: u16,
|
||||
pub home_world_id: u16,
|
||||
|
||||
pub gm_rank: GameMasterRank,
|
||||
pub u3c: u8,
|
||||
pub u4: u8,
|
||||
pub online_status: OnlineStatus,
|
||||
|
||||
pub pose: u8,
|
||||
pub u5a: u8,
|
||||
pub u5b: u8,
|
||||
pub u5c: u8,
|
||||
|
||||
pub target_id: ObjectTypeId,
|
||||
pub u6: u32,
|
||||
pub u7: u32,
|
||||
|
@ -133,8 +155,8 @@ pub struct CommonSpawn {
|
|||
/// Argument used in CharacterMode.
|
||||
// TODO: move to enum
|
||||
pub persistent_emote: u8,
|
||||
#[brw(pad_size_to = 2)] // for kinds that don't have a param
|
||||
pub object_kind: ObjectKind,
|
||||
pub subtype: u8,
|
||||
pub voice: u8,
|
||||
pub unk27: u8,
|
||||
/// See Battalion Excel sheet. Used for determing whether it's friendy or an enemy.
|
||||
|
|
|
@ -36,7 +36,10 @@ mod npc_spawn;
|
|||
pub use npc_spawn::NpcSpawn;
|
||||
|
||||
mod common_spawn;
|
||||
pub use common_spawn::{CharacterMode, CommonSpawn, GameMasterRank, ObjectKind, OnlineStatus};
|
||||
pub use common_spawn::{
|
||||
BattleNpcSubKind, CharacterMode, CommonSpawn, GameMasterRank, ObjectKind, OnlineStatus,
|
||||
PlayerSubKind,
|
||||
};
|
||||
|
||||
mod status_effect_list;
|
||||
pub use status_effect_list::StatusEffectList;
|
||||
|
|
|
@ -1,11 +1,24 @@
|
|||
use binrw::binrw;
|
||||
|
||||
use super::CommonSpawn;
|
||||
use super::{CommonSpawn, GameMasterRank, OnlineStatus};
|
||||
|
||||
#[binrw]
|
||||
#[brw(little)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct NpcSpawn {
|
||||
pub gimmick_id: u32,
|
||||
pub u1b: u8,
|
||||
pub u2b: u8,
|
||||
pub gm_rank: GameMasterRank, // lol really? what does an NPC need GM rank privileges for?
|
||||
pub u3b: u8,
|
||||
|
||||
pub aggression_mode: u8,
|
||||
pub online_status: OnlineStatus,
|
||||
pub u5a: u8,
|
||||
pub pose: u8,
|
||||
|
||||
pub u5b: u32,
|
||||
|
||||
pub common: CommonSpawn,
|
||||
pub padding: [u8; 10],
|
||||
}
|
||||
|
@ -18,7 +31,7 @@ mod tests {
|
|||
|
||||
use crate::{
|
||||
common::INVALID_OBJECT_ID,
|
||||
world::ipc::{CharacterMode, ObjectKind, OnlineStatus},
|
||||
world::ipc::{BattleNpcSubKind, CharacterMode, ObjectKind, OnlineStatus},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
@ -45,10 +58,13 @@ mod tests {
|
|||
assert_eq!(npc_spawn.common.bnpc_name, 10261);
|
||||
assert_eq!(npc_spawn.common.spawn_index, 56);
|
||||
assert_eq!(npc_spawn.common.mode, CharacterMode::Normal);
|
||||
assert_eq!(npc_spawn.common.object_kind, ObjectKind::BattleNpc);
|
||||
assert_eq!(npc_spawn.common.subtype, 2);
|
||||
assert_eq!(
|
||||
npc_spawn.common.object_kind,
|
||||
ObjectKind::BattleNpc(BattleNpcSubKind::Pet)
|
||||
);
|
||||
assert_eq!(npc_spawn.common.battalion, 0);
|
||||
assert_eq!(npc_spawn.common.online_status, OnlineStatus::Offline); // TODO: why is this guy offline?
|
||||
assert_eq!(npc_spawn.aggression_mode, 1); // passive
|
||||
assert_eq!(npc_spawn.online_status, OnlineStatus::Offline);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -73,11 +89,14 @@ mod tests {
|
|||
assert_eq!(npc_spawn.common.bnpc_name, 405);
|
||||
assert_eq!(npc_spawn.common.spawn_index, 14);
|
||||
assert_eq!(npc_spawn.common.mode, CharacterMode::Normal);
|
||||
assert_eq!(npc_spawn.common.object_kind, ObjectKind::BattleNpc);
|
||||
assert_eq!(npc_spawn.common.subtype, 5);
|
||||
assert_eq!(
|
||||
npc_spawn.common.object_kind,
|
||||
ObjectKind::BattleNpc(BattleNpcSubKind::Enemy)
|
||||
);
|
||||
assert_eq!(npc_spawn.common.battalion, 4);
|
||||
assert_eq!(npc_spawn.common.parent_actor_id, INVALID_OBJECT_ID);
|
||||
assert_eq!(npc_spawn.common.spawner_id, INVALID_OBJECT_ID);
|
||||
assert_eq!(npc_spawn.common.online_status, OnlineStatus::EventParticipant);
|
||||
assert_eq!(npc_spawn.aggression_mode, 1); // passive
|
||||
assert_eq!(npc_spawn.online_status, OnlineStatus::Offline);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,33 @@
|
|||
use binrw::binrw;
|
||||
|
||||
use super::CommonSpawn;
|
||||
use super::{CommonSpawn, GameMasterRank, OnlineStatus};
|
||||
|
||||
#[binrw]
|
||||
#[brw(little)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct PlayerSpawn {
|
||||
// also shows up in the friends list.
|
||||
pub some_unique_id: u32,
|
||||
// yes, really.
|
||||
pub account_id: u32,
|
||||
|
||||
#[brw(pad_before = 4)] // always empty?
|
||||
pub content_id: u64,
|
||||
|
||||
/// See Title Excel sheet
|
||||
pub title_id: u16,
|
||||
pub u1b: u16,
|
||||
pub current_world_id: u16,
|
||||
pub home_world_id: u16,
|
||||
|
||||
pub gm_rank: GameMasterRank,
|
||||
pub u3c: u8,
|
||||
pub u4: u8,
|
||||
pub online_status: OnlineStatus,
|
||||
|
||||
pub pose: u8,
|
||||
pub u5a: u8,
|
||||
pub u5b: u8,
|
||||
pub u5c: u8,
|
||||
|
||||
pub common: CommonSpawn,
|
||||
|
||||
pub padding: [u8; 2],
|
||||
|
@ -23,7 +39,7 @@ mod tests {
|
|||
|
||||
use binrw::BinRead;
|
||||
|
||||
use crate::world::ipc::{CharacterMode, ObjectKind, OnlineStatus};
|
||||
use crate::world::ipc::{CharacterMode, ObjectKind, OnlineStatus, PlayerSubKind};
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -36,8 +52,8 @@ mod tests {
|
|||
let mut buffer = Cursor::new(&buffer);
|
||||
|
||||
let player_spawn = PlayerSpawn::read_le(&mut buffer).unwrap();
|
||||
assert_eq!(player_spawn.common.current_world_id, 0x4F);
|
||||
assert_eq!(player_spawn.common.home_world_id, 0x4F);
|
||||
assert_eq!(player_spawn.current_world_id, 0x4F);
|
||||
assert_eq!(player_spawn.home_world_id, 0x4F);
|
||||
assert_eq!(player_spawn.common.hp_curr, 159);
|
||||
assert_eq!(player_spawn.common.hp_max, 159);
|
||||
assert_eq!(player_spawn.common.mp_curr, 10000);
|
||||
|
@ -55,10 +71,12 @@ mod tests {
|
|||
assert_eq!(player_spawn.common.look.gender, 1);
|
||||
assert_eq!(player_spawn.common.look.bust, 100);
|
||||
assert_eq!(player_spawn.common.fc_tag, "");
|
||||
assert_eq!(player_spawn.common.subtype, 4);
|
||||
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(PlayerSubKind::Player)
|
||||
);
|
||||
assert_eq!(player_spawn.common.display_flags, 262144);
|
||||
assert_eq!(player_spawn.common.online_status, OnlineStatus::Offline);
|
||||
assert_eq!(player_spawn.online_status, OnlineStatus::Offline);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue