1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-05-02 03:07:44 +00:00

Move model id grabbing to Inventory, fixup ClientSelectData

I wanted to make the lobby screen reflect your currently equipped items,
but that doesn't yet for some reason. These are still good refactorings
though!
This commit is contained in:
Joshua Goins 2025-04-30 23:05:43 -04:00
parent 614e470669
commit ed8ccb86ee
5 changed files with 99 additions and 113 deletions

View file

@ -832,12 +832,16 @@ async fn client_loop(
}
let mut inventory = Inventory::default();
{
let mut game_data = game_data.lock().unwrap();
// fill inventory
inventory.equip_racial_items(
chara_make.customize.race,
chara_make.customize.gender,
);
// fill inventory
inventory.equip_racial_items(
chara_make.customize.race,
chara_make.customize.gender,
&mut game_data,
);
}
let (content_id, actor_id) = database.create_player_data(
*service_account_id,
@ -932,11 +936,17 @@ async fn client_loop(
world_name = game_data.get_world_name(config.world.world_id);
}
let characters = database.get_character_list(
*service_account_id,
config.world.world_id,
&world_name,
);
let characters;
{
let mut game_data = game_data.lock().unwrap();
characters = database.get_character_list(
*service_account_id,
config.world.world_id,
&world_name,
&mut game_data,
);
}
// send response
{

View file

@ -3,7 +3,7 @@ use serde_json::json;
use crate::common::CustomizeData;
// TODO: this isn't really an enum in the game, nor is it a flag either. it's weird!
#[derive(Clone, Copy)]
#[derive(Debug, Clone, Copy)]
#[repr(i32)]
pub enum RemakeMode {
/// No remake options are available.
@ -15,10 +15,11 @@ pub enum RemakeMode {
}
/// See https://github.com/aers/FFXIVClientStructs/blob/main/FFXIVClientStructs/FFXIV/Application/Network/WorkDefinitions/ClientSelectData.cs
#[derive(Debug)]
pub struct ClientSelectData {
pub game_name_unk: String,
pub character_name: String,
pub current_class: i32,
pub class_levels: [i32; 30],
pub class_levels: [i32; 32],
pub race: i32,
pub subrace: i32,
pub gender: i32,
@ -32,9 +33,11 @@ pub struct ClientSelectData {
/// The most notable is if your character can be remade, it says "Your character is currently bound by duty..."
pub content_finder_condition: i32,
pub customize: CustomizeData,
pub model_main_weapon: i32,
pub model_main_weapon: u64,
pub model_sub_weapon: i32,
pub unk14: [i32; 10], // probably model ids
pub model_ids: [u32; 10],
pub equip_stain: [u32; 10],
pub glasses: [u32; 2],
pub unk15: i32,
pub unk16: i32,
pub remake_mode: RemakeMode, // TODO: upstream a comment about this to FFXIVClientStructs
@ -44,13 +47,12 @@ pub struct ClientSelectData {
pub unk20: i32,
pub world_name: String,
pub unk22: i32,
pub unk23: i32,
}
impl ClientSelectData {
pub fn to_json(&self) -> String {
let content = json!([
self.game_name_unk,
self.character_name,
self.current_class.to_string(),
self.class_levels.map(|x| x.to_string()),
self.race.to_string(),
@ -66,7 +68,9 @@ impl ClientSelectData {
self.customize.to_json(),
self.model_main_weapon.to_string(),
self.model_sub_weapon.to_string(),
self.unk14.map(|x| x.to_string()),
self.model_ids.map(|x| x.to_string()),
self.equip_stain.map(|x| x.to_string()),
self.glasses.map(|x| x.to_string()),
self.unk15.to_string(),
self.unk16.to_string(),
(self.remake_mode as i32).to_string(),
@ -75,7 +79,6 @@ impl ClientSelectData {
self.unk20.to_string(),
self.world_name,
self.unk22.to_string(),
self.unk23.to_string(),
]);
let obj = json!({

View file

@ -613,50 +613,17 @@ impl ZoneConnection {
let ipc;
{
let mut game_data = self.gamedata.lock().unwrap();
let equipped = &self.player_data.inventory.equipped;
let inventory = &self.player_data.inventory;
ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::Equip,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::Equip(Equip {
main_weapon_id: game_data
.get_primary_model_id(equipped.main_hand.id)
.unwrap_or(0),
main_weapon_id: inventory.get_main_weapon_id(&mut game_data),
sub_weapon_id: 0,
crest_enable: 0,
pattern_invalid: 0,
model_ids: [
game_data
.get_primary_model_id(equipped.head.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.body.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.hands.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.legs.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.feet.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.ears.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.neck.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.wrists.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.left_ring.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.right_ring.id)
.unwrap_or(0) as u32,
],
model_ids: inventory.get_model_ids(&mut game_data),
}),
..Default::default()
};
@ -785,7 +752,8 @@ impl ZoneConnection {
let chara_details = self.database.find_chara_make(self.player_data.content_id);
let equipped = &self.player_data.inventory.equipped;
let inventory = &self.player_data.inventory;
CommonSpawn {
class_job: self.player_data.classjob_id,
name: chara_details.name,
@ -797,41 +765,8 @@ impl ZoneConnection {
object_kind: ObjectKind::Player(PlayerSubKind::Player),
look: chara_details.chara_make.customize,
display_flags: DisplayFlag::UNK,
main_weapon_model: game_data
.get_primary_model_id(equipped.main_hand.id)
.unwrap_or(0),
models: [
game_data
.get_primary_model_id(equipped.head.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.body.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.hands.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.legs.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.feet.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.ears.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.neck.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.wrists.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.left_ring.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(equipped.right_ring.id)
.unwrap_or(0) as u32,
],
main_weapon_model: inventory.get_main_weapon_id(&mut game_data),
models: inventory.get_model_ids(&mut game_data),
pos: exit_position.unwrap_or_default(),
rotation: exit_rotation.unwrap_or(0.0),
..Default::default()

View file

@ -5,7 +5,7 @@ use serde::Deserialize;
use crate::{
common::{
CustomizeData, Position,
CustomizeData, GameData, Position,
workdefinitions::{CharaMake, ClientSelectData, RemakeMode},
},
lobby::ipc::{CharacterDetails, CharacterFlag},
@ -225,6 +225,7 @@ impl WorldDatabase {
service_account_id: u32,
world_id: u16,
world_name: &str,
game_data: &mut GameData,
) -> Vec<CharacterDetails> {
let connection = self.connection.lock().unwrap();
@ -250,22 +251,24 @@ impl WorldDatabase {
for (index, (content_id, actor_id)) in content_actor_ids.iter().enumerate() {
let mut stmt = connection
.prepare(
"SELECT name, chara_make, zone_id FROM character_data WHERE content_id = ?1",
"SELECT name, chara_make, zone_id, inventory FROM character_data WHERE content_id = ?1",
)
.unwrap();
let result: Result<(String, String, u16), rusqlite::Error> = stmt
let result: Result<(String, String, u16, String), rusqlite::Error> = stmt
.query_row((content_id,), |row| {
Ok((row.get(0)?, row.get(1)?, row.get(2)?))
Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
});
if let Ok((name, chara_make, zone_id)) = result {
if let Ok((name, chara_make, zone_id, inventory_json)) = result {
let chara_make = CharaMake::from_json(&chara_make);
let inventory: Inventory = serde_json::from_str(&inventory_json).unwrap();
let select_data = ClientSelectData {
game_name_unk: "Final Fantasy".to_string(),
character_name: name.clone(),
current_class: 2,
class_levels: [5; 30],
class_levels: [5; 32],
race: chara_make.customize.race as i32,
subrace: chara_make.customize.subrace as i32,
gender: chara_make.customize.gender as i32,
@ -277,9 +280,11 @@ impl WorldDatabase {
zone_id: zone_id as i32,
content_finder_condition: 0,
customize: chara_make.customize,
model_main_weapon: 0,
model_main_weapon: inventory.get_main_weapon_id(game_data),
model_sub_weapon: 0,
unk14: [0; 10],
model_ids: inventory.get_model_ids(game_data),
equip_stain: [0; 10],
glasses: [0; 2],
unk15: 0,
unk16: 0,
remake_mode: RemakeMode::None,
@ -288,7 +293,6 @@ impl WorldDatabase {
unk20: 0,
world_name: String::new(),
unk22: 0,
unk23: 0,
};
characters.push(CharacterDetails {

View file

@ -1,10 +1,7 @@
use physis::{
common::{Language, Platform},
gamedata::GameData,
};
use physis::common::Language;
use serde::{Deserialize, Serialize};
use crate::config::get_config;
use crate::common::GameData;
use super::ipc::{ContainerType, InventoryModify};
@ -179,14 +176,10 @@ impl Default for Inventory {
impl Inventory {
/// Equip the starting items for a given race
pub fn equip_racial_items(&mut self, race_id: u8, gender: 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("Race").unwrap();
pub fn equip_racial_items(&mut self, race_id: u8, gender: u8, game_data: &mut GameData) {
let exh = game_data.game_data.read_excel_sheet_header("Race").unwrap();
let exd = game_data
.game_data
.read_excel_sheet("Race", &exh, Language::English, 0)
.unwrap();
@ -278,4 +271,45 @@ impl Inventory {
ContainerType::ArmouryBody => todo!(),
}
}
pub fn get_main_weapon_id(&self, game_data: &mut GameData) -> u64 {
game_data
.get_primary_model_id(self.equipped.main_hand.id)
.unwrap_or(0)
}
pub fn get_model_ids(&self, game_data: &mut GameData) -> [u32; 10] {
[
game_data
.get_primary_model_id(self.equipped.head.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(self.equipped.body.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(self.equipped.hands.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(self.equipped.legs.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(self.equipped.feet.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(self.equipped.ears.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(self.equipped.neck.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(self.equipped.wrists.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(self.equipped.left_ring.id)
.unwrap_or(0) as u32,
game_data
.get_primary_model_id(self.equipped.right_ring.id)
.unwrap_or(0) as u32,
]
}
}