fix: the chunk unloading issue
at least hopefully, i think it was an Ticket Overlap, By adding the new ticket before removing the old one, the ChunkLoading system always sees at least one valid path for the chunks that overlap between the two view distances. The fix seems to made the system slower but atleast it seems to not bug anymore
This commit is contained in:
parent
1e691c71b9
commit
6f18d16581
@ -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<Box<dyn Future<Output = BlockStateId> + 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,
|
||||
|
||||
@ -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<Box<dyn Future<Output = BlockStateId> + Send + 'a>> {
|
||||
Box::pin(async move { self.get_block_state(&position.0).0 })
|
||||
}
|
||||
|
||||
fn get_block_and_state<'a>(
|
||||
&'a self,
|
||||
position: &'a BlockPos,
|
||||
|
||||
@ -598,30 +598,31 @@ impl Level {
|
||||
}
|
||||
|
||||
pub async fn get_chunk(self: &Arc<Self>, pos: Vector2<i32>) -> 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(
|
||||
|
||||
@ -138,6 +138,11 @@ pub trait BlockAccessor: Send + Sync {
|
||||
position: &'a BlockPos,
|
||||
) -> Pin<Box<dyn Future<Output = &'static BlockState> + Send + 'a>>;
|
||||
|
||||
fn get_block_state_id<'a>(
|
||||
&'a self,
|
||||
position: &'a BlockPos,
|
||||
) -> Pin<Box<dyn Future<Output = BlockStateId> + Send + 'a>>;
|
||||
|
||||
fn get_block_and_state<'a>(
|
||||
&'a self,
|
||||
position: &'a BlockPos,
|
||||
|
||||
@ -241,7 +241,7 @@ pub trait RedstoneGateBlock<T: Send + Sync + BlockProperties + RedstoneGateBlock
|
||||
self,
|
||||
args.world,
|
||||
*args.position,
|
||||
BlockState::from_id(args.old_state_id).id,
|
||||
args.old_state_id,
|
||||
args.block,
|
||||
)
|
||||
.await;
|
||||
|
||||
@ -67,7 +67,7 @@ impl BlockBehaviour for ComparatorBlock {
|
||||
self,
|
||||
args.world,
|
||||
*args.position,
|
||||
BlockState::from_id(args.state_id).id,
|
||||
args.state_id,
|
||||
args.block,
|
||||
)
|
||||
.await;
|
||||
|
||||
@ -162,7 +162,7 @@ impl BlockBehaviour for RepeaterBlock {
|
||||
self,
|
||||
args.world,
|
||||
*args.position,
|
||||
BlockState::from_id(args.state_id).id,
|
||||
args.state_id,
|
||||
args.block,
|
||||
)
|
||||
.await;
|
||||
|
||||
@ -692,21 +692,21 @@ impl BlockRegistry {
|
||||
block: &Block,
|
||||
flags: BlockFlags,
|
||||
) {
|
||||
let state = world.get_block_state(position).await;
|
||||
let state_id = world.get_block_state_id(position).await;
|
||||
for direction in BlockDirection::all() {
|
||||
let neighbor_pos = position.offset(direction.to_offset());
|
||||
let neighbor_state = world.get_block_state(&neighbor_pos).await;
|
||||
let neighbor_state_id = world.get_block_state_id(&neighbor_pos).await;
|
||||
let pumpkin_block = self.get_pumpkin_block(block);
|
||||
if let Some(pumpkin_block) = pumpkin_block {
|
||||
let new_state = pumpkin_block
|
||||
.get_state_for_neighbor_update(GetStateForNeighborUpdateArgs {
|
||||
world,
|
||||
block,
|
||||
state_id: state.id,
|
||||
state_id,
|
||||
position,
|
||||
direction: direction.opposite(),
|
||||
neighbor_position: &neighbor_pos,
|
||||
neighbor_state_id: neighbor_state.id,
|
||||
neighbor_state_id,
|
||||
})
|
||||
.await;
|
||||
world.set_block_state(&neighbor_pos, new_state, flags).await;
|
||||
|
||||
@ -185,40 +185,77 @@ impl ChunkManager {
|
||||
level: &Arc<Level>,
|
||||
) {
|
||||
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<Level>) {
|
||||
|
||||
@ -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<Box<dyn Future<Output = BlockStateId> + 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,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user