Skip to content

Commit f93316d

Browse files
committed
made chunks have direct reference to players
start on room implementations (puzzles and such)
1 parent 7955408 commit f93316d

File tree

15 files changed

+258
-240
lines changed

15 files changed

+258
-240
lines changed

server/src/player/player.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ use crate::network::protocol::play::serverbound::PlayerDiggingAction;
1616
use crate::player::packet_handling::BlockInteractResult;
1717
use crate::types::aabb::AABB;
1818
use crate::world::chunk::chunk::get_chunk_position;
19-
use crate::world::chunk::chunk_grid::{ChunkDiff, ChunkGrid};
19+
use crate::world::chunk::chunk_grid;
20+
use crate::world::chunk::chunk_grid::ChunkDiff;
2021
use crate::world::world::VIEW_DISTANCE;
2122
use crate::world::world::{World, WorldExtension};
2223
use fstr::FString;
@@ -215,9 +216,7 @@ impl<E : PlayerExtension> Player<E> {
215216
if let Some(old_chunk) = chunk_grid.get_chunk_mut(last_chunk_x, last_chunk_z) {
216217
old_chunk.remove_player(self.client_id)
217218
}
218-
if let Some(new_chunk) = chunk_grid.get_chunk_mut(chunk_x, chunk_z) {
219-
new_chunk.insert_player(self.client_id)
220-
}
219+
self.world_mut().add_player_to_chunk(self.client_id, chunk_x, chunk_z);
221220

222221
self.world().chunk_grid.for_each_diff(
223222
(chunk_x, chunk_z),
@@ -232,7 +231,7 @@ impl<E : PlayerExtension> Player<E> {
232231
chunk.write_spawn_entities(self);
233232
} else {
234233
chunk.write_despawn_entities(self);
235-
self.write_packet(&ChunkGrid::get_unload_chunk_packet(x, z));
234+
self.write_packet(&chunk_grid::get_unload_chunk_packet(x, z));
236235
}
237236
}
238237
)

server/src/world/chunk/chunk.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,21 @@ use crate::entity::entity::EntityId;
33
use crate::network::packets::packet_buffer::PacketBuffer;
44
use crate::network::protocol::play::clientbound::ChunkData;
55
use crate::player::player::ClientId;
6-
use crate::{Player, PlayerExtension};
6+
use crate::{Player, PlayerExtension, WorldExtension};
77
use glam::DVec3;
8-
use std::collections::HashSet;
8+
use std::cell::UnsafeCell;
9+
use std::collections::{HashMap, HashSet};
10+
use std::rc::Rc;
911

