1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-04-27 08:57:45 +00:00

Fix a few problems with ClientSelectData, use the same character in both servers

I apparently had a few fields missing here. Also just some general clean up,
make it the same looking character in both the Lobby and World server. I also
chose Gridania as the test zone.
This commit is contained in:
Joshua Goins 2025-03-14 00:30:37 -04:00
parent 5c22532474
commit 640aeb797c
7 changed files with 122 additions and 149 deletions

View file

@ -13,7 +13,7 @@ use kawari::oodle::FFXIVOodle;
use kawari::packet::{ use kawari::packet::{
CompressionType, PacketSegment, SegmentType, State, parse_packet, send_keep_alive, send_packet, CompressionType, PacketSegment, SegmentType, State, parse_packet, send_keep_alive, send_packet,
}; };
use kawari::{CONTENT_ID, WORLD_ID, WORLD_NAME, ZONE_ID}; use kawari::{CHAR_NAME, CONTENT_ID, CUSTOMIZE_DATA, WORLD_ID, WORLD_NAME, ZONE_ID};
use tokio::io::{AsyncReadExt, WriteHalf}; use tokio::io::{AsyncReadExt, WriteHalf};
use tokio::net::{TcpListener, TcpStream}; use tokio::net::{TcpListener, TcpStream};
@ -396,33 +396,7 @@ async fn send_lobby_info(socket: &mut WriteHalf<TcpStream>, state: &mut State, s
unk9: 0, unk9: 0,
zone_id: ZONE_ID as i32, zone_id: ZONE_ID as i32,
unk11: 0, unk11: 0,
customize: ClientCustomizeData { customize: CUSTOMIZE_DATA,
race: 3,
gender: 1,
height: 0,
subrace: 0,
face: 1,
hair: 1,
enable_highlights: 1,
skin_tone: 1,
right_eye_color: 1,
hair_tone: 1,
highlights: 1,
facial_features: 1,
facial_feature_color: 1,
eyebrows: 1,
left_eye_color: 1,
eyes: 1,
nose: 1,
jaw: 1,
mouth: 1,
lips_tone_fur_pattern: 1,
race_feature_size: 1,
race_feature_type: 1,
bust: 0,
face_paint: 1,
face_paint_color: 0,
},
unk12: 0, unk12: 0,
unk13: 0, unk13: 0,
unk14: [0; 10], unk14: [0; 10],
@ -432,7 +406,7 @@ async fn send_lobby_info(socket: &mut WriteHalf<TcpStream>, state: &mut State, s
unk18: 0, unk18: 0,
unk19: 0, unk19: 0,
unk20: 0, unk20: 0,
unk21: "hello".to_string(), unk21: String::new(),
unk22: 0, unk22: 0,
unk23: 0, unk23: 0,
}; };
@ -444,7 +418,7 @@ async fn send_lobby_info(socket: &mut WriteHalf<TcpStream>, state: &mut State, s
unk1: [0; 16], unk1: [0; 16],
origin_server_id: WORLD_ID, origin_server_id: WORLD_ID,
current_server_id: WORLD_ID, current_server_id: WORLD_ID,
character_name: "test".to_string(), character_name: CHAR_NAME.to_string(),
origin_server_name: WORLD_NAME.to_string(), origin_server_name: WORLD_NAME.to_string(),
current_server_name: WORLD_NAME.to_string(), current_server_name: WORLD_NAME.to_string(),
character_detail_json: select_data.to_json(), character_detail_json: select_data.to_json(),

View file

@ -7,10 +7,10 @@ use kawari::packet::{
CompressionType, PacketSegment, SegmentType, State, parse_packet, send_keep_alive, send_packet, CompressionType, PacketSegment, SegmentType, State, parse_packet, send_keep_alive, send_packet,
}; };
use kawari::world::{ use kawari::world::{
ActorControlSelf, ActorControlType, CustomizeData, InitZone, PlayerSetup, PlayerSpawn, ActorControlSelf, ActorControlType, InitZone, PlayerSetup, PlayerSpawn, PlayerStats, Position,
PlayerStats, Position, UpdateClassInfo, UpdateClassInfo,
}; };
use kawari::{CONTENT_ID, WORLD_ID, ZONE_ID}; use kawari::{CHAR_NAME, CONTENT_ID, CUSTOMIZE_DATA, WORLD_ID, ZONE_ID};
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
use tokio::net::TcpListener; use tokio::net::TcpListener;
@ -268,7 +268,7 @@ async fn main() {
content_id: CONTENT_ID, content_id: CONTENT_ID,
exp: [10000; 32], exp: [10000; 32],
levels: [100; 32], levels: [100; 32],
name: "KAWARI".to_string(), name: CHAR_NAME.to_string(),
..Default::default() ..Default::default()
}), }),
}; };
@ -499,7 +499,7 @@ async fn main() {
home_world_id: WORLD_ID, home_world_id: WORLD_ID,
title: 1, title: 1,
class_job: 35, class_job: 35,
name: "Test".to_string(), name: CHAR_NAME.to_string(),
hp_curr: 100, hp_curr: 100,
hp_max: 100, hp_max: 100,
mp_curr: 100, mp_curr: 100,
@ -508,35 +508,20 @@ async fn main() {
spawn_index: 1, spawn_index: 1,
state: 1, state: 1,
gm_rank: 3, gm_rank: 3,
look: CustomizeData { look: CUSTOMIZE_DATA,
race: 3,
age: 0,
gender: 1,
height: 5,
subrace: 0,
face: 1,
hair: 2,
enable_highlights: 0,
skin_tone: 4,
right_eye_color: 5,
hair_tone: 2,
highlights: 7,
facial_features: 1,
facial_feature_color: 1,
eyebrows: 2,
left_eye_color: 1,
eyes: 1,
nose: 0,
jaw: 1,
mouth: 0,
lips_tone_fur_pattern: 1,
race_feature_size: 1,
race_feature_type: 1,
bust: 0,
face_paint: 1,
face_paint_color: 1,
},
fc_tag: "LOCAL".to_string(), fc_tag: "LOCAL".to_string(),
models: [
0, // head
89, // body
89, // hands
89, // legs
89, // feet
0, // ears
0, // neck
0, // wrists
0, // left finger
0, // right finger
],
..Default::default() ..Default::default()
}), }),
}; };
@ -731,6 +716,9 @@ async fn main() {
} }
} }
} }
IPCStructData::Unk12 { .. } => {
tracing::info!("Recieved Unk12!");
}
_ => panic!( _ => panic!(
"The server is recieving a IPC response or unknown packet!" "The server is recieving a IPC response or unknown packet!"
), ),

