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::generation::settings::{GenerationSettings, gen_settings_from_dimension};
|
||||||
use crate::level::{Level, SyncChunk};
|
use crate::level::{Level, SyncChunk};
|
||||||
use crate::world::{BlockAccessor, BlockRegistryExt};
|
use crate::world::{BlockAccessor, BlockRegistryExt};
|
||||||
use crate::{GlobalRandomConfig, ProtoChunk, ProtoNoiseRouters};
|
use crate::{BlockStateId, GlobalRandomConfig, ProtoChunk, ProtoNoiseRouters};
|
||||||
use crossbeam::channel::{Receiver, Sender};
|
use crossbeam::channel::{Receiver, Sender};
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -898,6 +898,13 @@ impl BlockAccessor for Cache {
|
|||||||
Box::pin(async move { GenerationCache::get_block_state(self, &position.0).to_state() })
|
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>(
|
fn get_block_and_state<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
position: &'a BlockPos,
|
position: &'a BlockPos,
|
||||||
|
|||||||
@ -1133,6 +1133,13 @@ impl BlockAccessor for ProtoChunk {
|
|||||||
Box::pin(async move { self.get_block_state(&position.0).to_state() })
|
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>(
|
fn get_block_and_state<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
position: &'a BlockPos,
|
position: &'a BlockPos,
|
||||||
|
|||||||
@ -598,31 +598,32 @@ impl Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_chunk(self: &Arc<Self>, pos: Vector2<i32>) -> SyncChunk {
|
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) {
|
if let Some(chunk) = self.loaded_chunks.get(&pos) {
|
||||||
chunk.clone()
|
return chunk.clone();
|
||||||
} else {
|
}
|
||||||
|
|
||||||
log::debug!("Missing Chunk {pos:?}. Fetching.");
|
log::debug!("Missing Chunk {pos:?}. Fetching.");
|
||||||
let clock = Instant::now();
|
let clock = Instant::now();
|
||||||
let recv = self.chunk_listener.add_single_chunk_listener(pos);
|
let recv = self.chunk_listener.add_single_chunk_listener(pos);
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut lock = self.chunk_loading.lock().unwrap();
|
let mut lock = self.chunk_loading.lock().unwrap();
|
||||||
lock.add_force_ticket(pos);
|
lock.add_ticket(pos, 31);
|
||||||
lock.send_change();
|
lock.send_change();
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret = if let Some(chunk) = self.loaded_chunks.get(&pos) {
|
let ret = if let Some(chunk) = self.loaded_chunks.get(&pos) {
|
||||||
// try again here. otherwise deadlock
|
|
||||||
chunk.clone()
|
chunk.clone()
|
||||||
} else {
|
} else {
|
||||||
recv.await.unwrap()
|
recv.await
|
||||||
|
.expect("Chunk listener dropped without sending chunk")
|
||||||
};
|
};
|
||||||
let mut lock = self.chunk_loading.lock().unwrap();
|
|
||||||
lock.remove_force_ticket(pos);
|
|
||||||
log::debug!("Chunk {pos:?} received after {:?}.", Instant::now() - clock);
|
log::debug!("Chunk {pos:?} received after {:?}.", Instant::now() - clock);
|
||||||
|
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_single_entity_chunk(
|
async fn load_single_entity_chunk(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@ -138,6 +138,11 @@ pub trait BlockAccessor: Send + Sync {
|
|||||||
position: &'a BlockPos,
|
position: &'a BlockPos,
|
||||||
) -> Pin<Box<dyn Future<Output = &'static BlockState> + Send + 'a>>;
|
) -> 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>(
|
fn get_block_and_state<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
position: &'a BlockPos,
|
position: &'a BlockPos,
|
||||||
|
|||||||
@ -241,7 +241,7 @@ pub trait RedstoneGateBlock<T: Send + Sync + BlockProperties + RedstoneGateBlock
|
|||||||
self,
|
self,
|
||||||
args.world,
|
args.world,
|
||||||
*args.position,
|
*args.position,
|
||||||
BlockState::from_id(args.old_state_id).id,
|
args.old_state_id,
|
||||||
args.block,
|
args.block,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|||||||
@ -67,7 +67,7 @@ impl BlockBehaviour for ComparatorBlock {
|
|||||||
self,
|
self,
|
||||||
args.world,
|
args.world,
|
||||||
*args.position,
|
*args.position,
|
||||||
BlockState::from_id(args.state_id).id,
|
args.state_id,
|
||||||
args.block,
|
args.block,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|||||||
@ -162,7 +162,7 @@ impl BlockBehaviour for RepeaterBlock {
|
|||||||
self,
|
self,
|
||||||
args.world,
|
args.world,
|
||||||
*args.position,
|
*args.position,
|
||||||
BlockState::from_id(args.state_id).id,
|
args.state_id,
|
||||||
args.block,
|
args.block,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|||||||
@ -692,21 +692,21 @@ impl BlockRegistry {
|
|||||||
block: &Block,
|
block: &Block,
|
||||||
flags: BlockFlags,
|
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() {
|
for direction in BlockDirection::all() {
|
||||||
let neighbor_pos = position.offset(direction.to_offset());
|
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);
|
let pumpkin_block = self.get_pumpkin_block(block);
|
||||||
if let Some(pumpkin_block) = pumpkin_block {
|
if let Some(pumpkin_block) = pumpkin_block {
|
||||||
let new_state = pumpkin_block
|
let new_state = pumpkin_block
|
||||||
.get_state_for_neighbor_update(GetStateForNeighborUpdateArgs {
|
.get_state_for_neighbor_update(GetStateForNeighborUpdateArgs {
|
||||||
world,
|
world,
|
||||||
block,
|
block,
|
||||||
state_id: state.id,
|
state_id,
|
||||||
position,
|
position,
|
||||||
direction: direction.opposite(),
|
direction: direction.opposite(),
|
||||||
neighbor_position: &neighbor_pos,
|
neighbor_position: &neighbor_pos,
|
||||||
neighbor_state_id: neighbor_state.id,
|
neighbor_state_id,
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
world.set_block_state(&neighbor_pos, new_state, flags).await;
|
world.set_block_state(&neighbor_pos, new_state, flags).await;
|
||||||
|
|||||||
@ -185,41 +185,78 @@ impl ChunkManager {
|
|||||||
level: &Arc<Level>,
|
level: &Arc<Level>,
|
||||||
) {
|
) {
|
||||||
view_distance += 1;
|
view_distance += 1;
|
||||||
|
let old_center = self.center;
|
||||||
|
let old_view_distance = self.view_distance;
|
||||||
|
|
||||||
|
{
|
||||||
let mut lock = level.chunk_loading.lock().unwrap();
|
let mut lock = level.chunk_loading.lock().unwrap();
|
||||||
lock.add_ticket(
|
lock.add_ticket(
|
||||||
center,
|
center,
|
||||||
ChunkLoading::get_level_from_view_distance(view_distance),
|
ChunkLoading::get_level_from_view_distance(view_distance),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if old_center != center || old_view_distance != view_distance {
|
||||||
lock.remove_ticket(
|
lock.remove_ticket(
|
||||||
self.center,
|
old_center,
|
||||||
ChunkLoading::get_level_from_view_distance(self.view_distance),
|
ChunkLoading::get_level_from_view_distance(old_view_distance),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
lock.send_change();
|
lock.send_change();
|
||||||
drop(lock);
|
};
|
||||||
let view_distance = i32::from(view_distance);
|
|
||||||
self.chunk_sent
|
let view_distance_i32 = i32::from(view_distance);
|
||||||
.retain(|pos| (pos.x - center.x).abs().max((pos.y - center.y).abs()) <= 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());
|
let mut new_queue = BinaryHeap::with_capacity(self.chunk_queue.len());
|
||||||
for node in &self.chunk_queue {
|
for node in &self.chunk_queue {
|
||||||
let dst = (node.1.x - center.x).abs().max((node.1.y - center.y).abs());
|
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()));
|
new_queue.push(HeapNode(dst, node.1, node.2.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chunk_queue = new_queue;
|
self.chunk_queue = new_queue;
|
||||||
self.center = center;
|
self.center = center;
|
||||||
self.view_distance = view_distance as u8;
|
self.view_distance = view_distance;
|
||||||
for dx in (-view_distance)..=view_distance {
|
|
||||||
for dy in (-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);
|
let new_pos = center.add_raw(dx, dy);
|
||||||
if !self.chunk_sent.contains(&new_pos)
|
if !self.chunk_sent.contains(&new_pos) {
|
||||||
&& let Some(chunk) = level.loaded_chunks.get(&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());
|
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>) {
|
pub fn clean_up(&mut self, level: &Arc<Level>) {
|
||||||
let mut lock = level.chunk_loading.lock().unwrap();
|
let mut lock = level.chunk_loading.lock().unwrap();
|
||||||
|
|||||||
@ -3452,6 +3452,13 @@ impl BlockAccessor for World {
|
|||||||
Box::pin(async move { Self::get_block_state(self, position).await })
|
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>(
|
fn get_block_and_state<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
position: &'a BlockPos,
|
position: &'a BlockPos,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user