Server configuration rework

This commit is contained in:
xeon 2024-05-24 19:45:45 +03:00
parent 934ad89fdf
commit eb641d67fb
17 changed files with 75 additions and 81 deletions

11
.gitignore vendored
View file

@ -1,18 +1,9 @@
# ---> Rust
# Generated by Cargo
# will have compiled files and executables
debug/ debug/
target/ target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries /*.json
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk **/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb *.pdb
# Visual Studio crap
.vs/ .vs/

View file

@ -1,5 +1,5 @@
[workspace] [workspace]
members = ["gameserver", "protocol", "qwer", "qwer/qwer-derive", "sdkserver"] members = [ "common","gameserver", "protocol", "qwer", "qwer/qwer-derive", "sdkserver"]
resolver = "2" resolver = "2"
[workspace.package] [workspace.package]
@ -41,6 +41,7 @@ tracing-subscriber = { version = "0.3.18", features = [
] } ] }
tracing-bunyan-formatter = "0.3.9" tracing-bunyan-formatter = "0.3.9"
common = { version = "0.1.0", path = "common" }
protocol = { version = "0.1.0", path = "protocol" } protocol = { version = "0.1.0", path = "protocol" }
qwer = { version = "0.1.0", path = "qwer", features = ["full"] } qwer = { version = "0.1.0", path = "qwer", features = ["full"] }
qwer-derive = { version = "0.1.0", path = "qwer/qwer-derive" } qwer-derive = { version = "0.1.0", path = "qwer/qwer-derive" }

View file

@ -55,14 +55,9 @@ run the following in a terminal:
## Configuration ## Configuration
The game server can be configured using a `.env` file. The file contains one configurable The game server can be configured using a `gameserver.json` file.
option, `SKIP_TUTORIAL`, which is set to 0 by default. Configuration file with default settings will be created in
the working directory upon first startup.
If you have a `.env` file in the **same** directory as your executable, then this
is the file that will be loaded. Otherwise, upon _first_ running the `gameserver`
executable, it will create `{FOLDERID_RoamingAppData}\nap-gameserver\.env`
(`C:\Users\{user}\AppData\Roaming\nap-gameserver\.env`) for you, and will source
from this config instead.
## Contributing ## Contributing

6
common/Cargo.toml Normal file
View file

@ -0,0 +1,6 @@
[package]
name = "common"
edition = "2021"
version.workspace = true
[dependencies]

1
common/src/lib.rs Normal file
View file

@ -0,0 +1 @@
pub mod util;

9
common/src/util.rs Normal file
View file

@ -0,0 +1,9 @@
pub fn load_or_create_config(path: &str, defaults: &str) -> String {
std::fs::read_to_string(path).map_or_else(
|_| {
std::fs::write(path, defaults).unwrap();
defaults.to_string()
},
|data| data,
)
}

View file

@ -8,7 +8,6 @@ ansi_term.workspace = true
anyhow.workspace = true anyhow.workspace = true
atomic_refcell.workspace = true atomic_refcell.workspace = true
dirs.workspace = true dirs.workspace = true
dotenv.workspace = true
env_logger.workspace = true env_logger.workspace = true
hex.workspace = true hex.workspace = true
lazy_static.workspace = true lazy_static.workspace = true
@ -27,6 +26,7 @@ tracing-log.workspace = true
tracing-subscriber.workspace = true tracing-subscriber.workspace = true
tracing-bunyan-formatter.workspace = true tracing-bunyan-formatter.workspace = true
common.workspace = true
protocol.workspace = true protocol.workspace = true
qwer.workspace = true qwer.workspace = true

View file

@ -0,0 +1,5 @@
{
"gateway_endpoint": "0.0.0.0:10301",
"skip_tutorial": false,
"system_resources_logging": false
}

22
gameserver/src/config.rs Normal file
View file