View file

@ -4,31 +4,32 @@ use serde_json::{Value, json};
#[binrw] #[binrw]
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct ClientCustomizeData { pub struct ClientCustomizeData {
pub race: i32, pub race: u8,
pub gender: i32, pub gender: u8,
pub height: i32, pub age: u8,
pub subrace: i32, pub height: u8,
pub face: i32, pub subrace: u8,
pub hair: i32, pub face: u8,
pub enable_highlights: i32, pub hair: u8,
pub skin_tone: i32, pub enable_highlights: u8,
pub right_eye_color: i32, pub skin_tone: u8,
pub hair_tone: i32, pub right_eye_color: u8,
pub highlights: i32, pub hair_tone: u8,
pub facial_features: i32, pub highlights: u8,
pub facial_feature_color: i32, pub facial_features: u8,
pub eyebrows: i32, pub facial_feature_color: u8,
pub left_eye_color: i32, pub eyebrows: u8,
pub eyes: i32, pub left_eye_color: u8,
pub nose: i32, pub eyes: u8,
pub jaw: i32, pub nose: u8,
pub mouth: i32, pub jaw: u8,
pub lips_tone_fur_pattern: i32, pub mouth: u8,
pub race_feature_size: i32, pub lips_tone_fur_pattern: u8,
pub race_feature_type: i32, pub race_feature_size: u8,
pub bust: i32, pub race_feature_type: u8,
pub face_paint: i32, pub bust: u8,
pub face_paint_color: i32, pub face_paint: u8,
pub face_paint_color: u8,
} }
impl ClientCustomizeData { impl ClientCustomizeData {
@ -36,9 +37,11 @@ impl ClientCustomizeData {
json!([ json!([
self.race.to_string(), self.race.to_string(),
self.gender.to_string(), self.gender.to_string(),
self.age.to_string(),
self.height.to_string(), self.height.to_string(),
self.subrace.to_string(), self.subrace.to_string(),
self.face.to_string(), self.face.to_string(),
self.hair.to_string(),
self.enable_highlights.to_string(), self.enable_highlights.to_string(),
self.skin_tone.to_string(), self.skin_tone.to_string(),
self.right_eye_color.to_string(), self.right_eye_color.to_string(),
@ -63,31 +66,32 @@ impl ClientCustomizeData {
pub fn from_json(json: &Value) -> Self { pub fn from_json(json: &Value) -> Self {
Self { Self {
race: json[0].as_str().unwrap().parse::<i32>().unwrap(), race: json[0].as_str().unwrap().parse::<u8>().unwrap(),
gender: json[1].as_str().unwrap().parse::<i32>().unwrap(), gender: json[1].as_str().unwrap().parse::<u8>().unwrap(),
height: json[2].as_str().unwrap().parse::<i32>().unwrap(), height: json[2].as_str().unwrap().parse::<u8>().unwrap(),
subrace: json[3].as_str().unwrap().parse::<i32>().unwrap(), subrace: json[3].as_str().unwrap().parse::<u8>().unwrap(),
face: json[4].as_str().unwrap().parse::<i32>().unwrap(), face: json[4].as_str().unwrap().parse::<u8>().unwrap(),
hair: json[5].as_str().unwrap().parse::<i32>().unwrap(), hair: json[5].as_str().unwrap().parse::<u8>().unwrap(),
enable_highlights: json[6].as_str().unwrap().parse::<i32>().unwrap(), enable_highlights: json[6].as_str().unwrap().parse::<u8>().unwrap(),
skin_tone: json[7].as_str().unwrap().parse::<i32>().unwrap(), skin_tone: json[7].as_str().unwrap().parse::<u8>().unwrap(),
right_eye_color: json[8].as_str().unwrap().parse::<i32>().unwrap(), right_eye_color: json[8].as_str().unwrap().parse::<u8>().unwrap(),
hair_tone: json[9].as_str().unwrap().parse::<i32>().unwrap(), hair_tone: json[9].as_str().unwrap().parse::<u8>().unwrap(),
highlights: json[10].as_str().unwrap().parse::<i32>().unwrap(), highlights: json[10].as_str().unwrap().parse::<u8>().unwrap(),
facial_features: json[11].as_str().unwrap().parse::<i32>().unwrap(), facial_features: json[11].as_str().unwrap().parse::<u8>().unwrap(),
facial_feature_color: json[12].as_str().unwrap().parse::<i32>().unwrap(), facial_feature_color: json[12].as_str().unwrap().parse::<u8>().unwrap(),
eyebrows: json[13].as_str().unwrap().parse::<i32>().unwrap(), eyebrows: json[13].as_str().unwrap().parse::<u8>().unwrap(),
left_eye_color: json[14].as_str().unwrap().parse::<i32>().unwrap(), left_eye_color: json[14].as_str().unwrap().parse::<u8>().unwrap(),
eyes: json[15].as_str().unwrap().parse::<i32>().unwrap(), eyes: json[15].as_str().unwrap().parse::<u8>().unwrap(),
nose: json[16].as_str().unwrap().parse::<i32>().unwrap(), nose: json[16].as_str().unwrap().parse::<u8>().unwrap(),
jaw: json[17].as_str().unwrap().parse::<i32>().unwrap(), jaw: json[17].as_str().unwrap().parse::<u8>().unwrap(),
mouth: json[18].as_str().unwrap().parse::<i32>().unwrap(), mouth: json[18].as_str().unwrap().parse::<u8>().unwrap(),
lips_tone_fur_pattern: json[19].as_str().unwrap().parse::<i32>().unwrap(), lips_tone_fur_pattern: json[19].as_str().unwrap().parse::<u8>().unwrap(),
race_feature_size: json[20].as_str().unwrap().parse::<i32>().unwrap(), race_feature_size: json[20].as_str().unwrap().parse::<u8>().unwrap(),
race_feature_type: json[21].as_str().unwrap().parse::<i32>().unwrap(), race_feature_type: json[21].as_str().unwrap().parse::<u8>().unwrap(),
bust: json[22].as_str().unwrap().parse::<i32>().unwrap(), bust: json[22].as_str().unwrap().parse::<u8>().unwrap(),
face_paint: json[23].as_str().unwrap().parse::<i32>().unwrap(), face_paint: json[23].as_str().unwrap().parse::<u8>().unwrap(),
face_paint_color: json[24].as_str().unwrap().parse::<i32>().unwrap(), face_paint_color: json[24].as_str().unwrap().parse::<u8>().unwrap(),
age: 1,
} }
} }
} }
@ -109,7 +113,7 @@ pub struct ClientSelectData {
pub customize: ClientCustomizeData, pub customize: ClientCustomizeData,
pub unk12: i32, pub unk12: i32,
pub unk13: i32, pub unk13: i32,
pub unk14: [i32; 10], pub unk14: [i32; 10], // probably model ids
pub unk15: i32, pub unk15: i32,
pub unk16: i32, pub unk16: i32,
/// If set to 1, the user is granted one opportunity to edit their character and are prompted to re-choose their class. /// If set to 1, the user is granted one opportunity to edit their character and are prompted to re-choose their class.
@ -159,6 +163,6 @@ impl ClientSelectData {
"classid": 116, "classid": 116,
}); });
serde_json::to_string_pretty(&obj).unwrap() serde_json::to_string(&obj).unwrap()
} }
} }

