refactor(frontend): fix base template component
This commit is contained in:
@@ -123,14 +123,14 @@ export class VMICControls extends VMActiveICMixin(BaseElement) {
|
||||
${ics.map(
|
||||
([id, device], _index) =>
|
||||
html`<sl-option
|
||||
name=${device.name}
|
||||
prefabName=${device.prefabName}
|
||||
name=${device.obj_info.name}
|
||||
prefabName=${device.obj_info.prefab}
|
||||
value=${id}
|
||||
>
|
||||
${device.name
|
||||
? html`<span slot="suffix">${device.prefabName}</span>`
|
||||
${device.obj_info.name
|
||||
? html`<span slot="suffix">${device.obj_info.prefab}</span>`
|
||||
: ""}
|
||||
Device:${id} ${device.name ?? device.prefabName}
|
||||
Device:${id} ${device.obj_info.name ?? device.obj_info.prefab}
|
||||
</sl-option>`,
|
||||
)}
|
||||
</sl-select>
|
||||
@@ -156,13 +156,16 @@ export class VMICControls extends VMActiveICMixin(BaseElement) {
|
||||
<span>Errors</span>
|
||||
${this.errors.map(
|
||||
(err) =>
|
||||
html`<div class="hstack">
|
||||
<span>
|
||||
Line: ${err.ParseError.line} -
|
||||
${err.ParseError.start}:${err.ParseError.end}
|
||||
</span>
|
||||
<span class="ms-auto">${err.ParseError.msg}</span>
|
||||
</div>`,
|
||||
typeof err === "object"
|
||||
&& "ParseError" in err
|
||||
? html`<div class="hstack">
|
||||
<span>
|
||||
Line: ${err.ParseError.line} -
|
||||
${"ParseError" in err ? err.ParseError.start : "N/A"}:${err.ParseError.end}
|
||||
</span>
|
||||
<span class="ms-auto">${err.ParseError.msg}</span>
|
||||
</div>`
|
||||
: html`${JSON.stringify(err)}`,
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -432,7 +432,7 @@ export class VMDeviceCard extends VMTemplateDBMixin(
|
||||
const val = parseIntWithHexOrBinary(input.value);
|
||||
if (!isNaN(val)) {
|
||||
window.VM.get().then((vm) => {
|
||||
if (!vm.changeDeviceID(this.objectID, val)) {
|
||||
if (!vm.changeObjectID(this.objectID, val)) {
|
||||
input.value = this.objectID.toString();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,16 +1,58 @@
|
||||
import { Connection } from "ic10emu_wasm";
|
||||
import { DeviceDBConnection } from "../device_db";
|
||||
|
||||
const CableNetworkTypes: readonly string[] = Object.freeze(["Power", "Data", "PowerAndData"]);
|
||||
export function connectionFromDeviceDBConnection(conn: DeviceDBConnection): Connection {
|
||||
if (CableNetworkTypes.includes(conn.typ)) {
|
||||
return {
|
||||
import {
|
||||
Connection,
|
||||
ConnectionInfo,
|
||||
CableConnectionType,
|
||||
} from "ic10emu_wasm";
|
||||
export function connectionFromConnectionInfo(conn: ConnectionInfo): Connection {
|
||||
let connection: Connection = "None";
|
||||
if (
|
||||
conn.typ === "Power" ||
|
||||
conn.typ === "Data" ||
|
||||
conn.typ === "PowerAndData"
|
||||
) {
|
||||
connection = {
|
||||
CableNetwork: {
|
||||
net: window.VM.vm.ic10vm.defaultNetwork,
|
||||
typ: conn.typ
|
||||
}
|
||||
net: window.VM.vm.defaultNetwork,
|
||||
typ: conn.typ as CableConnectionType,
|
||||
role: conn.role,
|
||||
},
|
||||
};
|
||||
} else if (conn.typ === "Pipe") {
|
||||
connection = {
|
||||
Pipe: {
|
||||
role: conn.role,
|
||||
},
|
||||
};
|
||||
} else if (conn.typ === "PipeLiquid") {
|
||||
connection = {
|
||||
PipeLiquid: {
|
||||
role: conn.role,
|
||||
},
|
||||
};
|
||||
} else if (conn.typ === "Chute") {
|
||||
connection = {
|
||||
Chute: {
|
||||
role: conn.role,
|
||||
},
|
||||
};
|
||||
} else if (conn.typ === "Elevator") {
|
||||
connection = {
|
||||
Elevator: {
|
||||
role: conn.role,
|
||||
},
|
||||
};
|
||||
} else if (conn.typ === "LaunchPad") {
|
||||
connection = {
|
||||
LaunchPad: {
|
||||
role: conn.role,
|
||||
},
|
||||
};
|
||||
} else if (conn.typ === "LandingPad") {
|
||||
connection = {
|
||||
LandingPad: {
|
||||
role: conn.role,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
return "Other";
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
@@ -4,18 +4,42 @@ import type {
|
||||
LogicField,
|
||||
LogicType,
|
||||
Slot,
|
||||
Class,
|
||||
FrozenObject,
|
||||
MemoryAccess,
|
||||
SlotInfo,
|
||||
ConnectionInfo,
|
||||
ObjectID,
|
||||
CableConnectionType,
|
||||
ConnectionRole,
|
||||
ObjectInfo,
|
||||
SlotOccupantInfo,
|
||||
} from "ic10emu_wasm";
|
||||
import { html, css, HTMLTemplateResult } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators.js";
|
||||
import { BaseElement, defaultCss } from "components";
|
||||
|
||||
import { connectionFromDeviceDBConnection } from "./dbutils";
|
||||
import { connectionFromConnectionInfo } from "./dbutils";
|
||||
import { crc32, displayNumber, parseNumber } from "utils";
|
||||
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.component.js";
|
||||
import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.component.js";
|
||||
import { VMDeviceCard } from "./card";
|
||||
import { VMTemplateDBMixin } from "virtual_machine/base_device";
|
||||
|
||||
export interface SlotTemplate {
|
||||
typ: Class
|
||||
quantity: number,
|
||||
occupant?: FrozenObject,
|
||||
}
|
||||
|
||||
export interface ConnectionCableNetwork {
|
||||
CableNetwork: {
|
||||
net: ObjectID | undefined;
|
||||
typ: CableConnectionType;
|
||||
role: ConnectionRole;
|
||||
};
|
||||
}
|
||||
|
||||
@customElement("vm-device-template")
|
||||
export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
|
||||
|
||||
@@ -51,11 +75,12 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
|
||||
`,
|
||||
];
|
||||
|
||||
@state() fields: { [key in LogicType]?: LogicField };
|
||||
@state() fields: Map<LogicType, number>;
|
||||
@state() slots: SlotTemplate[];
|
||||
@state() template: ObjectTemplate;
|
||||
@state() device_id: number | undefined;
|
||||
@state() device_name: string | undefined;
|
||||
@state() pins: (ObjectID | undefined)[];
|
||||
@state() template: FrozenObject;
|
||||
@state() objectId: number | undefined;
|
||||
@state() objectName: string | undefined;
|
||||
@state() connections: Connection[];
|
||||
|
||||
constructor() {
|
||||
@@ -63,41 +88,61 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
|
||||
this.templateDB = window.VM.vm.templateDB;
|
||||
}
|
||||
|
||||
private _prefab_name: string;
|
||||
private _prefabName: string;
|
||||
private _prefabHash: number;
|
||||
|
||||
get prefab_name(): string {
|
||||
return this._prefab_name;
|
||||
|
||||
get prefabName(): string {
|
||||
return this._prefabName;
|
||||
}
|
||||
get prefabHash(): number {
|
||||
return this._prefabHash;
|
||||
}
|
||||
|
||||
@property({ type: String })
|
||||
set prefab_name(val: string) {
|
||||
this._prefab_name = val;
|
||||
set prefabName(val: string) {
|
||||
this._prefabName = val;
|
||||
this._prefabHash = crc32(this._prefabName);
|
||||
this.setupState();
|
||||
}
|
||||
|
||||
get dbTemplate(): ObjectTemplate {
|
||||
return this.templateDB.get( crc32(this.prefab_name));
|
||||
return this.templateDB.get(this._prefabHash);
|
||||
}
|
||||
|
||||
setupState() {
|
||||
const dbTemplate = this.dbTemplate;
|
||||
|
||||
this.fields = Object.fromEntries(
|
||||
Object.entries(this.dbTemplate?.logic ?? {}).map(([lt, ft]) => {
|
||||
const value = lt === "PrefabHash" ? this.dbTemplate.prefab.prefab_hash : 0.0;
|
||||
return [lt, { field_type: ft, value } as LogicField];
|
||||
this.fields = new Map(
|
||||
(
|
||||
Array.from(
|
||||
"logic" in dbTemplate
|
||||
? dbTemplate.logic.logic_types.entries() ?? []
|
||||
: [],
|
||||
) as [LogicType, MemoryAccess][]
|
||||
).map(([lt, access]) => {
|
||||
const value =
|
||||
lt === "PrefabHash" ? this.dbTemplate.prefab.prefab_hash : 0.0;
|
||||
return [lt, value];
|
||||
}),
|
||||
);
|
||||
|
||||
this.slots = (this.dbTemplate?.slots ?? []).map(
|
||||
this.slots = (
|
||||
("slots" in dbTemplate ? dbTemplate.slots ?? [] : []) as SlotInfo[]
|
||||
).map(
|
||||
(slot, _index) =>
|
||||
({
|
||||
typ: slot.typ,
|
||||
quantity: 0,
|
||||
}) as SlotTemplate,
|
||||
);
|
||||
|
||||
const connections = Object.entries(this.dbTemplate?.conn ?? {}).map(
|
||||
([index, conn]) =>
|
||||
[index, connectionFromDeviceDBConnection(conn)] as const,
|
||||
const connections = (
|
||||
"device" in dbTemplate
|
||||
? dbTemplate.device.connection_list
|
||||
: ([] as ConnectionInfo[])
|
||||
).map(
|
||||
(conn, index) => [index, connectionFromConnectionInfo(conn)] as const,
|
||||
);
|
||||
connections.sort((a, b) => {
|
||||
if (a[0] < b[0]) {
|
||||
@@ -110,12 +155,15 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
|
||||
});
|
||||
|
||||
this.connections = connections.map((conn) => conn[1]);
|
||||
|
||||
const numPins = "device" in dbTemplate ? dbTemplate.device.device_pins_length : 0;
|
||||
this.pins = new Array(numPins).fill(undefined);
|
||||
}
|
||||
renderFields(): HTMLTemplateResult {
|
||||
const fields = Object.entries(this.fields);
|
||||
return html`
|
||||
${fields.map(([name, field], _index, _fields) => {
|
||||
return html`
|
||||
return html`
|
||||
<sl-input
|
||||
key="${name}"
|
||||
value="${displayNumber(field.value)}"
|
||||
@@ -127,7 +175,7 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
|
||||
<span slot="suffix">${field.field_type}</span>
|
||||
</sl-input>
|
||||
`;
|
||||
})}
|
||||
})}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -135,9 +183,9 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
|
||||
const input = e.target as SlInput;
|
||||
const field = input.getAttribute("key")! as LogicType;
|
||||
const val = parseNumber(input.value);
|
||||
this.fields[field].value = val;
|
||||
this.fields.set(field, val);
|
||||
if (field === "ReferenceId" && val !== 0) {
|
||||
this.device_id = val;
|
||||
this.objectId = val;
|
||||
}
|
||||
this.requestUpdate();
|
||||
}
|
||||
@@ -161,9 +209,11 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
|
||||
return html`
|
||||
<div class="networks">
|
||||
${connections.map((connection, index, _conns) => {
|
||||
const conn =
|
||||
typeof connection === "object" ? connection.CableNetwork : null;
|
||||
return html`
|
||||
const conn =
|
||||
typeof connection === "object" && "CableNetwork" in connection
|
||||
? connection.CableNetwork
|
||||
: null;
|
||||
return html`
|
||||
<sl-select
|
||||
hoist
|
||||
placement="top"
|
||||
@@ -175,13 +225,13 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
|
||||
>
|
||||
<span slot="prefix">Connection:${index} </span>
|
||||
${vmNetworks.map(
|
||||
(net) =>
|
||||
html`<sl-option value=${net}>Network ${net}</sl-option>`,
|
||||
)}
|
||||
(net) =>
|
||||
html`<sl-option value=${net}>Network ${net}</sl-option>`,
|
||||
)}
|
||||
<span slot="prefix"> ${conn?.typ} </span>
|
||||
</sl-select>
|
||||
`;
|
||||
})}
|
||||
})}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -195,8 +245,48 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
|
||||
}
|
||||
|
||||
renderPins(): HTMLTemplateResult {
|
||||
const device = this.templateDB.db[this.prefab_name];
|
||||
return html`<div class="pins"></div>`;
|
||||
const networks = this.connections.flatMap((connection, index) => {
|
||||
return typeof connection === "object" && "CableNetwork" in connection
|
||||
? [connection.CableNetwork.net]
|
||||
: [];
|
||||
});
|
||||
const visibleDeviceIds = [
|
||||
...new Set(
|
||||
networks.flatMap((net) => window.VM.vm.networkDataDevices(net)),
|
||||
),
|
||||
];
|
||||
const visibleDevices = visibleDeviceIds.map((id) =>
|
||||
window.VM.vm.objects.get(id),
|
||||
);
|
||||
const pinsHtml = this.pins?.map(
|
||||
(pin, index) =>
|
||||
html` <sl-select
|
||||
hoist
|
||||
placement="top"
|
||||
clearable
|
||||
key=${index}
|
||||
.value=${pin}
|
||||
@sl-change=${this._handleChangePin}
|
||||
>
|
||||
<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>
|
||||
`,
|
||||
)}
|
||||
</sl-select>`,
|
||||
);
|
||||
return html`<div class="pins">${pinsHtml}</div>`;
|
||||
}
|
||||
|
||||
_handleChangePin(e: CustomEvent) {
|
||||
const select = e.target as SlSelect;
|
||||
const pin = parseInt(select.getAttribute("key")!);
|
||||
const val = select.value ? parseInt(select.value as string) : undefined;
|
||||
this.pins[pin] = val
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -204,17 +294,17 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
|
||||
return html`
|
||||
<sl-card class="template-card">
|
||||
<div class="header h-20 w-96" slot="header">
|
||||
<sl-tooltip content="${device?.name}">
|
||||
<sl-tooltip content="${device?.prefab.prefab_name}">
|
||||
<img
|
||||
class="image me-2"
|
||||
src="img/stationpedia/${device?.name}.png"
|
||||
src="img/stationpedia/${device?.prefab.prefab_name}.png"
|
||||
onerror="this.src = '${VMDeviceCard.transparentImg}'"
|
||||
/>
|
||||
</sl-tooltip>
|
||||
<div class="vstack">
|
||||
<span class="prefab-title">${device.title}</span>
|
||||
<span class="prefab-name"><small>${device?.name}</small></span>
|
||||
<span class="prefab-hash"><small>${device?.hash}</small></span>
|
||||
<span>${device.prefab.name}</span>
|
||||
<span><small>${device?.prefab.prefab_name}</small></span>
|
||||
<span><small>${device?.prefab.prefab_hash}</small></span>
|
||||
</div>
|
||||
<sl-button
|
||||
class="ms-auto mt-auto mb-auto"
|
||||
@@ -244,19 +334,68 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
|
||||
</sl-card>
|
||||
`;
|
||||
}
|
||||
_handleAddButtonClick() {
|
||||
async _handleAddButtonClick() {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("add-device-template", { bubbles: true }),
|
||||
);
|
||||
const template: DeviceTemplate = {
|
||||
id: this.device_id,
|
||||
name: this.device_name,
|
||||
prefab_name: this.prefab_name,
|
||||
slots: this.slots,
|
||||
connections: this.connections,
|
||||
fields: this.fields,
|
||||
// Typescript doesn't like fileds defined as `X | undefined` not being present, hence cast
|
||||
const objInfo: ObjectInfo = {
|
||||
id: this.objectId,
|
||||
name: this.objectName,
|
||||
prefab: this.prefabName
|
||||
} as ObjectInfo;
|
||||
|
||||
if (this.slots.length > 0) {
|
||||
const slotOccupants: [FrozenObject, number][] = this.slots.flatMap((slot, index) => {
|
||||
return typeof slot.occupant !== "undefined" ? [[slot.occupant, index]] : [];
|
||||
})
|
||||
let slotOccupantTemplates: FrozenObject[] | null = null;
|
||||
let slotOccupantObjectIds: ObjectID[] | null = null;
|
||||
|
||||
let slotOccupantIdsMap: Map<number, number> = new Map();
|
||||
if (slotOccupants.length > 0) {
|
||||
slotOccupantTemplates = slotOccupants.map(([slot, _]) => slot);
|
||||
slotOccupantObjectIds = await window.VM.vm.addObjectsFrozen(slotOccupantTemplates);
|
||||
slotOccupantIdsMap = new Map(slotOccupants.map((_, index) => {
|
||||
return [index, slotOccupantObjectIds[index]];
|
||||
}))
|
||||
}
|
||||
objInfo.slots = new Map(this.slots.flatMap((slot, index) => {
|
||||
const occupantId = slotOccupantIdsMap.get(index);
|
||||
if (typeof occupantId !== "undefined") {
|
||||
const info: SlotOccupantInfo = {
|
||||
id: occupantId,
|
||||
quantity: slot.quantity
|
||||
};
|
||||
return [[index, info]] as [number, SlotOccupantInfo][];
|
||||
} else {
|
||||
return [] as [number, SlotOccupantInfo][];
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
if (this.connections.length > 0) {
|
||||
objInfo.connections = new Map(
|
||||
this.connections.flatMap((conn, index) => {
|
||||
return typeof conn === "object" &&
|
||||
"CableNetwork" in conn &&
|
||||
typeof conn.CableNetwork.net !== "undefined"
|
||||
? ([[index, conn.CableNetwork.net]] as [number, number][])
|
||||
: ([] as [number, number][]);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (this.fields.size > 0) {
|
||||
objInfo.logic_values = new Map(this.fields)
|
||||
}
|
||||
|
||||
const template: FrozenObject = {
|
||||
obj_info: objInfo,
|
||||
database_template: true,
|
||||
template: undefined,
|
||||
};
|
||||
window.VM.vm.addDeviceFromTemplate(template);
|
||||
await window.VM.vm.addObjectFrozen(template);
|
||||
|
||||
// reset state for new device
|
||||
this.setupState();
|
||||
|
||||
@@ -8,6 +8,7 @@ import type {
|
||||
TemplateDatabase,
|
||||
FrozenCableNetwork,
|
||||
FrozenObjectFull,
|
||||
ObjectID,
|
||||
} from "ic10emu_wasm";
|
||||
import * as Comlink from "comlink";
|
||||
import "./base_device";
|
||||
@@ -29,6 +30,8 @@ export interface VirtualMachinEventMap {
|
||||
"vm-objects-modified": CustomEvent<number>;
|
||||
"vm-run-ic": CustomEvent<number>;
|
||||
"vm-object-id-change": CustomEvent<{ old: number; new: number }>;
|
||||
"vm-networks-update": CustomEvent<number[]>;
|
||||
"vm-networks-removed": CustomEvent<number[]>;
|
||||
}
|
||||
|
||||
class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEventMap>) {
|
||||
@@ -62,6 +65,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
this.templateDBPromise.then((db) => this.setupTemplateDatabase(db));
|
||||
|
||||
this.updateObjects();
|
||||
this.updateNetworks();
|
||||
this.updateCode();
|
||||
}
|
||||
|
||||
@@ -113,11 +117,65 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
return ids;
|
||||
}
|
||||
|
||||
async updateNetworks() {
|
||||
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 updatedNetworks: ObjectID[] = [];
|
||||
for (const [index, id] of networkIds.entries()) {
|
||||
if (!this._networks.has(id)) {
|
||||
this._networks.set(id, frozenNetworks[index]);
|
||||
updateFlag = true;
|
||||
updatedNetworks.push(id);
|
||||
} else {
|
||||
if (!structuralEqual(this._networks.get(id), frozenNetworks[index])) {
|
||||
this._networks.set(id, frozenNetworks[index]);
|
||||
updatedNetworks.push(id);
|
||||
updateFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const id of this._networks.keys()) {
|
||||
if (!networkIds.includes(id)) {
|
||||
this._networks.delete(id);
|
||||
updateFlag = true;
|
||||
removedNetworks.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (updateFlag) {
|
||||
const ids = Array.from(updatedNetworks);
|
||||
ids.sort();
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("vm-networks-update", {
|
||||
detail: ids,
|
||||
}),
|
||||
);
|
||||
if (removedNetworks.length > 0) {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("vm-networks-removed", {
|
||||
detail: removedNetworks,
|
||||
}),
|
||||
);
|
||||
}
|
||||
this.app.session.save();
|
||||
}
|
||||
}
|
||||
|
||||
async updateObjects() {
|
||||
let updateFlag = false;
|
||||
const removedObjects = [];
|
||||
let objectIds;
|
||||
let frozenObjects;
|
||||
let objectIds: Uint32Array;
|
||||
let frozenObjects: FrozenObjectFull[];
|
||||
try {
|
||||
objectIds = await this.ic10vm.objects;
|
||||
frozenObjects = await this.ic10vm.freezeObjects(objectIds);
|
||||
@@ -125,7 +183,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
this.handleVmError(e);
|
||||
return;
|
||||
}
|
||||
const updatedObjects = [];
|
||||
const updatedObjects: ObjectID[] = [];
|
||||
|
||||
for (const [index, id] of objectIds.entries()) {
|
||||
if (!this._objects.has(id)) {
|
||||
@@ -267,17 +325,18 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
|
||||
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.updateDevice(id, false);
|
||||
this.updateObject(id, false);
|
||||
}
|
||||
}, this);
|
||||
this.updateDevice(this.activeIC.obj_info.id, false);
|
||||
this.updateObject(this.activeIC.obj_info.id, false);
|
||||
if (save) this.app.session.save();
|
||||
}
|
||||
|
||||
async updateDevice(id: number, save: boolean = true) {
|
||||
async updateObject(id: number, save: boolean = true) {
|
||||
let frozen;
|
||||
try {
|
||||
frozen = await this.ic10vm.freezeObject(id);
|
||||
@@ -287,7 +346,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
}
|
||||
const device = this._objects.get(id);
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("vm-device-modified", { detail: device.obj_info.id }),
|
||||
new CustomEvent("vm-object-modified", { detail: device.obj_info.id }),
|
||||
);
|
||||
if (typeof device.obj_info.socketed_ic !== "undefined") {
|
||||
const ic = this._objects.get(device.obj_info.socketed_ic);
|
||||
@@ -309,7 +368,12 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
this.dispatchEvent(new CustomEvent("vm-message", { detail: message }));
|
||||
}
|
||||
|
||||
async changeDeviceID(oldID: number, newID: number): Promise<boolean> {
|
||||
// return the data connected oject ids for a network
|
||||
networkDataDevices(network: ObjectID): number[] {
|
||||
return this._networks.get(network)?.devices ?? []
|
||||
}
|
||||
|
||||
async changeObjectID(oldID: number, newID: number): Promise<boolean> {
|
||||
try {
|
||||
await this.ic10vm.changeDeviceId(oldID, newID);
|
||||
if (this.app.session.activeIC === oldID) {
|
||||
@@ -336,7 +400,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
const ic = this.activeIC!;
|
||||
try {
|
||||
await this.ic10vm.setRegister(ic.obj_info.id, index, val);
|
||||
this.updateDevice(ic.obj_info.id);
|
||||
this.updateObject(ic.obj_info.id);
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
@@ -348,7 +412,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
const ic = this.activeIC!;
|
||||
try {
|
||||
await this.ic10vm.setMemory(ic.obj_info.id, addr, val);
|
||||
this.updateDevice(ic.obj_info.id);
|
||||
this.updateObject(ic.obj_info.id);
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
@@ -361,7 +425,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
if (obj) {
|
||||
try {
|
||||
await this.ic10vm.setObjectName(obj.obj_info.id, name);
|
||||
this.updateDevice(obj.obj_info.id);
|
||||
this.updateObject(obj.obj_info.id);
|
||||
this.app.session.save();
|
||||
return true;
|
||||
} catch (e) {
|
||||
@@ -382,7 +446,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
if (obj) {
|
||||
try {
|
||||
await this.ic10vm.setLogicField(obj.obj_info.id, field, val, force);
|
||||
this.updateDevice(obj.obj_info.id);
|
||||
this.updateObject(obj.obj_info.id);
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
@@ -409,7 +473,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
val,
|
||||
force,
|
||||
);
|
||||
this.updateDevice(obj.obj_info.id);
|
||||
this.updateObject(obj.obj_info.id);
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
@@ -427,7 +491,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
if (typeof device !== "undefined") {
|
||||
try {
|
||||
await this.ic10vm.setDeviceConnection(id, conn, val);
|
||||
this.updateDevice(device.obj_info.id);
|
||||
this.updateObject(device.obj_info.id);
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
@@ -445,7 +509,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
if (typeof device !== "undefined") {
|
||||
try {
|
||||
await this.ic10vm.setPin(id, pin, val);
|
||||
this.updateDevice(device.obj_info.id);
|
||||
this.updateObject(device.obj_info.id);
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
@@ -462,10 +526,10 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
);
|
||||
}
|
||||
|
||||
async addObjectFromFrozen(frozen: FrozenObject): Promise<boolean> {
|
||||
async addObjectFrozen(frozen: FrozenObject): Promise<ObjectID | undefined> {
|
||||
try {
|
||||
console.log("adding device", frozen);
|
||||
const id = await this.ic10vm.addObjectFromFrozen(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;
|
||||
@@ -475,10 +539,32 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
}),
|
||||
);
|
||||
this.app.session.save();
|
||||
return true;
|
||||
return id;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
return false;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async addObjectsFrozen(frozenObjects: FrozenObject[]): Promise<ObjectID[] | undefined> {
|
||||
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.dispatchEvent(
|
||||
new CustomEvent("vm-objects-update", {
|
||||
detail: Array.from(device_ids),
|
||||
}),
|
||||
);
|
||||
this.app.session.save();
|
||||
return Array.from(ids);
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,7 +590,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
try {
|
||||
console.log("setting slot occupant", frozen);
|
||||
await this.ic10vm.setSlotOccupant(id, index, frozen, quantity);
|
||||
this.updateDevice(device.obj_info.id);
|
||||
this.updateObject(device.obj_info.id);
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
@@ -518,7 +604,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
|
||||
if (typeof device !== "undefined") {
|
||||
try {
|
||||
this.ic10vm.removeSlotOccupant(id, index);
|
||||
this.updateDevice(device.obj_info.id);
|
||||
this.updateObject(device.obj_info.id);
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
|
||||
@@ -44,17 +44,16 @@ export class VMICRegisters extends VMActiveICMixin(BaseElement) {
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const registerAliases: [string, number][] = (
|
||||
(
|
||||
[...(this.aliases ?? [])].filter(
|
||||
([_alias, target]) =>
|
||||
"RegisterSpec" in target && target.RegisterSpec.indirection === 0,
|
||||
) as [string, RegisterSpec][]
|
||||
).map(([alias, target]) => [alias, target.RegisterSpec.target]) as [
|
||||
string,
|
||||
number,
|
||||
][]
|
||||
).concat(VMICRegisters.defaultAliases);
|
||||
const registerAliases: [string, number][] =
|
||||
[...(Array.from(this.aliases?.entries() ?? []))].flatMap(
|
||||
([alias, target]) => {
|
||||
if ("RegisterSpec" in target && target.RegisterSpec.indirection === 0) {
|
||||
return [[alias, target.RegisterSpec.target]] as [string, number][];
|
||||
} else {
|
||||
return [] as [string, number][];
|
||||
}
|
||||
}
|
||||
).concat(VMICRegisters.defaultAliases);
|
||||
return html`
|
||||
<sl-card class="card">
|
||||
<div class="card-body">
|
||||
|
||||
Reference in New Issue
Block a user