summaryrefslogtreecommitdiff
path: root/src/sim/sim.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/sim/sim.rs')
-rw-r--r--src/sim/sim.rs231
1 files changed, 0 insertions, 231 deletions
diff --git a/src/sim/sim.rs b/src/sim/sim.rs
deleted file mode 100644
index b9f4b76..0000000
--- a/src/sim/sim.rs
+++ /dev/null
@@ -1,231 +0,0 @@
-use std::marker::PhantomData;
-
-use fxhash::FxHashMap;
-use rand::{Rng, SeedableRng, rngs::SmallRng};
-use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
-
-use crate::{
- config::CHUNK_SIZE,
- sim::{cell::Cell, chunk::Chunk, materials::MaterialDef, world::World},
-};
-
-struct ChunkAccess<'a> {
- ptr: *mut Chunk,
- len: usize,
- _marker: PhantomData<&'a mut [Chunk]>,
-}
-
-impl<'a> ChunkAccess<'a> {
- pub fn new(chunks: &'a mut [Chunk]) -> Self {
- Self {
- ptr: chunks.as_mut_ptr(),
- len: chunks.len(),
- _marker: PhantomData,
- }
- }
- unsafe fn get(&self, i: usize) -> &'a mut Chunk {
- debug_assert!(i < self.len);
- unsafe { &mut *self.ptr.add(i) }
- }
-}
-
-unsafe impl Sync for ChunkAccess<'_> {}
-
-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);
- if dcx != 0 || dcy != 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;
-
- chunks[(dcx + 1 + (dcy + 1) * 3) as usize]
- .as_ref()
- .map(|chunk| chunk.get_cell_at_local_position(nc_x, nc_y))
- } else {
- chunks[4]
- .as_ref()
- .map(|target| target.get_cell_at_local_position(x as u8, y as u8))
- }
-}
-
-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 {
- // 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);
- chunk.needs_texture_update = true;
- }
- } 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;
- }
- }
-}
-
-pub struct UpdateCtx<'a, 'b, 'c> {
- pub chunks: &'a mut [Option<&'b mut Chunk>; 9],
- pub seqno: u64,
- pub seqno_parity: u8,
-
- pub x: i32,
- pub y: i32,
- pub cell: &'c mut Cell,
- pub material: &'c MaterialDef,
-
- pub rng: &'c mut dyn Rng,
-}
-
-impl UpdateCtx<'_, '_, '_> {
- pub fn get_cell(&self, dx: i32, dy: i32) -> Option<Cell> {
- let x = self.x + dx;
- let y = self.y + dy;
- get_cell(self.chunks, x, y)
- }
-
- pub fn set_cell(&mut self, dx: i32, dy: i32, cell: Cell) {
- // cannot move out of the neighbourhood, but also cannot move to the edge of the neighbourhood
- // as this would wake a chunk outside of the neighbourhood
- debug_assert!(dx > -15 && dx < 15);
- debug_assert!(dy > -15 && dy < 15);
- 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 {
- for &(dx, dy) in candidates {
- let candidate_cell = self.get_cell(dx, dy);
- if candidate_cell.is_some_and(|c| c.material.def().density < self.material.density) {
- self.set_cell(0, 0, candidate_cell.unwrap());
- self.set_cell(dx, dy, *self.cell);
- return true;
- }
- }
- false
- }
-}
-
-pub fn sim_tick_chunk(chunks: &mut [Option<&mut Chunk>; 9], seqno: u64) {
- puffin::profile_function!();
- let seqno_parity = (seqno as u8) & 0b1;
- let mut rng = SmallRng::seed_from_u64(seqno);
-
- if chunks[4].is_some() {
- for y in (0..CHUNK_SIZE).rev() {
- for i in 0..CHUNK_SIZE {
- let x = if seqno_parity == 0 {
- i
- } else {
- (CHUNK_SIZE) - i - 1
- };
-
- let mut cell = get_cell(chunks, x, y).unwrap();
- let material = cell.material.def();
-
- if let Some(update) = material.sim_update
- && cell.parity() == seqno_parity
- {
- cell.flip_parity();
- // apply the flipped parity in case the sim target doesn't
- set_cell(chunks, x, y, cell);
-
- let mut update_ctx = UpdateCtx {
- chunks,
- seqno,
- seqno_parity,
-
- x,
- y,
- cell: &mut cell,
- material,
-
- // TODO this is platform-dependent, will break for multiplayer
- rng: &mut rng,
- };
-
- update(&mut update_ctx);
- }
- }
- }
- }
-}
-
-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!();
-
- let mut columns: FxHashMap<i32, Vec<i32>> = FxHashMap::default();
- for &(cx, cy) in world.chunk_position_to_chunk_idx.keys() {
- columns.entry(cx).or_default().push(cy);
- }
-
- // color columns s.t. columns of same color are separated by two columns
- // and sort the column bottom-to-top
- // --------------------
- // | 0, 1, 2, 0, 1, 2 |
- // | 0, 1, 2, 0, 1, 2 |
- // | 0, 1, 2, 0, 1, 2 |
- // --------------------
- let mut columns_by_color: [Vec<(i32, Vec<i32>)>; 3] = Default::default();
- for (cx, mut cys) in columns {
- cys.sort_unstable_by(|a, b| b.cmp(a));
- columns_by_color[cx.rem_euclid(3) as usize].push((cx, cys));
- }
-
- let access = ChunkAccess::new(&mut world.chunks);
-
- for color in &columns_by_color {
- puffin::profile_scope!("chunk_color");
-
- let chunk_closure = |(cx, cys): &(i32, Vec<i32>)| {
- let cx = *cx;
- for &cy in cys {
- let mut chunks: [Option<&mut Chunk>; 9] = NEIGHBORHOOD_OFFSETS.map(|(dx, dy)| {
- world
- .chunk_position_to_chunk_idx
- .get(&(cx + dx, cy + dy))
- .map(|&idx| unsafe { access.get(idx) })
- });
-
- if let Some(target) = &mut chunks[4] {
- if target.sleeping {
- continue;
- }
- target.sleeping = true;
- }
-
- sim_tick_chunk(&mut chunks, seqno);
- }
- };
-
- if use_threading {
- // TODO use forte
- color.par_iter().for_each(chunk_closure);
- } else {
- color.iter().for_each(chunk_closure);
- };
- }
-}