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

Fix CharaMake structure, derive City-State from class picked in creation

This commit is contained in:
Joshua Goins 2025-03-22 18:34:27 -04:00
parent c4b65f5ecd
commit 15ed586fd0
5 changed files with 58 additions and 22 deletions

View file

@ -1,8 +1,9 @@
use std::sync::Arc; use std::sync::Arc;
use kawari::common::custom_ipc::{CustomIpcData, CustomIpcSegment, CustomIpcType}; use kawari::common::custom_ipc::{CustomIpcData, CustomIpcSegment, CustomIpcType};
use kawari::common::get_world_name; use kawari::common::{get_citystate, get_world_name};
use kawari::config::get_config; use kawari::config::get_config;
use kawari::lobby::CharaMake;
use kawari::oodle::OodleNetwork; use kawari::oodle::OodleNetwork;
use kawari::packet::{ use kawari::packet::{
CompressionType, ConnectionType, PacketSegment, PacketState, SegmentType, send_keep_alive, CompressionType, ConnectionType, PacketSegment, PacketState, SegmentType, send_keep_alive,
@ -260,7 +261,7 @@ async fn main() {
.chara_make .chara_make
.customize .customize
.subrace, .subrace,
city_state: chara_details.chara_make.unk6 as u8, // TODO: probably wrong city_state: chara_details.city_state,
nameday_month: chara_details nameday_month: chara_details
.chara_make .chara_make
.birth_month .birth_month
@ -721,8 +722,16 @@ async fn main() {
"creating character from: {name} {chara_make_json}" "creating character from: {name} {chara_make_json}"
); );
let (content_id, actor_id) = let chara_make = CharaMake::from_json(&chara_make_json);
database.create_player_data(name, chara_make_json);
let city_state =
get_citystate(chara_make.classjob_id as u16);
let (content_id, actor_id) = database.create_player_data(
name,
chara_make_json,
city_state,
);
tracing::info!( tracing::info!(
"Created new player: {content_id} {actor_id}" "Created new player: {content_id} {actor_id}"

View file

@ -63,3 +63,23 @@ pub fn get_world_name(world_id: u16) -> String {
name.clone() name.clone()
} }
/// Gets the starting city-state from a given class/job id.
pub fn get_citystate(classjob_id: u16) -> u8 {
let config = get_config();
let mut game_data = GameData::from_existing(Platform::Win32, &config.game_location).unwrap();
let exh = game_data.read_excel_sheet_header("ClassJob").unwrap();
let exd = game_data
.read_excel_sheet("ClassJob", &exh, Language::English, 0)
.unwrap();
let world_row = &exd.read_row(&exh, classjob_id as u32).unwrap()[0];
let physis::exd::ColumnData::UInt8(town_id) = &world_row.data[33] else {
panic!("Unexpected type!");
};
*town_id
}

View file

@ -5,12 +5,12 @@ use crate::common::CustomizeData;
#[derive(Debug)] #[derive(Debug)]
pub struct CharaMake { pub struct CharaMake {
pub customize: CustomizeData, pub customize: CustomizeData,
pub unk1: i32, // always 1? pub unk1: i32,
pub guardian: i32, pub guardian: i32,
pub birth_month: i32, pub birth_month: i32,
pub classjob: i32,
pub birth_day: i32, pub birth_day: i32,
pub unk6: i32, // always 1? pub classjob_id: i32,
pub unk2: i32,
} }
impl CharaMake { impl CharaMake {
@ -23,9 +23,9 @@ impl CharaMake {
unk1: content[1].as_str().unwrap().parse::<i32>().unwrap(), unk1: content[1].as_str().unwrap().parse::<i32>().unwrap(),
guardian: content[2].as_str().unwrap().parse::<i32>().unwrap(), guardian: content[2].as_str().unwrap().parse::<i32>().unwrap(),
birth_month: content[3].as_str().unwrap().parse::<i32>().unwrap(), birth_month: content[3].as_str().unwrap().parse::<i32>().unwrap(),
classjob: content[4].as_str().unwrap().parse::<i32>().unwrap(), birth_day: content[4].as_str().unwrap().parse::<i32>().unwrap(),
birth_day: content[5].as_str().unwrap().parse::<i32>().unwrap(), classjob_id: content[5].as_str().unwrap().parse::<i32>().unwrap(),
unk6: content[6].as_str().unwrap().parse::<i32>().unwrap(), unk2: content[6].as_str().unwrap().parse::<i32>().unwrap(),
} }
} }
@ -35,9 +35,9 @@ impl CharaMake {
self.unk1, self.unk1,
self.guardian, self.guardian,
self.birth_month, self.birth_month,
self.classjob,
self.birth_day, self.birth_day,
self.unk6, self.classjob_id,
self.unk2,
]); ]);
let obj = json!({ let obj = json!({
@ -60,7 +60,7 @@ mod tests {
let chara_make = CharaMake::from_json(json); let chara_make = CharaMake::from_json(json);
assert_eq!(chara_make.customize.gender, 0); assert_eq!(chara_make.customize.gender, 0);
assert_eq!(chara_make.classjob, 1); assert_eq!(chara_make.unk1, 1);
// TODO: add more asserts // TODO: add more asserts
} }

View file

@ -9,6 +9,7 @@ use crate::{
get_world_name, timestamp_secs, get_world_name, timestamp_secs,
}, },
config::get_config, config::get_config,
lobby::CharaMake,
oodle::OodleNetwork, oodle::OodleNetwork,
packet::{ packet::{
CompressionType, ConnectionType, PacketSegment, PacketState, SegmentType, CompressionType, ConnectionType, PacketSegment, PacketState, SegmentType,
@ -207,8 +208,6 @@ impl LobbyConnection {
let mut characters = characters.to_vec(); let mut characters = characters.to_vec();
dbg!(&characters);
for i in 0..4 { for i in 0..4 {
let mut characters_in_packet = Vec::new(); let mut characters_in_packet = Vec::new();
for _ in 0..min(characters.len(), 2) { for _ in 0..min(characters.len(), 2) {
@ -429,6 +428,8 @@ impl LobbyConnection {
let our_actor_id; let our_actor_id;
let our_content_id; let our_content_id;
dbg!(CharaMake::from_json(&character_action.json));
// tell the world server to create this character // tell the world server to create this character
{ {
let ipc_segment = CustomIpcSegment { let ipc_segment = CustomIpcSegment {

View file

@ -16,6 +16,7 @@ pub struct WorldDatabase {
pub struct CharacterData { pub struct CharacterData {
pub name: String, pub name: String,
pub chara_make: CharaMake, // probably not the ideal way to store this? pub chara_make: CharaMake, // probably not the ideal way to store this?
pub city_state: u8,
} }
impl WorldDatabase { impl WorldDatabase {
@ -30,7 +31,7 @@ impl WorldDatabase {
// Create characters data table // Create characters data table
{ {
let query = "CREATE TABLE IF NOT EXISTS character_data (content_id INTEGER PRIMARY KEY, name STRING, chara_make STRING);"; let query = "CREATE TABLE IF NOT EXISTS character_data (content_id INTEGER PRIMARY KEY, name STRING, chara_make STRING, city_state INTEGER);";
connection.execute(query, ()).unwrap(); connection.execute(query, ()).unwrap();
} }
@ -165,7 +166,7 @@ impl WorldDatabase {
} }
/// Gives (content_id, actor_id) /// Gives (content_id, actor_id)
pub fn create_player_data(&self, name: &str, chara_make: &str) -> (u64, u32) { pub fn create_player_data(&self, name: &str, chara_make: &str, city_state: u8) -> (u64, u32) {
let content_id = Self::generate_content_id(); let content_id = Self::generate_content_id();
let actor_id = Self::generate_actor_id(); let actor_id = Self::generate_actor_id();
@ -182,8 +183,8 @@ impl WorldDatabase {
// insert char data // insert char data
connection connection
.execute( .execute(
"INSERT INTO character_data VALUES (?1, ?2, ?3);", "INSERT INTO character_data VALUES (?1, ?2, ?3, ?4);",
(content_id, name, chara_make), (content_id, name, chara_make, city_state),
) )
.unwrap(); .unwrap();
@ -205,15 +206,20 @@ impl WorldDatabase {
let connection = self.connection.lock().unwrap(); let connection = self.connection.lock().unwrap();
let mut stmt = connection let mut stmt = connection
.prepare("SELECT name, chara_make FROM character_data WHERE content_id = ?1") .prepare(
"SELECT name, chara_make, city_state FROM character_data WHERE content_id = ?1",
)
.unwrap(); .unwrap();
let (name, chara_make_json): (String, String) = stmt let (name, chara_make_json, city_state): (String, String, u8) = stmt
.query_row((content_id,), |row| Ok((row.get(0)?, row.get(1)?))) .query_row((content_id,), |row| {
Ok((row.get(0)?, row.get(1)?, row.get(2)?))
})
.unwrap(); .unwrap();
CharacterData { CharacterData {
name, name,
chara_make: CharaMake::from_json(&chara_make_json), chara_make: CharaMake::from_json(&chara_make_json),
city_state,
} }
} }