diff --git a/src/simulator/api-gdext/src/lib.rs b/src/simulator/api-gdext/src/lib.rs index bc5a3a00..a26561c2 100644 --- a/src/simulator/api-gdext/src/lib.rs +++ b/src/simulator/api-gdext/src/lib.rs @@ -20,6 +20,8 @@ use mc_climate::spec; use mc_core::grid::GridState; use mc_ecology::EcologyEngine; use mc_ecology::fauna_product::{fauna_product_supply, FaunaProduct}; +use mc_ecology::population::PopulationSlot; +use mc_ecology::species::Species; use mc_mapgen::MapGenerator; struct MagicCivPhysicsExtension; @@ -334,6 +336,42 @@ impl GdFaunaEcology { } out } + + /// Register a fauna species from its canonical JSON definition (the same + /// shape consumed by `mc_ecology::species::Species::from_json`, matching + /// `public/resources/ecology/fauna/species/*.json`). The numeric + /// `species_id` is derived from a hash of the string `id` field; the + /// caller passes that returned id to `seed_population`. + /// + /// Returns `-1` on parse error. Used by proof scenes and integration tests + /// to construct controlled fauna populations against the live engine. + #[func] + fn register_species_from_json(&mut self, species_json: GString) -> i64 { + match Species::from_json(&species_json.to_string()) { + Ok(species) => { + let id = species.id as i64; + self.inner.register_species(species); + id + } + Err(e) => { + godot_error!("GdFaunaEcology::register_species_from_json: {e}"); + -1 + } + } + } + + /// Seed a population slot onto a tile. `species_id` must be the value + /// returned by a prior `register_species_from_json` call. Negative or + /// out-of-range ids are silently ignored. Multiple seed calls on the + /// same tile push additional slots (matches `EcologyEngine::seed_population`). + #[func] + fn seed_population(&mut self, col: i32, row: i32, species_id: i64, population: f64) { + if !(0..=u32::MAX as i64).contains(&species_id) { + return; + } + let slot = PopulationSlot::new(species_id as u32, population as f32); + self.inner.seed_population(col, row, slot); + } } // ── GdAtmosphericChemistry ──────────────────────────────────────────────