mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Remove extra chunk cloning and parallelize serialization in the server terrain sys
This commit is contained in:
parent
9e0fbd392d
commit
e17477979f
@ -1924,7 +1924,7 @@ impl Client {
|
||||
match msg {
|
||||
ServerGeneral::TerrainChunkUpdate { key, chunk } => {
|
||||
if let Ok(chunk) = chunk {
|
||||
self.state.insert_chunk(key, *chunk);
|
||||
self.state.insert_chunk(key, chunk);
|
||||
}
|
||||
self.pending_chunks.remove(&key);
|
||||
},
|
||||
|
@ -12,7 +12,7 @@ use common::{
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use vek::*;
|
||||
|
||||
///This struct contains all messages the server might send (on different
|
||||
@ -106,7 +106,7 @@ pub enum ServerGeneral {
|
||||
// Ingame related AND terrain stream
|
||||
TerrainChunkUpdate {
|
||||
key: Vec2<i32>,
|
||||
chunk: Result<Box<TerrainChunk>, ()>,
|
||||
chunk: Result<Arc<TerrainChunk>, ()>,
|
||||
},
|
||||
TerrainBlockUpdates(HashMap<Vec3<i32>, Block>),
|
||||
// Always possible
|
||||
|
@ -383,11 +383,11 @@ impl State {
|
||||
}
|
||||
|
||||
/// Insert the provided chunk into this state's terrain.
|
||||
pub fn insert_chunk(&mut self, key: Vec2<i32>, chunk: TerrainChunk) {
|
||||
pub fn insert_chunk(&mut self, key: Vec2<i32>, chunk: Arc<TerrainChunk>) {
|
||||
if self
|
||||
.ecs
|
||||
.write_resource::<TerrainGrid>()
|
||||
.insert(key, Arc::new(chunk))
|
||||
.insert(key, chunk)
|
||||
.is_some()
|
||||
{
|
||||
self.ecs
|
||||
|
@ -9,6 +9,7 @@ use common_ecs::{Job, Origin, ParMode, Phase, System};
|
||||
use common_net::msg::{ClientGeneral, ServerGeneral};
|
||||
use rayon::iter::ParallelIterator;
|
||||
use specs::{Entities, Join, ParJoin, Read, ReadExpect, ReadStorage};
|
||||
use std::sync::Arc;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
/// This system will handle new messages from clients
|
||||
@ -74,12 +75,12 @@ impl<'a> System<'a> for Sys {
|
||||
true
|
||||
};
|
||||
if in_vd {
|
||||
match terrain.get_key(key) {
|
||||
match terrain.get_key_arc(key) {
|
||||
Some(chunk) => {
|
||||
network_metrics.chunks_served_from_memory.inc();
|
||||
client.send(ServerGeneral::TerrainChunkUpdate {
|
||||
key,
|
||||
chunk: Ok(Box::new(chunk.clone())),
|
||||
chunk: Ok(Arc::clone(chunk)),
|
||||
})?
|
||||
},
|
||||
None => {
|
||||
|
@ -69,6 +69,7 @@ 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() {
|
||||
let (chunk, supplement) = match res {
|
||||
Ok((chunk, supplement)) => (chunk, supplement),
|
||||
@ -85,31 +86,16 @@ impl<'a> System<'a> for Sys {
|
||||
continue 'insert_terrain_chunks;
|
||||
},
|
||||
};
|
||||
// Send the chunk to all nearby players.
|
||||
let mut lazy_msg = None;
|
||||
for (presence, pos, client) in (&presences, &positions, &clients).join() {
|
||||
let chunk_pos = terrain.pos_key(pos.0.map(|e| e as i32));
|
||||
// Subtract 2 from the offset before computing squared magnitude
|
||||
// 1 since chunks need neighbors to be meshed
|
||||
// 1 to act as a buffer if the player moves in that direction
|
||||
let adjusted_dist_sqr = (chunk_pos - key)
|
||||
.map(|e: i32| (e.abs() as u32).saturating_sub(2))
|
||||
.magnitude_squared();
|
||||
|
||||
if adjusted_dist_sqr <= presence.view_distance.pow(2) {
|
||||
if lazy_msg.is_none() {
|
||||
lazy_msg = Some(client.prepare(ServerGeneral::TerrainChunkUpdate {
|
||||
key,
|
||||
chunk: Ok(Box::new(chunk.clone())),
|
||||
}));
|
||||
}
|
||||
lazy_msg.as_ref().map(|ref msg| client.send_prepared(&msg));
|
||||
}
|
||||
}
|
||||
// Arcify the chunk
|
||||
let chunk = Arc::new(chunk);
|
||||
|
||||
// Add to list of chunks to send to nearby players.
|
||||
new_chunks.push((key, Arc::clone(&chunk)));
|
||||
|
||||
// TODO: code duplication for chunk insertion between here and state.rs
|
||||
// Insert the chunk into terrain changes
|
||||
if terrain.insert(key, Arc::new(chunk)).is_some() {
|
||||
if terrain.insert(key, chunk).is_some() {
|
||||
terrain_changes.modified_chunks.insert(key);
|
||||
} else {
|
||||
terrain_changes.new_chunks.insert(key);
|
||||
@ -233,6 +219,36 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
|
||||
// Send the chunk to all nearby players.
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
new_chunks.into_par_iter().for_each(|(key, chunk)| {
|
||||
let mut msg = Some(ServerGeneral::TerrainChunkUpdate {
|
||||
key,
|
||||
chunk: Ok(chunk),
|
||||
});
|
||||
let mut lazy_msg = None;
|
||||
|
||||
(&presences, &positions, &clients)
|
||||
.join()
|
||||
.for_each(|(presence, pos, client)| {
|
||||
let chunk_pos = terrain.pos_key(pos.0.map(|e| e as i32));
|
||||
// Subtract 2 from the offset before computing squared magnitude
|
||||
// 1 since chunks need neighbors to be meshed
|
||||
// 1 to act as a buffer if the player moves in that direction
|
||||
let adjusted_dist_sqr = (chunk_pos - key)
|
||||
.map(|e: i32| (e.abs() as u32).saturating_sub(2))
|
||||
.magnitude_squared();
|
||||
|
||||
if adjusted_dist_sqr <= presence.view_distance.pow(2) {
|
||||
if let Some(msg) = msg.take() {
|
||||
lazy_msg = Some(client.prepare(msg));
|
||||
};
|
||||
|
||||
lazy_msg.as_ref().map(|msg| client.send_prepared(msg));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Remove chunks that are too far from players.
|
||||
let mut chunks_to_remove = Vec::new();
|
||||
terrain
|
||||
|
@ -4,6 +4,7 @@ use common_ecs::{Job, Origin, Phase, System};
|
||||
use common_net::msg::ServerGeneral;
|
||||
use common_state::TerrainChanges;
|
||||
use specs::{Join, Read, ReadExpect, ReadStorage};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// This systems sends new chunks to clients as well as changes to existing
|
||||
/// chunks
|
||||
@ -37,10 +38,10 @@ impl<'a> System<'a> for Sys {
|
||||
if lazy_msg.is_none() {
|
||||
lazy_msg = Some(client.prepare(ServerGeneral::TerrainChunkUpdate {
|
||||
key: *chunk_key,
|
||||
chunk: Ok(Box::new(match terrain.get_key(*chunk_key) {
|
||||
Some(chunk) => chunk.clone(),
|
||||
chunk: Ok(match terrain.get_key_arc(*chunk_key) {
|
||||
Some(chunk) => Arc::clone(chunk),
|
||||
None => break 'chunk,
|
||||
})),
|
||||
}),
|
||||
}));
|
||||
}
|
||||
lazy_msg.as_ref().map(|ref msg| client.send_prepared(&msg));
|
||||
|
Loading…
Reference in New Issue
Block a user