summaryrefslogtreecommitdiff
path: root/platforms/tortuise-script-wasm/src/lib.rs
diff options
context:
space:
mode:
authorMica White <botahamec@outlook.com>2026-10-26 10:52:04 -0400
committerMica White <botahamec@outlook.com>2026-10-26 10:58:46 -0400
commitec40f6e3acc7874b82709ab81b254c741529fdff (patch)
treee3dfdc315bd0c6f1d2efcf442c2cfb3317d6810f /platforms/tortuise-script-wasm/src/lib.rs
parente3c5839159903658a667f789963f20a31567b25c (diff)
Finish engineHEADmain
Diffstat (limited to 'platforms/tortuise-script-wasm/src/lib.rs')
-rw-r--r--platforms/tortuise-script-wasm/src/lib.rs239
1 files changed, 239 insertions, 0 deletions
diff --git a/platforms/tortuise-script-wasm/src/lib.rs b/platforms/tortuise-script-wasm/src/lib.rs
new file mode 100644
index 0000000..6394b8f
--- /dev/null
+++ b/platforms/tortuise-script-wasm/src/lib.rs
@@ -0,0 +1,239 @@
+#![no_std]
+
+use core::marker::PhantomData;
+
+use alloc::vec::Vec;
+use serde::Serialize;
+
+extern crate alloc;
+
+pub mod allocator;
+pub mod buffer;
+pub mod entity;
+pub mod input;
+pub mod log;
+pub mod process;
+pub mod random;
+pub mod scene;
+pub mod script;
+pub mod state;
+pub mod storage;
+pub mod time;
+
+#[derive(Clone, Copy)]
+#[repr(transparent)]
+pub struct ScriptContext<'a>(u64, PhantomData<&'a ()>);
+
+pub struct TortuiseScript {
+ pub start: fn(cx: ScriptContext),
+ pub update: fn(cx: ScriptContext),
+ pub end: fn(cx: ScriptContext),
+}
+
+#[derive(Debug, Default, Clone)]
+pub struct TortuiseScene {
+ pub scripts: &'static [&'static str],
+}
+
+fn default_script(_cx: ScriptContext) {}
+
+impl Default for TortuiseScript {
+ fn default() -> Self {
+ Self {
+ start: default_script,
+ update: default_script,
+ end: default_script,
+ }
+ }
+}
+
+impl TortuiseScript {
+ pub const fn empty() -> Self {
+ Self {
+ start: default_script,
+ update: default_script,
+ end: default_script,
+ }
+ }
+}
+
+#[doc(hidden)]
+pub fn to_vec<T: Serialize>(val: &T) -> &'static [u8] {
+ Vec::leak(messagepack_serde::to_vec(val).unwrap())
+}
+
+#[doc(hidden)]
+pub type Lazy<T> = spin::LazyLock<T>;
+
+#[macro_export]
+macro_rules! game {
+ {
+ name: $name: literal,
+ author: $author: literal,
+ tld: $tld: literal,
+ first_scene: $first_scene: literal,
+ scenes: { $($scene_name: literal => $scene: expr),* },
+ scripts: { $($script_name: literal => $script: expr),* }
+ } => {
+ use alloc::boxed::Box;
+
+ #[derive(Debug, Clone, serde::Serialize)]
+ struct GameManifest {
+ name: Box<str>,
+ author: Box<str>,
+ tld: Box<str>,
+ first_scene: Box<str>,
+ scene: Box<[ManifestScene]>,
+ script: Box<[Box<str>]>,
+ }
+
+ #[derive(Debug, Clone, serde::Serialize)]
+ struct ManifestScene {
+ name: Box<str>,
+ scripts: Box<[Box<str>]>,
+ }
+
+ #[global_allocator]
+ static ALLOCATOR: $crate::allocator::TalcAllocator =
+ $crate::allocator::TalcAllocator::new();
+
+ static SCRIPTS: phf::Map<&'static str, $crate::TortuiseScript> = phf::phf_map! {
+ $($script_name => $script,)*
+ };
+
+ static MANIFEST: $crate::Lazy<&'static [u8]> = $crate::Lazy::new(|| {
+ fn slice_to_boxed_slice(names: &[&str]) -> Box<[Box<str>]> {
+ names.iter().cloned().map(Into::into).collect()
+ }
+
+ let manifest = GameManifest {
+ name: $name.into(),
+ author: $author.into(),
+ tld: $tld.into(),
+ first_scene: $first_scene.into(),
+ script: slice_to_boxed_slice([$($script_name,)*].as_slice()),
+ scene: Box::from([$(ManifestScene {
+ name: $scene_name.into(),
+ scripts: slice_to_boxed_slice($scene.scripts),
+ },)*].as_slice())
+ };
+
+ $crate::to_vec(&manifest)
+ });
+
+ #[unsafe(no_mangle)]
+ extern "C" fn manifest_addr() -> *const u8 {
+ MANIFEST.as_ptr()
+ }
+
+ #[unsafe(no_mangle)]
+ extern "C" fn manifest_len() -> usize {
+ MANIFEST.len()
+ }
+
+ #[unsafe(no_mangle)]
+ extern "C" fn start_script(cx: $crate::ScriptContext) {
+ let _ = $crate::log::TortuiseLogger::init();
+ let Some(script) = SCRIPTS.get(&*cx.current_script_name()) else { return };
+ (script.start)(cx);
+ }
+
+ #[unsafe(no_mangle)]
+ extern "C" fn update_script(cx: $crate::ScriptContext) {
+ let _ = $crate::log::TortuiseLogger::init();
+ let Some(script) = SCRIPTS.get(&*cx.current_script_name()) else { return };
+ (script.update)(cx);
+ }
+
+ #[unsafe(no_mangle)]
+ extern "C" fn end_script(cx: $crate::ScriptContext) {
+ let _ = $crate::log::TortuiseLogger::init();
+ let Some(script) = SCRIPTS.get(&*cx.current_script_name()) else { return };
+ (script.end)(cx);
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! patch {
+ {
+ scenes: { $($scene_name: literal => $scene: expr),* },
+ scripts: { $($script_name: literal => $script: expr),* }
+ } => {
+ use alloc::boxed::Box;
+
+ #[derive(Debug, Clone, serde::Serialize)]
+ struct GameManifestPatch {
+ new_scenes: Box<[ManifestScene]>,
+ new_scripts: Box<[Box<str>]>,
+ patched_scenes: Box<[ScenePatch]>,
+ }
+
+ #[derive(Debug, Clone, serde::Serialize)]
+ struct ManifestScene {
+ name: Box<str>,
+ scripts: Box<[Box<str>]>,
+ }
+
+ #[derive(Debug, Clone, serde::Serialize)]
+ struct ScenePatch {
+ add_scripts: Box<[Box<str>]>,
+ remove_scripts: Box<[Box<str>]>,
+ }
+
+ #[global_allocator]
+ static ALLOCATOR: $crate::allocator::TalcAllocator =
+ $crate::allocator::TalcAllocator::new();
+
+ static SCRIPTS: phf::Map<&'static str, $crate::TortuiseScript> = phf::phf_map! {
+ $($script_name => $script,)*
+ };
+
+ static MANIFEST: $crate::Lazy<&'static [u8]> = $crate::Lazy::new(|| {
+ fn slice_to_boxed_slice(names: &[&str]) -> Box<[Box<str>]> {
+ names.iter().cloned().map(Into::into).collect()
+ }
+
+ let manifest = GameManifestPatch {
+ added_scripts: slice_to_boxed_slice([$($script_name,)*].as_slice()),
+ added_scenes: Box::from([$(ManifestScene {
+ name: $scene_name.into(),
+ scripts: slice_to_boxed_slice($scene.scripts),
+ },)*].as_slice())
+ };
+
+ $crate::to_vec(&manifest)
+ });
+
+ #[unsafe(no_mangle)]
+ extern "C" fn manifest_addr() -> *const u8 {
+ MANIFEST.as_ptrhttps://botahamec.dev/cgit/shake/plain/shake()
+ }
+
+ #[unsafe(no_mangle)]
+ extern "C" fn manifest_len() -> usize {
+ MANIFEST.len()
+ }
+
+ #[unsafe(no_mangle)]
+ extern "C" fn start_script(cx: $crate::ScriptContext) {
+ let _ = $crate::log::TortuiseLogger::init();
+ let Some(script) = SCRIPTS.get(&*cx.current_script_name()) else { return };
+ (script.start)(cx);
+ }
+
+ #[unsafe(no_mangle)]
+ extern "C" fn update_script(cx: $crate::ScriptContext) {
+ let _ = $crate::log::TortuiseLogger::init();
+ let Some(script) = SCRIPTS.get(&*cx.current_script_name()) else { return };
+ (script.update)(cx);
+ }
+
+ #[unsafe(no_mangle)]
+ extern "C" fn end_script(cx: $crate::ScriptContext) {
+ let _ = $crate::log::TortuiseLogger::init();
+ let Some(script) = SCRIPTS.get(&*cx.current_script_name()) else { return };
+ (script.end)(cx);
+ }
+ };
+}