Blacksite/crates/game/src/launch.rs
Rbanh 0553a85220
Some checks are pending
CI / Format, lint, test, build (push) Waiting to run
Build production-ready editor authoring workflows
2026-07-11 12:41:04 -04:00

110 lines
3.5 KiB
Rust

//! Shared native launch configuration for the game and in-process editor.
use std::path::{Path, PathBuf};
use bevy::app::PluginGroupBuilder;
use bevy::asset::AssetPlugin;
use bevy::log::{LogPlugin, DEFAULT_FILTER};
use bevy::prelude::*;
use bevy::window::{CompositeAlphaMode, PresentMode, WindowMode, WindowPlugin};
/// Runtime switch for the HDR camera pass.
///
/// Set to `0`, `false`, `off`, or `no` to force the game/editor cameras through
/// the SDR path when debugging mixed HDR/SDR compositor issues.
pub const HDR_ENV_VAR: &str = "BEVY_FPS_HDR";
/// Locates the workspace `assets/` folder when the binary lives under `target/`.
pub fn resolve_assets_directory() -> String {
if let Some(path) = find_assets_directory(std::env::current_dir().ok()) {
return path;
}
if let Ok(exe) = std::env::current_exe() {
let mut dir = exe.parent().map(Path::to_path_buf);
while let Some(current) = dir {
if let Some(path) = find_assets_directory(Some(current.clone())) {
return path;
}
dir = current.parent().map(Path::to_path_buf);
}
}
"assets".into()
}
fn find_assets_directory(start: Option<PathBuf>) -> Option<String> {
let start = start?;
let assets = start.join("assets");
assets
.is_dir()
.then(|| assets.to_string_lossy().replace('\\', "/"))
}
pub fn default_plugins(title: impl Into<String>) -> PluginGroupBuilder {
DefaultPlugins
.set(LogPlugin {
// Blacksite intentionally replaces Bevy's `.scn.ron` loader with a
// schema-aware loader. Keep the expected registration warning out
// of normal startup logs; RUST_LOG still overrides this filter.
filter: format!("{DEFAULT_FILTER}bevy_asset::server::loaders=error"),
..default()
})
.set(WindowPlugin {
primary_window: Some(primary_window(title)),
..default()
})
.set(AssetPlugin {
file_path: resolve_assets_directory(),
..default()
})
}
pub fn primary_window(title: impl Into<String>) -> Window {
Window {
title: title.into(),
name: Some("bevy-fps-foundation".into()),
present_mode: PresentMode::AutoVsync,
mode: WindowMode::Windowed,
transparent: false,
// Force an opaque surface. On Wayland/Hyprland the default `Auto` mode
// can select an alpha-respecting surface, which may composite the whole
// window as transparent on SDR outputs in mixed HDR/SDR setups.
composite_alpha_mode: CompositeAlphaMode::Opaque,
..default()
}
}
pub fn hdr_enabled_from_env() -> bool {
std::env::var(HDR_ENV_VAR)
.map(|value| {
!matches!(
value.trim().to_ascii_lowercase().as_str(),
"0" | "false" | "off" | "no"
)
})
.unwrap_or(true)
}
#[cfg(test)]
mod tests {
use super::{primary_window, resolve_assets_directory};
use bevy::window::CompositeAlphaMode;
#[test]
fn primary_window_is_opaque() {
let window = primary_window("test");
assert!(!window.transparent);
assert_eq!(window.composite_alpha_mode, CompositeAlphaMode::Opaque);
}
#[test]
fn resolve_assets_directory_finds_workspace_assets() {
let cwd = std::env::current_dir().expect("cwd");
let expected = cwd.join("assets");
if !expected.is_dir() {
return;
}
assert_eq!(resolve_assets_directory(), expected.to_string_lossy());
}
}