use std::path::Path; use rustc_hash::FxHashMap; use wasmer::{Imports, Instance, Module, Store}; use crate::{buffer::Buffer, file::FileManager, input::InputManager}; pub struct ScriptManager<'a> { scripts: &'a [ScriptDeclaration], pub active_scripts: Vec, script_states: FxHashMap>, } pub struct ScriptContext<'a> { pub buffer: &'a mut Buffer, pub input: &'a InputManager, } type StaticScriptFunction = Option)>; pub enum ScriptDeclaration { Static { start: StaticScriptFunction, update: StaticScriptFunction, end: StaticScriptFunction, }, Wasm { path: Box, }, } pub struct WasmScript { pub module: Module, pub instance: Instance, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Profile { Debug, Release, } impl<'a> ScriptContext<'a> { pub fn exit(&mut self) -> ! { let _ = self.buffer.finish(); std::process::exit(0); } } fn get_script_state(states: &mut FxHashMap>, script_id: usize) -> &mut Box<[u8]> { states.entry(script_id).or_insert(Box::from([])) } impl<'a> ScriptManager<'a> { pub fn new(scripts: &'a [ScriptDeclaration]) -> Self { Self { scripts, active_scripts: Vec::new(), script_states: FxHashMap::default(), } } pub fn activate_script( &mut self, script_id: usize, context: &mut ScriptContext<'_>, files: &mut FileManager, ) { let Some(script_declaration) = self.scripts.get(script_id) else { unreachable!("The active script does not exist"); }; match script_declaration { ScriptDeclaration::Static { start, .. } => { start.map(|s| { s( context, get_script_state(&mut self.script_states, script_id), ) }); } ScriptDeclaration::Wasm { path } => { todo!("wasm scripts") // let module = files.load_file(path.clone()).unwrap().unwrap_wasm_module(); // let mut store = wasmi::Store::new(&files.wasm_compiler, context); // let instance = self // .linker // .instantiate_and_start(&mut store, &module) // .unwrap(); } } self.active_scripts.push(script_id); } pub fn deactivate_script(&mut self, script_id: usize, context: &mut ScriptContext<'_>) { self.active_scripts.retain(|element| { if *element != script_id { let Some(script) = self.scripts.get(script_id) else { unreachable!("The active script does not exist"); }; match script { ScriptDeclaration::Static { end, .. } => { end.map(|s| { s( context, get_script_state(&mut self.script_states, script_id), ); }); } ScriptDeclaration::Wasm { .. } => todo!("wasm scripts"), }; true } else { false } }); } pub fn run_scripts(&mut self, context: &mut ScriptContext<'_>) { puffin::profile_function!(); for script_id in &self.active_scripts { let Some(script) = self.scripts.get(*script_id) else { unreachable!("The active script does not exist"); }; match *script { ScriptDeclaration::Static { update, .. } => { if let Some(s) = update { s( context, get_script_state(&mut self.script_states, *script_id), ) } } ScriptDeclaration::Wasm { .. } => todo!("wasm scripts"), } } } pub fn reset_script(&mut self, script_id: usize, context: &mut ScriptContext<'_>) { let script = &self.scripts[script_id]; match script { ScriptDeclaration::Static { start, end, .. } => { if let Some(s) = start { s( context, get_script_state(&mut self.script_states, script_id), ) } if let Some(s) = end { s( context, get_script_state(&mut self.script_states, script_id), ) } } ScriptDeclaration::Wasm { .. } => todo!("wasm scripts"), } } } impl WasmScript { fn call_function(&self, name: &str, profile: Profile, store: &mut Store, imports: &Imports) { let instance = match profile { Profile::Debug => &Instance::new(store, &self.module, imports).unwrap(), Profile::Release => &self.instance, }; let function = instance.exports.get_function(name).unwrap(); function.call(store, &[]).unwrap(); } }