refactor(vm, frontend): turns out that the serde_wasm_bindgen facilities of TSify are borken...

This commit is contained in:
Rachel Powers
2024-06-01 04:22:58 -07:00
parent d618f7b091
commit 6c26a37ca0
22 changed files with 1236 additions and 1338 deletions

17
Cargo.lock generated
View File

@@ -645,13 +645,16 @@ dependencies = [
name = "ic10emu_wasm"
version = "0.2.3"
dependencies = [
"color-eyre",
"console_error_panic_hook",
"ic10emu",
"itertools",
"js-sys",
"serde",
"serde-wasm-bindgen 0.6.5",
"serde-wasm-bindgen",
"serde_derive",
"serde_ignored",
"serde_path_to_error",
"serde_with",
"stationeers_data",
"strum",
@@ -1276,17 +1279,6 @@ dependencies = [
"serde_derive",
]
[[package]]
name = "serde-wasm-bindgen"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e"
dependencies = [
"js-sys",
"serde",
"wasm-bindgen",
]
[[package]]
name = "serde-wasm-bindgen"
version = "0.6.5"
@@ -1802,7 +1794,6 @@ checksum = "d6b26cf145f2f3b9ff84e182c448eaf05468e247f148cf3d2a7d67d78ff023a0"
dependencies = [
"gloo-utils",
"serde",
"serde-wasm-bindgen 0.5.0",
"serde_json",
"tsify-macros",
"wasm-bindgen",

View File

@@ -29,7 +29,7 @@ time = { version = "0.3.36", features = [
"serde",
"local-offset",
] }
tsify = { version = "0.4.5", optional = true, features = ["js"] }
tsify = { version = "0.4.5", optional = true, features = ["json"] }
wasm-bindgen = { version = "0.2.92", optional = true }
[target.'cfg(target_arch = "wasm32")'.dependencies]

View File

@@ -16,10 +16,13 @@ wasm-bindgen-futures = { version = "0.4.42", features = [
] }
wasm-streams = "0.4"
serde-wasm-bindgen = "0.6.5"
serde_path_to_error = "0.1.16"
serde_ignored = "0.1.10"
color-eyre = "0.6.3"
itertools = "0.13.0"
serde = { version = "1.0.202", features = ["derive"] }
serde_with = "3.8.1"
tsify = { version = "0.4.5", features = ["js"] }
tsify = { version = "0.4.5", features = ["json"] }
thiserror = "1.0.61"
serde_derive = "1.0.203"

View File

@@ -108,6 +108,23 @@ impl IntoIterator for CompileErrors {
}
}
use color_eyre::eyre;
pub fn parse_value<'a, T: serde::Deserialize<'a>>(
jd: impl serde::Deserializer<'a>,
) -> Result<T, color_eyre::Report> {
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}");
};
serde_ignored::deserialize(path, &mut fun).map_err(|e| {
eyre::eyre!(
"path: {track} | error = {e}",
track = track.path().to_string(),
)
})
}
#[wasm_bindgen]
impl VMRef {
#[wasm_bindgen(constructor)]
@@ -120,6 +137,18 @@ impl VMRef {
self.vm.import_template_database(db);
}
#[wasm_bindgen(js_name = "importTemplateDatabaseSerde")]
pub fn import_template_database_serde(&self, db: JsValue) -> Result<(), JsError> {
let parsed_db: BTreeMap<i32, ObjectTemplate> =
parse_value(serde_wasm_bindgen::Deserializer::from(db)).map_err(|err| {
<&dyn std::error::Error as std::convert::Into<JsError>>::into(
std::convert::AsRef::<dyn std::error::Error>::as_ref(&err),
)
})?;
self.vm.import_template_database(parsed_db);
Ok(())
}
#[wasm_bindgen(js_name = "getTemplateDatabase")]
pub fn get_template_database(&self) -> TemplateDatabase {
TemplateDatabase(self.vm.get_template_database())

View File

@@ -16,5 +16,5 @@ phf = "0.11.2"
serde = "1.0.202"
serde_derive = "1.0.202"
strum = { version = "0.26.2", features = ["derive", "phf", "strum_macros"] }
tsify = { version = "0.4.5", optional = true, features = ["js"] }
tsify = { version = "0.4.5", optional = true, features = ["json"] }
wasm-bindgen = { version = "0.2.92", optional = true }

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
import { html, css } from "lit";
import { customElement, query } from "lit/decorators.js";
import { BaseElement, defaultCss } from "components";
import { VMActiveICMixin } from "virtual_machine/base_device";
import { VMActiveICMixin } from "virtual_machine/baseDevice";
import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.js";

View File

@@ -10,7 +10,7 @@ import { cache } from "lit/directives/cache.js";
import { default as uFuzzy } from "@leeoniya/ufuzzy";
import { when } from "lit/directives/when.js";
import { unsafeHTML } from "lit/directives/unsafe-html.js";
import { VMTemplateDBMixin } from "virtual_machine/base_device";
import { VMTemplateDBMixin } from "virtual_machine/baseDevice";
import { LogicInfo, ObjectTemplate, StructureInfo } from "ic10emu_wasm";
type LogicableStrucutureTemplate = Extract<

View File

@@ -1,7 +1,7 @@
import { html, css, HTMLTemplateResult } from "lit";
import { customElement, property, query, state } from "lit/decorators.js";
import { BaseElement, defaultCss } from "components";
import { VMTemplateDBMixin, VMObjectMixin } from "virtual_machine/base_device";
import { VMTemplateDBMixin, VMObjectMixin } from "virtual_machine/baseDevice";
import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.component.js";
import { parseIntWithHexOrBinary, parseNumber } from "utils";
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.component.js";

View File

@@ -1,7 +1,7 @@
import { html, css } from "lit";
import { customElement, property } from "lit/decorators.js";
import { BaseElement, defaultCss } from "components";
import { VMTemplateDBMixin, VMObjectMixin } from "virtual_machine/base_device";
import { VMTemplateDBMixin, VMObjectMixin } from "virtual_machine/baseDevice";
import { displayNumber, parseNumber } from "utils";
import type { LogicType } from "ic10emu_wasm";
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.component.js";

View File

@@ -1,7 +1,7 @@
import { html, css } from "lit";
import { customElement, property } from "lit/decorators.js";
import { BaseElement, defaultCss } from "components";
import { VMTemplateDBMixin, VMObjectMixin } from "virtual_machine/base_device";
import { VMTemplateDBMixin, VMObjectMixin } from "virtual_machine/baseDevice";
import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.component.js";
import { ObjectID } from "ic10emu_wasm";

View File

@@ -1,7 +1,7 @@
import { html, css } from "lit";
import { customElement, property} from "lit/decorators.js";
import { BaseElement, defaultCss } from "components";
import { VMTemplateDBMixin, VMObjectMixin } from "virtual_machine/base_device";
import { VMTemplateDBMixin, VMObjectMixin } from "virtual_machine/baseDevice";
import {
clamp,
crc32,

View File

@@ -1,7 +1,7 @@
import { html, css } from "lit";
import { customElement, property, query, state } from "lit/decorators.js";
import { BaseElement, defaultCss } from "components";
import { VMTemplateDBMixin } from "virtual_machine/base_device";
import { VMTemplateDBMixin } from "virtual_machine/baseDevice";
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.component.js";
import SlDialog from "@shoelace-style/shoelace/dist/components/dialog/dialog.component.js";
import { VMDeviceCard } from "./card";

View File

@@ -24,7 +24,7 @@ import { crc32, displayNumber, parseNumber } from "utils";
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.component.js";
import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.component.js";
import { VMDeviceCard } from "./card";
import { VMTemplateDBMixin } from "virtual_machine/base_device";
import { VMTemplateDBMixin } from "virtual_machine/baseDevice";
export interface SlotTemplate {
typ: Class

View File

@@ -11,7 +11,7 @@ import type {
ObjectID,
} from "ic10emu_wasm";
import * as Comlink from "comlink";
import "./base_device";
import "./baseDevice";
import "./device";
import { App } from "app";
import { structuralEqual, TypedEventTarget } from "utils";
@@ -52,15 +52,24 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
constructor(app: App) {
super();
this.app = app;
this.vm_worker = new Worker( new URL("./vm_worker.ts", import.meta.url));
const vm = Comlink.wrap<VMRef>(this.vm_worker);
this.ic10vm = vm;
window.VM.set(this);
this._objects = new Map();
this._circuitHolders = new Map();
this._networks = new Map();
this.setupVM();
}
async setupVM() {
this.vm_worker = new Worker(new URL("./vmWorker.ts", import.meta.url));
const loaded = (w: Worker) =>
new Promise((r) => w.addEventListener("message", r, { once: true }));
await Promise.all([loaded(this.vm_worker)]);
console.info("VM Worker loaded");
const vm = Comlink.wrap<VMRef>(this.vm_worker);
this.ic10vm = vm;
window.VM.set(this);
this.templateDBPromise = this.ic10vm.getTemplateDatabase();
this.templateDBPromise.then((db) => this.setupTemplateDatabase(db));

View File

@@ -1,4 +1,4 @@
{
export default {
"prefabs": {
"AccessCardBlack": {
"templateType": "Item",
@@ -66636,4 +66636,4 @@
"StructureNitrolyzer",
"StructureRocketCircuitHousing"
]
}
} as const

View File

@@ -1,7 +1,7 @@
import { html, css } from "lit";
import { customElement } from "lit/decorators.js";
import { BaseElement, defaultCss } from "components";
import { VMActiveICMixin } from "virtual_machine/base_device";
import { VMActiveICMixin } from "virtual_machine/baseDevice";
import { RegisterSpec } from "ic10emu_wasm";
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.js";

View File

@@ -1,7 +1,7 @@
import { html, css } from "lit";
import { customElement } from "lit/decorators.js";
import { BaseElement, defaultCss } from "components";
import { VMActiveICMixin } from "virtual_machine/base_device";
import { VMActiveICMixin } from "virtual_machine/baseDevice";
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.js";
import { displayNumber, parseNumber } from "utils";

File diff suppressed because it is too large Load Diff

View File

@@ -1,47 +0,0 @@
import { VMRef, init } from "ic10emu_wasm";
import type { StationpediaPrefab, ObjectTemplate } from "ic10emu_wasm";
import * as Comlink from "comlink";
import * as json_database from "../../../data/database.json" with { type: "json" };
export interface PrefabDatabase {
prefabs: { [key in StationpediaPrefab]: ObjectTemplate};
reagents: {
[key: string]: {
Hash: number;
Unit: string;
Sources?: {
[key in StationpediaPrefab]: number;
};
};
};
prefabsByHash: {
[key: number]: StationpediaPrefab;
};
structures: StationpediaPrefab[];
devices: StationpediaPrefab[];
items: StationpediaPrefab[];
logicableItems: StationpediaPrefab[];
suits: StationpediaPrefab[];
circuitHolders: StationpediaPrefab[];
}
const prefab_database = json_database as unknown as PrefabDatabase;
const vm: VMRef = init();
const template_database = new Map(
Object.entries(prefab_database.prefabsByHash).map(([hash, name]) => {
return [parseInt(hash), prefab_database.prefabs[name]];
}),
);
console.info("Loading Prefab Template Database into VM", template_database);
const start_time = performance.now();
vm.importTemplateDatabase(template_database);
const now = performance.now();
const time_elapsed = (now - start_time) / 1000;
console.log(`Prefab Templat Database loaded in ${time_elapsed} seconds`);
Comlink.expose(vm);

View File

@@ -187,12 +187,16 @@ pub fn generate_database(
circuit_holders,
};
let data_path = workspace.join("www").join("data");
let data_path = workspace
.join("www")
.join("src")
.join("ts")
.join("virtual_machine");
if !data_path.exists() {
std::fs::create_dir(&data_path)?;
}
{
let database_path = data_path.join("database.json");
let database_path = data_path.join("prefabDatabase.ts");
let mut database_file = std::io::BufWriter::new(std::fs::File::create(database_path)?);
let json = serde_json::to_string_pretty(&db)?;
// this may seem anathema but I don't want to write a separate struct set to skip Nones
@@ -205,9 +209,11 @@ pub fn generate_database(
//
// https://regex101.com/r/WFpjHV/1
//
let null_matcher = regex::Regex::new(r#"(?:,\n\s*"\w+":\snull)+(,?)|(?:(?:\n)?\s*"\w+":\snull),"#).unwrap();
let null_matcher =
regex::Regex::new(r#"(?:,\n\s*"\w+":\snull)+(,?)|(?:(?:\n)?\s*"\w+":\snull),"#)
.unwrap();
let json = null_matcher.replace_all(&json, "$1");
write!(&mut database_file, "{json}")?;
write!(&mut database_file, "export default {json} as const")?;
database_file.flush()?;
}
@@ -236,11 +242,13 @@ fn write_prefab_map<T: std::io::Write>(
use crate::templates::*;
}
)?;
let enum_tag_regex = regex::Regex::new(r#"templateType:\s"\w+"\.into\(\),"#).unwrap();
let entries = prefabs
.values()
.map(|prefab| {
let hash = prefab.prefab().prefab_hash;
let obj = syn::parse_str::<syn::Expr>(&uneval::to_string(prefab)?)?;
let uneval_src = &uneval::to_string(prefab)?;
let obj = syn::parse_str::<syn::Expr>(&enum_tag_regex.replace_all(&uneval_src, ""))?;
let entry = quote! {
map.insert(#hash, #obj.into());
};