diff --git a/Cargo.lock b/Cargo.lock index 109c592..a3da88a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1028,7 +1028,7 @@ dependencies = [ [[package]] name = "physis-sheets" version = "0.0.0" -source = "git+https://github.com/redstrate/PhysisSheets#ca42d72fc8a76211d67f6bd4698a45c7da0037fb" +source = "git+https://github.com/redstrate/PhysisSheets#4d11e27a1e31bb482184626d1e7a51fc5e673674" dependencies = [ "physis", ] diff --git a/Cargo.toml b/Cargo.toml index 2cabb8c..495c131 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -104,4 +104,4 @@ rkon = { version = "0.1" } tower-http = { version = "0.6", features = ["fs"] } # excel sheet data -physis-sheets = { git = "https://github.com/redstrate/PhysisSheets", features = ["Warp"], default-features = false } +physis-sheets = { git = "https://github.com/redstrate/PhysisSheets", features = ["Warp", "Tribe", "ClassJob", "World", "TerritoryType", "Race"], default-features = false } diff --git a/src/bin/kawari-lobby.rs b/src/bin/kawari-lobby.rs index 417b5a0..4e1ba45 100644 --- a/src/bin/kawari-lobby.rs +++ b/src/bin/kawari-lobby.rs @@ -27,7 +27,9 @@ async fn main() { tracing::info!("Server started on {addr}"); let mut game_data = GameData::new(); - let world_name = game_data.get_world_name(config.world.world_id); + let world_name = game_data + .get_world_name(config.world.world_id) + .expect("Unknown world name"); loop { let (socket, _) = listener.accept().await.unwrap(); diff --git a/src/common/gamedata.rs b/src/common/gamedata.rs index 879c044..0e3ada4 100644 --- a/src/common/gamedata.rs +++ b/src/common/gamedata.rs @@ -1,7 +1,9 @@ use physis::common::{Language, Platform}; use physis::exd::{EXD, ExcelRowKind}; use physis::exh::EXH; -use physis_sheets::Warp::Warp; +use physis_sheets::ClassJob::ClassJobSheet; +use physis_sheets::World::WorldSheet; +use physis_sheets::{Tribe::TribeSheet, Warp::WarpSheet}; use crate::{common::Attributes, config::get_config}; @@ -44,72 +46,35 @@ impl GameData { } /// Gets the world name from an id into the World Excel sheet. - pub fn get_world_name(&mut self, world_id: u16) -> String { - let exh = self.game_data.read_excel_sheet_header("World").unwrap(); - let exd = self - .game_data - .read_excel_sheet("World", &exh, Language::None, 0) - .unwrap(); + pub fn get_world_name(&mut self, world_id: u16) -> Option { + let sheet = WorldSheet::read_from(&mut self.game_data, Language::None)?; + let row = sheet.get_row(world_id as u32)?; - let ExcelRowKind::SingleRow(world_row) = &exd.get_row(world_id as u32).unwrap() else { - panic!("Expected a single row!") - }; - - let physis::exd::ColumnData::String(name) = &world_row.columns[1] else { - panic!("Unexpected type!"); - }; - - name.clone() + row.Name().into_string().map(|x| x.clone()) } /// Gets the starting city-state from a given class/job id. - pub fn get_citystate(&mut self, classjob_id: u16) -> u8 { - let exh = self.game_data.read_excel_sheet_header("ClassJob").unwrap(); - let exd = self - .game_data - .read_excel_sheet("ClassJob", &exh, Language::English, 0) - .unwrap(); + pub fn get_citystate(&mut self, classjob_id: u16) -> Option { + let sheet = ClassJobSheet::read_from(&mut self.game_data, Language::English)?; + let row = sheet.get_row(classjob_id as u32)?; - let ExcelRowKind::SingleRow(world_row) = &exd.get_row(classjob_id as u32).unwrap() else { - panic!("Expected a single row!") - }; - - let physis::exd::ColumnData::UInt8(town_id) = &world_row.columns[33] else { - panic!("Unexpected type!"); - }; - - *town_id + row.StartingTown().into_u8().map(|x| *x) } - pub fn get_racial_base_attributes(&mut self, tribe_id: u8) -> Attributes { + pub fn get_racial_base_attributes(&mut self, tribe_id: u8) -> Option { // The Tribe Excel sheet only has deltas (e.g. 2 or -2) which are applied to a base 20 number... from somewhere let base_stat = 20; - let exh = self.game_data.read_excel_sheet_header("Tribe").unwrap(); - let exd = self - .game_data - .read_excel_sheet("Tribe", &exh, Language::English, 0) - .unwrap(); + let sheet = TribeSheet::read_from(&mut self.game_data, Language::English)?; + let row = sheet.get_row(tribe_id as u32)?; - let ExcelRowKind::SingleRow(tribe_row) = &exd.get_row(tribe_id as u32).unwrap() else { - panic!("Expected a single row!") - }; - - let get_column = |column_index: usize| { - let physis::exd::ColumnData::Int8(delta) = &tribe_row.columns[column_index] else { - panic!("Unexpected type!"); - }; - - *delta - }; - - Attributes { - strength: (base_stat + get_column(4)) as u32, - dexterity: (base_stat + get_column(6)) as u32, - vitality: (base_stat + get_column(5)) as u32, - intelligence: (base_stat + get_column(7)) as u32, - mind: (base_stat + get_column(8)) as u32, - } + Some(Attributes { + strength: (base_stat + row.STR().into_i8()?) as u32, + dexterity: (base_stat + row.DEX().into_i8()?) as u32, + vitality: (base_stat + row.VIT().into_i8()?) as u32, + intelligence: (base_stat + row.INT().into_i8()?) as u32, + mind: (base_stat + row.MND().into_i8()?) as u32, + }) } /// Gets the primary model ID for a given item ID @@ -133,9 +98,8 @@ impl GameData { /// Returns the pop range object id that's associated with the warp id pub fn get_warp(&mut self, warp_id: u32) -> Option<(u32, u16)> { - let warp_sheet = Warp::read_from(&mut self.game_data, Language::English)?; - - let row = warp_sheet.get_row(warp_id)?; + let sheet = WarpSheet::read_from(&mut self.game_data, Language::English)?; + let row = sheet.get_row(warp_id)?; let pop_range_id = row.PopRange().into_u32()?; let zone_id = row.TerritoryType().into_u16()?; diff --git a/src/inventory/mod.rs b/src/inventory/mod.rs index acf3bfe..cfa15b7 100644 --- a/src/inventory/mod.rs +++ b/src/inventory/mod.rs @@ -1,4 +1,5 @@ -use physis::{common::Language, exd::ExcelRowKind}; +use physis::common::Language; +use physis_sheets::Race::RaceSheet; use serde::{Deserialize, Serialize}; use crate::common::GameData; @@ -122,34 +123,19 @@ impl<'a> Iterator for InventoryIterator<'a> { impl Inventory { /// Equip the starting items for a given race 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(); - - let ExcelRowKind::SingleRow(world_row) = &exd.get_row(race_id as u32).unwrap() else { - panic!("Expected a single row!") - }; - - let get_column = |column_index: usize| { - let physis::exd::ColumnData::Int32(item_id) = &world_row.columns[column_index] else { - panic!("Unexpected type!"); - }; - - *item_id - }; + let sheet = RaceSheet::read_from(&mut game_data.game_data, Language::English).unwrap(); + let row = sheet.get_row(race_id as u32).unwrap(); if gender == 0 { - self.equipped.body = Item::new(1, get_column(2) as u32); - self.equipped.hands = Item::new(1, get_column(3) as u32); - self.equipped.legs = Item::new(1, get_column(4) as u32); - self.equipped.feet = Item::new(1, get_column(5) as u32); + self.equipped.body = Item::new(1, *row.RSEMBody().into_i32().unwrap() as u32); + self.equipped.hands = Item::new(1, *row.RSEMHands().into_i32().unwrap() as u32); + self.equipped.legs = Item::new(1, *row.RSEMLegs().into_i32().unwrap() as u32); + self.equipped.feet = Item::new(1, *row.RSEMFeet().into_i32().unwrap() as u32); } else { - self.equipped.body = Item::new(1, get_column(6) as u32); - self.equipped.hands = Item::new(1, get_column(7) as u32); - self.equipped.legs = Item::new(1, get_column(8) as u32); - self.equipped.feet = Item::new(1, get_column(9) as u32); + self.equipped.body = Item::new(1, *row.RSEFBody().into_i32().unwrap() as u32); + self.equipped.hands = Item::new(1, *row.RSEFHands().into_i32().unwrap() as u32); + self.equipped.legs = Item::new(1, *row.RSEFLegs().into_i32().unwrap() as u32); + self.equipped.feet = Item::new(1, *row.RSEFFeet().into_i32().unwrap() as u32); } // TODO: don't hardcode diff --git a/src/world/connection.rs b/src/world/connection.rs index 53c1d86..d0c1a9b 100644 --- a/src/world/connection.rs +++ b/src/world/connection.rs @@ -834,8 +834,9 @@ impl ZoneConnection { { let mut game_data = self.gamedata.lock().unwrap(); - attributes = - game_data.get_racial_base_attributes(chara_details.chara_make.customize.subrace); + attributes = game_data + .get_racial_base_attributes(chara_details.chara_make.customize.subrace) + .expect("Failed to read racial attributes"); } let ipc = ServerZoneIpcSegment { diff --git a/src/world/custom_ipc_handler.rs b/src/world/custom_ipc_handler.rs index 98cdb03..9c16892 100644 --- a/src/world/custom_ipc_handler.rs +++ b/src/world/custom_ipc_handler.rs @@ -28,7 +28,9 @@ pub async fn handle_custom_ipc(connection: &mut ZoneConnection, data: &CustomIpc { let mut game_data = connection.gamedata.lock().unwrap(); - city_state = game_data.get_citystate(chara_make.classjob_id as u16); + city_state = game_data + .get_citystate(chara_make.classjob_id as u16) + .expect("Unknown citystate"); } let mut inventory = Inventory::default(); @@ -122,7 +124,9 @@ pub async fn handle_custom_ipc(connection: &mut ZoneConnection, data: &CustomIpc let world_name; { let mut game_data = connection.gamedata.lock().unwrap(); - world_name = game_data.get_world_name(config.world.world_id); + world_name = game_data + .get_world_name(config.world.world_id) + .expect("Couldn't read world name"); } let characters; diff --git a/src/world/zone.rs b/src/world/zone.rs index 1988272..d8f4972 100644 --- a/src/world/zone.rs +++ b/src/world/zone.rs @@ -1,11 +1,11 @@ use physis::{ common::Language, - exd::ExcelRowKind, gamedata::GameData, layer::{ ExitRangeInstanceObject, InstanceObject, LayerEntryData, LayerGroup, PopRangeInstanceObject, }, }; +use physis_sheets::TerritoryType::TerritoryTypeSheet; /// Represents a loaded zone #[derive(Default)] @@ -27,25 +27,11 @@ impl Zone { ..Default::default() }; - let Some(exh) = game_data.read_excel_sheet_header("TerritoryType") else { - return zone; - }; - let Some(exd) = game_data.read_excel_sheet("TerritoryType", &exh, Language::None, 0) else { - return zone; - }; - - let Some(territory_type_row) = &exd.get_row(id as u32) else { - return zone; - }; - - let ExcelRowKind::SingleRow(territory_type_row) = territory_type_row else { - panic!("Expected a single row!") - }; + let sheet = TerritoryTypeSheet::read_from(game_data, Language::None).unwrap(); + let row = sheet.get_row(id as u32).unwrap(); // e.g. ffxiv/fst_f1/fld/f1f3/level/f1f3 - let physis::exd::ColumnData::String(bg_path) = &territory_type_row.columns[1] else { - panic!("Unexpected type!"); - }; + let bg_path = row.Bg().into_string().unwrap(); let Some(level_index) = bg_path.find("/level/") else { return zone;