summaryrefslogtreecommitdiff
path: root/src/main.rs
blob: ade657e66c82037c541e87d96168cc5abd24f5e9 (plain)
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<Path>,
	script_type: ScriptType,
	hash: Option<String>,
}

#[derive(Debug, Clone, Deserialize)]
struct ConfigSprite {
	texture: String,
	x: f32,
	y: f32,
	z: f32,
}

#[derive(Debug, Clone, Deserialize)]
struct ConfigTexture {
	size: usize,
	path: Box<Path>,
}

#[derive(Debug, Clone, Deserialize)]
struct Scene {
	initial_sprites: HashMap<String, ConfigSprite>,
	initial_scripts: Vec<String>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Config {
	alligator_version: usize,
	scenes: HashMap<String, Scene>,
	textures: HashMap<String, ConfigTexture>,
	scripts: HashMap<String, ConfigScript>,
	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(),
	})
}