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:
@ -1924,7 +1924,7 @@ impl Client {
|
|||||||
match msg {
|
match msg {
|
||||||
ServerGeneral::TerrainChunkUpdate { key, chunk } => {
|
ServerGeneral::TerrainChunkUpdate { key, chunk } => {
|
||||||
if let Ok(chunk) = chunk {
|
if let Ok(chunk) = chunk {
|
||||||
self.state.insert_chunk(key, *chunk);
|
self.state.insert_chunk(key, chunk);
|
||||||
}
|
}
|
||||||
self.pending_chunks.remove(&key);
|
self.pending_chunks.remove(&key);
|
||||||
},
|
},
|
||||||
|
@ -12,7 +12,7 @@ use common::{
|
|||||||
};
|
};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::time::Duration;
|
use std::{sync::Arc, time::Duration};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
///This struct contains all messages the server might send (on different
|
///This struct contains all messages the server might send (on different
|
||||||
@ -106,7 +106,7 @@ pub enum ServerGeneral {
|
|||||||
// Ingame related AND terrain stream
|
// Ingame related AND terrain stream
|
||||||
TerrainChunkUpdate {
|
TerrainChunkUpdate {
|
||||||
key: Vec2<i32>,
|
key: Vec2<i32>,
|
||||||
chunk: Result<Box<TerrainChunk>, ()>,
|
chunk: Result<Arc<TerrainChunk>, ()>,
|
||||||
},
|
},
|
||||||
TerrainBlockUpdates(HashMap<Vec3<i32>, Block>),
|
TerrainBlockUpdates(HashMap<Vec3<i32>, Block>),
|
||||||
// Always possible
|
// Always possible
|
||||||
|
@ -383,11 +383,11 @@ impl State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Insert the provided chunk into this state's terrain.
|
/// 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
|
if self
|
||||||
.ecs
|
.ecs
|
||||||
.write_resource::<TerrainGrid>()
|
.write_resource::<TerrainGrid>()
|
||||||
.insert(key, Arc::new(chunk))
|
.insert(key, chunk)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
self.ecs
|
self.ecs
|
||||||
|
@ -9,6 +9,7 @@ use common_ecs::{Job, Origin, ParMode, Phase, System};
|
|||||||
use common_net::msg::{ClientGeneral, ServerGeneral};
|
use common_net::msg::{ClientGeneral, ServerGeneral};
|
||||||
use rayon::iter::ParallelIterator;
|
use rayon::iter::ParallelIterator;
|
||||||
use specs::{Entities, Join, ParJoin, Read, ReadExpect, ReadStorage};
|
use specs::{Entities, Join, ParJoin, Read, ReadExpect, ReadStorage};
|
||||||
|
use std::sync::Arc;
|
||||||
use tracing::{debug, trace};
|
use tracing::{debug, trace};
|
||||||
|
|
||||||
/// This system will handle new messages from clients
|
/// This system will handle new messages from clients
|
||||||
@ -74,12 +75,12 @@ impl<'a> System<'a> for Sys {
|
|||||||
true
|
true
|
||||||
};
|
};
|
||||||
if in_vd {
|
if in_vd {
|
||||||
match terrain.get_key(key) {
|
match terrain.get_key_arc(key) {
|
||||||
Some(chunk) => {
|
Some(chunk) => {
|
||||||
network_metrics.chunks_served_from_memory.inc();
|
network_metrics.chunks_served_from_memory.inc();
|
||||||
client.send(ServerGeneral::TerrainChunkUpdate {
|
client.send(ServerGeneral::TerrainChunkUpdate {
|
||||||
key,
|
key,
|
||||||
chunk: Ok(Box::new(chunk.clone())),
|
chunk: Ok(Arc::clone(chunk)),
|
||||||
})?
|
})?
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
@ -69,6 +69,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
|
|
||||||
// Fetch any generated `TerrainChunk`s and insert them into the terrain.
|
// Fetch any generated `TerrainChunk`s and insert them into the terrain.
|
||||||
// Also, send the chunk data to anybody that is close by.
|
// 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)) = chunk_generator.recv_new_chunk() {
|
||||||
let (chunk, supplement) = match res {
|
let (chunk, supplement) = match res {
|
||||||
Ok((chunk, supplement)) => (chunk, supplement),
|
Ok((chunk, supplement)) => (chunk, supplement),
|
||||||
@ -85,31 +86,16 @@ impl<'a> System<'a> for Sys {
|
|||||||
continue 'insert_terrain_chunks;
|
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) {
|
// Arcify the chunk
|
||||||
if lazy_msg.is_none() {
|
let chunk = Arc::new(chunk);
|
||||||
lazy_msg = Some(client.prepare(ServerGeneral::TerrainChunkUpdate {
|
|
||||||
key,
|
// Add to list of chunks to send to nearby players.
|
||||||
chunk: Ok(Box::new(chunk.clone())),
|
new_chunks.push((key, Arc::clone(&chunk)));
|
||||||
}));
|
|
||||||
}
|
|
||||||
lazy_msg.as_ref().map(|ref msg| client.send_prepared(&msg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: code duplication for chunk insertion between here and state.rs
|
// TODO: code duplication for chunk insertion between here and state.rs
|
||||||
// Insert the chunk into terrain changes
|
// 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);
|
terrain_changes.modified_chunks.insert(key);
|
||||||
} else {
|
} else {
|
||||||
terrain_changes.new_chunks.insert(key);
|
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.
|
// Remove chunks that are too far from players.
|
||||||
let mut chunks_to_remove = Vec::new();
|
let mut chunks_to_remove = Vec::new();
|
||||||
terrain
|
terrain
|
||||||
|
@ -4,6 +4,7 @@ use common_ecs::{Job, Origin, Phase, System};
|
|||||||
use common_net::msg::ServerGeneral;
|
use common_net::msg::ServerGeneral;
|
||||||
use common_state::TerrainChanges;
|
use common_state::TerrainChanges;
|
||||||
use specs::{Join, Read, ReadExpect, ReadStorage};
|
use specs::{Join, Read, ReadExpect, ReadStorage};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// This systems sends new chunks to clients as well as changes to existing
|
/// This systems sends new chunks to clients as well as changes to existing
|
||||||
/// chunks
|
/// chunks
|
||||||
@ -37,10 +38,10 @@ impl<'a> System<'a> for Sys {
|
|||||||
if lazy_msg.is_none() {
|
if lazy_msg.is_none() {
|
||||||
lazy_msg = Some(client.prepare(ServerGeneral::TerrainChunkUpdate {
|
lazy_msg = Some(client.prepare(ServerGeneral::TerrainChunkUpdate {
|
||||||
key: *chunk_key,
|
key: *chunk_key,
|
||||||
chunk: Ok(Box::new(match terrain.get_key(*chunk_key) {
|
chunk: Ok(match terrain.get_key_arc(*chunk_key) {
|
||||||
Some(chunk) => chunk.clone(),
|
Some(chunk) => Arc::clone(chunk),
|
||||||
None => break 'chunk,
|
None => break 'chunk,
|
||||||
})),
|
}),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
lazy_msg.as_ref().map(|ref msg| client.send_prepared(&msg));
|
lazy_msg.as_ref().map(|ref msg| client.send_prepared(&msg));
|
||||||
|
Reference in New Issue
Block a user