feat: add persistent-world station game
Bevy ECS workspace with three crates:
- game_core: rsn data definitions, components, Tiled map loader, protocol
- game_server: authoritative simulation, Rune scripting, persistence,
dedicated server binary
- game_client: rendering, UI and input; embeds the server for
singleplayer and hosting
Items, recipes, buildings and skills are defined in assets/data, behavior
in Rune scripts under assets/scripts, and maps are made in Tiled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-18 17:44:13 +00:00
|
|
|
//! Headless dedicated server.
|
|
|
|
|
//!
|
2026-10-18 19:41:58 +00:00
|
|
|
//! Configured by a TOML file (default `server.toml`, created on first start) and
|
|
|
|
|
//! command line options, which override the file for one run. Run with `--help`
|
|
|
|
|
//! for the options. Commands (`help`, `save`, `config set`, ...) can be typed into
|
|
|
|
|
//! the terminal.
|
feat: add persistent-world station game
Bevy ECS workspace with three crates:
- game_core: rsn data definitions, components, Tiled map loader, protocol
- game_server: authoritative simulation, Rune scripting, persistence,
dedicated server binary
- game_client: rendering, UI and input; embeds the server for
singleplayer and hosting
Items, recipes, buildings and skills are defined in assets/data, behavior
in Rune scripts under assets/scripts, and maps are made in Tiled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-18 17:44:13 +00:00
|
|
|
|
2026-10-18 19:41:58 +00:00
|
|
|
use std::{path::PathBuf, time::Duration};
|
feat: add persistent-world station game
Bevy ECS workspace with three crates:
- game_core: rsn data definitions, components, Tiled map loader, protocol
- game_server: authoritative simulation, Rune scripting, persistence,
dedicated server binary
- game_client: rendering, UI and input; embeds the server for
singleplayer and hosting
Items, recipes, buildings and skills are defined in assets/data, behavior
in Rune scripts under assets/scripts, and maps are made in Tiled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-18 17:44:13 +00:00
|
|
|
|
|
|
|
|
use bevy::{app::ScheduleRunnerPlugin, log::LogPlugin, prelude::*, state::app::StatesPlugin};
|
|
|
|
|
use bevy_replicon::prelude::*;
|
|
|
|
|
use bevy_replicon_renet::RepliconRenetPlugins;
|
2026-10-18 19:41:58 +00:00
|
|
|
use clap::Parser;
|
feat: add persistent-world station game
Bevy ECS workspace with three crates:
- game_core: rsn data definitions, components, Tiled map loader, protocol
- game_server: authoritative simulation, Rune scripting, persistence,
dedicated server binary
- game_client: rendering, UI and input; embeds the server for
singleplayer and hosting
Items, recipes, buildings and skills are defined in assets/data, behavior
in Rune scripts under assets/scripts, and maps are made in Tiled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-18 17:44:13 +00:00
|
|
|
use game_core::CorePlugin;
|
2026-10-18 18:47:43 +00:00
|
|
|
use game_server::{
|
2026-10-18 19:41:58 +00:00
|
|
|
GameServerPlugin, NetworkServerPlugin,
|
|
|
|
|
config::{ConfigFile, DEFAULT_CONFIG_PATH, ServerConfig},
|
|
|
|
|
console::ConsolePlugin,
|
2026-10-18 18:47:43 +00:00
|
|
|
};
|
|
|
|
|
|
2026-10-18 19:41:58 +00:00
|
|
|
/// Station dedicated server.
|
|
|
|
|
#[derive(Parser, Debug)]
|
|
|
|
|
#[command(
|
|
|
|
|
version,
|
|
|
|
|
about,
|
|
|
|
|
after_help = "Options override the config file for this run only."
|
|
|
|
|
)]
|
|
|
|
|
struct Cli {
|
|
|
|
|
/// Configuration file, created with defaults if missing.
|
|
|
|
|
#[arg(short, long, value_name = "FILE", default_value = DEFAULT_CONFIG_PATH)]
|
|
|
|
|
config: PathBuf,
|
|
|
|
|
/// UDP port to listen on.
|
|
|
|
|
#[arg(short, long)]
|
|
|
|
|
port: Option<u16>,
|
|
|
|
|
/// Password players need to join (empty for none).
|
|
|
|
|
#[arg(long)]
|
|
|
|
|
password: Option<String>,
|
|
|
|
|
#[arg(long, value_name = "N")]
|
|
|
|
|
max_players: Option<usize>,
|
|
|
|
|
/// Database URL: sqlite://FILE or postgres://USER:PASSWORD@HOST/DB.
|
|
|
|
|
#[arg(long, value_name = "URL")]
|
|
|
|
|
database: Option<String>,
|
|
|
|
|
/// World name (created if missing) or UUID.
|
|
|
|
|
#[arg(long, value_name = "NAME|UUID")]
|
|
|
|
|
world: Option<String>,
|
|
|
|
|
/// Don't persist the world.
|
|
|
|
|
#[arg(long)]
|
|
|
|
|
no_save: bool,
|
|
|
|
|
/// Tiled map for new worlds, relative to the assets directory.
|
|
|
|
|
#[arg(long)]
|
|
|
|
|
map: Option<String>,
|
|
|
|
|
/// Seconds between autosaves.
|
|
|
|
|
#[arg(long, value_name = "SECS")]
|
|
|
|
|
autosave: Option<u64>,
|
|
|
|
|
#[arg(long)]
|
|
|
|
|
motd: Option<String>,
|
|
|
|
|
/// Grant admin rights to a player id (repeatable).
|
|
|
|
|
#[arg(long, value_name = "ID")]
|
|
|
|
|
admin: Vec<String>,
|
|
|
|
|
/// Only allow whitelisted players.
|
|
|
|
|
#[arg(long)]
|
|
|
|
|
whitelist: bool,
|
|
|
|
|
/// Print the effective configuration and exit.
|
|
|
|
|
#[arg(long)]
|
|
|
|
|
print_config: bool,
|
|
|
|
|
}
|
feat: add persistent-world station game
Bevy ECS workspace with three crates:
- game_core: rsn data definitions, components, Tiled map loader, protocol
- game_server: authoritative simulation, Rune scripting, persistence,
dedicated server binary
- game_client: rendering, UI and input; embeds the server for
singleplayer and hosting
Items, recipes, buildings and skills are defined in assets/data, behavior
in Rune scripts under assets/scripts, and maps are made in Tiled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-18 17:44:13 +00:00
|
|
|
|
2026-10-18 19:41:58 +00:00
|
|
|
impl Cli {
|
|
|
|
|
fn apply(self, config: &mut ServerConfig) {
|
|
|
|
|
let Cli {
|
|
|
|
|
port,
|
|
|
|
|
password,
|
|
|
|
|
max_players,
|
|
|
|
|
database,
|
|
|
|
|
world,
|
|
|
|
|
no_save,
|
|
|
|
|
map,
|
|
|
|
|
autosave,
|
|
|
|
|
motd,
|
|
|
|
|
admin,
|
|
|
|
|
whitelist,
|
|
|
|
|
..
|
|
|
|
|
} = self;
|
|
|
|
|
macro_rules! set {
|
|
|
|
|
($($field:ident).+ = $value:expr) => {
|
|
|
|
|
if let Some(value) = $value {
|
|
|
|
|
config.$($field).+ = value;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
set!(port = port);
|
|
|
|
|
set!(password = password);
|
|
|
|
|
set!(max_players = max_players);
|
|
|
|
|
set!(database.url = database);
|
|
|
|
|
set!(database.world = world);
|
|
|
|
|
set!(map = map);
|
|
|
|
|
set!(autosave_secs = autosave);
|
|
|
|
|
set!(motd = motd);
|
|
|
|
|
if no_save {
|
|
|
|
|
config.database.save = false;
|
feat: add persistent-world station game
Bevy ECS workspace with three crates:
- game_core: rsn data definitions, components, Tiled map loader, protocol
- game_server: authoritative simulation, Rune scripting, persistence,
dedicated server binary
- game_client: rendering, UI and input; embeds the server for
singleplayer and hosting
Items, recipes, buildings and skills are defined in assets/data, behavior
in Rune scripts under assets/scripts, and maps are made in Tiled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-18 17:44:13 +00:00
|
|
|
}
|
2026-10-18 19:41:58 +00:00
|
|
|
if whitelist {
|
|
|
|
|
config.access.whitelist_enabled = true;
|
|
|
|
|
}
|
|
|
|
|
config.access.admins.extend(admin);
|
feat: add persistent-world station game
Bevy ECS workspace with three crates:
- game_core: rsn data definitions, components, Tiled map loader, protocol
- game_server: authoritative simulation, Rune scripting, persistence,
dedicated server binary
- game_client: rendering, UI and input; embeds the server for
singleplayer and hosting
Items, recipes, buildings and skills are defined in assets/data, behavior
in Rune scripts under assets/scripts, and maps are made in Tiled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-18 17:44:13 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-18 19:41:58 +00:00
|
|
|
fn main() -> AppExit {
|
|
|
|
|
let cli = Cli::parse();
|
|
|
|
|
let (file, mut config, created) = match ConfigFile::load_or_create(&cli.config) {
|
|
|
|
|
Ok(loaded) => loaded,
|
|
|
|
|
Err(e) => {
|
|
|
|
|
eprintln!("error: {e}");
|
|
|
|
|
return AppExit::error();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
let print = cli.print_config;
|
|
|
|
|
cli.apply(&mut config);
|
|
|
|
|
if print {
|
|
|
|
|
print!("{}", toml::to_string(&config).expect("config serializes"));
|
|
|
|
|
return AppExit::Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut app = App::new();
|
|
|
|
|
app.add_plugins((
|
|
|
|
|
MinimalPlugins.set(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f64(
|
|
|
|
|
1.0 / 60.0,
|
|
|
|
|
))),
|
|
|
|
|
StatesPlugin,
|
|
|
|
|
LogPlugin::default(),
|
|
|
|
|
bevy::app::TerminalCtrlCHandlerPlugin,
|
|
|
|
|
RepliconPlugins,
|
|
|
|
|
RepliconRenetPlugins,
|
|
|
|
|
CorePlugin,
|
|
|
|
|
GameServerPlugin {
|
|
|
|
|
settings: config.settings(),
|
|
|
|
|
},
|
|
|
|
|
NetworkServerPlugin { config },
|
|
|
|
|
ConsolePlugin,
|
|
|
|
|
));
|
|
|
|
|
if created {
|
|
|
|
|
info!("created config file `{}`", file.path.display());
|
|
|
|
|
} else {
|
|
|
|
|
info!("loaded config file `{}`", file.path.display());
|
feat: add persistent-world station game
Bevy ECS workspace with three crates:
- game_core: rsn data definitions, components, Tiled map loader, protocol
- game_server: authoritative simulation, Rune scripting, persistence,
dedicated server binary
- game_client: rendering, UI and input; embeds the server for
singleplayer and hosting
Items, recipes, buildings and skills are defined in assets/data, behavior
in Rune scripts under assets/scripts, and maps are made in Tiled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-18 17:44:13 +00:00
|
|
|
}
|
2026-10-18 19:41:58 +00:00
|
|
|
app.insert_resource(file);
|
|
|
|
|
app.run()
|
feat: add persistent-world station game
Bevy ECS workspace with three crates:
- game_core: rsn data definitions, components, Tiled map loader, protocol
- game_server: authoritative simulation, Rune scripting, persistence,
dedicated server binary
- game_client: rendering, UI and input; embeds the server for
singleplayer and hosting
Items, recipes, buildings and skills are defined in assets/data, behavior
in Rune scripts under assets/scripts, and maps are made in Tiled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-18 17:44:13 +00:00
|
|
|
}
|