summaryrefslogtreecommitdiff
path: root/src/script.rs
diff options
context:
space:
mode:
authorMica White <botahamec@outlook.com>2026-10-26 10:51:49 -0400
committerMica White <botahamec@outlook.com>2026-10-26 10:51:49 -0400
commit0c128e472b1b49e32c313874eaeccc8c5f1b1202 (patch)
tree2ce06455440e85ec3387f7348b7bd69bf2119634 /src/script.rs
parentc687e2aba30ca231b03288108b632f1bad464028 (diff)
Finish engineHEADmain
Diffstat (limited to 'src/script.rs')
-rw-r--r--src/script.rs230
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}");
}