2022-05-10 11:36:44 +00:00
|
|
|
use crate::{
|
2022-05-11 19:50:14 +00:00
|
|
|
chunk_serialize::ChunkSendEntry, client::Client, lod::Lod, metrics::NetworkRequestMetrics,
|
2022-05-08 23:11:46 +00:00
|
|
|
presence::Presence, ChunkRequest,
|
2022-05-10 11:36:44 +00:00
|
|
|
};
|
2021-03-11 12:07:03 +00:00
|
|
|
use common::{
|
|
|
|
comp::Pos,
|
2022-02-27 23:08:47 +00:00
|
|
|
event::{EventBus, ServerEvent},
|
2021-10-07 13:23:55 +00:00
|
|
|
spiral::Spiral2d,
|
2021-04-20 23:33:42 +00:00
|
|
|
terrain::{TerrainChunkSize, TerrainGrid},
|
2021-03-11 12:07:03 +00:00
|
|
|
vol::RectVolSize,
|
|
|
|
};
|
2021-03-28 19:08:40 +00:00
|
|
|
use common_ecs::{Job, Origin, ParMode, Phase, System};
|
2022-05-08 23:11:46 +00:00
|
|
|
use common_net::msg::{ClientGeneral, ServerGeneral};
|
2021-03-28 19:08:40 +00:00
|
|
|
use rayon::iter::ParallelIterator;
|
2022-05-11 15:52:22 +00:00
|
|
|
use specs::{Entities, Join, ParJoin, Read, ReadExpect, ReadStorage, Write};
|
2021-03-11 12:07:03 +00:00
|
|
|
use tracing::{debug, trace};
|
|
|
|
|
|
|
|
/// This system will handle new messages from clients
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct Sys;
|
|
|
|
impl<'a> System<'a> for Sys {
|
|
|
|
type SystemData = (
|
|
|
|
Entities<'a>,
|
2022-02-27 23:08:47 +00:00
|
|
|
Read<'a, EventBus<ServerEvent>>,
|
2022-05-11 19:50:14 +00:00
|
|
|
ReadExpect<'a, EventBus<ChunkSendEntry>>,
|
2021-03-11 12:07:03 +00:00
|
|
|
ReadExpect<'a, TerrainGrid>,
|
2022-05-08 23:53:19 +00:00
|
|
|
ReadExpect<'a, Lod>,
|
2021-03-11 12:07:03 +00:00
|
|
|
ReadExpect<'a, NetworkRequestMetrics>,
|
2021-10-08 18:31:04 +00:00
|
|
|
Write<'a, Vec<ChunkRequest>>,
|
2021-03-11 12:07:03 +00:00
|
|
|
ReadStorage<'a, Pos>,
|
|
|
|
ReadStorage<'a, Presence>,
|
|
|
|
ReadStorage<'a, Client>,
|
|
|
|
);
|
|
|
|
|
2021-03-11 17:40:22 +00:00
|
|
|
const NAME: &'static str = "msg::terrain";
|
2021-03-11 12:07:03 +00:00
|
|
|
const ORIGIN: Origin = Origin::Server;
|
|
|
|
const PHASE: Phase = Phase::Create;
|
|
|
|
|
|
|
|
fn run(
|
2021-03-28 19:08:40 +00:00
|
|
|
job: &mut Job<Self>,
|
2021-03-11 12:07:03 +00:00
|
|
|
(
|
|
|
|
entities,
|
2022-02-27 23:08:47 +00:00
|
|
|
server_event_bus,
|
2022-05-11 15:52:22 +00:00
|
|
|
chunk_send_bus,
|
2021-03-11 12:07:03 +00:00
|
|
|
terrain,
|
2022-05-08 23:53:19 +00:00
|
|
|
lod,
|
2021-03-11 12:07:03 +00:00
|
|
|
network_metrics,
|
2021-10-08 18:31:04 +00:00
|
|
|
mut chunk_requests,
|
2021-03-11 12:07:03 +00:00
|
|
|
positions,
|
|
|
|
presences,
|
|
|
|
clients,
|
|
|
|
): Self::SystemData,
|
|
|
|
) {
|
2021-03-28 19:08:40 +00:00
|
|
|
job.cpu_stats.measure(ParMode::Rayon);
|
2022-05-11 15:52:22 +00:00
|
|
|
let mut new_chunk_requests = (&entities, &clients, (&presences).maybe())
|
2021-03-28 19:08:40 +00:00
|
|
|
.par_join()
|
2022-05-11 15:52:22 +00:00
|
|
|
.map_init(
|
|
|
|
|| (chunk_send_bus.emitter(), server_event_bus.emitter()),
|
|
|
|
|(chunk_send_emitter, server_emitter), (entity, client, maybe_presence)| {
|
|
|
|
let mut chunk_requests = Vec::new();
|
|
|
|
let _ = super::try_recv_all(client, 5, |_, msg| {
|
|
|
|
let presence = match maybe_presence {
|
|
|
|
Some(g) => g,
|
|
|
|
None => {
|
|
|
|
debug!(?entity, "client is not in_game, ignoring msg");
|
|
|
|
trace!(?msg, "ignored msg content");
|
|
|
|
if matches!(msg, ClientGeneral::TerrainChunkRequest { .. }) {
|
|
|
|
network_metrics.chunks_request_dropped.inc();
|
|
|
|
}
|
|
|
|
return Ok(());
|
|
|
|
},
|
|
|
|
};
|
|
|
|
match msg {
|
|
|
|
ClientGeneral::TerrainChunkRequest { key } => {
|
|
|
|
let in_vd = if let Some(pos) = positions.get(entity) {
|
|
|
|
pos.0.xy().map(|e| e as f64).distance_squared(
|
|
|
|
key.map(|e| e as f64 + 0.5)
|
|
|
|
* TerrainChunkSize::RECT_SIZE.map(|e| e as f64),
|
|
|
|
) < ((presence.view_distance as f64 - 1.0
|
|
|
|
+ 2.5 * 2.0_f64.sqrt())
|
|
|
|
* TerrainChunkSize::RECT_SIZE.x as f64)
|
|
|
|
.powi(2)
|
2022-05-08 23:11:46 +00:00
|
|
|
} else {
|
2022-05-11 15:52:22 +00:00
|
|
|
true
|
|
|
|
};
|
|
|
|
if in_vd {
|
|
|
|
if terrain.get_key_arc(key).is_some() {
|
|
|
|
network_metrics.chunks_served_from_memory.inc();
|
2022-05-11 19:50:14 +00:00
|
|
|
chunk_send_emitter.emit(ChunkSendEntry {
|
2022-05-11 15:52:22 +00:00
|
|
|
chunk_key: key,
|
|
|
|
entity,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
network_metrics.chunks_generation_triggered.inc();
|
|
|
|
chunk_requests.push(ChunkRequest { entity, key });
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
network_metrics.chunks_request_dropped.inc();
|
2021-03-28 19:08:40 +00:00
|
|
|
}
|
2022-05-11 15:52:22 +00:00
|
|
|
},
|
|
|
|
ClientGeneral::LodZoneRequest { key } => {
|
|
|
|
client.send(ServerGeneral::LodZoneUpdate {
|
|
|
|
key,
|
|
|
|
zone: lod.zone(key).clone(),
|
|
|
|
})?;
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
debug!(
|
|
|
|
"Kicking possibly misbehaving client due to invalud terrain \
|
|
|
|
request"
|
|
|
|
);
|
|
|
|
server_emitter.emit(ServerEvent::ClientDisconnect(
|
|
|
|
entity,
|
|
|
|
common::comp::DisconnectReason::NetworkError,
|
|
|
|
));
|
|
|
|
},
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
});
|
2021-10-07 13:23:55 +00:00
|
|
|
|
2022-05-11 15:52:22 +00:00
|
|
|
// Load a minimum radius of chunks around each player.
|
|
|
|
// This is used to prevent view distance reloading exploits and make sure that
|
|
|
|
// entity simulation occurs within a minimum radius around the
|
|
|
|
// player.
|
|
|
|
if let Some(pos) = positions.get(entity) {
|
|
|
|
let player_chunk = pos
|
|
|
|
.0
|
|
|
|
.xy()
|
|
|
|
.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e as i32 / sz as i32);
|
|
|
|
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() {
|
|
|
|
// 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 });
|
|
|
|
}
|
2021-10-07 13:23:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-11 15:52:22 +00:00
|
|
|
chunk_requests
|
|
|
|
},
|
|
|
|
)
|
2021-03-28 19:08:40 +00:00
|
|
|
.flatten()
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
job.cpu_stats.measure(ParMode::Single);
|
2021-10-08 18:31:04 +00:00
|
|
|
|
|
|
|
chunk_requests.append(&mut new_chunk_requests);
|
2021-03-11 12:07:03 +00:00
|
|
|
}
|
|
|
|
}
|