Blacksite/crates/game/src/lib.rs
Rbanh 2054fa2558
Some checks are pending
CI / Format, lint, test, build (push) Waiting to run
Advance M0 scene and rendering foundations
2026-06-06 03:50:03 -04:00

192 lines
6.6 KiB
Rust

//! Runtime game crate: FPS player, rendering, and starter world.
#![allow(clippy::type_complexity)]
pub mod editor_ext;
pub mod launch;
pub mod player {
//! Player types re-exported from the stable sim crate.
pub use sim::{CameraSensitivity, PlayerCamera};
}
pub mod rendering {
//! Rendering helpers re-exported from the hot-reloadable implementation.
pub use game_hot::{
apply_camera_render_profile, apply_project_camera_fx, camera_auto_exposure_active,
clear_viewport_camera_stack, effective_gi_path_for_camera, effective_viewport_gi_path,
effective_viewport_render_stack, has_local_shadow_lights, hdr_enabled_profile,
patch_camera_effects, resolve_viewport_camera_owner, strip_project_camera_fx,
sync_optional_rendering_fx, sync_viewport_camera_stack, world_has_local_shadow_lights,
FullscreenEffectsPlugin, SolariRaytracingSceneStats, SolariRenderingPlugin,
ViewportCameraOwner, ViewportFxSnapshot, ViewportStackApply, HDR_ENV_VAR,
};
}
use bevy::prelude::*;
use settings::ProjectSettingsPlugin;
use sim::SimPlugin;
pub use sim::{GameInputEnabled, GameInputFocused, SimEnabled};
/// When set, the in-process editor owns [`apply_project_camera_fx`] on a single camera.
#[derive(Resource, Debug, Clone, Copy, Default)]
pub struct GameRenderBootstrap {
pub defer_player_camera_fx: bool,
}
#[cfg(not(feature = "hot-reload"))]
mod systems {
pub use game_hot::{
apply_ambient_light, apply_player_intent, grab_cursor, move_and_slide,
setup_project_camera_effects, spawn_level, spawn_player, spawn_sun,
sync_player_physics_position, sync_project_sun_visibility,
sync_scene_directional_shadow_cascades, tag_player_camera, toggle_cursor_grab,
update_camera_pitch, update_eye_height, update_local_player_intent,
};
}
#[cfg(feature = "hot-reload")]
mod systems {
pub use crate::hot::{
apply_ambient_light, apply_player_intent, grab_cursor, move_and_slide,
setup_project_camera_effects, spawn_level, spawn_player, spawn_sun,
sync_player_physics_position, sync_project_sun_visibility,
sync_scene_directional_shadow_cascades, tag_player_camera, toggle_cursor_grab,
update_camera_pitch, update_eye_height, update_local_player_intent,
};
}
#[cfg(feature = "hot-reload")]
#[hot_lib_reloader::hot_module(dylib = "game_hot", lib_dir = concat!(env!("CARGO_MANIFEST_DIR"), "/../../target/debug"))]
mod hot {
use avian3d::prelude::*;
use bevy::input::mouse::AccumulatedMouseMotion;
use bevy::light::CascadeShadowConfig;
use bevy::pbr::ScatteringMedium;
use bevy::prelude::*;
use bevy::time::Fixed;
use bevy::window::{CursorOptions, PrimaryWindow};
use game_hot::SolariRaytracingSceneStats;
use protocol::PlayerInputIntent;
use settings::{
ActiveCameraRenderProfile, ProjectRenderCamera, ProjectSettings, RenderingCapabilities,
SimTuning,
};
use shared::{InspectorOrder, LevelObject, LightDesc, ProjectSun};
use sim::{
CameraSensitivity, Crouching, GameInputEnabled, GameInputFocused, Grounded, JumpState,
Player, PlayerCamera, PlayerVelocity, PlayerYawSensitivity,
};
hot_functions_from_file!("crates/game_hot/src/sim_systems.rs"); // move_and_slide, sync_player_physics_position, apply_player_intent
hot_functions_from_file!("crates/game_hot/src/player/spawn.rs");
hot_functions_from_file!("crates/game_hot/src/player/input.rs");
hot_functions_from_file!("crates/game_hot/src/player/camera.rs");
hot_functions_from_file!("crates/game_hot/src/rendering/camera_fx.rs");
hot_functions_from_file!("crates/game_hot/src/world/mod.rs");
hot_functions_from_file!("crates/game_hot/src/world/level.rs");
hot_functions_from_file!("crates/game_hot/src/world/lighting.rs");
#[lib_change_subscription]
pub fn subscribe() -> hot_lib_reloader::LibReloadObserver {}
}
#[cfg(feature = "hot-reload")]
pub fn hot_reload_subscribe() -> hot_lib_reloader::LibReloadObserver {
hot::subscribe()
}
fn sim_enabled(enabled: Res<SimEnabled>) -> bool {
enabled.0
}
fn game_input_enabled(enabled: Res<GameInputEnabled>) -> bool {
enabled.0
}
fn register_game_systems(app: &mut App, defer_player_camera_fx: bool) {
app.add_systems(
FixedUpdate,
(
systems::apply_player_intent,
systems::move_and_slide,
systems::sync_player_physics_position,
)
.chain()
.run_if(sim_enabled),
)
.add_systems(Startup, systems::spawn_player)
.add_systems(
Startup,
systems::grab_cursor
.after(systems::spawn_player)
.run_if(game_input_enabled),
)
.add_systems(
Update,
(
systems::toggle_cursor_grab,
systems::update_local_player_intent,
systems::update_camera_pitch,
systems::update_eye_height,
)
.chain()
.run_if(game_input_enabled),
)
.add_systems(
Startup,
(
systems::apply_ambient_light,
systems::spawn_sun,
systems::spawn_level,
)
.chain(),
);
app.add_systems(
Update,
(
systems::sync_project_sun_visibility,
systems::sync_scene_directional_shadow_cascades,
),
);
if !defer_player_camera_fx {
app.add_systems(
PostStartup,
(
systems::tag_player_camera,
systems::setup_project_camera_effects,
)
.chain(),
);
}
}
/// Runtime game systems and content, without Bevy's platform/window plugins.
pub struct GamePlugin;
impl Plugin for GamePlugin {
fn build(&self, app: &mut App) {
let defer_player_camera_fx = app
.world()
.get_resource::<GameRenderBootstrap>()
.is_some_and(|bootstrap| bootstrap.defer_player_camera_fx);
app.register_type::<GameInputEnabled>()
.init_resource::<GameInputEnabled>()
.init_resource::<GameInputFocused>()
.add_plugins((ProjectSettingsPlugin, SimPlugin, bevy_ufbx::FbxPlugin))
.add_plugins(game_hot::SolariRenderingPlugin)
.add_plugins(game_hot::AutoExposureRenderingPlugin)
.add_plugins(game_hot::FullscreenEffectsPlugin)
.insert_resource(ClearColor(Color::srgb(0.0, 0.0, 0.0)));
register_game_systems(app, defer_player_camera_fx);
}
}
/// Called by the editor after swapping the hot dylib.
pub fn on_hot_reload(world: &mut World) {
game_hot::on_hot_reload(world);
}