From 57539df4e76ee5a9adb521f5a69ccab9364dcba1 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Fri, 12 Apr 2024 02:05:10 -0400 Subject: [PATCH] PoC for spawning entities with components and querying them --- .gitmodules | 3 + Cargo.lock | 43 +++++++++ Cargo.toml | 1 + lyra-engine | 1 + src/main.rs | 146 ++++++++++++++++++++++++++--- witguest/src/bindings.rs | 192 ++++++++++++++++++++++++++++++++------- witguest/src/lib.rs | 62 +++++++++++-- witguest/wit/world.wit | 42 ++++++++- 8 files changed, 440 insertions(+), 50 deletions(-) create mode 100644 .gitmodules create mode 160000 lyra-engine diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..ff59b57 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lyra-engine"] + path = lyra-engine + url = git@git.seanomik.net:SeanOMik/lyra-engine.git diff --git a/Cargo.lock b/Cargo.lock index 5eec9f0..381e042 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,6 +67,12 @@ dependencies = [ "syn", ] +[[package]] +name = "atomic_refcell" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41e67cd8309bbd06cd603a9e693a784ac2e5d1e955f11286e355089fcab3047c" + [[package]] name = "autocfg" version = "1.2.0" @@ -655,6 +661,12 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "glam" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" + [[package]] name = "hashbrown" version = "0.13.2" @@ -854,6 +866,36 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "lyra-ecs" +version = "0.1.0" +dependencies = [ + "anyhow", + "atomic_refcell", + "lyra-ecs-derive", + "lyra-math", + "paste", + "rand", + "thiserror", + "tracing", +] + +[[package]] +name = "lyra-ecs-derive" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "lyra-math" +version = "0.1.0" +dependencies = [ + "glam", +] + [[package]] name = "mach" version = "0.3.2" @@ -2228,6 +2270,7 @@ name = "wittest" version = "0.1.0" dependencies = [ "async-trait", + "lyra-ecs", "tokio", "wasmtime", "wasmtime-wasi", diff --git a/Cargo.toml b/Cargo.toml index 22d7fe8..36e2b68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,3 +11,4 @@ async-trait = "0.1.80" tokio = { version = "1.37.0", features = ["full"] } wasmtime = "19.0.2" wasmtime-wasi = "19.0.2" +lyra-ecs = { path = "./lyra-engine/lyra-ecs" } \ No newline at end of file diff --git a/lyra-engine b/lyra-engine new file mode 160000 index 0000000..60ec62c --- /dev/null +++ b/lyra-engine @@ -0,0 +1 @@ +Subproject commit 60ec62c55828a4ea273a10e5614e7cc589b005cf diff --git a/src/main.rs b/src/main.rs index ce09bea..a08205b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,25 @@ +use std::alloc::Layout; +use std::any::TypeId; +use std::mem; +use std::ptr::NonNull; + use async_trait::async_trait; +use component::witguest::{ecs_world, math}; +use ecs::query::dynamic::QueryDynamicType; +use lyra_ecs::{Component, World}; + +use lyra_ecs as ecs; + +use lyra_engine::ecs::component::witguest::ecs_world::WasmTypeId; use wasmtime_wasi::WasiView; +#[allow(unused_imports)] +pub(crate) mod lyra_engine { + pub(crate) mod ecs { + pub use super::super::*; + } +} + wasmtime::component::bindgen!({ world: "example", path: "witguest/wit/world.wit", @@ -8,8 +27,50 @@ wasmtime::component::bindgen!({ async: true, }); -struct Imports { +impl WasmTypeId { + pub fn of() -> Self { + Self { + inner: unsafe { mem::transmute(TypeId::of::()) }, + } + } +} +impl Into for WasmTypeId { + fn into(self) -> ecs::DynTypeId { + // SAFETY: the memory layout of (u64, u64) is the same as u128 + ecs::DynTypeId::Unknown(unsafe { mem::transmute(self.inner) }) + } +} + +impl Into for ecs_world::ComponentInfo { + fn into(self) -> ecs::ComponentInfo { + ecs::ComponentInfo::new_unknown( + None, + self.type_id, + Layout::from_size_align(self.size as _, self.alignment as _).unwrap(), + ) + } +} + +impl From for ecs_world::Entity { + fn from(value: ecs::Entity) -> Self { + Self { + id: ecs_world::EntityId { id: value.id().0 }, + generation: value.generation(), + } + } +} + +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Component)] +struct Vec3 { + x: f32, + y: f32, + z: f32, +} + +struct Imports { + world: lyra_ecs::World, } impl WasiView for Imports { @@ -24,12 +85,68 @@ impl WasiView for Imports { #[async_trait] impl ExampleImports for Imports { - async fn host_test(&mut self,) -> wasmtime::Result<()> { - println!("This is the host saying hi from the guest!"); + async fn host_print(&mut self, msg: String) -> wasmtime::Result<()> { + println!("{}", msg); Ok(()) } } +impl math::Host for Imports {} + +#[async_trait] +impl ecs_world::Host for Imports { + async fn spawn( + &mut self, + mut components: Vec, + infos: Vec, + ) -> wasmtime::Result { + // add the components in the tightly packed `components` buffer into the dynamic bundle + let mut bundle = ecs::DynamicBundle::new(); + let mut offset = 0; + for info in infos { + // SAFETY: The components are tightly packed, adding the offset to the pointer will + // get the next component in the buffer. + let data_ptr = unsafe { NonNull::new_unchecked(components.as_mut_ptr().add(offset)) }; + bundle.push_unknown(data_ptr, info.into()); + + offset += info.size as usize; + } + + let en = self.world.spawn(bundle); + Ok(en.into()) + } + + async fn view(&mut self, infos: Vec) -> wasmtime::Result> { + // Create a dynamic view for querying for the components + let mut view = self.world.dynamic_view(); + for info in infos.clone() { + view.push(QueryDynamicType::from_info(info.into())); + } + + // allocate the row of components + let total_len = infos.iter().map(|i| i.size as usize).sum(); + let mut components = Vec::with_capacity(total_len); + + // copy each row of the query into the set of components. could get pretty big, but its a PoC so :shrug: + for row in view.into_iter() { + let first = row.iter().next().unwrap(); + + let mut comp = Vec::::with_capacity(first.info.layout().size()); + unsafe { + std::ptr::copy_nonoverlapping( + first.ptr.as_ptr(), + comp.as_mut_ptr(), + first.info.layout().size(), + ); + comp.set_len(first.info.layout().size()); + } + components.extend(comp.into_iter()); + } + + Ok(components) + } +} + #[tokio::main] async fn main() -> wasmtime::Result<()> { // Instantiate the engine and store @@ -37,22 +154,29 @@ async fn main() -> wasmtime::Result<()> { config.async_support(true); let engine = wasmtime::Engine::new(&config)?; - let mut store = wasmtime::Store::new(&engine, Imports {}); - - // Load the component from disk - let bytes = std::fs::read("target/wasm32-wasi/debug/witguest.wasm")?; - let component = wasmtime::component::Component::new(&engine, bytes)?; // Configure the linker let mut linker = wasmtime::component::Linker::new(&engine); wasmtime_wasi::bindings::Imports::add_to_linker(&mut linker, |s| s)?; Example::add_to_linker(&mut linker, |s| s)?; + // memory per instance + let mut store = wasmtime::Store::new( + &engine, + Imports { + world: World::new(), + }, + ); + + // Load the component from disk + let bytes = std::fs::read("target/wasm32-wasi/debug/witguest.wasm")?; + let component = wasmtime::component::Component::new(&engine, bytes)?; + // Instantiate the component println!("creating example"); let (example, _instance) = Example::instantiate_async(&mut store, &component, &linker).await?; - let result = example.call_hello_world(&mut store).await?; - println!("Guest says: {}", result); + let result = example.call_on_init(&mut store).await?.unwrap(); + println!("Guest returned: {}", result); Ok(()) -} \ No newline at end of file +} diff --git a/witguest/src/bindings.rs b/witguest/src/bindings.rs index 57817b7..b479c00 100644 --- a/witguest/src/bindings.rs +++ b/witguest/src/bindings.rs @@ -1,29 +1,32 @@ // Generated by `wit-bindgen` 0.18.0. DO NOT EDIT! #[allow(unused_unsafe, clippy::all)] -pub fn host_test(){ +pub fn host_print(msg: &str,){ #[allow(unused_imports)] use wit_bindgen::rt::{alloc, vec::Vec, string::String}; unsafe { + let vec0 = msg; + let ptr0 = vec0.as_ptr() as i32; + let len0 = vec0.len() as i32; #[cfg(target_arch = "wasm32")] #[link(wasm_import_module = "$root")] extern "C" { - #[link_name = "host-test"] - fn wit_import(); + #[link_name = "host-print"] + fn wit_import(_: i32, _: i32, ); } #[cfg(not(target_arch = "wasm32"))] - fn wit_import(){ unreachable!() } - wit_import(); + fn wit_import(_: i32, _: i32, ){ unreachable!() } + wit_import(ptr0, len0); } } const _: () = { #[doc(hidden)] - #[export_name = "hello-world"] + #[export_name = "on-init"] #[allow(non_snake_case)] - unsafe extern "C" fn __export_hello_world() -> i32 { + unsafe extern "C" fn __export_on_init() -> i32 { #[allow(unused_imports)] use wit_bindgen::rt::{alloc, vec::Vec, string::String}; @@ -41,44 +44,171 @@ const _: () = { #[cfg(target_arch="wasm32")] wit_bindgen::rt::run_ctors_once(); - let result0 = <_GuestImpl as Guest>::hello_world(); + let result0 = <_GuestImpl as Guest>::on_init(); let ptr1 = _RET_AREA.0.as_mut_ptr() as i32; - let vec2 = (result0.into_bytes()).into_boxed_slice(); - let ptr2 = vec2.as_ptr() as i32; - let len2 = vec2.len() as i32; - ::core::mem::forget(vec2); - *((ptr1 + 4) as *mut i32) = len2; - *((ptr1 + 0) as *mut i32) = ptr2; - ptr1 + match result0 { + Ok(e) => { { + *((ptr1 + 0) as *mut u8) = (0i32) as u8; + *((ptr1 + 1) as *mut u8) = (wit_bindgen::rt::as_i32(e)) as u8; + } }, + Err(_) => { { + *((ptr1 + 0) as *mut u8) = (1i32) as u8; + } }, + };ptr1 } - - const _: () = { - #[doc(hidden)] - #[export_name = "cabi_post_hello-world"] - #[allow(non_snake_case)] - unsafe extern "C" fn __post_return_hello_world(arg0: i32,) { - let l0 = *((arg0 + 0) as *const i32); - let l1 = *((arg0 + 4) as *const i32); - wit_bindgen::rt::dealloc(l0, (l1) as usize, 1); - } - }; }; use super::Component as _GuestImpl; pub trait Guest { - fn hello_world() -> wit_bindgen::rt::string::String; + fn on_init() -> Result; } #[allow(unused_imports)] use wit_bindgen::rt::{alloc, vec::Vec, string::String}; -#[repr(align(4))] -struct _RetArea([u8; 8]); -static mut _RET_AREA: _RetArea = _RetArea([0; 8]); +#[repr(align(1))] +struct _RetArea([u8; 2]); +static mut _RET_AREA: _RetArea = _RetArea([0; 2]); +pub mod component { + pub mod witguest { + + #[allow(clippy::all)] + pub mod math { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = super::super::super::__link_section; + + } + + + #[allow(clippy::all)] + pub mod ecs_world { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = super::super::super::__link_section; + /// use math.{vec3}; + #[repr(C)] + #[derive(Clone, Copy)] + pub struct EntityId { + pub id: u64, + } + impl ::core::fmt::Debug for EntityId { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("EntityId").field("id", &self.id).finish() + } + } + #[repr(C)] + #[derive(Clone, Copy)] + pub struct Entity { + pub id: EntityId, + pub generation: u64, + } + impl ::core::fmt::Debug for Entity { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Entity").field("id", &self.id).field("generation", &self.generation).finish() + } + } + #[repr(C)] + #[derive(Clone, Copy)] + pub struct WasmTypeId { + pub inner: (u64,u64,), + } + impl ::core::fmt::Debug for WasmTypeId { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("WasmTypeId").field("inner", &self.inner).finish() + } + } + #[repr(C)] + #[derive(Clone, Copy)] + pub struct ComponentInfo { + pub size: u64, + pub alignment: u64, + pub type_id: WasmTypeId, + } + impl ::core::fmt::Debug for ComponentInfo { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ComponentInfo").field("size", &self.size).field("alignment", &self.alignment).field("type-id", &self.type_id).finish() + } + } + #[allow(unused_unsafe, clippy::all)] + /// expects components to be tightly packed in the same order of component-infos + pub fn spawn(components: &[u8],component_infos: &[ComponentInfo],) -> Entity{ + + #[allow(unused_imports)] + use wit_bindgen::rt::{alloc, vec::Vec, string::String}; + unsafe { + + #[repr(align(8))] + struct RetArea([u8; 16]); + let mut ret_area = ::core::mem::MaybeUninit::::uninit(); + let vec0 = components; + let ptr0 = vec0.as_ptr() as i32; + let len0 = vec0.len() as i32; + let vec1 = component_infos; + let ptr1 = vec1.as_ptr() as i32; + let len1 = vec1.len() as i32; + let ptr2 = ret_area.as_mut_ptr() as i32; + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "component:witguest/ecs-world")] + extern "C" { + #[link_name = "spawn"] + fn wit_import(_: i32, _: i32, _: i32, _: i32, _: i32, ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32, _: i32, _: i32, _: i32, ){ unreachable!() } + wit_import(ptr0, len0, ptr1, len1, ptr2); + let l3 = *((ptr2 + 0) as *const i64); + let l4 = *((ptr2 + 8) as *const i64); + Entity{ + id: EntityId{ + id: l3 as u64, + }, + generation: l4 as u64, + } + } + } + #[allow(unused_unsafe, clippy::all)] + pub fn view(component_infos: &[ComponentInfo],) -> wit_bindgen::rt::vec::Vec::{ + + #[allow(unused_imports)] + use wit_bindgen::rt::{alloc, vec::Vec, string::String}; + unsafe { + + #[repr(align(4))] + struct RetArea([u8; 8]); + let mut ret_area = ::core::mem::MaybeUninit::::uninit(); + let vec0 = component_infos; + let ptr0 = vec0.as_ptr() as i32; + let len0 = vec0.len() as i32; + let ptr1 = ret_area.as_mut_ptr() as i32; + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "component:witguest/ecs-world")] + extern "C" { + #[link_name = "view"] + fn wit_import(_: i32, _: i32, _: i32, ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32, _: i32, ){ unreachable!() } + wit_import(ptr0, len0, ptr1); + let l2 = *((ptr1 + 0) as *const i32); + let l3 = *((ptr1 + 4) as *const i32); + let len4 = l3 as usize; + Vec::from_raw_parts(l2 as *mut _, len4, len4) + } + } + + } + + } +} #[cfg(target_arch = "wasm32")] #[link_section = "component-type:example"] #[doc(hidden)] -pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 201] = [0, 97, 115, 109, 13, 0, 1, 0, 0, 25, 22, 119, 105, 116, 45, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 4, 0, 7, 77, 1, 65, 2, 1, 65, 4, 1, 64, 0, 1, 0, 3, 0, 9, 104, 111, 115, 116, 45, 116, 101, 115, 116, 1, 0, 1, 64, 0, 0, 115, 4, 0, 11, 104, 101, 108, 108, 111, 45, 119, 111, 114, 108, 100, 1, 1, 4, 1, 26, 99, 111, 109, 112, 111, 110, 101, 110, 116, 58, 119, 105, 116, 103, 117, 101, 115, 116, 47, 101, 120, 97, 109, 112, 108, 101, 4, 0, 11, 13, 1, 0, 7, 101, 120, 97, 109, 112, 108, 101, 3, 0, 0, 0, 70, 9, 112, 114, 111, 100, 117, 99, 101, 114, 115, 1, 12, 112, 114, 111, 99, 101, 115, 115, 101, 100, 45, 98, 121, 2, 13, 119, 105, 116, 45, 99, 111, 109, 112, 111, 110, 101, 110, 116, 6, 48, 46, 50, 49, 46, 48, 16, 119, 105, 116, 45, 98, 105, 110, 100, 103, 101, 110, 45, 114, 117, 115, 116, 6, 48, 46, 49, 56, 46, 48]; +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 514] = [0, 97, 115, 109, 13, 0, 1, 0, 0, 25, 22, 119, 105, 116, 45, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 4, 0, 7, 133, 3, 1, 65, 2, 1, 65, 9, 1, 66, 2, 1, 114, 3, 1, 120, 118, 1, 121, 118, 1, 122, 118, 4, 0, 4, 118, 101, 99, 51, 3, 0, 0, 3, 1, 23, 99, 111, 109, 112, 111, 110, 101, 110, 116, 58, 119, 105, 116, 103, 117, 101, 115, 116, 47, 109, 97, 116, 104, 5, 0, 1, 66, 15, 1, 114, 1, 2, 105, 100, 119, 4, 0, 9, 101, 110, 116, 105, 116, 121, 45, 105, 100, 3, 0, 0, 1, 114, 2, 2, 105, 100, 1, 10, 103, 101, 110, 101, 114, 97, 116, 105, 111, 110, 119, 4, 0, 6, 101, 110, 116, 105, 116, 121, 3, 0, 2, 1, 111, 2, 119, 119, 1, 114, 1, 5, 105, 110, 110, 101, 114, 4, 4, 0, 12, 119, 97, 115, 109, 45, 116, 121, 112, 101, 45, 105, 100, 3, 0, 5, 1, 114, 3, 4, 115, 105, 122, 101, 119, 9, 97, 108, 105, 103, 110, 109, 101, 110, 116, 119, 7, 116, 121, 112, 101, 45, 105, 100, 6, 4, 0, 14, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 105, 110, 102, 111, 3, 0, 7, 1, 112, 125, 1, 112, 8, 1, 64, 2, 10, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 9, 15, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 105, 110, 102, 111, 115, 10, 0, 3, 4, 0, 5, 115, 112, 97, 119, 110, 1, 11, 1, 64, 1, 15, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 105, 110, 102, 111, 115, 10, 0, 9, 4, 0, 4, 118, 105, 101, 119, 1, 12, 3, 1, 28, 99, 111, 109, 112, 111, 110, 101, 110, 116, 58, 119, 105, 116, 103, 117, 101, 115, 116, 47, 101, 99, 115, 45, 119, 111, 114, 108, 100, 5, 1, 1, 64, 1, 3, 109, 115, 103, 115, 1, 0, 3, 0, 10, 104, 111, 115, 116, 45, 112, 114, 105, 110, 116, 1, 2, 1, 106, 1, 125, 0, 1, 64, 0, 0, 3, 4, 0, 7, 111, 110, 45, 105, 110, 105, 116, 1, 4, 4, 1, 26, 99, 111, 109, 112, 111, 110, 101, 110, 116, 58, 119, 105, 116, 103, 117, 101, 115, 116, 47, 101, 120, 97, 109, 112, 108, 101, 4, 0, 11, 13, 1, 0, 7, 101, 120, 97, 109, 112, 108, 101, 3, 0, 0, 0, 70, 9, 112, 114, 111, 100, 117, 99, 101, 114, 115, 1, 12, 112, 114, 111, 99, 101, 115, 115, 101, 100, 45, 98, 121, 2, 13, 119, 105, 116, 45, 99, 111, 109, 112, 111, 110, 101, 110, 116, 6, 48, 46, 50, 49, 46, 48, 16, 119, 105, 116, 45, 98, 105, 110, 100, 103, 101, 110, 45, 114, 117, 115, 116, 6, 48, 46, 49, 56, 46, 48]; #[inline(never)] #[doc(hidden)] diff --git a/witguest/src/lib.rs b/witguest/src/lib.rs index c6a588c..a329767 100644 --- a/witguest/src/lib.rs +++ b/witguest/src/lib.rs @@ -1,13 +1,63 @@ +#[allow(warnings)] mod bindings; -use bindings::Guest; +use bindings::{component::witguest::ecs_world::{self, ComponentInfo, WasmTypeId}, Guest}; + +use std::{alloc::Layout, any::TypeId, mem}; + +impl WasmTypeId { + pub fn of() -> Self { + Self { + inner: unsafe { mem::transmute(TypeId::of::()) } + } + } +} + +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq)] +struct Vec3 { + x: f32, + y: f32, + z: f32, +} + +impl Vec3 { + pub fn new(x: f32, y: f32, z: f32) -> Self { + Self { + x, y, z + } + } + + pub fn component_info() -> ComponentInfo { + let layout = Layout::new::(); + ComponentInfo { + size: layout.size() as u64, + alignment: layout.align() as u64, + type_id: WasmTypeId::of::(), + } + } +} struct Component; impl Guest for Component { - /// Say hello! - fn hello_world() -> String { - bindings::host_test(); - "Hello, World!".to_string() + fn on_init() -> Result { + let comps = &mut [Vec3::new(7.0, 30.0, 18.0),]; + let info = &[Vec3::component_info()]; + + // no fucking clue if this will work, but lets try and it see + let comps = comps.as_mut_ptr().cast::(); + let comps = unsafe { Vec::from_raw_parts(comps, mem::size_of::(), 1) }; + + let en = ecs_world::spawn(&comps, info); + + bindings::host_print(&format!("Spawned entity: {}", en.id.id)); + + let mut buffer = ecs_world::view(&[Vec3::component_info()]); + bindings::host_print(&format!("Retrieved vec3 of {} bytes long", buffer.len())); + let fetched_vec = unsafe { std::ptr::read(buffer.as_mut_ptr().cast::()) }; + bindings::host_print(&format!("Retrieved vec3: {:?}", fetched_vec)); + + Ok(0) } -} +} \ No newline at end of file diff --git a/witguest/wit/world.wit b/witguest/wit/world.wit index a4b65ce..e53a904 100644 --- a/witguest/wit/world.wit +++ b/witguest/wit/world.wit @@ -1,7 +1,45 @@ package component:witguest; +interface math { + record vec3 { + x: f32, + y: f32, + z: f32, + } +} + +interface ecs-world { + //use math.{vec3}; + + record entity-id { + id: u64, + } + + record entity { + id: entity-id, + generation: u64, + } + + record wasm-type-id { + inner: tuple, + } + + record component-info { + size: u64, + alignment: u64, + type-id: wasm-type-id, // a u128 + } + + // expects components to be tightly packed in the same order of component-infos + spawn: func(components: list, component-infos: list) -> entity; + view: func(component-infos: list) -> list; +} + /// An example world for the component to target. world example { - import host-test: func(); - export hello-world: func() -> string; + import math; + import ecs-world; + + import host-print: func(msg: string); + export on-init: func() -> result; }