pub mod app;
pub mod game_state;
pub mod input;
pub mod renderer;
pub mod scene;
pub mod time;
pub mod window;
pub mod play;
pub mod authority;
pub mod mirror;
pub mod prelude;
pub mod presentation;
pub mod runtime_ui;
pub mod sync;
pub struct RuntimeConfig {
pub title: String,
pub width: u32,
pub height: u32,
pub vsync: bool,
pub msaa_samples: u32,
pub authority_mode: AuthorityMode,
pub asset_root: std::path::PathBuf,
pub pack_file: Option<String>,
pub lock_file: Option<String>,
pub db_host: Option<String>,
pub db_name: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AuthorityMode {
Local,
Remote,
}
impl Default for RuntimeConfig {
fn default() -> Self {
Self {
title: "Dreamwell".into(),
width: 1920,
height: 1080,
vsync: true,
msaa_samples: 1,
authority_mode: AuthorityMode::Local,
asset_root: "assets".into(),
pack_file: None,
lock_file: None,
db_host: None,
db_name: "dreamwell".into(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RuntimePhase {
PollInput,
PollAuthority,
StageAuthorityEvents,
ApplyAuthorityEvents,
UpdateMirror,
UpdatePresentation,
AssembleFrame,
Render,
DrainSync,
}
impl RuntimePhase {
pub const ALL: &'static [RuntimePhase] = &[
Self::PollInput,
Self::PollAuthority,
Self::StageAuthorityEvents,
Self::ApplyAuthorityEvents,
Self::UpdateMirror,
Self::UpdatePresentation,
Self::AssembleFrame,
Self::Render,
Self::DrainSync,
];
pub fn label(self) -> &'static str {
match self {
Self::PollInput => "poll_input",
Self::PollAuthority => "poll_authority",
Self::StageAuthorityEvents => "stage_authority",
Self::ApplyAuthorityEvents => "apply_authority",
Self::UpdateMirror => "update_mirror",
Self::UpdatePresentation => "update_presentation",
Self::AssembleFrame => "assemble_frame",
Self::Render => "render",
Self::DrainSync => "drain_sync",
}
}
}
pub struct Runtime {
config: RuntimeConfig,
}
impl Runtime {
pub fn new(config: RuntimeConfig) -> Result<Self, Box<dyn std::error::Error>> {
Ok(Self { config })
}
#[cfg(not(target_arch = "wasm32"))]
pub fn run(self) -> Result<(), Box<dyn std::error::Error>> {
#[cfg(target_os = "windows")]
let event_loop = {
use winit::platform::windows::EventLoopBuilderExtWindows;
winit::event_loop::EventLoop::builder().with_any_thread(true).build()?
};
#[cfg(not(target_os = "windows"))]
let event_loop = winit::event_loop::EventLoop::new()?;
let mut runtime_app = app::RuntimeApp::new(RuntimeConfig {
title: self.config.title.clone(),
width: self.config.width,
height: self.config.height,
authority_mode: self.config.authority_mode,
pack_file: self.config.pack_file.clone(),
lock_file: self.config.lock_file.clone(),
db_host: self.config.db_host.clone(),
db_name: self.config.db_name.clone(),
..Default::default()
})
.map_err(|e| format!("{e:?}"))?;
if let Some(ref pack_path) = self.config.pack_file {
match std::fs::read_to_string(pack_path) {
Ok(json) => {
if let Err(e) = runtime_app.mount_pack(&json) {
log::warn!("Failed to mount pack {}: {}", pack_path, e);
}
}
Err(e) => log::warn!("Failed to read pack file {}: {}", pack_path, e),
}
}
event_loop.run_app(&mut runtime_app)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn runtime_config_default() {
let c = RuntimeConfig::default();
assert_eq!(c.title, "Dreamwell");
assert_eq!(c.width, 1280);
assert_eq!(c.height, 720);
assert!(c.vsync);
assert_eq!(c.msaa_samples, 4);
assert_eq!(c.authority_mode, AuthorityMode::Local);
assert!(c.pack_file.is_none());
assert!(c.db_host.is_none());
assert_eq!(c.db_name, "dreamwell");
}
#[test]
fn runtime_phase_count() {
assert_eq!(RuntimePhase::ALL.len(), 9);
}
#[test]
fn runtime_phase_labels() {
assert_eq!(RuntimePhase::PollInput.label(), "poll_input");
assert_eq!(RuntimePhase::Render.label(), "render");
assert_eq!(RuntimePhase::DrainSync.label(), "drain_sync");
}
#[test]
fn authority_mode_default_local() {
assert_eq!(RuntimeConfig::default().authority_mode, AuthorityMode::Local);
}
}