124 lines
4.2 KiB
Rust
124 lines
4.2 KiB
Rust
use bevy::prelude::*;
|
|
|
|
use crate::{
|
|
load_project_settings_with_source, save_project_settings_to_string, PhysicsSettings,
|
|
ProjectSettings, DEFAULT_PROJECT_PATH,
|
|
};
|
|
|
|
/// Runtime copy of physics tuning consumed by `sim` systems.
|
|
#[derive(Resource, Debug, Clone, Copy)]
|
|
pub struct SimTuning {
|
|
pub player_radius: f32,
|
|
pub player_length: f32,
|
|
pub eye_offset_stand: f32,
|
|
pub eye_offset_crouch: f32,
|
|
pub gravity: f32,
|
|
pub walk_speed: f32,
|
|
pub run_speed: f32,
|
|
pub crouch_speed: f32,
|
|
pub jump_speed: f32,
|
|
pub ground_accel: f32,
|
|
pub air_accel: f32,
|
|
pub ground_check_dist: f32,
|
|
pub skin: f32,
|
|
pub max_slide_iter: u32,
|
|
pub ground_normal_y: f32,
|
|
pub coyote_time: f32,
|
|
pub jump_buffer: f32,
|
|
}
|
|
|
|
impl SimTuning {
|
|
pub fn from_physics(physics: &PhysicsSettings) -> Self {
|
|
Self {
|
|
player_radius: physics.player_radius,
|
|
player_length: physics.player_length,
|
|
eye_offset_stand: physics.eye_offset_stand,
|
|
eye_offset_crouch: physics.eye_offset_crouch,
|
|
gravity: physics.gravity,
|
|
walk_speed: physics.walk_speed,
|
|
run_speed: physics.run_speed,
|
|
crouch_speed: physics.crouch_speed,
|
|
jump_speed: physics.jump_speed,
|
|
ground_accel: physics.ground_accel,
|
|
air_accel: physics.air_accel,
|
|
ground_check_dist: physics.ground_check_dist,
|
|
skin: physics.skin,
|
|
max_slide_iter: physics.max_slide_iter,
|
|
ground_normal_y: physics.ground_normal_y,
|
|
coyote_time: physics.coyote_time,
|
|
jump_buffer: physics.jump_buffer,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Tracks project settings file path and dirty state (editor persists via UI).
|
|
#[derive(Resource, Debug)]
|
|
pub struct ProjectSettingsIo {
|
|
pub path: String,
|
|
pub dirty: bool,
|
|
/// Exact source loaded or last saved by this process; collaboration guards hash it.
|
|
pub loaded_source: Option<String>,
|
|
}
|
|
|
|
impl Default for ProjectSettingsIo {
|
|
fn default() -> Self {
|
|
Self {
|
|
path: DEFAULT_PROJECT_PATH.into(),
|
|
dirty: false,
|
|
loaded_source: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Fired after project settings are saved or reloaded from disk.
|
|
#[derive(Message, Debug, Clone, Copy, Default)]
|
|
pub struct ProjectSettingsChanged;
|
|
|
|
pub struct ProjectSettingsPlugin;
|
|
|
|
impl Plugin for ProjectSettingsPlugin {
|
|
fn build(&self, app: &mut App) {
|
|
app.init_resource::<ProjectSettingsIo>()
|
|
.register_type::<ProjectSettings>()
|
|
.register_type::<crate::ProjectKind>()
|
|
.register_type::<crate::AudioSettings>()
|
|
.register_type::<crate::AudioBusSettings>()
|
|
.register_type::<crate::GiMode>()
|
|
.register_type::<crate::ExposureMode>()
|
|
.register_type::<crate::ActiveCameraRenderProfile>()
|
|
.register_type::<crate::EffectiveRenderStack>()
|
|
.register_type::<crate::RenderFallbackReason>()
|
|
.register_type::<crate::RenderingCapabilities>()
|
|
.add_message::<ProjectSettingsChanged>()
|
|
.add_systems(PreStartup, load_settings);
|
|
}
|
|
}
|
|
|
|
fn load_settings(mut commands: Commands, mut io: ResMut<ProjectSettingsIo>) {
|
|
let (settings, source) = load_project_settings_with_source(&io.path);
|
|
io.loaded_source = source;
|
|
let tuning = SimTuning::from_physics(&settings.physics);
|
|
commands.insert_resource(settings);
|
|
commands.insert_resource(tuning);
|
|
}
|
|
|
|
/// Refreshes [`SimTuning`] from the current [`ProjectSettings`] resource.
|
|
pub fn sync_sim_tuning(settings: &ProjectSettings, mut tuning: ResMut<SimTuning>) {
|
|
*tuning = SimTuning::from_physics(&settings.physics);
|
|
}
|
|
|
|
/// Low-level unconditional persistence for non-editor callers.
|
|
///
|
|
/// The editor uses its guarded authored-file publication path instead so external revisions cannot
|
|
/// be overwritten.
|
|
pub fn save_project_settings(
|
|
settings: &ProjectSettings,
|
|
io: &mut ProjectSettingsIo,
|
|
) -> Result<(), String> {
|
|
let text = save_project_settings_to_string(settings).map_err(|error| error.to_string())?;
|
|
std::fs::write(&io.path, &text).map_err(|error| error.to_string())?;
|
|
io.loaded_source = Some(text);
|
|
io.dirty = false;
|
|
Ok(())
|
|
}
|