kitgit

tirbofish/dropbear · diff

7dd7277 · tk

done a lot fo refactoring, and started on WASM scripting. smh...

Unverified

diff --git a/Cargo.toml b/Cargo.toml
index e4c2e8e..843b111 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -48,9 +48,9 @@ transform-gizmo-egui = { git = "https://github.com/4tkbytes/transform-gizmo"}
 tokio = { version = "1", features = ["full"] }
 wgpu = "26"
 winit = { version = "0.30", features = [] }
-zip = "4.6"
+zip = "5.1"
 walkdir = "2.3"
-wasmer = { version = "6.0" }
+wasmer = { version = "6.1.0-rc.3" }
 
 [workspace.dependencies.image]
 version = "0.25"
diff --git a/eucalyptus-core/Cargo.toml b/eucalyptus-core/Cargo.toml
index eadbe0f..fca9101 100644
--- a/eucalyptus-core/Cargo.toml
+++ b/eucalyptus-core/Cargo.toml
@@ -24,16 +24,11 @@ parking_lot.workspace = true
 ron.workspace = true
 serde.workspace = true
 winit.workspace = true
-# zip.workspace = true
-rustyscript.workspace = true
 wasmer.workspace = true
 
 [features]
 editor = []
 
-[package.metadata.cargo-machete]
-ignored = ["wasmer"]
-
 [target.'cfg(not(target_os = "android"))'.dependencies]
 rfd.workspace = true
 
diff --git a/eucalyptus-core/src/input.rs b/eucalyptus-core/src/input.rs
index d51ae61..1c83cd3 100644
--- a/eucalyptus-core/src/input.rs
+++ b/eucalyptus-core/src/input.rs
@@ -3,7 +3,10 @@ use std::{
     time::{Duration, Instant},
 };
 
-use winit::{event::MouseButton, keyboard::KeyCode};
+use wasmer::{Function, FunctionEnvMut};
+use winit::{event::MouseButton, keyboard::KeyCode, platform::scancode::PhysicalKeyExtScancode};
+
+use crate::scripting::{DropbearScriptingAPIContext, ScriptableModuleWithEnv};
 
 #[derive(Clone)]
 pub struct InputState {
@@ -40,4 +43,46 @@ impl InputState {
     pub fn lock_cursor(&mut self, toggle: bool) {
         self.is_cursor_locked = toggle;
     }
+
+    pub fn is_key_pressed(&self, key: KeyCode) -> bool {
+        self.pressed_keys.contains(&key)
+    }
+}
+
+impl ScriptableModuleWithEnv for InputState {
+    type T = DropbearScriptingAPIContext;
+
+    fn register(env: &wasmer::FunctionEnv<Self::T>, imports: &mut wasmer::Imports, store: &mut wasmer::Store) -> anyhow::Result<()> {
+        fn is_key_pressed_impl(env: FunctionEnvMut<DropbearScriptingAPIContext>, key_code: u32) -> u32 {
+            if let Some(input) = env.data().get_input() {
+                match KeyCode::from_scancode(key_code) {
+                    winit::keyboard::PhysicalKey::Code(key_code) => {
+                        if input.is_key_pressed(key_code) { 1 } else { 0 }
+                    },
+                    winit::keyboard::PhysicalKey::Unidentified(_) => 0,
+                }
+            } else {
+                0
+            }
+        }
+        let is_key_pressed = Function::new_typed_with_env(store, &env, is_key_pressed_impl);
+
+        fn get_mouse_position_impl(env: FunctionEnvMut<DropbearScriptingAPIContext>) -> (f64, f64) {
+            if let Some(input) = env.data().get_input() {
+                input.mouse_pos
+            } else {
+                (0.0, 0.0)
+            }
+        }
+        let get_mouse_position = Function::new_typed_with_env(store, &env, get_mouse_position_impl);
+
+        imports.define(Self::module_name(), "getMousePosition", get_mouse_position);
+        imports.define(Self::module_name(), "isKeyPressed", is_key_pressed);
+
+        Ok(())
+    }
+
+    fn module_name() -> &'static str {
+        "dropbear_input"
+    }
 }
diff --git a/eucalyptus-core/src/scripting.rs b/eucalyptus-core/src/scripting.rs
index 613b01e..5a0d197 100644
--- a/eucalyptus-core/src/scripting.rs
+++ b/eucalyptus-core/src/scripting.rs
@@ -1,24 +1,30 @@
-use crate::camera::CameraComponent;
+pub mod dropbear;
+
 use crate::input::InputState;
-use crate::states::{EntityNode, ModelProperties, PROJECT, SOURCE, ScriptComponent};
-use dropbear_engine::camera::Camera;
+use crate::scripting::dropbear::DropbearAPI;
+use crate::states::{EntityNode, PROJECT, SOURCE, ScriptComponent, Value};
 use dropbear_engine::entity::{AdoptedEntity, Transform};
-use dropbear_engine::lighting::{Light, LightComponent};
-use glam::DVec3;
-use hecs::World;
-use rustyscript::{Module, ModuleHandle, Runtime, RuntimeOptions, serde_json};
+use hecs::{Entity, World};
+use wasmer::{FunctionEnv, Imports, Instance, Module, Store, imports};
 use std::path::PathBuf;
