refactor(ui): start using signals
smaller DOM updates & easier data update paths. fix sl-select problems with force update on signal sub Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
223
rust-testing.ipynb
Normal file
223
rust-testing.ipynb
Normal file
@@ -0,0 +1,223 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
":dep stationeers_data = { path = \"./stationeers_data\" }\n",
|
||||
":dep const-crc32 = \"1.3.0\"\n",
|
||||
":dep color-eyre\n",
|
||||
":dep serde_path_to_error\n",
|
||||
":dep serde_ignored\n",
|
||||
":dep serde\n",
|
||||
":dep serde_json\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 21,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"use color_eyre::eyre;\n",
|
||||
"pub fn parse_value<'a, T: serde::Deserialize<'a>>(\n",
|
||||
" jd: impl serde::Deserializer<'a>,\n",
|
||||
") -> Result<T, color_eyre::Report> {\n",
|
||||
" let mut track = serde_path_to_error::Track::new();\n",
|
||||
" let path = serde_path_to_error::Deserializer::new(jd, &mut track);\n",
|
||||
" let mut fun = |path: serde_ignored::Path| {\n",
|
||||
" eprintln!(\"Found ignored key: {path}\");\n",
|
||||
" };\n",
|
||||
" serde_ignored::deserialize(path, &mut fun).map_err(|e| {\n",
|
||||
" eyre::eyre!(\n",
|
||||
" \"path: {track} | error = {e}\",\n",
|
||||
" track = track.path().to_string(),\n",
|
||||
" )\n",
|
||||
" })\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 25,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{7274344: StructureLogicDevice(StructureLogicDeviceTemplate { prefab: PrefabInfo { prefab_name: \"StructureAutoMinerSmall\", prefab_hash: 7274344, desc: \"The <link=Recurso><color=#0080FFFF>Recurso</color></link> SquareDig autominer is a structure that when built will mine a vertical 2x2 shaft until it hits bedrock. The autominer can be connected to a chute system, and is controllable by a logic network. Note that the autominer outputs more <link=OrePage><color=#0080FFFF>ore</color></link> than a conventional <link=ThingItemMiningDrill><color=green>Mining Drill</color></link> over the same area.\", name: \"Autominer (Small)\" }, structure: StructureInfo { small_grid: true }, thermal_info: None, internal_atmo_info: None, logic: LogicInfo { logic_slot_types: {0: {}, 1: {}}, logic_types: {Power: Read, Open: ReadWrite, Error: Read, Activate: ReadWrite, On: ReadWrite, RequiredPower: Read, ClearMemory: Write, ExportCount: Read, ImportCount: Read, PrefabHash: Read, ReferenceId: Read, NameHash: Read}, modes: None, transmission_receiver: false, wireless_logic: false, circuit_holder: false }, slots: [SlotInfo { name: \"Import\", typ: None }, SlotInfo { name: \"Export\", typ: None }], device: DeviceInfo { connection_list: [ConnectionInfo { typ: Chute, role: Input }, ConnectionInfo { typ: Chute, role: Output }, ConnectionInfo { typ: Data, role: None }, ConnectionInfo { typ: Power, role: None }], device_pins_length: None, has_activate_state: true, has_atmosphere: false, has_color_state: false, has_lock_state: false, has_mode_state: false, has_on_off_state: true, has_open_state: true, has_reagents: false } }), 111280987: ItemLogic(ItemLogicTemplate { prefab: PrefabInfo { prefab_name: \"ItemTerrainManipulator\", prefab_hash: 111280987, desc: \"0.Mode0\\n1.Mode1\", name: \"Terrain Manipulator\" }, item: ItemInfo { consumable: false, filter_type: None, ingredient: false, max_quantity: 1, reagents: None, slot_class: Tool, sorting_class: Default }, thermal_info: None, internal_atmo_info: None, logic: LogicInfo { logic_slot_types: {0: {Occupied: Read, OccupantHash: Read, Quantity: Read, Damage: Read, Charge: Read, ChargeRatio: Read, Class: Read, MaxQuantity: Read, ReferenceId: Read}, 1: {Occupied: Read, OccupantHash: Read, Quantity: Read, Damage: Read, Class: Read, MaxQuantity: Read, ReferenceId: Read}}, logic_types: {Power: Read, Mode: ReadWrite, Error: Read, Activate: ReadWrite, On: ReadWrite, ReferenceId: Read}, modes: Some({0: \"Mode0\", 1: \"Mode1\"}), transmission_receiver: false, wireless_logic: false, circuit_holder: false }, slots: [SlotInfo { name: \"Battery\", typ: Battery }, SlotInfo { name: \"Dirt Canister\", typ: Ore }] })}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"let entries = r#\"\n",
|
||||
"{\n",
|
||||
"\"7274344\": {\n",
|
||||
" \"templateType\": \"StructureLogicDevice\",\n",
|
||||
" \"prefab\": {\n",
|
||||
" \"prefab_name\": \"StructureAutoMinerSmall\",\n",
|
||||
" \"prefab_hash\": 7274344,\n",
|
||||
" \"desc\": \"The <link=Recurso><color=#0080FFFF>Recurso</color></link> SquareDig autominer is a structure that when built will mine a vertical 2x2 shaft until it hits bedrock. The autominer can be connected to a chute system, and is controllable by a logic network. Note that the autominer outputs more <link=OrePage><color=#0080FFFF>ore</color></link> than a conventional <link=ThingItemMiningDrill><color=green>Mining Drill</color></link> over the same area.\",\n",
|
||||
" \"name\": \"Autominer (Small)\"\n",
|
||||
" },\n",
|
||||
" \"structure\": {\n",
|
||||
" \"small_grid\": true\n",
|
||||
" },\n",
|
||||
" \"logic\": {\n",
|
||||
" \"logic_slot_types\": {\n",
|
||||
" \"0\": {},\n",
|
||||
" \"1\": {}\n",
|
||||
" },\n",
|
||||
" \"logic_types\": {\n",
|
||||
" \"Power\": \"Read\",\n",
|
||||
" \"Open\": \"ReadWrite\",\n",
|
||||
" \"Error\": \"Read\",\n",
|
||||
" \"Activate\": \"ReadWrite\",\n",
|
||||
" \"On\": \"ReadWrite\",\n",
|
||||
" \"RequiredPower\": \"Read\",\n",
|
||||
" \"ClearMemory\": \"Write\",\n",
|
||||
" \"ExportCount\": \"Read\",\n",
|
||||
" \"ImportCount\": \"Read\",\n",
|
||||
" \"PrefabHash\": \"Read\",\n",
|
||||
" \"ReferenceId\": \"Read\",\n",
|
||||
" \"NameHash\": \"Read\"\n",
|
||||
" },\n",
|
||||
" \"transmission_receiver\": false,\n",
|
||||
" \"wireless_logic\": false,\n",
|
||||
" \"circuit_holder\": false\n",
|
||||
" },\n",
|
||||
" \"slots\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"Import\",\n",
|
||||
" \"typ\": \"None\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"Export\",\n",
|
||||
" \"typ\": \"None\"\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" \"device\": {\n",
|
||||
" \"connection_list\": [\n",
|
||||
" {\n",
|
||||
" \"typ\": \"Chute\",\n",
|
||||
" \"role\": \"Input\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"typ\": \"Chute\",\n",
|
||||
" \"role\": \"Output\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"typ\": \"Data\",\n",
|
||||
" \"role\": \"None\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"typ\": \"Power\",\n",
|
||||
" \"role\": \"None\"\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" \"has_activate_state\": true,\n",
|
||||
" \"has_atmosphere\": false,\n",
|
||||
" \"has_color_state\": false,\n",
|
||||
" \"has_lock_state\": false,\n",
|
||||
" \"has_mode_state\": false,\n",
|
||||
" \"has_on_off_state\": true,\n",
|
||||
" \"has_open_state\": true,\n",
|
||||
" \"has_reagents\": false\n",
|
||||
" }\n",
|
||||
" },\n",
|
||||
" \"111280987\": {\n",
|
||||
" \"templateType\": \"ItemLogic\",\n",
|
||||
" \"prefab\": {\n",
|
||||
" \"prefab_name\": \"ItemTerrainManipulator\",\n",
|
||||
" \"prefab_hash\": 111280987,\n",
|
||||
" \"desc\": \"0.Mode0\\n1.Mode1\",\n",
|
||||
" \"name\": \"Terrain Manipulator\"\n",
|
||||
" },\n",
|
||||
" \"item\": {\n",
|
||||
" \"consumable\": false,\n",
|
||||
" \"ingredient\": false,\n",
|
||||
" \"max_quantity\": 1,\n",
|
||||
" \"slot_class\": \"Tool\",\n",
|
||||
" \"sorting_class\": \"Default\"\n",
|
||||
" },\n",
|
||||
" \"logic\": {\n",
|
||||
" \"logic_slot_types\": {\n",
|
||||
" \"0\": {\n",
|
||||
" \"Occupied\": \"Read\",\n",
|
||||
" \"OccupantHash\": \"Read\",\n",
|
||||
" \"Quantity\": \"Read\",\n",
|
||||
" \"Damage\": \"Read\",\n",
|
||||
" \"Charge\": \"Read\",\n",
|
||||
" \"ChargeRatio\": \"Read\",\n",
|
||||
" \"Class\": \"Read\",\n",
|
||||
" \"MaxQuantity\": \"Read\",\n",
|
||||
" \"ReferenceId\": \"Read\"\n",
|
||||
" },\n",
|
||||
" \"1\": {\n",
|
||||
" \"Occupied\": \"Read\",\n",
|
||||
" \"OccupantHash\": \"Read\",\n",
|
||||
" \"Quantity\": \"Read\",\n",
|
||||
" \"Damage\": \"Read\",\n",
|
||||
" \"Class\": \"Read\",\n",
|
||||
" \"MaxQuantity\": \"Read\",\n",
|
||||
" \"ReferenceId\": \"Read\"\n",
|
||||
" }\n",
|
||||
" },\n",
|
||||
" \"logic_types\": {\n",
|
||||
" \"Power\": \"Read\",\n",
|
||||
" \"Mode\": \"ReadWrite\",\n",
|
||||
" \"Error\": \"Read\",\n",
|
||||
" \"Activate\": \"ReadWrite\",\n",
|
||||
" \"On\": \"ReadWrite\",\n",
|
||||
" \"ReferenceId\": \"Read\"\n",
|
||||
" },\n",
|
||||
" \"modes\": {\n",
|
||||
" \"0\": \"Mode0\",\n",
|
||||
" \"1\": \"Mode1\"\n",
|
||||
" },\n",
|
||||
" \"transmission_receiver\": false,\n",
|
||||
" \"wireless_logic\": false,\n",
|
||||
" \"circuit_holder\": false\n",
|
||||
" },\n",
|
||||
" \"slots\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"Battery\",\n",
|
||||
" \"typ\": \"Battery\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"Dirt Canister\",\n",
|
||||
" \"typ\": \"Ore\"\n",
|
||||
" }\n",
|
||||
" ]\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"\"#;\n",
|
||||
"use std::collections::BTreeMap;\n",
|
||||
"use stationeers_data::templates::ObjectTemplate;\n",
|
||||
"let parsed_db: BTreeMap<i32, ObjectTemplate> =\n",
|
||||
" parse_value(&mut serde_json::Deserializer::from_str(entries))?;\n",
|
||||
"println!(\"{parsed_db:?}\");"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Rust",
|
||||
"language": "rust",
|
||||
"name": "rust"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": "rust",
|
||||
"file_extension": ".rs",
|
||||
"mimetype": "text/rust",
|
||||
"name": "rust",
|
||||
"pygment_lexer": "rust",
|
||||
"version": ""
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -54,6 +54,8 @@
|
||||
"brnez",
|
||||
"Circuitboard",
|
||||
"codegen",
|
||||
"Comlink",
|
||||
"datapoints",
|
||||
"Depressurising",
|
||||
"deviceslength",
|
||||
"endpos",
|
||||
@@ -62,13 +64,16 @@
|
||||
"hardwrap",
|
||||
"hashables",
|
||||
"hstack",
|
||||
"idxs",
|
||||
"infile",
|
||||
"jetpack",
|
||||
"Keybind",
|
||||
"labelledby",
|
||||
"lbns",
|
||||
"logicable",
|
||||
"LogicSlotType",
|
||||
"logicslottypes",
|
||||
"LogicSlotTypes",
|
||||
"logictype",
|
||||
"logictypes",
|
||||
"lparen",
|
||||
@@ -82,6 +87,7 @@
|
||||
"pedia",
|
||||
"pinf",
|
||||
"popperjs",
|
||||
"preact",
|
||||
"preproc",
|
||||
"Pressurising",
|
||||
"putd",
|
||||
@@ -103,8 +109,6 @@
|
||||
"slotclass",
|
||||
"slotlogic",
|
||||
"slotlogicable",
|
||||
"LogicSlotType",
|
||||
"LogicSlotTypes",
|
||||
"slottype",
|
||||
"sltz",
|
||||
"snan",
|
||||
|
||||
@@ -25,12 +25,12 @@
|
||||
"homepage": "https://github.com/ryex/ic10emu#readme",
|
||||
"devDependencies": {
|
||||
"@oneidentity/zstd-js": "^1.0.3",
|
||||
"@rsbuild/core": "^0.6.4",
|
||||
"@rsbuild/plugin-image-compress": "^0.6.4",
|
||||
"@rsbuild/plugin-type-check": "^0.6.4",
|
||||
"@rspack/cli": "^0.6.2",
|
||||
"@rspack/core": "^0.6.2",
|
||||
"@swc/helpers": "^0.5.10",
|
||||
"@rsbuild/core": "^0.7.10",
|
||||
"@rsbuild/plugin-image-compress": "^0.7.10",
|
||||
"@rsbuild/plugin-type-check": "^0.7.10",
|
||||
"@rspack/cli": "^0.7.5",
|
||||
"@rspack/core": "^0.7.5",
|
||||
"@swc/helpers": "^0.5.12",
|
||||
"@types/ace": "^0.0.52",
|
||||
"@types/bootstrap": "^5.2.10",
|
||||
"@types/wicg-file-system-access": "^2023.10.5",
|
||||
@@ -38,34 +38,35 @@
|
||||
"lit-scss-loader": "^2.0.1",
|
||||
"mini-css-extract-plugin": "^2.9.0",
|
||||
"postcss-loader": "^8.1.1",
|
||||
"sass": "^1.75.0",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"sass": "^1.77.8",
|
||||
"tailwindcss": "^3.4.10",
|
||||
"ts-lit-plugin": "^2.0.2",
|
||||
"ts-loader": "^9.5.1",
|
||||
"typescript": "^5.4.5",
|
||||
"typescript": "^5.5.4",
|
||||
"typescript-lit-html-plugin": "^0.9.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@leeoniya/ufuzzy": "^1.0.14",
|
||||
"@lit/context": "^1.1.1",
|
||||
"@lit-labs/preact-signals": "^1.0.2",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@shoelace-style/shoelace": "^2.15.0",
|
||||
"ace-builds": "^1.33.0",
|
||||
"ace-linters": "^1.2.0",
|
||||
"@shoelace-style/shoelace": "^2.16.0",
|
||||
"ace-builds": "^1.35.4",
|
||||
"ace-linters": "^1.2.3",
|
||||
"bootstrap": "^5.3.3",
|
||||
"bson": "^6.6.0",
|
||||
"bson": "^6.8.0",
|
||||
"buffer": "^6.0.3",
|
||||
"comlink": "^4.4.1",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"ic10emu_wasm": "file:../ic10emu_wasm/pkg",
|
||||
"ic10lsp_wasm": "file:../ic10lsp_wasm/pkg",
|
||||
"ic10emu_wasm": "file:..\\ic10emu_wasm\\pkg",
|
||||
"ic10lsp_wasm": "file:..\\ic10lsp_wasm\\pkg",
|
||||
"idb": "^8.0.0",
|
||||
"jquery": "^3.7.1",
|
||||
"lit": "^3.1.3",
|
||||
"lit": "^3.2.0",
|
||||
"lzma-web": "^3.0.1",
|
||||
"marked": "^12.0.2",
|
||||
"marked": "^14.0.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"uuid": "^9.0.1",
|
||||
"uuid": "^10.0.0",
|
||||
"vm-browserify": "^1.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
6286
www/pnpm-lock.yaml
generated
6286
www/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -14,58 +14,15 @@ import type {
|
||||
LogicSlotType,
|
||||
SlotOccupantInfo,
|
||||
ICState,
|
||||
ObjectTemplate,
|
||||
} from "ic10emu_wasm";
|
||||
import { crc32, structuralEqual } from "utils";
|
||||
import { LitElement, PropertyValueMap } from "lit";
|
||||
|
||||
type Constructor<T = {}> = new (...args: any[]) => T;
|
||||
|
||||
export declare class VMObjectMixinInterface {
|
||||
objectID: ObjectID;
|
||||
activeICId: ObjectID;
|
||||
obj: FrozenObjectFull;
|
||||
name: string | null;
|
||||
nameHash: number | null;
|
||||
prefabName: string | null;
|
||||
prefabHash: number | null;
|
||||
logicFields: Map<LogicType, LogicField> | null;
|
||||
slots: VmObjectSlotInfo[] | null;
|
||||
slotsCount: number | null;
|
||||
reagents: Map<number, number> | null;
|
||||
connections: Connection[] | null;
|
||||
icIP: number | null;
|
||||
icOpCount: number | null;
|
||||
icState: string | null;
|
||||
errors: ICError[] | null;
|
||||
registers: number[] | null;
|
||||
memory: number[] | null;
|
||||
aliases: Map<string, Operand> | null;
|
||||
defines: Map<string, number> | null;
|
||||
numPins: number | null;
|
||||
pins: Map<number, ObjectID> | null;
|
||||
visibleDevices: ObjectID[] | null;
|
||||
_handleDeviceModified(e: CustomEvent): void;
|
||||
updateDevice(): void;
|
||||
updateIC(): void;
|
||||
subscribe(...sub: VMObjectMixinSubscription[]): void;
|
||||
unsubscribe(filter: (sub: VMObjectMixinSubscription) => boolean): void;
|
||||
}
|
||||
|
||||
export type VMObjectMixinSubscription =
|
||||
| "name"
|
||||
| "nameHash"
|
||||
| "prefabName"
|
||||
| "fields"
|
||||
| "slots"
|
||||
| "slots-count"
|
||||
| "reagents"
|
||||
| "connections"
|
||||
| "memory"
|
||||
| "ic"
|
||||
| "active-ic"
|
||||
| { field: LogicType }
|
||||
| { slot: number }
|
||||
| "visible-devices";
|
||||
import {
|
||||
computed,
|
||||
} from '@lit-labs/preact-signals';
|
||||
import type { Signal } from '@lit-labs/preact-signals';
|
||||
|
||||
export interface VmObjectSlotInfo {
|
||||
parent: ObjectID;
|
||||
@@ -74,9 +31,309 @@ export interface VmObjectSlotInfo {
|
||||
typ: Class;
|
||||
logicFields: Map<LogicSlotType, LogicField>;
|
||||
quantity: number;
|
||||
occupant: FrozenObjectFull | undefined;
|
||||
occupant: ComputedObjectSignals | null;
|
||||
}
|
||||
|
||||
export class ComputedObjectSignals {
|
||||
obj: Signal<FrozenObjectFull>;
|
||||
id: Signal<number>;
|
||||
template: Signal<ObjectTemplate>;
|
||||
|
||||
name: Signal<string | null>;
|
||||
nameHash: Signal<number | null>;
|
||||
prefabName: Signal<string | null>;
|
||||
prefabHash: Signal<number | null>;
|
||||
displayName: Signal<string>;
|
||||
logicFields: Signal<Map<LogicType, LogicField> | null>;
|
||||
slots: Signal<VmObjectSlotInfo[] | null>;
|
||||
slotsCount: Signal<number | null>;
|
||||
reagents: Signal<Map<number, number> | null>;
|
||||
|
||||
connections: Signal<Connection[] | null>;
|
||||
visibleDevices: Signal<ComputedObjectSignals[]>;
|
||||
|
||||
memory: Signal<number[] | null>;
|
||||
icIP: Signal<number | null>;
|
||||
icOpCount: Signal<number | null>;
|
||||
icState: Signal<ICState | null>;
|
||||
errors: Signal<ICError[] | null>;
|
||||
registers: Signal<number[] | null>;
|
||||
aliases: Signal<Map<string, Operand> | null>;
|
||||
defines: Signal<Map<string, number> | null>;
|
||||
|
||||
numPins: Signal<number | null>;
|
||||
pins: Signal<Map<number, ObjectID> | null>;
|
||||
|
||||
|
||||
constructor(obj: Signal<FrozenObjectFull>) {
|
||||
this.obj = obj
|
||||
this.id = computed(() => { return this.obj.value.obj_info.id; });
|
||||
|
||||
this.template = computed(() => { return this.obj.value.template; });
|
||||
|
||||
this.name = computed(() => { return this.obj.value.obj_info.name; });
|
||||
this.nameHash = computed(() => { return this.name.value !== "undefined" ? crc32(this.name.value) : null; });
|
||||
this.prefabName = computed(() => { return this.obj.value.obj_info.prefab; });
|
||||
this.prefabHash = computed(() => { return this.obj.value.obj_info.prefab_hash; });
|
||||
this.displayName = computed(() => { return this.obj.value.obj_info.name ?? this.obj.value.obj_info.prefab; });
|
||||
|
||||
this.logicFields = computed(() => {
|
||||
const obj_info = this.obj.value.obj_info;
|
||||
const template = this.obj.value.template;
|
||||
|
||||
const logicValues =
|
||||
obj_info.logic_values != null
|
||||
? (new Map(Object.entries(obj_info.logic_values)) as Map<
|
||||
LogicType,
|
||||
number
|
||||
>)
|
||||
: null;
|
||||
const logicTemplate =
|
||||
"logic" in template ? template.logic : null;
|
||||
|
||||
return new Map(
|
||||
Array.from(Object.entries(logicTemplate?.logic_types) ?? []).map(
|
||||
([lt, access]) => {
|
||||
let field: LogicField = {
|
||||
field_type: access,
|
||||
value: logicValues.get(lt as LogicType) ?? 0,
|
||||
};
|
||||
return [lt as LogicType, field];
|
||||
},
|
||||
),
|
||||
)
|
||||
});
|
||||
|
||||
this.slots = computed(() => {
|
||||
const obj_info = this.obj.value.obj_info;
|
||||
const template = this.obj.value.template;
|
||||
|
||||
const slotsOccupantInfo =
|
||||
obj_info.slots != null
|
||||
? new Map(
|
||||
Object.entries(obj_info.slots).map(([key, val]) => [
|
||||
parseInt(key),
|
||||
val,
|
||||
]),
|
||||
)
|
||||
: null;
|
||||
const slotsLogicValues =
|
||||
obj_info.slot_logic_values != null
|
||||
? new Map<number, Map<LogicSlotType, number>>(
|
||||
Object.entries(obj_info.slot_logic_values).map(
|
||||
([index, values]) => [
|
||||
parseInt(index),
|
||||
new Map(Object.entries(values)) as Map<
|
||||
LogicSlotType,
|
||||
number
|
||||
>,
|
||||
],
|
||||
),
|
||||
)
|
||||
: null;
|
||||
const logicTemplate =
|
||||
"logic" in template ? template.logic : null;
|
||||
const slotsTemplate =
|
||||
"slots" in template ? template.slots : [];
|
||||
|
||||
return slotsTemplate.map((template, index) => {
|
||||
const fieldEntryInfos = Array.from(
|
||||
Object.entries(logicTemplate?.logic_slot_types[index]) ?? [],
|
||||
);
|
||||
const logicFields = new Map(
|
||||
fieldEntryInfos.map(([slt, access]) => {
|
||||
let field: LogicField = {
|
||||
field_type: access,
|
||||
value:
|
||||
slotsLogicValues.get(index)?.get(slt as LogicSlotType) ?? 0,
|
||||
};
|
||||
return [slt as LogicSlotType, field];
|
||||
}),
|
||||
);
|
||||
let occupantInfo = slotsOccupantInfo.get(index);
|
||||
let occupant =
|
||||
typeof occupantInfo !== "undefined"
|
||||
? globalObjectSignalMap.get(occupantInfo.id) ?? null
|
||||
: null;
|
||||
let slot: VmObjectSlotInfo = {
|
||||
parent: obj_info.id,
|
||||
index: index,
|
||||
name: template.name,
|
||||
typ: template.typ,
|
||||
logicFields: logicFields,
|
||||
occupant: occupant,
|
||||
quantity: occupantInfo?.quantity ?? 0,
|
||||
};
|
||||
return slot;
|
||||
});
|
||||
});
|
||||
|
||||
this.slotsCount = computed(() => {
|
||||
const slotsTemplate =
|
||||
"slots" in this.obj.value.template ? this.obj.value.template.slots : [];
|
||||
return slotsTemplate.length;
|
||||
});
|
||||
|
||||
this.reagents = computed(() => {
|
||||
const reagents =
|
||||
this.obj.value.obj_info.reagents != null
|
||||
? new Map(
|
||||
Object.entries(this.obj.value.obj_info.reagents).map(
|
||||
([key, val]) => [parseInt(key), val],
|
||||
),
|
||||
)
|
||||
: null;
|
||||
return reagents;
|
||||
});
|
||||
|
||||
this.connections = computed(() => {
|
||||
const obj_info = this.obj.value.obj_info;
|
||||
const template = this.obj.value.template;
|
||||
|
||||
const connectionsMap =
|
||||
obj_info.connections != null
|
||||
? new Map(
|
||||
Object.entries(obj_info.connections).map(
|
||||
([key, val]) => [parseInt(key), val],
|
||||
),
|
||||
)
|
||||
: null;
|
||||
const connectionList =
|
||||
"device" in template
|
||||
? template.device.connection_list
|
||||
: [];
|
||||
let connections: Connection[] | null = null;
|
||||
if (connectionList.length !== 0) {
|
||||
connections = connectionList.map((conn, index) => {
|
||||
if (conn.typ === "Data") {
|
||||
return {
|
||||
CableNetwork: {
|
||||
typ: "Data",
|
||||
role: conn.role,
|
||||
net: connectionsMap.get(index),
|
||||
},
|
||||
};
|
||||
} else if (conn.typ === "Power") {
|
||||
return {
|
||||
CableNetwork: {
|
||||
typ: "Power",
|
||||
role: conn.role,
|
||||
net: connectionsMap.get(index),
|
||||
},
|
||||
};
|
||||
} else if (conn.typ === "PowerAndData") {
|
||||
return {
|
||||
CableNetwork: {
|
||||
typ: "Data",
|
||||
role: conn.role,
|
||||
net: connectionsMap.get(index),
|
||||
},
|
||||
};
|
||||
} else if (conn.typ === "Pipe") {
|
||||
return { Pipe: { role: conn.role } };
|
||||
} else if (conn.typ === "Chute") {
|
||||
return { Chute: { role: conn.role } };
|
||||
} else if (conn.typ === "Elevator") {
|
||||
return { Elevator: { role: conn.role } };
|
||||
} else if (conn.typ === "LaunchPad") {
|
||||
return { LaunchPad: { role: conn.role } };
|
||||
} else if (conn.typ === "LandingPad") {
|
||||
return { LandingPad: { role: conn.role } };
|
||||
} else if (conn.typ === "PipeLiquid") {
|
||||
return { PipeLiquid: { role: conn.role } };
|
||||
}
|
||||
return "None";
|
||||
});
|
||||
}
|
||||
return connections;
|
||||
});
|
||||
|
||||
this.visibleDevices = computed(() => {
|
||||
return this.obj.value.obj_info.visible_devices.map((id) => globalObjectSignalMap.get(id))
|
||||
});
|
||||
|
||||
this.memory = computed(() => {
|
||||
return this.obj.value.obj_info.memory ?? null;
|
||||
});
|
||||
|
||||
this.icIP = computed(() => {
|
||||
return this.obj.value.obj_info.circuit?.instruction_pointer ?? null;
|
||||
});
|
||||
|
||||
this.icOpCount = computed(() => {
|
||||
return this.obj.value.obj_info.circuit?.yield_instruction_count ?? null;
|
||||
});
|
||||
|
||||
this.icState = computed(() => {
|
||||
return this.obj.value.obj_info.circuit?.state ?? null;
|
||||
});
|
||||
|
||||
this.errors = computed(() => {
|
||||
return this.obj.value.obj_info.compile_errors ?? null;
|
||||
});
|
||||
|
||||
this.registers = computed(() => {
|
||||
return this.obj.value.obj_info.circuit?.registers ?? null;
|
||||
});
|
||||
|
||||
this.aliases = computed(() => {
|
||||
const aliases = this.obj.value.obj_info.circuit?.aliases ?? null;
|
||||
return aliases != null ? new Map(Object.entries(aliases)) : null;
|
||||
});
|
||||
|
||||
this.defines = computed(() => {
|
||||
const defines = this.obj.value.obj_info.circuit?.defines ?? null;
|
||||
return defines != null ? new Map(Object.entries(defines)) : null;
|
||||
});
|
||||
|
||||
this.pins = computed(() => {
|
||||
const pins = this.obj.value.obj_info.device_pins;
|
||||
return pins != null ? new Map(Object.entries(pins).map(([key, val]) => [parseInt(key), val])) : null;
|
||||
});
|
||||
|
||||
this.numPins = computed(() => {
|
||||
return "device" in this.obj.value.template
|
||||
? this.obj.value.template.device.device_pins_length
|
||||
: Math.max(...Array.from(this.pins.value?.keys() ?? [0]));
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class ObjectComputedSignalMap extends Map {
|
||||
get(id: ObjectID): ComputedObjectSignals {
|
||||
if (!this.has(id)) {
|
||||
const obj = window.VM.vm.objects.get(id)
|
||||
if (typeof obj !== "undefined") {
|
||||
this.set(id, new ComputedObjectSignals(obj));
|
||||
}
|
||||
}
|
||||
return super.get(id);
|
||||
}
|
||||
set(id: ObjectID, value: ComputedObjectSignals): this {
|
||||
super.set(id, value);
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
export const globalObjectSignalMap = new ObjectComputedSignalMap();
|
||||
|
||||
type Constructor<T = {}> = new (...args: any[]) => T;
|
||||
|
||||
export declare class VMObjectMixinInterface {
|
||||
objectID: ObjectID;
|
||||
activeICId: ObjectID;
|
||||
objectSignals: ComputedObjectSignals | null;
|
||||
_handleDeviceModified(e: CustomEvent): void;
|
||||
updateDevice(): void;
|
||||
subscribe(...sub: VMObjectMixinSubscription[]): void;
|
||||
unsubscribe(filter: (sub: VMObjectMixinSubscription) => boolean): void;
|
||||
}
|
||||
|
||||
export type VMObjectMixinSubscription =
|
||||
| "active-ic"
|
||||
| "visible-devices";
|
||||
|
||||
export const VMObjectMixin = <T extends Constructor<LitElement>>(
|
||||
superClass: T,
|
||||
) => {
|
||||
@@ -104,31 +361,10 @@ export const VMObjectMixin = <T extends Constructor<LitElement>>(
|
||||
);
|
||||
}
|
||||
|
||||
obj: FrozenObjectFull;
|
||||
@state() objectSignals: ComputedObjectSignals | null;
|
||||
|
||||
@state() activeICId: number;
|
||||
|
||||
@state() name: string | null = null;
|
||||
@state() nameHash: number | null = null;
|
||||
@state() prefabName: string | null = null;
|
||||
@state() prefabHash: number | null = null;
|
||||
@state() logicFields: Map<LogicType, LogicField> | null = null;
|
||||
@state() slots: VmObjectSlotInfo[] | null = null;
|
||||
@state() slotsCount: number | null = null;
|
||||
@state() reagents: Map<number, number> | null = null;
|
||||
@state() connections: Connection[] | null = null;
|
||||
@state() icIP: number | null = null;
|
||||
@state() icOpCount: number | null = null;
|
||||
@state() icState: ICState | null = null;
|
||||
@state() errors: ICError[] | null = null;
|
||||
@state() registers: number[] | null = null;
|
||||
@state() memory: number[] | null = null;
|
||||
@state() aliases: Map<string, Operand> | null = null;
|
||||
@state() defines: Map<string, number> | null = null;
|
||||
@state() numPins: number | null = null;
|
||||
@state() pins: Map<number, ObjectID> | null = null;
|
||||
@state() visibleDevices: ObjectID[] | null = null;
|
||||
|
||||
connectedCallback(): void {
|
||||
const root = super.connectedCallback();
|
||||
window.VM.get().then((vm) => {
|
||||
@@ -246,315 +482,20 @@ export const VMObjectMixin = <T extends Constructor<LitElement>>(
|
||||
}
|
||||
|
||||
updateDevice() {
|
||||
this.obj = window.VM.vm.objects.get(this.objectID)!;
|
||||
const newObjSignals = globalObjectSignalMap.get(this.objectID);
|
||||
if (newObjSignals !== this.objectSignals) {
|
||||
this.objectSignals = newObjSignals
|
||||
}
|
||||
|
||||
if (typeof this.obj === "undefined") {
|
||||
if (typeof this.objectSignals === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
let newFields: Map<LogicType, LogicField> | null = null;
|
||||
if (
|
||||
this.objectSubscriptions.some(
|
||||
(sub) =>
|
||||
sub === "fields" || (typeof sub === "object" && "field" in sub),
|
||||
)
|
||||
) {
|
||||
const logicValues =
|
||||
this.obj.obj_info.logic_values != null
|
||||
? (new Map(Object.entries(this.obj.obj_info.logic_values)) as Map<
|
||||
LogicType,
|
||||
number
|
||||
>)
|
||||
: null;
|
||||
const logicTemplate =
|
||||
"logic" in this.obj.template ? this.obj.template.logic : null;
|
||||
newFields = new Map(
|
||||
Array.from(Object.entries(logicTemplate?.logic_types) ?? []).map(
|
||||
([lt, access]) => {
|
||||
let field: LogicField = {
|
||||
field_type: access,
|
||||
value: logicValues.get(lt as LogicType) ?? 0,
|
||||
};
|
||||
return [lt as LogicType, field];
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
// other updates needed
|
||||
|
||||
const visibleDevices = this.obj.obj_info.visible_devices ?? [];
|
||||
if (!structuralEqual(this.visibleDevices, visibleDevices)) {
|
||||
this.visibleDevices = visibleDevices;
|
||||
}
|
||||
|
||||
let newSlots: VmObjectSlotInfo[] | null = null;
|
||||
if (
|
||||
this.objectSubscriptions.some(
|
||||
(sub) =>
|
||||
sub === "slots" || (typeof sub === "object" && "slot" in sub),
|
||||
)
|
||||
) {
|
||||
const slotsOccupantInfo =
|
||||
this.obj.obj_info.slots != null
|
||||
? new Map(
|
||||
Object.entries(this.obj.obj_info.slots).map(([key, val]) => [
|
||||
parseInt(key),
|
||||
val,
|
||||
]),
|
||||
)
|
||||
: null;
|
||||
const slotsLogicValues =
|
||||
this.obj.obj_info.slot_logic_values != null
|
||||
? new Map<number, Map<LogicSlotType, number>>(
|
||||
Object.entries(this.obj.obj_info.slot_logic_values).map(
|
||||
([index, values]) => [
|
||||
parseInt(index),
|
||||
new Map(Object.entries(values)) as Map<
|
||||
LogicSlotType,
|
||||
number
|
||||
>,
|
||||
],
|
||||
),
|
||||
)
|
||||
: null;
|
||||
const logicTemplate =
|
||||
"logic" in this.obj.template ? this.obj.template.logic : null;
|
||||
const slotsTemplate =
|
||||
"slots" in this.obj.template ? this.obj.template.slots : [];
|
||||
newSlots = slotsTemplate.map((template, index) => {
|
||||
const fieldEntryInfos = Array.from(
|
||||
Object.entries(logicTemplate?.logic_slot_types[index]) ?? [],
|
||||
);
|
||||
const logicFields = new Map(
|
||||
fieldEntryInfos.map(([slt, access]) => {
|
||||
let field: LogicField = {
|
||||
field_type: access,
|
||||
value:
|
||||
slotsLogicValues.get(index)?.get(slt as LogicSlotType) ?? 0,
|
||||
};
|
||||
return [slt as LogicSlotType, field];
|
||||
}),
|
||||
);
|
||||
let occupantInfo = slotsOccupantInfo.get(index);
|
||||
let occupant =
|
||||
typeof occupantInfo !== "undefined"
|
||||
? window.VM.vm.objects.get(occupantInfo.id)
|
||||
: null;
|
||||
let slot: VmObjectSlotInfo = {
|
||||
parent: this.obj.obj_info.id,
|
||||
index: index,
|
||||
name: template.name,
|
||||
typ: template.typ,
|
||||
logicFields: logicFields,
|
||||
occupant: occupant,
|
||||
quantity: occupantInfo?.quantity ?? 0,
|
||||
};
|
||||
return slot;
|
||||
});
|
||||
}
|
||||
|
||||
for (const sub of this.objectSubscriptions) {
|
||||
if (typeof sub === "string") {
|
||||
if (sub == "name") {
|
||||
const name = this.obj.obj_info.name ?? null;
|
||||
if (this.name !== name) {
|
||||
this.name = name;
|
||||
}
|
||||
} else if (sub === "nameHash") {
|
||||
const nameHash =
|
||||
typeof this.obj.obj_info.name !== "undefined"
|
||||
? crc32(this.obj.obj_info.name)
|
||||
: null;
|
||||
if (this.nameHash !== nameHash) {
|
||||
this.nameHash = nameHash;
|
||||
}
|
||||
} else if (sub === "prefabName") {
|
||||
const prefabName = this.obj.obj_info.prefab ?? null;
|
||||
if (this.prefabName !== prefabName) {
|
||||
this.prefabName = prefabName;
|
||||
this.prefabHash = crc32(prefabName);
|
||||
}
|
||||
} else if (sub === "fields") {
|
||||
if (!structuralEqual(this.logicFields, newFields)) {
|
||||
this.logicFields = newFields;
|
||||
}
|
||||
} else if (sub === "slots") {
|
||||
if (!structuralEqual(this.slots, newSlots)) {
|
||||
this.slots = newSlots;
|
||||
this.slotsCount = newSlots.length;
|
||||
}
|
||||
} else if (sub === "slots-count") {
|
||||
const slotsTemplate =
|
||||
"slots" in this.obj.template ? this.obj.template.slots : [];
|
||||
const slotsCount = slotsTemplate.length;
|
||||
if (this.slotsCount !== slotsCount) {
|
||||
this.slotsCount = slotsCount;
|
||||
}
|
||||
} else if (sub === "reagents") {
|
||||
const reagents =
|
||||
this.obj.obj_info.reagents != null
|
||||
? new Map(
|
||||
Object.entries(this.obj.obj_info.reagents).map(
|
||||
([key, val]) => [parseInt(key), val],
|
||||
),
|
||||
)
|
||||
: null;
|
||||
if (!structuralEqual(this.reagents, reagents)) {
|
||||
this.reagents = reagents;
|
||||
}
|
||||
} else if (sub === "connections") {
|
||||
const connectionsMap =
|
||||
this.obj.obj_info.connections != null
|
||||
? new Map(
|
||||
Object.entries(this.obj.obj_info.connections).map(
|
||||
([key, val]) => [parseInt(key), val],
|
||||
),
|
||||
)
|
||||
: null;
|
||||
const connectionList =
|
||||
"device" in this.obj.template
|
||||
? this.obj.template.device.connection_list
|
||||
: [];
|
||||
let connections: Connection[] | null = null;
|
||||
if (connectionList.length !== 0) {
|
||||
connections = connectionList.map((conn, index) => {
|
||||
if (conn.typ === "Data") {
|
||||
return {
|
||||
CableNetwork: {
|
||||
typ: "Data",
|
||||
role: conn.role,
|
||||
net: connectionsMap.get(index),
|
||||
},
|
||||
};
|
||||
} else if (conn.typ === "Power") {
|
||||
return {
|
||||
CableNetwork: {
|
||||
typ: "Power",
|
||||
role: conn.role,
|
||||
net: connectionsMap.get(index),
|
||||
},
|
||||
};
|
||||
} else if (conn.typ === "PowerAndData") {
|
||||
return {
|
||||
CableNetwork: {
|
||||
typ: "Data",
|
||||
role: conn.role,
|
||||
net: connectionsMap.get(index),
|
||||
},
|
||||
};
|
||||
} else if (conn.typ === "Pipe") {
|
||||
return { Pipe: { role: conn.role } };
|
||||
} else if (conn.typ === "Chute") {
|
||||
return { Chute: { role: conn.role } };
|
||||
} else if (conn.typ === "Elevator") {
|
||||
return { Elevator: { role: conn.role } };
|
||||
} else if (conn.typ === "LaunchPad") {
|
||||
return { LaunchPad: { role: conn.role } };
|
||||
} else if (conn.typ === "LandingPad") {
|
||||
return { LandingPad: { role: conn.role } };
|
||||
} else if (conn.typ === "PipeLiquid") {
|
||||
return { PipeLiquid: { role: conn.role } };
|
||||
}
|
||||
return "None";
|
||||
});
|
||||
}
|
||||
if (!structuralEqual(this.connections, connections)) {
|
||||
this.connections = connections;
|
||||
}
|
||||
} else if (sub === "memory") {
|
||||
const stack = this.obj.obj_info.memory ?? null;
|
||||
if (!structuralEqual(this.memory, stack)) {
|
||||
this.memory = stack;
|
||||
}
|
||||
} else if (sub === "ic") {
|
||||
if (
|
||||
typeof this.obj.obj_info.circuit !== "undefined" ||
|
||||
typeof this.obj.obj_info.socketed_ic !== "undefined"
|
||||
) {
|
||||
this.updateIC();
|
||||
}
|
||||
} else if (sub === "active-ic") {
|
||||
const activeIc = window.VM.vm?.activeIC;
|
||||
if (this.activeICId !== activeIc.obj_info.id) {
|
||||
this.activeICId = activeIc.obj_info.id;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ("field" in sub) {
|
||||
if (this.logicFields.get(sub.field) !== newFields.get(sub.field)) {
|
||||
this.logicFields = newFields;
|
||||
}
|
||||
} else if ("slot" in sub) {
|
||||
if (
|
||||
typeof this.slots === "undefined" ||
|
||||
this.slots.length < sub.slot
|
||||
) {
|
||||
this.slots = newSlots;
|
||||
} else if (
|
||||
!structuralEqual(this.slots[sub.slot], newSlots[sub.slot])
|
||||
) {
|
||||
this.slots = newSlots;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateIC() {
|
||||
const ip = this.obj.obj_info.circuit?.instruction_pointer ?? null;
|
||||
if (this.icIP !== ip) {
|
||||
this.icIP = ip;
|
||||
}
|
||||
const opCount =
|
||||
this.obj.obj_info.circuit?.yield_instruction_count ?? null;
|
||||
if (this.icOpCount !== opCount) {
|
||||
this.icOpCount = opCount;
|
||||
}
|
||||
const state = this.obj.obj_info.circuit?.state ?? null;
|
||||
if (this.icState !== state) {
|
||||
this.icState = state;
|
||||
}
|
||||
const errors = this.obj.obj_info.compile_errors ?? null;
|
||||
if (!structuralEqual(this.errors, errors)) {
|
||||
this.errors = errors;
|
||||
}
|
||||
const registers = this.obj.obj_info.circuit?.registers ?? null;
|
||||
if (!structuralEqual(this.registers, registers)) {
|
||||
this.registers = registers;
|
||||
}
|
||||
const aliases =
|
||||
this.obj.obj_info.circuit?.aliases != null
|
||||
? new Map(Object.entries(this.obj.obj_info.circuit.aliases))
|
||||
: null;
|
||||
if (!structuralEqual(this.aliases, aliases)) {
|
||||
this.aliases = aliases;
|
||||
}
|
||||
const defines =
|
||||
this.obj.obj_info.circuit?.defines != null
|
||||
? new Map(
|
||||
Object.entries(this.obj.obj_info.circuit.defines),
|
||||
// .map(([key, val]) => [])
|
||||
)
|
||||
: null;
|
||||
if (!structuralEqual(this.defines, defines)) {
|
||||
this.defines = new Map(defines);
|
||||
}
|
||||
const pins =
|
||||
this.obj.obj_info.device_pins != null
|
||||
? new Map(
|
||||
Object.entries(this.obj.obj_info.device_pins).map(
|
||||
([key, val]) => [parseInt(key), val],
|
||||
),
|
||||
)
|
||||
: null;
|
||||
if (!structuralEqual(this.pins, pins)) {
|
||||
this.pins = pins;
|
||||
this.numPins =
|
||||
"device" in this.obj.template
|
||||
? this.obj.template.device.device_pins_length
|
||||
: Math.max(...Array.from(this.pins?.keys() ?? [0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return VMObjectMixinClass as Constructor<VMObjectMixinInterface> & T;
|
||||
};
|
||||
|
||||
@@ -596,7 +537,6 @@ export const VMActiveICMixin = <T extends Constructor<LitElement>>(
|
||||
const id = e.detail;
|
||||
if (this.objectID !== id) {
|
||||
this.objectID = id;
|
||||
this.obj = window.VM.vm.objects.get(this.objectID)!;
|
||||
}
|
||||
this.updateDevice();
|
||||
}
|
||||
@@ -618,7 +558,7 @@ export const VMTemplateDBMixin = <T extends Constructor<LitElement>>(
|
||||
connectedCallback(): void {
|
||||
const root = super.connectedCallback();
|
||||
window.VM.vm.addEventListener(
|
||||
"vm-device-db-loaded",
|
||||
"vm-template-db-loaded",
|
||||
this._handleDeviceDBLoad.bind(this),
|
||||
);
|
||||
if (typeof window.VM.vm.templateDB !== "undefined") {
|
||||
@@ -644,7 +584,7 @@ export const VMTemplateDBMixin = <T extends Constructor<LitElement>>(
|
||||
return this._templateDB;
|
||||
}
|
||||
|
||||
postDBSetUpdate(): void {}
|
||||
postDBSetUpdate(): void { }
|
||||
|
||||
@state()
|
||||
set templateDB(val: TemplateDatabase) {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
||||
import { VMTemplateDBMixin } from "virtualMachine/baseDevice";
|
||||
import { LogicInfo, ObjectTemplate, StructureInfo } from "ic10emu_wasm";
|
||||
|
||||
type LogicableStrucutureTemplate = Extract<
|
||||
type LogicableStructureTemplate = Extract<
|
||||
ObjectTemplate,
|
||||
{ structure: StructureInfo; logic: LogicInfo }
|
||||
>;
|
||||
@@ -38,7 +38,7 @@ export class VMAddDeviceButton extends VMTemplateDBMixin(BaseElement) {
|
||||
@query("sl-drawer") drawer: SlDrawer;
|
||||
@query(".device-search-input") searchInput: SlInput;
|
||||
|
||||
private _structures: Map<string, LogicableStrucutureTemplate> = new Map();
|
||||
private _structures: Map<string, LogicableStructureTemplate> = new Map();
|
||||
private _datapoints: [string, string][] = [];
|
||||
private _haystack: string[] = [];
|
||||
|
||||
@@ -48,10 +48,10 @@ export class VMAddDeviceButton extends VMTemplateDBMixin(BaseElement) {
|
||||
if ("structure" in template && "logic" in template) {
|
||||
return [[template.prefab.prefab_name, template]] as [
|
||||
string,
|
||||
LogicableStrucutureTemplate,
|
||||
LogicableStructureTemplate,
|
||||
][];
|
||||
} else {
|
||||
return [] as [string, LogicableStrucutureTemplate][];
|
||||
return [] as [string, LogicableStructureTemplate][];
|
||||
}
|
||||
}),
|
||||
);
|
||||
@@ -84,7 +84,7 @@ export class VMAddDeviceButton extends VMTemplateDBMixin(BaseElement) {
|
||||
}
|
||||
|
||||
private _searchResults: {
|
||||
entry: LogicableStrucutureTemplate;
|
||||
entry: LogicableStructureTemplate;
|
||||
haystackEntry: string;
|
||||
ranges: number[];
|
||||
}[] = [];
|
||||
@@ -132,7 +132,7 @@ export class VMAddDeviceButton extends VMTemplateDBMixin(BaseElement) {
|
||||
super.connectedCallback();
|
||||
window.VM.get().then((vm) =>
|
||||
vm.addEventListener(
|
||||
"vm-device-db-loaded",
|
||||
"vm-template-db-loaded",
|
||||
this._handleDeviceDBLoad.bind(this),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { html, css, HTMLTemplateResult } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators.js";
|
||||
import { watch, SignalWatcher, computed } from '@lit-labs/preact-signals';
|
||||
import { BaseElement, defaultCss } from "components";
|
||||
import { VMTemplateDBMixin, VMObjectMixin } from "virtualMachine/baseDevice";
|
||||
import { VMTemplateDBMixin, VMObjectMixin, globalObjectSignalMap } from "virtualMachine/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";
|
||||
@@ -16,7 +17,7 @@ export type CardTab = "fields" | "slots" | "reagents" | "networks" | "pins";
|
||||
|
||||
@customElement("vm-device-card")
|
||||
export class VMDeviceCard extends VMTemplateDBMixin(
|
||||
VMObjectMixin(BaseElement),
|
||||
VMObjectMixin(SignalWatcher(BaseElement)),
|
||||
) {
|
||||
image_err: boolean;
|
||||
|
||||
@@ -26,13 +27,6 @@ export class VMDeviceCard extends VMTemplateDBMixin(
|
||||
super();
|
||||
this.open = false;
|
||||
this.subscribe(
|
||||
"prefabName",
|
||||
"name",
|
||||
"nameHash",
|
||||
"reagents",
|
||||
"slots-count",
|
||||
"reagents",
|
||||
"connections",
|
||||
"active-ic",
|
||||
);
|
||||
}
|
||||
@@ -142,23 +136,12 @@ export class VMDeviceCard extends VMTemplateDBMixin(
|
||||
if (thisIsActiveIc) {
|
||||
badges.push(html`<sl-badge variant="primary" pill pulse>db</sl-badge>`);
|
||||
}
|
||||
const activeIc = window.VM.vm.activeIC;
|
||||
const activeIc = globalObjectSignalMap.get(this.activeICId);
|
||||
|
||||
const numPins =
|
||||
"device" in activeIc?.template
|
||||
? activeIc.template.device.device_pins_length
|
||||
: Math.max(
|
||||
...Array.from(
|
||||
activeIc?.obj_info.device_pins != null
|
||||
? Object.keys(activeIc?.obj_info.device_pins).map((key) =>
|
||||
parseInt(key),
|
||||
)
|
||||
: [0],
|
||||
),
|
||||
);
|
||||
const numPins = activeIc.numPins.value;
|
||||
const pins = new Array(numPins)
|
||||
.fill(true)
|
||||
.map((_, index) => this.pins.get(index));
|
||||
.map((_, index) => this.objectSignals.pins.value.get(index));
|
||||
pins.forEach((id, index) => {
|
||||
if (this.objectID == id) {
|
||||
badges.push(
|
||||
@@ -167,10 +150,10 @@ export class VMDeviceCard extends VMTemplateDBMixin(
|
||||
}
|
||||
}, this);
|
||||
return html`
|
||||
<sl-tooltip content="${this.prefabName}">
|
||||
<sl-tooltip content="${watch(this.objectSignals.prefabName)}">
|
||||
<img
|
||||
class="image me-2"
|
||||
src="img/stationpedia/${this.prefabName}.png"
|
||||
src="img/stationpedia/${watch(this.objectSignals.prefabName)}.png"
|
||||
onerror="this.src = '${VMDeviceCard.transparentImg}'"
|
||||
/>
|
||||
</sl-tooltip>
|
||||
@@ -194,8 +177,8 @@ export class VMDeviceCard extends VMTemplateDBMixin(
|
||||
class="device-name me-1"
|
||||
size="small"
|
||||
pill
|
||||
placeholder=${this.prefabName}
|
||||
value=${this.name}
|
||||
placeholder=${watch(this.objectSignals.prefabName)}
|
||||
value=${watch(this.objectSignals.name)}
|
||||
@sl-change=${this._handleChangeName}
|
||||
>
|
||||
<span slot="prefix">Name</span>
|
||||
@@ -209,7 +192,7 @@ export class VMDeviceCard extends VMTemplateDBMixin(
|
||||
size="small"
|
||||
pill
|
||||
class="device-name-hash me-1"
|
||||
value="${this.nameHash.toString()}"
|
||||
value="${watch(this.objectSignals.nameHash)}"
|
||||
readonly
|
||||
>
|
||||
<span slot="prefix">Hash</span>
|
||||
@@ -257,9 +240,7 @@ export class VMDeviceCard extends VMTemplateDBMixin(
|
||||
"slots",
|
||||
html`
|
||||
<div class="flex flex-row flex-wrap">
|
||||
${repeat(
|
||||
this.slots,
|
||||
(slot, index) => slot.typ + index.toString(),
|
||||
${repeat(Array(this.objectSignals.slotsCount),
|
||||
(_slot, index) => html`
|
||||
<vm-device-slot .deviceID=${this.objectID} .slotIndex=${index} class-"flex flex-row max-w-lg mr-2 mb-2">
|
||||
</vm-device-slot>
|
||||
@@ -276,7 +257,7 @@ export class VMDeviceCard extends VMTemplateDBMixin(
|
||||
|
||||
renderNetworks() {
|
||||
const vmNetworks = window.VM.vm.networks;
|
||||
const networks = this.connections.map((connection, index, _conns) => {
|
||||
const networks = this.objectSignals.connections.value.map((connection, index, _conns) => {
|
||||
const conn =
|
||||
typeof connection === "object" && "CableNetwork" in connection
|
||||
? connection.CableNetwork
|
||||
@@ -357,6 +338,8 @@ export class VMDeviceCard extends VMTemplateDBMixin(
|
||||
}
|
||||
|
||||
render(): HTMLTemplateResult {
|
||||
const disablePins = computed(() => {return !this.objectSignals.numPins.value;});
|
||||
const displayName = computed(() => { return this.objectSignals.name.value ?? this.objectSignals.prefabName.value})
|
||||
return html`
|
||||
<ic10-details class="device-card" ?open=${this.open}>
|
||||
<div class="header" slot="summary">${this.renderHeader()}</div>
|
||||
@@ -365,7 +348,7 @@ export class VMDeviceCard extends VMTemplateDBMixin(
|
||||
<sl-tab slot="nav" panel="slots">Slots</sl-tab>
|
||||
<sl-tab slot="nav" panel="reagents" disabled>Reagents</sl-tab>
|
||||
<sl-tab slot="nav" panel="networks">Networks</sl-tab>
|
||||
<sl-tab slot="nav" panel="pins" ?disabled=${!this.numPins}
|
||||
<sl-tab slot="nav" panel="pins" ?disabled=${watch(disablePins)}
|
||||
>Pins</sl-tab
|
||||
>
|
||||
|
||||
@@ -394,12 +377,12 @@ export class VMDeviceCard extends VMTemplateDBMixin(
|
||||
<div class="remove-dialog-body">
|
||||
<img
|
||||
class="dialog-image mt-auto mb-auto me-2"
|
||||
src="img/stationpedia/${this.prefabName}.png"
|
||||
src="img/stationpedia/${watch(this.objectSignals.prefabName)}.png"
|
||||
onerror="this.src = '${VMDeviceCard.transparentImg}'"
|
||||
/>
|
||||
<div class="flex-g">
|
||||
<p><strong>Are you sure you want to remove this device?</strong></p>
|
||||
<span>Id ${this.objectID} : ${this.name ?? this.prefabName}</span>
|
||||
<span>Id ${this.objectID} : ${watch(displayName)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
@@ -452,7 +435,7 @@ export class VMDeviceCard extends VMTemplateDBMixin(
|
||||
const name = input.value.length === 0 ? undefined : input.value;
|
||||
window.VM.get().then((vm) => {
|
||||
if (!vm.setObjectName(this.objectID, name)) {
|
||||
input.value = this.name;
|
||||
input.value = this.objectSignals.name.value;
|
||||
}
|
||||
this.updateDevice();
|
||||
});
|
||||
|
||||
@@ -5,26 +5,46 @@ import { VMTemplateDBMixin, VMObjectMixin } from "virtualMachine/baseDevice";
|
||||
import { displayNumber, parseNumber } from "utils";
|
||||
import type { LogicType } from "ic10emu_wasm";
|
||||
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.component.js";
|
||||
import { computed, Signal, watch } from "@lit-labs/preact-signals";
|
||||
|
||||
@customElement("vm-device-fields")
|
||||
export class VMDeviceSlot extends VMObjectMixin(VMTemplateDBMixin(BaseElement)) {
|
||||
constructor() {
|
||||
super();
|
||||
this.subscribe("fields");
|
||||
this.setupSignals();
|
||||
}
|
||||
|
||||
setupSignals() {
|
||||
this.logicFieldNames = computed(() => {
|
||||
return Array.from(this.objectSignals.logicFields.value.keys());
|
||||
});
|
||||
}
|
||||
|
||||
logicFieldNames: Signal<LogicType[]>;
|
||||
|
||||
render() {
|
||||
const fields = Array.from(this.logicFields.entries());
|
||||
const inputIdBase = `vmDeviceCard${this.objectID}Field`;
|
||||
return html`
|
||||
${fields.map(([name, field], _index, _fields) => {
|
||||
return html` <sl-input id="${inputIdBase}${name}" key="${name}" value="${displayNumber(field.value)}" size="small"
|
||||
const fieldsHtml = computed(() => {
|
||||
return this.logicFieldNames.value.map((name) => {
|
||||
const field = computed(() => {
|
||||
return this.objectSignals.logicFields.value.get(name);
|
||||
});
|
||||
const typ = computed(() => {
|
||||
return field.value.field_type;
|
||||
});
|
||||
const value = computed(() => {
|
||||
return displayNumber(field.value.value);
|
||||
});
|
||||
return html` <sl-input id="${inputIdBase}${name}" key="${name}" value="${watch(value)}" size="small"
|
||||
@sl-change=${this._handleChangeField}>
|
||||
<span slot="prefix">${name}</span>
|
||||
<sl-copy-button slot="suffix" from="${inputIdBase}${name}.value"></sl-copy-button>
|
||||
<span slot="suffix">${field.field_type}</span>
|
||||
<span slot="suffix">${watch(typ)}</span>
|
||||
</sl-input>`;
|
||||
})}
|
||||
})
|
||||
});
|
||||
return html`
|
||||
${watch(fieldsHtml)}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -34,7 +54,7 @@ export class VMDeviceSlot extends VMObjectMixin(VMTemplateDBMixin(BaseElement))
|
||||
const val = parseNumber(input.value);
|
||||
window.VM.get().then((vm) => {
|
||||
if (!vm.setObjectField(this.objectID, field, val, true)) {
|
||||
input.value = this.logicFields.get(field).value.toString();
|
||||
input.value = this.objectSignals.logicFields.value.get(field).value.toString();
|
||||
}
|
||||
this.updateDevice();
|
||||
});
|
||||
|
||||
@@ -4,22 +4,30 @@ import { BaseElement, defaultCss } from "components";
|
||||
import { VMTemplateDBMixin, VMObjectMixin } from "virtualMachine/baseDevice";
|
||||
import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.component.js";
|
||||
import { ObjectID } from "ic10emu_wasm";
|
||||
import { effect, watch } from "@lit-labs/preact-signals";
|
||||
import { SlOption } from "@shoelace-style/shoelace";
|
||||
|
||||
@customElement("vm-device-pins")
|
||||
export class VMDevicePins extends VMObjectMixin(VMTemplateDBMixin(BaseElement)) {
|
||||
constructor() {
|
||||
super();
|
||||
this.subscribe("ic", "visible-devices");
|
||||
// this.subscribe("visible-devices");
|
||||
}
|
||||
|
||||
render() {
|
||||
const pins = new Array(this.numPins ?? 0)
|
||||
const pins = new Array(this.objectSignals.numPins.value ?? 0)
|
||||
.fill(true)
|
||||
.map((_, index) => this.pins.get(index));
|
||||
const visibleDevices = (this.visibleDevices ?? []).map((id) => window.VM.vm.objects.get(id));
|
||||
.map((_, index) => this.objectSignals.pins.value.get(index));
|
||||
const visibleDevices = (this.objectSignals.visibleDevices.value ?? []);
|
||||
const forceSelectUpdate = () => {
|
||||
const slSelect = this.renderRoot.querySelector("sl-select") as SlSelect;
|
||||
if (slSelect != null) {
|
||||
slSelect.handleValueChange();
|
||||
}
|
||||
};
|
||||
const pinsHtml = pins?.map(
|
||||
(pin, index) =>
|
||||
html` <sl-select
|
||||
(pin, index) => {
|
||||
return html` <sl-select
|
||||
hoist
|
||||
placement="top"
|
||||
clearable
|
||||
@@ -29,14 +37,24 @@ export class VMDevicePins extends VMObjectMixin(VMTemplateDBMixin(BaseElement))
|
||||
>
|
||||
<span slot="prefix">d${index}</span>
|
||||
${visibleDevices.map(
|
||||
(device, _index) => html`
|
||||
<sl-option value=${device.obj_info.id.toString()}>
|
||||
Device ${device.obj_info.id} :
|
||||
${device.obj_info.name ?? device.obj_info.prefab}
|
||||
</sl-option>
|
||||
`,
|
||||
(device, _index) => {
|
||||
device.id.subscribe((id: ObjectID) => {
|
||||
forceSelectUpdate();
|
||||
});
|
||||
device.displayName.subscribe((_: string) => {
|
||||
forceSelectUpdate();
|
||||
});
|
||||
return html`
|
||||
<sl-option value=${watch(device.id)}>
|
||||
Device ${watch(device.id)} :
|
||||
${watch(device.displayName)}
|
||||
</sl-option>
|
||||
`
|
||||
}
|
||||
|
||||
)}
|
||||
</sl-select>`,
|
||||
</sl-select>`;
|
||||
}
|
||||
);
|
||||
return pinsHtml;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { html, css } from "lit";
|
||||
import { customElement, property} from "lit/decorators.js";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { BaseElement, defaultCss } from "components";
|
||||
import { VMTemplateDBMixin, VMObjectMixin } from "virtualMachine/baseDevice";
|
||||
import { VMTemplateDBMixin, VMObjectMixin, VmObjectSlotInfo, ComputedObjectSignals } from "virtualMachine/baseDevice";
|
||||
import {
|
||||
clamp,
|
||||
crc32,
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.component.js";
|
||||
import { VMDeviceCard } from "./card";
|
||||
import { when } from "lit/directives/when.js";
|
||||
import { computed, signal, Signal, SignalWatcher, watch } from "@lit-labs/preact-signals";
|
||||
|
||||
export interface SlotModifyEvent {
|
||||
deviceID: number;
|
||||
@@ -25,24 +26,29 @@ export interface SlotModifyEvent {
|
||||
}
|
||||
|
||||
@customElement("vm-device-slot")
|
||||
export class VMDeviceSlot extends VMObjectMixin(VMTemplateDBMixin(BaseElement)) {
|
||||
private _slotIndex: number;
|
||||
export class VMDeviceSlot extends VMObjectMixin(VMTemplateDBMixin(SignalWatcher(BaseElement))) {
|
||||
private _slotIndex: Signal<number>;
|
||||
|
||||
slotSignal: Signal<VmObjectSlotInfo>;
|
||||
|
||||
get slotIndex() {
|
||||
return this._slotIndex;
|
||||
return this._slotIndex.value;
|
||||
}
|
||||
|
||||
@property({ type: Number })
|
||||
set slotIndex(val: number) {
|
||||
this._slotIndex = val;
|
||||
this.unsubscribe((sub) => typeof sub === "object" && "slot" in sub);
|
||||
this.subscribe({ slot: val });
|
||||
this._slotIndex.value = val;
|
||||
}
|
||||
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.subscribe("active-ic", "prefabName");
|
||||
this._slotIndex = signal(0);
|
||||
this.subscribe("active-ic");
|
||||
this.slotSignal = computed(() => {
|
||||
const index = this._slotIndex.value;
|
||||
return this.objectSignals.slots.value[index];
|
||||
});
|
||||
this.setupSignals();
|
||||
}
|
||||
|
||||
static styles = [
|
||||
@@ -73,49 +79,158 @@ export class VMDeviceSlot extends VMObjectMixin(VMTemplateDBMixin(BaseElement))
|
||||
`,
|
||||
];
|
||||
|
||||
slotOccupantImg(): string {
|
||||
const slot = this.slots[this.slotIndex];
|
||||
if (typeof slot.occupant !== "undefined") {
|
||||
const prefabName = slot.occupant.obj_info.prefab;
|
||||
return `img/stationpedia/${prefabName}.png`;
|
||||
} else {
|
||||
return `img/stationpedia/SlotIcon_${slot.typ}.png`;
|
||||
}
|
||||
setupSignals() {
|
||||
this.slotOccupant = computed(() => {
|
||||
const slot = this.slotSignal.value ?? null;
|
||||
return slot?.occupant ?? null;
|
||||
});
|
||||
this.slotFieldTypes = computed(() => {
|
||||
return Array.from(this.slotSignal.value?.logicFields.keys() ?? []) ;
|
||||
});
|
||||
this.slotOccupantImg = computed(() => {
|
||||
const slot = this.slotSignal.value ?? null;
|
||||
if (slot != null && slot.occupant != null) {
|
||||
const prefabName = slot.occupant.prefabName;
|
||||
return `img/stationpedia/${watch(prefabName)}.png`;
|
||||
} else {
|
||||
return `img/stationpedia/SlotIcon_${slot.typ}.png`;
|
||||
}
|
||||
});
|
||||
this.slotOccupantPrefabName = computed(() => {
|
||||
const slot = this.slotSignal.value ?? null;
|
||||
if (slot != null && slot.occupant != null) {
|
||||
const prefabName = slot.occupant.prefabName.value;
|
||||
return prefabName;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
this.slotOccupantTemplate = computed(() => {
|
||||
if (this.objectSignals != null && "slots" in this.objectSignals.template.value) {
|
||||
return this.objectSignals.template.value.slots[this.slotIndex];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
slotOccupantPrefabName(): string {
|
||||
const slot = this.slots[this.slotIndex];
|
||||
if (typeof slot.occupant !== "undefined") {
|
||||
const prefabName = slot.occupant.obj_info.prefab;
|
||||
return prefabName;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
slotOcccupantTemplate(): SlotInfo | undefined {
|
||||
if ("slots" in this.obj.template) {
|
||||
return this.obj.template.slots[this.slotIndex];
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
slotOccupant: Signal<ComputedObjectSignals | null>;
|
||||
slotFieldTypes: Signal<LogicSlotType[]>;
|
||||
slotOccupantImg: Signal<string>;
|
||||
slotOccupantPrefabName: Signal<string | null>;
|
||||
slotOccupantTemplate: Signal<SlotInfo | null>;
|
||||
|
||||
renderHeader() {
|
||||
const inputIdBase = `vmDeviceSlot${this.objectID}Slot${this.slotIndex}Head`;
|
||||
const slot = this.slots[this.slotIndex];
|
||||
const slotImg = this.slotOccupantImg();
|
||||
// const slot = this.slotSignal.value;
|
||||
const slotImg = this.slotOccupantImg;
|
||||
const img = html`<img
|
||||
class="w-10 h-10"
|
||||
src="${slotImg}"
|
||||
src="${watch(slotImg)}"
|
||||
onerror="this.src = '${VMDeviceCard.transparentImg}'"
|
||||
/>`;
|
||||
const template = this.slotOcccupantTemplate();
|
||||
|
||||
const thisIsActiveIc = this.activeICId === this.objectID;
|
||||
const template = this.slotOccupantTemplate;
|
||||
const templateName = computed(() => {
|
||||
return template.value?.name ?? null;
|
||||
});
|
||||
const slotTyp = computed(() => {
|
||||
return this.slotSignal.value.typ;
|
||||
})
|
||||
|
||||
const enableQuantityInput = false;
|
||||
|
||||
const quantity = computed(() => {
|
||||
const slot = this.slotSignal.value;
|
||||
return slot.quantity;
|
||||
});
|
||||
|
||||
const maxQuantity = computed(() => {
|
||||
const slotOccupant = this.slotSignal.value.occupant;
|
||||
const template = slotOccupant?.template.value ?? null;
|
||||
if (template != null && "item" in template) {
|
||||
return template.item.max_quantity;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
const slotDisplayName = computed(() => {
|
||||
return this.slotOccupantPrefabName.value ?? this.slotSignal.value.typ;
|
||||
});
|
||||
|
||||
const tooltipContent = computed(() => {
|
||||
return this.activeICId === this.objectID && slotTyp.value === "ProgrammableChip"
|
||||
? "Removing the selected Active IC is disabled"
|
||||
: "Remove Occupant"
|
||||
})
|
||||
|
||||
const removeDisabled = computed(() => {
|
||||
return this.activeICId === this.objectID && slotTyp.value === "ProgrammableChip"
|
||||
});
|
||||
|
||||
const quantityContent = computed(() => {
|
||||
if (this.slotOccupant.value != null) {
|
||||
return html`
|
||||
<div
|
||||
class="absolute bottom-0 right-0 mr-1 mb-1 text-xs
|
||||
text-neutral-200/90 font-mono bg-neutral-500/40 rounded pl-1 pr-1"
|
||||
>
|
||||
<small>
|
||||
${watch(quantity)}/${watch(maxQuantity)}
|
||||
</small>
|
||||
</div>`
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
});
|
||||
|
||||
const slotName = computed(() => {
|
||||
if(this.slotOccupant.value != null) {
|
||||
return html` <span> ${watch(this.slotOccupantPrefabName)} </span> `
|
||||
} else {
|
||||
html` <span> ${watch(templateName)} </span> `
|
||||
}
|
||||
});
|
||||
|
||||
const inputContent = computed(() => {
|
||||
if (this.slotOccupant.value != null) {
|
||||
return html`
|
||||
<div class="quantity-input ms-auto pl-2 mt-auto mb-auto me-2">
|
||||
${enableQuantityInput
|
||||
? html`<sl-input
|
||||
type="number"
|
||||
size="small"
|
||||
.value=${watch(quantity)}
|
||||
.min=${1}
|
||||
.max=${watch(maxQuantity)}
|
||||
@sl-change=${this._handleSlotQuantityChange}
|
||||
>
|
||||
<div slot="help-text">
|
||||
<span>
|
||||
Max Quantity:
|
||||
${watch(maxQuantity)}
|
||||
</span>
|
||||
</div>
|
||||
</sl-input>`
|
||||
: ""}
|
||||
<sl-tooltip
|
||||
content=${watch(tooltipContent)}
|
||||
>
|
||||
<sl-icon-button
|
||||
class="clear-occupant"
|
||||
name="x-octagon"
|
||||
label="Remove"
|
||||
?disabled=${watch(removeDisabled)}
|
||||
@click=${this._handleSlotOccupantRemove}
|
||||
></sl-icon-button>
|
||||
</sl-tooltip>
|
||||
</div>
|
||||
`
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
return html`
|
||||
<div class="flex flex-row me-2">
|
||||
<div
|
||||
@@ -130,82 +245,24 @@ export class VMDeviceSlot extends VMObjectMixin(VMTemplateDBMixin(BaseElement))
|
||||
>
|
||||
<small>${this.slotIndex}</small>
|
||||
</div>
|
||||
<sl-tooltip content="${this.slotOccupantPrefabName() ?? slot.typ}">
|
||||
<sl-tooltip content="${watch(slotDisplayName)}">
|
||||
${img}
|
||||
</sl-tooltip>
|
||||
${when(
|
||||
typeof slot.occupant !== "undefined",
|
||||
() =>
|
||||
html`<div
|
||||
class="absolute bottom-0 right-0 mr-1 mb-1 text-xs
|
||||
text-neutral-200/90 font-mono bg-neutral-500/40 rounded pl-1 pr-1"
|
||||
>
|
||||
<small>
|
||||
${slot.quantity}/${"item" in slot.occupant.template
|
||||
? slot.occupant.template.item.max_quantity
|
||||
: 1}
|
||||
</small>
|
||||
</div>`,
|
||||
)}
|
||||
${watch(quantityContent)}
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="flex flex-col justify-end">
|
||||
<div class="text-sm mt-auto mb-auto">
|
||||
${when(
|
||||
typeof slot.occupant !== "undefined",
|
||||
() => html` <span> ${this.slotOccupantPrefabName()} </span> `,
|
||||
() => html` <span> ${template?.name} </span> `,
|
||||
)}
|
||||
${watch(slotName)}
|
||||
</div>
|
||||
<div class="text-neutral-400 text-xs mt-auto flex flex-col mb-1">
|
||||
<div>
|
||||
<strong class="mt-auto mb-auto">Type:</strong
|
||||
><span class="p-1">${slot.typ}</span>
|
||||
><span class="p-1">${watch(slotTyp)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
${when(
|
||||
typeof slot.occupant !== "undefined",
|
||||
() => html`
|
||||
<div class="quantity-input ms-auto pl-2 mt-auto mb-auto me-2">
|
||||
${enableQuantityInput
|
||||
? html` <sl-input
|
||||
type="number"
|
||||
size="small"
|
||||
.value=${slot.quantity.toString()}
|
||||
.min=${1}
|
||||
.max=${"item" in slot.occupant.template
|
||||
? slot.occupant.template.item.max_quantity
|
||||
: 1}
|
||||
@sl-change=${this._handleSlotQuantityChange}
|
||||
>
|
||||
<div slot="help-text">
|
||||
<span>
|
||||
Max Quantity:
|
||||
${"item" in slot.occupant.template
|
||||
? slot.occupant.template.item.max_quantity
|
||||
: 1}
|
||||
</span>
|
||||
</div>
|
||||
</sl-input>`
|
||||
: ""}
|
||||
<sl-tooltip
|
||||
content=${thisIsActiveIc && slot.typ === "ProgrammableChip"
|
||||
? "Removing the selected Active IC is disabled"
|
||||
: "Remove Occupant"}
|
||||
>
|
||||
<sl-icon-button
|
||||
class="clear-occupant"
|
||||
name="x-octagon"
|
||||
label="Remove"
|
||||
?disabled=${thisIsActiveIc && slot.typ === "ProgrammableChip"}
|
||||
@click=${this._handleSlotOccupantRemove}
|
||||
></sl-icon-button>
|
||||
</sl-tooltip>
|
||||
</div>
|
||||
`,
|
||||
() => html``,
|
||||
)}
|
||||
${watch(inputContent)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -226,12 +283,12 @@ export class VMDeviceSlot extends VMObjectMixin(VMTemplateDBMixin(BaseElement))
|
||||
|
||||
_handleSlotQuantityChange(e: Event) {
|
||||
const input = e.currentTarget as SlInput;
|
||||
const slot = this.slots[this.slotIndex];
|
||||
const slot = this.slotSignal.value;
|
||||
const val = clamp(
|
||||
input.valueAsNumber,
|
||||
1,
|
||||
"item" in slot.occupant.template
|
||||
? slot.occupant.template.item.max_quantity
|
||||
"item" in slot.occupant.template.value
|
||||
? slot.occupant.template.value.item.max_quantity
|
||||
: 1,
|
||||
);
|
||||
if (
|
||||
@@ -243,25 +300,33 @@ export class VMDeviceSlot extends VMObjectMixin(VMTemplateDBMixin(BaseElement))
|
||||
true,
|
||||
)
|
||||
) {
|
||||
input.value = this.slots[this.slotIndex].quantity.toString();
|
||||
input.value = this.slotSignal.value.quantity.toString();
|
||||
}
|
||||
}
|
||||
|
||||
renderFields() {
|
||||
const inputIdBase = `vmDeviceSlot${this.objectID}Slot${this.slotIndex}Field`;
|
||||
const _fields =
|
||||
this.slots[this.slotIndex].logicFields ??
|
||||
new Map<LogicSlotType, LogicField>();
|
||||
const fields = Array.from(_fields.entries());
|
||||
|
||||
return html`
|
||||
<div class="slot-fields">
|
||||
${fields.map(
|
||||
([name, field], _index, _fields) => html`
|
||||
const fields = computed(() => {
|
||||
const slot = this.slotSignal.value;
|
||||
const _fields =
|
||||
slot.logicFields??
|
||||
new Map<LogicSlotType, LogicField>();
|
||||
return this.slotFieldTypes.value.map(
|
||||
(name, _index, _types) => {
|
||||
const slotField = computed(() => {
|
||||
return this.slotSignal.value.logicFields.get(name);
|
||||
});
|
||||
const fieldValue = computed(() => {
|
||||
return displayNumber(slotField.value.value);
|
||||
})
|
||||
const fieldAccessType = computed(() => {
|
||||
return slotField.value.field_type;
|
||||
})
|
||||
return html`
|
||||
<sl-input
|
||||
id="${inputIdBase}${name}"
|
||||
key="${name}"
|
||||
value="${displayNumber(field.value)}"
|
||||
value="${watch(fieldValue)}"
|
||||
size="small"
|
||||
@sl-change=${this._handleChangeSlotField}
|
||||
>
|
||||
@@ -270,10 +335,16 @@ export class VMDeviceSlot extends VMObjectMixin(VMTemplateDBMixin(BaseElement))
|
||||
slot="suffix"
|
||||
from="${inputIdBase}${name}.value"
|
||||
></sl-copy-button>
|
||||
<span slot="suffix">${field.field_type}</span>
|
||||
<span slot="suffix">${watch(fieldAccessType)}</span>
|
||||
</sl-input>
|
||||
`,
|
||||
)}
|
||||
`
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
return html`
|
||||
<div class="slot-fields">
|
||||
${watch(fields)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -283,12 +354,12 @@ export class VMDeviceSlot extends VMObjectMixin(VMTemplateDBMixin(BaseElement))
|
||||
const field = input.getAttribute("key")! as LogicSlotType;
|
||||
let val = parseNumber(input.value);
|
||||
if (field === "Quantity") {
|
||||
const slot = this.slots[this.slotIndex];
|
||||
const slot = this.slotSignal.value;
|
||||
val = clamp(
|
||||
input.valueAsNumber,
|
||||
1,
|
||||
"item" in slot.occupant.template
|
||||
? slot.occupant.template.item.max_quantity
|
||||
"item" in slot.occupant.template.value
|
||||
? slot.occupant.template.value.item.max_quantity
|
||||
: 1,
|
||||
);
|
||||
}
|
||||
@@ -297,7 +368,7 @@ export class VMDeviceSlot extends VMObjectMixin(VMTemplateDBMixin(BaseElement))
|
||||
!vm.setObjectSlotField(this.objectID, this.slotIndex, field, val, true)
|
||||
) {
|
||||
input.value = (
|
||||
this.slots[this.slotIndex].logicFields ??
|
||||
this.slotSignal.value.logicFields ??
|
||||
new Map<LogicSlotType, LogicField>()
|
||||
)
|
||||
.get(field)
|
||||
|
||||
@@ -22,6 +22,12 @@ export interface ToastMessage {
|
||||
msg: string;
|
||||
id: string;
|
||||
}
|
||||
import {
|
||||
signal,
|
||||
computed,
|
||||
effect,
|
||||
} from '@lit-labs/preact-signals';
|
||||
import type { Signal } from '@lit-labs/preact-signals';
|
||||
|
||||
export interface VirtualMachineEventMap {
|
||||
"vm-template-db-loaded": CustomEvent<TemplateDatabase>;
|
||||
@@ -40,10 +46,12 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
templateDBPromise: Promise<TemplateDatabase>;
|
||||
templateDB: TemplateDatabase;
|
||||
|
||||
private _objects: Map<number, FrozenObjectFull>;
|
||||
private _circuitHolders: Map<number, FrozenObjectFull>;
|
||||
private _networks: Map<number, FrozenCableNetwork>;
|
||||
private _default_network: number;
|
||||
private _vmState: Signal<FrozenVM>;
|
||||
|
||||
private _objects: Map<number, Signal<FrozenObjectFull>>;
|
||||
private _circuitHolders: Map<number, Signal<FrozenObjectFull>>;
|
||||
private _networks: Map<number, Signal<FrozenCableNetwork>>;
|
||||
private _default_network: Signal<number>;
|
||||
|
||||
private vm_worker: Worker;
|
||||
|
||||
@@ -61,6 +69,9 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
}
|
||||
|
||||
async setupVM() {
|
||||
this.templateDBPromise = this.ic10vm.getTemplateDatabase();
|
||||
this.templateDBPromise.then((db) => this.setupTemplateDatabase(db));
|
||||
|
||||
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 }));
|
||||
@@ -68,17 +79,21 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
console.info("VM Worker loaded");
|
||||
const vm = Comlink.wrap<VMRef>(this.vm_worker);
|
||||
this.ic10vm = vm;
|
||||
this._vmState.value = await this.ic10vm.saveVMState();
|
||||
window.VM.set(this);
|
||||
|
||||
this.templateDBPromise = this.ic10vm.getTemplateDatabase();
|
||||
effect(() => {
|
||||
this.updateObjects(this._vmState.value);
|
||||
this.updateNetworks(this._vmState.value);
|
||||
});
|
||||
|
||||
this.templateDBPromise.then((db) => this.setupTemplateDatabase(db));
|
||||
|
||||
this.updateObjects();
|
||||
this.updateNetworks();
|
||||
this.updateCode();
|
||||
}
|
||||
|
||||
get state() {
|
||||
return this._vmState;
|
||||
}
|
||||
|
||||
get objects() {
|
||||
return this._objects;
|
||||
}
|
||||
@@ -113,41 +128,42 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
return this._circuitHolders.get(this.app.session.activeIC);
|
||||
}
|
||||
|
||||
async visibleDevices(source: number) {
|
||||
const visDevices = await this.ic10vm.visibleDevices(source);
|
||||
const ids = Array.from(visDevices);
|
||||
ids.sort();
|
||||
return ids.map((id, _index) => this._objects.get(id)!);
|
||||
async visibleDevices(source: number): Promise<Signal<FrozenObjectFull>[]> {
|
||||
try {
|
||||
const visDevices = await this.ic10vm.visibleDevices(source);
|
||||
const ids = Array.from(visDevices);
|
||||
ids.sort();
|
||||
return ids.map((id, _index) => this._objects.get(id)!);
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
}
|
||||
}
|
||||
|
||||
async visibleDeviceIds(source: number) {
|
||||
async visibleDeviceIds(source: number): Promise<number[]> {
|
||||
const visDevices = await this.ic10vm.visibleDevices(source);
|
||||
const ids = Array.from(visDevices);
|
||||
ids.sort();
|
||||
return ids;
|
||||
}
|
||||
|
||||
async updateNetworks() {
|
||||
async updateNetworks(state: FrozenVM) {
|
||||
let updateFlag = false;
|
||||
const removedNetworks = [];
|
||||
let networkIds: Uint32Array;
|
||||
let frozenNetworks: FrozenCableNetwork[];
|
||||
try {
|
||||
networkIds = await this.ic10vm.networks;
|
||||
frozenNetworks = await this.ic10vm.freezeNetworks(networkIds);
|
||||
} catch (e) {
|
||||
this.handleVmError(e);
|
||||
return;
|
||||
}
|
||||
const networkIds: ObjectID[] = [];
|
||||
const frozenNetworks: FrozenCableNetwork[] = state.networks;
|
||||
const updatedNetworks: ObjectID[] = [];
|
||||
for (const [index, id] of networkIds.entries()) {
|
||||
|
||||
for (const [index, net] of frozenNetworks.entries()) {
|
||||
const id = net.id;
|
||||
networkIds.push(id);
|
||||
if (!this._networks.has(id)) {
|
||||
this._networks.set(id, frozenNetworks[index]);
|
||||
this._networks.set(id, signal(net));
|
||||
updateFlag = true;
|
||||
updatedNetworks.push(id);
|
||||
} else {
|
||||
if (!structuralEqual(this._networks.get(id), frozenNetworks[index])) {
|
||||
this._networks.set(id, frozenNetworks[index]);
|
||||
const mappedNet = this._networks.get(id);
|
||||
if (!structuralEqual(mappedNet.peek(), net)) {
|
||||
mappedNet.value = net;
|
||||
updatedNetworks.push(id);
|
||||
updateFlag = true;
|
||||
}
|
||||
@@ -173,28 +189,24 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
}
|
||||
}
|
||||
|
||||
async updateObjects() {
|
||||
let updateFlag = false;
|
||||
async updateObjects(state: FrozenVM) {
|
||||
const removedObjects = [];
|
||||
let objectIds: Uint32Array;
|
||||
let frozenObjects: FrozenObjectFull[];
|
||||
try {
|
||||
objectIds = await this.ic10vm.objects;
|
||||
frozenObjects = await this.ic10vm.freezeObjects(objectIds);
|
||||
} catch (e) {
|
||||
this.handleVmError(e);
|
||||
return;
|
||||
}
|
||||
const frozenObjects = state.objects;
|
||||
const objectIds: ObjectID[] = [];
|
||||
const updatedObjects: ObjectID[] = [];
|
||||
let updateFlag = false;
|
||||
|
||||
for (const [index, id] of objectIds.entries()) {
|
||||
for (const [index, obj] of frozenObjects.entries()) {
|
||||
const id = obj.obj_info.id;
|
||||
objectIds.push(id);
|
||||
if (!this._objects.has(id)) {
|
||||
this._objects.set(id, frozenObjects[index]);
|
||||
this._objects.set(id, signal(obj));
|
||||
updateFlag = true;
|
||||
updatedObjects.push(id);
|
||||
} else {
|
||||
if (!structuralEqual(this._objects.get(id), frozenObjects[index])) {
|
||||
this._objects.set(id, frozenObjects[index]);
|
||||
const mappedObject = this._objects.get(id);
|
||||
if (!structuralEqual(obj, mappedObject.peek())) {
|
||||
mappedObject.value = obj;
|
||||
updatedObjects.push(id);
|
||||
updateFlag = true;
|
||||
}
|
||||
@@ -210,7 +222,7 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
}
|
||||
|
||||
for (const [id, obj] of this._objects) {
|
||||
if (typeof obj.obj_info.socketed_ic !== "undefined") {
|
||||
if (typeof obj.peek().obj_info.socketed_ic !== "undefined") {
|
||||
if (!this._circuitHolders.has(id)) {
|
||||
this._circuitHolders.set(id, obj);
|
||||
updateFlag = true;
|
||||
@@ -259,7 +271,7 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
if (
|
||||
circuitHolder &&
|
||||
prog &&
|
||||
circuitHolder.obj_info.source_code !== prog
|
||||
circuitHolder.peek().obj_info.source_code !== prog
|
||||
) {
|
||||
try {
|
||||
console.time(`CompileProgram_${id}_${attempt}`);
|
||||
@@ -281,12 +293,12 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
const ic = this.activeIC;
|
||||
if (ic) {
|
||||
try {
|
||||
await this.ic10vm.stepProgrammable(ic.obj_info.id, false);
|
||||
await this.ic10vm.stepProgrammable(ic.peek().obj_info.id, false);
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
}
|
||||
this.update();
|
||||
this.dispatchCustomEvent("vm-run-ic", this.activeIC!.obj_info.id);
|
||||
this.dispatchCustomEvent("vm-run-ic", this.activeIC!.peek().obj_info.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,55 +306,30 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
const ic = this.activeIC;
|
||||
if (ic) {
|
||||
try {
|
||||
await this.ic10vm.runProgrammable(ic.obj_info.id, false);
|
||||
await this.ic10vm.runProgrammable(ic.peek().obj_info.id, false);
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
}
|
||||
this.update();
|
||||
this.dispatchCustomEvent("vm-run-ic", this.activeIC!.obj_info.id);
|
||||
this.dispatchCustomEvent("vm-run-ic", this.activeIC!.peek().obj_info.id);
|
||||
}
|
||||
}
|
||||
|
||||
async reset() {
|
||||
const ic = this.activeIC;
|
||||
if (ic) {
|
||||
await this.ic10vm.resetProgrammable(ic.obj_info.id);
|
||||
await this.ic10vm.resetProgrammable(ic.peek().obj_info.id);
|
||||
await this.update();
|
||||
}
|
||||
}
|
||||
|
||||
async update(save: boolean = true) {
|
||||
await this.updateObjects();
|
||||
await this.updateNetworks();
|
||||
const lastModified = await this.ic10vm.lastOperationModified;
|
||||
lastModified.forEach((id, _index, _modifiedIds) => {
|
||||
if (this.objects.has(id)) {
|
||||
this.updateObject(id, false);
|
||||
}
|
||||
}, this);
|
||||
const activeIC = this.activeIC;
|
||||
if (activeIC != null) {
|
||||
this.updateObject(activeIC.obj_info.id, false);
|
||||
}
|
||||
if (save) this.app.session.save();
|
||||
}
|
||||
|
||||
async updateObject(id: number, save: boolean = true) {
|
||||
let frozen;
|
||||
try {
|
||||
frozen = await this.ic10vm.freezeObject(id);
|
||||
this._objects.set(id, frozen);
|
||||
} catch (e) {
|
||||
this.handleVmError(e);
|
||||
this._vmState.value = await this.ic10vm.saveVMState();
|
||||
if (save) this.app.session.save();
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
}
|
||||
const device = this._objects.get(id);
|
||||
this.dispatchCustomEvent("vm-object-modified", device.obj_info.id);
|
||||
if (typeof device.obj_info.socketed_ic !== "undefined") {
|
||||
const ic = this._objects.get(device.obj_info.socketed_ic);
|
||||
const ip = ic.obj_info.circuit?.instruction_pointer;
|
||||
this.app.session.setActiveLine(device.obj_info.id, ip);
|
||||
}
|
||||
if (save) this.app.session.save();
|
||||
}
|
||||
|
||||
handleVmError(err: Error) {
|
||||
@@ -359,7 +346,7 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
|
||||
// return the data connected oject ids for a network
|
||||
networkDataDevices(network: ObjectID): number[] {
|
||||
return this._networks.get(network)?.devices ?? [];
|
||||
return this._networks.get(network)?.peek().devices ?? [];
|
||||
}
|
||||
|
||||
async changeObjectID(oldID: number, newID: number): Promise<boolean> {
|
||||
@@ -368,7 +355,7 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
if (this.app.session.activeIC === oldID) {
|
||||
this.app.session.activeIC = newID;
|
||||
}
|
||||
await this.updateObjects();
|
||||
await this.update();
|
||||
this.dispatchCustomEvent("vm-object-id-change", {
|
||||
old: oldID,
|
||||
new: newID,
|
||||
@@ -383,25 +370,29 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
|
||||
async setRegister(index: number, val: number): Promise<boolean> {
|
||||
const ic = this.activeIC!;
|
||||
try {
|
||||
await this.ic10vm.setRegister(ic.obj_info.id, index, val);
|
||||
this.updateObject(ic.obj_info.id);
|
||||
if (ic) {
|
||||
try {
|
||||
await this.ic10vm.setRegister(ic.peek().obj_info.id, index, val);
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
return false;
|
||||
}
|
||||
await this.update();
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async setStack(addr: number, val: number): Promise<boolean> {
|
||||
const ic = this.activeIC!;
|
||||
try {
|
||||
await this.ic10vm.setMemory(ic.obj_info.id, addr, val);
|
||||
this.updateObject(ic.obj_info.id);
|
||||
if (ic) {
|
||||
try {
|
||||
await this.ic10vm.setMemory(ic.peek().obj_info.id, addr, val);
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
return false;
|
||||
}
|
||||
await this.update();
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,13 +400,13 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
const obj = this._objects.get(id);
|
||||
if (obj) {
|
||||
try {
|
||||
await this.ic10vm.setObjectName(obj.obj_info.id, name);
|
||||
this.updateObject(obj.obj_info.id);
|
||||
this.app.session.save();
|
||||
return true;
|
||||
await this.ic10vm.setObjectName(obj.peek().obj_info.id, name);
|
||||
} catch (e) {
|
||||
this.handleVmError(e);
|
||||
return false;
|
||||
}
|
||||
await this.update();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -430,12 +421,13 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
const obj = this._objects.get(id);
|
||||
if (obj) {
|
||||
try {
|
||||
await this.ic10vm.setLogicField(obj.obj_info.id, field, val, force);
|
||||
this.updateObject(obj.obj_info.id);
|
||||
return true;
|
||||
await this.ic10vm.setLogicField(obj.peek().obj_info.id, field, val, force);
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
return false;
|
||||
}
|
||||
await this.update();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -452,17 +444,18 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
if (obj) {
|
||||
try {
|
||||
await this.ic10vm.setSlotLogicField(
|
||||
obj.obj_info.id,
|
||||
obj.peek().obj_info.id,
|
||||
field,
|
||||
slot,
|
||||
val,
|
||||
force,
|
||||
);
|
||||
this.updateObject(obj.obj_info.id);
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
return false;
|
||||
}
|
||||
await this.update();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -476,11 +469,12 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
if (typeof device !== "undefined") {
|
||||
try {
|
||||
await this.ic10vm.setDeviceConnection(id, conn, val);
|
||||
this.updateObject(device.obj_info.id);
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
return false;
|
||||
}
|
||||
await this.update();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -494,11 +488,12 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
if (typeof device !== "undefined") {
|
||||
try {
|
||||
await this.ic10vm.setPin(id, pin, val);
|
||||
this.updateObject(device.obj_info.id);
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
return false;
|
||||
}
|
||||
await this.update();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -513,11 +508,7 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
try {
|
||||
console.log("adding device", frozen);
|
||||
const id = await this.ic10vm.addObjectFrozen(frozen);
|
||||
const refrozen = await this.ic10vm.freezeObject(id);
|
||||
this._objects.set(id, refrozen);
|
||||
const device_ids = await this.ic10vm.objects;
|
||||
this.dispatchCustomEvent("vm-objects-update", Array.from(device_ids));
|
||||
this.app.session.save();
|
||||
await this.update();
|
||||
return id;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
@@ -531,13 +522,7 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
try {
|
||||
console.log("adding devices", frozenObjects);
|
||||
const ids = await this.ic10vm.addObjectsFrozen(frozenObjects);
|
||||
const refrozen = await this.ic10vm.freezeObjects(ids);
|
||||
ids.forEach((id, index) => {
|
||||
this._objects.set(id, refrozen[index]);
|
||||
});
|
||||
const device_ids = await this.ic10vm.objects;
|
||||
this.dispatchCustomEvent("vm-objects-update", Array.from(device_ids));
|
||||
this.app.session.save();
|
||||
await this.update();
|
||||
return Array.from(ids);
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
@@ -548,12 +533,12 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
async removeDevice(id: number): Promise<boolean> {
|
||||
try {
|
||||
await this.ic10vm.removeDevice(id);
|
||||
await this.updateObjects();
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
return false;
|
||||
}
|
||||
await this.update();
|
||||
return true;
|
||||
}
|
||||
|
||||
async setSlotOccupant(
|
||||
@@ -567,7 +552,7 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
try {
|
||||
console.log("setting slot occupant", frozen);
|
||||
await this.ic10vm.setSlotOccupant(id, index, frozen, quantity);
|
||||
this.updateObject(device.obj_info.id);
|
||||
await this.update();
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
@@ -580,8 +565,8 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
const device = this._objects.get(id);
|
||||
if (typeof device !== "undefined") {
|
||||
try {
|
||||
this.ic10vm.removeSlotOccupant(id, index);
|
||||
this.updateObject(device.obj_info.id);
|
||||
await this.ic10vm.removeSlotOccupant(id, index);
|
||||
await this.update();
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
@@ -591,7 +576,7 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
}
|
||||
|
||||
async saveVMState(): Promise<FrozenVM> {
|
||||
return this.ic10vm.saveVMState();
|
||||
return await this.ic10vm.saveVMState();
|
||||
}
|
||||
|
||||
async restoreVMState(state: FrozenVM) {
|
||||
@@ -599,7 +584,7 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
await this.ic10vm.restoreVMState(state);
|
||||
this._objects = new Map();
|
||||
this._circuitHolders = new Map();
|
||||
await this.updateObjects();
|
||||
await this.update();
|
||||
} catch (e) {
|
||||
this.handleVmError(e);
|
||||
}
|
||||
@@ -608,7 +593,7 @@ class VirtualMachine extends TypedEventTarget<VirtualMachineEventMap>() {
|
||||
getPrograms(): [number, string][] {
|
||||
const programs: [number, string][] = Array.from(
|
||||
this._circuitHolders.entries(),
|
||||
).map(([id, ic]) => [id, ic.obj_info.source_code]);
|
||||
).map(([id, ic]) => [id, ic.peek().obj_info.source_code]);
|
||||
return programs;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user