sim_core/
lib.rs

1//! Core simulation types, plugins, and systems for CortenForge Bevy apps.
2//!
3//! This crate provides:
4//! - Run mode management (`SimRunMode`: Sim, Datagen, Inference).
5//! - Camera systems (flycam, instrument POV, camera toggling).
6//! - Autopilot and controls abstractions.
7//! - Capture recording and metadata generation.
8//! - Articulated segment/spring types for entity rigging.
9//!
10//! Designed to be detector-agnostic: detector wiring happens in higher-level binaries or
11//! the `vision_runtime` crate.
12
13use bevy::prelude::*;
14use bevy_rapier3d::prelude::{NoUserData, RapierPhysicsPlugin};
15use std::path::PathBuf;
16
17/// High-level run mode for the sim runtime (detector-free).
18#[derive(Resource, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
19pub enum SimRunMode {
20    #[default]
21    Sim,
22    Datagen,
23    Inference,
24}
25
26/// Common configuration for the sim runtime.
27#[derive(Resource, Debug, Clone)]
28pub struct SimConfig {
29    pub mode: SimRunMode,
30    pub headless: bool,
31    pub capture_output_root: PathBuf,
32    pub prune_empty: bool,
33    pub prune_output_root: Option<PathBuf>,
34    pub max_frames: Option<u32>,
35    pub capture_interval_secs: Option<f32>,
36}
37
38impl Default for SimConfig {
39    fn default() -> Self {
40        Self {
41            mode: SimRunMode::Sim,
42            headless: false,
43            capture_output_root: PathBuf::from("assets/datasets/captures"),
44            prune_empty: false,
45            prune_output_root: None,
46            max_frames: None,
47            capture_interval_secs: None,
48        }
49    }
50}
51
52/// System sets for the core sim scheduling.
53#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
54pub enum ModeSet {
55    Common,
56    SimDatagen,
57    Inference,
58}
59
60/// Core sim plugin: registers mode-based system sets and injects default config.
61pub struct SimPlugin;
62
63impl Plugin for SimPlugin {
64    fn build(&self, app: &mut App) {
65        app.insert_resource(SimConfig::default()).configure_sets(
66            Update,
67            (ModeSet::Common, ModeSet::SimDatagen, ModeSet::Inference),
68        );
69    }
70}
71
72pub mod prelude {
73    pub use super::{ModeSet, SimConfig, SimPlugin, SimRunMode};
74    pub use crate::articulated_types::{ArticulatedSegment, SegmentSpring};
75    pub use crate::autopilot_types::{AutoDir, AutoDrive, AutoStage, DataRun, DatagenInit};
76    pub use crate::camera::{
77        camera_controller, pov_toggle_system, setup_camera, ActiveCameraMode, Flycam,
78        InstrumentPovCamera, UiOverlayCamera,
79    };
80    pub use crate::controls::ControlConfig;
81    pub use crate::hooks::{AutopilotHook, ControlsHook, SimHooks};
82    pub use crate::recorder::{
83        AutoRecordTimer, BasicMeta, Config as RecorderConfig, MetaProvider, MetadataProvider,
84        Motion as RecorderMotion, RecorderWorldSnapshot, Sink as RecorderSink,
85        State as RecorderState,
86    };
87    pub use crate::runtime::{register_runtime_systems, SimRuntimePlugin};
88}
89
90/// Build a base Bevy `App` with sim mode sets and config. Detector wiring is intentionally omitted.
91pub fn build_app(sim_config: SimConfig) -> App {
92    let mut app = App::new();
93    let headless = sim_config.headless;
94    app.insert_resource(sim_config)
95        .add_plugins(DefaultPlugins.set(WindowPlugin {
96            primary_window: Some(Window {
97                visible: !headless,
98                fit_canvas_to_parent: true,
99                ..default()
100            }),
101            ..default()
102        }))
103        .add_plugins(RapierPhysicsPlugin::<NoUserData>::default())
104        .configure_sets(
105            Update,
106            (ModeSet::Common, ModeSet::SimDatagen, ModeSet::Inference),
107        );
108    app
109}
110
111pub mod articulated_types;
112pub mod autopilot_types;
113pub mod camera;
114pub mod controls;
115pub mod hooks;
116pub mod recorder;
117pub mod runtime;