+use std::sync::Arc;
 use std::{collections::HashMap, fs};
 
 /// A trait that describes a module that can be registered.
 pub trait ScriptableModule {
-    /// Registers the functions for the dropbear typescript API
-    fn register(runtime: &mut Runtime) -> anyhow::Result<()>;
-    // /// Gathers the information into a serializable format that can be sent over to the
-    // /// dropbear typescript API
-    // fn gather(world: &World, entity_id: hecs::Entity);
-    // /// Fetches the mutated information from the dropbear typescript module and applys it to the world
-    // fn release(world: &mut World, entity_id: hecs::Entity, data: &serde_json::Value) -> anyhow::Result<()>;
+    type Data;
+
+    fn register(data: &Self::Data, imports: &mut Imports, store: &mut Store) -> anyhow::Result<()>;
+
+    fn module_name() -> &'static str;
+}
+
+pub trait ScriptableModuleWithEnv {
+    type T;
+
+    fn register(env: &FunctionEnv<Self::T>, imports: &mut Imports, store: &mut Store) -> anyhow::Result<()>;
+
+    fn module_name() -> &'static str;
 }
 
 pub const TEMPLATE_SCRIPT: &'static str = include_str!("../../resources/template.ts");
@@ -36,40 +42,131 @@ pub enum ScriptAction {
     EditScript,
 }
 
