diff options
| author | Kai Stevenson <kai@kaistevenson.com> | 2026-08-18 23:50:37 -0700 |
|---|---|---|
| committer | Kai Stevenson <kai@kaistevenson.com> | 2026-08-18 23:55:41 -0700 |
| commit | afae4ace5ffcefa4590b80ddcf097559c64c7413 (patch) | |
| tree | ad2e0beca3da19fba8e53534c03e9f018d387ca1 /src | |
| parent | a0b3de6086d5245eaefa9e510cbf2844b0224405 (diff) | |
optimize chunk wakes
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 1 | ||||
| -rw-r--r-- | src/sim/cell_sim/sim.rs | 126 |
2 files changed, 101 insertions, 26 deletions
diff --git a/src/main.rs b/src/main.rs index 10bea68..7cd1f37 100644 --- a/src/main.rs +++ b/src/main.rs @@ -212,6 +212,7 @@ impl App { .chunk_position_to_chunk_idx .get(&(cx, cy)) .map(|&idx| &world.chunks[idx]) + && !chunk.sleeping { physics_manager.upsert_chunk_collider(cx, cy, chunk); } 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!(); |
