mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'imbris/dedup-chunk-gen-attempt' into 'master'
More robustly avoid duplicate chunk generation See merge request veloren/veloren!2912
This commit is contained in:
commit
a7a9e00a3a
@ -148,7 +148,6 @@ pub enum ServerEvent {
|
||||
CreateWaypoint(Vec3<f32>),
|
||||
ClientDisconnect(EcsEntity, DisconnectReason),
|
||||
ClientDisconnectWithoutPersistence(EcsEntity),
|
||||
ChunkRequest(EcsEntity, Vec2<i32>),
|
||||
Command(EcsEntity, String, Vec<String>),
|
||||
/// Send a chat message to the player from an npc or other player
|
||||
Chat(comp::UnresolvedChatMsg),
|
||||
|
@ -65,14 +65,17 @@ impl ChunkGenerator {
|
||||
}
|
||||
|
||||
pub fn recv_new_chunk(&mut self) -> Option<ChunkGenResult> {
|
||||
if let Ok((key, res)) = self.chunk_rx.try_recv() {
|
||||
self.pending_chunks.remove(&key);
|
||||
self.metrics.chunks_served.inc();
|
||||
// TODO: do anything else if res is an Err?
|
||||
Some((key, res))
|
||||
} else {
|
||||
None
|
||||
// Make sure chunk wasn't cancelled and if it was check to see if there are more
|
||||
// chunks to receive
|
||||
while let Ok((key, res)) = self.chunk_rx.try_recv() {
|
||||
if self.pending_chunks.remove(&key).is_some() {
|
||||
self.metrics.chunks_served.inc();
|
||||
// TODO: do anything else if res is an Err?
|
||||
return Some((key, res));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn pending_chunks(&self) -> impl Iterator<Item = Vec2<i32>> + '_ {
|
||||
|
@ -51,7 +51,6 @@ impl Server {
|
||||
span!(_guard, "handle_events", "Server::handle_events");
|
||||
let mut frontend_events = Vec::new();
|
||||
|
||||
let mut requested_chunks = Vec::new();
|
||||
let mut commands = Vec::new();
|
||||
let mut chat_messages = Vec::new();
|
||||
|
||||
@ -191,10 +190,6 @@ impl Server {
|
||||
true,
|
||||
))
|
||||
},
|
||||
|
||||
ServerEvent::ChunkRequest(entity, key) => {
|
||||
requested_chunks.push((entity, key));
|
||||
},
|
||||
ServerEvent::Command(entity, name, args) => {
|
||||
commands.push((entity, name, args));
|
||||
},
|
||||
@ -245,11 +240,6 @@ impl Server {
|
||||
}
|
||||
}
|
||||
|
||||
// Generate requested chunks
|
||||
for (entity, key) in requested_chunks {
|
||||
self.generate_chunk(entity, key);
|
||||
}
|
||||
|
||||
for (entity, name, args) in commands {
|
||||
self.process_command(entity, name, args);
|
||||
}
|
||||
|
@ -180,6 +180,11 @@ impl BattleModeBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ChunkRequest {
|
||||
entity: EcsEntity,
|
||||
key: Vec2<i32>,
|
||||
}
|
||||
|
||||
pub struct Server {
|
||||
state: State,
|
||||
world: Arc<World>,
|
||||
@ -234,6 +239,7 @@ impl Server {
|
||||
path: data_dir.to_owned(),
|
||||
});
|
||||
state.ecs_mut().insert(EventBus::<ServerEvent>::default());
|
||||
state.ecs_mut().insert(Vec::<ChunkRequest>::new());
|
||||
state.ecs_mut().insert(LoginProvider::new(
|
||||
settings.auth_server_address.clone(),
|
||||
Arc::clone(&runtime),
|
||||
@ -1071,7 +1077,7 @@ impl Server {
|
||||
|
||||
pub fn generate_chunk(&mut self, entity: EcsEntity, key: Vec2<i32>) {
|
||||
let ecs = self.state.ecs();
|
||||
let slow_jobs = ecs.write_resource::<SlowJobPool>();
|
||||
let slow_jobs = ecs.read_resource::<SlowJobPool>();
|
||||
ecs.write_resource::<ChunkGenerator>().generate_chunk(
|
||||
Some(entity),
|
||||
key,
|
||||
|
@ -27,7 +27,7 @@ pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||
dispatch::<melee::Sys>(dispatch_builder, &[&projectile::Sys::sys_name()]);
|
||||
//Note: server should not depend on interpolation system
|
||||
dispatch::<agent::Sys>(dispatch_builder, &[]);
|
||||
dispatch::<terrain::Sys>(dispatch_builder, &[]);
|
||||
dispatch::<terrain::Sys>(dispatch_builder, &[&msg::terrain::Sys::sys_name()]);
|
||||
dispatch::<waypoint::Sys>(dispatch_builder, &[]);
|
||||
dispatch::<invite_timeout::Sys>(dispatch_builder, &[]);
|
||||
dispatch::<persistence::Sys>(dispatch_builder, &[]);
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::{client::Client, metrics::NetworkRequestMetrics, presence::Presence};
|
||||
use crate::{client::Client, metrics::NetworkRequestMetrics, presence::Presence, ChunkRequest};
|
||||
use common::{
|
||||
comp::Pos,
|
||||
event::{EventBus, ServerEvent},
|
||||
spiral::Spiral2d,
|
||||
terrain::{TerrainChunkSize, TerrainGrid},
|
||||
vol::RectVolSize,
|
||||
@ -9,7 +8,7 @@ use common::{
|
||||
use common_ecs::{Job, Origin, ParMode, Phase, System};
|
||||
use common_net::msg::{ClientGeneral, SerializedTerrainChunk, ServerGeneral};
|
||||
use rayon::iter::ParallelIterator;
|
||||
use specs::{Entities, Join, ParJoin, Read, ReadExpect, ReadStorage};
|
||||
use specs::{Entities, Join, ParJoin, ReadExpect, ReadStorage, Write};
|
||||
use tracing::{debug, trace};
|
||||
|
||||
/// This system will handle new messages from clients
|
||||
@ -19,9 +18,9 @@ impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
ReadExpect<'a, NetworkRequestMetrics>,
|
||||
Write<'a, Vec<ChunkRequest>>,
|
||||
ReadStorage<'a, Pos>,
|
||||
ReadStorage<'a, Presence>,
|
||||
ReadStorage<'a, Client>,
|
||||
@ -35,21 +34,19 @@ impl<'a> System<'a> for Sys {
|
||||
job: &mut Job<Self>,
|
||||
(
|
||||
entities,
|
||||
server_event_bus,
|
||||
terrain,
|
||||
network_metrics,
|
||||
mut chunk_requests,
|
||||
positions,
|
||||
presences,
|
||||
clients,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
let mut server_emitter = server_event_bus.emitter();
|
||||
|
||||
job.cpu_stats.measure(ParMode::Rayon);
|
||||
let mut events = (&entities, &clients, (&presences).maybe())
|
||||
let mut new_chunk_requests = (&entities, &clients, (&presences).maybe())
|
||||
.par_join()
|
||||
.map(|(entity, client, maybe_presence)| {
|
||||
let mut events = Vec::new();
|
||||
let mut chunk_requests = Vec::new();
|
||||
let _ = super::try_recv_all(client, 5, |client, msg| {
|
||||
let presence = match maybe_presence {
|
||||
Some(g) => g,
|
||||
@ -93,7 +90,7 @@ impl<'a> System<'a> for Sys {
|
||||
},
|
||||
None => {
|
||||
network_metrics.chunks_generation_triggered.inc();
|
||||
events.push(ServerEvent::ChunkRequest(entity, key));
|
||||
chunk_requests.push(ChunkRequest { entity, key });
|
||||
},
|
||||
}
|
||||
} else {
|
||||
@ -117,19 +114,21 @@ impl<'a> System<'a> for Sys {
|
||||
for rpos in Spiral2d::new().take((crate::MIN_VD as usize + 1).pow(2)) {
|
||||
let key = player_chunk + rpos;
|
||||
if terrain.get_key(key).is_none() {
|
||||
events.push(ServerEvent::ChunkRequest(entity, key));
|
||||
// TODO: @zesterer do we want to be sending these chunk to the client
|
||||
// even if they aren't requested? If we don't we could replace the
|
||||
// entity here with Option<Entity> and pass in None.
|
||||
chunk_requests.push(ChunkRequest { entity, key });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
events
|
||||
chunk_requests
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
job.cpu_stats.measure(ParMode::Single);
|
||||
for event in events.drain(..) {
|
||||
server_emitter.emit(event);
|
||||
}
|
||||
|
||||
chunk_requests.append(&mut new_chunk_requests);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,10 @@
|
||||
#[cfg(feature = "persistent_world")]
|
||||
use crate::TerrainPersistence;
|
||||
#[cfg(not(feature = "worldgen"))]
|
||||
use test_world::{IndexOwned, World};
|
||||
#[cfg(feature = "worldgen")]
|
||||
use world::{IndexOwned, World};
|
||||
|
||||
use crate::{
|
||||
chunk_generator::ChunkGenerator,
|
||||
client::Client,
|
||||
@ -7,14 +12,15 @@ use crate::{
|
||||
presence::{Presence, RepositionOnChunkLoad},
|
||||
rtsim::RtSim,
|
||||
settings::Settings,
|
||||
SpawnPoint, Tick,
|
||||
ChunkRequest, SpawnPoint, Tick,
|
||||
};
|
||||
use common::{
|
||||
comp::{self, agent, bird_medium, BehaviorCapability, ForceUpdate, Pos, Waypoint},
|
||||
event::{EventBus, ServerEvent},
|
||||
generation::EntityInfo,
|
||||
lottery::LootSpec,
|
||||
resources::Time,
|
||||
resources::{Time, TimeOfDay},
|
||||
slowjob::SlowJobPool,
|
||||
terrain::TerrainGrid,
|
||||
LoadoutBuilder, SkillSetBuilder,
|
||||
};
|
||||
@ -104,10 +110,15 @@ impl<'a> System<'a> for Sys {
|
||||
Read<'a, Tick>,
|
||||
Read<'a, SpawnPoint>,
|
||||
Read<'a, Settings>,
|
||||
Read<'a, TimeOfDay>,
|
||||
ReadExpect<'a, SlowJobPool>,
|
||||
ReadExpect<'a, IndexOwned>,
|
||||
ReadExpect<'a, Arc<World>>,
|
||||
ReadExpect<'a, NetworkRequestMetrics>,
|
||||
WriteExpect<'a, ChunkGenerator>,
|
||||
WriteExpect<'a, TerrainGrid>,
|
||||
Write<'a, TerrainChanges>,
|
||||
Write<'a, Vec<ChunkRequest>>,
|
||||
WriteExpect<'a, RtSim>,
|
||||
TerrainPersistenceData<'a>,
|
||||
WriteStorage<'a, Pos>,
|
||||
@ -131,10 +142,15 @@ impl<'a> System<'a> for Sys {
|
||||
tick,
|
||||
spawn_point,
|
||||
server_settings,
|
||||
time_of_day,
|
||||
slow_jobs,
|
||||
index,
|
||||
world,
|
||||
network_metrics,
|
||||
mut chunk_generator,
|
||||
mut terrain,
|
||||
mut terrain_changes,
|
||||
mut chunk_requests,
|
||||
mut rtsim,
|
||||
mut _terrain_persistence,
|
||||
mut positions,
|
||||
@ -149,6 +165,22 @@ impl<'a> System<'a> for Sys {
|
||||
) {
|
||||
let mut server_emitter = server_event_bus.emitter();
|
||||
|
||||
// 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(
|
||||
Some(request.entity),
|
||||
request.key,
|
||||
&slow_jobs,
|
||||
Arc::clone(&world),
|
||||
index.clone(),
|
||||
*time_of_day,
|
||||
)
|
||||
});
|
||||
|
||||
// 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();
|
||||
|
Loading…
Reference in New Issue
Block a user