+#[derive(Clone)]
+pub struct DropbearScriptingAPIContext {
+    pub current_entity: Option<Entity>,
+    current_world: Option<Arc<World>>,
+    pub current_input: Option<InputState>,
+    pub persistent_data: HashMap<String, Value>,
+    pub frame_data: HashMap<String, Value>,
+}
+
+impl DropbearScriptingAPIContext {
+    pub fn new() -> Self {
+        Self {
+            current_entity: None,
+            current_world: None,
+            current_input: None,
+            persistent_data: HashMap::new(),
+            frame_data: HashMap::new(),
+        }
+    }
+
+    pub fn set_context(&mut self, entity: Entity, world: Arc<World>, input: &InputState) {
+        self.current_entity = Some(entity);
+        self.current_world = Some(world);
+        self.current_input = Some(input.clone());
+    }
+
+    pub fn clear_context(&mut self) {
+        self.current_entity = None;
+        self.current_world = None;
+        self.current_input = None;
+        self.frame_data.clear();
+    }
+
+    pub fn get_current_entity(&self) -> Option<Entity> {
+        self.current_entity
+    }
+
+    pub fn get_input(&self) -> Option<&InputState> {
+        self.current_input.as_ref()
+    }
+
+    pub fn set_persistent_data(&mut self, key: String, value: Value) {
+        self.persistent_data.insert(key, value);
+    }
+
+    pub fn get_persistent_data(&self, key: &str) -> Option<&Value> {
+        self.persistent_data.get(key)
+    }
+
+    pub fn set_frame_data(&mut self, key: String, value: Value) {
+        self.frame_data.insert(key, value);
+    }
+
+    pub fn get_frame_data(&self, key: &str) -> Option<&Value> {
+        self.frame_data.get(key)
+    }
+
+    pub fn cleanup_entity_data(&mut self, entity: Entity) {
+        let entity_prefix = format!("entity_{:?}_", entity);
+        self.persistent_data.retain(|k, _| !k.starts_with(&entity_prefix));
+    }
+}
+
 pub struct ScriptManager {
-    pub runtime: Runtime,
-    compiled_scripts: HashMap<String, ModuleHandle>,
-    entity_script_data: HashMap<hecs::Entity, serde_json::Value>,
+    pub store: Store,
+    compiled_scripts: HashMap<String, Module>,
+    entity_script_data: HashMap<hecs::Entity, u32>,
+    script_context: DropbearScriptingAPIContext,
 }
 
 impl ScriptManager {
     pub fn new() -> anyhow::Result<Self> {
-        todo!();
-    }
+        let store = Store::default();
+        
+        let result = Self {
+            store,
+            compiled_scripts: HashMap::new(),
+            entity_script_data: HashMap::new(),
+            script_context: DropbearScriptingAPIContext::new(),
+        };
 
-    pub fn load_script_from_source(
-        &mut self,
-        script_name: &String,
-        script_content: &String,
-    ) -> anyhow::Result<String> {
-        todo!();
+        log::debug!("Initialised ScriptManager");
+        Ok(result)
     }
 
-    pub fn load_script(&mut self, script_path: &PathBuf) -> anyhow::Result<String> {
-        todo!();
+    pub fn load_script(&mut self, script_name: &String, script_content: impl AsRef<[u8]>) -> anyhow::Result<String> {
+        let module = Module::new(self.store.engine(), script_content)?;
+        self.compiled_scripts.insert(script_name.clone(), module);
+        log::debug!("Loaded script [{}]", script_name);
+        Ok(script_name.clone())
     }
 
     pub fn init_entity_script(
         &mut self,
         entity_id: hecs::Entity,
         script_name: &str,
-        world: &mut World,
-        input_state: &InputState,
+        world: &mut Arc<World>,
+        input_state: &InputState
     ) -> anyhow::Result<()> {
         log_once::debug_once!("init_entity_script: {} for {:?}", script_name, entity_id);
 
         if let Some(module) = self.compiled_scripts.get(script_name).cloned() {
-            todo!();
+            self.script_context.set_context(entity_id, world.clone(), input_state);
+
+            let import_obj = self.create_imports()?;
+            let instance = Instance::new(&mut self.store, &module, &import_obj)?;
+
+            if let Ok(alloc_func) = instance.exports.get_function("__alloc") {
+                let size = std::mem::size_of::<Transform>() as i32;
+                let result = alloc_func.call(&mut self.store, &[size.into()])?;
+                if let Some(wasmer::Value::I32(ptr)) = result.get(0) {
+                    self.entity_script_data.insert(entity_id, *ptr as u32);
+                }
+            }
+
+            self.sync_entity_to_memory(entity_id, world, &instance)?;
+
+            if let Ok(init_func) = instance.exports.get_function("init") {
+                init_func.call(&mut self.store, &[])?;
+            }
+
+            self.sync_memory_to_entity(entity_id, world, &instance)?;
+
+            self.script_context.clear_context();
+
             Ok(())
         } else {
             Err(anyhow::anyhow!("Script '{}' not found", script_name))
@@ -80,20 +177,31 @@ impl ScriptManager {
         &mut self,
         entity_id: hecs::Entity,
         script_name: &str,
-        world: &mut World,
+        world: &mut Arc<World>,
         input_state: &InputState,
         dt: f32,
     ) -> anyhow::Result<()> {
         log_once::debug_once!("Update entity script name: {}", script_name);
 
         if let Some(module) = self.compiled_scripts.get(script_name).cloned() {
-            todo!();
+            self.script_context.set_context(entity_id, world.clone(), input_state);
+            
+            let import_object = self.create_imports()?;
+            let instance = Instance::new(&mut self.store, &module, &import_object)?;
+            
+            self.sync_entity_to_memory(entity_id, world, &instance)?;
+            
+            if let Ok(update_func) = instance.exports.get_function("update") {
+                let dt_value = wasmer::Value::F32(dt);
+                update_func.call(&mut self.store, &[dt_value])?;
+            }
+            
+            self.sync_memory_to_entity(entity_id, world, &instance)?;
+            
+            self.script_context.clear_context();
+            
         } else {
-            log_once::error_once!(
-                "Unable to fetch compiled scripts for entity {:?}. Script Name: {}",
-                entity_id,
-                script_name
-            );
+            log_once::error_once!("Unable to fetch compiled scripts for entity {:?}. Script Name: {}", entity_id, script_name);
         }
         Ok(())
     }
@@ -101,6 +209,57 @@ impl ScriptManager {
     pub fn remove_entity_script(&mut self, entity_id: hecs::Entity) {
         self.entity_script_data.remove(&entity_id);
     }
+
+    fn sync_entity_to_memory(&self, entity_id: hecs::Entity, world: &mut Arc<World>, instance: &Instance) -> anyhow::Result<()> {
+        if let Some(&memory_offset) = self.entity_script_data.get(&entity_id) {
+            let memory = instance.exports.get_memory("memory")?;
+            let memory_view = memory.view(&self.store);
+
+            if let Ok(transform) = Arc::get_mut(world).unwrap().query_one_mut::<&Transform>(entity_id) {
+                let transform_bytes = unsafe { std::slice::from_raw_parts(
+                    transform as *const Transform as *const u8, 
+                    std::mem::size_of::<Transform>()
+                )};
+                
+                for (i, &byte) in transform_bytes.iter().enumerate() {
+                    memory_view.write_u8((memory_offset + i as u32).into(), byte)?;
+                }
+            }
+        }
+        Ok(())
+    }
+
+    fn sync_memory_to_entity(&self, entity_id: hecs::Entity, world: &mut Arc<World>, instance: &Instance) -> anyhow::Result<()> {
+        if let Some(&memory_offset) = self.entity_script_data.get(&entity_id) {
+            let memory = instance.exports.get_memory("memory")?;
+            let memory_view = memory.view(&self.store);
+
+            Self::update::<Transform>(memory_offset, &memory_view, world, &entity_id)?;
+        }
+        Ok(())
+    }
+
+    fn update<T: Send + Sync + 'static>(memory_offset: u32, memory_view: &wasmer::MemoryView<'_>, world: &mut Arc<World>, entity_id: &hecs::Entity) -> anyhow::Result<()> {
+        let mut obj_bytes = vec![0u8; std::mem::size_of::<T>()];
+        for (i, byte) in obj_bytes.iter_mut().enumerate() {
+            *byte = memory_view.read_u8((memory_offset + i as u32).into())?;
+        }
+
+        let obj = unsafe {
+            std::ptr::read(obj_bytes.as_ptr() as *const T)
+        };
+
+        Arc::get_mut(world).unwrap().insert_one(*entity_id, obj)?;
+        Ok(())
+    }
+
+    fn create_imports(&mut self) -> anyhow::Result<Imports> {
+        let mut imports = imports! {};
+
+        DropbearAPI::register(&self.script_context, &mut imports, &mut self.store)?;
+
+        Ok(imports)
+    }
 }
 
 pub fn move_script_to_src(script_path: &PathBuf) -> anyhow::Result<PathBuf> {
diff --git a/eucalyptus-core/src/scripting/dropbear.rs b/eucalyptus-core/src/scripting/dropbear.rs
new file mode 100644
index 0000000..c226442
--- /dev/null
+++ b/eucalyptus-core/src/scripting/dropbear.rs
@@ -0,0 +1,22 @@
+
+use wasmer::FunctionEnv;
+
+use crate::{input::InputState, scripting::{DropbearScriptingAPIContext, ScriptableModule, ScriptableModuleWithEnv}};
+
+pub struct DropbearAPI;
+
+impl ScriptableModule for DropbearAPI {
+    type Data = DropbearScriptingAPIContext;
+
+    fn register(data: &Self::Data, imports: &mut wasmer::Imports, store: &mut wasmer::Store) -> anyhow::Result<()> {
+        let env = FunctionEnv::new(store, data.clone());
+
+        InputState::register(&env, imports, store)?;
+
+        Ok(())
+    }
+
+    fn module_name() -> &'static str {
+        "dropbear"
+    }
+}
\ No newline at end of file
diff --git a/eucalyptus-core/src/states.rs b/eucalyptus-core/src/states.rs
index 9d0ac04..ab67c1c 100644
--- a/eucalyptus-core/src/states.rs
+++ b/eucalyptus-core/src/states.rs
@@ -632,11 +632,11 @@ pub struct SceneEntity {
 
 #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
 pub struct ModelProperties {
-    pub custom_properties: HashMap<String, PropertyValue>,
+    pub custom_properties: HashMap<String, Value>,
 }
 
 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-pub enum PropertyValue {
+pub enum Value {
     String(String),
     Int(i64),
     Float(f64),
@@ -651,11 +651,11 @@ impl ModelProperties {
         }
     }
 
-    pub fn set_property(&mut self, key: String, value: PropertyValue) {
+    pub fn set_property(&mut self, key: String, value: Value) {
         self.custom_properties.insert(key, value);
     }
 
-    pub fn get_property(&self, key: &str) -> Option<&PropertyValue> {
+    pub fn get_property(&self, key: &str) -> Option<&Value> {
         self.custom_properties.get(key)
     }
 }
@@ -728,7 +728,7 @@ impl SceneConfig {
         #[allow(unused_variables)]
         let project_config = if cfg!(feature = "editor") {
             let cfg = PROJECT.read();
-            { cfg.project_path.clone() }
+            cfg.project_path.clone()
         } else {
             log::debug!("Not using the editor feature, returning empty pathbuffer");
             PathBuf::new()
@@ -806,7 +806,7 @@ impl SceneConfig {
                         .get("width")
                         .ok_or_else(|| anyhow::anyhow!("Entity has no width property"))?;
                     let width = match width {
-                        PropertyValue::Float(width) => width,
+                        Value::Float(width) => width,
                         _ => panic!("Entity has a width property that is not a float"),
                     };
                     let height = entity_config
@@ -815,7 +815,7 @@ impl SceneConfig {
                         .get("height")
                         .ok_or_else(|| anyhow::anyhow!("Entity has no height property"))?;
                     let height = match height {
-                        PropertyValue::Float(height) => height,
+                        Value::Float(height) => height,
                         _ => panic!("Entity has a height property that is not a float"),
                     };
                     let tiles_x = entity_config
@@ -824,7 +824,7 @@ impl SceneConfig {
                         .get("tiles_x")
                         .ok_or_else(|| anyhow::anyhow!("Entity has no tiles_x property"))?;
                     let tiles_x = match tiles_x {
-                        PropertyValue::Int(tiles_x) => tiles_x,
+                        Value::Int(tiles_x) => tiles_x,
                         _ => panic!("Entity has a tiles_x property that is not an int"),
                     };
                     let tiles_z = entity_config
@@ -833,7 +833,7 @@ impl SceneConfig {
                         .get("tiles_z")
                         .ok_or_else(|| anyhow::anyhow!("Entity has no tiles_z property"))?;
                     let tiles_z = match tiles_z {
-                        PropertyValue::Int(tiles_z) => tiles_z,
+                        Value::Int(tiles_z) => tiles_z,
                         _ => panic!("Entity has a tiles_z property that is not an int"),
                     };
 
diff --git a/eucalyptus-editor/src/camera.rs b/eucalyptus-editor/src/camera.rs
index 97b85fa..7447bbe 100644
--- a/eucalyptus-editor/src/camera.rs
+++ b/eucalyptus-editor/src/camera.rs
@@ -72,6 +72,8 @@ impl Component for Camera {
 }
 
 #[derive(Debug)]
+#[allow(dead_code)]
+// todo: provide a purpose for this
 pub enum UndoableCameraAction {
     Speed(Entity, f64),
     Sensitivity(Entity, f64),
diff --git a/eucalyptus-editor/src/editor/dock.rs b/eucalyptus-editor/src/editor/dock.rs
index 4da3551..669492f 100644
--- a/eucalyptus-editor/src/editor/dock.rs
+++ b/eucalyptus-editor/src/editor/dock.rs
@@ -26,7 +26,7 @@ pub struct EditorTabViewer<'a> {
     pub nodes: Vec<EntityNode>,
     pub tex_size: Extent3d,
     pub gizmo: &'a mut Gizmo,
-    pub world: &'a mut World,
+    pub world: &'a mut Arc<World>,
     pub selected_entity: &'a mut Option<hecs::Entity>,
     pub viewport_mode: &'a mut ViewportMode,
     pub undo_stack: &'a mut Vec<UndoableAction>,
@@ -407,7 +407,7 @@ impl<'a> TabViewer for EditorTabViewer<'a> {
                 if !matches!(self.viewport_mode, ViewportMode::None) {
                     if let Some(entity_id) = self.selected_entity {
                         if let Ok(transform) =
-                            self.world.query_one_mut::<&mut Transform>(*entity_id)
+                            Arc::get_mut(&mut self.world).unwrap().query_one_mut::<&mut Transform>(*entity_id)
                         {
                             let was_focused = cfg.is_focused;
                             cfg.is_focused = self.gizmo.is_focused();
@@ -719,7 +719,7 @@ impl<'a> TabViewer for EditorTabViewer<'a> {
                         camera,
                         camera_component,
                         follow_target,
-                    )) = self.world.query_one_mut::<(
+                    )) = Arc::get_mut(&mut self.world).unwrap().query_one_mut::<(
                         &mut AdoptedEntity,
                         Option<&mut Transform>,
                         Option<&ModelProperties>,
@@ -816,7 +816,7 @@ impl<'a> TabViewer for EditorTabViewer<'a> {
                     }
 
                     if let Ok((light, transform, props)) =
-                        self.world
+                        Arc::get_mut(&mut self.world).unwrap()
                             .query_one_mut::<(&mut Light, &mut Transform, &mut LightComponent)>(
                                 *entity,
                             )
@@ -866,7 +866,7 @@ impl<'a> TabViewer for EditorTabViewer<'a> {
                     }
 
                     if let Ok((camera, camera_component, follow_target)) =
-                        self.world.query_one_mut::<(
+                        Arc::get_mut(&mut self.world).unwrap().query_one_mut::<(
                             &mut Camera,
                             &mut CameraComponent,
                             Option<&mut CameraFollowTarget>,
@@ -1024,14 +1024,14 @@ impl<'a> TabViewer for EditorTabViewer<'a> {
                         EditorTabMenuAction::AddComponent => {
                             log::debug!("Add Component clicked");
                             if let Some(entity) = self.selected_entity {
-                                if let Ok(..) = self.world.query_one_mut::<&AdoptedEntity>(*entity)
+                                if let Ok(..) = Arc::get_mut(&mut self.world).unwrap().query_one_mut::<&AdoptedEntity>(*entity)
                                 {
                                     log::debug!("Queried selected entity, it is an entity");
                                     *self.signal =
                                         Signal::AddComponent(*entity, EntityType::Entity);
                                 }
 
-                                if let Ok(..) = self.world.query_one_mut::<&Light>(*entity) {
+                                if let Ok(..) = Arc::get_mut(&mut self.world).unwrap().query_one_mut::<&Light>(*entity) {
                                     log::debug!("Queried selected entity, it is a light");
                                     *self.signal = Signal::AddComponent(*entity, EntityType::Light);
                                 }
@@ -1055,7 +1055,7 @@ impl<'a> TabViewer for EditorTabViewer<'a> {
                             log::debug!("Remove Component clicked");
                             if let Some(entity) = self.selected_entity {
                                 if let Ok(script) =
-                                    self.world.query_one_mut::<&ScriptComponent>(*entity)
+                                    Arc::get_mut(&mut self.world).unwrap().query_one_mut::<&ScriptComponent>(*entity)
                                 {
                                     log::debug!(
                                         "Queried selected entity, it has a script component"
@@ -1177,6 +1177,8 @@ pub(crate) fn import_object() -> anyhow::Result<()> {
 }
 
 #[derive(Debug, Clone, Copy)]
+#[allow(dead_code)]
+// todo: provide a purpose to RemoveComponent
 pub enum EditorTabMenuAction {
     ImportResource,
     RefreshAssets,
diff --git a/eucalyptus-editor/src/editor/mod.rs b/eucalyptus-editor/src/editor/mod.rs
index 6a85dda..5bf17ad 100644
--- a/eucalyptus-editor/src/editor/mod.rs
+++ b/eucalyptus-editor/src/editor/mod.rs
@@ -44,7 +44,7 @@ use winit::{keyboard::KeyCode, window::Window};
 
 pub struct Editor {
     scene_command: SceneCommand,
-    world: World,
+    world: Arc<World>,
     dock_state: DockState<EditorTab>,
     texture_id: Option<egui::TextureId>,
     size: Extent3d,
@@ -123,7 +123,7 @@ impl Editor {
             is_viewport_focused: false,
             // is_cursor_locked: false,
             window: None,
-            world: World::new(),
+            world: Arc::new(World::new()),
             show_new_project: false,
             project_name: String::new(),
             project_path: None,
@@ -277,7 +277,7 @@ impl Editor {
         {
             let scenes = SCENES.read();
             if let Some(first_scene) = scenes.first() {
-                self.active_camera = Some(first_scene.load_into_world(&mut self.world, graphics)?);
+                self.active_camera = Some(first_scene.load_into_world(Arc::get_mut(&mut self.world).unwrap(), graphics)?);
 
                 log::info!(
                     "Successfully loaded scene with {} entities and {} camera configs",
@@ -306,7 +306,7 @@ impl Editor {
                     let debug_camera = Camera::predetermined(graphics, Some("Debug Camera"));
                     let component = DebugCamera::new();
 
-                    let e = self.world.spawn((debug_camera, component));
+                    let e = Arc::get_mut(&mut self.world).unwrap().spawn((debug_camera, component));
                     self.active_camera = Some(e);
                 }
             }
@@ -637,6 +637,8 @@ pub enum UndoableAction {
     CameraAction(UndoableCameraAction),
 }
 #[derive(Debug)]
+#[allow(dead_code)]
+// todo: deal with why there is no Camera
 pub enum EntityType {
     Entity,
     Light,
@@ -813,6 +815,8 @@ pub enum Signal {
 }
 
 #[derive(Debug)]
+#[allow(dead_code)]
+// todo: deal with the Camera and create an implementation
 pub enum ComponentType {
     Script(ScriptComponent),
     Camera(Camera, CameraComponent, Option<CameraFollowTarget>),
@@ -902,10 +906,10 @@ impl PlayModeBackup {
                         }
                     }
                     (true, None) => {
-                        let _ = editor.world.remove_one::<ScriptComponent>(*entity_id);
+                        let _ = Arc::get_mut(&mut editor.world).unwrap().remove_one::<ScriptComponent>(*entity_id);
                     }
                     (false, Some(original)) => {
-                        let _ = editor.world.insert_one(*entity_id, original.clone());
+                        let _ = Arc::get_mut(&mut editor.world).unwrap().insert_one(*entity_id, original.clone());
                     }
                     (false, None) => {
                         // No change needed
@@ -935,10 +939,10 @@ impl PlayModeBackup {
                         }
                     }
                     (true, None) => {
-                        let _ = editor.world.remove_one::<CameraFollowTarget>(*entity_id);
+                        let _ = Arc::get_mut(&mut editor.world).unwrap().remove_one::<CameraFollowTarget>(*entity_id);
                     }
                     (false, Some(original)) => {
-                        let _ = editor.world.insert_one(*entity_id, original.clone());
+                        let _ = Arc::get_mut(&mut editor.world).unwrap().insert_one(*entity_id, original.clone());
                     }
                     (false, None) => {
                         // No change needed
diff --git a/eucalyptus-editor/src/editor/scene.rs b/eucalyptus-editor/src/editor/scene.rs
index b9eb7db..52133a9 100644
--- a/eucalyptus-editor/src/editor/scene.rs
+++ b/eucalyptus-editor/src/editor/scene.rs
@@ -11,7 +11,7 @@ use dropbear_engine::{
 };
 use egui::{Align2, Image};
 use eucalyptus_core::camera::PlayerCamera;
-use eucalyptus_core::states::PropertyValue;
+use eucalyptus_core::states::Value;
 use eucalyptus_core::utils::{PROTO_TEXTURE, PendingSpawn};
 use eucalyptus_core::{logging, scripting, success_without_console, warn_without_console};
 use log;
@@ -95,7 +95,7 @@ impl Scene for Editor {
                 match AdoptedEntity::new(graphics, &spawn.asset_path, Some(&spawn.asset_name)) {
                     Ok(adopted) => {
                         let entity_id =
-                            self.world
+                            Arc::get_mut(&mut self.world).unwrap()
                                 .spawn((adopted, spawn.transform, spawn.properties));
                         self.selected_entity = Some(entity_id);
 
@@ -123,7 +123,7 @@ impl Scene for Editor {
             }
 
             let mut script_entities = Vec::new();
-            for (entity_id, script) in self.world.query::<&mut ScriptComponent>().iter() {
+            for (entity_id, script) in Arc::get_mut(&mut self.world).unwrap().query::<&mut ScriptComponent>().iter() {
                 log_once::debug_once!(
                     "Script Entity -> id: {:?}, component: {:?}",
                     entity_id,
@@ -233,7 +233,7 @@ impl Scene for Editor {
                     Some(&scene_entity.label),
                 ) {
                     Ok(adopted) => {
-                        let entity_id = self.world.spawn((
+                        let entity_id = Arc::get_mut(&mut self.world).unwrap().spawn((
                             adopted,
                             scene_entity.transform,
                             ModelProperties::default(),
@@ -256,7 +256,7 @@ impl Scene for Editor {
             Signal::Delete => {
                 if let Some(sel_e) = &self.selected_entity {
                     let is_viewport_cam =
-                        if let Ok(mut q) = self.world.query_one::<&CameraComponent>(*sel_e) {
+                        if let Ok(mut q) = Arc::get_mut(&mut self.world).unwrap().query_one::<&CameraComponent>(*sel_e) {
                             if let Some(c) = q.get() {
                                 if matches!(c.camera_type, CameraType::Debug) {
                                     true
@@ -273,7 +273,7 @@ impl Scene for Editor {
                         warn!("You can't delete the viewport camera");
                         self.signal = Signal::None;
                     } else {
-                        match self.world.despawn(*sel_e) {
+                        match Arc::get_mut(&mut self.world).unwrap().despawn(*sel_e) {
                             Ok(_) => {
                                 info!("Decimated entity");
                                 self.signal = Signal::None;
@@ -288,7 +288,7 @@ impl Scene for Editor {
             }
             Signal::Undo => {
                 if let Some(action) = self.undo_stack.pop() {
-                    match action.undo(&mut self.world) {
+                    match action.undo(&mut Arc::get_mut(&mut self.world).unwrap()) {
                         Ok(_) => {
                             info!("Undid action");
                         }
@@ -318,14 +318,14 @@ impl Scene for Editor {
                                 };
 
                                 let replaced = if let Ok(mut sc) =
-                                    self.world.get::<&mut ScriptComponent>(selected_entity)
+                                    Arc::get_mut(&mut self.world).unwrap().get::<&mut ScriptComponent>(selected_entity)
                                 {
                                     sc.name = new_script.name.clone();
                                     sc.path = new_script.path.clone();
                                     true
                                 } else {
                                     match scripting::attach_script_to_entity(
-                                        &mut self.world,
+                                        &mut Arc::get_mut(&mut self.world).unwrap(),
                                         selected_entity,
                                         new_script.clone(),
                                     ) {
@@ -343,7 +343,7 @@ impl Scene for Editor {
                                 };
 
                                 if let Err(e) =
-                                    scripting::convert_entity_to_group(&self.world, selected_entity)
+                                    scripting::convert_entity_to_group(&Arc::get_mut(&mut self.world).unwrap(), selected_entity)
                                 {
                                     log::warn!("convert_entity_to_group failed (non-fatal): {}", e);
                                 }
@@ -377,14 +377,14 @@ impl Scene for Editor {
                         };
 
                         let replaced = if let Ok(mut sc) =
-                            self.world.get::<&mut ScriptComponent>(selected_entity)
+                            Arc::get_mut(&mut self.world).unwrap().get::<&mut ScriptComponent>(selected_entity)
                         {
                             sc.name = new_script.name.clone();
                             sc.path = new_script.path.clone();
                             true
                         } else {
                             match scripting::attach_script_to_entity(
-                                &mut self.world,
+                                Arc::get_mut(&mut self.world).unwrap(),
                                 selected_entity,
                                 new_script.clone(),
                             ) {
@@ -398,7 +398,7 @@ impl Scene for Editor {
                         };
 
                         if let Err(e) =
-                            scripting::convert_entity_to_group(&self.world, selected_entity)
+                            scripting::convert_entity_to_group(&Arc::get_mut(&mut self.world).unwrap(), selected_entity)
                         {
                             log::warn!("convert_entity_to_group failed (non-fatal): {}", e);
                         }
@@ -419,12 +419,12 @@ impl Scene for Editor {
                 ScriptAction::RemoveScript => {
                     if let Some(selected_entity) = self.selected_entity {
                         if let Ok(script) =
-                            self.world.remove_one::<ScriptComponent>(selected_entity)
+                            Arc::get_mut(&mut self.world).unwrap().remove_one::<ScriptComponent>(selected_entity)
                         {
                             success!("Removed script from entity {:?}", selected_entity);
 
                             if let Err(e) =
-                                scripting::convert_entity_to_group(&self.world, selected_entity)
+                                scripting::convert_entity_to_group(&Arc::get_mut(&mut self.world).unwrap(), selected_entity)
                             {
                                 log::warn!("convert_entity_to_group failed (non-fatal): {}", e);
                             }
@@ -447,7 +447,7 @@ impl Scene for Editor {
                 }
                 ScriptAction::EditScript => {
                     if let Some(selected_entity) = self.selected_entity {
-                        if let Ok(mut q) = self.world.query_one::<&ScriptComponent>(selected_entity)
+                        if let Ok(mut q) = Arc::get_mut(&mut self.world).unwrap().query_one::<&ScriptComponent>(selected_entity)
                         {
                             if let Some(script) = q.get() {
                                 match open::that(script.path.clone()) {
@@ -488,7 +488,7 @@ impl Scene for Editor {
                     self.switch_to_player_camera();
 
                     let mut script_entities = Vec::new();
-                    for (entity_id, script) in self.world.query::<&ScriptComponent>().iter() {
+                    for (entity_id, script) in Arc::get_mut(&mut self.world).unwrap().query::<&ScriptComponent>().iter() {
                         script_entities.push((entity_id, script.clone()));
                     }
 
@@ -498,7 +498,17 @@ impl Scene for Editor {
                             script.name,
                             script.path.display()
                         );
-                        match self.script_manager.load_script(&script.path) {
+
+                        let bytes = match std::fs::read(&script.path) {
+                            Ok(val) => val,
+                            Err(e) => {
+                                fatal!("Unable to read script {} to bytes because {}", &script.path.display(), e);
+                                self.signal = Signal::None;
+                                return;
+                            },
+                        };
+                        
+                        match self.script_manager.load_script(&script.path.file_name().unwrap().to_string_lossy().to_string(), bytes) {
                             Ok(script_name) => {
                                 if let Err(e) = self.script_manager.init_entity_script(
                                     entity_id,
@@ -543,7 +553,7 @@ impl Scene for Editor {
 
                 self.switch_to_debug_camera();
 
-                for (entity_id, _) in self.world.query::<&ScriptComponent>().iter() {
+                for (entity_id, _) in Arc::get_mut(&mut self.world).unwrap().query::<&ScriptComponent>().iter() {
                     self.script_manager.remove_entity_script(entity_id);
                 }
 
@@ -570,7 +580,7 @@ impl Scene for Editor {
                     if let Some(camera_entity) = player_camera {
                         let mut follow_target = (false, CameraFollowTarget::default());
                         // Find the target entity label
-                        if let Ok(mut query) = self.world.query_one::<&AdoptedEntity>(*entity) {
+                        if let Ok(mut query) = Arc::get_mut(&mut self.world).unwrap().query_one::<&AdoptedEntity>(*entity) {
                             if let Some(adopted) = query.get() {
                                 follow_target = (
                                     true,
@@ -583,7 +593,7 @@ impl Scene for Editor {
                         }
 
                         if follow_target.0 {
-                            let _ = self.world.insert_one(camera_entity, follow_target);
+                            let _ = Arc::get_mut(&mut self.world).unwrap().insert_one(camera_entity, follow_target);
                             info!("Set player camera target to entity {:?}", entity);
                         }
                     }
@@ -603,7 +613,7 @@ impl Scene for Editor {
                         });
 
                     if let Some(camera_entity) = player_camera {
-                        let _ = self.world.remove_one::<CameraFollowTarget>(camera_entity);
+                        let _ = Arc::get_mut(&mut self.world).unwrap().remove_one::<CameraFollowTarget>(camera_entity);
                     }
                     info!("Cleared player camera target");
                     self.signal = Signal::None;
@@ -612,7 +622,7 @@ impl Scene for Editor {
             Signal::AddComponent(entity, e_type) => {
                 match e_type {
                     EntityType::Entity => {
-                        if let Ok(e) = self.world.query_one_mut::<&AdoptedEntity>(*entity) {
+                        if let Ok(e) = Arc::get_mut(&mut self.world).unwrap().query_one_mut::<&AdoptedEntity>(*entity) {
                             let mut local_signal: Option<Signal> = None;
                             let label = e.label().clone();
                             let mut show = true;
@@ -634,8 +644,7 @@ impl Scene for Editor {
                                             "Adding scripting component to entity [{}]",
                                             label
                                         );
-                                        if let Err(e) = self
-                                            .world
+                                        if let Err(e) = Arc::get_mut(&mut self.world).unwrap()
                                             .insert_one(*entity, ScriptComponent::default())
                                         {
                                             warn!(
@@ -677,7 +686,7 @@ impl Scene for Editor {
                                             let component = CameraComponent::new();
 
                                             if let Err(e) =
-                                                self.world.insert(*entity, (camera, component))
+                                                Arc::get_mut(&mut self.world).unwrap().insert(*entity, (camera, component))
                                             {
                                                 warn!(
                                                     "Failed to add camera component to entity: {}",
@@ -703,7 +712,7 @@ impl Scene for Editor {
                         }
                     }
                     EntityType::Light => {
-                        if let Ok(light) = self.world.query_one_mut::<&Light>(*entity) {
+                        if let Ok(light) = Arc::get_mut(&mut self.world).unwrap().query_one_mut::<&Light>(*entity) {
                             let mut show = true;
                             egui::Window::new(format!("Add component for {}", light.label))
                                 .scroll([false, true])
@@ -741,8 +750,7 @@ impl Scene for Editor {
                         }
                     }
                     EntityType::Camera => {
-                        if let Ok((cam, _comp)) = self
-                            .world
+                        if let Ok((cam, _comp)) = Arc::get_mut(&mut self.world).unwrap()
                             .query_one_mut::<(&Camera, &CameraComponent)>(*entity)
                         {
                             let mut show = true;
@@ -780,7 +788,7 @@ impl Scene for Editor {
             }
             Signal::RemoveComponent(entity, c_type) => match c_type {
                 ComponentType::Script(_) => {
-                    match self.world.remove_one::<ScriptComponent>(*entity) {
+                    match Arc::get_mut(&mut self.world).unwrap().remove_one::<ScriptComponent>(*entity) {
                         Ok(component) => {
                             success!("Removed script component from entity {:?}", entity);
                             UndoableAction::push_to_undo(
@@ -799,8 +807,7 @@ impl Scene for Editor {
                 }
                 ComponentType::Camera(_, _, follow) => {
                     if let Some(_) = follow {
-                        match self
-                            .world
+                        match Arc::get_mut(&mut self.world).unwrap()
                             .remove::<(Camera, CameraComponent, CameraFollowTarget)>(*entity)
                         {
                             Ok(component) => {
@@ -822,7 +829,7 @@ impl Scene for Editor {
                             }
                         };
                     } else {
-                        match self.world.remove::<(Camera, CameraComponent)>(*entity) {
+                        match Arc::get_mut(&mut self.world).unwrap().remove::<(Camera, CameraComponent)>(*entity) {
                             Ok(component) => {
                                 success!("Removed camera component from entity {:?}", entity);
                                 UndoableAction::push_to_undo(
@@ -862,7 +869,7 @@ impl Scene for Editor {
                             let transform = Transform::new();
                             let component = LightComponent::default();
                             let light = Light::new(graphics, &component, &transform, Some("Light"));
-                            self.world.spawn((light, component, transform));
+                            Arc::get_mut(&mut self.world).unwrap().spawn((light, component, transform));
                             success!("Created new light");
 
                             // always ensure the signal is reset after action is dun
@@ -880,11 +887,11 @@ impl Scene for Editor {
                                 ).unwrap();
                             let transform = Transform::new();
                             let mut props = ModelProperties::new();
-                            props.custom_properties.insert("width".to_string(), PropertyValue::Float(500.0));
-                            props.custom_properties.insert("height".to_string(), PropertyValue::Float(200.0));
-                            props.custom_properties.insert("tiles_x".to_string(), PropertyValue::Int(500));
-                            props.custom_properties.insert("tiles_z".to_string(), PropertyValue::Int(200));
-                            self.world.spawn((plane, transform, props));
+                            props.custom_properties.insert("width".to_string(), Value::Float(500.0));
+                            props.custom_properties.insert("height".to_string(), Value::Float(200.0));
+                            props.custom_properties.insert("tiles_x".to_string(), Value::Int(500));
+                            props.custom_properties.insert("tiles_z".to_string(), Value::Int(200));
+                            Arc::get_mut(&mut self.world).unwrap().spawn((plane, transform, props));
                             success!("Created new plane");
 
                             self.signal = Signal::None;
@@ -904,7 +911,7 @@ impl Scene for Editor {
                                         model,
                                         Some("Cube")
                                     );
-                                    self.world.spawn((cube, Transform::new(), ModelProperties::new()));
+                                    Arc::get_mut(&mut self.world).unwrap().spawn((cube, Transform::new(), ModelProperties::new()));
                                 }
                                 Err(e) => {
                                     fatal!("Failed to load cube model: {}", e);
@@ -929,7 +936,7 @@ impl Scene for Editor {
                                         model,
                                         Some("Cube")
                                     );
-                                    self.world.spawn((cube, Transform::new(), ModelProperties::new()));
+                                    Arc::get_mut(&mut self.world).unwrap().spawn((cube, Transform::new(), ModelProperties::new()));
                                 }
                                 Err(e) => {
                                     fatal!("Failed to load cube model: {}", e);
@@ -944,7 +951,7 @@ impl Scene for Editor {
                             log::debug!("Creating new cube");
                             let camera = Camera::predetermined(graphics, None);
                             let component = CameraComponent::new();
-                            self.world.spawn((camera, component));
+                            Arc::get_mut(&mut self.world).unwrap().spawn((camera, component));
                             success!("Created new camera");
 
                             self.signal = Signal::None;
@@ -956,7 +963,7 @@ impl Scene for Editor {
             }
             Signal::LogEntities => {
                 log::info!("====================");
-                for entity in self.world.iter() {
+                for entity in Arc::get_mut(&mut self.world).unwrap().iter() {
                     if let Some(entity) = entity.get::<&AdoptedEntity>() {
                         log::info!("Model: {:?}", entity.label());
                     }
@@ -975,7 +982,7 @@ impl Scene for Editor {
 
         let new_aspect = current_size.width as f64 / current_size.height as f64;
         if let Some(active_camera) = self.active_camera {
-            if let Ok(mut query) = self.world.query_one::<&mut Camera>(active_camera) {
+            if let Ok(mut query) = Arc::get_mut(&mut self.world).unwrap().query_one::<&mut Camera>(active_camera) {
                 if let Some(camera) = query.get() {
                     camera.aspect = new_aspect;
                 }
@@ -1010,19 +1017,18 @@ impl Scene for Editor {
             camera.update(graphics);
         }
 
-        let query = self.world.query_mut::<(&mut AdoptedEntity, &Transform)>();
+        let query = Arc::get_mut(&mut self.world).unwrap().query_mut::<(&mut AdoptedEntity, &Transform)>();
         for (_, (entity, transform)) in query {
             entity.update(&graphics, transform);
         }
 
-        let light_query = self
-            .world
+        let light_query = Arc::get_mut(&mut self.world).unwrap()
             .query_mut::<(&mut LightComponent, &Transform, &mut Light)>();
         for (_, (light_component, transform, light)) in light_query {
             light.update(light_component, transform);
         }
 
-        self.light_manager.update(graphics, &self.world);
+        self.light_manager.update(graphics, &Arc::get_mut(&mut self.world).unwrap());
     }
 
     fn render(&mut self, graphics: &mut Graphics) {