1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-04-27 17:07:46 +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::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()
},
},

View file

@ -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
{

View file

@ -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()
}

View file

@ -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
}
}
}

View file

@ -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 <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.
/// See the TerritoryType excel sheet for a list of possible IDs.
pub const ZONE_ID: u16 = 132;

View file

@ -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

View file

@ -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(),

View file

@ -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<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 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],
});