From a34fb426b7708c83d592401f63c26bae4da9602a Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Mon, 16 Sep 2024 21:40:51 -0700 Subject: [PATCH] refactor(vm+frontend): better logging, fix slot serialization Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- Cargo.lock | 3 + ic10emu/src/vm.rs | 49 ++++++++++++ ic10emu_wasm/Cargo.toml | 1 + ic10emu_wasm/src/lib.rs | 24 +++++- ic10emu_wasm/src/utils.rs | 9 --- ic10lsp_wasm/Cargo.toml | 2 + ic10lsp_wasm/src/lib.rs | 6 +- stationeers_data/src/templates.rs | 48 +++++++++++ www/cspell.json | 3 + www/src/ts/app/app.ts | 11 +-- www/src/ts/app/nav.ts | 5 +- www/src/ts/app/save.ts | 3 +- www/src/ts/database/index.ts | 6 +- www/src/ts/editor/ace.ts | 2 +- www/src/ts/editor/index.ts | 8 +- www/src/ts/editor/lspWorker.ts | 16 ++-- www/src/ts/editor/prompt_patch.ts | 2 - www/src/ts/log.ts | 51 ++++++++++++ www/src/ts/session.ts | 10 ++- www/src/ts/utils.ts | 15 ++-- www/src/ts/virtualMachine/device/card.ts | 6 +- .../ts/virtualMachine/device/slotAddDialog.ts | 4 +- www/src/ts/virtualMachine/device/template.ts | 3 +- www/src/ts/virtualMachine/index.ts | 20 ++--- www/src/ts/virtualMachine/state.ts | 16 ++-- www/src/ts/virtualMachine/vmWorker.ts | 80 ++++++++++++++----- 26 files changed, 310 insertions(+), 93 deletions(-) create mode 100644 www/src/ts/log.ts diff --git a/Cargo.lock b/Cargo.lock index f4a64db..d1c9b09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -659,6 +659,7 @@ dependencies = [ "serde_with", "stationeers_data", "thiserror", + "tracing", "tracing-wasm", "tsify", "wasm-bindgen", @@ -694,6 +695,8 @@ dependencies = [ "js-sys", "tokio", "tower-lsp", + "tracing", + "tracing-wasm", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", diff --git a/ic10emu/src/vm.rs b/ic10emu/src/vm.rs index 1096909..72ba687 100644 --- a/ic10emu/src/vm.rs +++ b/ic10emu/src/vm.rs @@ -113,16 +113,22 @@ impl VM { /// Take ownership of an iterable that produces (prefab hash, ObjectTemplate) pairs and build a prefab /// database + #[tracing::instrument(skip(db))] pub fn import_template_database( self: &Rc, db: impl IntoIterator, ) { + tracing::info!("importing new template database"); self.template_database .borrow_mut() .replace(db.into_iter().collect()); } + /// Take ownership of an iterable that produces (reagent id, Reagent) pairs and build a reagent + /// database + #[tracing::instrument(skip(db))] pub fn import_reagent_database(self: &Rc, db: impl IntoIterator) { + tracing::info!("importing new reagent database"); self.reagent_database .borrow_mut() .replace(db.into_iter().collect()); @@ -192,6 +198,7 @@ impl VM { /// Add an number of object to the VM state using Frozen Object structs. /// See also `add_objects_frozen` /// Returns the built objects' IDs + #[tracing::instrument(skip(frozen_objects))] pub fn add_objects_frozen( self: &Rc, frozen_objects: impl IntoIterator, @@ -249,6 +256,7 @@ impl VM { /// current database. /// Errors if the object can not be built do to a template error /// Returns the built object's ID + #[tracing::instrument] pub fn add_object_frozen(self: &Rc, frozen: FrozenObject) -> Result { let mut transaction = VMTransaction::new(self); @@ -295,6 +303,7 @@ impl VM { } /// Creates a new network adn return it's ID + #[tracing::instrument] pub fn add_network(self: &Rc) -> ObjectID { let next_id = self.network_id_space.borrow_mut().next(); self.networks.borrow_mut().insert( @@ -322,6 +331,7 @@ impl VM { /// /// Iterates over all objects borrowing them mutably, never call unless VM is not currently /// stepping or you'll get reborrow panics + #[tracing::instrument] pub fn change_device_id( self: &Rc, old_id: ObjectID, @@ -385,6 +395,7 @@ impl VM { /// Set program code if it's valid /// Object Id is the programmable Id or the circuit holder's id + #[tracing::instrument] pub fn set_code(self: &Rc, id: ObjectID, code: &str) -> Result { let obj = self .objects @@ -420,6 +431,7 @@ impl VM { /// Set program code and translate invalid lines to Nop, collecting errors /// Object Id is the programmable Id or the circuit holder's id + #[tracing::instrument] pub fn set_code_invalid(self: &Rc, id: ObjectID, code: &str) -> Result { let obj = self .objects @@ -455,6 +467,7 @@ impl VM { /// Get program code /// Object Id is the programmable Id or the circuit holder's id + #[tracing::instrument] pub fn get_code(self: &Rc, id: ObjectID) -> Result { let obj = self .objects @@ -488,6 +501,7 @@ impl VM { /// Get a vector of any errors compiling the source code /// Object Id is the programmable Id or the circuit holder's id + #[tracing::instrument] pub fn get_compile_errors(self: &Rc, id: ObjectID) -> Result, VMError> { let obj = self .objects @@ -521,6 +535,7 @@ impl VM { /// Set register of integrated circuit /// Object Id is the circuit Id or the circuit holder's id + #[tracing::instrument] pub fn set_register( self: &Rc, id: ObjectID, @@ -561,6 +576,7 @@ impl VM { /// Set memory at address of object with memory /// Object Id is the memory writable Id or the circuit holder's id + #[tracing::instrument] pub fn set_memory( self: &Rc, id: ObjectID, @@ -610,6 +626,7 @@ impl VM { } /// Set logic field on a logicable object + #[tracing::instrument] pub fn set_logic_field( self: &Rc, id: ObjectID, @@ -634,6 +651,7 @@ impl VM { } /// Set slot logic filed on device object + #[tracing::instrument] pub fn set_slot_logic_field( self: &Rc, id: ObjectID, @@ -661,6 +679,7 @@ impl VM { self.operation_modified.borrow().clone() } + #[tracing::instrument] pub fn step_programmable( self: &Rc, id: ObjectID, @@ -705,6 +724,7 @@ impl VM { } /// returns true if executed 128 lines, false if returned early. + #[tracing::instrument] pub fn run_programmable( self: &Rc, id: ObjectID, @@ -816,10 +836,12 @@ impl VM { Err(VMError::NoIC(id)) } + #[tracing::instrument] pub fn get_object(self: &Rc, id: ObjectID) -> Option { self.objects.borrow().get(&id).cloned() } + #[tracing::instrument] pub fn batch_device( self: &Rc, source: ObjectID, @@ -850,6 +872,7 @@ impl VM { .into_iter() } + #[tracing::instrument] pub fn get_device_same_network( self: &Rc, source: ObjectID, @@ -862,6 +885,7 @@ impl VM { } } + #[tracing::instrument] pub fn get_network_channel( self: &Rc, id: ObjectID, @@ -887,6 +911,7 @@ impl VM { } } + #[tracing::instrument] pub fn set_network_channel( self: &Rc, id: ObjectID, @@ -913,6 +938,7 @@ impl VM { } } + #[tracing::instrument] pub fn devices_on_same_network(self: &Rc, ids: &[ObjectID]) -> bool { for net in self.networks.borrow().values() { if net @@ -928,6 +954,7 @@ impl VM { } /// return a vector with the device ids the source id can see via it's connected networks + #[tracing::instrument] pub fn visible_devices(self: &Rc, source: ObjectID) -> Vec { self.networks .borrow() @@ -944,6 +971,7 @@ impl VM { .concat() } + #[tracing::instrument] pub fn set_pin( self: &Rc, id: ObjectID, @@ -976,6 +1004,7 @@ impl VM { } } + #[tracing::instrument] pub fn set_device_connection( self: &Rc, id: ObjectID, @@ -1076,6 +1105,7 @@ impl VM { Ok(true) } + #[tracing::instrument] pub fn remove_device_from_network( self: &Rc, id: ObjectID, @@ -1108,6 +1138,7 @@ impl VM { } } + #[tracing::instrument] pub fn set_batch_device_field( self: &Rc, source: ObjectID, @@ -1129,6 +1160,7 @@ impl VM { .try_collect() } + #[tracing::instrument] pub fn set_batch_device_slot_field( self: &Rc, source: ObjectID, @@ -1151,6 +1183,7 @@ impl VM { .try_collect() } + #[tracing::instrument] pub fn set_batch_name_device_field( self: &Rc, source: ObjectID, @@ -1173,6 +1206,7 @@ impl VM { .try_collect() } + #[tracing::instrument] pub fn get_batch_device_field( self: &Rc, source: ObjectID, @@ -1195,6 +1229,7 @@ impl VM { Ok(LogicBatchMethodWrapper(mode).apply(&samples)) } + #[tracing::instrument] pub fn get_batch_name_device_field( self: &Rc, source: ObjectID, @@ -1218,6 +1253,7 @@ impl VM { Ok(LogicBatchMethodWrapper(mode).apply(&samples)) } + #[tracing::instrument] pub fn get_batch_name_device_slot_field( self: &Rc, source: ObjectID, @@ -1242,6 +1278,7 @@ impl VM { Ok(LogicBatchMethodWrapper(mode).apply(&samples)) } + #[tracing::instrument] pub fn get_batch_device_slot_field( self: &Rc, source: ObjectID, @@ -1265,6 +1302,7 @@ impl VM { Ok(LogicBatchMethodWrapper(mode).apply(&samples)) } + #[tracing::instrument] pub fn remove_object(self: &Rc, id: ObjectID) -> Result<(), VMError> { let Some(obj) = self.objects.borrow_mut().remove(&id) else { return Err(VMError::UnknownId(id)); @@ -1294,6 +1332,7 @@ impl VM { /// object must already be added to the VM /// does not clean up previous object /// returns the id of any former occupant + #[tracing::instrument] pub fn set_slot_occupant( self: &Rc, id: ObjectID, @@ -1348,6 +1387,7 @@ impl VM { } /// returns former occupant id if any + #[tracing::instrument] pub fn remove_slot_occupant( self: &Rc, id: ObjectID, @@ -1368,6 +1408,7 @@ impl VM { Ok(last) } + #[tracing::instrument] pub fn freeze_object(self: &Rc, id: ObjectID) -> Result { let Some(obj) = self.objects.borrow().get(&id).cloned() else { return Err(VMError::UnknownId(id)); @@ -1375,6 +1416,7 @@ impl VM { Ok(FrozenObject::freeze_object(&obj, self)?) } + #[tracing::instrument(skip(ids))] pub fn freeze_objects( self: &Rc, ids: impl IntoIterator, @@ -1389,6 +1431,7 @@ impl VM { .collect() } + #[tracing::instrument] pub fn freeze_network(self: &Rc, id: ObjectID) -> Result { Ok(self .networks @@ -1401,6 +1444,7 @@ impl VM { .into()) } + #[tracing::instrument(skip(ids))] pub fn freeze_networks( self: &Rc, ids: impl IntoIterator, @@ -1420,7 +1464,9 @@ impl VM { .collect::, VMError>>() } + #[tracing::instrument] pub fn save_vm_state(self: &Rc) -> Result { + tracing::trace!("saving vm state"); Ok(FrozenVM { objects: self .objects @@ -1449,7 +1495,9 @@ impl VM { }) } + #[tracing::instrument] pub fn restore_vm_state(self: &Rc, state: FrozenVM) -> Result<(), VMError> { + tracing::trace!("restoring vm state from {:?}", &state); let mut transaction_network_id_space = IdSpace::new(); transaction_network_id_space .use_ids(&state.networks.iter().map(|net| net.id).collect_vec())?; @@ -1624,6 +1672,7 @@ impl VMTransaction { } pub fn finalize(&mut self) -> Result<(), VMError> { + tracing::trace!("finalizing vm transaction: {:?}", &self); for (child, (slot, parent)) in &self.object_parents { let child_obj = self .objects diff --git a/ic10emu_wasm/Cargo.toml b/ic10emu_wasm/Cargo.toml index 7b6934d..a871eac 100644 --- a/ic10emu_wasm/Cargo.toml +++ b/ic10emu_wasm/Cargo.toml @@ -27,6 +27,7 @@ thiserror = "1.0.61" serde_derive = "1.0.203" serde_json = "1.0.117" tracing-wasm = "0.2.1" +tracing = "0.1.40" [features] default = ["console_error_panic_hook"] diff --git a/ic10emu_wasm/src/lib.rs b/ic10emu_wasm/src/lib.rs index 60bd7f5..688580b 100644 --- a/ic10emu_wasm/src/lib.rs +++ b/ic10emu_wasm/src/lib.rs @@ -18,7 +18,7 @@ use serde_derive::{Deserialize, Serialize}; use stationeers_data::{ enums::script::{LogicSlotType, LogicType}, - templates::ObjectTemplate, + templates::{ObjectTemplate, Reagent}, }; use std::{collections::BTreeMap, rc::Rc}; @@ -60,6 +60,18 @@ impl IntoIterator for TemplateDatabase { } } +#[derive(Clone, Debug, Serialize, Deserialize, Tsify)] +#[tsify(into_wasm_abi, from_wasm_abi)] +pub struct ReagentDatabase(BTreeMap); + +impl IntoIterator for ReagentDatabase { + type Item = (u8, Reagent); + type IntoIter = std::collections::btree_map::IntoIter; + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + #[derive(Clone, Debug, Serialize, Deserialize, Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct FrozenObjects(Vec); @@ -115,7 +127,7 @@ pub fn parse_value<'a, T: serde::Deserialize<'a>>( let mut track = serde_path_to_error::Track::new(); let path = serde_path_to_error::Deserializer::new(jd, &mut track); let mut fun = |path: serde_ignored::Path| { - log!("Found ignored key: {path}"); + tracing::warn!("Found ignored key: {path}"); }; serde_ignored::deserialize(path, &mut fun).map_err(|e| { eyre::eyre!( @@ -125,6 +137,7 @@ pub fn parse_value<'a, T: serde::Deserialize<'a>>( }) } +#[allow(non_snake_case)] #[wasm_bindgen] impl VMRef { #[wasm_bindgen(constructor)] @@ -137,6 +150,11 @@ impl VMRef { self.vm.import_template_database(db); } + #[wasm_bindgen(js_name = "importReagentDatabase")] + pub fn import_reagent_database(&self, db: ReagentDatabase) { + self.vm.import_reagent_database(db); + } + #[wasm_bindgen(js_name = "importTemplateDatabaseSerdeWasm")] pub fn import_template_database_serde_wasm(&self, db: JsValue) -> Result<(), JsError> { let parsed_db: BTreeMap = @@ -480,6 +498,6 @@ pub fn init() -> VMRef { utils::set_panic_hook(); tracing_wasm::set_as_global_default(); let vm = VMRef::new(); - log!("Hello from ic10emu!"); + tracing::info!("Hello from ic10emu!"); vm } diff --git a/ic10emu_wasm/src/utils.rs b/ic10emu_wasm/src/utils.rs index 7439406..55e764b 100644 --- a/ic10emu_wasm/src/utils.rs +++ b/ic10emu_wasm/src/utils.rs @@ -11,12 +11,3 @@ pub fn set_panic_hook() { web_sys::console::log_1(&"Panic hook set...".into()); } } - -extern crate web_sys; - -// A macro to provide `println!(..)`-style syntax for `console.log` logging. -macro_rules! log { - ( $( $t:tt )* ) => { - web_sys::console::log_1(&format!( $( $t )* ).into()); - } -} diff --git a/ic10lsp_wasm/Cargo.toml b/ic10lsp_wasm/Cargo.toml index a6ebbfc..6cc34c8 100644 --- a/ic10lsp_wasm/Cargo.toml +++ b/ic10lsp_wasm/Cargo.toml @@ -26,6 +26,8 @@ wasm-bindgen-futures = { version = "0.4.42", features = [ wasm-streams = "0.4" # web-tree-sitter-sys = "1.3" ic10lsp = { git = "https://github.com/Ryex/ic10lsp.git", branch = "wasm" } +tracing-wasm = "0.2.1" +tracing = "0.1.40" # ic10lsp = { path = "../../ic10lsp" } [package.metadata.wasm-pack.profile.dev] diff --git a/ic10lsp_wasm/src/lib.rs b/ic10lsp_wasm/src/lib.rs index b300c60..2034a14 100644 --- a/ic10lsp_wasm/src/lib.rs +++ b/ic10lsp_wasm/src/lib.rs @@ -30,8 +30,9 @@ impl ServerConfig { #[wasm_bindgen] pub async fn serve(config: ServerConfig) -> Result<(), JsValue> { console_error_panic_hook::set_once(); + tracing_wasm::set_as_global_default(); - web_sys::console::log_1(&"server::serve".into()); + tracing::trace!("server::serv error:"); let ServerConfig { into_server, @@ -51,6 +52,7 @@ pub async fn serve(config: ServerConfig) -> Result<(), JsValue> { }) .map_err(|err| { web_sys::console::log_2(&"server::input Error: ".into(), &err); + tracing::error!("server::input error: {:?}", &err); std::io::Error::from(std::io::ErrorKind::Other) }) @@ -67,7 +69,7 @@ pub async fn serve(config: ServerConfig) -> Result<(), JsValue> { }); Server::new(input, output, messages).serve(service).await; - web_sys::console::log_1(&"server::serve ic10lsp started".into()); + tracing::info!("server::serve ic10lsp started"); Ok(()) } diff --git a/stationeers_data/src/templates.rs b/stationeers_data/src/templates.rs index 529c835..c1f94cf 100644 --- a/stationeers_data/src/templates.rs +++ b/stationeers_data/src/templates.rs @@ -174,11 +174,14 @@ impl From for ObjectTemplate { } } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct HumanTemplate { pub prefab: PrefabInfo, pub species: Species, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, } @@ -420,6 +423,7 @@ pub struct StructureTemplate { pub internal_atmo_info: Option, } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct StructureSlotsTemplate { @@ -429,9 +433,12 @@ pub struct StructureSlotsTemplate { pub thermal_info: Option, #[cfg_attr(feature = "tsify", tsify(optional))] pub internal_atmo_info: Option, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct StructureLogicTemplate { @@ -442,9 +449,12 @@ pub struct StructureLogicTemplate { #[cfg_attr(feature = "tsify", tsify(optional))] pub internal_atmo_info: Option, pub logic: LogicInfo, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct StructureLogicDeviceTemplate { @@ -455,10 +465,13 @@ pub struct StructureLogicDeviceTemplate { #[cfg_attr(feature = "tsify", tsify(optional))] pub internal_atmo_info: Option, pub logic: LogicInfo, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, pub device: DeviceInfo, } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct StructureLogicDeviceConsumerTemplate { @@ -469,6 +482,8 @@ pub struct StructureLogicDeviceConsumerTemplate { #[cfg_attr(feature = "tsify", tsify(optional))] pub internal_atmo_info: Option, pub logic: LogicInfo, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, pub device: DeviceInfo, pub consumer_info: ConsumerInfo, @@ -476,6 +491,7 @@ pub struct StructureLogicDeviceConsumerTemplate { pub fabricator_info: Option, } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct StructureLogicDeviceMemoryTemplate { @@ -486,11 +502,14 @@ pub struct StructureLogicDeviceMemoryTemplate { #[cfg_attr(feature = "tsify", tsify(optional))] pub internal_atmo_info: Option, pub logic: LogicInfo, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, pub device: DeviceInfo, pub memory: MemoryInfo, } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct StructureCircuitHolderTemplate { @@ -501,10 +520,13 @@ pub struct StructureCircuitHolderTemplate { #[cfg_attr(feature = "tsify", tsify(optional))] pub internal_atmo_info: Option, pub logic: LogicInfo, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, pub device: DeviceInfo, } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct StructureLogicDeviceConsumerMemoryTemplate { @@ -515,6 +537,8 @@ pub struct StructureLogicDeviceConsumerMemoryTemplate { #[cfg_attr(feature = "tsify", tsify(optional))] pub internal_atmo_info: Option, pub logic: LogicInfo, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, pub device: DeviceInfo, pub consumer_info: ConsumerInfo, @@ -534,6 +558,7 @@ pub struct ItemTemplate { pub internal_atmo_info: Option, } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct ItemSlotsTemplate { @@ -543,9 +568,12 @@ pub struct ItemSlotsTemplate { pub thermal_info: Option, #[cfg_attr(feature = "tsify", tsify(optional))] pub internal_atmo_info: Option, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct ItemConsumerTemplate { @@ -555,10 +583,13 @@ pub struct ItemConsumerTemplate { pub thermal_info: Option, #[cfg_attr(feature = "tsify", tsify(optional))] pub internal_atmo_info: Option, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, pub consumer_info: ConsumerInfo, } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct ItemLogicTemplate { @@ -569,9 +600,12 @@ pub struct ItemLogicTemplate { #[cfg_attr(feature = "tsify", tsify(optional))] pub internal_atmo_info: Option, pub logic: LogicInfo, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct ItemLogicMemoryTemplate { @@ -582,10 +616,13 @@ pub struct ItemLogicMemoryTemplate { #[cfg_attr(feature = "tsify", tsify(optional))] pub internal_atmo_info: Option, pub logic: LogicInfo, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, pub memory: MemoryInfo, } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct ItemCircuitHolderTemplate { @@ -596,9 +633,12 @@ pub struct ItemCircuitHolderTemplate { #[cfg_attr(feature = "tsify", tsify(optional))] pub internal_atmo_info: Option, pub logic: LogicInfo, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct ItemSuitTemplate { @@ -608,10 +648,13 @@ pub struct ItemSuitTemplate { pub thermal_info: Option, #[cfg_attr(feature = "tsify", tsify(optional))] pub internal_atmo_info: Option, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, pub suit_info: SuitInfo, } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct ItemSuitLogicTemplate { @@ -622,10 +665,13 @@ pub struct ItemSuitLogicTemplate { #[cfg_attr(feature = "tsify", tsify(optional))] pub internal_atmo_info: Option, pub logic: LogicInfo, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, pub suit_info: SuitInfo, } +#[serde_as] #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct ItemSuitCircuitHolderTemplate { @@ -636,6 +682,8 @@ pub struct ItemSuitCircuitHolderTemplate { #[cfg_attr(feature = "tsify", tsify(optional))] pub internal_atmo_info: Option, pub logic: LogicInfo, + #[serde_as(as = "BTreeMap")] + #[cfg_attr(feature = "tsify", tsify(type = "Map"))] pub slots: BTreeMap, pub suit_info: SuitInfo, pub memory: MemoryInfo, diff --git a/www/cspell.json b/www/cspell.json index 2992b2e..7a7c288 100644 --- a/www/cspell.json +++ b/www/cspell.json @@ -60,6 +60,7 @@ "dbutils", "Depressurising", "deviceslength", + "dodgerblue", "endpos", "getd", "Hardsuit", @@ -72,6 +73,7 @@ "jetpack", "Keybind", "labelledby", + "lawngreen", "lbns", "leeoniya", "logicable", @@ -136,6 +138,7 @@ "VMIC", "VMUI", "vstack", + "whitesmoke", "whos" ], "flagWords": [], diff --git a/www/src/ts/app/app.ts b/www/src/ts/app/app.ts index 3a7c53d..4a85eee 100644 --- a/www/src/ts/app/app.ts +++ b/www/src/ts/app/app.ts @@ -9,6 +9,7 @@ import { IC10Editor } from "../editor"; import { Session } from "../session"; import { VirtualMachine } from "../virtualMachine"; import { openFile, saveFile } from "../utils"; +import * as log from "log"; import "../virtualMachine/ui"; import "./save"; @@ -103,8 +104,8 @@ export class App extends BaseElement {
${until( - mainBody, - html` + mainBody, + html`

@@ -115,7 +116,7 @@ export class App extends BaseElement {

` - )} + )}
@@ -138,7 +139,7 @@ export class App extends BaseElement { const saved = JSON.parse(seenVersionsStr); seenVersions = saved; } catch (e) { - console.log("error pulling seen versions", e); + log.error("error pulling seen versions", e); } } const ourVer = `${this.appVersion}_${this.gitVer}_${this.buildDate}`; @@ -155,7 +156,7 @@ export class App extends BaseElement { const saved = JSON.parse(seenVersionsStr); seenVersions.concat(saved); } catch (e) { - console.log("error pulling seen versions", e); + log.error("error pulling seen versions", e); } } const unique = new Set(seenVersions); diff --git a/www/src/ts/app/nav.ts b/www/src/ts/app/nav.ts index aa4a4b8..a94cc98 100644 --- a/www/src/ts/app/nav.ts +++ b/www/src/ts/app/nav.ts @@ -1,6 +1,7 @@ import { HTMLTemplateResult, html, css } from "lit"; import { customElement, property } from "lit/decorators.js"; import { BaseElement, defaultCss } from "components"; +import * as log from "log"; import SlMenuItem from "@shoelace-style/shoelace/dist/components/menu-item/menu-item.js"; @@ -213,7 +214,7 @@ export class Nav extends BaseElement { `; } - firstUpdated(): void {} + firstUpdated(): void { } _menuClickHandler(e: CustomEvent) { const item = e.detail.item as SlMenuItem; @@ -248,7 +249,7 @@ export class Nav extends BaseElement { this.dispatchEvent(new CustomEvent("app-changelog", { bubbles: true })); break; default: - console.log("Unknown main menu item", item.value); + log.debug("Unknown main menu item", item.value); } } } diff --git a/www/src/ts/app/save.ts b/www/src/ts/app/save.ts index 14cc33d..cb62c3e 100644 --- a/www/src/ts/app/save.ts +++ b/www/src/ts/app/save.ts @@ -2,6 +2,7 @@ import { html, css} from "lit"; import { customElement, query, state } from "lit/decorators.js"; import { BaseElement, defaultCss } from "components"; import { SessionDB } from "sessionDB"; +import * as log from "log"; import SlInput from "@shoelace-style/shoelace/dist/components/input/input.js"; import { repeat } from "lit/directives/repeat.js"; @@ -256,7 +257,7 @@ export class SaveDialog extends BaseElement { async _handleSaveButtonClick(_e: CustomEvent) { const name = this.saveInput.value; const app = await window.App.get(); - console.log(app); + log.debug(app); await app.session.saveLocal(name); this.saveDialog.hide(); } diff --git a/www/src/ts/database/index.ts b/www/src/ts/database/index.ts index dcb700e..801793b 100644 --- a/www/src/ts/database/index.ts +++ b/www/src/ts/database/index.ts @@ -6,7 +6,7 @@ import { isSome } from "utils"; export type PrefabName = keyof typeof prefabDatabase.prefabs; export type Prefab = typeof prefabDatabase.prefabs[K] export type ReagentName = keyof typeof prefabDatabase.reagents; -export type ReagentHash = (typeof prefabDatabase.reagents)[ReagentName]["Hash"] +export type ReagentHash = (typeof prefabDatabase.reagents)[ReagentName]["hash"] export type NetworkChannels = [number, number, number, number, number, number, number, number] export const validCircuitPrefabsNames = ["ItemIntegratedCircuit10"] as const; @@ -25,7 +25,7 @@ export interface ObjectFromTemplateOptions { obj: ObjectID, slot: number, } : never, - slots?: Prefab extends { slots: readonly unknown[] } ? Record extends { slots: {} } ? Record : never, @@ -102,7 +102,7 @@ export function objectFromTemplate( } if (isSome(options?.reagents)) { frozen.obj_info.reagents = new Map(Object.entries(options.reagents).map(([reagent, value]: [ReagentName, number]) => { - return [prefabDatabase.reagents[reagent].Hash, value] + return [prefabDatabase.reagents[reagent].hash, value] })) } diff --git a/www/src/ts/editor/ace.ts b/www/src/ts/editor/ace.ts index 536273d..484487b 100644 --- a/www/src/ts/editor/ace.ts +++ b/www/src/ts/editor/ace.ts @@ -10,7 +10,7 @@ import { Mode as TextMode } from "ace-builds/src-noconflict/mode-text"; export async function setupLspWorker() { // Create a web worker - let worker = new Worker(new URL("./lspWorker.ts", import.meta.url)); + let worker = new Worker(new URL("./lspWorker.ts", import.meta.url), { name: "ic10lsp-Worker" }); const loaded = (w: Worker) => new Promise((r) => w.addEventListener("message", r, { once: true })); diff --git a/www/src/ts/editor/index.ts b/www/src/ts/editor/index.ts index cb77f2a..ea1761e 100644 --- a/www/src/ts/editor/index.ts +++ b/www/src/ts/editor/index.ts @@ -40,6 +40,8 @@ import { VirtualMachine } from "virtualMachine"; import { isSome } from "utils"; import { Session } from "session"; +import * as log from "log"; + interface SessionStateExtension { state?: { errorMarkers?: Ace.MarkerGroup; @@ -108,7 +110,7 @@ export class IC10Editor extends BaseElement { constructor() { super(); - console.log("constructing editor"); + log.trace("constructing editor"); window.Editor = this; } @@ -158,7 +160,7 @@ export class IC10Editor extends BaseElement { async firstUpdated() { await this.setupApp(); - console.log("editor firstUpdated"); + log.trace("editor firstUpdated"); if (!ace.require("ace/ext/language_tools")) { await import("ace-builds/src-noconflict/ext-language_tools"); } @@ -608,7 +610,7 @@ export class IC10Editor extends BaseElement { const temp = Object.assign({}, this.settings, saved); Object.assign(this.settings, temp); } catch (e) { - console.log("error loading editor settings", e); + log.error("error loading editor settings", e); } } } diff --git a/www/src/ts/editor/lspWorker.ts b/www/src/ts/editor/lspWorker.ts index 7204a37..a84a279 100644 --- a/www/src/ts/editor/lspWorker.ts +++ b/www/src/ts/editor/lspWorker.ts @@ -1,5 +1,7 @@ import { ServerConfig, serve } from "ic10lsp_wasm"; +import * as log from "log"; + export const encoder = new TextEncoder(); export const decoder = new TextDecoder(); @@ -120,9 +122,7 @@ export class AsyncStreamQueueUint8Array async next(): Promise> { const done = false; - // console.log(`AsyncStream(${this.tag}) waiting for message`) const value = await this.dequeue(); - // console.log(`AsyncStream(${this.tag}) got message`, decoder.decode(value)) return { done, value }; } @@ -194,7 +194,7 @@ function sendClient(data: any) { async function listen() { let contentLength: number | null = null; let buffer = new Uint8Array(); - console.log("Worker: listening for lsp messages..."); + log.trace("Worker: listening for lsp messages..."); for await (const bytes of serverMsgStream) { buffer = Bytes.append(Uint8Array, buffer, bytes); let waitingForFullContent = false; @@ -236,18 +236,18 @@ async function listen() { try { const message = JSON.parse(delimited); - console.log( + log.debug( "Lsp Message:", `| This Loop: ${messagesThisLoop} |`, message, ); postMessage(message); } catch (e) { - console.log("Error parsing Lsp Message:", e); + log.error("Error parsing Lsp Message:", e); } } } - console.log("Worker: lsp message queue done?"); + log.debug("Worker: lsp message queue done?"); } listen(); @@ -255,9 +255,9 @@ listen(); postMessage("ready"); onmessage = function (e) { - console.log("Client Message:", e.data); + log.debug("Client Message:", e.data); sendClient(e.data); }; -console.log("Starting LSP..."); +log.trace("Starting LSP..."); start(); diff --git a/www/src/ts/editor/prompt_patch.ts b/www/src/ts/editor/prompt_patch.ts index 7cd4262..c4ffe1b 100644 --- a/www/src/ts/editor/prompt_patch.ts +++ b/www/src/ts/editor/prompt_patch.ts @@ -1,7 +1,5 @@ import { prompt as ace_prompt } from "ace-builds/src-noconflict/ext-prompt" -console.log(ace_prompt); - function prompt(editor: { cmdLine: { setTheme: (arg0: string) => void; }; }, message: any, options: any, callback: any) { ace_prompt(editor, message, options, callback); if (editor.cmdLine) { diff --git a/www/src/ts/log.ts b/www/src/ts/log.ts new file mode 100644 index 0000000..c47b3b4 --- /dev/null +++ b/www/src/ts/log.ts @@ -0,0 +1,51 @@ + +export function logHeaderFormatting(msg: string, style: string, origin: string,): string[] { + return [ + `%c${msg}%c ${origin}%c`, + style, + "color: gray; font-style: italic", + "color: inherit" + ]; +} + +declare var WorkerGlobalScope: { + prototype: any; + new(): any; +}; + +export function getOrigin(framesUp: number = 1) { + const origin = new Error().stack.split('\n')[framesUp + 1]; + if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) { + const workerName = self.name ?? "worker" + return `(worker: ${workerName})|${origin}`; + } else { + return origin; + } +} + +export function error(...args: any[]): void { + const header = logHeaderFormatting("ERROR", "color: red; background: #444", getOrigin()); + console.error(...header, ...args) +} + +export function warn(...args: any[]): void { + const header = logHeaderFormatting("WARN", "color: orange; background: #444", getOrigin()); + console.warn(...header, ...args) +} + +export function info(...args: any[]): void { + const header = logHeaderFormatting("INFO", "color: whitesmoke; background: #444", getOrigin()); + console.info(...header, ...args) +} + +export function debug(...args: any[]): void { + const header = logHeaderFormatting("DEBUG", "color: lawngreen; background: #444", getOrigin()); + console.debug(...header, ...args) +} + +export function trace(...args: any[]): void { + const header = logHeaderFormatting("TRACE", "color: dodgerblue; background: #444", getOrigin()); + console.log(...header, ...args) +} + + diff --git a/www/src/ts/session.ts b/www/src/ts/session.ts index 08bf097..b636c97 100644 --- a/www/src/ts/session.ts +++ b/www/src/ts/session.ts @@ -10,6 +10,8 @@ import { toJson, } from "./utils"; +import * as log from "log"; + import * as presets from "./presets"; import { computed, signal, Signal } from "@lit-labs/preact-signals"; import { SessionDB } from "sessionDB"; @@ -97,7 +99,7 @@ export class Session extends TypedEventTarget(object: T | null | undefined): object is T { return typeof object !== "undefined" && object !== null; @@ -230,7 +231,7 @@ export function makeRequest(opts: { export async function saveFile(content: BlobPart) { const blob = new Blob([content], { type: "text/plain" }); if (typeof window.showSaveFilePicker !== "undefined") { - console.log("Saving via FileSystem API"); + log.info("Saving via FileSystem API"); try { const saveHandle = await window.showSaveFilePicker({ types: [ @@ -247,10 +248,10 @@ export async function saveFile(content: BlobPart) { await ws.write(blob); await ws.close(); } catch (e) { - console.log(e); + log.error(e); } } else { - console.log("saving file via hidden link event"); + log.info("saving file via hidden link event"); var a = document.createElement("a"); const date = new Date().valueOf().toString(16); a.download = `code_${date}.ic10`; @@ -261,7 +262,7 @@ export async function saveFile(content: BlobPart) { export async function openFile(editor: Ace.Editor) { if (typeof window.showOpenFilePicker !== "undefined") { - console.log("opening file via FileSystem Api"); + log.info("opening file via FileSystem Api"); try { const [fileHandle] = await window.showOpenFilePicker(); const file = await fileHandle.getFile(); @@ -269,16 +270,16 @@ export async function openFile(editor: Ace.Editor) { const session = editor.getSession(); session.setValue(contents); } catch (e) { - console.log(e); + log.error(e); } } else { - console.log("opening file via hidden input event"); + log.info("opening file via hidden input event"); let input = document.createElement("input"); input.type = "file"; input.accept = ".txt,.ic10,.mips,text/*"; input.onchange = (_) => { const files = Array.from(input.files!); - console.log(files); + log.trace(files); const file = files[0]; var reader = new FileReader(); reader.onload = (e) => { diff --git a/www/src/ts/virtualMachine/device/card.ts b/www/src/ts/virtualMachine/device/card.ts index 0f738c8..7a086bf 100644 --- a/www/src/ts/virtualMachine/device/card.ts +++ b/www/src/ts/virtualMachine/device/card.ts @@ -15,6 +15,8 @@ import { repeat } from "lit/directives/repeat.js"; import { Connection } from "ic10emu_wasm"; import { createRef, ref, Ref } from "lit/directives/ref.js"; +import * as log from "log"; + export type CardTab = "fields" | "slots" | "reagents" | "networks" | "pins"; @customElement("vm-device-card") @@ -119,7 +121,7 @@ export class VMDeviceCard extends VMObjectMixin(BaseElement) { onImageErr(e: Event) { this.image_err = true; - console.log("Image load error", e); + log.error("Image load error", e); } thisIsActiveIc = computed(() => { @@ -327,7 +329,7 @@ export class VMDeviceCard extends VMObjectMixin(BaseElement) { }); const connectionSelectRef = this.getConnectionSelectRef(index); - selectOptions.subscribe(() => {this.forceSelectUpdate(connectionSelectRef)}) + selectOptions.subscribe(() => { this.forceSelectUpdate(connectionSelectRef) }) connNet.subscribe((net) => { if (isSome(connectionSelectRef.value)) { diff --git a/www/src/ts/virtualMachine/device/slotAddDialog.ts b/www/src/ts/virtualMachine/device/slotAddDialog.ts index 9548132..b98403c 100644 --- a/www/src/ts/virtualMachine/device/slotAddDialog.ts +++ b/www/src/ts/virtualMachine/device/slotAddDialog.ts @@ -82,8 +82,8 @@ export class VMSlotAddDialog extends VMObjectMixin(BaseElement) { const obj = this.vm.value?.state.getObject(this.objectIDSignal.value).value; if (isSome(obj)) { const template = obj.template; - const slot = "slots" in template ? template.slots[this.slotIndex.value] : null; - const typ = slot?.typ; + const slot = "slots" in template ? template.slots.get(this.slotIndex.value.toString()) : null; + const typ = typeof slot === "object" && "Direct" in slot ? slot.Direct.class : null; if (typeof typ === "string" && typ !== "None") { filtered = Array.from(Object.values(this.items.value)).filter( diff --git a/www/src/ts/virtualMachine/device/template.ts b/www/src/ts/virtualMachine/device/template.ts index 8409011..076431c 100644 --- a/www/src/ts/virtualMachine/device/template.ts +++ b/www/src/ts/virtualMachine/device/template.ts @@ -151,8 +151,7 @@ export class VmObjectTemplate extends VMObjectMixin( ).map( (slot, _index) => ({ - typ: slot.class -, + typ: typeof slot === "object" && "Direct" in slot ? slot.Direct.class : null, quantity: 0, }) as SlotTemplate, ); diff --git a/www/src/ts/virtualMachine/index.ts b/www/src/ts/virtualMachine/index.ts index 37ab4ad..d3e24d2 100644 --- a/www/src/ts/virtualMachine/index.ts +++ b/www/src/ts/virtualMachine/index.ts @@ -28,6 +28,8 @@ import { import { getJsonContext } from "./jsonErrorUtils"; import { VMState } from "./state"; +import * as log from "log"; + export interface VirtualMachineEventMap { "vm-template-db-loaded": CustomEvent; "vm-objects-update": CustomEvent; @@ -62,11 +64,11 @@ class VirtualMachine extends TypedEventTarget new Promise((r) => w.addEventListener("message", r, { once: true })); await Promise.all([loaded(this.vmWorker)]); - console.info("VM Worker loaded"); + log.info("VM Worker loaded"); const vm = Comlink.wrap(this.vmWorker); this.ic10vm = vm; this.state.vm.value = await this.ic10vm.saveVMState(); @@ -133,11 +135,11 @@ class VirtualMachine extends TypedEventTarget { let id = undefined; try { - console.log("adding device", frozen); + log.trace("adding device", frozen); id = await this.ic10vm.addObjectFrozen(frozen); } catch (err) { this.handleVmError(err); @@ -329,7 +331,7 @@ class VirtualMachine extends TypedEventTarget { let ids = undefined; try { - console.log("adding devices", frozenObjects); + log.trace("adding devices", frozenObjects); ids = await this.ic10vm.addObjectsFrozen(frozenObjects); } catch (err) { this.handleVmError(err); @@ -357,7 +359,7 @@ class VirtualMachine extends TypedEventTarget { try { - console.log("setting slot occupant", frozen); + log.trace("setting slot occupant", frozen); await this.ic10vm.setSlotOccupant(id, index, frozen, quantity); } catch (err) { this.handleVmError(err); @@ -384,7 +386,7 @@ class VirtualMachine extends TypedEventTarget { const obj = this.getObject(id).value; const template = obj?.template; - return isSome(template) && "slots" in template ? template.slots.length : 0 + return isSome(template) && "slots" in template ? template.slots.size : 0 }); this.signalCacheSet(key, s); return s; @@ -248,13 +250,15 @@ export class VMState { const obj = this.getObject(id).value; const info = obj?.obj_info.slots.get(index); const template = obj?.template; - const slotTemplate = isSome(template) && "slots" in template ? template.slots[index] : null; + const slotTemplate = isSome(template) && "slots" in template ? template.slots.get(index.toString()) : null; + const name = typeof slotTemplate === "object" && "Direct" in slotTemplate ? slotTemplate.Direct.name : slotTemplate?.Proxy.name; + const typ = typeof slotTemplate === "object" && "Direct" in slotTemplate ? slotTemplate.Direct.class : null; if (isSome(obj)) { const next = { parent: obj?.obj_info.id, index, - name: slotTemplate?.name, - typ: slotTemplate?.typ, + name, + typ, quantity: info?.quantity, occupant: info?.id } @@ -713,7 +717,7 @@ export class VMState { } else if (this.programHolderIds.value?.includes(id)) { return this.getObject(id).value?.obj_info.source_code ?? null; } else { - console.error(`(objectId: ${id}) does not refer to a object with a known program interface`) + log.error(`(objectId: ${id}) does not refer to a object with a known program interface`) return null; } }) @@ -735,7 +739,7 @@ export class VMState { } else if (this.programHolderIds.value?.includes(id)) { ic = this.getObject(id).value ?? null; } else { - console.error(`(objectId: ${id}) does not refer to a object with a known program interface`) + log.error(`(objectId: ${id}) does not refer to a object with a known program interface`) return null; } const errors = ic?.obj_info.compile_errors?.flatMap((error): LineError[] => { diff --git a/www/src/ts/virtualMachine/vmWorker.ts b/www/src/ts/virtualMachine/vmWorker.ts index fccde20..14e9ba5 100644 --- a/www/src/ts/virtualMachine/vmWorker.ts +++ b/www/src/ts/virtualMachine/vmWorker.ts @@ -1,42 +1,78 @@ import { VMRef, init } from "ic10emu_wasm"; import type { - TemplateDatabase, + Reagent, + ObjectTemplate, } from "ic10emu_wasm"; import * as Comlink from "comlink"; +import * as log from "log"; + import prefabDatabase from "../database/prefabDatabase"; import { comlinkSpecialJsonTransferHandler } from "utils"; Comlink.transferHandlers.set("SpecialJson", comlinkSpecialJsonTransferHandler); -console.info("Processing Json prefab Database ", prefabDatabase); const vm: VMRef = init(); -const start_time = performance.now(); -const template_database = new Map( - Object.entries(prefabDatabase.prefabsByHash).map(([hash, prefabName]) => [ - parseInt(hash), - prefabDatabase.prefabs[prefabName], - ]), -) as TemplateDatabase; -console.info("Loading Prefab Template Database into VM", template_database); -try { - // vm.importTemplateDatabase(template_database); - vm.importTemplateDatabase(template_database); - const now = performance.now(); - const time_elapsed = (now - start_time) / 1000; - console.info(`Prefab Template Database loaded in ${time_elapsed} seconds`); -} catch (e) { - if ("stack" in e) { - console.error("Error importing template database:", e.toString(), e.stack); - } else { - console.error("Error importing template database:", e.toString()); +log.info("Processing Json Database", prefabDatabase); +{ + const start_time = performance.now(); + const template_database = new Map( + Object.entries(prefabDatabase.prefabsByHash).map(([hash, prefabName]) => [ + parseInt(hash), + prefabDatabase.prefabs[prefabName] as ObjectTemplate, + ]), + ); + log.info("Loading Prefab Template Database into VM", template_database); + + try { + vm.importTemplateDatabase(template_database); + const now = performance.now(); + const time_elapsed = (now - start_time) / 1000; + log.info(`Prefab Template Database loaded in ${time_elapsed} seconds`); + } catch (e) { + if ("stack" in e) { + log.error("Error importing template database:", e.toString(), e.stack); + } else { + log.error("Error importing template database:", e.toString()); + } } - console.info(JSON.stringify(template_database)); } + +{ + const start_time = performance.now(); + const reagent_database = new Map( + Object.entries(prefabDatabase.reagents).map(([_name, entry]) => [ + entry.id, + { + id: entry.id satisfies number, + name: entry.name satisfies string, + hash: entry.hash satisfies number, + unit: entry.unit satisfies string, + is_organic: entry.is_organic satisfies boolean, + sources: new Map(Object.entries(entry.sources)) + } satisfies Reagent + ]) + ) + log.info("Loading Reagent Database into VM", reagent_database); + + try { + vm.importReagentDatabase(reagent_database); + const now = performance.now(); + const time_elapsed = (now - start_time) / 1000; + log.info(`Prefab Reagent Database loaded in ${time_elapsed} seconds`); + } catch (e) { + if ("stack" in e) { + log.error("Error importing reagent database:", e.toString(), e.stack); + } else { + log.error("Error importing reagent database:", e.toString()); + } + } +} + postMessage("ready"); Comlink.expose(vm);