1pub mod app;
13pub mod game_state;
14pub mod input;
15pub mod renderer;
16pub mod scene;
17pub mod time;
18pub mod window;
19
20pub mod play;
21
22pub mod authority;
24pub mod mirror;
25pub mod prelude;
26pub mod presentation;
27pub mod runtime_ui;
28pub mod sync;
29
30pub struct RuntimeConfig {
32 pub title: String,
34 pub width: u32,
36 pub height: u32,
38 pub vsync: bool,
40 pub msaa_samples: u32,
42 pub authority_mode: AuthorityMode,
44 pub asset_root: std::path::PathBuf,
46 pub pack_file: Option<String>,
48 pub lock_file: Option<String>,
50 pub db_host: Option<String>,
52 pub db_name: String,
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub enum AuthorityMode {
59 Local,
61 Remote,
63}
64
65impl Default for RuntimeConfig {
66 fn default() -> Self {
67 Self {
68 title: "Dreamwell".into(),
69 width: 1920,
70 height: 1080,
71 vsync: true,
72 msaa_samples: 1,
73 authority_mode: AuthorityMode::Local,
74 asset_root: "assets".into(),
75 pack_file: None,
76 lock_file: None,
77 db_host: None,
78 db_name: "dreamwell".into(),
79 }
80 }
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq)]
96pub enum RuntimePhase {
97 PollInput,
98 PollAuthority,
99 StageAuthorityEvents,
100 ApplyAuthorityEvents,
101 UpdateMirror,
102 UpdatePresentation,
103 AssembleFrame,
104 Render,
105 DrainSync,
106}
107
108impl RuntimePhase {
109 pub const ALL: &'static [RuntimePhase] = &[
111 Self::PollInput,
112 Self::PollAuthority,
113 Self::StageAuthorityEvents,
114 Self::ApplyAuthorityEvents,
115 Self::UpdateMirror,
116 Self::UpdatePresentation,
117 Self::AssembleFrame,
118 Self::Render,
119 Self::DrainSync,
120 ];
121
122 pub fn label(self) -> &'static str {
124 match self {
125 Self::PollInput => "poll_input",
126 Self::PollAuthority => "poll_authority",
127 Self::StageAuthorityEvents => "stage_authority",
128 Self::ApplyAuthorityEvents => "apply_authority",
129 Self::UpdateMirror => "update_mirror",
130 Self::UpdatePresentation => "update_presentation",
131 Self::AssembleFrame => "assemble_frame",
132 Self::Render => "render",
133 Self::DrainSync => "drain_sync",
134 }
135 }
136}
137
138pub struct Runtime {
140 config: RuntimeConfig,
141}
142
143impl Runtime {
144 pub fn new(config: RuntimeConfig) -> Result<Self, Box<dyn std::error::Error>> {
145 Ok(Self { config })
146 }
147
148 #[cfg(not(target_arch = "wasm32"))]
150 pub fn run(self) -> Result<(), Box<dyn std::error::Error>> {
151 #[cfg(target_os = "windows")]
154 let event_loop = {
155 use winit::platform::windows::EventLoopBuilderExtWindows;
156 winit::event_loop::EventLoop::builder().with_any_thread(true).build()?
157 };
158 #[cfg(not(target_os = "windows"))]
159 let event_loop = winit::event_loop::EventLoop::new()?;
160
161 let mut runtime_app = app::RuntimeApp::new(RuntimeConfig {
162 title: self.config.title.clone(),
163 width: self.config.width,
164 height: self.config.height,
165 authority_mode: self.config.authority_mode,
166 pack_file: self.config.pack_file.clone(),
167 lock_file: self.config.lock_file.clone(),
168 db_host: self.config.db_host.clone(),
169 db_name: self.config.db_name.clone(),
170 ..Default::default()
171 })
172 .map_err(|e| format!("{e:?}"))?;
173
174 if let Some(ref pack_path) = self.config.pack_file {
176 match std::fs::read_to_string(pack_path) {
177 Ok(json) => {
178 if let Err(e) = runtime_app.mount_pack(&json) {
179 log::warn!("Failed to mount pack {}: {}", pack_path, e);
180 }
181 }
182 Err(e) => log::warn!("Failed to read pack file {}: {}", pack_path, e),
183 }
184 }
185
186 event_loop.run_app(&mut runtime_app)?;
187 Ok(())
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194
195 #[test]
196 fn runtime_config_default() {
197 let c = RuntimeConfig::default();
198 assert_eq!(c.title, "Dreamwell");
199 assert_eq!(c.width, 1280);
200 assert_eq!(c.height, 720);
201 assert!(c.vsync);
202 assert_eq!(c.msaa_samples, 4);
203 assert_eq!(c.authority_mode, AuthorityMode::Local);
204 assert!(c.pack_file.is_none());
205 assert!(c.db_host.is_none());
206 assert_eq!(c.db_name, "dreamwell");
207 }
208
209 #[test]
210 fn runtime_phase_count() {
211 assert_eq!(RuntimePhase::ALL.len(), 9);
212 }
213
214 #[test]
215 fn runtime_phase_labels() {
216 assert_eq!(RuntimePhase::PollInput.label(), "poll_input");
217 assert_eq!(RuntimePhase::Render.label(), "render");
218 assert_eq!(RuntimePhase::DrainSync.label(), "drain_sync");
219 }
220
221 #[test]
222 fn authority_mode_default_local() {
223 assert_eq!(RuntimeConfig::default().authority_mode, AuthorityMode::Local);
224 }
225}