diff options
Diffstat (limited to 'src/script.rs')
| -rw-r--r-- | src/script.rs | 230 |
1 files changed, 99 insertions, 131 deletions
diff --git a/src/script.rs b/src/script.rs index a2cb76d..306ea49 100644 --- a/src/script.rs +++ b/src/script.rs @@ -1,12 +1,14 @@ -use std::{path::Path, sync::Arc}; +use std::{path::Path, sync::Arc, time::Duration}; use rustc_hash::FxHashMap; +use serde::{Deserialize, Serialize}; use crate::{ buffer::{Buffer, Cell}, - file::{FileManager, GameManifest}, + file::FileManager, input::InputManager, - scene::{preload_scene, switch_scenes}, + manifest::{DeserializedGameManifest, GameManifest, GameManifestPatch}, + scene::switch_scenes, script::wasm::WasmModule, storage::StorageManager, time::TimeContext, @@ -30,6 +32,7 @@ pub struct WasmRunner { } pub struct ScriptContext<'a> { + pub framerate_limit: &'a mut Option<Duration>, pub manifest: &'a GameManifest, pub buffer: &'a mut Buffer, pub input: &'a InputManager, @@ -53,10 +56,8 @@ pub struct FullScriptContext<'a> { pub enum Operation { AddCell(Cell), - PreloadScene(usize), + SetFrameLimit(Option<Duration>), SwitchScene(usize), - PreloadScript(usize), - UnloadScript(usize), ActivateScript(usize), DeactivateScript(usize), UpdateState { @@ -70,23 +71,24 @@ pub enum Operation { UpdateStorage { new_save: Box<[u8]>, }, + UpdateConfig { + new_save: Box<[u8]>, + }, Exit, } -type StaticScriptFunction = Option<fn(&mut ScriptContext<'_>, &mut Box<[u8]>)>; +pub type StaticScriptFunction = Option<Arc<dyn Fn(FullScriptContext<'_>) + Send + Sync>>; -#[derive(Debug, Clone)] +#[derive(Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "kebab-case")] pub enum ScriptDeclaration { + #[serde(skip)] Static { name: Box<str>, start: StaticScriptFunction, update: StaticScriptFunction, end: StaticScriptFunction, }, - Lua { - name: Box<str>, - path: Box<Path>, - }, Wasm { name: Box<str>, path: Box<Path>, @@ -100,10 +102,6 @@ impl<'a> ScriptContext<'a> { } } -fn get_script_state(states: &mut FxHashMap<usize, Box<[u8]>>, script_id: usize) -> &mut Box<[u8]> { - states.entry(script_id).or_insert(Box::from([])) -} - impl Default for WasmRunner { fn default() -> Self { Self::new() @@ -133,11 +131,54 @@ impl WasmRunner { Ok(WasmModule { instance }) } + pub fn manifest( + &self, + path: Box<Path>, + module: &WasmModule, + ) -> Result<GameManifest, tinywasm::Error> { + let mut store = self.store.lock(); + let offset = module + .instance + .func::<(), u32>(&store, "manifest_addr")? + .call(&mut store, ())?; + let length = module + .instance + .func::<(), u32>(&store, "manifest_len")? + .call(&mut store, ())?; + let manifest = + module + .instance + .memory("memory")? + .read_vec(&store, offset as usize, length as usize)?; + let manifest = + messagepack_serde::from_slice::<DeserializedGameManifest>(&manifest).unwrap(); + Ok(GameManifest::from_wasm(path, manifest)) + } + + pub fn patch(&self, module: &WasmModule) -> Result<GameManifestPatch, tinywasm::Error> { + let mut store = self.store.lock(); + let offset = module + .instance + .func::<(), u32>(&store, "manifest_addr")? + .call(&mut store, ())?; + let length = module + .instance + .func::<(), u32>(&store, "manifest_len")? + .call(&mut store, ())?; + let manifest = + module + .instance + .memory("memory")? + .read_vec(&store, offset as usize, length as usize)?; + let manifest = messagepack_serde::from_slice::<GameManifestPatch>(&manifest).unwrap(); + Ok(manifest) + } + #[expect(clippy::too_many_arguments)] pub fn run_function( &self, script_id: usize, - module: &mut WasmModule, + module: &WasmModule, scripts: &ScriptManager, files: Box<[Box<Path>]>, wasm_runner: &WasmRunner, @@ -171,6 +212,15 @@ impl WasmRunner { } } +impl ScriptDeclaration { + pub fn name(&self) -> &str { + match self { + Self::Static { name, .. } => name, + Self::Wasm { name, .. } => name, + } + } +} + impl<'a> ScriptManager<'a> { pub fn new(scripts: &'a [ScriptDeclaration]) -> Self { Self { @@ -189,11 +239,6 @@ impl<'a> ScriptManager<'a> { return Some(i); } } - ScriptDeclaration::Lua { name, .. } => { - if &**name == needle { - return Some(i); - } - } ScriptDeclaration::Wasm { name, .. } => { if &**name == needle { return Some(i); @@ -205,38 +250,6 @@ impl<'a> ScriptManager<'a> { None } - pub fn preload_script( - &self, - script_id: usize, - files: &mut FileManager, - wasm_runner: &WasmRunner, - ) { - let script = &self.scripts[script_id]; - match script { - ScriptDeclaration::Static { .. } => (), - ScriptDeclaration::Lua { path, .. } => files.start_loading_file(path, wasm_runner), - ScriptDeclaration::Wasm { path, .. } => files.start_loading_file(path, wasm_runner), - } - } - - pub fn is_script_loaded(&self, script_id: usize, loaded_files: &[Box<Path>]) -> bool { - let script = &self.scripts[script_id]; - match script { - ScriptDeclaration::Static { .. } => true, - ScriptDeclaration::Lua { path, .. } => loaded_files.contains(path), - ScriptDeclaration::Wasm { path, .. } => loaded_files.contains(path), - } - } - - pub fn unload_script(&self, script_id: usize, files: &mut FileManager) { - let script = &self.scripts[script_id]; - match script { - ScriptDeclaration::Static { .. } => (), - ScriptDeclaration::Lua { path, .. } => files.unload_file(path), - ScriptDeclaration::Wasm { path, .. } => files.unload_file(path), - } - } - pub fn handle_queue( &mut self, context: &mut ScriptContext<'_>, @@ -246,12 +259,11 @@ impl<'a> ScriptManager<'a> { 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::SetFrameLimit(duration) => *context.framerate_limit = *duration, Operation::SwitchScene(id) => switch_scenes( self, &mut ScriptContext { + framerate_limit: context.framerate_limit, manifest: context.manifest, buffer: context.buffer, input: context.input, @@ -263,8 +275,6 @@ impl<'a> ScriptManager<'a> { 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 { @@ -274,6 +284,7 @@ impl<'a> ScriptManager<'a> { time: context.time, storage: context.storage, operation_queue: Vec::new(), + framerate_limit: context.framerate_limit, }, wasm_runner, files, @@ -287,6 +298,7 @@ impl<'a> ScriptManager<'a> { time: context.time, storage: context.storage, operation_queue: Vec::new(), + framerate_limit: context.framerate_limit, }, wasm_runner, files, @@ -301,7 +313,10 @@ impl<'a> ScriptManager<'a> { self.entities.insert(name.clone(), new_state.clone()); } Operation::UpdateStorage { new_save } => { - context.storage.background_save(new_save.clone()); + context.storage.background_save_data(new_save.clone()); + } + Operation::UpdateConfig { new_save } => { + context.storage.background_save_config(new_save.clone()); } Operation::Exit => context.exit(), } @@ -321,20 +336,9 @@ impl<'a> ScriptManager<'a> { }; match script_declaration { ScriptDeclaration::Static { start, .. } => { - start.map(|s| { - s( - context, - get_script_state(&mut self.script_states, script_id), - ) - }); - } - ScriptDeclaration::Lua { path, .. } => { - files.load_file(path.clone(), wasm_runner).unwrap(); - let loaded_files = files.loaded_files(); - let module = files.get_cached_file_mut(path).unwrap().unwrap_lua_module(); - if let Err(e) = module.run_function( - "start", - FullScriptContext { + start.as_ref().inspect(|s| { + let loaded_files = files.loaded_files(); + s(FullScriptContext { script_id, manifest: context.manifest, buffer: context.buffer, @@ -345,18 +349,13 @@ impl<'a> ScriptManager<'a> { storage: context.storage, wasm_runner, operation_queue: &mut context.operation_queue, - }, - ) { - log::error!("{e}"); - } + }) + }); } ScriptDeclaration::Wasm { path, .. } => { - files.load_file(path.clone(), wasm_runner).unwrap(); + let module = files.load_file(path.clone(), wasm_runner); + let module = module.as_ref().as_ref().unwrap(); let loaded_files = files.loaded_files(); - let module = files - .get_cached_file_mut(path) - .unwrap() - .unwrap_wasm_module_mut(); if let Err(e) = wasm_runner.run_function( script_id, module, @@ -364,7 +363,7 @@ impl<'a> ScriptManager<'a> { loaded_files, wasm_runner, context, - "start", + "start_script", ) { log::error!("{e}"); } @@ -393,20 +392,9 @@ impl<'a> ScriptManager<'a> { self.script_states.remove(&script_id); match script { ScriptDeclaration::Static { end, .. } => { - end.map(|s| { - s( - context, - get_script_state(&mut self.script_states, script_id), - ); - }); - } - ScriptDeclaration::Lua { path, .. } => { - files.load_file(path.clone(), wasm_runner).unwrap(); - let loaded_files = files.loaded_files(); - let module = files.get_cached_file_mut(path).unwrap().unwrap_lua_module(); - if let Err(e) = module.run_function( - "end", - FullScriptContext { + end.as_ref().inspect(|s| { + let loaded_files = files.loaded_files(); + s(FullScriptContext { script_id, manifest: context.manifest, buffer: context.buffer, @@ -417,18 +405,13 @@ impl<'a> ScriptManager<'a> { storage: context.storage, wasm_runner, operation_queue: &mut context.operation_queue, - }, - ) { - log::error!("{e}"); - } + }); + }); } ScriptDeclaration::Wasm { path, .. } => { - files.load_file(path.clone(), wasm_runner).unwrap(); + let module = files.load_file(path.clone(), wasm_runner); + let module = module.as_ref().as_ref().unwrap(); let loaded_files = files.loaded_files(); - let module = files - .get_cached_file_mut(path) - .unwrap() - .unwrap_wasm_module_mut(); if let Err(e) = wasm_runner.run_function( script_id, module, @@ -436,7 +419,7 @@ impl<'a> ScriptManager<'a> { loaded_files, wasm_runner, context, - "end", + "end_script", ) { log::error!("{e}"); } @@ -459,21 +442,11 @@ impl<'a> ScriptManager<'a> { unreachable!("The active script does not exist"); }; match script { - ScriptDeclaration::Static { update, .. } => { + ScriptDeclaration::Static { name, update, .. } => { if let Some(s) = update { - s( - context, - get_script_state(&mut self.script_states, *script_id), - ) - } - } - ScriptDeclaration::Lua { path, .. } => { - files.load_file(path.clone(), wasm_runner).unwrap(); - let loaded_files = files.loaded_files(); - let module = files.get_cached_file_mut(path).unwrap().unwrap_lua_module(); - if let Err(e) = module.run_function( - "update", - FullScriptContext { + puffin::profile_scope!("run script", name); + let loaded_files = files.loaded_files(); + s(FullScriptContext { script_id: *script_id, manifest: context.manifest, buffer: context.buffer, @@ -484,18 +457,13 @@ impl<'a> ScriptManager<'a> { storage: context.storage, wasm_runner, operation_queue: &mut context.operation_queue, - }, - ) { - log::error!("{e}"); + }); } } ScriptDeclaration::Wasm { path, .. } => { - files.load_file(path.clone(), wasm_runner).unwrap(); + let module = files.load_file(path.clone(), wasm_runner); + let module = module.as_ref().as_ref().unwrap(); let loaded_files = files.loaded_files(); - let module = files - .get_cached_file_mut(path) - .unwrap() - .unwrap_wasm_module_mut(); if let Err(e) = wasm_runner.run_function( *script_id, module, @@ -503,7 +471,7 @@ impl<'a> ScriptManager<'a> { loaded_files, wasm_runner, context, - "update", + "update_script", ) { log::error!("Error while running scripts: {e}"); } |
