perf: performance improvments

- switch to BTreeMap for consistant ordering of fields (less UI updates)
- cache calls to expensive getters in the vm via witha Proxy on
  DeviceRefs
- have DeviceMixin explicitly subscribe to device property changes to
  limit updates
- split fields into seperate componate to avoid rerender of other
  components
- speedup ic10emu_wasm DeviceRef::get_slots by only calling serde once.

Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
Rachel Powers
2024-04-25 20:38:03 -07:00
parent 2480a08ada
commit cfa240c579
16 changed files with 427 additions and 212 deletions

View File

@@ -12,6 +12,7 @@ import type {
Aliases,
Defines,
Pins,
LogicType,
} from "ic10emu_wasm";
import { structuralEqual } from "utils";
import { LitElement, PropertyValueMap } from "lit";
@@ -21,6 +22,7 @@ type Constructor<T = {}> = new (...args: any[]) => T;
export declare class VMDeviceMixinInterface {
deviceID: number;
activeICId: number;
device: DeviceRef;
name: string | null;
nameHash: number | null;
@@ -41,8 +43,24 @@ export declare class VMDeviceMixinInterface {
_handleDeviceModified(e: CustomEvent): void;
updateDevice(): void;
updateIC(): void;
subscribe(...sub: VMDeviceMixinSubscription[]): void;
unsubscribe(filter: (sub: VMDeviceMixinSubscription) => boolean): void;
}
export type VMDeviceMixinSubscription =
| "name"
| "nameHash"
| "prefabName"
| "fields"
| "slots"
| "slots-count"
| "reagents"
| "connections"
| "ic"
| "active-ic"
| { field: LogicType }
| { slot: number };
export const VMDeviceMixin = <T extends Constructor<LitElement>>(
superClass: T,
) => {
@@ -57,8 +75,23 @@ export const VMDeviceMixin = <T extends Constructor<LitElement>>(
this.updateDevice();
}
@state() private deviceSubscriptions: VMDeviceMixinSubscription[] = [];
subscribe(...sub: VMDeviceMixinSubscription[]) {
this.deviceSubscriptions = this.deviceSubscriptions.concat(sub);
}
// remove subscripotions matching the filter
unsubscribe(filter: (sub: VMDeviceMixinSubscription) => boolean) {
this.deviceSubscriptions = this.deviceSubscriptions.filter(
(sub) => !filter(sub),
);
}
device: DeviceRef;
@state() activeICId: number;
@state() name: string | null = null;
@state() nameHash: number | null = null;
@state() prefabName: string | null;
@@ -107,7 +140,6 @@ export const VMDeviceMixin = <T extends Constructor<LitElement>>(
this._handleDevicesModified.bind(this),
),
);
}
_handleDeviceModified(e: CustomEvent) {
@@ -115,49 +147,93 @@ export const VMDeviceMixin = <T extends Constructor<LitElement>>(
const activeIc = window.VM.vm.activeIC;
if (this.deviceID === id) {
this.updateDevice();
} else if (id === activeIc.id) {
this.requestUpdate();
} else if (id === activeIc.id && this.deviceSubscriptions.includes("active-ic")) {
this.updateDevice();
}
}
_handleDevicesModified(e: CustomEvent) {
_handleDevicesModified(e: CustomEvent<number[]>) {
const activeIc = window.VM.vm.activeIC;
const ids = e.detail;
this.requestUpdate();
if (ids.includes(this.deviceID)) {
this.updateDevice()
} else if (ids.includes(activeIc.id) && this.deviceSubscriptions.includes("active-ic")) {
this.updateDevice();
}
}
updateDevice() {
this.device = window.VM.vm.devices.get(this.deviceID)!;
const name = this.device.name ?? null;
if (this.name !== name) {
this.name = name;
}
const nameHash = this.device.nameHash ?? null;
if (this.nameHash !== nameHash) {
this.nameHash = nameHash;
}
const prefabName = this.device.prefabName ?? null;
if (this.prefabName !== prefabName) {
this.prefabName = prefabName;
}
const fields = this.device.fields;
if (!structuralEqual(this.fields, fields)) {
this.fields = fields;
}
const slots = this.device.slots;
if (!structuralEqual(this.slots, slots)) {
this.slots = slots;
}
const reagents = this.device.reagents;
if (!structuralEqual(this.reagents, reagents)) {
this.reagents = reagents;
}
const connections = this.device.connections;
if (!structuralEqual(this.connections, connections)) {
this.connections = connections;
}
if (typeof this.device.ic !== "undefined") {
this.updateIC();
for (const sub of this.deviceSubscriptions) {
if (typeof sub === "string") {
if (sub == "name") {
const name = this.device.name ?? null;
if (this.name !== name) {
this.name = name;
}
} else if (sub === "nameHash") {
const nameHash = this.device.nameHash ?? null;
if (this.nameHash !== nameHash) {
this.nameHash = nameHash;
}
} else if (sub === "prefabName") {
const prefabName = this.device.prefabName ?? null;
if (this.prefabName !== prefabName) {
this.prefabName = prefabName;
}
} else if (sub === "fields") {
const fields = this.device.fields;
if (!structuralEqual(this.fields, fields)) {
this.fields = fields;
}
} else if (sub === "slots") {
const slots = this.device.slots;
if (!structuralEqual(this.slots, slots)) {
this.slots = slots;
}
} else if (sub === "slots-count") {
const slots = this.device.slots;
if (typeof this.slots === "undefined") {
this.slots = slots;
} else if (this.slots.length !== slots.length) {
this.slots = slots;
}
} else if (sub === "reagents") {
const reagents = this.device.reagents;
if (!structuralEqual(this.reagents, reagents)) {
this.reagents = reagents;
}
} else if (sub === "connections") {
const connections = this.device.connections;
if (!structuralEqual(this.connections, connections)) {
this.connections = connections;
}
} else if (sub === "ic") {
if (typeof this.device.ic !== "undefined") {
this.updateIC();
}
} else if (sub === "active-ic") {
const activeIc = window.VM.vm?.activeIC;
if (this.activeICId !== activeIc.id) {
this.activeICId = activeIc.id;
}
}
} else {
if ( "field" in sub ) {
const fields = this.device.fields;
if (this.fields.get(sub.field) !== fields.get(sub.field)) {
this.fields = fields;
}
} else if ( "slot" in sub) {
const slots = this.device.slots;
if (typeof this.slots === "undefined" || this.slots.length < sub.slot) {
this.slots = slots;
} else if (!structuralEqual(this.slots[sub.slot], slots[sub.slot])) {
this.slots = slots;
}
}
}
}
}
@@ -224,10 +300,12 @@ export const VMActiveICMixin = <T extends Constructor<LitElement>>(
return root;
}
disconnectedCallback(): void {
window.VM.get().then((vm) =>
vm.removeEventListener("vm-run-ic", this._handleDeviceModified.bind(this)),
vm.removeEventListener(
"vm-run-ic",
this._handleDeviceModified.bind(this),
),
);
window.App.app.session.removeEventListener(
"session-active-ic",
@@ -274,7 +352,7 @@ export const VMDeviceDBMixin = <T extends Constructor<LitElement>>(
window.VM.vm.removeEventListener(
"vm-device-db-loaded",
this._handleDeviceDBLoad.bind(this),
)
);
}
_handleDeviceDBLoad(e: CustomEvent) {

View File

@@ -7,6 +7,12 @@ import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.js"
@customElement("vm-ic-controls")
export class VMICControls extends VMActiveICMixin(BaseElement) {
constructor() {
super();
this.subscribe("ic", "active-ic")
}
static styles = [
...defaultCss,
css`

View File

@@ -3,19 +3,11 @@ import { customElement, property, query, state } from "lit/decorators.js";
import { BaseElement, defaultCss } from "components";
import { VMDeviceDBMixin, VMDeviceMixin } from "virtual_machine/base_device";
import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.component.js";
import { displayNumber, parseIntWithHexOrBinary, parseNumber } from "utils";
import {
LogicType,
Slot,
SlotLogicType,
SlotOccupant,
SlotType,
} from "ic10emu_wasm";
import { parseIntWithHexOrBinary, parseNumber } from "utils";
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 "./slot";
import { when } from "lit/directives/when.js";
import { cache } from "lit/directives/cache.js";
import "./fields";
import { until } from "lit/directives/until.js";
import { repeat } from "lit/directives/repeat.js";
@@ -30,6 +22,16 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) {
constructor() {
super();
this.open = false;
this.subscribe(
"prefabName",
"name",
"nameHash",
"reagents",
"slots-count",
"reagents",
"connections",
"active-ic",
);
}
static styles = [
@@ -72,13 +74,6 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) {
.device-name-hash::part(input) {
width: 7rem;
}
.slot-header.image {
width: 1.5rem;
height: 1.5rem;
border: var(--sl-panel-border-width) solid var(--sl-panel-border-color);
border-radius: var(--sl-border-radius-medium);
background-color: var(--sl-color-neutral-0);
}
sl-divider {
--spacing: 0.25rem;
}
@@ -139,12 +134,12 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) {
}
renderHeader(): HTMLTemplateResult {
const activeIc = window.VM.vm.activeIC;
const thisIsActiveIc = activeIc.id === this.deviceID;
const thisIsActiveIc = this.activeICId === this.deviceID;
const badges: HTMLTemplateResult[] = [];
if (this.deviceID == activeIc?.id) {
if (thisIsActiveIc) {
badges.push(html`<sl-badge variant="primary" pill pulse>db</sl-badge>`);
}
const activeIc = window.VM.vm.activeIC;
activeIc?.pins?.forEach((id, index) => {
if (this.deviceID == id) {
badges.push(
@@ -185,18 +180,10 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) {
}
renderFields() {
const fields = Array.from(this.fields.entries());
const inputIdBase = `vmDeviceCard${this.deviceID}Field`;
return this.delayRenderTab("fields", html`
${fields.map(([name, field], _index, _fields) => {
return html` <sl-input id="${inputIdBase}${name}" key="${name}" value="${displayNumber(field.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>
</sl-input>`;
})}
`);
return this.delayRenderTab(
"fields",
html`<vm-device-fields .deviceID=${this.deviceID}></vm-device-fields>`,
);
}
_onSlotImageErr(e: Event) {
@@ -207,18 +194,20 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) {
"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" as const;
async renderSlots() {
return this.delayRenderTab("slots", html`
<div class="flex flex-row flex-wrap">
${repeat(
this.slots,
(_slot, index) => index,
(_slot, index) => html`
<vm-device-slot .deviceID=${this.deviceID} .slotIndex=${index} class-"flex flex-row max-w-lg mr-2 mb-2">
</vm-device-slot>
`,
)}
</div>
`);
return this.delayRenderTab(
"slots",
html`
<div class="flex flex-row flex-wrap">
${repeat(this.slots,
(slot, index) => slot.typ + index.toString(),
(_slot, index) => html`
<vm-device-slot .deviceID=${this.deviceID} .slotIndex=${index} class-"flex flex-row max-w-lg mr-2 mb-2">
</vm-device-slot>
`,
)}
</div>
`,
);
}
renderReagents() {
@@ -242,7 +231,10 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) {
</sl-select>
`;
});
return this.delayRenderTab("networks", html`<div class="networks">${networks}</div>`);
return this.delayRenderTab(
"networks",
html`<div class="networks">${networks}</div>`,
);
}
renderPins() {
@@ -303,7 +295,6 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) {
this.tabResolves[name].resolver(this.tabResolves[name].result);
this.tabsShown.push(name);
}
}
render(): HTMLTemplateResult {
@@ -389,18 +380,6 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) {
this.updateDevice();
});
}
_handleChangeField(e: CustomEvent) {
const input = e.target as SlInput;
const field = input.getAttribute("key")! as LogicType;
const val = parseNumber(input.value);
window.VM.get().then((vm) => {
if (!vm.setDeviceField(this.deviceID, field, val, true)) {
input.value = this.fields.get(field).value.toString();
}
this.updateDevice();
});
}
_handleDeviceRemoveButton(_e: Event) {
this.removeDialog.show();
}

View File

@@ -0,0 +1,42 @@
import { html, css } from "lit";
import { customElement, property } from "lit/decorators.js";
import { BaseElement, defaultCss } from "components";
import { VMDeviceDBMixin, VMDeviceMixin } from "virtual_machine/base_device";
import { displayNumber, parseNumber } from "utils";
import type { LogicType } from "ic10emu_wasm";
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.component.js";
@customElement("vm-device-fields")
export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) {
constructor() {
super();
this.subscribe("fields");
}
render() {
const fields = Array.from(this.fields.entries());
const inputIdBase = `vmDeviceCard${this.deviceID}Field`;
return html`
${fields.map(([name, field], _index, _fields) => {
return html` <sl-input id="${inputIdBase}${name}" key="${name}" value="${displayNumber(field.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>
</sl-input>`;
})}
`;
}
_handleChangeField(e: CustomEvent) {
const input = e.target as SlInput;
const field = input.getAttribute("key")! as LogicType;
const val = parseNumber(input.value);
window.VM.get().then((vm) => {
if (!vm.setDeviceField(this.deviceID, field, val, true)) {
input.value = this.fields.get(field).value.toString();
}
this.updateDevice();
});
}
}

