diff --git a/pumpkin-world/src/level.rs b/pumpkin-world/src/level.rs index 8689a077d..fd9f76a19 100644 --- a/pumpkin-world/src/level.rs +++ b/pumpkin-world/src/level.rs @@ -28,8 +28,6 @@ use std::{ atomic::{AtomicBool, AtomicU64, Ordering}, }, }; -use tokio::sync::watch; -use tokio::sync::watch::{Receiver, Sender}; use tokio::{ select, sync::{ @@ -75,7 +73,7 @@ pub struct Level { /// Semaphore to limit concurrent chunk generation tasks //chunk_generation_semaphore: Arc, /// Map to deduplicate chunk generation and avoid DashMap write lock - chunk_generation_locks: Arc, Receiver>>>, + chunk_generation_locks: Arc, Arc>>>, /// Tracks tasks associated with this world instance tasks: TaskTracker, /// Notification that interrupts tasks for shutdown @@ -787,29 +785,20 @@ impl Level { let block_registry = block_registry.clone(); let self_clone = self_clone.clone(); - enum Notify { - Send(Sender), - Recv(Receiver), - } - let notify = { let mut locks = self_clone.chunk_generation_locks.lock().await; if let Some(existing) = locks.get(&pos) { - Notify::Recv(existing.clone()) + Some(existing.clone()) } else { - let (send, recv) = watch::channel(true); - locks.insert(pos, recv); - Notify::Send(send) + let notify = Arc::new(Notify::new()); + locks.insert(pos, notify.clone()); + None } }; - if let Notify::Recv(mut notify) = notify { + if let Some(notify) = notify { // Wait for the chunk to be generated by another task - 'notify: while *notify.borrow_and_update() { - if notify.changed().await.is_err() { - break 'notify; - } - } + notify.notified().await; // After being notified, the chunk should be in loaded_chunks // However, it might have been unloaded between notification and access if let Some(chunk) = loaded_chunks.get(&pos) { @@ -823,7 +812,7 @@ impl Level { // The chunk generation will be retried if needed log::info!("Chunk at {pos:?} was unloaded after generation notification"); } - } else if let Notify::Send(notify) = notify { + } else { //let _permit = chunk_generation_semaphore // .acquire() // .await @@ -851,15 +840,19 @@ impl Level { loaded_chunks.insert(pos, arc_chunk.clone()); // Store the notify for later removal - arc_chunk + (arc_chunk, pos) }; // Remove the notify and wake up any waiters // Do this outside the rayon thread to avoid deadlock - let arc_chunk = result; + let (arc_chunk, pos) = result; { + let self_clone = self_clone.clone(); handle.spawn(async move { - notify.send(true).unwrap(); + let mut locks = self_clone.chunk_generation_locks.lock().await; + if let Some(notify) = locks.remove(&pos) { + notify.notify_waiters(); + } }); }