feat(simulation): foundation shared types + struct plumbing (#1006)

Define the type-definition layer the Phase-4 fill-seam tickets depend on
(D-229/D-230/D-231/D-232/D-233), compiling with stubs/defaults; behavior
logic lands in #982-985/#998.

- New types in generator.rs: BuildingPropertyTag, FloorExtent +
  FloorHeightProfile (floor_at_voxel_z/voxel_range_for_floor, resolves
  Q-104), BuildingEntryClass, ConstructionEra, ZoneTypeId, MorphologyZone,
  BulkClass(5), ProductionUbiquity, DoorSpec, InteriorDescriptor,
  DistrictWorldState.
- Rename spatial AccessTier -> ZoneAccessTier to free the name for the new
  per-building BuildingEntryClass.
- CityGenerationContext: +morphology_zone, +trait_selection,
  +dominant_bulk_class, +dominant_production_ubiquity.
- BodyWorldState: +districts (DistrictWorldState w/ block_tags).
- GenCompletion::SkeletonGenerated carries body_id + DistrictWorldState;
  plugin handler inserts into BodyWorldState.districts.
- Add smallvec as a direct dep (DoorSpec list stays Vec for now, TODO).

cargo check --all-targets / clippy clean; 1259 lib tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 16:07:33 +02:00
co-authored by Claude Opus 4.8
parent 6e7f6356f0
commit 46b8688fa3
10 changed files with 535 additions and 12 deletions
+15 -1
View File
@@ -13,7 +13,7 @@ use std::collections::{BTreeMap, BTreeSet};
use bevy_ecs::prelude::Resource;
use serde::{Deserialize, Serialize};
use crate::simulation::generator::GeographicAttractor;
use crate::simulation::generator::{DistrictId, DistrictWorldState, GeographicAttractor};
/// Simulation tick counter — monotonically increasing u64.
pub type SimTick = u64;
@@ -71,6 +71,11 @@ pub struct BodyWorldState {
pub drainage_basins: Vec<DrainageBasin>,
/// Geographic attractors (D-195, D-209). Empty until attractor task completes.
pub attractors: Vec<GeographicAttractor>,
/// District-level world state, keyed by `DistrictId` (D-230).
///
/// Populated by `GenCompletion::SkeletonGenerated` after the plan phase
/// completes for each city. `BTreeMap` for D-010 determinism.
pub districts: BTreeMap<DistrictId, DistrictWorldState>,
/// Last sim tick this entry was read. Used for LRU eviction.
pub last_accessed: SimTick,
}
@@ -129,6 +134,14 @@ impl BodyWorldStateCache {
self.entries.get(body_id)
}
/// Get a mutable reference without bumping `last_accessed`.
///
/// Used by the district-state insertion path (D-230) which writes into
/// the cached state without constituting a "read" for LRU purposes.
pub fn peek_mut(&mut self, body_id: &str) -> Option<&mut BodyWorldState> {
self.entries.get_mut(body_id)
}
/// Returns `true` if the cache has an entry for `body_id`.
pub fn contains(&self, body_id: &str) -> bool {
self.entries.contains_key(body_id)
@@ -183,6 +196,7 @@ mod tests {
river_network: RiverNetwork::default(),
drainage_basins: vec![],
attractors: vec![],
districts: BTreeMap::new(),
last_accessed: tick,
}
}