Skip to content

Commit

Permalink
Fix chunk loading deadlock and dangling chunk memory (#159)
Browse files Browse the repository at this point in the history
* rebase to master

* fix chunk unloading
  • Loading branch information
kralverde authored Oct 22, 2024
1 parent f7398bf commit 9eac0f0
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 230 deletions.
1 change: 1 addition & 0 deletions pumpkin-world/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ parking_lot.workspace = true
num-traits.workspace = true
num-derive.workspace = true
futures = "0.3"
dashmap = "6.1.0"

# Compression
flate2 = "1.0"
Expand Down
62 changes: 41 additions & 21 deletions pumpkin-world/src/cylindrical_chunk_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,24 @@ impl Cylindrical {
}
}

#[allow(unused_variables)]
pub fn for_each_changed_chunk(
old_cylindrical: Cylindrical,
new_cylindrical: Cylindrical,
mut newly_included: impl FnMut(Vector2<i32>),
mut just_removed: impl FnMut(Vector2<i32>),
ignore: bool,
) {
let min_x = old_cylindrical.left().min(new_cylindrical.left());
let max_x = old_cylindrical.right().max(new_cylindrical.right());
let min_z = old_cylindrical.bottom().min(new_cylindrical.bottom());
let max_z = old_cylindrical.top().max(new_cylindrical.top());

//log::debug!("{:?} {:?}", old_cylindrical, new_cylindrical);
for x in min_x..=max_x {
for z in min_z..=max_z {
let old_is_within = if ignore {
false
} else {
old_cylindrical.is_within_distance(x, z)
};
let new_is_within = if ignore {
true
} else {
new_cylindrical.is_within_distance(x, z)
};
let old_is_within = old_cylindrical.is_within_distance(x, z);
let new_is_within = new_cylindrical.is_within_distance(x, z);

//log::debug!("{}, {}: {} {}", x, z, old_is_within, new_is_within);

if old_is_within != new_is_within {
if new_is_within {
Expand Down Expand Up @@ -68,21 +61,23 @@ impl Cylindrical {
}

fn is_within_distance(&self, x: i32, z: i32) -> bool {
let max_dist_squared = self.view_distance * self.view_distance;
let max_dist = self.view_distance as i64;
let dist_x = (x - self.center.x).abs().max(0) - (1);
let dist_z = (z - self.center.z).abs().max(0) - (1);
let dist_squared = dist_x.pow(2) + (max_dist.min(dist_z as i64) as i32).pow(2);
dist_squared < max_dist_squared
let rel_x = ((x - self.center.x).abs() - 1).max(0);
let rel_z = ((z - self.center.z).abs() - 1).max(0);

let max_leg = (rel_x.max(rel_z) - 1).max(0) as i64;
let min_leg = rel_x.min(rel_z) as i64;

let hyp_sqr = max_leg * max_leg + min_leg * min_leg;
hyp_sqr < (self.view_distance * self.view_distance) as i64
}

/// Returns an iterator of all chunks within this cylinder
pub fn all_chunks_within(&self) -> Vec<Vector2<i32>> {
// This is a naive implementation: start with square and cut out ones that dont fit
let mut all_chunks = Vec::new();
for x in -self.view_distance..=self.view_distance {
for z in -self.view_distance..=self.view_distance {
all_chunks.push(Vector2::new(self.center.x + x, self.center.z + z));
for x in self.left()..=self.right() {
for z in self.bottom()..=self.top() {
all_chunks.push(Vector2::new(x, z));
}
}
all_chunks
Expand All @@ -91,3 +86,28 @@ impl Cylindrical {
.collect()
}
}

#[cfg(test)]
mod test {

use super::Cylindrical;
use pumpkin_core::math::vector2::Vector2;

#[test]
fn test_bounds() {
let cylinder = Cylindrical::new(Vector2::new(0, 0), 10);
for chunk in cylinder.all_chunks_within() {
assert!(chunk.x >= cylinder.left() && chunk.x <= cylinder.right());
assert!(chunk.z >= cylinder.bottom() && chunk.z <= cylinder.top());
}

for x in (cylinder.left() - 2)..=(cylinder.right() + 2) {
for z in (cylinder.bottom() - 2)..=(cylinder.top() + 2) {
if cylinder.is_within_distance(x, z) {
assert!(x >= cylinder.left() && x <= cylinder.right());
assert!(z >= cylinder.bottom() && z <= cylinder.top());
}
}
}
}
}
Loading

0 comments on commit 9eac0f0

Please sign in to comment.