diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index 40adf3c78..435d730f5 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -1,11 +1,11 @@ use core::f32; -use std::collections::{BinaryHeap, HashSet, VecDeque}; +use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; use std::f64::consts::TAU; use std::mem; use std::num::NonZeroU8; use std::ops::AddAssign; -use std::sync::Arc; use std::sync::atomic::{AtomicBool, AtomicI32, AtomicI64, AtomicU8, AtomicU32, Ordering}; +use std::sync::{Arc, Weak}; use std::time::{Duration, Instant}; use arc_swap::ArcSwap; @@ -136,7 +136,7 @@ pub struct ChunkManager { center: Vector2, view_distance: u8, chunk_listener: Receiver<(Vector2, SyncChunk)>, - chunk_sent: HashSet>, + chunk_sent: HashMap, Weak>, chunk_queue: BinaryHeap, entity_chunk_queue: VecDeque<(Vector2, SyncEntityChunk)>, batches_sent_since_ack: BatchState, @@ -158,7 +158,7 @@ impl ChunkManager { center: Vector2::::new(0, 0), view_distance: 0, chunk_listener, - chunk_sent: HashSet::new(), + chunk_sent: HashMap::new(), chunk_queue: BinaryHeap::new(), entity_chunk_queue: VecDeque::new(), batches_sent_since_ack: BatchState::Initial, @@ -172,6 +172,13 @@ impl ChunkManager { &self.world } + fn should_enqueue_chunk(&mut self, position: Vector2, chunk: &SyncChunk) -> bool { + self.chunk_sent + .insert(position, Arc::downgrade(chunk)) + .and_then(|old_chunk| old_chunk.upgrade()) + .is_none_or(|old_chunk| !Arc::ptr_eq(&old_chunk, chunk)) + } + pub fn pull_new_chunks(&mut self) { // log::debug!("pull new chunks"); while let Ok((pos, chunk)) = self.chunk_listener.try_recv() { @@ -181,7 +188,7 @@ impl ChunkManager { if dst > i32::from(self.view_distance) { continue; } - if self.chunk_sent.insert(pos) { + if self.should_enqueue_chunk(pos, &chunk) { // log::debug!("receive new chunk {pos:?}"); self.chunk_queue.push(HeapNode(dst, pos, chunk)); } @@ -222,7 +229,7 @@ impl ChunkManager { let view_distance_i32 = i32::from(view_distance); let unloading_chunks: HashSet> = unloading_chunks.iter().copied().collect(); - self.chunk_sent.retain(|pos| { + self.chunk_sent.retain(|pos, _| { (pos.x - center.x).abs().max((pos.y - center.y).abs()) <= view_distance_i32 && !unloading_chunks.contains(pos) }); @@ -237,7 +244,7 @@ impl ChunkManager { self.chunk_queue = new_queue; for pos in loading_chunks { - if !self.chunk_sent.contains(pos) + if !self.chunk_sent.contains_key(pos) && let Some(chunk) = level.loaded_chunks.get(pos) { self.push_chunk(*pos, chunk.value().clone()); @@ -283,11 +290,12 @@ impl ChunkManager { } pub fn push_chunk(&mut self, position: Vector2, chunk: SyncChunk) { - self.chunk_sent.insert(position); - let dst = (position.x - self.center.x) - .abs() - .max((position.y - self.center.y).abs()); - self.chunk_queue.push(HeapNode(dst, position, chunk)); + if self.should_enqueue_chunk(position, &chunk) { + let dst = (position.x - self.center.x) + .abs() + .max((position.y - self.center.y).abs()); + self.chunk_queue.push(HeapNode(dst, position, chunk)); + } } pub fn push_entity(&mut self, position: Vector2, chunk: SyncEntityChunk) {