#![allow(dead_code)]
use crate::paths;
pub mod catalog;
pub mod generator;
pub mod lister;
pub mod profile;
pub mod robot_generator;
pub mod runner;
pub mod scene;
pub mod selector;
pub mod validator;
pub use catalog::EnvironmentCatalog;
#[allow(unused_imports)]
pub use lister::list_environments;
pub use profile::RobotProfile;
pub use robot_generator::RobotGenerator;
#[allow(unused_imports)]
pub use runner::run_simulation;
pub use selector::EnvironmentSelector;
#[allow(unused_imports)]
pub use validator::{validate_catalog, validate_config};
use anyhow::Result;
use std::path::Path;
use std::process::Command;
fn validate_godot_installation() -> Result<()> {
let godot_paths = if cfg!(target_os = "macos") {
vec![
"/Applications/Godot.app/Contents/MacOS/Godot",
"/usr/local/bin/godot",
"/opt/homebrew/bin/godot",
]
} else if cfg!(target_os = "linux") {
vec!["/usr/bin/godot", "/usr/local/bin/godot", "/snap/bin/godot"]
} else {
vec!["godot.exe", "C:\\Program Files\\Godot\\godot.exe"]
};
let mut found = false;
let mut godot_version = String::new();
let mut godot_path = String::new();
if let Ok(output) = Command::new("godot").arg("--version").output() {
if output.status.success() {
found = true;
godot_version = String::from_utf8_lossy(&output.stdout).trim().to_string();
godot_path = "godot (in PATH)".to_string();
}
}
if !found {
for path in &godot_paths {
if std::path::Path::new(path).exists() {
if let Ok(output) = Command::new(path).arg("--version").output() {
if output.status.success() {
found = true;
godot_version = String::from_utf8_lossy(&output.stdout).trim().to_string();
godot_path = path.to_string();
break;
}
}
}
}
}
if !found {
anyhow::bail!(
"❌ Godot not found\n\n\
Godot 4.x is required to generate and run simulations.\n\n\
Installation instructions:\n\
• macOS: brew install godot or download from https://godotengine.org/download/macos\n\
• Linux: sudo apt install godot or download from https://godotengine.org/download/linux\n\
• Windows: Download from https://godotengine.org/download/windows\n\n\
After installation, ensure 'godot' is in your PATH or installed to a standard location."
);
}
if !godot_version.starts_with("4.") {
println!("⚠️ Warning: Godot {} detected at {}", godot_version, godot_path);
println!(" mecha10 is designed for Godot 4.x. Some features may not work correctly.");
println!();
} else {
println!("✓ Godot {} detected at {}", godot_version, godot_path);
println!();
}
Ok(())
}
pub fn generate_simulation(config_path: &Path, max_envs: usize, min_score: i32) -> Result<()> {
println!("🤖 Mecha10 Simulation Generator\n");
validate_godot_installation()?;
let profile = RobotProfile::from_config_file(config_path)?;
println!("📋 Robot Configuration:");
println!(" Platform: {}", profile.platform);
println!(" Sensors: {}", profile.sensors.join(", "));
println!(
" Task Nodes: {}",
profile
.task_nodes
.iter()
.map(|n| n.name.as_str())
.collect::<Vec<_>>()
.join(", ")
);
println!();
println!("🤖 Step 1/3: Generating robot scene...");
let robot_output = std::path::PathBuf::from(paths::project::SIMULATION_GODOT_DIR).join("robot.tscn");
let robot_generator = RobotGenerator::from_config_file(config_path)?;
robot_generator.generate(&robot_output)?;
println!(" ✓ Generated: {}", robot_output.display());
println!();
println!("🎯 Step 2/3: Selecting environments...");
let selector = EnvironmentSelector::new()?;
let matches = selector.select_environments(&profile, max_envs)?;
let filtered_matches: Vec<_> = matches.into_iter().filter(|m| m.score >= min_score).collect();
if filtered_matches.is_empty() {
println!("❌ No matching environments found (min score: {})", min_score);
println!("\nTry:");
println!(" - Lowering --min-score");
println!(" - Adding more sensors");
return Ok(());
}
println!(" Available environments:");
for env_match in &filtered_matches {
println!(" • {} (score: {})", env_match.environment.name, env_match.score);
}
println!();
println!("✅ Step 3/3: Validating environment catalog...");
let catalog_path = std::path::PathBuf::from(paths::framework::ROBOT_TASKS_CATALOG);
let _catalog = EnvironmentCatalog::load(&catalog_path)?;
let base_path = std::path::PathBuf::from(paths::framework::ROBOT_TASKS_DIR);
let mut available_count = 0;
for env_match in &filtered_matches {
let env_path = base_path.join(&env_match.environment.path);
if env_path.exists() {
available_count += 1;
println!(" ✓ {} (ready)", env_match.environment.id);
} else {
println!(" ❌ {} (not implemented)", env_match.environment.id);
}
}
println!();
println!("✅ Generation complete!\n");
println!("📊 Summary:");
println!(" Robot scene: {}", robot_output.display());
println!(
" Available environments: {}/{}",
available_count,
filtered_matches.len()
);
println!();
if available_count > 0 {
let best_env = &filtered_matches[0].environment;
println!("🚀 Next steps:");
println!();
println!(" Run simulation:");
println!(
" mecha10 sim run --robot rover-robot --env {} --headless",
best_env.id
);
println!();
println!(" List all environments:");
println!(" mecha10 sim list-envs");
println!();
println!(" Open in Godot:");
println!(
" godot --path packages/simulation/godot-project -- --env={} --robot=rover-robot",
best_env.id
);
println!();
}
Ok(())
}
pub fn generate_robot(config_path: &Path, output_path: &Path) -> Result<()> {
println!("🤖 Mecha10 Robot Generator\n");
let generator = RobotGenerator::from_config_file(config_path)?;
generator.generate(output_path)?;
println!("\n✅ Robot generation complete!");
println!("\nOutput: {}", output_path.display());
println!("\nNext steps:");
println!(" 1. Open in Godot: godot {}", output_path.display());
println!(" 2. Test with environment: godot --headless --robot=<name> --env=corridor_navigation");
Ok(())
}