use std::collections::HashMap; use std::fs::File; use std::io::Read; use std::num::NonZeroU32; use std::path::Path; use alligator_scripts::ScriptManager; use alligator_sprites::SpriteManager; use alligator_sys::{Renderer, RendererConfig, Window, WindowConfig, WindowEvent}; use serde::Deserialize; use sha3::{Digest, Sha3_256}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] enum ScriptType { Wasm, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] enum ConfigWindowMode { Windowed, BorderlessFullscreen, } #[derive(Debug, Clone, Deserialize)] struct ConfigScript { path: Box, script_type: ScriptType, hash: Option, } #[derive(Debug, Clone, Deserialize)] struct ConfigSprite { texture: String, x: f32, y: f32, z: f32, } #[derive(Debug, Clone, Deserialize)] struct ConfigTexture { size: usize, path: Box, } #[derive(Debug, Clone, Deserialize)] struct Scene { initial_sprites: HashMap, initial_scripts: Vec, } #[derive(Debug, Clone, Deserialize)] pub struct Config { alligator_version: usize, scenes: HashMap, textures: HashMap, scripts: HashMap, default_scene: String, sprite_manager_capacity: u32, default_window_width: NonZeroU32, default_window_height: NonZeroU32, default_window_mode: ConfigWindowMode, window_title: String, vsync: bool, } fn sprite_manager(config: &Config) -> SpriteManager { SpriteManager::with_capacity(config.sprite_manager_capacity as usize) } fn script_manager(config: &Config) -> ScriptManager { let mut scripts = ScriptManager::new(); for (key, script) in config.scripts.iter() { let path = script.path.clone(); let trusted = if let Some(hash) = &script.hash { let mut bytes = Vec::new(); let mut msg = File::open(&path).unwrap(); msg.read_to_end(&mut bytes).unwrap(); let mut hasher = Sha3_256::new(); hasher.update(bytes); let result = hasher.finalize(); hash.as_bytes() == &result[..] } else { false }; scripts .add_wasm_script(key.clone().into_boxed_str(), path, trusted) .unwrap(); } scripts } fn window(config: &Config) -> Window { let config = WindowConfig { title: config.window_title.clone(), default_width: config.default_window_width.get(), default_height: config.default_window_height.get(), default_x: 100, default_y: 100, borderless_fullscreen: config.default_window_mode == ConfigWindowMode::BorderlessFullscreen, visible: false, }; Window::new(config) } fn renderer(config: &Config, window: &Window) -> Renderer { let config = RendererConfig { width: config.default_window_width.get(), height: config.default_window_height.get(), instance_capacity: config.sprite_manager_capacity, fullscreen: false, vsync: config.vsync, }; Renderer::new(window, config) } fn main() { std::env::set_current_dir(std::env::current_exe().unwrap().parent().unwrap()).unwrap(); let config = File::open("game.json").unwrap(); let config: Config = serde_json::from_reader(config).unwrap(); let sprites = sprite_manager(&config); let scripts = script_manager(&config); let mut window = window(&config); window.wait_for_resume(); let mut renderer = renderer(&config, &window); window.set_visible(true); window.run(move |window, event| match event { Some(WindowEvent::RedrawRequest) => { renderer.render_frame(); } Some(WindowEvent::CloseRequest) => { std::process::exit(0); } Some(_) => (), None => window.request_redraw(), }) }