1012
pub struct ChunkSection {
1113
solid_block_amount: u16,
1214
data: Box<[u16; 4096]>,
1315
}
14-
pub struct Chunk {
16+
pub struct Chunk<W : WorldExtension> {
1517
pub chunk_sections: [Option<ChunkSection>; 16],
1618
pub packet_buffer: PacketBuffer,
1719

18-
pub players: HashSet<ClientId>,
20+
pub players: HashMap<ClientId, Rc<UnsafeCell<Player<W::Player>>>>,
1921
pub entities: HashSet<EntityId>,
2022

2123
// contains the chunk data packet,
@@ -26,13 +28,13 @@ pub struct Chunk {
2628
dirty: bool,
2729
}
2830

29-
impl Chunk {
31+
impl<W : WorldExtension> Chunk<W> {
3032

3133
pub fn new() -> Self {
3234
Self {
3335
chunk_sections: [const { None }; 16],
3436
packet_buffer: PacketBuffer::new(),
35-
players: HashSet::new(),
37+
players: HashMap::new(),
3638
entities: HashSet::new(),
3739

3840
cached_chunk_data: PacketBuffer::new(),
@@ -131,9 +133,9 @@ impl Chunk {
131133
into.copy_from(&self.cached_chunk_data);
132134
}
133135

134-
pub fn insert_player(&mut self, client_id: ClientId) {
135-
debug_assert!(!self.players.contains(&client_id), "player already in chunk");
136-
self.players.insert(client_id);
136+
pub fn insert_player(&mut self, client_id: ClientId, player: Rc<UnsafeCell<Player<W::Player>>>) {
137+
debug_assert!(!self.players.contains_key(&client_id), "player already in chunk");
138+
self.players.insert(client_id, player);
137139
}
138140

139141
pub fn insert_entity(&mut self, entity_id: EntityId) {
@@ -142,7 +144,7 @@ impl Chunk {
142144
}
143145

144146
pub fn remove_player(&mut self, client_id: ClientId) {
145-
debug_assert!(self.players.contains(&client_id), "player was never in this chunk");
147+
debug_assert!(self.players.contains_key(&client_id), "player was never in this chunk");
146148
self.players.remove(&client_id);
147149
}
148150

server/src/world/chunk/chunk_grid.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use crate::block::blocks::Block;
22
use crate::network::protocol::play::clientbound::{BlockChange, ChunkData};
33
use crate::world::chunk::chunk::Chunk;
4+
use crate::WorldExtension;
45
use glam::{ivec3, IVec3};
56
use std::cmp::{max, min};
67

78
/// Chunk grid
89
///
910
/// Stores a square grid of chunks, based on the provided size.
10-
pub struct ChunkGrid {
11-
pub chunks: Vec<Chunk>,
11+
pub struct ChunkGrid<W : WorldExtension> {
12+
pub chunks: Vec<Chunk<W>>,
1213
pub size: usize,
1314

1415
index_offset_x: usize,
@@ -21,9 +22,9 @@ pub enum ChunkDiff {
2122
Old,
2223
}
2324

24-
impl ChunkGrid {
25+
impl<W : WorldExtension> ChunkGrid<W> {
2526

26-
pub fn new(size: usize, offset_x: usize, offset_z: usize) -> ChunkGrid {
27+
pub fn new(size: usize, offset_x: usize, offset_z: usize) -> Self {
2728
let mut chunks = Vec::with_capacity(size * size);
2829
for _ in 0..size * size {
2930
chunks.push(Chunk::new());
@@ -78,7 +79,7 @@ impl ChunkGrid {
7879
}
7980

8081
/// returns the chunk at the x and z coordinates provided, none if no chunk is present
81-
pub fn get_chunk(&self, chunk_x: i32, chunk_z: i32) -> Option<&Chunk> {
82+
pub fn get_chunk(&self, chunk_x: i32, chunk_z: i32) -> Option<&Chunk<W>> {
8283
let size = self.size as i32;
8384
let x = chunk_x + self.index_offset_x as i32;
8485
let z = chunk_z + self.index_offset_z as i32;
@@ -88,7 +89,7 @@ impl ChunkGrid {
8889
self.chunks.get(z as usize * self.size + x as usize)
8990
}
9091

91-
pub fn get_chunk_mut(&mut self, chunk_x: i32, chunk_z: i32) -> Option<&mut Chunk> {
92+
pub fn get_chunk_mut(&mut self, chunk_x: i32, chunk_z: i32) -> Option<&mut Chunk<W>> {
9293
let size = self.size as i32;
9394
let x = chunk_x + self.index_offset_x as i32;
9495
let z = chunk_z + self.index_offset_z as i32;
@@ -105,7 +106,7 @@ impl ChunkGrid {
105106
view_distance: i32,
106107
mut callback: F,
107108
) where
108-
F: FnMut(&mut Chunk, i32, i32)
109+
F: FnMut(&mut Chunk<W>, i32, i32)
109110
{
110111
let min_x = max(chunk_x - view_distance + self.index_offset_x as i32, 0);
111112
let min_z = max(chunk_z - view_distance + self.index_offset_z as i32, 0);
@@ -147,19 +148,18 @@ impl ChunkGrid {
147148
for z in min_z..=max_z {
148149
let in_old_range =
149150
x >= old_min_x && x <= old_max_x &&
150-
z >= old_min_z && z <= old_max_z;
151+
z >= old_min_z && z <= old_max_z;
151152

152153
if !in_old_range {
153154
callback(x - self.index_offset_x as i32, z - self.index_offset_z as i32, ChunkDiff::New);
154155
}
155156
}
156157
}
157-
158158
for x in old_min_x..=old_max_x {
159159
for z in old_min_z..=old_max_z {
160160
let in_new_range =
161161
x >= min_x && x <= max_x &&
162-
z >= min_z && z <= max_z;
162+
z >= min_z && z <= max_z;
163163

164164
if !in_new_range {
165165
callback(x - self.index_offset_x as i32, z - self.index_offset_z as i32, ChunkDiff::Old);
@@ -173,15 +173,15 @@ impl ChunkGrid {
173173
self.set_block_at(block, x, y, z)
174174
})
175175
}
176+
}
176177

177-
pub fn get_unload_chunk_packet(chunk_x: i32, chunk_z: i32) -> ChunkData {
178-
ChunkData {
179-
chunk_x,
180-
chunk_z,
181-
is_new_chunk: true,
182-
bitmask: 0,
183-
data: vec![],
184-
}
178+
pub fn get_unload_chunk_packet(chunk_x: i32, chunk_z: i32) -> ChunkData {
179+
ChunkData {
180+
chunk_x,
181+
chunk_z,
182+
is_new_chunk: true,
183+
bitmask: 0,
184+
data: vec![],
185185
}
186186
}
187187

server/src/world/world.rs

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ use crate::world::chunk::get_chunk_position;
1212
use enumset::EnumSet;
1313
use glam::{DVec3, Vec3};
1414
use slotmap::SecondaryMap;
15+
use std::cell::UnsafeCell;
1516
use std::collections::HashMap;
1617
use std::ops::{Deref, DerefMut};
18+
use std::rc::Rc;
1719
use tokio::sync::mpsc::UnboundedSender;
1820

1921
pub const VIEW_DISTANCE: i32 = 6;
@@ -29,15 +31,16 @@ pub trait WorldExtension: Sized {
2931
pub struct World<W: WorldExtension> {
3032
pub network_tx: UnboundedSender<NetworkThreadMessage>,
3133

32-
pub players: Vec<Player<W::Player>>,
34+
// maybe go back to only map for players?
35+
pub players: Vec<Rc<UnsafeCell<Player<W::Player>>>>,
3336
pub player_map: SecondaryMap<ClientId, usize>,
3437

3538
entity_id: i32,
3639
pub entities: Vec<Entity<W>>,
3740
pub entity_map: HashMap<EntityId, usize>,
3841
entities_for_removal: Vec<EntityId>,
3942

40-
pub chunk_grid: ChunkGrid,
43+
pub chunk_grid: ChunkGrid<W>,
4144

4245
pub extension: W,
4346
}
@@ -73,9 +76,9 @@ impl<W: WorldExtension> World<W> {
7376
gamemode: Gamemode,
7477
extension: W::Player,
7578
) -> &mut Player<W::Player> {
76-
let entity_id = self.new_entity_id();
7779

78-
let mut player = Player::new(
80+
let entity_id = self.new_entity_id();
81+
let player_rc = Rc::new(UnsafeCell::new(Player::new(
7982
self,
8083
profile,
8184
client_id,
@@ -85,7 +88,8 @@ impl<W: WorldExtension> World<W> {
8588
pitch,
8689
gamemode,
8790
extension
88-
);
91+
)));
92+
let mut player = unsafe { &mut *player_rc.get() };
8993

9094
player.write_packet(&JoinGame {
9195
entity_id: player.entity_id,
@@ -99,7 +103,7 @@ impl<W: WorldExtension> World<W> {
99103

100104
let (chunk_x, chunk_z) = get_chunk_position(player.position);
101105
if let Some(chunk) = self.chunk_grid.get_chunk_mut(chunk_x, chunk_z) {
102-
chunk.insert_player(client_id)
106+
chunk.insert_player(client_id, player_rc.clone())
103107
}
104108

105109
self.chunk_grid
@@ -134,9 +138,10 @@ impl<W: WorldExtension> World<W> {
134138
player.flush_packets();
135139

136140
let index = self.players.len();
137-
self.players.push(player);
141+
self.players.push(player_rc);
138142
self.player_map.insert(client_id, index);
139-
&mut self.players[index]
143+
// should always be present
144+
unsafe { self.players[index].get().as_mut().unwrap() }
140145
}
141146

142147
pub fn spawn_entity<A: EntityAppearance<W> + 'static, E: EntityExtension<W> + 'static>(
@@ -158,7 +163,8 @@ impl<W: WorldExtension> World<W> {
158163
self.chunk_grid
159164
.for_each_in_view(chunk_x, chunk_z, VIEW_DISTANCE, |chunk, _, _| {
160165
if chunk.has_players() {
161-
for player in self.players.iter_mut().filter(|p| chunk.players.contains(&p.client_id)) {
166+
for (_, player_rc) in chunk.players.iter() {
167+
let player = unsafe { &mut *player_rc.get() };
162168
entity.enter_view(player)
163169
}
164170
}
@@ -194,11 +200,12 @@ impl<W: WorldExtension> World<W> {
194200
if let Some(index) = self.player_map.remove(client_id) {
195201
let last_index = self.players.len() - 1;
196202

197-
let mut player = self.players.swap_remove(index);
198-
W::on_player_leave(self, &mut player);
203+
let player_rc = self.players.swap_remove(index);
204+
let player = unsafe { player_rc.get().as_mut().unwrap() };
205+
W::on_player_leave(self, player);
199206

200207
if last_index != index {
201-
let moved_id = self.players[index].client_id;
208+
let moved_id = unsafe { self.players[index].get().as_ref().unwrap() }.client_id;
202209
self.player_map.insert(moved_id, index);
203210
}
204211

@@ -207,6 +214,8 @@ impl<W: WorldExtension> World<W> {
207214
if let Some(chunk) = self.chunk_grid.get_chunk_mut(chunk_x, chunk_z) {
208215
chunk.remove_player(client_id)
209216
}
217+
218+
assert_eq!(Rc::strong_count(&player_rc), 1, "player leaked")
210219
}
211220
}
212221

@@ -239,6 +248,7 @@ impl<W: WorldExtension> World<W> {
239248
}
240249

241250
for player in self.players.iter_mut() {
251+
let player = unsafe { player.get().as_mut().unwrap() };
242252
player.write_packet(&packet_destroy_entities);
243253
player.tick();
244254
}
@@ -248,6 +258,16 @@ impl<W: WorldExtension> World<W> {
248258
}
249259
}
250260

261+
pub fn add_player_to_chunk(&mut self, client_id: ClientId, chunk_x: i32, chunk_z: i32) {
262+
if let Some(index) = self.player_map.get(client_id) {
263+
let player = self.players[*index].clone();
264+
265+
if let Some(chunk) = self.chunk_grid.get_chunk_mut(chunk_x, chunk_z) {
266+
chunk.insert_player(client_id, player)
267+
}
268+
}
269+
}
270+
251271
pub fn process_event(&mut self, event: MainThreadMessage) {
252272
match event {
253273
MainThreadMessage::NewPlayer { client_id, profile } => {
@@ -258,7 +278,8 @@ impl<W: WorldExtension> World<W> {
258278
}
259279
MainThreadMessage::PacketReceived { client_id, packet } => {
260280
if let Some(index) = self.player_map.get(client_id) {
261-
let player = &mut self.players[*index];
281+
let player_rc = &mut self.players[*index];
282+
let player = unsafe { &mut *player_rc.get() };
262283
packet.process(player)
263284
}
264285
}

src/dungeon/door/door.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl Door {
5959

6060
pub fn load_into_world(
6161
&self,
62-
chunk_grid: &mut ChunkGrid,
62+
chunk_grid: &mut ChunkGrid<Dungeon>,
6363
door_blocks: &DeterministicHashMap<DoorType, Vec<Vec<Block>>>
6464
) {
6565
// Area to fill with air

0 commit comments

Comments
 (0)