From a9977e7fabeb06a6f21824cc4a41b36ea39f6799 Mon Sep 17 00:00:00 2001 From: Mica White Date: Tue, 7 Jul 2026 22:45:22 -0400 Subject: Full host environment --- src/script.rs | 249 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 200 insertions(+), 49 deletions(-) (limited to 'src/script.rs') diff --git a/src/script.rs b/src/script.rs index 4429b9c..93f6f99 100644 --- a/src/script.rs +++ b/src/script.rs @@ -3,9 +3,10 @@ use std::path::Path; use rustc_hash::FxHashMap; use crate::{ - buffer::Buffer, + buffer::{Buffer, Cell}, file::{FileManager, GameManifest}, input::InputManager, + scene::{preload_scene, switch_scenes}, time::TimeContext, }; @@ -19,7 +20,7 @@ pub struct ScriptManager<'a> { pub struct WasmRunner { pub engine: wasmi::Engine, - pub linker: wasmi::Linker<&'static mut ScriptContext<'static>>, + pub linker: wasmi::Linker>, } pub struct ScriptContext<'a> { @@ -27,6 +28,34 @@ pub struct ScriptContext<'a> { pub buffer: &'a mut Buffer, pub input: &'a InputManager, pub time: &'a TimeContext, + pub operation_queue: Vec, +} + +pub struct FullScriptContext<'a> { + pub script_id: usize, + pub manifest: &'a GameManifest, + pub buffer: &'a Buffer, + pub input: &'a InputManager, + pub time: &'a TimeContext, + pub scripts: &'a ScriptManager<'a>, + pub files: &'a FileManager, + pub wasm_runner: &'a WasmRunner, + pub operation_queue: &'a mut Vec, +} + +pub enum Operation { + AddCell(Cell), + PreloadScene(usize), + SwitchScene(usize), + PreloadScript(usize), + UnloadScript(usize), + ActivateScript(usize), + DeactivateScript(usize), + UpdateState { + script_id: usize, + new_state: Box<[u8]>, + }, + Exit, } type StaticScriptFunction = Option, &mut Box<[u8]>)>; @@ -34,11 +63,13 @@ type StaticScriptFunction = Option, &mut Box<[u8]>)>; #[derive(Debug, Clone)] pub enum ScriptDeclaration { Static { + name: Box, start: StaticScriptFunction, update: StaticScriptFunction, end: StaticScriptFunction, }, Wasm { + name: Box, path: Box, }, } @@ -65,8 +96,8 @@ impl WasmRunner { let engine = wasmi::Engine::default(); let linker = unsafe { std::mem::transmute::< - wasmi::Linker<&mut ScriptContext<'_>>, - wasmi::Linker<&mut ScriptContext<'_>>, + wasmi::Linker>, + wasmi::Linker>, >(wasm::linker(&engine).unwrap()) }; Self { engine, linker } @@ -76,9 +107,14 @@ impl WasmRunner { wasmi::Module::new(&self.engine, data) } + #[allow(clippy::too_many_arguments)] pub fn run_function( &self, + script_id: usize, module: &wasmi::Module, + scripts: &ScriptManager, + files: &FileManager, + wasm_runner: &WasmRunner, context: &mut ScriptContext<'_>, function_name: &str, ) -> Result<(), wasmi::Error> { @@ -87,7 +123,19 @@ impl WasmRunner { let mut store = { puffin::profile_scope!("create store"); wasmi::Store::new(&self.engine, unsafe { - std::mem::transmute::<&mut ScriptContext<'_>, &mut ScriptContext<'_>>(context) + std::mem::transmute::, FullScriptContext<'_>>( + FullScriptContext { + script_id, + manifest: context.manifest, + buffer: context.buffer, + input: context.input, + time: context.time, + scripts, + files, + wasm_runner, + operation_queue: &mut context.operation_queue, + }, + ) }) }; let instance = { @@ -116,6 +164,25 @@ impl<'a> ScriptManager<'a> { } } + pub fn script_id_by_name(&self, needle: &str) -> Option { + for (i, script) in self.scripts.iter().enumerate() { + match script { + ScriptDeclaration::Static { name, .. } => { + if &**name == needle { + return Some(i); + } + } + ScriptDeclaration::Wasm { name, .. } => { + if &**name == needle { + return Some(i); + } + } + } + } + + None + } + pub fn preload_script( &self, script_id: usize, @@ -125,15 +192,17 @@ impl<'a> ScriptManager<'a> { let script = &self.scripts[script_id]; match script { ScriptDeclaration::Static { .. } => (), - ScriptDeclaration::Wasm { path } => files.start_loading_file(path, &wasm_runner.engine), + ScriptDeclaration::Wasm { path, .. } => { + files.start_loading_file(path, &wasm_runner.engine) + } } } - pub fn is_script_loaded(&self, script_id: usize, files: &mut FileManager) -> bool { + pub fn is_script_loaded(&self, script_id: usize, files: &FileManager) -> bool { let script = &self.scripts[script_id]; match script { ScriptDeclaration::Static { .. } => true, - ScriptDeclaration::Wasm { path } => files.is_file_loaded(path), + ScriptDeclaration::Wasm { path, .. } => files.is_file_loaded(path), } } @@ -141,8 +210,69 @@ impl<'a> ScriptManager<'a> { let script = &self.scripts[script_id]; match script { ScriptDeclaration::Static { .. } => (), - ScriptDeclaration::Wasm { path } => files.unload_file(path), + ScriptDeclaration::Wasm { path, .. } => files.unload_file(path), + } + } + + pub fn handle_queue( + &mut self, + context: &mut ScriptContext<'_>, + wasm_runner: &WasmRunner, + files: &mut FileManager, + ) { + for operation in &context.operation_queue { + match operation { + Operation::AddCell(cell) => context.buffer.cells.push(*cell), + Operation::PreloadScene(id) => { + preload_scene(&context.manifest.scenes, self, files, wasm_runner, *id) + } + Operation::SwitchScene(id) => switch_scenes( + self, + &mut ScriptContext { + manifest: context.manifest, + buffer: context.buffer, + input: context.input, + time: context.time, + operation_queue: Vec::new(), + }, + files, + wasm_runner, + *id, + ), + Operation::PreloadScript(id) => self.preload_script(*id, files, wasm_runner), + Operation::UnloadScript(id) => self.unload_script(*id, files), + Operation::ActivateScript(id) => self.activate_script( + *id, + &mut ScriptContext { + manifest: context.manifest, + buffer: context.buffer, + input: context.input, + time: context.time, + operation_queue: Vec::new(), + }, + wasm_runner, + files, + ), + Operation::DeactivateScript(id) => self.deactivate_script( + *id, + &mut ScriptContext { + manifest: context.manifest, + buffer: context.buffer, + input: context.input, + time: context.time, + operation_queue: Vec::new(), + }, + wasm_runner, + files, + ), + Operation::UpdateState { + script_id, + new_state, + } => *get_script_state(&mut self.script_states, *script_id) = new_state.clone(), + Operation::Exit => context.exit(), + } } + context.operation_queue.clear(); } pub fn activate_script( @@ -164,15 +294,22 @@ impl<'a> ScriptManager<'a> { ) }); } - ScriptDeclaration::Wasm { path } => { - let module = files - .load_file(path.clone(), &wasm_runner.engine) - .unwrap() - .unwrap_wasm_module(); - wasm_runner.run_function(module, context, "start"); + ScriptDeclaration::Wasm { path, .. } => { + files.load_file(path.clone(), &wasm_runner.engine).unwrap(); + let module = files.get_cached_file(path).unwrap().unwrap_wasm_module(); + wasm_runner.run_function( + script_id, + module, + self, + files, + wasm_runner, + context, + "start", + ); } } self.active_scripts.push(script_id); + self.handle_queue(context, wasm_runner, files); } pub fn deactivate_script( @@ -182,34 +319,41 @@ impl<'a> ScriptManager<'a> { wasm_runner: &WasmRunner, files: &mut FileManager, ) { - 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 { path } => { - let module = files - .load_file(path.clone(), &wasm_runner.engine) - .unwrap() - .unwrap_wasm_module(); - wasm_runner.run_function(module, context, "end"); - } - }; - - true - } else { - false - } - }); + for script_id in self + .active_scripts + .iter() + .cloned() + .filter(|element| *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 { path, .. } => { + files.load_file(path.clone(), &wasm_runner.engine).unwrap(); + let module = files.get_cached_file(path).unwrap().unwrap_wasm_module(); + wasm_runner.run_function( + script_id, + module, + self, + files, + wasm_runner, + context, + "end", + ); + } + }; + } + self.active_scripts.retain(|element| *element != script_id); + self.handle_queue(context, wasm_runner, files); } pub fn run_scripts( @@ -232,17 +376,24 @@ impl<'a> ScriptManager<'a> { ) } } - ScriptDeclaration::Wasm { path } => { + ScriptDeclaration::Wasm { path, .. } => { let module = { puffin::profile_scope!("load module"); - files - .load_file(path.clone(), &wasm_runner.engine) - .unwrap() - .unwrap_wasm_module() + files.load_file(path.clone(), &wasm_runner.engine).unwrap(); + files.get_cached_file(path).unwrap().unwrap_wasm_module() }; - wasm_runner.run_function(module, context, "update"); + wasm_runner.run_function( + *script_id, + module, + self, + files, + wasm_runner, + context, + "update", + ); } } } + self.handle_queue(context, wasm_runner, files); } } -- cgit v1.2.3