View file

@ -98,6 +98,8 @@ pub enum IPCOpCode {
Unk11 = 0x156, Unk11 = 0x156,
// Assumed what this is, but probably incorrect // Assumed what this is, but probably incorrect
CharacterCreated = 0xE, CharacterCreated = 0xE,
// Unknown, client sends this for ???
Unk12 = 0x0E9,
} }
#[binrw] #[binrw]
@ -357,6 +359,10 @@ pub enum IPCStructData {
#[br(dbg)] #[br(dbg)]
unk: [u8; 24], unk: [u8; 24],
}, },
#[br(pre_assert(*magic == IPCOpCode::Unk12))]
Unk12 {
unk: [u8; 8], // TODO: unknown
},
// Server->Client IPC // Server->Client IPC
#[br(pre_assert(false))] #[br(pre_assert(false))]
@ -571,6 +577,7 @@ impl IPCSegment {
IPCStructData::Unk11 { .. } => 32, IPCStructData::Unk11 { .. } => 32,
IPCStructData::NameRejection { .. } => 536, IPCStructData::NameRejection { .. } => 536,
IPCStructData::CharacterCreated { .. } => 2568, IPCStructData::CharacterCreated { .. } => 2568,
IPCStructData::Unk12 { .. } => todo!(),
} }
} }
} }

