summaryrefslogtreecommitdiff
path: root/src/sim
diff options
context:
space:
mode:
authorKai Stevenson <kai@kaistevenson.com>2026-08-18 23:50:37 -0700
committerKai Stevenson <kai@kaistevenson.com>2026-08-18 23:55:41 -0700
commitafae4ace5ffcefa4590b80ddcf097559c64c7413 (patch)
treead2e0beca3da19fba8e53534c03e9f018d387ca1 /src/sim
parenta0b3de6086d5245eaefa9e510cbf2844b0224405 (diff)
optimize chunk wakes
Diffstat (limited to 'src/sim')
-rw-r--r--src/sim/cell_sim/sim.rs126
1 files changed, 100 insertions, 26 deletions
diff --git a/src/sim/cell_sim/sim.rs b/src/sim/cell_sim/sim.rs
index 253da8a..9b07b98 100644
--- a/src/sim/cell_sim/sim.rs
+++ b/src/sim/cell_sim/sim.rs
@@ -34,6 +34,23 @@ impl<'a> ChunkAccess<'a> {
unsafe impl Sync for ChunkAccess<'_> {}
+const NEIGHBORHOOD_OFFSETS: [(i32, i32); 9] = [
+ (-1, -1),
+ (0, -1),
+ (1, -1),
+ (-1, 0),
+ (0, 0),
+ (1, 0),
+ (-1, 1),
+ (0, 1),
+ (1, 1),
+];
+
+#[inline]
+fn neighbourhood_index(x: i8, y: i8) -> usize {
+ (x + 1 + (y + 1) * 3) as usize
+}
+
fn get_cell(chunks: &[Option<&mut Chunk>; 9], x: i32, y: i32) -> Option<Cell> {
let dcx = x.div_euclid(CHUNK_SIZE);
let dcy = y.div_euclid(CHUNK_SIZE);
@@ -42,7 +59,7 @@ fn get_cell(chunks: &[Option<&mut Chunk>; 9], x: i32, y: i32) -> Option<Cell> {
let nc_x = x.rem_euclid(CHUNK_SIZE) as u8;
let nc_y = y.rem_euclid(CHUNK_SIZE) as u8;
- chunks[(dcx + 1 + (dcy + 1) * 3) as usize]
+ chunks[neighbourhood_index(dcx as i8, dcy as i8)]
.as_ref()
.map(|chunk| chunk.get_cell_at_local_position(nc_x, nc_y))
} else {
@@ -52,22 +69,93 @@ fn get_cell(chunks: &[Option<&mut Chunk>; 9], x: i32, y: i32) -> Option<Cell> {
}
}
+fn adjacent_chunks(x: u8, y: u8) -> Vec<usize> {
+ if x == 0 {
+ if y == 0 {
+ vec![
+ // L
+ neighbourhood_index(-1, 0),
+ // U
+ neighbourhood_index(0, -1),
+ // LU
+ neighbourhood_index(-1, -1),
+ ]
+ } else if y == (CHUNK_SIZE - 1) as u8 {
+ vec![
+ // L
+ neighbourhood_index(-1, 0),
+ // D
+ neighbourhood_index(0, 1),
+ // LD
+ neighbourhood_index(-1, 1),
+ ]
+ } else {
+ // L
+ vec![neighbourhood_index(-1, 0)]
+ }
+ } else if x == (CHUNK_SIZE - 1) as u8 {
+ if y == 0 {
+ vec![
+ // R
+ neighbourhood_index(1, 0),
+ // U
+ neighbourhood_index(0, -1),
+ // RU
+ neighbourhood_index(1, -1),
+ ]
+ } else if y == (CHUNK_SIZE - 1) as u8 {
+ vec![
+ // R
+ neighbourhood_index(1, 0),
+ // D
+ neighbourhood_index(0, 1),
+ // RD
+ neighbourhood_index(1, 1),
+ ]
+ } else {
+ // R
+ vec![neighbourhood_index(1, 0)]
+ }
+ } else if y == 0 {
+ // U
+ vec![neighbourhood_index(0, -1)]
+ } else if y == (CHUNK_SIZE - 1) as u8 {
+ // D
+ vec![neighbourhood_index(0, 1)]
+ } else {
+ vec![]
+ }
+}
+
pub fn set_cell(chunks: &mut [Option<&mut Chunk>; 9], x: i32, y: i32, cell: Cell) {
- let dcx = x.div_euclid(CHUNK_SIZE);
- let dcy = y.div_euclid(CHUNK_SIZE);
- if dcx != 0 || dcy != 0 {
+ let cx = x.div_euclid(CHUNK_SIZE);
+ let cy = y.div_euclid(CHUNK_SIZE);
+ let lx = x.rem_euclid(CHUNK_SIZE) as u8;
+ let ly = y.rem_euclid(CHUNK_SIZE) as u8;
+ if cx != 0 || cy != 0 {
// in a different chunk
- let nc_x = x.rem_euclid(CHUNK_SIZE) as u8;
- let nc_y = y.rem_euclid(CHUNK_SIZE) as u8;
-
- if let Some(chunk) = &mut chunks[(dcx + 1 + (dcy + 1) * 3) as usize] {
- chunk.set_cell_at_local_position(nc_x, nc_y, cell);
+ if let Some(chunk) = &mut chunks[neighbourhood_index(cx as i8, cy as i8)] {
+ chunk.set_cell_at_local_position(lx, ly, cell);
chunk.needs_texture_update = true;
+ chunk.sleeping = false;
+ // if we're at the boundaries of the chunk, wake the adjacent chunk(s)
+ for idx in adjacent_chunks(lx, ly) {
+ if let Some(chunk) = chunks[idx].as_mut() {
+ chunk.sleeping = false;
+ }
+ }
}
} else {
if let Some(target) = &mut chunks[4] {
target.set_cell_at_local_position(x as u8, y as u8, cell);
target.needs_texture_update = true;
+ target.sleeping = false;
+ // if we're at the boundaries of the chunk, wake the adjacent chunk(s)
+ for idx in adjacent_chunks(lx, ly) {
+ if let Some(chunk) = chunks[idx].as_mut() {
+ chunk.sleeping = false;
+ }
+ }
}
}
}
@@ -101,11 +189,6 @@ impl UpdateCtx<'_, '_, '_> {
let x = self.x + dx;
let y = self.y + dy;
set_cell(self.chunks, x, y, cell);
- self.chunks.iter_mut().for_each(|c| {
- if let Some(chunk) = c {
- chunk.sleeping = false;
- }
- })
}
pub fn candidates_swap(&mut self, candidates: &[(i32, i32)]) -> bool {
@@ -145,6 +228,9 @@ pub fn sim_tick_chunk(chunks: &mut [Option<&mut Chunk>; 9], seqno: u64) {
let material = cell.material.def();
if let Some(update) = material.sim_update
+ // NOTE we only update parity when cells are updated, which means that static cells
+ // are only evaluated every other tick
+ // it also means that the settled counter increases every other tick
&& cell.parity() == seqno_parity
{
let mut update_ctx = UpdateCtx {
@@ -175,18 +261,6 @@ pub fn sim_tick_chunk(chunks: &mut [Option<&mut Chunk>; 9], seqno: u64) {
}
}
-const NEIGHBORHOOD_OFFSETS: [(i32, i32); 9] = [
- (-1, -1),
- (0, -1),
- (1, -1),
- (-1, 0),
- (0, 0),
- (1, 0),
- (-1, 1),
- (0, 1),
- (1, 1),
-];
-
pub fn sim_tick(world: &mut World, seqno: u64, use_threading: bool) {
puffin::profile_function!();