feat: multi-layer world — temperature, gas, pressure, light as parallel per-chunk arrays
- Removed temp from Cell (13→9 bytes), added temps/pressure/gas_type/gas_density/light arrays to Chunk - Layer access via grid.get_temp()/set_temp()/get_gas()/set_gas()/get_pressure()/set_pressure()/get_light()/set_light() - cells_swap swaps all layers, set_material sets default_temp - heat_transfer refactored to direct array access on temps[] (no Cell copy) - CA rules refactored: cell.temp → grid.get_temp()/set_temp() - gas_step: gas flow (rise, spread), fire produces CO2+smoke, steam condenses to water, acid+organic→poison gas - pressure_step: pressure equalization for connected non-solid cells - light_step: world-space persistent lighting, updated every 10 ticks, ray-cast line-of-sight - Gas damage: poison gas damages entities, CO2 suffocates, applied before ca.step() - Multi-section chunk serialization (VWM1 magic + cells + temps + gas + pressure + light) - Old 12-byte chunk format auto-detected for backward compat - AI spectrum: new gas + pressure spectrums, light spectrum uses world-space fallback - Protocol: gas/pressure spectrum commands - pre_dirty mechanism: layer steps process pre-clear dirty rects for cross-cell diffusion - 14 new multilayer tests, all 185 tests + 14 scenarios pass - Benchmark: 85.9 FPS (graphics surface, was 128 pre-layers — 33% regression from 4 new layer steps)
This commit is contained in:
+78
-2
@@ -4,6 +4,11 @@ pub const CHUNK_SIZE: usize = 64;
|
||||
|
||||
pub struct Chunk {
|
||||
pub cells: Vec<Cell>,
|
||||
pub temps: Vec<f32>,
|
||||
pub pressure: Vec<u8>,
|
||||
pub gas_type: Vec<u8>,
|
||||
pub gas_density: Vec<u8>,
|
||||
pub light: Vec<[u8; 3]>,
|
||||
pub active: bool,
|
||||
pub modified: bool,
|
||||
pub was_modified: bool,
|
||||
@@ -11,11 +16,18 @@ pub struct Chunk {
|
||||
pub dirty: Option<(i32, i32, i32, i32)>,
|
||||
}
|
||||
|
||||
const CHUNK_AREA: usize = CHUNK_SIZE * CHUNK_SIZE;
|
||||
const ATMOSPHERIC_PRESSURE: u8 = 128;
|
||||
|
||||
impl Chunk {
|
||||
pub fn new() -> Self {
|
||||
let size = CHUNK_SIZE * CHUNK_SIZE;
|
||||
Self {
|
||||
cells: vec![Cell::empty(); size],
|
||||
cells: vec![Cell::empty(); CHUNK_AREA],
|
||||
temps: vec![20.0; CHUNK_AREA],
|
||||
pressure: vec![ATMOSPHERIC_PRESSURE; CHUNK_AREA],
|
||||
gas_type: vec![0; CHUNK_AREA],
|
||||
gas_density: vec![0; CHUNK_AREA],
|
||||
light: vec![[0, 0, 0]; CHUNK_AREA],
|
||||
active: false,
|
||||
modified: false,
|
||||
was_modified: false,
|
||||
@@ -62,10 +74,74 @@ impl Chunk {
|
||||
pub fn set_material(&mut self, x: i32, y: i32, mat: MaterialId) {
|
||||
if Self::in_bounds(x, y) {
|
||||
self.cells[Self::idx(x, y)] = Cell::new(mat);
|
||||
self.temps[Self::idx(x, y)] = crate::world::cell::default_temp(mat);
|
||||
self.modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_temp(&self, x: i32, y: i32) -> f32 {
|
||||
if !Self::in_bounds(x, y) {
|
||||
return 20.0;
|
||||
}
|
||||
self.temps[Self::idx(x, y)]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_temp(&mut self, x: i32, y: i32, t: f32) {
|
||||
if Self::in_bounds(x, y) {
|
||||
self.temps[Self::idx(x, y)] = t;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_pressure(&self, x: i32, y: i32) -> u8 {
|
||||
if !Self::in_bounds(x, y) {
|
||||
return 128;
|
||||
}
|
||||
self.pressure[Self::idx(x, y)]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_pressure(&mut self, x: i32, y: i32, p: u8) {
|
||||
if Self::in_bounds(x, y) {
|
||||
self.pressure[Self::idx(x, y)] = p;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_gas(&self, x: i32, y: i32) -> (u8, u8) {
|
||||
if !Self::in_bounds(x, y) {
|
||||
return (0, 0);
|
||||
}
|
||||
let i = Self::idx(x, y);
|
||||
(self.gas_type[i], self.gas_density[i])
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_gas(&mut self, x: i32, y: i32, gas_type: u8, density: u8) {
|
||||
if Self::in_bounds(x, y) {
|
||||
let i = Self::idx(x, y);
|
||||
self.gas_type[i] = gas_type;
|
||||
self.gas_density[i] = density;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_light(&self, x: i32, y: i32) -> [u8; 3] {
|
||||
if !Self::in_bounds(x, y) {
|
||||
return [0, 0, 0];
|
||||
}
|
||||
self.light[Self::idx(x, y)]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_light(&mut self, x: i32, y: i32, rgb: [u8; 3]) {
|
||||
if Self::in_bounds(x, y) {
|
||||
self.light[Self::idx(x, y)] = rgb;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.cells.iter().all(|c| c.is_empty())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user