summaryrefslogtreecommitdiff
path: root/src/script.rs
diff options
context:
space:
mode:
authorMica White <botahamec@outlook.com>2026-07-07 22:45:22 -0400
committerMica White <botahamec@outlook.com>2026-07-07 22:45:22 -0400
commita9977e7fabeb06a6f21824cc4a41b36ea39f6799 (patch)
tree86b586fa8b8a312b2e4d2e5800260fc98430b91b /src/script.rs
parent07018cb37b278dbd73c864a662454f1cf9d33457 (diff)
Full host environment
Diffstat (limited to 'src/script.rs')
-rw-r--r--src/script.rs249
1 files changed, 200 insertions, 49 deletions
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<FullScriptContext<'static>>,
}
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<Operation>,
+}
+
+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<Operation>,
+}
+
+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<fn(&mut ScriptContext<'_>, &mut Box<[u8]>)>;
@@ -34,11 +63,13 @@ type StaticScriptFunction = Option<fn(&mut ScriptContext<'_>, &mut Box<[u8]>)>;
#[derive(Debug, Clone)]
pub enum ScriptDeclaration {
Static {
+ name: Box<str>,
start: StaticScriptFunction,
update: StaticScriptFunction,
end: StaticScriptFunction,
},
Wasm {
+ name: Box<str>,
path: Box<Path>,
},
}
@@ -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<FullScriptContext<'_>>,
+ wasmi::Linker<FullScriptContext<'_>>,
>(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<'_>>(
+ 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<usize> {
+ 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);
}
}