1use crate::context_registry::scene::{SceneId, SceneManager};
4use crate::core::error::{GoudError, GoudResult};
5use crate::ecs::{Component, Entity, World};
6
7#[cfg(feature = "native")]
8use crate::ecs::InputManager;
9#[cfg(feature = "native")]
10use crate::libs::graphics::backend::opengl::OpenGLBackend;
11#[cfg(feature = "native")]
12use crate::libs::graphics::renderer3d::Renderer3D;
13#[cfg(feature = "native")]
14use crate::libs::platform::PlatformBackend;
15#[cfg(feature = "native")]
16use crate::rendering::sprite_batch::SpriteBatch;
17
18use crate::core::providers::ProviderRegistry;
19use crate::sdk::debug_overlay::{DebugOverlay, FpsStats};
20use crate::sdk::engine_config::EngineConfig;
21use crate::sdk::entity_builder::EntityBuilder;
22use crate::sdk::game_config::{GameConfig, GameContext};
23
24pub struct GoudGame {
39 pub(crate) scene_manager: SceneManager,
41
42 pub(crate) config: GameConfig,
44
45 pub(crate) context: GameContext,
47
48 pub(crate) initialized: bool,
50
51 pub(crate) debug_overlay: DebugOverlay,
53
54 pub(crate) providers: ProviderRegistry,
56
57 #[cfg(feature = "native")]
62 pub(crate) platform: Option<Box<dyn PlatformBackend>>,
63
64 #[cfg(feature = "native")]
66 pub(crate) render_backend: Option<OpenGLBackend>,
67
68 #[cfg(feature = "native")]
70 pub(crate) input_manager: InputManager,
71
72 #[cfg(feature = "native")]
74 pub(crate) sprite_batch: Option<SpriteBatch<OpenGLBackend>>,
75
76 #[cfg(feature = "native")]
78 pub(crate) asset_server: Option<crate::assets::AssetServer>,
79
80 #[cfg(feature = "native")]
82 pub(crate) renderer_3d: Option<Renderer3D>,
83
84 #[cfg(feature = "native")]
86 pub(crate) immediate_state: Option<crate::sdk::rendering::ImmediateRenderState>,
87}
88
89impl GoudGame {
90 pub fn new(config: GameConfig) -> GoudResult<Self> {
96 let window_size = (config.width, config.height);
97 let mut debug_overlay = DebugOverlay::new(config.fps_update_interval);
98 debug_overlay.set_enabled(config.show_fps_overlay);
99 Ok(Self {
100 scene_manager: SceneManager::new(),
101 config,
102 context: GameContext::new(window_size),
103 initialized: false,
104 debug_overlay,
105 providers: ProviderRegistry::default(),
106 #[cfg(feature = "native")]
107 platform: None,
108 #[cfg(feature = "native")]
109 render_backend: None,
110 #[cfg(feature = "native")]
111 input_manager: InputManager::default(),
112 #[cfg(feature = "native")]
113 sprite_batch: None,
114 #[cfg(feature = "native")]
115 asset_server: None,
116 #[cfg(feature = "native")]
117 renderer_3d: None,
118 #[cfg(feature = "native")]
119 immediate_state: None,
120 })
121 }
122
123 pub fn default_game() -> GoudResult<Self> {
125 Self::new(GameConfig::default())
126 }
127
128 #[cfg(feature = "native")]
137 pub fn with_platform(config: GameConfig) -> GoudResult<Self> {
138 use crate::libs::platform::glfw_platform::GlfwPlatform;
139 use crate::libs::platform::WindowConfig;
140
141 let window_config = WindowConfig {
142 width: config.width,
143 height: config.height,
144 title: config.title.clone(),
145 vsync: config.vsync,
146 resizable: config.resizable,
147 };
148
149 let platform = GlfwPlatform::new(&window_config)?;
150 let window_size = (config.width, config.height);
151 let mut debug_overlay = DebugOverlay::new(config.fps_update_interval);
152 debug_overlay.set_enabled(config.show_fps_overlay);
153
154 Ok(Self {
155 scene_manager: SceneManager::new(),
156 config,
157 context: GameContext::new(window_size),
158 initialized: false,
159 debug_overlay,
160 providers: ProviderRegistry::default(),
161 platform: Some(Box::new(platform)),
162 render_backend: None,
163 input_manager: InputManager::default(),
164 sprite_batch: None,
165 asset_server: None,
166 renderer_3d: None,
167 immediate_state: None,
168 })
169 }
170
171 #[inline]
177 pub fn world(&self) -> &World {
178 self.scene_manager
179 .get_scene(self.scene_manager.default_scene())
180 .expect("default scene must exist")
181 }
182
183 #[inline]
185 pub fn world_mut(&mut self) -> &mut World {
186 let default = self.scene_manager.default_scene();
187 self.scene_manager
188 .get_scene_mut(default)
189 .expect("default scene must exist")
190 }
191
192 #[inline]
194 pub fn spawn(&mut self) -> EntityBuilder<'_> {
195 let default = self.scene_manager.default_scene();
196 let world = self
197 .scene_manager
198 .get_scene_mut(default)
199 .expect("default scene must exist");
200 EntityBuilder::new(world)
201 }
202
203 #[inline]
205 pub fn spawn_empty(&mut self) -> Entity {
206 self.world_mut().spawn_empty()
207 }
208
209 #[inline]
211 pub fn spawn_batch(&mut self, count: usize) -> Vec<Entity> {
212 self.world_mut().spawn_batch(count)
213 }
214
215 #[inline]
217 pub fn despawn(&mut self, entity: Entity) -> bool {
218 self.world_mut().despawn(entity)
219 }
220
221 #[inline]
223 pub fn get<T: Component>(&self, entity: Entity) -> Option<&T> {
224 self.world().get::<T>(entity)
225 }
226
227 #[inline]
229 pub fn get_mut<T: Component>(&mut self, entity: Entity) -> Option<&mut T> {
230 self.world_mut().get_mut::<T>(entity)
231 }
232
233 #[inline]
235 pub fn insert<T: Component>(&mut self, entity: Entity, component: T) {
236 self.world_mut().insert(entity, component);
237 }
238
239 #[inline]
241 pub fn remove<T: Component>(&mut self, entity: Entity) -> Option<T> {
242 self.world_mut().remove::<T>(entity)
243 }
244
245 #[inline]
247 pub fn has<T: Component>(&self, entity: Entity) -> bool {
248 self.world().has::<T>(entity)
249 }
250
251 #[inline]
253 pub fn entity_count(&self) -> usize {
254 self.world().entity_count()
255 }
256
257 #[inline]
259 pub fn is_alive(&self, entity: Entity) -> bool {
260 self.world().is_alive(entity)
261 }
262
263 pub fn create_scene(&mut self, name: &str) -> Result<SceneId, GoudError> {
269 self.scene_manager.create_scene(name)
270 }
271
272 pub fn destroy_scene(&mut self, id: SceneId) -> Result<(), GoudError> {
274 self.scene_manager.destroy_scene(id)
275 }
276
277 pub fn scene(&self, id: SceneId) -> Option<&World> {
279 self.scene_manager.get_scene(id)
280 }
281
282 pub fn scene_mut(&mut self, id: SceneId) -> Option<&mut World> {
284 self.scene_manager.get_scene_mut(id)
285 }
286
287 pub fn scene_by_name(&self, name: &str) -> Option<SceneId> {
289 self.scene_manager.get_scene_by_name(name)
290 }
291
292 pub fn set_scene_active(&mut self, id: SceneId, active: bool) -> Result<(), GoudError> {
294 self.scene_manager.set_active(id, active)
295 }
296
297 #[inline]
299 pub fn scene_manager(&self) -> &SceneManager {
300 &self.scene_manager
301 }
302
303 #[inline]
305 pub fn scene_manager_mut(&mut self) -> &mut SceneManager {
306 &mut self.scene_manager
307 }
308
309 #[inline]
311 pub fn config(&self) -> &GameConfig {
312 &self.config
313 }
314
315 #[inline]
317 pub fn title(&self) -> &str {
318 &self.config.title
319 }
320
321 #[inline]
323 pub fn window_size(&self) -> (u32, u32) {
324 (self.config.width, self.config.height)
325 }
326
327 pub fn run<F>(&mut self, mut update: F)
333 where
334 F: FnMut(&mut GameContext, &mut World),
335 {
336 self.initialized = true;
337
338 let frame_time = if self.config.target_fps > 0 {
340 1.0 / self.config.target_fps as f32
341 } else {
342 1.0 / 60.0 };
344
345 while self.context.is_running() {
348 self.context.update(frame_time);
349 self.debug_overlay.update(frame_time);
350
351 let active: Vec<SceneId> = self.scene_manager.active_scenes().to_vec();
353 for scene_id in active {
354 if let Some(world) = self.scene_manager.get_scene_mut(scene_id) {
355 update(&mut self.context, world);
356 }
357 }
358
359 if self.context.frame_count() > 10000 {
361 break;
362 }
363 }
364 }
365
366 pub fn update_frame<F>(&mut self, delta_time: f32, mut update: F)
368 where
369 F: FnMut(&mut GameContext, &mut World),
370 {
371 self.context.update(delta_time);
372 self.debug_overlay.update(delta_time);
373
374 let active: Vec<SceneId> = self.scene_manager.active_scenes().to_vec();
375 for scene_id in active {
376 if let Some(world) = self.scene_manager.get_scene_mut(scene_id) {
377 update(&mut self.context, world);
378 }
379 }
380 }
381
382 #[inline]
384 pub fn fps_stats(&self) -> FpsStats {
385 self.debug_overlay.stats()
386 }
387
388 #[inline]
390 pub fn set_fps_overlay_enabled(&mut self, enabled: bool) {
391 self.debug_overlay.set_enabled(enabled);
392 }
393
394 #[inline]
396 pub fn frame_count(&self) -> u64 {
397 self.context.frame_count()
398 }
399
400 #[inline]
402 pub fn total_time(&self) -> f32 {
403 self.context.total_time()
404 }
405
406 #[inline]
408 pub fn fps(&self) -> f32 {
409 self.context.fps()
410 }
411
412 #[inline]
414 pub fn is_initialized(&self) -> bool {
415 self.initialized
416 }
417
418 pub fn from_engine_config(config: EngineConfig) -> GoudResult<Self> {
420 let (game_config, providers) = config.build();
421 let mut game = Self::new(game_config)?;
422 game.providers = providers;
423 Ok(game)
424 }
425
426 #[cfg(feature = "native")]
428 pub fn from_engine_config_with_platform(config: EngineConfig) -> GoudResult<Self> {
429 let (game_config, providers) = config.build();
430 let mut game = Self::with_platform(game_config)?;
431 game.providers = providers;
432 Ok(game)
433 }
434
435 #[inline]
437 pub fn providers(&self) -> &ProviderRegistry {
438 &self.providers
439 }
440}
441
442impl Default for GoudGame {
443 fn default() -> Self {
444 Self::new(GameConfig::default()).expect("Failed to create default GoudGame")
445 }
446}
447
448impl std::fmt::Debug for GoudGame {
449 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
450 f.debug_struct("GoudGame")
451 .field("config", &self.config)
452 .field("entity_count", &self.entity_count())
453 .field("initialized", &self.initialized)
454 .finish()
455 }
456}