fix
This commit is contained in:
-201
@@ -1,201 +0,0 @@
|
|||||||
diff --git a/config.toml b/config.toml
|
|
||||||
index 9e6f89b..fbb1c42 100644
|
|
||||||
--- a/config.toml
|
|
||||||
+++ b/config.toml
|
|
||||||
@@ -1,4 +1,4 @@
|
|
||||||
-initial_chunk_radius = 5
|
|
||||||
+initial_chunk_radius = 15
|
|
||||||
|
|
||||||
[spawn_counts]
|
|
||||||
dorfs = 5
|
|
||||||
diff --git a/src/world/mod.rs b/src/world/mod.rs
|
|
||||||
index 9698168..f597c34 100644
|
|
||||||
--- a/src/world/mod.rs
|
|
||||||
+++ b/src/world/mod.rs
|
|
||||||
@@ -27,6 +27,7 @@ impl Plugin for WorldPlugin {
|
|
||||||
.init_resource::<tiles::TilemapBenchmark>()
|
|
||||||
.init_resource::<tiles::TilemapChunkRegistry>()
|
|
||||||
.init_resource::<tiles::TilemapChunkSpawner>()
|
|
||||||
+ .init_resource::<tiles::PreviousZIndex>()
|
|
||||||
.add_message::<GenerateChunkEvent>()
|
|
||||||
.add_message::<ChunkTerrainEvent>()
|
|
||||||
.add_message::<ChunkWeatheringAndPrecipitationEvent>()
|
|
||||||
diff --git a/src/world/tiles/benchmark.rs b/src/world/tiles/benchmark.rs
|
|
||||||
index bac3570..8541a71 100644
|
|
||||||
--- a/src/world/tiles/benchmark.rs
|
|
||||||
+++ b/src/world/tiles/benchmark.rs
|
|
||||||
@@ -37,6 +37,11 @@ pub struct TilemapBenchmark {
|
|
||||||
pub dirty_keys_total: usize,
|
|
||||||
/// CPU memory estimate for tile data in MB.
|
|
||||||
pub tile_data_mb: f64,
|
|
||||||
+
|
|
||||||
+ pub last_z_change_dirty_ms: f64,
|
|
||||||
+ pub last_z_change_dirty_count: usize,
|
|
||||||
+ pub last_z_change_populate_ms: f64,
|
|
||||||
+ pub z_change_history_ms: Vec<f64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for TilemapBenchmark {
|
|
||||||
@@ -53,6 +58,10 @@ impl Default for TilemapBenchmark {
|
|
||||||
dirty_keys_last: 0,
|
|
||||||
dirty_keys_total: 0,
|
|
||||||
tile_data_mb: 0.0,
|
|
||||||
+ last_z_change_dirty_ms: 0.0,
|
|
||||||
+ last_z_change_dirty_count: 0,
|
|
||||||
+ last_z_change_populate_ms: 0.0,
|
|
||||||
+ z_change_history_ms: Vec::with_capacity(100),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -69,7 +78,7 @@ impl TilemapBenchmark {
|
|
||||||
let p50_idx = (self.frame_times.len() as f32 * 0.50) as usize;
|
|
||||||
let p99_idx = (self.frame_times.len() as f32 * 0.99) as usize;
|
|
||||||
let mut sorted = self.frame_times.clone();
|
|
||||||
- sorted.sort();
|
|
||||||
+ sorted.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
|
||||||
let p50 = sorted
|
|
||||||
.get(p50_idx.min(sorted.len().saturating_sub(1)))
|
|
||||||
.copied()
|
|
||||||
@@ -107,6 +116,35 @@ impl TilemapBenchmark {
|
|
||||||
);
|
|
||||||
println!("║ Tile data mem: {:.2} MB", self.tile_data_mb);
|
|
||||||
println!("║ Cumulative: {:.2}s", self.populate_ms / 1000.0);
|
|
||||||
+ println!("╠══════════════════════════════════════════════════════════════╣");
|
|
||||||
+ let z_p50 = if !self.z_change_history_ms.is_empty() {
|
|
||||||
+ let mut sorted = self.z_change_history_ms.clone();
|
|
||||||
+ sorted.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
|
||||||
+ sorted[sorted.len() / 2]
|
|
||||||
+ } else {
|
|
||||||
+ 0.0
|
|
||||||
+ };
|
|
||||||
+ let z_p95 = if !self.z_change_history_ms.is_empty() {
|
|
||||||
+ let mut sorted = self.z_change_history_ms.clone();
|
|
||||||
+ sorted.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
|
||||||
+ let idx = ((sorted.len() as f32) * 0.95) as usize;
|
|
||||||
+ sorted[idx.min(sorted.len().saturating_sub(1))]
|
|
||||||
+ } else {
|
|
||||||
+ 0.0
|
|
||||||
+ };
|
|
||||||
+ println!("║ Z-scroll spike:");
|
|
||||||
+ println!(
|
|
||||||
+ "║ Last dirty marking: {:.2}ms ({} keys)",
|
|
||||||
+ self.last_z_change_dirty_ms, self.last_z_change_dirty_count
|
|
||||||
+ );
|
|
||||||
+ println!(
|
|
||||||
+ "║ Last z-change populate: {:.2}ms",
|
|
||||||
+ self.last_z_change_populate_ms
|
|
||||||
+ );
|
|
||||||
+ println!(
|
|
||||||
+ "║ Z-change populate p50: {:.2}ms p95: {:.2}ms",
|
|
||||||
+ z_p50, z_p95
|
|
||||||
+ );
|
|
||||||
println!("╚══════════════════════════════════════════════════════════════╝");
|
|
||||||
println!();
|
|
||||||
}
|
|
||||||
diff --git a/src/world/tiles/tilemap_chunk.rs b/src/world/tiles/tilemap_chunk.rs
|
|
||||||
index 6074dc5..bf8f459 100644
|
|
||||||
--- a/src/world/tiles/tilemap_chunk.rs
|
|
||||||
+++ b/src/world/tiles/tilemap_chunk.rs
|
|
||||||
@@ -50,6 +50,17 @@ impl Default for TilemapChunkSpawner {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+pub const MAX_POPULATE_PER_FRAME: usize = 512;
|
|
||||||
+
|
|
||||||
+#[derive(Resource)]
|
|
||||||
+pub struct PreviousZIndex(pub i32);
|
|
||||||
+
|
|
||||||
+impl Default for PreviousZIndex {
|
|
||||||
+ fn default() -> Self {
|
|
||||||
+ Self(0)
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
impl TilemapChunkSpawner {
|
|
||||||
pub fn queue_chunk(&mut self, chunk_pos: IVec2) {
|
|
||||||
for z in 0..=(Z_TOTAL as usize) {
|
|
||||||
@@ -284,18 +295,27 @@ pub fn populate_tilemap_chunk_data(
|
|
||||||
if registry.dirty_keys.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ let was_z_change = bench.last_z_change_dirty_count > 0;
|
|
||||||
let now = Instant::now();
|
|
||||||
let camera_z = z_index.0 as i32;
|
|
||||||
- let current_z = (camera_z as f32 + Z_BELOW) as usize;
|
|
||||||
+ let current_z_index = (camera_z as f32 + Z_BELOW) as usize;
|
|
||||||
+
|
|
||||||
+ let mut to_process: Vec<ChunkLayerKey> = registry.dirty_keys.iter().cloned().collect();
|
|
||||||
+ to_process.sort_by_key(|k| (k.z_index as i32 - current_z_index as i32).unsigned_abs());
|
|
||||||
+ to_process.truncate(MAX_POPULATE_PER_FRAME);
|
|
||||||
+
|
|
||||||
+ for key in &to_process {
|
|
||||||
+ registry.dirty_keys.remove(key);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- let dirty: Vec<ChunkLayerKey> = registry.dirty_keys.drain().collect();
|
|
||||||
let mut processed = 0usize;
|
|
||||||
|
|
||||||
- for key in dirty {
|
|
||||||
+ for key in to_process {
|
|
||||||
let Some(&entity) = registry.entities.get(&key) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
- let Ok((mut tile_data, chunk_key)) = chunk_data_query.get_mut(entity) else {
|
|
||||||
+ let Ok((mut tile_data, _)) = chunk_data_query.get_mut(entity) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -320,15 +340,48 @@ pub fn populate_tilemap_chunk_data(
|
|
||||||
bench.dirty_keys_total += processed;
|
|
||||||
bench.tile_data_mb = (registry.entities.len() as f64 * (CHUNK_SIZE * CHUNK_SIZE) as f64 * 4.0)
|
|
||||||
/ (1024.0 * 1024.0);
|
|
||||||
+
|
|
||||||
+ if was_z_change {
|
|
||||||
+ bench.last_z_change_populate_ms = elapsed;
|
|
||||||
+ bench.z_change_history_ms.push(elapsed);
|
|
||||||
+ if bench.z_change_history_ms.len() > 100 {
|
|
||||||
+ bench.z_change_history_ms.remove(0);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
-pub fn on_camera_z_changed(z_index: Res<ZIndex>, mut registry: ResMut<TilemapChunkRegistry>) {
|
|
||||||
- if z_index.is_changed() {
|
|
||||||
- let keys: Vec<ChunkLayerKey> = registry.entities.keys().cloned().collect();
|
|
||||||
- for key in keys {
|
|
||||||
+pub fn on_camera_z_changed(
|
|
||||||
+ z_index: Res<ZIndex>,
|
|
||||||
+ mut registry: ResMut<TilemapChunkRegistry>,
|
|
||||||
+ mut prev_z: ResMut<PreviousZIndex>,
|
|
||||||
+ mut bench: ResMut<super::TilemapBenchmark>,
|
|
||||||
+) {
|
|
||||||
+ if !z_index.is_changed() {
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ let old_camera_z = prev_z.0;
|
|
||||||
+ let new_camera_z = z_index.0 as i32;
|
|
||||||
+ prev_z.0 = new_camera_z;
|
|
||||||
+
|
|
||||||
+ let now = Instant::now();
|
|
||||||
+ let mut count = 0;
|
|
||||||
+
|
|
||||||
+ let keys: Vec<ChunkLayerKey> = registry.entities.keys().cloned().collect();
|
|
||||||
+ for key in keys {
|
|
||||||
+ let tile_z = camera_z_for_z_index(key.z_index);
|
|
||||||
+ let old_diff = old_camera_z - tile_z;
|
|
||||||
+ let new_diff = new_camera_z - tile_z;
|
|
||||||
+ let was_in_range = old_diff >= 0 && old_diff <= 8;
|
|
||||||
+ let is_in_range = new_diff >= 0 && new_diff <= 8;
|
|
||||||
+ if was_in_range || is_in_range {
|
|
||||||
registry.dirty_keys.insert(key);
|
|
||||||
+ count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ bench.last_z_change_dirty_ms = now.elapsed().as_secs_f64() * 1000.0;
|
|
||||||
+ bench.last_z_change_dirty_count = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn despawn_tilemap_chunks(
|
|
||||||
@@ -9,8 +9,8 @@ use crate::{
|
|||||||
constants::{SEED, TILE_SIZE},
|
constants::{SEED, TILE_SIZE},
|
||||||
world::{
|
world::{
|
||||||
tiles::{ChunkData, FloorTileData, TileMap},
|
tiles::{ChunkData, FloorTileData, TileMap},
|
||||||
ChunkForrestryEvent, ChunkTerrainEvent, FloorTilePrefab, TileOcclusionEvent, CHUNK_SIZE,
|
ChunkForrestryEvent, ChunkMap, ChunkTerrainEvent, FloorTilePrefab, TileOcclusionEvent,
|
||||||
Z_ABOVE, Z_BELOW, ChunkMap,
|
CHUNK_SIZE, Z_ABOVE, Z_BELOW,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -280,10 +280,12 @@ pub fn spawn_terrain_tasks(
|
|||||||
for event in events.read() {
|
for event in events.read() {
|
||||||
let chunk_pos = event.chunk_position;
|
let chunk_pos = event.chunk_position;
|
||||||
let blobs_clone = blobs.clone();
|
let blobs_clone = blobs.clone();
|
||||||
task_pool.spawn(async move {
|
task_pool
|
||||||
let blob = generate_terrain_blob(chunk_pos);
|
.spawn(async move {
|
||||||
blobs_clone.lock().unwrap().push(blob);
|
let blob = generate_terrain_blob(chunk_pos);
|
||||||
}).detach();
|
blobs_clone.lock().unwrap().push(blob);
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{} terrain tasks spawned in {:.2?}", count, start.elapsed());
|
println!("{} terrain tasks spawned in {:.2?}", count, start.elapsed());
|
||||||
@@ -331,7 +333,11 @@ pub fn apply_terrain_blobs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if applied_count > 0 {
|
if applied_count > 0 {
|
||||||
println!("{} terrain blobs applied in {:.2?}", applied_count, start.elapsed());
|
println!(
|
||||||
|
"{} terrain blobs applied in {:.2?}",
|
||||||
|
applied_count,
|
||||||
|
start.elapsed()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user