View file

@ -1,3 +1,4 @@
use client_select_data::ClientCustomizeData;
use minijinja::Environment; use minijinja::Environment;
use rand::Rng; use rand::Rng;
use rand::distributions::Alphanumeric; use rand::distributions::Alphanumeric;
@ -20,13 +21,44 @@ pub mod world;
pub const WORLD_ID: u16 = 63; pub const WORLD_ID: u16 = 63;
pub const WORLD_NAME: &str = "KAWARI"; pub const WORLD_NAME: &str = "KAWARI";
pub const ZONE_ID: u16 = 1255; pub const ZONE_ID: u16 = 132;
pub const CONTENT_ID: u64 = 11111111111111111; pub const CONTENT_ID: u64 = 11111111111111111;
pub const CUSTOMIZE_DATA: ClientCustomizeData = ClientCustomizeData {
race: 4,
gender: 1,
age: 1,
height: 50,
subrace: 7,
face: 3,
hair: 5,
enable_highlights: 0,
skin_tone: 10,
right_eye_color: 75,
hair_tone: 50,
highlights: 0,
facial_features: 1,
facial_feature_color: 19,
eyebrows: 1,
left_eye_color: 75,
eyes: 1,
nose: 0,
jaw: 1,
mouth: 1,
lips_tone_fur_pattern: 169,
race_feature_size: 100,
race_feature_type: 1,
bust: 100,
face_paint: 0,
face_paint_color: 167,
};
/// Maxmimum length of a character's name. /// Maxmimum length of a character's name.
pub const CHAR_NAME_MAX_LENGTH: usize = 32; pub const CHAR_NAME_MAX_LENGTH: usize = 32;
pub const CHAR_NAME: &str = "Test User";
pub fn generate_sid() -> String { pub fn generate_sid() -> String {
let random_id: String = rand::thread_rng() let random_id: String = rand::thread_rng()
.sample_iter(&Alphanumeric) .sample_iter(&Alphanumeric)

View file

@ -1,5 +1,4 @@
mod player_spawn; mod player_spawn;
pub use player_spawn::CustomizeData;
pub use player_spawn::PlayerSpawn; pub use player_spawn::PlayerSpawn;
mod position; mod position;

View file

@ -88,7 +88,7 @@ pub struct PlayerSpawn {
#[br(map = read_string)] #[br(map = read_string)]
#[bw(map = write_string)] #[bw(map = write_string)]
pub name: String, pub name: String,
pub look: CustomizeData, pub look: ClientCustomizeData,
#[br(count = 6)] #[br(count = 6)]
#[bw(pad_size_to = 6)] #[bw(pad_size_to = 6)]
#[br(map = read_string)] #[br(map = read_string)]
@ -97,37 +97,6 @@ pub struct PlayerSpawn {
pub padding: [u8; 2], pub padding: [u8; 2],
} }
#[binrw]
#[derive(Debug, Clone, Default)]
pub struct CustomizeData {
pub race: u8,
pub gender: u8,
pub age: u8,
pub height: u8,
pub subrace: u8,
pub face: u8,
pub hair: u8,
pub enable_highlights: u8,
pub skin_tone: u8,
pub right_eye_color: u8,
pub hair_tone: u8,
pub highlights: u8,
pub facial_features: u8,
pub facial_feature_color: u8,
pub eyebrows: u8,
pub left_eye_color: u8,
pub eyes: u8,
pub nose: u8,
pub jaw: u8,
pub mouth: u8,
pub lips_tone_fur_pattern: u8,
pub race_feature_size: u8,
pub race_feature_type: u8,
pub bust: u8,
pub face_paint: u8,
pub face_paint_color: u8,
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{fs::read, io::Cursor, path::PathBuf}; use std::{fs::read, io::Cursor, path::PathBuf};