@ -0,0 +1,22 @@
use common::util::load_or_create_config;
use lazy_static::lazy_static;
use serde::Deserialize;
const DEFAULT_CONFIG: &str = include_str!("../gameserver.default.json");
#[derive(Deserialize)]
pub struct GameServerConfig {
pub gateway_endpoint: String,
pub skip_tutorial: bool,
pub system_resources_logging: bool,
}
lazy_static! {
pub static ref CONFIGURATION: GameServerConfig =
serde_json::from_str(&load_or_create_config("gameserver.json", DEFAULT_CONFIG))
.expect("Failed to parse server configuration file");
}
pub fn init_config() {
let _configuration = &*CONFIGURATION; // init static
}

View file

@ -1,11 +0,0 @@
use std::env;
use lazy_static::lazy_static;
lazy_static! {
static ref SKIP_TUTORIAL: i32 = env::var("SKIP_TUTORIAL").map_or(0, |v| v.parse().unwrap());
}
pub fn should_skip_tutorial() -> bool {
*SKIP_TUTORIAL != 0
}

View file

@ -1,6 +1,5 @@
mod context; mod context;
pub mod data; pub mod data;
pub mod globals;
pub mod manager; pub mod manager;
pub mod util; pub mod util;

View file

@ -23,7 +23,10 @@ macro_rules! log_error {
}; };
} }
pub fn init_tracing() { pub fn init_logging() {
#[cfg(target_os = "windows")]
ansi_term::enable_ansi_support().unwrap();
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
} }

View file

@ -1,56 +1,28 @@
use std::path::Path;
use anyhow::Result; use anyhow::Result;
use config::init_assets;
use tracing::Level; use tracing::Level;
mod config; mod config;
mod data;
mod game; mod game;
mod logging; mod logging;
mod net; mod net;
use logging::{init_system_logging, init_tracing}; use config::{init_config, CONFIGURATION};
use data::init_assets;
const GATE_HOST: &str = "0.0.0.0"; use logging::{init_logging, init_system_logging};
const GATE_PORT: u16 = 10301;
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
#[cfg(target_os = "windows")] init_logging();
ansi_term::enable_ansi_support().unwrap(); init_config();
init_config()?;
init_assets()?; init_assets()?;
init_tracing();
let span = tracing::span!(Level::DEBUG, "main"); let span = tracing::span!(Level::DEBUG, "main");
let _enter = span.enter(); let _enter = span.enter();
if CONFIGURATION.system_resources_logging {
init_system_logging().await; init_system_logging().await;
net::gateway::listen(GATE_HOST, GATE_PORT).await?;
Ok(())
} }
fn init_config() -> Result<()> { net::gateway::listen(&CONFIGURATION.gateway_endpoint).await
let local_dotenv = Path::new(".env");
if local_dotenv.exists() {
dotenv::dotenv()?;
} else {
let config = dirs::config_dir()
.ok_or_else(|| anyhow::anyhow!("No config directory found"))?
.join("nap-gameserver");
std::fs::create_dir_all(&config)?;
let env = config.join(".env");
if !env.exists() {
std::fs::write(&env, "SKIP_TUTORIAL=0")?;
}
dotenv::from_path(&env)?;
}
Ok(())
} }

View file

