fix test-server compile warnings

This commit is contained in:
crabman 2024-03-06 12:47:30 +00:00
parent a78ad8de79
commit e6a9d4434f
No known key found for this signature in database
17 changed files with 229 additions and 209 deletions

View File

@ -4,7 +4,7 @@
time cargo clippy \
--all-targets \
--locked \
--features="bin_cmd_doc_gen,bin_compression,bin_csv,bin_graphviz,bin_bot,bin_asset_migrate,asset_tweak,bin,stat" \
--features="bin_cmd_doc_gen,bin_compression,bin_csv,bin_graphviz,bin_bot,bin_asset_migrate,asset_tweak,bin,stat,cli" \
-- -D warnings &&
# Ensure that the veloren-voxygen default-publish feature builds as it excludes some default features
@ -13,4 +13,7 @@ time cargo clippy -p \
--no-default-features \
--features="default-publish" \
-- -D warnings &&
# Ensure that test-server compiles
time cargo clippy --locked --bin veloren-server-cli --no-default-features -F simd -- -D warnings &&
time cargo fmt --all -- --check

View File

@ -60,6 +60,7 @@ pub enum Message {
},
/// Loads up the chunks at map center and adds a entity that mimics a
/// player to keep them from despawning
#[cfg(feature = "worldgen")]
LoadArea {
/// View distance of the loaded area
view_distance: u32,

View File

@ -208,6 +208,7 @@ fn main() -> io::Result<()> {
let protocols_and_addresses = server_settings.gameserver_protocols.clone();
let web_port = &settings.web_address.port();
// Create server
#[cfg_attr(not(feature = "worldgen"), allow(unused_mut))]
let mut server = Server::new(
server_settings,
editable_settings,
@ -263,8 +264,8 @@ fn main() -> io::Result<()> {
"Server is ready to accept connections."
);
#[cfg(feature = "worldgen")]
if let Some(bench) = bench {
#[cfg(feature = "worldgen")]
server.create_centered_persister(bench.view_distance);
}
@ -367,8 +368,8 @@ fn server_loop(
}) => {
server.remove_admin(&username);
},
#[cfg(feature = "worldgen")]
Message::LoadArea { view_distance } => {
#[cfg(feature = "worldgen")]
server.create_centered_persister(view_distance);
},
Message::SqlLogMode { mode } => {

View File

@ -1,6 +1,8 @@
use crate::metrics::ChunkGenMetrics;
#[cfg(feature = "worldgen")]
use crate::rtsim::RtSim;
#[cfg(not(feature = "worldgen"))]
use crate::test_world::{IndexOwned, World};
use crate::{metrics::ChunkGenMetrics, rtsim::RtSim};
use common::{
calendar::Calendar, generation::ChunkSupplement, resources::TimeOfDay, slowjob::SlowJobPool,
terrain::TerrainChunk,
@ -45,7 +47,7 @@ impl ChunkGenerator {
slowjob_pool: &SlowJobPool,
world: Arc<World>,
#[cfg(feature = "worldgen")] rtsim: &RtSim,
#[cfg(not(feature = "worldgen"))] rtsim: &(),
#[cfg(not(feature = "worldgen"))] _rtsim: &(),
index: IndexOwned,
time: (TimeOfDay, Calendar),
) {

View File

@ -1,6 +1,8 @@
//! # Implementing new commands.
//! To implement a new command provide a handler function
//! in [do_command].
#[cfg(feature = "worldgen")]
use crate::weather::WeatherJob;
use crate::{
client::Client,
location::Locations,
@ -10,7 +12,6 @@ use crate::{
SettingError, WhitelistInfo, WhitelistRecord,
},
sys::terrain::SpawnEntityData,
weather::WeatherJob,
wiring,
wiring::OutputFormula,
Server, Settings, StateExt,
@ -54,13 +55,15 @@ use common::{
resources::{BattleMode, PlayerPhysicsSettings, ProgramTime, Secs, Time, TimeOfDay, TimeScale},
rtsim::{Actor, Role},
spiral::Spiral2d,
terrain::{Block, BlockKind, CoordinateConversions, SpriteKind, TerrainChunkSize},
terrain::{Block, BlockKind, CoordinateConversions, SpriteKind},
tether::Tethered,
uid::Uid,
vol::ReadVol,
weather, CachedSpatialGrid, Damage, DamageKind, DamageSource, Explosion, GroupTarget,
LoadoutBuilder, RadiusEffect,
CachedSpatialGrid, Damage, DamageKind, DamageSource, Explosion, GroupTarget, LoadoutBuilder,
RadiusEffect,
};
#[cfg(feature = "worldgen")]
use common::{terrain::TerrainChunkSize, weather};
use common_net::{
msg::{DisconnectReason, Notification, PlayerListUpdate, ServerGeneral},
sync::WorldSyncExt,
@ -74,6 +77,7 @@ use specs::{storage::StorageEntry, Builder, Entity as EcsEntity, Join, LendJoin,
use std::{fmt::Write, num::NonZeroU32, ops::DerefMut, str::FromStr, sync::Arc, time::Duration};
use vek::*;
use wiring::{Circuit, Wire, WireNode, WiringAction, WiringActionEffect, WiringElement};
#[cfg(feature = "worldgen")]
use world::util::{Sampler, LOCALITY};
use common::comp::Alignment;
@ -929,8 +933,20 @@ fn handle_goto(
}
}
#[cfg(not(feature = "worldgen"))]
fn handle_site(
_server: &mut Server,
_client: EcsEntity,
_target: EcsEntity,
_args: Vec<String>,
_action: &ServerChatCommand,
) -> CmdResult<()> {
Err("Unsupported without worldgen enabled".into())
}
/// TODO: Add autocompletion if possible (might require modifying enum to handle
/// dynamic values).
#[cfg(feature = "worldgen")]
fn handle_site(
server: &mut Server,
_client: EcsEntity,
@ -938,7 +954,6 @@ fn handle_site(
args: Vec<String>,
action: &ServerChatCommand,
) -> CmdResult<()> {
#[cfg(feature = "worldgen")]
if let (Some(dest_name), dismount_volume) = parse_cmd_args!(args, String, bool) {
let site = server
.world
@ -964,9 +979,6 @@ fn handle_site(
} else {
Err(Content::Plain(action.help_string()))
}
#[cfg(not(feature = "worldgen"))]
Ok(())
}
fn handle_respawn(
@ -3475,9 +3487,9 @@ fn handle_join_faction(
#[cfg(not(feature = "worldgen"))]
fn handle_debug_column(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
_server: &mut Server,
_client: EcsEntity,
_target: EcsEntity,
_args: Vec<String>,
_action: &ServerChatCommand,
) -> CmdResult<()> {
@ -3569,9 +3581,9 @@ cliff_height {:?} "#,
#[cfg(not(feature = "worldgen"))]
fn handle_debug_ways(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
_server: &mut Server,
_client: EcsEntity,
_target: EcsEntity,
_args: Vec<String>,
_action: &ServerChatCommand,
) -> CmdResult<()> {
@ -4728,6 +4740,18 @@ fn handle_delete_location(
}
}
#[cfg(not(feature = "worldgen"))]
fn handle_weather_zone(
_server: &mut Server,
_client: EcsEntity,
_target: EcsEntity,
_args: Vec<String>,
_action: &ServerChatCommand,
) -> CmdResult<()> {
Err("Unsupported without worldgen enabled".into())
}
#[cfg(feature = "worldgen")]
fn handle_weather_zone(
server: &mut Server,
client: EcsEntity,

View File

@ -1,5 +1,5 @@
#[cfg(not(feature = "worldgen"))]
use crate::test_world::{IndexOwned, World};
#[cfg(feature = "worldgen")]
use crate::rtsim::RtSim;
use crate::{
client::Client,
comp::{
@ -11,11 +11,12 @@ use crate::{
error,
events::entity_creation::handle_create_npc,
pet::tame_pet,
rtsim::RtSim,
state_ext::StateExt,
sys::terrain::{NpcData, SpawnEntityData, SAFE_ZONE_RADIUS},
Server, Settings, SpawnPoint,
};
#[cfg(feature = "worldgen")]
use common::rtsim::{Actor, RtSimEntity};
use common::{
combat,
combat::{AttackSource, DamageContributor},
@ -48,7 +49,6 @@ use common::{
mounting::{Rider, VolumeRider},
outcome::{HealthChangeInfo, Outcome},
resources::{ProgramTime, Secs, Time},
rtsim::{Actor, RtSimEntity},
spiral::Spiral2d,
states::utils::StageSection,
terrain::{Block, BlockKind, TerrainGrid},
@ -62,11 +62,14 @@ use common_net::{msg::ServerGeneral, sync::WorldSyncExt};
use common_state::{AreasContainer, BlockChange, NoDurabilityArea};
use hashbrown::HashSet;
use rand::Rng;
#[cfg(feature = "worldgen")]
use specs::WriteExpect;
use specs::{
shred, DispatcherBuilder, Entities, Entity as EcsEntity, Entity, Join, LendJoin, Read,
ReadExpect, ReadStorage, SystemData, WorldExt, Write, WriteExpect, WriteStorage,
ReadExpect, ReadStorage, SystemData, WorldExt, Write, WriteStorage,
};
use std::{collections::HashMap, iter, sync::Arc, time::Duration};
#[cfg(feature = "worldgen")] use std::sync::Arc;
use std::{collections::HashMap, iter, time::Duration};
use tracing::{debug, warn};
use vek::{Vec2, Vec3};
#[cfg(feature = "worldgen")]
@ -296,7 +299,9 @@ pub struct DestroyEventData<'a> {
ability_map: ReadExpect<'a, AbilityMap>,
time: Read<'a, Time>,
program_time: ReadExpect<'a, ProgramTime>,
#[cfg(feature = "worldgen")]
world: ReadExpect<'a, Arc<World>>,
#[cfg(feature = "worldgen")]
index: ReadExpect<'a, IndexOwned>,
areas_container: Read<'a, AreasContainer<NoDurabilityArea>>,
outcomes: Read<'a, EventBus<Outcome>>,
@ -323,7 +328,9 @@ pub struct DestroyEventData<'a> {
alignments: ReadStorage<'a, Alignment>,
stats: ReadStorage<'a, Stats>,
agents: ReadStorage<'a, Agent>,
#[cfg(feature = "worldgen")]
rtsim_entities: ReadStorage<'a, RtSimEntity>,
#[cfg(feature = "worldgen")]
presences: ReadStorage<'a, Presence>,
}
@ -716,6 +723,7 @@ impl ServerEvent for DestroyEvent {
}
}
#[cfg(feature = "worldgen")]
let entity_as_actor = |entity| {
if let Some(rtsim_entity) = data.rtsim_entities.get(entity).copied() {
Some(Actor::Npc(rtsim_entity.0))
@ -727,6 +735,7 @@ impl ServerEvent for DestroyEvent {
None
}
};
#[cfg(feature = "worldgen")]
let actor = entity_as_actor(ev.entity);
#[cfg(feature = "worldgen")]

View File

@ -3,8 +3,11 @@ use common::event::RequestSiteInfoEvent;
use common_net::msg::{world_msg::EconomyInfo, ServerGeneral};
#[cfg(feature = "plugins")]
use common_state::plugin::PluginMgr;
use specs::{DispatcherBuilder, ReadExpect, ReadStorage};
#[cfg(feature = "worldgen")]
use specs::ReadExpect;
use specs::{DispatcherBuilder, ReadStorage};
use std::collections::HashMap;
#[cfg(feature = "worldgen")]
use world::IndexOwned;
use super::{event_dispatch, ServerEvent};

View File

@ -3,8 +3,6 @@ use super::{
group_manip::{self, update_map_markers},
ServerEvent,
};
#[cfg(not(feature = "worldgen"))]
use crate::test_world::IndexOwned;
use crate::{client::Client, Settings};
use common::{
comp::{
@ -20,9 +18,10 @@ use common::{
uid::{IdMaps, Uid},
};
use common_net::msg::{InviteAnswer, ServerGeneral};
#[cfg(feature = "worldgen")]
use specs::ReadExpect;
use specs::{
shred, DispatcherBuilder, Entities, Entity, Read, ReadExpect, ReadStorage, SystemData, Write,
WriteStorage,
shred, DispatcherBuilder, Entities, Entity, Read, ReadStorage, SystemData, Write, WriteStorage,
};
use std::time::{Duration, Instant};
use tracing::{error, warn};
@ -226,6 +225,7 @@ pub struct InviteResponseData<'a> {
entities: Entities<'a>,
group_manager: Write<'a, GroupManager>,
trades: Write<'a, Trades>,
#[cfg(feature = "worldgen")]
index: ReadExpect<'a, IndexOwned>,
id_maps: Read<'a, IdMaps>,
invites: WriteStorage<'a, Invite>,

View File

@ -1,4 +1,4 @@
use std::sync::Arc;
#[cfg(feature = "worldgen")] use std::sync::Arc;
use common::{
comp::{self, pet::is_mountable},
@ -6,12 +6,15 @@ use common::{
event::{MountEvent, MountVolumeEvent, UnmountEvent},
link::Is,
mounting::{Mounting, Rider, VolumeMounting, VolumeRider},
rtsim::RtSimEntity,
uid::{IdMaps, Uid},
uid::Uid,
};
#[cfg(feature = "worldgen")]
use common::{rtsim::RtSimEntity, uid::IdMaps};
use specs::WorldExt;
use crate::{rtsim::RtSim, state_ext::StateExt, Server};
#[cfg(feature = "worldgen")]
use crate::rtsim::RtSim;
use crate::{state_ext::StateExt, Server};
pub fn within_mounting_range(
player_position: Option<&comp::Pos>,

View File

@ -18,6 +18,7 @@ use hashbrown::{hash_map::Entry, HashMap};
use specs::{world::WorldExt, Entity as EcsEntity};
use std::{cmp::Ordering, num::NonZeroU32};
use tracing::{error, trace};
#[cfg(feature = "worldgen")]
use world::IndexOwned;
pub fn notify_agent_simple(
@ -30,6 +31,7 @@ pub fn notify_agent_simple(
}
}
#[cfg(feature = "worldgen")]
fn notify_agent_prices(
mut agents: specs::WriteStorage<Agent>,
index: &IndexOwned,
@ -104,7 +106,10 @@ pub(super) fn handle_process_trade_action(
} else {
let mut entities: [Option<specs::Entity>; 2] = [None, None];
let mut inventories: [Option<ReducedInventory>; 2] = [None, None];
#[cfg(feature = "worldgen")]
let mut prices = None;
#[cfg(not(feature = "worldgen"))]
let prices = None;
let agents = server.state.ecs().read_storage::<Agent>();
// sadly there is no map and collect on arrays
for i in 0..2 {

View File

@ -41,7 +41,7 @@ pub mod sys;
pub mod terrain_persistence;
#[cfg(not(feature = "worldgen"))] mod test_world;
mod weather;
#[cfg(feature = "worldgen")] mod weather;
pub mod wiring;
@ -73,6 +73,8 @@ use crate::{
use censor::Censor;
#[cfg(not(feature = "worldgen"))]
use common::grid::Grid;
#[cfg(feature = "worldgen")]
use common::terrain::TerrainChunkSize;
use common::{
assets::AssetExt,
calendar::Calendar,
@ -90,7 +92,7 @@ use common::{
rtsim::RtSimEntity,
shared_server_config::ServerConstants,
slowjob::SlowJobPool,
terrain::{TerrainChunk, TerrainChunkSize},
terrain::TerrainChunk,
vol::RectRasterableVol,
};
use common_base::prof_span;
@ -117,15 +119,12 @@ use std::{
sync::Arc,
time::{Duration, Instant},
};
#[cfg(not(feature = "worldgen"))]
use test_world::{IndexOwned, World};
use tokio::runtime::Runtime;
use tracing::{debug, error, info, trace, warn};
use vek::*;
pub use world::{civ::WorldCivStage, sim::WorldSimStage, WorldGenerateStage};
#[cfg(not(feature = "worldgen"))]
use {
common_net::msg::WorldMapMsg,
test_world::{IndexOwned, World},
};
use crate::{
persistence::{DatabaseSettings, SqlLogMode},
@ -496,7 +495,7 @@ impl Server {
#[cfg(feature = "worldgen")]
let size = world.sim().get_size();
#[cfg(not(feature = "worldgen"))]
let size = Vec2::new(40, 40);
let size = world.map_size_lg().chunks().map(u32::from);
let world_size = size.map(|e| e as i32) * TerrainChunk::RECT_SIZE.map(|e| e as i32);
let world_aabb = Aabb {

View File

@ -1,3 +1,5 @@
#[cfg(feature = "worldgen")]
use crate::rtsim::RtSim;
use crate::{
automod::AutoMod,
chat::ChatExporter,
@ -6,13 +8,13 @@ use crate::{
persistence::PersistedComponents,
pet::restore_pet,
presence::RepositionOnChunkLoad,
rtsim::RtSim,
settings::Settings,
sys::sentinel::DeletedEntities,
wiring, BattleModeBuffer, SpawnPoint,
};
#[cfg(feature = "worldgen")]
use common::{calendar::Calendar, resources::TimeOfDay, slowjob::SlowJobPool};
use common::{
calendar::Calendar,
character::CharacterId,
combat,
combat::DamageContributor,
@ -26,9 +28,8 @@ use common::{
effect::Effect,
link::{Is, Link, LinkHandle},
mounting::{Mounting, Rider, VolumeMounting, VolumeRider},
resources::{Secs, Time, TimeOfDay},
resources::{Secs, Time},
rtsim::{Actor, RtSimEntity},
slowjob::SlowJobPool,
tether::Tethered,
uid::{IdMaps, Uid},
util::Dir,
@ -111,6 +112,7 @@ pub trait StateExt {
/// Queues chunk generation in the view distance of the persister, this
/// entity must be built before those chunks are received (the builder
/// borrows the ecs world so that is kind of impossible in practice)
#[cfg(feature = "worldgen")]
fn create_persister(
&mut self,
pos: comp::Pos,
@ -546,6 +548,7 @@ impl StateExt for State {
/// Queues chunk generation in the view distance of the persister, this
/// entity must be built before those chunks are received (the builder
/// borrows the ecs world so that is kind of impossible in practice)
#[cfg(feature = "worldgen")]
fn create_persister(
&mut self,
pos: comp::Pos,
@ -559,10 +562,7 @@ impl StateExt for State {
{
let ecs = self.ecs();
let slow_jobs = ecs.write_resource::<SlowJobPool>();
#[cfg(feature = "worldgen")]
let rtsim = ecs.read_resource::<RtSim>();
#[cfg(not(feature = "worldgen"))]
let rtsim = ();
let mut chunk_generator =
ecs.write_resource::<crate::chunk_generator::ChunkGenerator>();
let chunk_pos = self.terrain().pos_key(pos.0.map(|e| e as i32));
@ -580,7 +580,6 @@ impl StateExt for State {
* TerrainChunkSize::RECT_SIZE.x as f64
})
.for_each(|chunk_key| {
#[cfg(feature = "worldgen")]
{
let time = (*ecs.read_resource::<TimeOfDay>(), (*ecs.read_resource::<Calendar>()).clone());
chunk_generator.generate_chunk(None, chunk_key, &slow_jobs, Arc::clone(world), &rtsim, index.clone(), time);

View File

@ -1,5 +1,5 @@
#[cfg(not(feature = "worldgen"))]
use crate::test_world::{IndexOwned, World};
use crate::test_world::World;
#[cfg(feature = "worldgen")]
use world::{IndexOwned, World};
@ -10,6 +10,8 @@ use crate::{
persistence::{character_loader::CharacterLoader, character_updater::CharacterUpdater},
EditableSettings,
};
#[cfg(feature = "worldgen")]
use common::terrain::TerrainChunkSize;
use common::{
comp::{Admin, AdminRole, ChatType, Player, Presence, Waypoint},
event::{
@ -18,14 +20,15 @@ use common::{
},
event_emitters,
resources::Time,
terrain::TerrainChunkSize,
uid::Uid,
};
use common_ecs::{Job, Origin, Phase, System};
use common_net::msg::{ClientGeneral, ServerGeneral};
use specs::{Entities, Join, ReadExpect, ReadStorage, WriteExpect, WriteStorage};
use specs::{
shred, Entities, Join, ReadExpect, ReadStorage, SystemData, WriteExpect, WriteStorage,
};
use std::sync::{atomic::Ordering, Arc};
use tracing::{debug, error};
use tracing::debug;
event_emitters! {
struct Events[Emitters] {
@ -54,7 +57,7 @@ impl Sys {
automod: &AutoMod,
msg: ClientGeneral,
time: Time,
index: &ReadExpect<'_, IndexOwned>,
#[cfg(feature = "worldgen")] index: &ReadExpect<'_, IndexOwned>,
world: &ReadExpect<'_, Arc<World>>,
) -> Result<(), crate::error::Error> {
let mut send_join_messages = || -> Result<(), crate::error::Error> {
@ -165,7 +168,10 @@ impl Sys {
mainhand,
offhand,
body,
#[cfg(feature = "worldgen")]
start_site,
#[cfg(not(feature = "worldgen"))]
start_site: _,
} => {
if censor.check(&alias) {
debug!(?alias, "denied alias as it contained a banned word");
@ -188,7 +194,7 @@ impl Sys {
.find(|(_, site)| site.site_tmp.map(|i| i.id()) == Some(site_idx))
.map(Some)
.unwrap_or_else(|| {
error!(
tracing::error!(
"Tried to create character with starting site index {}, but \
such a site does not exist",
site_idx
@ -272,73 +278,59 @@ impl Sys {
}
}
#[derive(SystemData)]
pub struct Data<'a> {
entities: Entities<'a>,
events: Events<'a>,
character_loader: ReadExpect<'a, CharacterLoader>,
character_updater: WriteExpect<'a, CharacterUpdater>,
uids: ReadStorage<'a, Uid>,
clients: WriteStorage<'a, Client>,
players: ReadStorage<'a, Player>,
admins: ReadStorage<'a, Admin>,
presences: ReadStorage<'a, Presence>,
editable_settings: ReadExpect<'a, EditableSettings>,
censor: ReadExpect<'a, Arc<censor::Censor>>,
automod: ReadExpect<'a, AutoMod>,
time: ReadExpect<'a, Time>,
#[cfg(feature = "worldgen")]
index: ReadExpect<'a, IndexOwned>,
world: ReadExpect<'a, Arc<World>>,
}
/// This system will handle new messages from clients
#[derive(Default)]
pub struct Sys;
impl<'a> System<'a> for Sys {
type SystemData = (
Entities<'a>,
Events<'a>,
ReadExpect<'a, CharacterLoader>,
WriteExpect<'a, CharacterUpdater>,
ReadStorage<'a, Uid>,
WriteStorage<'a, Client>,
ReadStorage<'a, Player>,
ReadStorage<'a, Admin>,
ReadStorage<'a, Presence>,
ReadExpect<'a, EditableSettings>,
ReadExpect<'a, Arc<censor::Censor>>,
ReadExpect<'a, AutoMod>,
ReadExpect<'a, Time>,
ReadExpect<'a, IndexOwned>,
ReadExpect<'a, Arc<World>>,
);
type SystemData = Data<'a>;
const NAME: &'static str = "msg::character_screen";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run(
_job: &mut Job<Self>,
(
entities,
events,
character_loader,
mut character_updater,
uids,
mut clients,
players,
admins,
presences,
editable_settings,
censor,
automod,
time,
index,
world,
): Self::SystemData,
) {
let mut emitters = events.get_emitters();
fn run(_job: &mut Job<Self>, mut data: Self::SystemData) {
let mut emitters = data.events.get_emitters();
for (entity, client) in (&entities, &mut clients).join() {
for (entity, client) in (&data.entities, &mut data.clients).join() {
let _ = super::try_recv_all(client, 1, |client, msg| {
Self::handle_client_character_screen_msg(
&mut emitters,
entity,
client,
&character_loader,
&mut character_updater,
&uids,
&players,
&admins,
&presences,
&editable_settings,
&censor,
&automod,
&data.character_loader,
&mut data.character_updater,
&data.uids,
&data.players,
&data.admins,
&data.presences,
&data.editable_settings,
&data.censor,
&data.automod,
msg,
*time,
&index,
&world,
*data.time,
#[cfg(feature = "worldgen")]
&data.index,
&data.world,
)
});
}

View File

@ -6,9 +6,10 @@ use tracing::error;
#[cfg(feature = "worldgen")]
use world::{IndexOwned, World};
#[cfg(feature = "worldgen")] use crate::rtsim;
use crate::{
chunk_generator::ChunkGenerator, chunk_serialize::ChunkSendEntry, client::Client,
presence::RepositionOnChunkLoad, rtsim, settings::Settings, ChunkRequest, Tick,
presence::RepositionOnChunkLoad, settings::Settings, ChunkRequest, Tick,
};
use common::{
calendar::Calendar,
@ -35,8 +36,8 @@ use core::cmp::Reverse;
use itertools::Itertools;
use rayon::{iter::Either, prelude::*};
use specs::{
storage::GenericReadStorage, Entities, Entity, Join, LendJoin, ParJoin, Read, ReadExpect,
ReadStorage, Write, WriteExpect, WriteStorage,
shred, storage::GenericReadStorage, Entities, Entity, Join, LendJoin, ParJoin, Read,
ReadExpect, ReadStorage, SystemData, Write, WriteExpect, WriteStorage,
};
use std::{f32::consts::TAU, sync::Arc};
use vek::*;
@ -60,6 +61,34 @@ event_emitters! {
}
}
#[derive(SystemData)]
pub struct Data<'a> {
events: Events<'a>,
tick: Read<'a, Tick>,
server_settings: Read<'a, Settings>,
time_of_day: Read<'a, TimeOfDay>,
calendar: Read<'a, Calendar>,
slow_jobs: ReadExpect<'a, SlowJobPool>,
index: ReadExpect<'a, IndexOwned>,
world: ReadExpect<'a, Arc<World>>,
chunk_send_bus: ReadExpect<'a, EventBus<ChunkSendEntry>>,
chunk_generator: WriteExpect<'a, ChunkGenerator>,
terrain: WriteExpect<'a, TerrainGrid>,
terrain_changes: Write<'a, TerrainChanges>,
chunk_requests: Write<'a, Vec<ChunkRequest>>,
rtsim: RtSimData<'a>,
#[cfg(feature = "persistent_world")]
terrain_persistence: TerrainPersistenceData<'a>,
positions: WriteStorage<'a, Pos>,
presences: ReadStorage<'a, Presence>,
clients: ReadStorage<'a, Client>,
entities: Entities<'a>,
reposition_on_load: WriteStorage<'a, RepositionOnChunkLoad>,
forced_updates: WriteStorage<'a, ForceUpdate>,
waypoints: WriteStorage<'a, Waypoint>,
time: ReadExpect<'a, Time>,
}
/// This system will handle loading generated chunks and unloading
/// unneeded chunks.
/// 1. Inserts newly generated chunks into the TerrainGrid
@ -70,80 +99,29 @@ event_emitters! {
pub struct Sys;
impl<'a> System<'a> for Sys {
#[allow(clippy::type_complexity)]
type SystemData = (
Events<'a>,
Read<'a, Tick>,
Read<'a, Settings>,
Read<'a, TimeOfDay>,
Read<'a, Calendar>,
ReadExpect<'a, SlowJobPool>,
ReadExpect<'a, IndexOwned>,
ReadExpect<'a, Arc<World>>,
ReadExpect<'a, EventBus<ChunkSendEntry>>,
WriteExpect<'a, ChunkGenerator>,
WriteExpect<'a, TerrainGrid>,
Write<'a, TerrainChanges>,
Write<'a, Vec<ChunkRequest>>,
RtSimData<'a>,
TerrainPersistenceData<'a>,
WriteStorage<'a, Pos>,
ReadStorage<'a, Presence>,
ReadStorage<'a, Client>,
Entities<'a>,
WriteStorage<'a, RepositionOnChunkLoad>,
WriteStorage<'a, ForceUpdate>,
WriteStorage<'a, Waypoint>,
ReadExpect<'a, Time>,
);
type SystemData = Data<'a>;
const NAME: &'static str = "terrain";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run(
_job: &mut Job<Self>,
(
events,
tick,
server_settings,
time_of_day,
calendar,
slow_jobs,
index,
world,
chunk_send_bus,
mut chunk_generator,
mut terrain,
mut terrain_changes,
mut chunk_requests,
mut rtsim,
mut _terrain_persistence,
mut positions,
presences,
clients,
entities,
mut reposition_on_load,
mut force_update,
mut waypoints,
time,
): Self::SystemData,
) {
let mut emitters = events.get_emitters();
fn run(_job: &mut Job<Self>, mut data: Self::SystemData) {
let mut emitters = data.events.get_emitters();
// Generate requested chunks
//
// Submit requests for chunks right before receiving finished chunks so that we
// don't create duplicate work for chunks that just finished but are not
// yet added to the terrain.
chunk_requests.drain(..).for_each(|request| {
chunk_generator.generate_chunk(
data.chunk_requests.drain(..).for_each(|request| {
data.chunk_generator.generate_chunk(
Some(request.entity),
request.key,
&slow_jobs,
Arc::clone(&world),
&rtsim,
index.clone(),
(*time_of_day, calendar.clone()),
&data.slow_jobs,
Arc::clone(&data.world),
&data.rtsim,
data.index.clone(),
(*data.time_of_day, data.calendar.clone()),
)
});
@ -151,12 +129,12 @@ impl<'a> System<'a> for Sys {
// Fetch any generated `TerrainChunk`s and insert them into the terrain.
// 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() {
'insert_terrain_chunks: while let Some((key, res)) = data.chunk_generator.recv_new_chunk() {
#[allow(unused_mut)]
let (mut chunk, supplement) = match res {
Ok((chunk, supplement)) => (chunk, supplement),
Err(Some(entity)) => {
if let Some(client) = clients.get(entity) {
if let Some(client) = data.clients.get(entity) {
client.send_fallible(ServerGeneral::TerrainChunkUpdate {
key,
chunk: Err(()),
@ -171,7 +149,7 @@ impl<'a> System<'a> for Sys {
// Apply changes from terrain persistence to this chunk
#[cfg(feature = "persistent_world")]
if let Some(terrain_persistence) = _terrain_persistence.as_mut() {
if let Some(terrain_persistence) = data.terrain_persistence.as_mut() {
terrain_persistence.apply_changes(key, &mut chunk);
}
@ -183,19 +161,20 @@ impl<'a> System<'a> for Sys {
// TODO: code duplication for chunk insertion between here and state.rs
// Insert the chunk into terrain changes
if terrain.insert(key, chunk).is_some() {
terrain_changes.modified_chunks.insert(key);
if data.terrain.insert(key, chunk).is_some() {
data.terrain_changes.modified_chunks.insert(key);
} else {
terrain_changes.new_chunks.insert(key);
data.terrain_changes.new_chunks.insert(key);
#[cfg(feature = "worldgen")]
rtsim.hook_load_chunk(key, supplement.rtsim_max_resources);
data.rtsim
.hook_load_chunk(key, supplement.rtsim_max_resources);
}
// Handle chunk supplement
for entity in supplement.entities {
// Check this because it's a common source of weird bugs
assert!(
terrain
data.terrain
.pos_key(entity.pos.map(|e| e.floor() as i32))
.map2(key, |e, tgt| (e - tgt).abs() <= 1)
.reduce_and(),
@ -223,7 +202,7 @@ impl<'a> System<'a> for Sys {
// TODO: Consider putting this in another system since this forces us to take
// positions by write rather than read access.
let repositioned = (&entities, &mut positions, (&mut force_update).maybe(), &reposition_on_load)
let repositioned = (&data.entities, &mut data.positions, (&mut data.forced_updates).maybe(), &data.reposition_on_load)
// TODO: Consider using par_bridge() because Rayon has very poor work splitting for
// sparse joins.
.par_join()
@ -234,11 +213,11 @@ impl<'a> System<'a> for Sys {
// If an entity is marked as needing repositioning once the chunk loads (e.g.
// from having just logged in), reposition them.
let chunk_pos = TerrainGrid::chunk_key(entity_pos);
let chunk = terrain.get_key(chunk_pos)?;
let chunk = data.terrain.get_key(chunk_pos)?;
let new_pos = if reposition.needs_ground {
terrain.try_find_ground(entity_pos)
data.terrain.try_find_ground(entity_pos)
} else {
terrain.try_find_space(entity_pos)
data.terrain.try_find_space(entity_pos)
}.map(|x| x.as_::<f32>()).unwrap_or_else(|| chunk.find_accessible_pos(entity_pos.xy(), false));
pos.0 = new_pos;
force_update.map(|force_update| force_update.update());
@ -247,30 +226,30 @@ impl<'a> System<'a> for Sys {
.collect::<Vec<_>>();
for (entity, new_pos) in repositioned {
if let Some(waypoint) = waypoints.get_mut(entity) {
*waypoint = Waypoint::new(new_pos, *time);
if let Some(waypoint) = data.waypoints.get_mut(entity) {
*waypoint = Waypoint::new(new_pos, *data.time);
}
reposition_on_load.remove(entity);
data.reposition_on_load.remove(entity);
}
let max_view_distance = server_settings.max_view_distance.unwrap_or(u32::MAX);
let max_view_distance = data.server_settings.max_view_distance.unwrap_or(u32::MAX);
#[cfg(feature = "worldgen")]
let world_size = world.sim().get_size();
let world_size = data.world.sim().get_size();
#[cfg(not(feature = "worldgen"))]
let world_size = world.map_size_lg().chunks().map(u32::from);
let world_size = data.world.map_size_lg().chunks().map(u32::from);
let (presences_position_entities, presences_positions) = prepare_player_presences(
world_size,
max_view_distance,
&entities,
&positions,
&presences,
&clients,
&data.entities,
&data.positions,
&data.presences,
&data.clients,
);
let real_max_view_distance = convert_to_loaded_vd(u32::MAX, max_view_distance);
// Send the chunks to all nearby players.
new_chunks.par_iter().for_each_init(
|| chunk_send_bus.emitter(),
|| data.chunk_send_bus.emitter(),
|chunk_send_emitter, chunk_key| {
// We only have to check players inside the maximum view distance of the server
// of our own position.
@ -311,19 +290,19 @@ impl<'a> System<'a> for Sys {
},
);
let tick = (tick.0 % 16) as i32;
let tick = (data.tick.0 % 16) as i32;
// Remove chunks that are too far from players.
//
// Note that all chunks involved here (both terrain chunks and pending chunks)
// are guaranteed in bounds. This simplifies the rest of the logic
// here.
let chunks_to_remove = terrain
let chunks_to_remove = data.terrain
.par_keys()
.copied()
// There may be lots of pending chunks, so don't check them all. This should be okay
// as long as we're maintaining a reasonable tick rate.
.chain(chunk_generator.par_pending_chunks())
.chain(data.chunk_generator.par_pending_chunks())
// Don't check every chunk every tick (spread over 16 ticks)
//
// TODO: Investigate whether we can add support for performing this filtering directly
@ -370,26 +349,26 @@ impl<'a> System<'a> for Sys {
.filter_map(|key| {
// Register the unloading of this chunk from terrain persistence
#[cfg(feature = "persistent_world")]
if let Some(terrain_persistence) = _terrain_persistence.as_mut() {
if let Some(terrain_persistence) = data.terrain_persistence.as_mut() {
terrain_persistence.unload_chunk(key);
}
chunk_generator.cancel_if_pending(key);
data.chunk_generator.cancel_if_pending(key);
// If you want to trigger any behaivour on unload, do it in `Server::tick` by
// reading `TerrainChanges::removed_chunks` since chunks can also be removed
// using eg. /reload_chunks
// TODO: code duplication for chunk insertion between here and state.rs
terrain.remove(key).map(|chunk| {
terrain_changes.removed_chunks.insert(key);
data.terrain.remove(key).map(|chunk| {
data.terrain_changes.removed_chunks.insert(key);
chunk
})
})
.collect::<Vec<_>>();
if !chunks_to_remove.is_empty() {
// Drop chunks in a background thread.
slow_jobs.spawn("CHUNK_DROP", move || {
data.slow_jobs.spawn("CHUNK_DROP", move || {
drop(chunks_to_remove);
});
}

View File

@ -59,8 +59,6 @@ impl<'a> System<'a> for Sys {
&presences,
&clients,
);
#[cfg(not(feature = "worldgen"))]
let presences_position_entities: Vec<((vek::Vec2<i16>, i32), specs::Entity)> = Vec::new();
let real_max_view_distance =
super::terrain::convert_to_loaded_vd(u32::MAX, max_view_distance);

View File

@ -1,12 +1,12 @@
use common::{
calendar::Calendar,
generation::{ChunkSupplement, EntityInfo},
generation::ChunkSupplement,
resources::TimeOfDay,
rtsim::ChunkResource,
terrain::{
Block, BlockKind, MapSizeLg, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize,
},
vol::{ReadVol, RectVolSize, WriteVol},
vol::RectVolSize,
};
use enum_map::EnumMap;
use rand::{prelude::*, rngs::SmallRng};
@ -26,6 +26,7 @@ pub struct World;
pub struct IndexOwned;
#[derive(Clone, Copy)]
#[allow(dead_code)]
pub struct IndexRef<'a>(&'a IndexOwned);
impl IndexOwned {
@ -39,7 +40,7 @@ impl IndexOwned {
impl World {
pub fn generate(_seed: u32) -> (Self, IndexOwned) { (Self, IndexOwned) }
pub fn tick(&self, dt: Duration) {}
pub fn tick(&self, _dt: Duration) {}
#[inline(always)]
pub const fn map_size_lg(&self) -> MapSizeLg { DEFAULT_WORLD_CHUNKS_LG }
@ -63,7 +64,7 @@ impl World {
]);
let height = rng.gen::<i32>() % 8;
let mut supplement = ChunkSupplement::default();
let supplement = ChunkSupplement::default();
Ok((
TerrainChunk::new(
@ -79,7 +80,7 @@ impl World {
pub fn get_center(&self) -> Vec2<u32> {
// FIXME: Assumes that TerrainChunkSize::RECT_SIZE.x ==
// TerrainChunkSize::RECT_SIZE.y
DEFAULT_WORLD_CHUNKS_LG.chunks().as_::<u32>() / 2 * TerrainChunkSize::RECT_SIZE.x as u32
DEFAULT_WORLD_CHUNKS_LG.chunks().as_::<u32>() / 2 * TerrainChunkSize::RECT_SIZE.x
}
pub fn get_location_name(&self, _index: IndexRef, _wpos2d: Vec2<i32>) -> Option<String> {

View File

@ -10,6 +10,7 @@ pub use tick::WeatherJob;
/// How often the weather is updated, in seconds
const WEATHER_DT: f32 = 5.0;
#[cfg(feature = "worldgen")]
pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) {
dispatch::<tick::Sys>(dispatch_builder, &[]);
}