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:
parent
c4b65f5ecd
commit
15ed586fd0
5 changed files with 58 additions and 22 deletions
|
@ -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}"
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue