2025-03-22 16:47:21 -04:00
use std ::{
net ::{ IpAddr , SocketAddr } ,
str ::FromStr ,
} ;
2023-10-05 12:09:05 -04:00
use serde ::{ Deserialize , Serialize } ;
2025-03-22 16:47:21 -04:00
/// Configuration for the admin server.
2023-10-05 12:09:05 -04:00
#[ derive(Serialize, Deserialize) ]
2025-03-22 16:47:21 -04:00
pub struct AdminConfig {
pub port : u16 ,
pub listen_address : String ,
}
2024-06-29 14:06:44 -04:00
2025-03-22 16:47:21 -04:00
impl Default for AdminConfig {
fn default ( ) -> Self {
Self {
port : 5800 ,
listen_address : " 127.0.0.1 " . to_string ( ) ,
}
}
}
impl AdminConfig {
/// Returns the configured IP address & port as a `SocketAddr`.
pub fn get_socketaddr ( & self ) -> SocketAddr {
SocketAddr ::from ( (
IpAddr ::from_str ( & self . listen_address ) . expect ( " Invalid IP address format in config! " ) ,
self . port ,
) )
}
}
/// Configuration for the frontier server.
#[ derive(Serialize, Deserialize) ]
pub struct FrontierConfig {
pub port : u16 ,
pub listen_address : String ,
pub worlds_open : bool ,
2024-06-29 14:06:44 -04:00
pub login_open : bool ,
2025-03-22 16:47:21 -04:00
}
impl Default for FrontierConfig {
fn default ( ) -> Self {
Self {
port : 5857 ,
listen_address : " 127.0.0.1 " . to_string ( ) ,
worlds_open : true ,
login_open : true ,
}
}
}
impl FrontierConfig {
/// Returns the configured IP address & port as a `SocketAddr`.
pub fn get_socketaddr ( & self ) -> SocketAddr {
SocketAddr ::from ( (
IpAddr ::from_str ( & self . listen_address ) . expect ( " Invalid IP address format in config! " ) ,
self . port ,
) )
}
}
/// Configuration for the lobby server.
#[ derive(Serialize, Deserialize) ]
pub struct LobbyConfig {
pub port : u16 ,
pub listen_address : String ,
}
impl Default for LobbyConfig {
fn default ( ) -> Self {
Self {
port : 7000 ,
listen_address : " 127.0.0.1 " . to_string ( ) ,
}
}
}
impl LobbyConfig {
/// Returns the configured IP address & port as a `SocketAddr`.
pub fn get_socketaddr ( & self ) -> SocketAddr {
SocketAddr ::from ( (
IpAddr ::from_str ( & self . listen_address ) . expect ( " Invalid IP address format in config! " ) ,
self . port ,
) )
}
}
2024-05-11 13:41:00 -04:00
2025-03-22 16:47:21 -04:00
/// Configuration for the login server.
#[ derive(Serialize, Deserialize) ]
pub struct LoginConfig {
pub port : u16 ,
pub listen_address : String ,
2025-04-05 22:40:44 -04:00
/// Public-facing domain of the server.
pub server_name : String ,
2025-03-22 16:47:21 -04:00
}
impl Default for LoginConfig {
fn default ( ) -> Self {
Self {
port : 6700 ,
listen_address : " 127.0.0.1 " . to_string ( ) ,
2025-04-05 22:40:44 -04:00
server_name : " ffxiv-login.square.localhost " . to_string ( ) ,
2025-03-22 16:47:21 -04:00
}
}
}
impl LoginConfig {
/// Returns the configured IP address & port as a `SocketAddr`.
pub fn get_socketaddr ( & self ) -> SocketAddr {
SocketAddr ::from ( (
IpAddr ::from_str ( & self . listen_address ) . expect ( " Invalid IP address format in config! " ) ,
self . port ,
) )
}
}
/// Configuration for the patch server.
#[ derive(Serialize, Deserialize) ]
pub struct PatchConfig {
pub port : u16 ,
pub listen_address : String ,
2025-03-23 07:35:11 -04:00
/// Publicly accessible URL to download patches from.
/// For example, "patch-dl.ffxiv.localhost". Patch files must be served so they're accessible as: "http://patch-dl.ffxiv.localhost/game/ex4/somepatchfilename.patch"
pub patch_dl_url : String ,
/// Location of the patches directory on disk. Must be setup like so:
2025-03-23 08:21:43 -04:00
/// ```ignore
2025-03-23 07:35:11 -04:00
/// <channel> (e.g. ffxivneo_release_game) /
/// game/
/// ex1/
/// ...
/// ```
pub patches_location : String ,
2025-05-03 18:49:39 -04:00
pub game_server_name : String ,
pub boot_server_name : String ,
2025-03-22 16:47:21 -04:00
}
impl Default for PatchConfig {
fn default ( ) -> Self {
Self {
port : 6900 ,
listen_address : " 127.0.0.1 " . to_string ( ) ,
2025-03-23 07:35:11 -04:00
patch_dl_url : " patch-dl.ffxiv.localhost " . to_string ( ) ,
patches_location : String ::new ( ) ,
2025-05-03 18:49:39 -04:00
boot_server_name : " patch-bootver.ffxiv.localhost " . to_string ( ) ,
game_server_name : " patch-gamever.ffxiv.localhost " . to_string ( ) ,
2025-03-22 16:47:21 -04:00
}
}
}
impl PatchConfig {
/// Returns the configured IP address & port as a `SocketAddr`.
pub fn get_socketaddr ( & self ) -> SocketAddr {
SocketAddr ::from ( (
IpAddr ::from_str ( & self . listen_address ) . expect ( " Invalid IP address format in config! " ) ,
self . port ,
) )
}
}
/// Configuration for the web server.
#[ derive(Serialize, Deserialize) ]
pub struct WebConfig {
pub port : u16 ,
pub listen_address : String ,
2025-04-05 22:40:44 -04:00
/// Public-facing domain of the server.
pub server_name : String ,
2025-03-22 16:47:21 -04:00
}
impl Default for WebConfig {
fn default ( ) -> Self {
Self {
port : 5801 ,
listen_address : " 127.0.0.1 " . to_string ( ) ,
2025-04-05 22:40:44 -04:00
server_name : " ffxiv.localhost " . to_string ( ) ,
2025-03-22 16:47:21 -04:00
}
}
}
impl WebConfig {
/// Returns the configured IP address & port as a `SocketAddr`.
pub fn get_socketaddr ( & self ) -> SocketAddr {
SocketAddr ::from ( (
IpAddr ::from_str ( & self . listen_address ) . expect ( " Invalid IP address format in config! " ) ,
self . port ,
) )
}
}
/// Configuration for the world server.
#[ derive(Serialize, Deserialize) ]
pub struct WorldConfig {
2025-04-15 23:35:49 -04:00
#[ serde(default = " WorldConfig::default_port " ) ]
2025-03-22 16:47:21 -04:00
pub port : u16 ,
2025-04-15 23:35:49 -04:00
#[ serde(default = " WorldConfig::default_listen_address " ) ]
2025-03-22 16:47:21 -04:00
pub listen_address : String ,
2025-03-22 17:00:21 -04:00
/// See the World Excel sheet.
2025-04-15 23:35:49 -04:00
#[ serde(default = " WorldConfig::default_world_id " ) ]
2025-03-22 17:00:21 -04:00
pub world_id : u16 ,
2025-03-27 16:20:33 -04:00
/// Location of the scripts directory.
/// Defaults to a sensible value if the project is self-built.
2025-04-15 23:35:49 -04:00
#[ serde(default = " WorldConfig::default_scripts_location " ) ]
2025-03-27 16:20:33 -04:00
pub scripts_location : String ,
2025-04-15 23:35:49 -04:00
/// Port of the RCON server.
#[ serde(default = " WorldConfig::default_rcon_port " ) ]
pub rcon_port : u16 ,
/// Password of the RCON server, if left blank (the default) RCON is disabled.
#[ serde(default = " WorldConfig::default_rcon_password " ) ]
pub rcon_password : String ,
2025-04-30 22:37:57 -04:00
/// Enable packet obsfucation. There's literally no reason to do this!
#[ serde(default = " WorldConfig::default_packet_obsfucation " ) ]
pub enable_packet_obsfucation : bool ,
2025-05-02 22:41:31 -04:00
/// Enable packet compression for packets from the server. It's recommended to keep this on.
#[ serde(default = " WorldConfig::default_packet_compression " ) ]
pub enable_packet_compression : bool ,
2025-03-22 16:47:21 -04:00
}
impl Default for WorldConfig {
fn default ( ) -> Self {
Self {
2025-04-15 23:35:49 -04:00
port : Self ::default_port ( ) ,
listen_address : Self ::default_listen_address ( ) ,
world_id : Self ::default_world_id ( ) ,
scripts_location : Self ::default_scripts_location ( ) ,
rcon_port : Self ::default_rcon_port ( ) ,
rcon_password : Self ::default_rcon_password ( ) ,
2025-04-30 22:37:57 -04:00
enable_packet_obsfucation : Self ::default_packet_obsfucation ( ) ,
2025-05-02 22:41:31 -04:00
enable_packet_compression : Self ::default_packet_compression ( ) ,
2025-03-22 16:47:21 -04:00
}
}
}
2025-04-15 23:35:49 -04:00
impl WorldConfig {
fn default_port ( ) -> u16 {
7100
}
fn default_listen_address ( ) -> String {
" 127.0.0.1 " . to_string ( )
}
fn default_world_id ( ) -> u16 {
63 // Gilgamesh
}
fn default_scripts_location ( ) -> String {
" resources/scripts " . to_string ( )
}
fn default_rcon_port ( ) -> u16 {
25575
}
fn default_rcon_password ( ) -> String {
String ::default ( )
}
2025-04-30 22:37:57 -04:00
fn default_packet_obsfucation ( ) -> bool {
false
}
2025-05-02 22:41:31 -04:00
fn default_packet_compression ( ) -> bool {
true
}
2025-04-15 23:35:49 -04:00
}
2025-03-22 16:47:21 -04:00
impl WorldConfig {
/// Returns the configured IP address & port as a `SocketAddr`.
pub fn get_socketaddr ( & self ) -> SocketAddr {
SocketAddr ::from ( (
IpAddr ::from_str ( & self . listen_address ) . expect ( " Invalid IP address format in config! " ) ,
self . port ,
) )
}
2025-04-15 23:35:49 -04:00
/// Returns the configured IP address & port as a `SocketAddr` for RCON.
pub fn get_rcon_socketaddr ( & self ) -> SocketAddr {
SocketAddr ::from ( (
IpAddr ::from_str ( & self . listen_address ) . expect ( " Invalid IP address format in config! " ) ,
self . rcon_port ,
) )
}
2025-03-22 16:47:21 -04:00
}
2025-04-22 16:00:10 -04:00
/// Configuration for the launcher server.
#[ derive(Serialize, Deserialize) ]
pub struct LauncherConfig {
pub port : u16 ,
pub listen_address : String ,
2025-05-03 18:49:39 -04:00
pub server_name : String ,
2025-04-22 16:00:10 -04:00
}
impl Default for LauncherConfig {
fn default ( ) -> Self {
Self {
port : 5802 ,
listen_address : " 127.0.0.1 " . to_string ( ) ,
2025-05-03 18:49:39 -04:00
server_name : " launcher.ffxiv.localhost " . to_string ( ) ,
2025-04-22 16:00:10 -04:00
}
}
}
impl LauncherConfig {
/// Returns the configured IP address & port as a `SocketAddr`.
pub fn get_socketaddr ( & self ) -> SocketAddr {
SocketAddr ::from ( (
IpAddr ::from_str ( & self . listen_address ) . expect ( " Invalid IP address format in config! " ) ,
self . port ,
) )
}
}
2025-04-22 18:46:04 -04:00
/// Configuration for the save data bank server.
#[ derive(Serialize, Deserialize) ]
pub struct SaveDataBankConfig {
pub port : u16 ,
pub listen_address : String ,
}
impl Default for SaveDataBankConfig {
fn default ( ) -> Self {
Self {
port : 5803 ,
listen_address : " 127.0.0.1 " . to_string ( ) ,
}
}
}
impl SaveDataBankConfig {
/// Returns the configured IP address & port as a `SocketAddr`.
pub fn get_socketaddr ( & self ) -> SocketAddr {
SocketAddr ::from ( (
IpAddr ::from_str ( & self . listen_address ) . expect ( " Invalid IP address format in config! " ) ,
self . port ,
) )
}
}
2025-03-22 16:47:21 -04:00
/// Global and all-encompassing config.
/// Settings that affect all servers belong here.
#[ derive(Serialize, Deserialize) ]
pub struct Config {
2024-05-11 13:41:00 -04:00
#[ serde(default = " default_supported_platforms " ) ]
pub supported_platforms : Vec < String > ,
2024-06-29 14:44:13 -04:00
2025-03-15 19:34:29 -04:00
#[ serde(default) ]
pub game_location : String ,
2025-03-22 16:47:21 -04:00
#[ serde(default) ]
pub admin : AdminConfig ,
#[ serde(default) ]
pub frontier : FrontierConfig ,
#[ serde(default) ]
pub lobby : LobbyConfig ,
#[ serde(default) ]
pub login : LoginConfig ,
#[ serde(default) ]
pub patch : PatchConfig ,
#[ serde(default) ]
pub web : WebConfig ,
#[ serde(default) ]
pub world : WorldConfig ,
2025-04-01 16:58:39 -04:00
2025-04-22 16:00:10 -04:00
#[ serde(default) ]
pub launcher : LauncherConfig ,
2025-04-22 18:46:04 -04:00
#[ serde(default) ]
pub save_data_bank : SaveDataBankConfig ,
2025-04-01 16:58:39 -04:00
/// Enable various packet debug functions. This will clutter your working directory!
#[ serde(default) ]
pub packet_debugging : bool ,
2024-05-11 13:13:03 -04:00
}
impl Default for Config {
fn default ( ) -> Self {
Self {
2025-03-08 13:27:41 -05:00
supported_platforms : default_supported_platforms ( ) ,
2025-03-15 19:34:29 -04:00
game_location : String ::new ( ) ,
2025-03-22 16:47:21 -04:00
admin : AdminConfig ::default ( ) ,
frontier : FrontierConfig ::default ( ) ,
lobby : LobbyConfig ::default ( ) ,
login : LoginConfig ::default ( ) ,
patch : PatchConfig ::default ( ) ,
web : WebConfig ::default ( ) ,
world : WorldConfig ::default ( ) ,
2025-04-22 16:00:10 -04:00
launcher : LauncherConfig ::default ( ) ,
2025-04-22 18:46:04 -04:00
save_data_bank : SaveDataBankConfig ::default ( ) ,
2025-04-01 16:58:39 -04:00
packet_debugging : false ,
2024-05-11 13:13:03 -04:00
}
}
2024-05-11 13:41:00 -04:00
}
impl Config {
pub fn supports_platform ( & self , platform : & String ) -> bool {
self . supported_platforms . contains ( platform )
}
}
fn default_supported_platforms ( ) -> Vec < String > {
vec! [ " win32 " . to_string ( ) ]
}
pub fn get_config ( ) -> Config {
2025-03-22 16:47:21 -04:00
if let Ok ( data ) = std ::fs ::read_to_string ( " config.yaml " ) {
serde_yaml_ng ::from_str ( & data ) . expect ( " Failed to parse " )
2024-05-11 13:41:00 -04:00
} else {
Config ::default ( )
}
2025-03-08 13:27:41 -05:00
}