diff --git a/Cargo.lock b/Cargo.lock index 722a0f2cf3..c3fc723502 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6075,6 +6075,7 @@ version = "0.10.0" dependencies = [ "atomicwrites", "authc", + "bincode", "chrono", "crossbeam-channel", "futures-util", diff --git a/server-cli/Cargo.toml b/server-cli/Cargo.toml index bbe0bd15f4..3df973d6d9 100644 --- a/server-cli/Cargo.toml +++ b/server-cli/Cargo.toml @@ -16,9 +16,10 @@ This package includes the official server CLI. [features] worldgen = ["server/worldgen"] +persistent_world = ["server/persistent_world"] # needed to stay compatible with voxygens format default-publish = ["default"] -default = ["worldgen"] +default = ["worldgen", "persistent_world"] tracy = ["common-frontend/tracy"] plugins = ["server/plugins"] diff --git a/server/Cargo.toml b/server/Cargo.toml index e3d71259c7..a1855ae590 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -8,8 +8,9 @@ edition = "2018" worldgen = [] simd = ["vek/platform_intrinsics"] plugins = ["common-state/plugins"] +persistent_world = [] -default = ["worldgen", "plugins", "simd"] +default = ["worldgen", "plugins", "simd", "persistent_world"] [dependencies] common = { package = "veloren-common", path = "../common" } diff --git a/server/src/cmd.rs b/server/src/cmd.rs index f706b68a0f..1d3ed22303 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -529,6 +529,7 @@ fn handle_make_block( let new_block = Block::new(bk, Rgb::new(r, g, b).map(|e| e.unwrap_or(255))); let pos = pos.0.map(|e| e.floor() as i32); server.state.set_block(pos, new_block); + #[cfg(feature = "persistent_world")] if let Some(terrain_persistence) = server .state .ecs() @@ -564,6 +565,7 @@ fn handle_make_sprite( .unwrap_or_else(|| Block::air(SpriteKind::Empty)) .with_sprite(sk); server.state.set_block(pos, new_block); + #[cfg(feature = "persistent_world")] if let Some(terrain_persistence) = server .state .ecs() diff --git a/server/src/lib.rs b/server/src/lib.rs index c7dca932c8..10e6d06fc6 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -31,6 +31,7 @@ pub mod rtsim; pub mod settings; pub mod state_ext; pub mod sys; +#[cfg(feature = "persistent_world")] pub mod terrain_persistence; #[cfg(not(feature = "worldgen"))] mod test_world; pub mod wiring; @@ -44,6 +45,8 @@ pub use crate::{ settings::{EditableSettings, Settings}, }; +#[cfg(feature = "persistent_world")] +use crate::terrain_persistence::TerrainPersistence; use crate::{ alias_validator::AliasValidator, chunk_generator::ChunkGenerator, @@ -56,7 +59,6 @@ use crate::{ rtsim::RtSim, state_ext::StateExt, sys::sentinel::{DeletedEntities, TrackedComps}, - terrain_persistence::TerrainPersistence, }; #[cfg(not(feature = "worldgen"))] use common::grid::Grid; @@ -219,15 +221,23 @@ impl Server { state.ecs_mut().insert(tick_metrics); state.ecs_mut().insert(physics_metrics); if settings.experimental_terrain_persistence { - warn!( - "Experimental terrain persistence support is enabled. This feature may break, be \ - disabled, or otherwise change under your feet at *any time*. Additionally, it is \ - expected to be replaced in the future *without* migration or warning. You have \ - been warned." + #[cfg(feature = "persistent_world")] + { + warn!( + "Experimental terrain persistence support is enabled. This feature may break, \ + be disabled, or otherwise change under your feet at *any time*. \ + Additionally, it is expected to be replaced in the future *without* \ + migration or warning. You have been warned." + ); + state + .ecs_mut() + .insert(TerrainPersistence::new(data_dir.to_owned())); + } + #[cfg(not(feature = "persistent_world"))] + error!( + "Experimental terrain persistence support was requested, but the server was not \ + compiled with the feature. Terrain modifications will *not* be persisted." ); - state - .ecs_mut() - .insert(TerrainPersistence::new(data_dir.to_owned())); } state .ecs_mut() @@ -874,6 +884,7 @@ impl Server { self.state.cleanup(); // Maintain persisted terrain + #[cfg(feature = "persistent_world")] self.state .ecs() .try_fetch_mut::() @@ -1253,8 +1264,11 @@ impl Server { impl Drop for Server { fn drop(&mut self) { self.metrics_shutdown.notify_one(); + self.state .notify_players(ServerGeneral::Disconnect(DisconnectReason::Shutdown)); + + #[cfg(feature = "persistent_world")] self.state .ecs() .try_fetch_mut::() diff --git a/server/src/sys/msg/in_game.rs b/server/src/sys/msg/in_game.rs index ebbe0b103d..296864c78c 100644 --- a/server/src/sys/msg/in_game.rs +++ b/server/src/sys/msg/in_game.rs @@ -1,4 +1,6 @@ -use crate::{client::Client, presence::Presence, Settings, TerrainPersistence}; +#[cfg(feature = "persistent_world")] +use crate::TerrainPersistence; +use crate::{client::Client, presence::Presence, Settings}; use common::{ comp::{ Admin, CanBuild, ControlEvent, Controller, ForceUpdate, Health, Ori, Player, Pos, SkillSet, @@ -16,6 +18,11 @@ use specs::{Entities, Join, Read, ReadExpect, ReadStorage, Write, WriteStorage}; use tracing::{debug, trace, warn}; use vek::*; +#[cfg(feature = "persistent_world")] +pub type TerrainPersistenceData<'a> = Option>; +#[cfg(not(feature = "persistent_world"))] +pub type TerrainPersistenceData<'a> = (); + impl Sys { #[allow(clippy::too_many_arguments)] fn handle_client_in_game_msg( @@ -36,7 +43,7 @@ impl Sys { settings: &Read<'_, Settings>, build_areas: &Read<'_, BuildAreas>, player_physics_settings: &mut Write<'_, PlayerPhysicsSettings>, - terrain_persistence: &mut Option>, + _terrain_persistence: &mut TerrainPersistenceData<'_>, maybe_player: &Option<&Player>, maybe_admin: &Option<&Admin>, msg: ClientGeneral, @@ -200,9 +207,10 @@ impl Sys { .and_then(|_| terrain.get(pos).ok()) { let new_block = old_block.into_vacant(); - let was_placed = block_changes.try_set(pos, new_block).is_some(); - if was_placed { - if let Some(terrain_persistence) = terrain_persistence.as_mut() + let _was_set = block_changes.try_set(pos, new_block).is_some(); + #[cfg(feature = "persistent_world")] + if _was_set { + if let Some(terrain_persistence) = _terrain_persistence.as_mut() { terrain_persistence.set_block(pos, new_block); } @@ -224,9 +232,10 @@ impl Sys { .filter(|aabb| aabb.contains_point(pos)) .is_some() { - let was_placed = block_changes.try_set(pos, new_block).is_some(); - if was_placed { - if let Some(terrain_persistence) = terrain_persistence.as_mut() + let _was_set = block_changes.try_set(pos, new_block).is_some(); + #[cfg(feature = "persistent_world")] + if _was_set { + if let Some(terrain_persistence) = _terrain_persistence.as_mut() { terrain_persistence.set_block(pos, new_block); } @@ -301,7 +310,7 @@ impl<'a> System<'a> for Sys { Read<'a, Settings>, Read<'a, BuildAreas>, Write<'a, PlayerPhysicsSettings>, - Option>, + TerrainPersistenceData<'a>, ReadStorage<'a, Player>, ReadStorage<'a, Admin>, ); diff --git a/server/src/sys/terrain.rs b/server/src/sys/terrain.rs index 836f6a538b..ced500bbd2 100644 --- a/server/src/sys/terrain.rs +++ b/server/src/sys/terrain.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "persistent_world")] +use crate::TerrainPersistence; use crate::{ chunk_generator::ChunkGenerator, client::Client, @@ -5,7 +7,7 @@ use crate::{ presence::{Presence, RepositionOnChunkLoad}, rtsim::RtSim, settings::Settings, - SpawnPoint, TerrainPersistence, Tick, + SpawnPoint, Tick, }; use common::{ comp::{self, agent, bird_medium, Alignment, BehaviorCapability, ForceUpdate, Pos, Waypoint}, @@ -24,6 +26,11 @@ use specs::{Entities, Join, Read, ReadExpect, ReadStorage, Write, WriteExpect, W use std::sync::Arc; use vek::*; +#[cfg(feature = "persistent_world")] +pub type TerrainPersistenceData<'a> = Option>; +#[cfg(not(feature = "persistent_world"))] +pub type TerrainPersistenceData<'a> = (); + pub(crate) struct LazyTerrainMessage { lazy_msg_lo: Option, lazy_msg_hi: Option, @@ -99,7 +106,7 @@ impl<'a> System<'a> for Sys { WriteExpect<'a, TerrainGrid>, Write<'a, TerrainChanges>, WriteExpect<'a, RtSim>, - Option>, + TerrainPersistenceData<'a>, WriteStorage<'a, Pos>, ReadStorage<'a, Presence>, ReadStorage<'a, Client>, @@ -126,7 +133,7 @@ impl<'a> System<'a> for Sys { mut terrain, mut terrain_changes, mut rtsim, - mut terrain_persistence, + mut _terrain_persistence, mut positions, presences, clients, @@ -143,6 +150,7 @@ impl<'a> System<'a> for Sys { // Also, send the chunk data to anybody that is close by. let mut new_chunks = Vec::new(); 'insert_terrain_chunks: while let Some((key, res)) = chunk_generator.recv_new_chunk() { + #[allow(unused_mut)] let (mut chunk, supplement) = match res { Ok((chunk, supplement)) => (chunk, supplement), Err(Some(entity)) => { @@ -160,7 +168,8 @@ impl<'a> System<'a> for Sys { }; // Apply changes from terrain persistence to this chunk - if let Some(terrain_persistence) = terrain_persistence.as_mut() { + #[cfg(feature = "persistent_world")] + if let Some(terrain_persistence) = _terrain_persistence.as_mut() { terrain_persistence.apply_changes(key, &mut chunk); } @@ -417,7 +426,8 @@ impl<'a> System<'a> for Sys { for key in chunks_to_remove { // Register the unloading of this chunk from terrain persistence - if let Some(terrain_persistence) = terrain_persistence.as_mut() { + #[cfg(feature = "persistent_world")] + if let Some(terrain_persistence) = _terrain_persistence.as_mut() { terrain_persistence.unload_chunk(key); } diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml index 2b1bebc83f..ddba1a96be 100644 --- a/voxygen/Cargo.toml +++ b/voxygen/Cargo.toml @@ -83,7 +83,7 @@ vek = {version = "=0.14.1", features = ["serde"]} gilrs = {version = "0.8.0", features = ["serde-serialize"]} # Singleplayer -server = {package = "veloren-server", path = "../server", optional = true} +server = { package = "veloren-server", path = "../server", optional = true, default-features = false, features = ["worldgen"] } # Utility backtrace = "0.3.40"