Merge pull request #2741 from horizon-rust/refactor/cut-biome-spawn-parsers

🤖 Agent: verify passed at 0f565f4e4. Move only: parse_entries/parse_costs/SpawnCost go from mobs/spawn_selection.rs to biome.rs (re-exported), cutting biome -> mobs (step A of the cycle plan). pr_ready --quick green (1315 tests). Ready to merge once parity is green.
This commit is contained in:
Ludovic Marie
2026-10-28 13:12:01 +01:00
committed by GitHub
5 changed files with 63 additions and 58 deletions
+59 -3
View File
@@ -20,12 +20,68 @@ pub struct SpawnEntry {
/// A `ConstantInt` count (sampling draws nothing).
pub constant: bool,
}
/// A `natural_mob_spawns` / `spawn_overrides` entry list.
pub fn parse_entries(list: &Value) -> Vec<SpawnEntry> {
list.as_array()
.into_iter()
.flatten()
.filter_map(|e| {
let count = &e["count"];
let (min, max, constant) = match count {
Value::Number(n) => {
let n = n.as_u64().unwrap_or(1) as u32;
(n, n, true)
}
c if c["type"].as_str() == Some("minecraft:constant") => {
let n = c["value"].as_u64().unwrap_or(1) as u32;
(n, n, true)
}
c => (
c["min_inclusive"].as_u64().unwrap_or(1) as u32,
c["max_inclusive"].as_u64().unwrap_or(1) as u32,
false,
),
};
Some(SpawnEntry {
entity: e["type"].as_str()?.to_owned(),
weight: e["weight"].as_u64().unwrap_or(1) as u32,
min,
max,
constant,
})
})
.collect()
}
/// `MobSpawnSettings.MobSpawnCost`.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct SpawnCost {
pub energy_budget: f64,
pub charge: f64,
}
/// The `spawn_costs` of a `natural_mob_spawns` value.
pub fn parse_costs(costs: &Value) -> HashMap<String, SpawnCost> {
costs
.as_object()
.into_iter()
.flatten()
.map(|(k, c)| {
(
k.clone(),
SpawnCost {
energy_budget: c["energy_budget"].as_f64().unwrap_or(0.0),
charge: c["charge"].as_f64().unwrap_or(0.0),
},
)
})
.collect()
}
#[derive(Clone, Debug)]
pub struct BiomeInfo {
/// `natural_mob_spawns` by category (creature, monster, ...).
pub spawns: HashMap<String, Vec<SpawnEntry>>,
/// `natural_mob_spawns` spawn costs by entity type.
pub spawn_costs: HashMap<String, crate::mobs::spawn_selection::SpawnCost>,
pub spawn_costs: HashMap<String, SpawnCost>,
/// The `gameplay/creature_world_gen_spawn_probability` attribute.
pub creature_probability: f32,
/// The `gameplay/increased_fire_burnout` attribute (jungles, swamps, peaks,
@@ -150,12 +206,12 @@ impl Biomes {
};
let categories = &natural["spawns_by_category"];
for (category, entries) in categories.as_object().into_iter().flatten() {
let list = crate::mobs::spawn_selection::parse_entries(entries);
let list = parse_entries(entries);
spawns.insert(category.clone(), list);
}
list.push(BiomeInfo {
spawns,
spawn_costs: crate::mobs::spawn_selection::parse_costs(&natural["spawn_costs"]),
spawn_costs: parse_costs(&natural["spawn_costs"]),
creature_probability:
attributes["minecraft:gameplay/creature_world_gen_spawn_probability"]
.as_f64()
@@ -23,61 +23,7 @@ use horizon_core::{
use serde_json::Value;
use std::{collections::HashMap, fs, path::Path};
/// A `natural_mob_spawns` / `spawn_overrides` entry list.
pub fn parse_entries(list: &Value) -> Vec<SpawnEntry> {
list.as_array()
.into_iter()
.flatten()
.filter_map(|e| {
let count = &e["count"];
let (min, max, constant) = match count {
Value::Number(n) => {
let n = n.as_u64().unwrap_or(1) as u32;
(n, n, true)
}
c if c["type"].as_str() == Some("minecraft:constant") => {
let n = c["value"].as_u64().unwrap_or(1) as u32;
(n, n, true)
}
c => (
c["min_inclusive"].as_u64().unwrap_or(1) as u32,
c["max_inclusive"].as_u64().unwrap_or(1) as u32,
false,
),
};
Some(SpawnEntry {
entity: e["type"].as_str()?.to_owned(),
weight: e["weight"].as_u64().unwrap_or(1) as u32,
min,
max,
constant,
})
})
.collect()
}
/// `MobSpawnSettings.MobSpawnCost`.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct SpawnCost {
pub energy_budget: f64,
pub charge: f64,
}
/// The `spawn_costs` of a `natural_mob_spawns` value.
pub fn parse_costs(costs: &Value) -> HashMap<String, SpawnCost> {
costs
.as_object()
.into_iter()
.flatten()
.map(|(k, c)| {
(
k.clone(),
SpawnCost {
energy_budget: c["energy_budget"].as_f64().unwrap_or(0.0),
charge: c["charge"].as_f64().unwrap_or(0.0),
},
)
})
.collect()
}
pub use crate::biome::{SpawnCost, parse_costs, parse_entries};
/// `MobCategory`.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+1
View File
@@ -552,6 +552,7 @@ def main():
oracle = lab.ROOT / 'mods/horizon/src/test/java/dev/horizonlab/parity/VanillaNaturalSpawnOracle.java'
sources = [oracle, Path(__file__), lab.ROOT / 'crates/horizon-client/examples/probe/natural_spawn_fixture.rs',
lab.ROOT / 'crates/horizon-client/src/mobs/spawn_selection.rs',
lab.ROOT / 'crates/horizon-client/src/biome.rs',
lab.ROOT / 'crates/horizon-client/src/mobs/spawn_rules.rs']
tested = base.source_hashes(sources)
inputs = build / 'inputs.txt'
+1
View File
@@ -235,6 +235,7 @@ def main():
lab.ROOT / 'crates/horizon-client/src/chunk/block_entity.rs',
lab.ROOT / 'crates/horizon-client-core/src/identifier.rs',
lab.ROOT / 'crates/horizon-client/src/mobs/spawn_selection.rs',
lab.ROOT / 'crates/horizon-client/src/biome.rs',
lab.ROOT / 'crates/horizon-client/src/mobs/spawn_rules.rs']
tested = base.source_hashes(sources)
inputs = build / 'inputs.txt'
+1
View File
@@ -200,6 +200,7 @@ def main():
lab.ROOT / 'crates/horizon-client/src/chunk/block_entity.rs',
lab.ROOT / 'crates/horizon-client-core/src/identifier.rs',
lab.ROOT / 'crates/horizon-client/src/mobs/spawn_selection.rs',
lab.ROOT / 'crates/horizon-client/src/biome.rs',
lab.ROOT / 'crates/horizon-client/src/mobs/spawn_rules.rs']
tested = base.source_hashes(sources)
inputs = build / 'inputs.txt'