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

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.
This commit is contained in:
Joshua Goins 2025-03-22 17:00:21 -04:00
parent 3f27d2b3df
commit a91c59aaaa
8 changed files with 72 additions and 33 deletions

View file

@ -1,6 +1,8 @@
use kawari::CONTENT_ID;
use kawari::common::custom_ipc::CustomIpcData; use kawari::common::custom_ipc::CustomIpcData;
use kawari::common::custom_ipc::CustomIpcSegment; use kawari::common::custom_ipc::CustomIpcSegment;
use kawari::common::custom_ipc::CustomIpcType; use kawari::common::custom_ipc::CustomIpcType;
use kawari::common::get_world_name;
use kawari::config::get_config; use kawari::config::get_config;
use kawari::lobby::LobbyConnection; use kawari::lobby::LobbyConnection;
use kawari::lobby::ipc::{ use kawari::lobby::ipc::{
@ -11,7 +13,6 @@ use kawari::lobby::send_custom_world_packet;
use kawari::oodle::OodleNetwork; use kawari::oodle::OodleNetwork;
use kawari::packet::ConnectionType; use kawari::packet::ConnectionType;
use kawari::packet::{PacketSegment, PacketState, SegmentType, send_keep_alive}; use kawari::packet::{PacketSegment, PacketState, SegmentType, send_keep_alive};
use kawari::{CONTENT_ID, WORLD_NAME};
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
use tokio::net::TcpListener; use tokio::net::TcpListener;
@ -27,6 +28,8 @@ async fn main() {
tracing::info!("Lobby server started on {addr}"); tracing::info!("Lobby server started on {addr}");
let world_name = get_world_name(config.world.world_id);
loop { loop {
let (socket, _) = listener.accept().await.unwrap(); let (socket, _) = listener.accept().await.unwrap();
@ -43,6 +46,8 @@ async fn main() {
stored_character_creation_name: String::new(), stored_character_creation_name: String::new(),
}; };
let world_name = world_name.clone();
tokio::spawn(async move { tokio::spawn(async move {
let mut buf = [0; 2056]; let mut buf = [0; 2056];
loop { loop {
@ -136,10 +141,8 @@ async fn main() {
character_name: character_action character_name: character_action
.name .name
.clone(), .clone(),
origin_server_name: WORLD_NAME origin_server_name: world_name.clone(),
.to_string(), current_server_name: world_name.clone(),
current_server_name: WORLD_NAME
.to_string(),
..Default::default() ..Default::default()
}, },
}, },
@ -241,10 +244,8 @@ async fn main() {
character_name: character_action character_name: character_action
.name .name
.clone(), .clone(),
origin_server_name: WORLD_NAME origin_server_name: world_name.clone(),
.to_string(), current_server_name: world_name.clone(),
current_server_name: WORLD_NAME
.to_string(),
..Default::default() ..Default::default()
}, },
}, },

View file

@ -1,6 +1,7 @@
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::config::get_config; use kawari::config::get_config;
use kawari::oodle::OodleNetwork; use kawari::oodle::OodleNetwork;
use kawari::packet::{ use kawari::packet::{
@ -19,7 +20,7 @@ use kawari::world::{
}, },
}; };
use kawari::world::{PlayerData, WorldDatabase}; 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::common::{Language, Platform};
use physis::gamedata::GameData; use physis::gamedata::GameData;
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
@ -320,8 +321,8 @@ async fn main() {
data: ServerZoneIpcData::PlayerSpawn(PlayerSpawn { data: ServerZoneIpcData::PlayerSpawn(PlayerSpawn {
content_id: CONTENT_ID, content_id: CONTENT_ID,
common: CommonSpawn { common: CommonSpawn {
current_world_id: WORLD_ID, current_world_id: config.world.world_id,
home_world_id: WORLD_ID, home_world_id: config.world.world_id,
title: 1, title: 1,
class_job: 35, class_job: 35,
name: chara_details.name, name: chara_details.name,
@ -802,8 +803,13 @@ async fn main() {
} }
} }
CustomIpcData::RequestCharacterList { service_account_id } => { CustomIpcData::RequestCharacterList { service_account_id } => {
let characters = let config = get_config();
database.get_character_list(*service_account_id);
let characters = database.get_character_list(
*service_account_id,
config.world.world_id,
&get_world_name(config.world.world_id),
);
// send response // send response
{ {

View file

@ -5,6 +5,12 @@ use std::{
mod customize_data; mod customize_data;
pub use customize_data::CustomizeData; pub use customize_data::CustomizeData;
use physis::{
common::{Language, Platform},
gamedata::GameData,
};
use crate::config::get_config;
pub mod custom_ipc; pub mod custom_ipc;
@ -37,3 +43,23 @@ pub fn timestamp_msecs() -> u64 {
.try_into() .try_into()
.unwrap() .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()
}

View file

@ -170,6 +170,8 @@ impl WebConfig {
pub struct WorldConfig { pub struct WorldConfig {
pub port: u16, pub port: u16,
pub listen_address: String, pub listen_address: String,
/// See the World Excel sheet.
pub world_id: u16,
} }
impl Default for WorldConfig { impl Default for WorldConfig {
@ -177,6 +179,7 @@ impl Default for WorldConfig {
Self { Self {
port: 7100, port: 7100,
listen_address: "127.0.0.1".to_string(), listen_address: "127.0.0.1".to_string(),
world_id: 1, // Dev
} }
} }
} }

View file

@ -27,12 +27,6 @@ pub mod packet;
/// Logic server-specific code. /// Logic server-specific code.
pub mod login; pub mod login;
// TODO: make this configurable
/// The world ID and name for the lobby.
/// See <https://ffxiv.consolegameswiki.com/wiki/Servers> 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. /// The zone ID you initially spawn in.
/// See the TerritoryType excel sheet for a list of possible IDs. /// See the TerritoryType excel sheet for a list of possible IDs.
pub const ZONE_ID: u16 = 132; pub const ZONE_ID: u16 = 132;

View file

@ -3,11 +3,10 @@ use std::cmp::min;
use tokio::{io::AsyncReadExt, net::TcpStream}; use tokio::{io::AsyncReadExt, net::TcpStream};
use crate::{ use crate::{
WORLD_ID, WORLD_NAME,
blowfish::Blowfish, blowfish::Blowfish,
common::{ common::{
custom_ipc::{CustomIpcData, CustomIpcSegment, CustomIpcType}, custom_ipc::{CustomIpcData, CustomIpcSegment, CustomIpcType},
timestamp_secs, get_world_name, timestamp_secs,
}, },
config::get_config, config::get_config,
oodle::OodleNetwork, oodle::OodleNetwork,
@ -114,12 +113,14 @@ impl LobbyConnection {
let mut packets = Vec::new(); let mut packets = Vec::new();
// send them the server list // send them the server list
{ {
let config = get_config();
let mut servers = [Server { let mut servers = [Server {
id: WORLD_ID, id: config.world.world_id,
index: 0, index: 0,
flags: 0, flags: 0,
icon: 0, icon: 0,
name: WORLD_NAME.to_string(), name: get_world_name(config.world.world_id),
}] }]
.to_vec(); .to_vec();
// add any empty boys // add any empty boys

View file

@ -1,6 +1,7 @@
use crate::{ use crate::{
CHAR_NAME, CUSTOMIZE_DATA, INVALID_OBJECT_ID, WORLD_ID, CHAR_NAME, CUSTOMIZE_DATA, INVALID_OBJECT_ID,
common::timestamp_secs, common::timestamp_secs,
config::get_config,
packet::{PacketSegment, SegmentType}, packet::{PacketSegment, SegmentType},
world::ipc::{ world::ipc::{
ActorControl, ActorControlCategory, CommonSpawn, NpcSpawn, ObjectKind, PlayerSpawn, ActorControl, ActorControlCategory, CommonSpawn, NpcSpawn, ObjectKind, PlayerSpawn,
@ -66,6 +67,8 @@ impl ChatHandler {
.await; .await;
} }
let config = get_config();
// send player spawn // send player spawn
{ {
let ipc = ServerZoneIpcSegment { let ipc = ServerZoneIpcSegment {
@ -78,8 +81,8 @@ impl ChatHandler {
some_unique_id: 1, some_unique_id: 1,
content_id: 1, content_id: 1,
common: CommonSpawn { common: CommonSpawn {
current_world_id: WORLD_ID, current_world_id: config.world.world_id,
home_world_id: WORLD_ID, home_world_id: config.world.world_id,
title: 1, title: 1,
class_job: 35, class_job: 35,
name: CHAR_NAME.to_string(), name: CHAR_NAME.to_string(),

View file

@ -3,7 +3,7 @@ use std::sync::Mutex;
use rusqlite::Connection; use rusqlite::Connection;
use crate::{ use crate::{
WORLD_ID, WORLD_NAME, ZONE_ID, ZONE_ID,
lobby::{CharaMake, ClientSelectData, ipc::CharacterDetails}, lobby::{CharaMake, ClientSelectData, ipc::CharacterDetails},
}; };
@ -68,7 +68,12 @@ impl WorldDatabase {
stmt.query_row((content_id,), |row| row.get(0)).unwrap() stmt.query_row((content_id,), |row| row.get(0)).unwrap()
} }
pub fn get_character_list(&self, service_account_id: u32) -> Vec<CharacterDetails> { pub fn get_character_list(
&self,
service_account_id: u32,
world_id: u16,
world_name: &str,
) -> Vec<CharacterDetails> {
let connection = self.connection.lock().unwrap(); let connection = self.connection.lock().unwrap();
let content_actor_ids: Vec<(u32, u32)>; let content_actor_ids: Vec<(u32, u32)>;
@ -137,11 +142,11 @@ impl WorldDatabase {
content_id: *content_id as u64, content_id: *content_id as u64,
index: index as u32, index: index as u32,
unk1: [0; 16], unk1: [0; 16],
origin_server_id: WORLD_ID, origin_server_id: world_id,
current_server_id: WORLD_ID, current_server_id: world_id,
character_name: name.clone(), character_name: name.clone(),
origin_server_name: WORLD_NAME.to_string(), origin_server_name: world_name.to_string(),
current_server_name: WORLD_NAME.to_string(), current_server_name: world_name.to_string(),
character_detail_json: select_data.to_json(), character_detail_json: select_data.to_json(),
unk2: [0; 20], unk2: [0; 20],
}); });