bit the bullet and make the ts move

(I want types sooo bad...)
This commit is contained in:
Rachel
2024-03-30 21:43:41 -07:00
parent d76610f5d9
commit d0cc415ca5
20 changed files with 5681 additions and 1133 deletions

View File

@@ -65,24 +65,50 @@ pub struct DeviceTemplate {
pub logic: HashMap<grammar::LogicType, LogicField>, pub logic: HashMap<grammar::LogicType, LogicField>,
pub slots: Vec<SlotTemplate>, pub slots: Vec<SlotTemplate>,
pub slotlogic: HashMap<grammar::LogicType, usize>, pub slotlogic: HashMap<grammar::LogicType, usize>,
pub conn: HashMap<u32, Connection>, pub conn: Vec<(ConnectionType, ConnectionRole)>,
} }
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ConnectionType { pub enum ConnectionType {
Chute,
Pipe, Pipe,
Power, Power,
PowerData,
#[default]
Data, Data,
Chute,
Elevator,
PipeLiquid,
LandingPad,
LaunchPad,
PowerAndData,
#[serde(other)]
#[default]
None,
} }
impl From<ConnectionType> for Connection { #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
fn from(value: ConnectionType) -> Self { pub enum ConnectionRole {
match value { Input,
ConnectionType::Chute | ConnectionType::Pipe | ConnectionType::Power => Self::Other, Input2,
_ => Self::CableNetwork(None), Output,
Output2,
Waste,
#[serde(other)]
#[default]
None,
}
impl Connection {
fn from(typ: ConnectionType, _role: ConnectionRole) -> Self {
match typ {
ConnectionType::None
| ConnectionType::Chute
| ConnectionType::Pipe
| ConnectionType::Elevator
| ConnectionType::LandingPad
| ConnectionType::LaunchPad
| ConnectionType::PipeLiquid => Self::Other,
ConnectionType::Data | ConnectionType::Power | ConnectionType::PowerAndData => {
Self::CableNetwork(None)
}
} }
} }
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -145,7 +145,7 @@
<a class="navbar-brand active" aria-current="page" href="">Stationeers IC10 Emulator</a> <a class="navbar-brand active" aria-current="page" href="">Stationeers IC10 Emulator</a>
</div> </div>
<div class="nav navbar-nav ms-2"> <div class="nav navbar-nav ms-2">
</div> </div>
<div class="nav navbar-nav ms-auto navbar-right d-flex flex-row"> <div class="nav navbar-nav ms-auto navbar-right d-flex flex-row">
<a class="navbar-text mt-auto mb-auto align-self-center" href="https://github.com/ryex/ic10emu">View on Github <a class="navbar-text mt-auto mb-auto align-self-center" href="https://github.com/ryex/ic10emu">View on Github
@@ -192,7 +192,8 @@
<div id="vmActiveIC" class="container "> <div id="vmActiveIC" class="container ">
<div class="ms-1 me-2 pb-2 row border border-secondary rounded bg-secondary bg-opacity-10"> <div class="ms-1 me-2 pb-2 row border border-secondary rounded bg-secondary bg-opacity-10">
<div class="mt-2 col"> <div class="mt-2 col">
<div id="vmControls" class="btn-group-vertical btn-group-sm " role="group" aria-label="Virtual Machine Controls"> <div id="vmControls" class="btn-group-vertical btn-group-sm " role="group"
aria-label="Virtual Machine Controls">
<button id="vmControlRun" type="button" class="btn btn-primary">Run</button> <button id="vmControlRun" type="button" class="btn btn-primary">Run</button>
<button id="vmControlStep" type="button" class="btn btn-secondary">Step</button> <button id="vmControlStep" type="button" class="btn btn-secondary">Step</button>
<button id="vmControlReset" type="button" class="btn btn-warning">Reset</button> <button id="vmControlReset" type="button" class="btn btn-warning">Reset</button>
@@ -217,6 +218,10 @@
</div> </div>
</div> </div>
<div class="row mt-2 p2">
<button type="button" class="btn btn-outline-secondary">View Devices <span
id="vmViewDeviceCount"></span></button>
</div>
<div class="row mt-2"> <div class="row mt-2">
<div class="accordion" id="vmActiveIC"> <div class="accordion" id="vmActiveIC">
<div class="accordion-item"> <div class="accordion-item">
@@ -249,9 +254,6 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -264,6 +266,18 @@
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.7/ace.js" type="text/javascript" charset="utf-8"></script> --> <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.7/ace.js" type="text/javascript" charset="utf-8"></script> -->
<script> <script>
</script> </script>
<div class="offcanvas offcanvas-start" tabindex="-1" id="vmDevices" aria-labelledby="vmDevicesLabel"
data-bs-scroll="true" data-bs-backdrop="false">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="vmDevicesLabel">Devices</h5>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<div class="p-2" id="vmDevicesOCBody"></div>
</div>
</div>
</body> </body>
</html> </html>

View File

@@ -57,17 +57,17 @@ class IC10Editor {
this.ui = new IC10EditorUI(this); this.ui = new IC10EditorUI(this);
const self = this; const that = this;
App.session.onLoad((session) => { App.session.onLoad((session) => {
const updated_ids = []; const updated_ids = [];
for (const id in session.programs) { for (const id in session.programs) {
updated_ids.push(id); updated_ids.push(id);
self.createOrSetSession(id, session.programs[id]); that.createOrSetSession(id, session.programs[id]);
} }
for (const id in self.sessions) { for (const id in that.sessions) {
if (!updated_ids.includes(id)) { if (!updated_ids.includes(id)) {
self.destroySession(id); that.destroySession(id);
} }
} }
}); });
@@ -77,17 +77,17 @@ class IC10Editor {
for (const id in Object.keys(session.programs)) { for (const id in Object.keys(session.programs)) {
const active_line = session.getActiveLine(id); const active_line = session.getActiveLine(id);
if (typeof active_line !== "undefined") { if (typeof active_line !== "undefined") {
const marker = self.active_line_markers[id]; const marker = that.active_line_markers[id];
if (marker) { if (marker) {
self.sessions[id].removeMarker(marker); that.sessions[id].removeMarker(marker);
self.active_line_markers[id] = null; that.active_line_markers[id] = null;
} }
const session = self.sessions[id]; const session = that.sessions[id];
if (session) { if (session) {
self.active_line_markers[id] = session.addMarker(new Range(active_line, 0, active_line, 1), "vm_ic_active_line", "fullLine", true); that.active_line_markers[id] = session.addMarker(new Range(active_line, 0, active_line, 1), "vm_ic_active_line", "fullLine", true);
if (self.active_session == id) { if (that.active_session == id) {
// editor.resize(true); // editor.resize(true);
self.aceEditor.scrollToLine(active_line, true, true) that.aceEditor.scrollToLine(active_line, true, true)
} }
} }
} }

View File

@@ -5,11 +5,11 @@ class IC10EditorUI {
constructor(ic10editor) { constructor(ic10editor) {
const self = this; const that = this;
self.ic10editor = ic10editor; that.ic10editor = ic10editor;
self.ic10editor.aceEditor.commands.addCommand({ that.ic10editor.aceEditor.commands.addCommand({
name: "showSettingsMenu", name: "showSettingsMenu",
description: "Show settings menu", description: "Show settings menu",
bindKey: { win: "Ctrl-,", mac: "Command-," }, bindKey: { win: "Ctrl-,", mac: "Command-," },
@@ -21,50 +21,50 @@ class IC10EditorUI {
ace.config.loadModule("ace/ext/keyboard_menu", function (module) { ace.config.loadModule("ace/ext/keyboard_menu", function (module) {
console.log("keybinding_menu loaded"); console.log("keybinding_menu loaded");
module.init(self.ic10editor.aceEditor); module.init(that.ic10editor.aceEditor);
}); });
self.ic10editor.loadEditorSettings(); that.ic10editor.loadEditorSettings();
self.displayEditorSettings(); that.displayEditorSettings();
self.updateEditorSettings(); that.updateEditorSettings();
self.reCalcEditorSize(); that.reCalcEditorSize();
window.addEventListener('resize', (e) => { self.reCalcEditorSize(); }); window.addEventListener('resize', (e) => { that.reCalcEditorSize(); });
document.getElementsByName("editorKeybindRadio").forEach((el) => { document.getElementsByName("editorKeybindRadio").forEach((el) => {
el.addEventListener('change', (e) => { el.addEventListener('change', (e) => {
self.ic10editor.settings.keyboard = e.target.value; that.ic10editor.settings.keyboard = e.target.value;
self.ic10editor.saveEditorSettings(); that.ic10editor.saveEditorSettings();
self.updateEditorSettings(); that.updateEditorSettings();
}); });
}); });
document.getElementsByName("editorCursorRadio").forEach((el) => { document.getElementsByName("editorCursorRadio").forEach((el) => {
el.addEventListener('change', (e) => { el.addEventListener('change', (e) => {
self.ic10editor.settings.cursor = e.target.value; that.ic10editor.settings.cursor = e.target.value;
self.ic10editor.saveEditorSettings(); that.ic10editor.saveEditorSettings();
self.updateEditorSettings(); that.updateEditorSettings();
}); });
}); });
document.getElementById("editorSettingsFontSize").addEventListener('change', (e) => { document.getElementById("editorSettingsFontSize").addEventListener('change', (e) => {
window.App.editorSettings.fontSize = e.target.value; window.App.editorSettings.fontSize = e.target.value;
self.ic10editor.saveEditorSettings(); that.ic10editor.saveEditorSettings();
self.updateEditorSettings(); that.updateEditorSettings();
}); });
document.getElementById("editorSettingsRelativeLineNumbers").addEventListener('change', (e) => { document.getElementById("editorSettingsRelativeLineNumbers").addEventListener('change', (e) => {
window.App.editorSettings.relativeLineNumbers = e.target.checked; window.App.editorSettings.relativeLineNumbers = e.target.checked;
self.ic10editor.saveEditorSettings(); that.ic10editor.saveEditorSettings();
self.updateEditorSettings(); that.updateEditorSettings();
}); });
console.log(self.ic10editor.aceEditor.getOption('keyboardHandler')); console.log(that.ic10editor.aceEditor.getOption('keyboardHandler'));
self.ic10editor.aceEditor.setTheme("ace/theme/one_dark"); that.ic10editor.aceEditor.setTheme("ace/theme/one_dark");
ace.config.loadModule("ace/ext/statusbar", function (module) { ace.config.loadModule("ace/ext/statusbar", function (module) {
const statusBar = new module.StatusBar(self.ic10editor.aceEditor, document.getElementById("statusBar")); const statusBar = new module.StatusBar(that.ic10editor.aceEditor, document.getElementById("statusBar"));
statusBar.updateStatus(self.ic10editor.aceEditor); statusBar.updateStatus(that.ic10editor.aceEditor);
}); });
self.ic10editor.aceEditor.setAutoScrollEditorIntoView(true); that.ic10editor.aceEditor.setAutoScrollEditorIntoView(true);
} }

61
www/src/js/index.ts Normal file
View File

@@ -0,0 +1,61 @@
import { IC10Editor, setupLspWorker } from "./editor";
import { Session } from './session';
import { VirtualMachine } from "./virtual_machine";
import { docReady, openFile, saveFile } from "./utils";
// import { makeRequest } from "./utils";
const App = {
editor: null,
vm: null,
session: new Session()
};
window.App = App;
// const dbPromise = makeRequest({ method: "GET", url: "/data/database.json"});
const dbPromise = fetch("/data/database.json").then(resp => resp.json());
docReady(() => {
App.vm = new VirtualMachine();
dbPromise.then(db => App.vm.setupDeviceDatabase(db))
const init_session_id = App.vm.devices[0];
App.editor = new IC10Editor(init_session_id);
setupLspWorker().then((worker) => {
App.editor.setupLsp(worker);
})
// Menu
document.getElementById("mainMenuShare").addEventListener('click', (_event) => {
const link = document.getElementById("shareLinkText");
link.setAttribute('value', window.location);
link.setSelectionRange(0, 0);
}, { capture: true });
document.getElementById("shareLinkCopyButton").addEventListener('click', (event) => {
event.preventDefault();
const link = document.getElementById("shareLinkText");
link.select();
link.setSelectionRange(0, 99999);
navigator.clipboard.writeText(link.value);
}, { capture: true });
document.getElementById("mainMenuOpenFile").addEventListener('click', (_event) => {
openFile(editor);
}, { capture: true });
document.getElementById("mainMenuSaveAs").addEventListener('click', (_event) => {
saveFile(editor.getSession().getValue())
}, { capture: true });
document.getElementById("mainMenuKeyboardShortcuts").addEventListener('click', (_event) => {
App.editor.editor.execCommand("showKeyboardShortcuts");
}, { capture: true });
});

View File

@@ -63,17 +63,17 @@ j ra
class Session { class Session {
constructor() { constructor() {
this._programs = {}; this._programs = new Map();
this._save_timeout = 0; this._save_timeout = 0;
this._onLoadCallbacks = []; this._onLoadCallbacks = [];
this._activeSession = 0; this._activeSession = 0;
this._activeLines = {}; this._activeLines = new Map();
this._onActiveLineCallbacks = []; this._onActiveLineCallbacks = [];
this.loadFromFragment(); this.loadFromFragment();
const self = this; const that = this;
window.addEventListener('hashchange', (_event) => { window.addEventListener('hashchange', (_event) => {
self.loadFromFragment(); that.loadFromFragment();
}); });
} }
@@ -82,7 +82,7 @@ class Session {
} }
set programs(programs) { set programs(programs) {
Object.assign(this._programs, programs); this._programs = new Map([...programs]);
} }
get activeSession() { get activeSession() {
@@ -90,11 +90,11 @@ class Session {
} }
getActiveLine(id) { getActiveLine(id) {
return this._activeLines[id]; return this._activeLines.get(id);
} }
setActiveLine(id, line) { setActiveLine(id, line) {
this._activeLines[id] = line; this._activeLines.set(id, line);
this._fireOnActiveLine(); this._fireOnActiveLine();
} }
@@ -103,7 +103,7 @@ class Session {
} }
setProgramCode(id, code) { setProgramCode(id, code) {
this._programs[id] = code; this._programs.set(id, code);
this.save(); this.save();
} }
@@ -112,8 +112,7 @@ class Session {
} }
_fireOnLoad() { _fireOnLoad() {
for (const i in this._onLoadCallbacks) { for (const callback of this._onLoadCallbacks) {
const callback = this._onLoadCallbacks[i];
callback(this); callback(this);
} }
} }
@@ -123,8 +122,7 @@ class Session {
} }
_fireOnActiveLine() { _fireOnActiveLine() {
for (const i in this._onActiveLineCallbacks) { for (const callback of this._onActiveLineCallbacks) {
const callback = this._onActiveLineCallbacks[i];
callback(this); callback(this);
} }
} }
@@ -141,7 +139,7 @@ class Session {
} }
async saveToFragment() { async saveToFragment() {
const toSave = { programs: this._programs }; const toSave = { programs: Array.from(this._programs) };
const bytes = new TextEncoder().encode(JSON.stringify(toSave)); const bytes = new TextEncoder().encode(JSON.stringify(toSave));
try { try {
const c_bytes = await compress(bytes); const c_bytes = await compress(bytes);
@@ -157,7 +155,7 @@ class Session {
async loadFromFragment() { async loadFromFragment() {
const fragment = window.location.hash.slice(1); const fragment = window.location.hash.slice(1);
if (fragment === "demo") { if (fragment === "demo") {
this._programs = { 0: demoCode }; this._programs = new Map([[0, demoCode]]);
this._fireOnLoad(); this._fireOnLoad();
return; return;
} }
@@ -168,12 +166,12 @@ class Session {
const txt = new TextDecoder().decode(bytes); const txt = new TextDecoder().decode(bytes);
const data = getJson(txt); const data = getJson(txt);
if (data === null) { // backwards compatible if (data === null) { // backwards compatible
this._programs = { 0: txt }; this._programs = new Map([[0, txt]]);
this, this._fireOnLoad(); this, this._fireOnLoad();
return; return;
} }
try { try {
this._programs = Object.assign({}, data.programs); this._programs = new Map(data.programs);
this._fireOnLoad(); this._fireOnLoad();
return; return;
} catch (e) { } catch (e) {

View File

@@ -1,14 +1,3 @@
import { IC10Editor, setupLspWorker } from "./editor";
import { Session } from './session';
import { VirtualMachine } from "./virtual_machine";
const App = {
editor: null,
vm: null,
session: new Session()
};
window.App = App;
function docReady(fn) { function docReady(fn) {
@@ -20,44 +9,42 @@ function docReady(fn) {
} }
} }
docReady(() => { // probably not needed, fetch() exists now
function makeRequest (opts) {
App.vm = new VirtualMachine(); const req = new Request()
return new Promise(function (resolve, reject) {
const init_session_id = App.vm.devices[0]; var xhr = new XMLHttpRequest();
xhr.open(opts.method, opts.url);
App.editor = new IC10Editor(init_session_id); xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 300) {
setupLspWorker().then((worker) => { resolve(xhr.response);
App.editor.setupLsp(worker); } else {
}) reject({
status: xhr.status,
statusText: xhr.statusText
// Menu });
document.getElementById("mainMenuShare").addEventListener('click', (_event) => { }
const link = document.getElementById("shareLinkText"); };
link.setAttribute('value', window.location); xhr.onerror = function () {
link.setSelectionRange(0, 0); reject({
}, { capture: true }); status: xhr.status,
document.getElementById("shareLinkCopyButton").addEventListener('click', (event) => { statusText: xhr.statusText
event.preventDefault(); });
const link = document.getElementById("shareLinkText"); };
link.select(); if (opts.headers) {
link.setSelectionRange(0, 99999); Object.keys(opts.headers).forEach(function (key) {
navigator.clipboard.writeText(link.value); xhr.setRequestHeader(key, opts.headers[key]);
}, { capture: true }); });
document.getElementById("mainMenuOpenFile").addEventListener('click', (_event) => { }
openFile(editor); var params = opts.params;
}, { capture: true }); if (params && typeof params === 'object') {
document.getElementById("mainMenuSaveAs").addEventListener('click', (_event) => { params = Object.keys(params).map(function (key) {
saveFile(editor.getSession().getValue()) return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
}).join('&');
}, { capture: true }); }
document.getElementById("mainMenuKeyboardShortcuts").addEventListener('click', (_event) => { xhr.send(params);
App.editor.editor.execCommand("showKeyboardShortcuts"); });
}, { capture: true }); }
});
async function saveFile(content) { async function saveFile(content) {
const blob = new Blob([content], { type: "text/plain" }); const blob = new Blob([content], { type: "text/plain" });
@@ -116,6 +103,4 @@ async function openFile(editor) {
input.click(); input.click();
} }
} }
export { docReady, makeRequest, saveFile, openFile }

View File

@@ -0,0 +1,44 @@
import { Offcanvas } from 'bootstrap';
class VMDeviceUI {
constructor(ui) {
const that = this;
that.ui = ui;
this.root = document.createElement('div');
this.canvasEl = document.getElementById('vmDevicesOCBody');
this.deviceCountEl = document.getElementById('vmDViewDeviceCount');
this.canvas = new Offcanvas(this.canvasEl)
}
update(active_ic) {
const devices = window.VM.devices;
}
}
class VMDeviceCard {
constructor(deviceUI, device) {
const that = this;
this.deviceUI = deviceUI;
this.device = device;
this.root = document.createElement('div');
this.root.classList.add("hstack", "gap-2");
this.viewBtn = document.createElement('button');
this.viewBtn.type = "button";
this.viewBtn.classList.add("btn", "btn-secondary");
const btnTxt = document.createTextNode(device.name)
this.deviceUI.root.appendChild(this.root);
}
destroy() {
this.root.remove();
}
}
export { VMDeviceUI }

View File

@@ -1,4 +1,5 @@
import { init } from "ic10emu_wasm"; import { init } from "ic10emu_wasm";
import { VMDeviceUI } from "./device";
// import { Card } from 'bootstrap'; // import { Card } from 'bootstrap';
class VirtualMachine { class VirtualMachine {
@@ -11,40 +12,76 @@ class VirtualMachine {
this.ic10vm = vm; this.ic10vm = vm;
this.ui = new VirtualMachineUI(this); this.ui = new VirtualMachineUI(this);
this.ics = {} this._devices = new Map();
const ics = this.ic10vm.ics; this._ics = new Map();
for (const id of Object.keys(ics)) {
this.ics[id] = this.ic10vm.getDevice(parseInt(id));
}
this.updateCode()
this.updateDevices();
this.updateCode()
} }
get devices () { get devices () {
return this.ic10vm.devices; return this._devices;
}
get ics () {
return this._ics;
}
get activeIC () {
return this._ics.get(window.App.session.activeSession);
}
updateDevices() {
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));
}
}
for(const id of this._devices) {
if (!device_ids.includes(id)) {
this._devices.delete(id);
}
}
const ics = this.ic10vm.ics;
for (const id of ics) {
if (!this._ics.has(id)){
this._ics.set(id, this._devices.get(id));
}
}
for(const id of this._ics) {
if (!ics.includes(id)) {
this._ics.delete(id);
}
}
} }
updateCode() { updateCode() {
const progs = window.App.session.programs; const progs = window.App.session.programs;
for (const id of Object.keys(progs)) { for (const id of Object.keys(progs)) {
const ic = this.ics[id]; const attempt = Date.now().toString(16)
const ic = this._ics.get(id);
const prog = progs[id]; const prog = progs[id];
if (ic && prog) { if (ic && prog) {
console.time(`CompileProgram_${id}`); console.time(`CompileProgram_${id}_${attempt}`);
try { try {
this.ics[id].setCode(progs[id]); this.ics[id].setCode(progs[id]);
} catch (e) { } catch (e) {
console.log(e); console.log(e);
} }
console.timeEnd(`CompileProgram_${id}`); console.timeEnd(`CompileProgram_${id}_${attempt}`);
} }
} }
this.update(); this.update();
} }
step() { step() {
const ic = this.ics[window.App.session.activeSession]; const ic = this.activeIC;
if (ic) { if (ic) {
try { try {
ic.step(); ic.step();
@@ -56,7 +93,7 @@ class VirtualMachine {
} }
run() { run() {
const ic = this.ics[window.App.session.activeSession]; const ic = this.activeIC;
if (ic) { if (ic) {
try { try {
ic.run(false); ic.run(false);
@@ -68,7 +105,7 @@ class VirtualMachine {
} }
reset() { reset() {
const ic = this.ics[window.App.session.activeSession]; const ic = this.activeIC;
if (ic) { if (ic) {
ic.reset(); ic.reset();
this.update(); this.update();
@@ -76,13 +113,14 @@ class VirtualMachine {
} }
update() { update() {
const ic = this.ics[window.App.session.activeSession]; this.updateDevices();
const ic = this.activeIC;
window.App.session.setActiveLine(window.App.session.activeSession, ic.ip); window.App.session.setActiveLine(window.App.session.activeSession, ic.ip);
this.ui.update(ic); this.ui.update(ic);
} }
setRegister(index, val) { setRegister(index, val) {
const ic = this.ics[window.App.session.activeSession]; const ic = this.activeIC;
try { try {
ic.setRegister(index, val); ic.setRegister(index, val);
} catch (e) { } catch (e) {
@@ -91,13 +129,18 @@ class VirtualMachine {
} }
setStack(addr, val) { setStack(addr, val) {
const ic = this.ics[window.App.session.activeSession]; const ic = this.activeIC;
try { try {
ic.setStack(addr, val); ic.setStack(addr, val);
} catch (e) { } catch (e) {
console.log(e); console.log(e);
} }
} }
setupDeviceDatabase(db) {
this.db = db;
console.log("Loaded Device Database", this.db);
}
} }
@@ -107,17 +150,18 @@ class VirtualMachineUI {
this.state = new VMStateUI(this); this.state = new VMStateUI(this);
this.registers = new VMRegistersUI(this); this.registers = new VMRegistersUI(this);
this.stack = new VMStackUI(this); this.stack = new VMStackUI(this);
this.devices = new VMDeviceUI(this);
const self = this; const that = this;
document.getElementById("vmControlRun").addEventListener('click', (_event) => { document.getElementById("vmControlRun").addEventListener('click', (_event) => {
self.vm.run(); that.vm.run();
}, { capture: true }); }, { capture: true });
document.getElementById("vmControlStep").addEventListener('click', (_event) => { document.getElementById("vmControlStep").addEventListener('click', (_event) => {
self.vm.step(); that.vm.step();
}, { capture: true }); }, { capture: true });
document.getElementById("vmControlReset").addEventListener('click', (_event) => { document.getElementById("vmControlReset").addEventListener('click', (_event) => {
self.vm.reset(); that.vm.reset();
}, { capture: true }); }, { capture: true });
} }
@@ -126,6 +170,7 @@ class VirtualMachineUI {
this.state.update(ic); this.state.update(ic);
this.registers.update(ic); this.registers.update(ic);
this.stack.update(ic); this.stack.update(ic);
this.devices.update(ic);
} }
} }
@@ -154,10 +199,10 @@ class VMRegistersUI {
const regDom = document.getElementById("vmActiveRegisters"); const regDom = document.getElementById("vmActiveRegisters");
this.tbl = document.createElement("div"); this.tbl = document.createElement("div");
this.tbl.classList.add("d-flex", "flex-wrap", "justify-content-start", "align-items-end",); this.tbl.classList.add("d-flex", "flex-wrap", "justify-content-start", "align-items-end",);
this.regCels = []; this.regCells = [];
for (var i = 0; i < 18; i++) { for (var i = 0; i < 18; i++) {
const container = document.createElement("div"); const container = document.createElement("div");
container.classList.add("vm_reg_cel", "align-self-stretch"); container.classList.add("vm_reg_cel", "align-that-stretch");
const cell = document.createElement("div"); const cell = document.createElement("div");
cell.classList.add("input-group", "input-group-sm") cell.classList.add("input-group", "input-group-sm")
// cell.style.width = "30%"; // cell.style.width = "30%";
@@ -173,7 +218,7 @@ class VMRegistersUI {
const aliasesLabel = document.createElement("span"); const aliasesLabel = document.createElement("span");
aliasesLabel.classList.add("input-group-text", "reg_label") aliasesLabel.classList.add("input-group-text", "reg_label")
cell.appendChild(aliasesLabel); cell.appendChild(aliasesLabel);
this.regCels.push({ this.regCells.push({
cell, cell,
nameLabel, nameLabel,
aliasesLabel, aliasesLabel,
@@ -182,7 +227,7 @@ class VMRegistersUI {
container.appendChild(cell); container.appendChild(cell);
this.tbl.appendChild(container); this.tbl.appendChild(container);
} }
this.regCels.forEach(cell => { this.regCells.forEach(cell => {
cell.input.addEventListener('change', this.onCellUpdate); cell.input.addEventListener('change', this.onCellUpdate);
}); });
this.default_aliases = { "sp": 16, "ra": 17 } this.default_aliases = { "sp": 16, "ra": 17 }
@@ -206,12 +251,12 @@ class VMRegistersUI {
} }
update(ic) { update(ic) {
const self = this; const that = this;
if (ic) { if (ic) {
const registers = ic.registers; const registers = ic.registers;
if (registers) { if (registers) {
for (var i = 0; i < registers.length; i++) { for (var i = 0; i < registers.length; i++) {
this.regCels[i].input.value = registers[i]; this.regCells[i].input.value = registers[i];
} }
} }
const aliases = ic.aliases; const aliases = ic.aliases;
@@ -242,7 +287,7 @@ class VMRegistersUI {
} }
for(const [index, label] of Object.entries(labels)) { for(const [index, label] of Object.entries(labels)) {
this.regCels[index].aliasesLabel.innerText = label.join(", ") this.regCells[index].aliasesLabel.innerText = label.join(", ")
} }
} }
} }
@@ -253,10 +298,10 @@ class VMStackUI {
const stackDom = document.getElementById("vmActiveStack"); const stackDom = document.getElementById("vmActiveStack");
this.tbl = document.createElement("div"); this.tbl = document.createElement("div");
this.tbl.classList.add("d-flex", "flex-wrap", "justify-content-start", "align-items-end",); this.tbl.classList.add("d-flex", "flex-wrap", "justify-content-start", "align-items-end",);
this.stackCels = []; this.stackCells = [];
for (var i = 0; i < 512; i++) { for (var i = 0; i < 512; i++) {
const container = document.createElement("div"); const container = document.createElement("div");
container.classList.add("vm_stack_cel", "align-self-stretch"); container.classList.add("vm_stack_cel", "align-that-stretch");
const cell = document.createElement("div"); const cell = document.createElement("div");
cell.classList.add("input-group", "input-group-sm") cell.classList.add("input-group", "input-group-sm")
const nameLabel = document.createElement("span"); const nameLabel = document.createElement("span");
@@ -269,7 +314,7 @@ class VMStackUI {
input.dataset.index = i; input.dataset.index = i;
cell.appendChild(input); cell.appendChild(input);
this.stackCels.push({ this.stackCells.push({
cell, cell,
nameLabel, nameLabel,
input, input,
@@ -277,7 +322,7 @@ class VMStackUI {
container.appendChild(cell); container.appendChild(cell);
this.tbl.appendChild(container); this.tbl.appendChild(container);
} }
this.stackCels.forEach(cell => { this.stackCells.forEach(cell => {
cell.input.addEventListener('change', this.onCellUpdate); cell.input.addEventListener('change', this.onCellUpdate);
}); });
stackDom.appendChild(this.tbl); stackDom.appendChild(this.tbl);
@@ -299,17 +344,17 @@ class VMStackUI {
} }
update(ic) { update(ic) {
const self = this; const that = this;
if (ic) { if (ic) {
const stack = ic.stack; const stack = ic.stack;
const sp = ic.registers[16]; const sp = ic.registers[16];
if (stack) { if (stack) {
for (var i = 0; i < stack.length; i++) { for (var i = 0; i < stack.length; i++) {
this.stackCels[i].input.value = stack[i]; this.stackCells[i].input.value = stack[i];
if (i == sp) { if (i == sp) {
this.stackCels[i].nameLabel.classList.add("stack_pointer"); this.stackCells[i].nameLabel.classList.add("stack_pointer");
} else { } else {
this.stackCels[i].nameLabel.classList.remove("stack_pointer"); this.stackCells[i].nameLabel.classList.remove("stack_pointer");
} }
} }
} }

View File

@@ -5,6 +5,7 @@ from collections import defaultdict
import re import re
import json import json
def extract_all(): def extract_all():
items = {} items = {}
pedia = {} pedia = {}
@@ -19,15 +20,16 @@ def extract_all():
"Title": _, "Title": _,
"Description": desc, "Description": desc,
"PrefabName": name, "PrefabName": name,
"PrefabHash": hash, "PrefabHash": name_hash,
"SlotInserts": slots, "SlotInserts": slots,
"LogicInsert": logic, "LogicInsert": logic,
"LogicSlotInsert": slotlogic, "LogicSlotInsert": slotlogic,
"ModeInsert": modes, "ModeInsert": modes,
"ConnectionInsert": connections, "ConnectionInsert": _,
"ConnectionList": connections, # type: List[Tuple[str, str]]
}: }:
item["name"] = name item["name"] = name
item["hash"] = hash item["hash"] = name_hash
item["desc"] = re.sub(linkPat, r"\1", desc) item["desc"] = re.sub(linkPat, r"\1", desc)
match slots: match slots:
case []: case []:
@@ -47,7 +49,7 @@ def extract_all():
item["logic"] = {} item["logic"] = {}
for lat in logic: for lat in logic:
item["logic"][re.sub(linkPat, r"\1", lat["LogicName"])] = ( item["logic"][re.sub(linkPat, r"\1", lat["LogicName"])] = (
lat["LogicAccessTypes"] lat["LogicAccessTypes"].replace(" ", "")
) )
match slotlogic: match slotlogic:
@@ -75,10 +77,8 @@ def extract_all():
item["conn"] = None item["conn"] = None
case _: case _:
item["conn"] = {} item["conn"] = {}
for conn in connections: for index, [conn_typ, conn_role] in enumerate(connections):
item["conn"][int(conn["LogicAccessTypes"])] = conn[ item["conn"][index] = [conn_typ, conn_role]
"LogicName"
]
case _: case _:
print(f"NON-CONFORMING: ") print(f"NON-CONFORMING: ")
@@ -91,21 +91,34 @@ def extract_all():
slotlogicable = [ slotlogicable = [
item["name"] for item in items.values() if item["slotlogic"] is not None item["name"] for item in items.values() if item["slotlogic"] is not None
] ]
devices = [ devices = [
item["name"] item["name"]
for item in items.values() for item in items.values()
if item["logic"] is not None and item["conn"] is not None if item["logic"] is not None and item["conn"] is not None
] ]
def clean_nones(value):
if isinstance(value, list):
return [clean_nones(x) for x in value if x is not None]
elif isinstance(value, dict):
return {
key: clean_nones(val) for key, val in value.items() if val is not None
}
else:
return value
with open("data/database.json", "w") as f: with open("data/database.json", "w") as f:
json.encoder json.encoder
json.dump( json.dump(
{ clean_nones(
"logic_enabled": logicable, {
"slot_logic_enabled": slotlogicable, "logic_enabled": logicable,
"devices": devices, "slot_logic_enabled": slotlogicable,
"items": items, "devices": devices,
}, "items": items,
}
),
f, f,
) )

View File

@@ -19,7 +19,7 @@ module.exports = {
mode: "development", mode: "development",
devtool: "eval-source-map", devtool: "eval-source-map",
plugins: [ plugins: [
new CopyWebpackPlugin({ patterns: ['img/*.png', 'img/*/*.png'] }), new CopyWebpackPlugin({ patterns: ['img/*.png', 'img/*/*.png', { from: 'data/database.json', to: 'data' }] }),
new HtmlWebpackPlugin({ template: './src/index.html' }), new HtmlWebpackPlugin({ template: './src/index.html' }),
new miniCssExtractPlugin() new miniCssExtractPlugin()
], ],
@@ -67,7 +67,7 @@ module.exports = {
},], },],
}, },
resolve: { resolve: {
extensions: ['.tsx', '.ts', '.js'], extensions: ['.tsx', '.ts', '.js', '.json'],
fallback: { fallback: {
"crypto": require.resolve("crypto-browserify"), "crypto": require.resolve("crypto-browserify"),
"buffer": require.resolve("buffer"), "buffer": require.resolve("buffer"),
@@ -79,8 +79,9 @@ module.exports = {
asyncWebAssembly: true, asyncWebAssembly: true,
syncWebAssembly: true, syncWebAssembly: true,
}, },
// output: { output: {
// filename: 'bundle.js', path: path.resolve(__dirname, 'dist'),
// path: path.resolve(__dirname, 'dist'),
// }, clean: true,
},
}; };

View File

@@ -19,7 +19,7 @@ module.exports = {
mode: "production", mode: "production",
devtool: "source-map", devtool: "source-map",
plugins: [ plugins: [
new CopyWebpackPlugin({ patterns: ['img/*.png', 'img/*/*.png'] }), new CopyWebpackPlugin({ patterns: ['img/*.png', 'img/*/*.png', { from: 'data/database.json', to: 'data' }] }),
new HtmlWebpackPlugin({ template: './src/index.html' }), new HtmlWebpackPlugin({ template: './src/index.html' }),
new miniCssExtractPlugin() new miniCssExtractPlugin()
], ],
@@ -119,9 +119,10 @@ module.exports = {
}, },
}) })
] ]
} },
// output: { output: {
// filename: 'bundle.js', filename: 'bundle.js',
// path: path.resolve(__dirname, 'dist'), path: path.resolve(__dirname, 'dist'),
// }, clean: true
},
}; };