mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
distance changes (until the player crossed a chunk boundary and triggered the normal update). This introduces a `ViewDistance` struct that provides an abstraction around limiting the rate the view distance can be cycled up and down. This helps avoid unnecessary sending, deleting, and then resending of synced things like entities (the client will still delete its terrain locally and re-request it though). The second part of this fix is storing the last view distance in the `RegionSubscription` struct and then updating region subscriptions if this doesn't match the current view distance in the `Presence` component.
65 lines
2.3 KiB
Rust
65 lines
2.3 KiB
Rust
use crate::{chunk_serialize::ChunkSendEntry, client::Client, presence::Presence};
|
|
use common::{comp::Pos, event::EventBus, terrain::TerrainGrid};
|
|
use common_ecs::{Job, Origin, Phase, System};
|
|
use common_net::msg::{CompressedData, ServerGeneral};
|
|
use common_state::TerrainChanges;
|
|
use specs::{Entities, Join, Read, ReadExpect, ReadStorage};
|
|
|
|
/// This systems sends new chunks to clients as well as changes to existing
|
|
/// chunks
|
|
#[derive(Default)]
|
|
pub struct Sys;
|
|
impl<'a> System<'a> for Sys {
|
|
type SystemData = (
|
|
Entities<'a>,
|
|
ReadExpect<'a, TerrainGrid>,
|
|
Read<'a, TerrainChanges>,
|
|
ReadExpect<'a, EventBus<ChunkSendEntry>>,
|
|
ReadStorage<'a, Pos>,
|
|
ReadStorage<'a, Presence>,
|
|
ReadStorage<'a, Client>,
|
|
);
|
|
|
|
const NAME: &'static str = "terrain_sync";
|
|
const ORIGIN: Origin = Origin::Server;
|
|
const PHASE: Phase = Phase::Create;
|
|
|
|
fn run(
|
|
_job: &mut Job<Self>,
|
|
(entities, terrain, terrain_changes, chunk_send_bus, positions, presences, clients): Self::SystemData,
|
|
) {
|
|
let mut chunk_send_emitter = chunk_send_bus.emitter();
|
|
|
|
// Sync changed chunks
|
|
for chunk_key in &terrain_changes.modified_chunks {
|
|
for (entity, presence, pos) in (&entities, &presences, &positions).join() {
|
|
if super::terrain::chunk_in_vd(
|
|
pos.0,
|
|
*chunk_key,
|
|
&terrain,
|
|
presence.view_distance.current(),
|
|
) {
|
|
chunk_send_emitter.emit(ChunkSendEntry {
|
|
entity,
|
|
chunk_key: *chunk_key,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: Don't send all changed blocks to all clients
|
|
// Sync changed blocks
|
|
if !terrain_changes.modified_blocks.is_empty() {
|
|
let mut lazy_msg = None;
|
|
for (_, client) in (&presences, &clients).join() {
|
|
if lazy_msg.is_none() {
|
|
lazy_msg = Some(client.prepare(ServerGeneral::TerrainBlockUpdates(
|
|
CompressedData::compress(&terrain_changes.modified_blocks, 1),
|
|
)));
|
|
}
|
|
lazy_msg.as_ref().map(|msg| client.send_prepared(msg));
|
|
}
|
|
}
|
|
}
|
|
}
|