-
Notifications
You must be signed in to change notification settings - Fork 144
Expand file tree
/
Copy pathchunk_subscriptions.rs
More file actions
95 lines (84 loc) · 2.69 KB
/
Copy pathchunk_subscriptions.rs
File metadata and controls
95 lines (84 loc) · 2.69 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
83
84
85
86
87
88
89
90
91
92
93
94
95
use ahash::AHashMap;
use common::{events::ViewUpdateEvent, view::View, Game};
use libcraft::ChunkPosition;
use quill::components::EntityWorld;
use quill::events::EntityRemoveEvent;
use quill::WorldId;
use utils::vec_remove_item;
use vane::{SysResult, SystemExecutor};
use crate::{ClientId, Server};
#[derive(Eq, PartialEq, Hash)]
pub struct ChunkPositionWithWorld {
pub world: WorldId,
pub chunk: ChunkPosition,
}
impl ChunkPositionWithWorld {
pub fn new(world: WorldId, chunk: ChunkPosition) -> Self {
Self { world, chunk }
}
}
/// Data structure to query which clients should
/// receive updates from a given chunk, fast.
#[derive(Default)]
pub struct ChunkSubscriptions {
chunks: AHashMap<ChunkPositionWithWorld, Vec<ClientId>>,
}
impl ChunkSubscriptions {
pub fn subscriptions_for(&self, chunk: ChunkPositionWithWorld) -> &[ClientId] {
self.chunks
.get(&chunk)
.map(Vec::as_slice)
.unwrap_or_default()
}
}
pub fn register(systems: &mut SystemExecutor<Game>) {
systems
.group::<Server>()
.add_system(update_chunk_subscriptions);
}
fn update_chunk_subscriptions(game: &mut Game, server: &mut Server) -> SysResult {
// Update players whose views have changed
for (_, (event, client_id)) in game.ecs.query::<(&ViewUpdateEvent, &ClientId)>().iter() {
for new_chunk in event.new_view.difference(&event.old_view) {
server
.chunk_subscriptions
.chunks
.entry(ChunkPositionWithWorld::new(
event.new_view.world(),
new_chunk,
))
.or_default()
.push(*client_id);
}
for old_chunk in event.old_view.difference(&event.new_view) {
remove_subscription(
server,
ChunkPositionWithWorld::new(event.old_view.world(), old_chunk),
*client_id,
);
}
}
// Update players that have left
for (_, (_event, client_id, view, world)) in game
.ecs
.query::<(&EntityRemoveEvent, &ClientId, &View, &EntityWorld)>()
.iter()
{
for chunk in view.iter() {
remove_subscription(
server,
ChunkPositionWithWorld::new(world.0, chunk),
*client_id,
);
}
}
Ok(())
}
fn remove_subscription(server: &mut Server, chunk: ChunkPositionWithWorld, client_id: ClientId) {
if let Some(vec) = server.chunk_subscriptions.chunks.get_mut(&chunk) {
vec_remove_item(vec, &client_id);
if vec.is_empty() {
server.chunk_subscriptions.chunks.remove(&chunk);
}
}
}