View File

@@ -1,19 +1,17 @@
import { html, css } from "lit";
import { customElement, property, query, state } from "lit/decorators.js";
import { customElement, property} from "lit/decorators.js";
import { BaseElement, defaultCss } from "components";
import { VMDeviceDBMixin, VMDeviceMixin } from "virtual_machine/base_device";
import type { DeviceDB, DeviceDBEntry } from "virtual_machine/device_db";
import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.component.js";
import { clamp, displayNumber, parseIntWithHexOrBinary, parseNumber } from "utils";
import {
LogicType,
Slot,
clamp,
displayNumber,
parseNumber,
} from "utils";
import {
SlotLogicType,
SlotOccupant,
SlotType,
} from "ic10emu_wasm";
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";
import { when } from "lit/directives/when.js";
@@ -24,10 +22,23 @@ export interface SlotModifyEvent {
@customElement("vm-device-slot")
export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) {
@property({ type: Number }) slotIndex: number;
private _slotIndex: number;
get slotIndex() {
return this._slotIndex;
}
@property({ type: Number })
set slotIndex(val: number) {
this._slotIndex = val;
this.unsubscribe((sub) => typeof sub === "object" && "slot" in sub);
this.subscribe({ slot: val });
}
constructor() {
super();
this.subscribe("active-ic");
}
static styles = [
@@ -101,7 +112,7 @@ export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) {
const template = this.slotOcccupantTemplate();
const activeIc = window.VM.vm.activeIC;
const thisIsActiveIc = activeIc.id === this.deviceID;
const thisIsActiveIc = this.activeICId === this.deviceID;
const enableQuantityInput = false;
@@ -109,13 +120,13 @@ export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) {
<div class="flex flex-row me-2">
<div
class="relative shrink-0 border border-neutral-200/40 rounded-lg p-1
hover:ring-2 hover:ring-purple-500 hover:ring-offset-1
hover:ring-offset-purple-500 cursor-pointer me-2"
hover:ring-2 hover:ring-purple-500 hover:ring-offset-1
hover:ring-offset-purple-500 cursor-pointer me-2"
@click=${this._handleSlotClick}
>
<div
class="absolute top-0 left-0 ml-1 mt-1 text-xs
text-neutral-200/90 font-mono bg-neutral-500/40 rounded pl-1 pr-1"
text-neutral-200/90 font-mono bg-neutral-500/40 rounded pl-1 pr-1"
>
<small>${this.slotIndex}</small>
</div>
@@ -127,7 +138,7 @@ export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) {
() =>
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"
text-neutral-200/90 font-mono bg-neutral-500/40 rounded pl-1 pr-1"
>
<small
>${slot.occupant.quantity}/${slot.occupant
@@ -156,22 +167,32 @@ export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) {
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.occupant.quantity.toString()}
.min=${1}
.max=${slot.occupant.max_quantity}
@sl-change=${this._handleSlotQuantityChange}
${enableQuantityInput
? html` <sl-input
type="number"
size="small"
.value=${slot.occupant.quantity.toString()}
.min=${1}
.max=${slot.occupant.max_quantity}
@sl-change=${this._handleSlotQuantityChange}
>
<div slot="help-text">
<span>Max Quantity: ${slot.occupant.max_quantity}</span>
</div>
</sl-input>`
: ""}
<sl-tooltip
content=${thisIsActiveIc && slot.typ === "ProgrammableChip"
? "Removing the selected Active IC is disabled"
: "Remove Occupant"}
>
<div slot="help-text">
<span>Max Quantity: ${slot.occupant.max_quantity}</span>
</div>
</sl-input>` : "" }
<sl-tooltip content=${thisIsActiveIc ? "Removing the selected Active IC is disabled" : "Remove Occupant" }>
<sl-icon-button class="clear-occupant" name="x-octagon" label="Remove" ?disabled=${thisIsActiveIc}
@click=${this._handleSlotOccupantRemove}></sl-icon-button>
<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>
`,
@@ -199,8 +220,18 @@ export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) {
const input = e.currentTarget as SlInput;
const slot = this.slots[this.slotIndex];
const val = clamp(input.valueAsNumber, 1, slot.occupant.max_quantity);
if (!window.VM.vm.setDeviceSlotField(this.deviceID, this.slotIndex, "Quantity", val, true)) {
input.value = this.device.getSlotField(this.slotIndex, "Quantity").toString();
if (
!window.VM.vm.setDeviceSlotField(
this.deviceID,
this.slotIndex,
"Quantity",
val,
true,
)
) {
input.value = this.device
.getSlotField(this.slotIndex, "Quantity")
.toString();
}
}
@@ -255,7 +286,9 @@ export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) {
render() {
return html`
<ic10-details class="slot-card">
<ic10-details
class="slot-card"
>
<div class="slot-header w-full" slot="summary">
${this.renderHeader()}
</div>
@@ -263,4 +296,5 @@ export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) {
</ic10-details>
`;
}
}

View File

@@ -5,6 +5,7 @@ import {
LogicType,
SlotLogicType,
SlotOccupantTemplate,
Slots,
VMRef,
init,
} from "ic10emu_wasm";
@@ -20,9 +21,39 @@ export interface ToastMessage {
id: string;
}
export interface CacheDeviceRef extends DeviceRef {
dirty: boolean
}
function cachedDeviceRef(ref: DeviceRef) {
let slotsDirty = true;
let cachedSlots: Slots = undefined;
return new Proxy<DeviceRef>(ref, {
get(target, prop, receiver) {
if (prop === "slots") {
if (typeof cachedSlots === undefined || slotsDirty) {
cachedSlots = target.slots;
slotsDirty = false;
}
return cachedSlots;
} else if (prop === "dirty") {
return slotsDirty;
}
return Reflect.get(target, prop, receiver);
},
set(target, prop, value) {
if (prop === "dirty") {
slotsDirty = value
return true;
}
return Reflect.set(target, prop, value)
}
}) as CacheDeviceRef
}
class VirtualMachine extends EventTarget {
ic10vm: VMRef;
_devices: Map<number, DeviceRef>;
_devices: Map<number, CacheDeviceRef>;
_ics: Map<number, DeviceRef>;
db: DeviceDB;
@@ -93,7 +124,7 @@ class VirtualMachine extends EventTarget {
const device_ids = this.ic10vm.devices;
for (const id of device_ids) {
if (!this._devices.has(id)) {
this._devices.set(id, this.ic10vm.getDevice(id)!);
this._devices.set(id, cachedDeviceRef(this.ic10vm.getDevice(id)!));
update_flag = true;
}
}
@@ -105,6 +136,7 @@ class VirtualMachine extends EventTarget {
}
for (const [id, device] of this._devices) {
device.dirty = true;
if (typeof device.ic !== "undefined") {
if (!this._ics.has(id)) {
this._ics.set(id, device);
@@ -204,11 +236,13 @@ class VirtualMachine extends EventTarget {
);
}
}, this);
this.updateDevice(this.activeIC, save);
this.updateDevice(this.activeIC.id, save);
if (save) this.app.session.save();
}
updateDevice(device: DeviceRef, save: boolean = true) {
updateDevice(id: number, save: boolean = true) {
const device = this._devices.get(id);
device.dirty = true;
this.dispatchEvent(
new CustomEvent("vm-device-modified", { detail: device.id }),
);
@@ -248,7 +282,7 @@ class VirtualMachine extends EventTarget {
const ic = this.activeIC!;
try {
ic.setRegister(index, val);
this.updateDevice(ic);
this.updateDevice(ic.id);
return true;
} catch (err) {
this.handleVmError(err);
@@ -260,7 +294,7 @@ class VirtualMachine extends EventTarget {
const ic = this.activeIC!;
try {
ic!.setStack(addr, val);
this.updateDevice(ic);
this.updateDevice(ic.id);
return true;
} catch (err) {
this.handleVmError(err);
@@ -296,7 +330,7 @@ class VirtualMachine extends EventTarget {
if (device) {
try {
device.setField(field, val, force);
this.updateDevice(device);
this.updateDevice(device.id);
return true;
} catch (err) {
this.handleVmError(err);
@@ -317,7 +351,7 @@ class VirtualMachine extends EventTarget {
if (device) {
try {
device.setSlotField(slot, field, val, force);
this.updateDevice(device);
this.updateDevice(device.id);
return true;
} catch (err) {
this.handleVmError(err);
@@ -335,7 +369,7 @@ class VirtualMachine extends EventTarget {
if (typeof device !== "undefined") {
try {
this.ic10vm.setDeviceConnection(id, conn, val);
this.updateDevice(device);
this.updateDevice(device.id);
return true;
} catch (err) {
this.handleVmError(err);
@@ -349,7 +383,7 @@ class VirtualMachine extends EventTarget {
if (typeof device !== "undefined") {
try {
this.ic10vm.setPin(id, pin, val);
this.updateDevice(device);
this.updateDevice(device.id);
return true;
} catch (err) {
this.handleVmError(err);
@@ -370,7 +404,7 @@ class VirtualMachine extends EventTarget {
try {
console.log("adding device", template);
const id = this.ic10vm.addDeviceFromTemplate(template);
this._devices.set(id, this.ic10vm.getDevice(id)!);
this._devices.set(id, cachedDeviceRef(this.ic10vm.getDevice(id)!));
const device_ids = this.ic10vm.devices;
this.dispatchEvent(
new CustomEvent("vm-devices-update", {
@@ -402,7 +436,7 @@ class VirtualMachine extends EventTarget {
try {
console.log("setting slot occupant", template);
this.ic10vm.setSlotOccupant(id, index, template);
this.updateDevice(device);
this.updateDevice(device.id);
return true;
} catch (err) {
this.handleVmError(err);
@@ -416,7 +450,7 @@ class VirtualMachine extends EventTarget {
if (typeof device !== "undefined") {
try {
this.ic10vm.removeSlotOccupant(id, index);
this.updateDevice(device);
this.updateDevice(device.id);
return true;
} catch (err) {
this.handleVmError(err);

View File

@@ -40,6 +40,7 @@ export class VMICRegisters extends VMActiveICMixin(BaseElement) {
constructor() {
super();
this.subscribe("ic", "active-ic")
}
protected render() {

View File

@@ -37,6 +37,7 @@ export class VMICStack extends VMActiveICMixin(BaseElement) {
constructor() {
super();
this.subscribe("ic", "active-ic")
}
protected render() {