Pumpkin/pumpkin-world/src/chunk_system/channel.rs
2026-04-25 21:18:10 +02:00

132 lines
4.1 KiB
Rust

use super::{ChunkLevel, ChunkPos, HashMapType};
use crate::chunk_system::chunk_state::StagedChunkEnum;
use crate::level::Level;
use std::collections::hash_map::Entry;
use std::mem::swap;
use std::sync::atomic::Ordering::SeqCst;
use std::sync::{Arc, Condvar, Mutex};
pub type LevelChange = (
HashMapType<ChunkPos, (StagedChunkEnum, StagedChunkEnum)>,
ChunkLevel,
);
pub struct LevelChannel {
pub value: Mutex<(Option<LevelChange>, Option<Vec<ChunkPos>>)>,
pub notify: Condvar,
}
impl Default for LevelChannel {
fn default() -> Self {
Self::new()
}
}
impl LevelChannel {
#[must_use]
pub const fn new() -> Self {
Self {
value: Mutex::new((None, None)),
notify: Condvar::new(),
}
}
pub fn set_both(
&self,
new_value: (
HashMapType<ChunkPos, (StagedChunkEnum, StagedChunkEnum)>,
ChunkLevel,
),
pos: Vec<ChunkPos>,
) {
// debug!("set new level and priority");
let mut value = self.value.lock().unwrap();
value.1 = Some(pos);
if let Some(old) = &mut value.0 {
for (pos, change) in new_value.0 {
match old.0.entry(pos) {
Entry::Occupied(mut entry) => {
let tmp = entry.get_mut();
debug_assert_eq!(tmp.1, change.0);
if tmp.0 == change.1 {
entry.remove();
} else {
tmp.1 = change.1;
}
}
Entry::Vacant(entry) => {
debug_assert_ne!(change.0, change.1);
entry.insert(change);
}
}
}
old.1 = new_value.1;
} else {
value.0 = Some(new_value);
}
self.notify.notify_one();
}
pub fn set_level(
&self,
new_value: (
HashMapType<ChunkPos, (StagedChunkEnum, StagedChunkEnum)>,
ChunkLevel,
),
) {
// debug!("set new level");
let mut value = self.value.lock().unwrap();
if let Some(old) = &mut value.0 {
for (pos, change) in new_value.0 {
match old.0.entry(pos) {
Entry::Occupied(mut entry) => {
let tmp = entry.get_mut();
debug_assert_eq!(tmp.1, change.0);
if tmp.0 == change.1 {
entry.remove();
} else {
tmp.1 = change.1;
}
}
Entry::Vacant(entry) => {
debug_assert_ne!(change.0, change.1);
entry.insert(change);
}
}
}
old.1 = new_value.1;
} else {
value.0 = Some(new_value);
}
self.notify.notify_one();
}
pub fn set_priority(&self, pos: Vec<ChunkPos>) {
// debug!("set new priority");
self.value.lock().unwrap().1 = Some(pos);
self.notify.notify_one();
}
pub fn get(&self) -> (Option<LevelChange>, Option<Vec<ChunkPos>>) {
let mut lock = self.value.lock().unwrap();
let mut ret = (None, None);
swap(&mut ret, &mut *lock);
ret
}
pub fn wait_and_get(&self, level: &Arc<Level>) -> (Option<LevelChange>, Option<Vec<ChunkPos>>) {
let mut lock = self.value.lock().unwrap();
while lock.0.is_none()
&& lock.1.is_none()
&& !level.should_unload.load(SeqCst)
&& !level.should_save.load(SeqCst)
&& !level.shut_down_chunk_system.load(SeqCst)
{
lock = self.notify.wait(lock).unwrap();
}
let mut ret = (None, None);
swap(&mut ret, &mut *lock);
ret
}
pub fn notify(&self) {
let val = self.value.lock().unwrap_or_else(|e| e.into_inner());
drop(val);
self.notify.notify_one();
}
}