From a91c59aaaa53cbad6338a6eb162463ccae57ca02 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sat, 22 Mar 2025 17:00:21 -0400 Subject: [PATCH] Remove hardcoded world id & name, make it configurable Now the world isn't hardcoded to Gilgamesh, and is configurable. It's also now the "Dev" server listed in the excel sheet which makes a more sensible default. --- src/bin/kawari-lobby.rs | 19 ++++++++++--------- src/bin/kawari-world.rs | 16 +++++++++++----- src/common/mod.rs | 26 ++++++++++++++++++++++++++ src/config.rs | 3 +++ src/lib.rs | 6 ------ src/lobby/connection.rs | 9 +++++---- src/world/chat_handler.rs | 9 ++++++--- src/world/database.rs | 17 +++++++++++------ 8 files changed, 72 insertions(+), 33 deletions(-) diff --git a/src/bin/kawari-lobby.rs b/src/bin/kawari-lobby.rs index 581daad..7ec7516 100644 --- a/src/bin/kawari-lobby.rs +++ b/src/bin/kawari-lobby.rs @@ -1,6 +1,8 @@ +use kawari::CONTENT_ID; use kawari::common::custom_ipc::CustomIpcData; use kawari::common::custom_ipc::CustomIpcSegment; use kawari::common::custom_ipc::CustomIpcType; +use kawari::common::get_world_name; use kawari::config::get_config; use kawari::lobby::LobbyConnection; use kawari::lobby::ipc::{ @@ -11,7 +13,6 @@ use kawari::lobby::send_custom_world_packet; use kawari::oodle::OodleNetwork; use kawari::packet::ConnectionType; use kawari::packet::{PacketSegment, PacketState, SegmentType, send_keep_alive}; -use kawari::{CONTENT_ID, WORLD_NAME}; use tokio::io::AsyncReadExt; use tokio::net::TcpListener; @@ -27,6 +28,8 @@ async fn main() { tracing::info!("Lobby server started on {addr}"); + let world_name = get_world_name(config.world.world_id); + loop { let (socket, _) = listener.accept().await.unwrap(); @@ -43,6 +46,8 @@ async fn main() { stored_character_creation_name: String::new(), }; + let world_name = world_name.clone(); + tokio::spawn(async move { let mut buf = [0; 2056]; loop { @@ -136,10 +141,8 @@ async fn main() { character_name: character_action .name .clone(), - origin_server_name: WORLD_NAME - .to_string(), - current_server_name: WORLD_NAME - .to_string(), + origin_server_name: world_name.clone(), + current_server_name: world_name.clone(), ..Default::default() }, }, @@ -241,10 +244,8 @@ async fn main() { character_name: character_action .name .clone(), - origin_server_name: WORLD_NAME - .to_string(), - current_server_name: WORLD_NAME - .to_string(), + origin_server_name: world_name.clone(), + current_server_name: world_name.clone(), ..Default::default() }, }, diff --git a/src/bin/kawari-world.rs b/src/bin/kawari-world.rs index 598fd01..0b1d885 100644 --- a/src/bin/kawari-world.rs +++ b/src/bin/kawari-world.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use kawari::common::custom_ipc::{CustomIpcData, CustomIpcSegment, CustomIpcType}; +use kawari::common::get_world_name; use kawari::config::get_config; use kawari::oodle::OodleNetwork; use kawari::packet::{ @@ -19,7 +20,7 @@ use kawari::world::{ }, }; use kawari::world::{PlayerData, WorldDatabase}; -use kawari::{CHAR_NAME, CITY_STATE, CONTENT_ID, WORLD_ID, ZONE_ID, common::timestamp_secs}; +use kawari::{CHAR_NAME, CITY_STATE, CONTENT_ID, ZONE_ID, common::timestamp_secs}; use physis::common::{Language, Platform}; use physis::gamedata::GameData; use tokio::io::AsyncReadExt; @@ -320,8 +321,8 @@ async fn main() { data: ServerZoneIpcData::PlayerSpawn(PlayerSpawn { content_id: CONTENT_ID, common: CommonSpawn { - current_world_id: WORLD_ID, - home_world_id: WORLD_ID, + current_world_id: config.world.world_id, + home_world_id: config.world.world_id, title: 1, class_job: 35, name: chara_details.name, @@ -802,8 +803,13 @@ async fn main() { } } CustomIpcData::RequestCharacterList { service_account_id } => { - let characters = - database.get_character_list(*service_account_id); + let config = get_config(); + + let characters = database.get_character_list( + *service_account_id, + config.world.world_id, + &get_world_name(config.world.world_id), + ); // send response { diff --git a/src/common/mod.rs b/src/common/mod.rs index 57bedf4..98b2757 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -5,6 +5,12 @@ use std::{ mod customize_data; pub use customize_data::CustomizeData; +use physis::{ + common::{Language, Platform}, + gamedata::GameData, +}; + +use crate::config::get_config; pub mod custom_ipc; @@ -37,3 +43,23 @@ pub fn timestamp_msecs() -> u64 { .try_into() .unwrap() } + +/// Gets the world name from an id into the World Excel sheet. +pub fn get_world_name(world_id: u16) -> String { + 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("World").unwrap(); + let exd = game_data + .read_excel_sheet("World", &exh, Language::None, 0) + .unwrap(); + + let world_row = &exd.read_row(&exh, world_id as u32).unwrap()[0]; + + let physis::exd::ColumnData::String(name) = &world_row.data[1] else { + panic!("Unexpected type!"); + }; + + name.clone() +} diff --git a/src/config.rs b/src/config.rs index d4264bb..34d3337 100644 --- a/src/config.rs +++ b/src/config.rs @@ -170,6 +170,8 @@ impl WebConfig { pub struct WorldConfig { pub port: u16, pub listen_address: String, + /// See the World Excel sheet. + pub world_id: u16, } impl Default for WorldConfig { @@ -177,6 +179,7 @@ impl Default for WorldConfig { Self { port: 7100, listen_address: "127.0.0.1".to_string(), + world_id: 1, // Dev } } } diff --git a/src/lib.rs b/src/lib.rs index c507928..8527171 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,12 +27,6 @@ pub mod packet; /// Logic server-specific code. pub mod login; -// TODO: make this configurable -/// The world ID and name for the lobby. -/// See for a list of possible IDs. -pub const WORLD_ID: u16 = 63; -pub const WORLD_NAME: &str = "KAWARI"; - /// The zone ID you initially spawn in. /// See the TerritoryType excel sheet for a list of possible IDs. pub const ZONE_ID: u16 = 132; diff --git a/src/lobby/connection.rs b/src/lobby/connection.rs index 911ec11..8a78e69 100644 --- a/src/lobby/connection.rs +++ b/src/lobby/connection.rs @@ -3,11 +3,10 @@ use std::cmp::min; use tokio::{io::AsyncReadExt, net::TcpStream}; use crate::{ - WORLD_ID, WORLD_NAME, blowfish::Blowfish, common::{ custom_ipc::{CustomIpcData, CustomIpcSegment, CustomIpcType}, - timestamp_secs, + get_world_name, timestamp_secs, }, config::get_config, oodle::OodleNetwork, @@ -114,12 +113,14 @@ impl LobbyConnection { let mut packets = Vec::new(); // send them the server list { + let config = get_config(); + let mut servers = [Server { - id: WORLD_ID, + id: config.world.world_id, index: 0, flags: 0, icon: 0, - name: WORLD_NAME.to_string(), + name: get_world_name(config.world.world_id), }] .to_vec(); // add any empty boys diff --git a/src/world/chat_handler.rs b/src/world/chat_handler.rs index df43bcd..e96f529 100644 --- a/src/world/chat_handler.rs +++ b/src/world/chat_handler.rs @@ -1,6 +1,7 @@ use crate::{ - CHAR_NAME, CUSTOMIZE_DATA, INVALID_OBJECT_ID, WORLD_ID, + CHAR_NAME, CUSTOMIZE_DATA, INVALID_OBJECT_ID, common::timestamp_secs, + config::get_config, packet::{PacketSegment, SegmentType}, world::ipc::{ ActorControl, ActorControlCategory, CommonSpawn, NpcSpawn, ObjectKind, PlayerSpawn, @@ -66,6 +67,8 @@ impl ChatHandler { .await; } + let config = get_config(); + // send player spawn { let ipc = ServerZoneIpcSegment { @@ -78,8 +81,8 @@ impl ChatHandler { some_unique_id: 1, content_id: 1, common: CommonSpawn { - current_world_id: WORLD_ID, - home_world_id: WORLD_ID, + current_world_id: config.world.world_id, + home_world_id: config.world.world_id, title: 1, class_job: 35, name: CHAR_NAME.to_string(), diff --git a/src/world/database.rs b/src/world/database.rs index 2ae01df..1c378cb 100644 --- a/src/world/database.rs +++ b/src/world/database.rs @@ -3,7 +3,7 @@ use std::sync::Mutex; use rusqlite::Connection; use crate::{ - WORLD_ID, WORLD_NAME, ZONE_ID, + ZONE_ID, lobby::{CharaMake, ClientSelectData, ipc::CharacterDetails}, }; @@ -68,7 +68,12 @@ impl WorldDatabase { stmt.query_row((content_id,), |row| row.get(0)).unwrap() } - pub fn get_character_list(&self, service_account_id: u32) -> Vec { + pub fn get_character_list( + &self, + service_account_id: u32, + world_id: u16, + world_name: &str, + ) -> Vec { let connection = self.connection.lock().unwrap(); let content_actor_ids: Vec<(u32, u32)>; @@ -137,11 +142,11 @@ impl WorldDatabase { content_id: *content_id as u64, index: index as u32, unk1: [0; 16], - origin_server_id: WORLD_ID, - current_server_id: WORLD_ID, + origin_server_id: world_id, + current_server_id: world_id, character_name: name.clone(), - origin_server_name: WORLD_NAME.to_string(), - current_server_name: WORLD_NAME.to_string(), + origin_server_name: world_name.to_string(), + current_server_name: world_name.to_string(), character_detail_json: select_data.to_json(), unk2: [0; 20], });