@ -6,9 +6,9 @@ use crate::log_error;
use super::NetworkSession; use super::NetworkSession;
pub async fn listen(host: &str, port: u16) -> Result<()> { pub async fn listen(bind_addr: &str) -> Result<()> {
let listener = TcpListener::bind(format!("{host}:{port}")).await?; let listener = TcpListener::bind(bind_addr).await?;
tracing::info!("Listening at {host}:{port}"); tracing::info!("Listening at {bind_addr}");
loop { loop {
let Ok((client_socket, client_addr)) = listener.accept().await else { let Ok((client_socket, client_addr)) = listener.accept().await else {

View file

@ -2,8 +2,9 @@ use qwer::{
pdkhashmap, phashmap, phashset, PropertyDoubleKeyHashMap, PropertyHashMap, PropertyHashSet, pdkhashmap, phashmap, phashset, PropertyDoubleKeyHashMap, PropertyHashMap, PropertyHashSet,
}; };
use crate::config; use crate::config::CONFIGURATION;
use crate::game::{globals, util}; use crate::data;
use crate::game::util;
use super::*; use super::*;
@ -17,7 +18,7 @@ pub async fn on_rpc_run_event_graph_arg(
let unit = scene_unit_mgr.get(arg.owner_uid); let unit = scene_unit_mgr.get(arg.owner_uid);
let SceneUnitProtocolInfo::NpcProtocolInfo { tag, id, .. } = unit; let SceneUnitProtocolInfo::NpcProtocolInfo { tag, id, .. } = unit;
let main_city_object = config::get_main_city_object(tag, id).unwrap(); let main_city_object = data::get_main_city_object(tag, id).unwrap();
let mut ptc_sync_event_info = PtcSyncEventInfoArg { let mut ptc_sync_event_info = PtcSyncEventInfoArg {
owner_type: EventGraphOwnerType::SceneUnit, owner_type: EventGraphOwnerType::SceneUnit,
@ -89,7 +90,7 @@ pub async fn on_rpc_interact_with_unit_arg(
let unit = scene_unit_mgr.get(arg.unit_uid); let unit = scene_unit_mgr.get(arg.unit_uid);
let SceneUnitProtocolInfo::NpcProtocolInfo { tag, id, .. } = unit; let SceneUnitProtocolInfo::NpcProtocolInfo { tag, id, .. } = unit;
let main_city_object = config::get_main_city_object(tag, id).unwrap(); let main_city_object = data::get_main_city_object(tag, id).unwrap();
let mut ptc_sync_event_info = PtcSyncEventInfoArg { let mut ptc_sync_event_info = PtcSyncEventInfoArg {
owner_type: EventGraphOwnerType::SceneUnit, owner_type: EventGraphOwnerType::SceneUnit,
@ -152,7 +153,7 @@ fn create_player(id: u64) -> PlayerInfo {
z: 11.18, z: 11.18,
}); });
if globals::should_skip_tutorial() { if CONFIGURATION.skip_tutorial {
let beginner_procedure = player.beginner_procedure_info.as_mut().unwrap(); let beginner_procedure = player.beginner_procedure_info.as_mut().unwrap();
beginner_procedure.procedure_info.replace(6); beginner_procedure.procedure_info.replace(6);
player.nick_name.replace(String::from("xeondev")); player.nick_name.replace(String::from("xeondev"));
@ -207,7 +208,7 @@ pub async fn on_rpc_enter_world_arg(
item_manager.add_resource(10, 228); item_manager.add_resource(10, 228);
item_manager.add_resource(100, 1337); item_manager.add_resource(100, 1337);
for avatar_id in config::iter_avatar_config_collection() for avatar_id in data::iter_avatar_config_collection()
.map(|c| c.id) .map(|c| c.id)
.filter(|id| *id < 2000) .filter(|id| *id < 2000)
{ {
@ -215,7 +216,7 @@ pub async fn on_rpc_enter_world_arg(
} }
let unlock_manager = session.context.unlock_manager.borrow(); let unlock_manager = session.context.unlock_manager.borrow();
for unlock_id in config::iter_unlock_config_collection().map(|c| c.id) { for unlock_id in data::iter_unlock_config_collection().map(|c| c.id) {
unlock_manager.unlock(unlock_id); unlock_manager.unlock(unlock_id);
} }
@ -257,7 +258,7 @@ pub async fn on_rpc_enter_world_arg(
let yorozuya_quest_manager = session.context.yorozuya_quest_manager.borrow(); let yorozuya_quest_manager = session.context.yorozuya_quest_manager.borrow();
yorozuya_quest_manager.add_hollow_quest(102, HollowQuestType::SideQuest, 10010002); yorozuya_quest_manager.add_hollow_quest(102, HollowQuestType::SideQuest, 10010002);
if globals::should_skip_tutorial() { if CONFIGURATION.skip_tutorial {
Box::pin(enter_main_city(session)).await?; Box::pin(enter_main_city(session)).await?;
} else { } else {
let fresh_scene_uid = *dungeon_manager.create_fresh().unwrap(); let fresh_scene_uid = *dungeon_manager.create_fresh().unwrap();