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.
|
|
|
|
|
//!
|
|
|
|
|
//! ```text
|
2026-10-18 18:47:43 +00:00
|
|
|
//! game-server [--port 5000] [--database URL | --no-save] [--world NAME|UUID] [--map maps/station.tmx]
|
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 18:47:43 +00:00
|
|
|
use std::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;
|
|
|
|
|
use game_core::CorePlugin;
|
2026-10-18 18:47:43 +00:00
|
|
|
use game_server::{
|
|
|
|
|
GameServerPlugin, NetworkServerPlugin, ServerSettings,
|
|
|
|
|
persistence::{StorageSettings, WorldSelector},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const DEFAULT_DATABASE: &str = "sqlite://saves/server.sqlite";
|
|
|
|
|
const DEFAULT_WORLD: &str = "main";
|
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
|
|
|
|
|
|
|
|
fn main() -> AppExit {
|
|
|
|
|
let mut port = game_core::DEFAULT_PORT;
|
2026-10-18 18:47:43 +00:00
|
|
|
let mut settings = ServerSettings::default();
|
|
|
|
|
let mut database = Some(DEFAULT_DATABASE.to_owned());
|
|
|
|
|
let mut world = WorldSelector::Name(DEFAULT_WORLD.to_owned());
|
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
|
|
|
let mut args = std::env::args().skip(1);
|
|
|
|
|
while let Some(arg) = args.next() {
|
|
|
|
|
let mut value = |name: &str| {
|
|
|
|
|
args.next()
|
|
|
|
|
.unwrap_or_else(|| usage(&format!("{name} needs a value")))
|
|
|
|
|
};
|
|
|
|
|
match arg.as_str() {
|
|
|
|
|
"--port" => {
|
|
|
|
|
port = value("--port")
|
|
|
|
|
.parse()
|
|
|
|
|
.unwrap_or_else(|_| usage("invalid port"))
|
|
|
|
|
}
|
2026-10-18 18:47:43 +00:00
|
|
|
"--database" => database = Some(value("--database")),
|
|
|
|
|
"--world" => world = WorldSelector::parse(&value("--world")),
|
|
|
|
|
"--no-save" => database = None,
|
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
|
|
|
"--map" => settings.map = value("--map"),
|
|
|
|
|
"-h" | "--help" => usage(""),
|
|
|
|
|
other => usage(&format!("unknown argument `{other}`")),
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-10-18 18:47:43 +00:00
|
|
|
settings.storage = database.map(|database_url| StorageSettings {
|
|
|
|
|
database_url,
|
|
|
|
|
world,
|
|
|
|
|
});
|
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
|
|
|
|
|
|
|
|
App::new()
|
|
|
|
|
.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 },
|
|
|
|
|
NetworkServerPlugin { port },
|
|
|
|
|
))
|
|
|
|
|
.run()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn usage(error: &str) -> ! {
|
|
|
|
|
if !error.is_empty() {
|
|
|
|
|
eprintln!("error: {error}\n");
|
|
|
|
|
}
|
|
|
|
|
eprintln!(
|
2026-10-18 18:47:43 +00:00
|
|
|
"usage: game-server [--port PORT] [--database URL | --no-save] [--world NAME|UUID] [--map MAP]\n\n\
|
|
|
|
|
--port UDP port to listen on (default {})\n\
|
|
|
|
|
--database sqlite:// or postgres:// URL (default {DEFAULT_DATABASE})\n\
|
|
|
|
|
--world world name or UUID in the database, created if missing (default {DEFAULT_WORLD})\n\
|
|
|
|
|
--no-save don't persist the world\n\
|
|
|
|
|
--map Tiled map relative to the assets directory (default {})",
|
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
|
|
|
game_core::DEFAULT_PORT,
|
|
|
|
|
game_core::DEFAULT_MAP
|
|
|
|
|
);
|
|
|
|
|
std::process::exit(if error.is_empty() { 0 } else { 2 })
|
|
|
|
|
}
|