From ec40f6e3acc7874b82709ab81b254c741529fdff Mon Sep 17 00:00:00 2001 From: Mica White Date: Mon, 26 Oct 2026 10:52:04 -0400 Subject: Finish engine --- platforms/tortuise-script-wasm/src/entity.rs | 157 +++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 platforms/tortuise-script-wasm/src/entity.rs (limited to 'platforms/tortuise-script-wasm/src/entity.rs') diff --git a/platforms/tortuise-script-wasm/src/entity.rs b/platforms/tortuise-script-wasm/src/entity.rs new file mode 100644 index 0000000..e66e2fe --- /dev/null +++ b/platforms/tortuise-script-wasm/src/entity.rs @@ -0,0 +1,157 @@ +use core::{ + alloc::Layout, + ops::{Deref, DerefMut}, +}; + +use alloc::{ + alloc::{alloc, dealloc}, + borrow::Cow, + string::String, +}; +use serde::{Deserialize, Serialize}; +use spin::lock_api::{MappedRwLockWriteGuard, RwLock, RwLockWriteGuard}; + +use crate::ScriptContext; + +mod tortuise { + #[link(wasm_import_module = "tortuise")] + unsafe extern "C" { + pub unsafe fn entity_size(context: u64, name: *const u8, name_len: usize) -> usize; + pub unsafe fn load_entity(context: u64, name: *const u8, name_len: usize, offset: *mut u8); + pub unsafe fn save_entity( + context: u64, + name: *const u8, + name_len: usize, + offset: *const u8, + size: usize, + ); + } +} + +fn load_entity<'de, T: Deserialize<'de>>(context: u64, name: &str) -> Option { + unsafe { + let size = tortuise::entity_size(context, name.as_ptr(), name.len()); + let Ok(layout) = Layout::array::(size) else { + log::error!("Failed to create layout for size: {size}"); + panic!(); + }; + if layout.size() == 0 { + return None; + } + let ptr = alloc(layout); + tortuise::load_entity(context, name.as_ptr(), name.len(), ptr); + let data = core::slice::from_raw_parts(ptr, size); + let data = match messagepack_serde::from_slice(data) { + Ok(data) => data, + Err(e) => { + log::error!("Failed to parse entity: {e}"); + return None; + } + }; + dealloc(ptr, layout); + Some(data) + } +} + +fn save_entity(context: u64, name: &str, state: &T) { + unsafe { + let data = match messagepack_serde::to_vec(state) { + Ok(data) => data, + Err(e) => { + log::error!("Failed to save entity: {e}"); + panic!(); + } + }; + tortuise::save_entity( + context, + name.as_ptr(), + name.len(), + data.as_ptr(), + data.len(), + ); + } +} + +pub struct Entity { + name: Cow<'static, str>, + data: RwLock>, + default: fn(&ScriptContext) -> T, +} + +pub struct EntityRef<'entity, T> { + data: MappedRwLockWriteGuard<'entity, T>, +} + +pub struct EntityMut<'entity, T: Serialize> { + context: u64, + name: &'entity str, + data: MappedRwLockWriteGuard<'entity, T>, +} + +impl<'de, T: Serialize + Deserialize<'de>> Entity { + pub const fn new(name: &'static str, default: fn(&ScriptContext) -> T) -> Self { + Self { + name: Cow::Borrowed(name), + data: RwLock::new(None), + default, + } + } + + pub const fn from_string(name: String, default: fn(&ScriptContext) -> T) -> Self { + Self { + name: Cow::Owned(name), + data: RwLock::new(None), + default, + } + } + + pub fn get(&self, context: &ScriptContext) -> EntityRef<'_, T> { + let data = RwLockWriteGuard::map(self.data.write(), |data| { + data.get_or_insert_with(|| { + load_entity(context.0, &self.name).unwrap_or_else(|| (self.default)(context)) + }) + }); + EntityRef { data } + } + + pub fn get_mut(&self, context: &ScriptContext) -> EntityMut<'_, T> { + let data = RwLockWriteGuard::map(self.data.write(), |data| { + data.get_or_insert_with(|| { + load_entity(context.0, &self.name).unwrap_or_else(|| (self.default)(context)) + }) + }); + EntityMut { + context: context.0, + name: &self.name, + data, + } + } +} + +impl Deref for EntityRef<'_, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.data + } +} + +impl Deref for EntityMut<'_, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.data + } +} + +impl DerefMut for EntityMut<'_, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.data + } +} + +impl Drop for EntityMut<'_, T> { + fn drop(&mut self) { + save_entity(self.context, self.name, &*self.data); + } +} -- cgit v1.3.1