//! Authoritative game simulation. //! //! Used by the dedicated server binary and embedded in the client for //! singleplayer and hosting. Clients only send intents (see //! [`game_core::protocol`]); all game rules run here. pub mod actions; pub mod commands; pub mod config; pub mod console; pub mod crafting; pub mod machines; pub mod movement; pub mod network; pub mod persistence; pub mod players; pub mod scripting; pub mod survival; pub mod world; use std::{sync::Arc, time::Duration}; use bevy::prelude::*; use game_core::GameData; pub use network::NetworkServerPlugin; /// Configuration of the simulation. #[derive(Resource, Clone, Debug)] pub struct ServerSettings { /// Tiled map, relative to the assets directory. pub map: String, /// Database and world to persist to. `None` disables saving. pub storage: Option, pub autosave_interval: Duration, } impl Default for ServerSettings { fn default() -> Self { Self { map: game_core::DEFAULT_MAP.to_owned(), storage: None, autosave_interval: Duration::from_secs(60), } } } /// Runs the game world. Requires [`game_core::CorePlugin`] and the replicon plugins. pub struct GameServerPlugin { pub settings: ServerSettings, } impl Plugin for GameServerPlugin { fn build(&self, app: &mut App) { app.insert_resource(self.settings.clone()) .insert_resource(persistence::AutosaveTimer(Timer::new( self.settings.autosave_interval, TimerMode::Repeating, ))) .init_resource::() .init_resource::() .init_resource::() .init_resource::() .add_systems(Startup, (load_scripts, world::setup_world).chain()) .add_systems( FixedUpdate, ( movement::move_characters, survival::tick_survival, machines::tick_machines, ), ) .add_systems(Update, persistence::autosave) .add_systems(Last, persistence::save_on_exit) .add_observer(players::on_login) .add_observer(players::on_disconnect) .add_observer(movement::on_set_move_dir) .add_observer(actions::on_pick_up) .add_observer(actions::on_drop_item) .add_observer(actions::on_use_item) .add_observer(actions::on_interact) .add_observer(actions::on_craft) .add_observer(actions::on_construct) .add_observer(actions::on_deconstruct) .add_observer(machines::on_machine_insert) .add_observer(machines::on_machine_take); } } fn load_scripts(mut commands: Commands, data: Res) { let dir = game_core::asset_path("scripts"); let engine = scripting::ScriptEngine::load(&dir, &data).unwrap_or_else(|e| panic!("{e}")); info!("compiled scripts from `{}`", dir.display()); commands.insert_resource(engine); commands.insert_resource(actions::SharedData(Arc::new(data.clone()))); }