diff --git a/pumpkin-world/src/chunk_system.rs b/pumpkin-world/src/chunk_system.rs index e05a5dd3b..75da0cb2a 100644 --- a/pumpkin-world/src/chunk_system.rs +++ b/pumpkin-world/src/chunk_system.rs @@ -19,7 +19,7 @@ use crate::generation::proto_chunk::{GenerationCache, TerrainCache}; use crate::generation::settings::{GenerationSettings, gen_settings_from_dimension}; use crate::level::{Level, SyncChunk}; use crate::world::{BlockAccessor, BlockRegistryExt}; -use crate::{GlobalRandomConfig, ProtoChunk, ProtoNoiseRouters}; +use crate::{BlockStateId, GlobalRandomConfig, ProtoChunk, ProtoNoiseRouters}; use crossbeam::channel::{Receiver, Sender}; use dashmap::DashMap; use itertools::Itertools; @@ -898,6 +898,13 @@ impl BlockAccessor for Cache { Box::pin(async move { GenerationCache::get_block_state(self, &position.0).to_state() }) } + fn get_block_state_id<'a>( + &'a self, + position: &'a BlockPos, + ) -> Pin + Send + 'a>> { + Box::pin(async move { GenerationCache::get_block_state(self, &position.0).0 }) + } + fn get_block_and_state<'a>( &'a self, position: &'a BlockPos, diff --git a/pumpkin-world/src/generation/proto_chunk.rs b/pumpkin-world/src/generation/proto_chunk.rs index a7561b6c1..742eaaecc 100644 --- a/pumpkin-world/src/generation/proto_chunk.rs +++ b/pumpkin-world/src/generation/proto_chunk.rs @@ -1133,6 +1133,13 @@ impl BlockAccessor for ProtoChunk { Box::pin(async move { self.get_block_state(&position.0).to_state() }) } + fn get_block_state_id<'a>( + &'a self, + position: &'a BlockPos, + ) -> Pin + Send + 'a>> { + Box::pin(async move { self.get_block_state(&position.0).0 }) + } + fn get_block_and_state<'a>( &'a self, position: &'a BlockPos, diff --git a/pumpkin-world/src/level.rs b/pumpkin-world/src/level.rs index 69281f903..f306f272f 100644 --- a/pumpkin-world/src/level.rs +++ b/pumpkin-world/src/level.rs @@ -598,30 +598,31 @@ impl Level { } pub async fn get_chunk(self: &Arc, pos: Vector2) -> SyncChunk { - // Already loaded? + // Check if already in memory if let Some(chunk) = self.loaded_chunks.get(&pos) { + return chunk.clone(); + } + + log::debug!("Missing Chunk {pos:?}. Fetching."); + let clock = Instant::now(); + let recv = self.chunk_listener.add_single_chunk_listener(pos); + + { + let mut lock = self.chunk_loading.lock().unwrap(); + lock.add_ticket(pos, 31); + lock.send_change(); + } + + let ret = if let Some(chunk) = self.loaded_chunks.get(&pos) { chunk.clone() } else { - log::debug!("Missing Chunk {pos:?}. Fetching."); - let clock = Instant::now(); - let recv = self.chunk_listener.add_single_chunk_listener(pos); - { - let mut lock = self.chunk_loading.lock().unwrap(); - lock.add_force_ticket(pos); - lock.send_change(); - } + recv.await + .expect("Chunk listener dropped without sending chunk") + }; - let ret = if let Some(chunk) = self.loaded_chunks.get(&pos) { - // try again here. otherwise deadlock - chunk.clone() - } else { - recv.await.unwrap() - }; - let mut lock = self.chunk_loading.lock().unwrap(); - lock.remove_force_ticket(pos); - log::debug!("Chunk {pos:?} received after {:?}.", Instant::now() - clock); - ret - } + log::debug!("Chunk {pos:?} received after {:?}.", Instant::now() - clock); + + ret } async fn load_single_entity_chunk( diff --git a/pumpkin-world/src/world.rs b/pumpkin-world/src/world.rs index 46b405337..46ba5dcd8 100644 --- a/pumpkin-world/src/world.rs +++ b/pumpkin-world/src/world.rs @@ -138,6 +138,11 @@ pub trait BlockAccessor: Send + Sync { position: &'a BlockPos, ) -> Pin + Send + 'a>>; + fn get_block_state_id<'a>( + &'a self, + position: &'a BlockPos, + ) -> Pin + Send + 'a>>; + fn get_block_and_state<'a>( &'a self, position: &'a BlockPos, diff --git a/pumpkin/src/block/blocks/redstone/abstract_redstone_gate.rs b/pumpkin/src/block/blocks/redstone/abstract_redstone_gate.rs index 8e599c44c..99a374e09 100644 --- a/pumpkin/src/block/blocks/redstone/abstract_redstone_gate.rs +++ b/pumpkin/src/block/blocks/redstone/abstract_redstone_gate.rs @@ -241,7 +241,7 @@ pub trait RedstoneGateBlock, ) { view_distance += 1; - let mut lock = level.chunk_loading.lock().unwrap(); - lock.add_ticket( - center, - ChunkLoading::get_level_from_view_distance(view_distance), - ); - lock.remove_ticket( - self.center, - ChunkLoading::get_level_from_view_distance(self.view_distance), - ); - lock.send_change(); - drop(lock); - let view_distance = i32::from(view_distance); - self.chunk_sent - .retain(|pos| (pos.x - center.x).abs().max((pos.y - center.y).abs()) <= view_distance); + let old_center = self.center; + let old_view_distance = self.view_distance; + + { + let mut lock = level.chunk_loading.lock().unwrap(); + lock.add_ticket( + center, + ChunkLoading::get_level_from_view_distance(view_distance), + ); + + if old_center != center || old_view_distance != view_distance { + lock.remove_ticket( + old_center, + ChunkLoading::get_level_from_view_distance(old_view_distance), + ); + } + lock.send_change(); + }; + + let view_distance_i32 = i32::from(view_distance); + + let mut chunks_to_watch = Vec::new(); + let mut chunks_to_unwatch = Vec::new(); + + for pos in &self.chunk_sent { + if (pos.x - center.x).abs().max((pos.y - center.y).abs()) > view_distance_i32 { + chunks_to_unwatch.push(*pos); + } + } + + let level_clone = level.clone(); + let chunks_to_unwatch_clone = chunks_to_unwatch.clone(); + tokio::spawn(async move { + level_clone + .mark_chunks_as_not_watched(&chunks_to_unwatch_clone) + .await; + }); + + self.chunk_sent.retain(|pos| { + (pos.x - center.x).abs().max((pos.y - center.y).abs()) <= view_distance_i32 + }); + let mut new_queue = BinaryHeap::with_capacity(self.chunk_queue.len()); for node in &self.chunk_queue { let dst = (node.1.x - center.x).abs().max((node.1.y - center.y).abs()); - if dst <= view_distance { + if dst <= view_distance_i32 { new_queue.push(HeapNode(dst, node.1, node.2.clone())); } } + self.chunk_queue = new_queue; self.center = center; - self.view_distance = view_distance as u8; - for dx in (-view_distance)..=view_distance { - for dy in (-view_distance)..=view_distance { + self.view_distance = view_distance; + + for dx in (-view_distance_i32)..=view_distance_i32 { + for dy in (-view_distance_i32)..=view_distance_i32 { let new_pos = center.add_raw(dx, dy); - if !self.chunk_sent.contains(&new_pos) - && let Some(chunk) = level.loaded_chunks.get(&new_pos) - { - self.push_chunk(new_pos, chunk.value().clone()); + if !self.chunk_sent.contains(&new_pos) { + chunks_to_watch.push(new_pos); + if let Some(chunk) = level.loaded_chunks.get(&new_pos) { + self.push_chunk(new_pos, chunk.value().clone()); + } } } } + let level_clone = level.clone(); + tokio::spawn(async move { + level_clone + .mark_chunks_as_newly_watched(&chunks_to_watch) + .await; + }); } pub fn clean_up(&mut self, level: &Arc) { diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index f5f2025ba..569570773 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -3452,6 +3452,13 @@ impl BlockAccessor for World { Box::pin(async move { Self::get_block_state(self, position).await }) } + fn get_block_state_id<'a>( + &'a self, + position: &'a BlockPos, + ) -> Pin + Send + 'a>> { + Box::pin(async move { Self::get_block_state_id(self, position).await }) + } + fn get_block_and_state<'a>( &'a self, position: &'a BlockPos,