Skip to main content

mecha10_sim/sim/
mod.rs

1//! Simulation generation module
2//!
3//! Automatically generates simulation scenes from mecha10.json configuration.
4//!
5//! # Architecture
6//!
7//! The simulation module is organized into:
8//! - `catalog`: Environment catalog management
9//! - `environment_config`: `environment.json` parsing/validation (`features.objects[]`,
10//!   including the LAB-2025 config-driven image billboard objects)
11//! - `generator`: Scene generation logic
12//! - `preset_config`: `preset.json` parsing/validation (LAB-3629 -- environment-namespaced
13//!   content sets that layer onto an environment at runtime, reusing `environment_config`'s
14//!   `SceneObject` types)
15//! - `profile`: Robot profile extraction
16//! - `robot_generator`: Robot scene generation
17//! - `selector`: Environment selection logic
18//! - `validator`: Configuration and catalog validation
19//! - `lister`: Environment listing
20
21#![allow(dead_code)]
22
23pub mod catalog;
24pub mod environment_config;
25pub mod generator;
26pub mod lister;
27pub mod preset_config;
28pub mod profile;
29pub mod robot_generator;
30pub mod selector;
31pub mod validator;
32
33pub use catalog::EnvironmentCatalog;
34pub use environment_config::{
35    AmbientLight, CubeObject, DirectionalLight, DistanceUnit, EnvironmentConfig, EnvironmentDimensions,
36    EnvironmentFeatures, FloorFeature, GoalsFeature, ImageObject, LightingFeature, NpcsFeature, ObstaclesFeature,
37    SceneObject, SpawnPointsFeature, WallsFeature,
38};
39#[allow(unused_imports)]
40pub use lister::list_environments;
41pub use preset_config::PresetConfig;
42pub use profile::RobotProfile;
43pub use robot_generator::RobotGenerator;
44pub use selector::EnvironmentSelector;
45#[allow(unused_imports)]
46pub use validator::{validate_catalog, validate_config};
47
48use anyhow::{Context, Result};
49use std::path::Path;
50
51/// Read `path` as UTF-8 and parse it as JSON, with a consistent
52/// read-failed/parse-failed error message shape.
53///
54/// Shared by [`profile::RobotProfile::from_config_file`], [`environment_config::EnvironmentConfig::load`],
55/// and [`catalog::EnvironmentCatalog::load`], which otherwise each hand-rolled the same
56/// read-then-parse-with-context boilerplate for their own JSON file.
57pub(crate) fn load_json<T: serde::de::DeserializeOwned>(path: &Path, description: &str) -> Result<T> {
58    let content =
59        std::fs::read_to_string(path).with_context(|| format!("Failed to read {description}: {}", path.display()))?;
60
61    serde_json::from_str(&content).with_context(|| format!("Failed to parse {description}: {}", path.display()))
62}
63
64/// Generate standalone robot scene from mecha10.json
65pub fn generate_robot(config_path: &Path, output_path: &Path) -> Result<()> {
66    println!("šŸ¤– Mecha10 Robot Generator\n");
67
68    let generator = RobotGenerator::from_config_file(config_path)?;
69    generator.generate(output_path)?;
70
71    println!("\nāœ… Robot generation complete!");
72    println!("\nOutput: {}", output_path.display());
73
74    Ok(())
75}