-
Notifications
You must be signed in to change notification settings - Fork 144
Expand file tree
/
Copy pathblock.rs
More file actions
82 lines (73 loc) · 2.77 KB
/
block.rs
File metadata and controls
82 lines (73 loc) · 2.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//! Implements block change broadcasting.
//!
//! # Bulk updates
//! The protocol provides three methods to change blocks
//! on the client:
//! * The `BlockChange` packet to update a single block.
//! * The `MultiBlockChange` packet to update multiple blocks
//! within a single chunk section.
//! * The `ChunkData` packet to overwrite entire chunk sections
//! at once.
//!
//! Feather is optimized for bulk block updates to cater to plugins
//! like WorldEdit. This module chooses the optimal packet from
//! the above three options to achieve ideal performance.
use ahash::AHashMap;
use base::{chunk::SECTION_VOLUME, position, ChunkPosition, CHUNK_WIDTH};
use common::{events::BlockChangeEvent, Game};
use ecs::{SysResult, SystemExecutor};
use crate::Server;
pub fn register(systems: &mut SystemExecutor<Game>) {
systems
.group::<Server>()
.add_system(broadcast_block_changes);
}
fn broadcast_block_changes(game: &mut Game, server: &mut Server) -> SysResult {
for (_, event) in game.ecs.query::<&BlockChangeEvent>().iter() {
broadcast_block_change(event, game, server);
}
Ok(())
}
/// Threshold at which to switch from block change to chunk
// overwrite packets.
const CHUNK_OVERWRITE_THRESHOLD: usize = SECTION_VOLUME / 2;
fn broadcast_block_change(event: &BlockChangeEvent, game: &Game, server: &mut Server) {
if event.count() >= CHUNK_OVERWRITE_THRESHOLD {
broadcast_block_change_chunk_overwrite(event, game, server);
} else {
broadcast_block_change_simple(event, game, server);
}
}
fn broadcast_block_change_chunk_overwrite(
event: &BlockChangeEvent,
game: &Game,
server: &mut Server,
) {
let mut sections: AHashMap<ChunkPosition, Vec<usize>> = AHashMap::new();
for (chunk, section, _) in event.iter_affected_chunk_sections() {
sections.entry(chunk).or_default().push(section + 1); // + 1 to account for the void air chunk
}
for (chunk_pos, sections) in sections {
let chunk = game.world.chunk_map().chunk_handle_at(chunk_pos);
if let Some(chunk) = chunk {
let position = position!(
(chunk_pos.x * CHUNK_WIDTH as i32) as f64,
0.0,
(chunk_pos.z * CHUNK_WIDTH as i32) as f64,
);
server.broadcast_nearby_with(position, |client| {
client.overwrite_chunk_sections(&chunk, sections.clone());
})
}
}
}
fn broadcast_block_change_simple(event: &BlockChangeEvent, game: &Game, server: &mut Server) {
for pos in event.iter_changed_blocks() {
let new_block = game.block(pos);
if let Some(new_block) = new_block {
server.broadcast_nearby_with(pos.position(), |client| {
client.send_block_change(pos, new_block)
});
}
}
}