Server configuration rework
This commit is contained in:
parent
934ad89fdf
commit
eb641d67fb
17 changed files with 75 additions and 81 deletions
11
.gitignore
vendored
11
.gitignore
vendored
|
@ -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/
|
||||||
|
|
|
@ -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" }
|
||||||
|
|
11
README.md
11
README.md
|
@ -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
6
common/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[package]
|
||||||
|
name = "common"
|
||||||
|
edition = "2021"
|
||||||
|
version.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
1
common/src/lib.rs
Normal file
1
common/src/lib.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub mod util;
|
9
common/src/util.rs
Normal file
9
common/src/util.rs
Normal 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,
|
||||||
|
)
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
|
|
5
gameserver/gameserver.default.json
Normal file
5
gameserver/gameserver.default.json
Normal 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
22
gameserver/src/config.rs
Normal 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
|
||||||
|
}
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
init_system_logging().await;
|
if CONFIGURATION.system_resources_logging {
|
||||||
|
init_system_logging().await;
|
||||||
net::gateway::listen(GATE_HOST, GATE_PORT).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_config() -> Result<()> {
|
|
||||||
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(())
|
net::gateway::listen(&CONFIGURATION.gateway_endpoint).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue