Merge pull request #18 from Ryex/attach_devices

Let Users Attach devices
This commit is contained in:
Rachel Powers
2024-04-17 19:24:49 -07:00
committed by GitHub
61 changed files with 51476 additions and 5499 deletions

1
Cargo.lock generated
View File

@@ -588,6 +588,7 @@ dependencies = [
"serde",
"serde-wasm-bindgen 0.6.5",
"serde_with",
"strum",
"thiserror",
"tsify",
"wasm-bindgen",

1
ic10emu/data/Enums.json Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,12 @@
{
"english": {
"bapz": "Branch to line c if abs(a) <= max(b * abs(a), float.epsilon * 8)",
"bapzal": "Branch to line c if abs(a) <= max(b * abs(a), float.epsilon * 8) and store next line number in ra",
"bnaz": "Branch to line c if abs(a) > max b * abs(a), float.epsilon * 8)",
"bnazal": "Branch to line c if abs(a) > max b * abs(a), float.epsilon * 8) and store next line number in ra",
"brapz": "Relative branch to line c if abs(a) <= max(b * abs(a), float.epsilon * 8)",
"brnaz": "Relative branch to line c if abs(a) > max(b * abs(a), float.epsilon * 8)",
"sapz": "Register = 1 if |a| <= max(b * abs(a), float.epsilon * 8), otherwise 0",
"snaz": "Register = 1 if |a| > max(b * abs(a), float.epsilon), otherwise 0"
}
}

View File

@@ -8,8 +8,8 @@ atan Returns the angle (radians) whos tan is the specified value
atan2 Returns the angle (radians) whose tangent is the quotient of two specified values: a (y) and b (x)
bap Branch to line d if abs(a - b) <= max(c * max(abs(a), abs(b)), float.epsilon * 8)
bapal Branch to line d if abs(a - b) <= max(c * max(abs(a), abs(b)), float.epsilon * 8) and store next line number in ra
bapz Branch to line c if abs(a) <= float.epsilon * 8
bapzal Branch to line c if abs(a) <= float.epsilon * 8
bapz Branch to line c if abs(a) <= max(b * abs(a), float.epsilon * 8)
bapzal Branch to line c if abs(a) <= max(b * abs(a), float.epsilon * 8) and store next line number in ra
bdns Branch to line a if device d isn't set
bdnsal Jump execution to line a and store next line number if device is not set
bdse Branch to line a if device d is set
@@ -37,14 +37,14 @@ bltzal Branch to line b if a < 0 and store next line number in ra
bna Branch to line d if abs(a - b) > max(c * max(abs(a), abs(b)), float.epsilon * 8)
bnaal Branch to line d if abs(a - b) <= max(c * max(abs(a), abs(b)), float.epsilon * 8) and store next line number in ra
bnan Branch to line b if a is not a number (NaN)
bnaz Branch to line c if abs(a) > float.epsilon * 8
bnazal Branch to line c if abs(a) > float.epsilon * 8
bnaz Branch to line c if abs(a) > max b * abs(a), float.epsilon * 8)
bnazal Branch to line c if abs(a) > max b * abs(a), float.epsilon * 8) and store next line number in ra
bne Branch to line c if a != b
bneal Branch to line c if a != b and store next line number in ra
bnez branch to line b if a != 0
bnezal Branch to line b if a != 0 and store next line number in ra
brap Relative branch to line d if abs(a - b) <= max(c * max(abs(a), abs(b)), float.epsilon * 8)
brapz Relative branch to line c if abs(a) <= float.epsilon * 8
brapz Relative branch to line c if abs(a) <= max(b * abs(a), float.epsilon * 8)
brdns Relative jump to line a if device is not set
brdse Relative jump to line a if device is set
breq Relative branch to line c if a == b
@@ -59,7 +59,7 @@ brlt Relative jump to line c if a < b
brltz Relative branch to line b if a < 0
brna Relative branch to line d if abs(a - b) > max(c * max(abs(a), abs(b)), float.epsilon * 8)
brnan Relative branch to line b if a is not a number (NaN)
brnaz Relative branch to line c if abs(a) > float.epsilon * 8
brnaz Relative branch to line c if abs(a) > max(b * abs(a), float.epsilon * 8)
brne Relative branch to line c if a != b
brnez Relative branch to line b if a != 0
ceil Register = smallest integer greater than a
@@ -97,7 +97,7 @@ rand Register = a random value x with 0 <= x < 1
round Register = a rounded to nearest integer
s Stores register value to LogicType on device by housing index value.
sap Register = 1 if abs(a - b) <= max(c * max(abs(a), abs(b)), float.epsilon * 8), otherwise 0
sapz Register = 1 if |a| <= float.epsilon * 8, otherwise 0
sapz Register = 1 if |a| <= max(b * abs(a), float.epsilon * 8), otherwise 0
sb Stores register value to LogicType on all output network devices with provided type hash.
sbn Stores register value to LogicType on all output network devices with provided type hash and name.
sbs Stores register value to LogicSlotType on all output network devices with provided type hash in the provided slot.
@@ -122,7 +122,7 @@ sltz Register = 1 if a < 0, otherwise 0
sna Register = 1 if abs(a - b) > max(c * max(abs(a), abs(b)), float.epsilon * 8), otherwise 0
snan Register = 1 if a is NaN, otherwise 0
snanz Register = 0 if a is NaN, otherwise 1
snaz Register = 1 if |a| > float.epsilon, otherwise 0
snaz Register = 1 if |a| > max(b * abs(a), float.epsilon), otherwise 0
sne Register = 1 if a != b, otherwise 0
snez Register = 1 if a != 0, otherwise 0
sqrt Register = square root of a

View File

@@ -1,15 +1,16 @@
from collections import defaultdict
import json
import xml.etree.ElementTree as ET
import argparse
from pathlib import Path
import sys
import re
from itertools import chain
import struct
import binascii
import json
import re
import struct
import sys
import xml.etree.ElementTree as ET
from collections import defaultdict
from itertools import chain
from pathlib import Path
def intOrNone(val):
def intOrNone(val: str):
try:
return int(val)
except ValueError:
@@ -20,32 +21,32 @@ def main():
description="Generate instructions, enums, and docs for lsp.\n\nWorks best when using https://github.com/Ryex/StationeersStationpediaExtractor",
epilog="Point at the Stationeers install and go!",
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
arg_parser.add_argument("path", help="Path to Stationeers installation")
arg_parser.add_argument("--lang", help="language to extract from (ie. english)", default="english")
_ = arg_parser.add_argument("path", help="Path to Stationeers installation")
_ = arg_parser.add_argument("--lang", help="language to extract from (ie. english)", default="english")
args = arg_parser.parse_args()
install_path = Path(args.path)
install_path = Path(args.path) # type:ignore[reportAny]
if install_path.match("Stationeers/*.exe") or install_path.match("Stationeers/rocketstation_Data"):
install_path = install_path.parent
elif install_path.name == "Stationeers":
pass
elif (install_path / "Stationeers").is_dir():
install_path = install_path / "Stationeers"
data_path = install_path / "rocketstation_Data" / "StreamingAssets" / "Language"
data_path = install_path / "rocketstation_Data" / "StreamingAssets" / "Language"
if not data_path.is_dir():
print(f"Invalid install path. {install_path} does not point to a valid Stationeers installation")
arg_parser.print_help()
sys.exit(1)
lang = args.lang
lang: str = args.lang # type:ignore[reportAny]
if not (data_path / f"{lang}.xml").is_file():
print("Language file '{lang}.xml' does not exist. can not pull help strings.")
sys.exit(2)
extract_data(install_path, data_path, lang)
def extract_data(install_path, data_path: Path, language: str):
def extract_data(install_path: Path, data_path: Path, language: str):
tree = ET.parse(data_path / f"{language}.xml")
root = tree.getroot()
interface = root.find("Interface")
@@ -53,7 +54,7 @@ def extract_data(install_path, data_path: Path, language: str):
colors = root.find("Colors")
elms = [elm for elm in (interface, strings, colors) if elm is not None ]
logic_type = re.compile(r"LogicType(\w+)")
logic_slot_type = re.compile(r"LogicSlotType(\w+)")
script_command = re.compile(r"ScriptCommand(\w+)")
@@ -89,11 +90,11 @@ def extract_data(install_path, data_path: Path, language: str):
op_help_patch_path = Path("data") / "instruction_help_patches.json"
if op_help_patch_path.exists():
with op_help_patch_path.open(mode="r") as f:
patches = defaultdict(dict)
patches.update(json.load(f))
patches: dict[str, dict[str,str]] = defaultdict(dict)
patches.update(json.load(f)) # type:ignore[reportAny]
operation_help_strings.update(patches[language])
enums = {}
enums: dict[str, tuple[int | None, str]] = {}
with (Path("data") / "enums.txt").open("r") as f:
for line in f.readlines():
match line.strip().split(' ', maxsplit=2):
@@ -121,7 +122,7 @@ def extract_data(install_path, data_path: Path, language: str):
logictypes[name] = (intOrNone(val), help)
case _:
pass
with(Path("data") / "slotlogictypes.txt").open("r") as f:
for line in f.readlines():
match line.strip().split(' ', maxsplit=2):
@@ -136,8 +137,8 @@ def extract_data(install_path, data_path: Path, language: str):
slotlogictypes[name] = (intOrNone(val), help)
case _:
pass
batchmodes = {}
batchmodes: dict[str, tuple[int | None, str]] = {}
with(Path("data") / "batchmodes.txt").open("r") as f:
for line in f.readlines():
match line.strip().split(' ', maxsplit=2):
@@ -148,7 +149,7 @@ def extract_data(install_path, data_path: Path, language: str):
case _:
pass
reagentmodes = {}
reagentmodes: dict[str, tuple[int | None, str]] = {}
with(Path("data") / "reagentmodes.txt").open("r") as f:
for line in f.readlines():
match line.strip().split(' ', maxsplit=2):
@@ -162,8 +163,8 @@ def extract_data(install_path, data_path: Path, language: str):
enum_values_path = install_path / "Stationpedia" / "Enums.json"
if enum_values_path.exists():
with enum_values_path.open(mode="r") as f:
enum_values = json.load(f)
def update_enum(enum, values):
enum_values: dict[str, dict[str, int]] = json.load(f)
def update_enum(enum: dict[str, tuple[int | None, str]], values: dict[str, int]):
for name, val, in values.items():
if name in enum:
_, help = enum[name]
@@ -178,13 +179,13 @@ def extract_data(install_path, data_path: Path, language: str):
update_enum(batchmodes, enum_values["LogicBatchMethod"])
update_enum(reagentmodes, enum_values["LogicReagentMode"])
update_enum(enums, enum_values["Enums"])
op_help_path = Path("data") / "instructions_help.txt"
with op_help_path.open(mode="w") as f:
for key, val in sorted(operation_help_strings.items()):
f.write("{} {}\n".format(key, val.replace("\r", "").replace("\n", "\\n")))
_ = f.write("{} {}\n".format(key, val.replace("\r", "").replace("\n", "\\n")))
stationpedia: dict[str, tuple[str, str | None]] = {}
stationpedia: dict[int, tuple[str, str | None]] = {}
things = root.find("Things")
reagents = root.find("Reagents")
hashables = [elm for elm in (things, reagents) if elm is not None]
@@ -197,44 +198,44 @@ def extract_data(install_path, data_path: Path, language: str):
value = value.text
if key is None:
continue
crc = binascii.crc32(key.encode('utf-8'))
crc_s = struct.unpack("i", struct.pack("I", crc))[0]
stationpedia[crc_s] = (key, value)
crc_u = binascii.crc32(key.encode('utf-8'))
crc_i: int = struct.unpack("i", struct.pack("I", crc_u))[0]
stationpedia[crc_i] = (key, value)
exported_stationpedia_path = install_path / "Stationpedia" / "Stationpedia.json"
if exported_stationpedia_path.exists():
with exported_stationpedia_path.open(mode="r") as f:
exported = json.load(f)
for page in exported["pages"]:
exported: dict[str, list[dict[str, Any]]] = json.load(f) # type:ignore[reportAny]
for page in exported["pages"]: # type:ignore[reportUnknownVariableType]
stationpedia[page["PrefabHash"]] = (page["PrefabName"], page["Title"])
hashables_path = Path("data") / "stationpedia.txt"
with hashables_path.open(mode="w") as f:
for key, val in sorted(stationpedia.items(), key=lambda i: i[1][0]):
name = val[0]
desc = val[1] if val[1] is not None else ""
f.write("{} {} {}\n".format(key, name, desc.replace("\r", "").replace("\n", "\\n")))
_ = f.write("{} {} {}\n".format(key, name, desc.replace("\r", "").replace("\n", "\\n")))
logic_types_path = Path("data") / "logictypes.txt"
with logic_types_path.open(mode="w") as f:
for t, (v, help) in sorted(logictypes.items()):
f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
_ = f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
slot_logic_types_path = Path("data") / "slotlogictypes.txt"
with slot_logic_types_path.open(mode="w") as f:
for t, (v, help) in sorted(slotlogictypes.items()):
f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
_ = f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
batch_modes_path = Path("data") / "batchmodes.txt"
with batch_modes_path.open(mode="w") as f:
for t, (v, help) in sorted(batchmodes.items()):
f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
_ = f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
reagent_modes_path = Path("data") / "reagentmodes.txt"
with reagent_modes_path.open(mode="w") as f:
for t, (v, help) in sorted(reagentmodes.items()):
f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
_ = f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
enums_path = Path("data") / "enums.txt"
with enums_path.open(mode="w") as f:
for name, (val, help) in sorted(enums.items()):
f.write(f"{name} {val} {help.replace("\r", "").replace("\n", "\\n")}\n")
_ = f.write(f"{name} {val} {help.replace("\r", "").replace("\n", "\\n")}\n")
if __name__ == "__main__":
main()

View File

@@ -339,7 +339,7 @@ pub struct RegisterSpec {
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct DeviceSpec {
pub device: Device,
pub connection: Option<u32>,
pub connection: Option<usize>,
}
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
@@ -424,7 +424,7 @@ impl Operand {
ic: &interpreter::IC,
inst: InstructionOp,
index: u32,
) -> Result<(Option<u16>, Option<u32>), interpreter::ICError> {
) -> Result<(Option<u32>, Option<usize>), interpreter::ICError> {
match self.translate_alias(ic) {
Operand::DeviceSpec(DeviceSpec { device, connection }) => match device {
Device::Db => Ok((Some(ic.device), connection)),
@@ -615,7 +615,7 @@ impl FromStr for Operand {
let connection_str = rest_iter
.take_while_ref(|c| c.is_ascii_digit())
.collect::<String>();
let connection = connection_str.parse::<u32>().unwrap();
let connection = connection_str.parse::<usize>().unwrap();
if rest_iter.next().is_none() {
Ok(Some(connection))
} else {
@@ -669,7 +669,7 @@ impl FromStr for Operand {
let connection_str = rest_iter
.take_while_ref(|c| c.is_ascii_digit())
.collect::<String>();
let connection = connection_str.parse::<u32>().unwrap();
let connection = connection_str.parse::<usize>().unwrap();
if rest_iter.next().is_none() {
Ok(Some(connection))
} else {

View File

@@ -105,11 +105,13 @@ pub enum ICError {
#[error("connection specifier missing")]
MissingConnectionSpecifier,
#[error("no data network on connection '{0}'")]
NotDataConnection(usize),
NotACableConnection(usize),
#[error("network not connected on connection '{0}'")]
NetworkNotConnected(usize),
#[error("bad network Id '{0}'")]
BadNetworkId(u32),
#[error("channel index out of range '{0}'")]
ChannelIndexOutOfRange(usize),
}
impl ICError {
@@ -169,15 +171,17 @@ impl Display for ICState {
#[derive(Debug)]
pub struct IC {
pub device: u16,
pub id: u16,
pub device: u32,
pub id: u32,
pub registers: [f64; 18],
/// Instruction Pointer
pub ip: u32,
/// Instruction Count since last yield
pub ic: u16,
pub stack: [f64; 512],
pub aliases: HashMap<String, grammar::Operand>,
pub defines: HashMap<String, f64>,
pub pins: [Option<u16>; 6],
pub pins: [Option<u32>; 6],
pub code: String,
pub program: Program,
pub state: ICState,
@@ -295,7 +299,7 @@ impl Program {
}
impl IC {
pub fn new(id: u16, device: u16) -> Self {
pub fn new(id: u32, device: u32) -> Self {
IC {
device,
id,
@@ -2042,8 +2046,14 @@ impl IC {
Some(device) => match device.borrow().ic.as_ref() {
Some(ic_id) => {
let addr = addr.as_value(this, inst, 3)?;
let ic = vm.ics.get(ic_id).unwrap().borrow();
let val = ic.peek_addr(addr)?;
let val = {
if ic_id == &this.id {
this.peek_addr(addr)
} else {
let ic = vm.ics.get(ic_id).unwrap().borrow();
ic.peek_addr(addr)
}
}?;
this.set_register(indirection, target, val)?;
Ok(())
}
@@ -2069,8 +2079,14 @@ impl IC {
Some(device) => match device.borrow().ic.as_ref() {
Some(ic_id) => {
let addr = addr.as_value(this, inst, 3)?;
let ic = vm.ics.get(ic_id).unwrap().borrow();
let val = ic.peek_addr(addr)?;
let val = {
if ic_id == &this.id {
this.peek_addr(addr)
} else {
let ic = vm.ics.get(ic_id).unwrap().borrow();
ic.peek_addr(addr)
}
}?;
this.set_register(indirection, target, val)?;
Ok(())
}
@@ -2093,8 +2109,12 @@ impl IC {
Some(ic_id) => {
let addr = addr.as_value(this, inst, 2)?;
let val = val.as_value(this, inst, 3)?;
let mut ic = vm.ics.get(ic_id).unwrap().borrow_mut();
ic.poke(addr, val)?;
if ic_id == &this.id {
this.poke(addr, val)?;
} else {
let mut ic = vm.ics.get(ic_id).unwrap().borrow_mut();
ic.poke(addr, val)?;
}
vm.set_modified(device_id);
Ok(())
}
@@ -2111,15 +2131,19 @@ impl IC {
if device_id >= u16::MAX as f64 || device_id < u16::MIN as f64 {
return Err(DeviceIndexOutOfRange(device_id));
}
let device = vm.get_device_same_network(this.device, device_id as u16);
let device = vm.get_device_same_network(this.device, device_id as u32);
match device {
Some(device) => match device.borrow().ic.as_ref() {
Some(ic_id) => {
let addr = addr.as_value(this, inst, 2)?;
let val = val.as_value(this, inst, 3)?;
let mut ic = vm.ics.get(ic_id).unwrap().borrow_mut();
ic.poke(addr, val)?;
vm.set_modified(device_id as u16);
if ic_id == &this.id {
this.poke(addr, val)?;
} else {
let mut ic = vm.ics.get(ic_id).unwrap().borrow_mut();
ic.poke(addr, val)?;
}
vm.set_modified(device_id as u32);
Ok(())
}
None => Err(DeviceHasNoIC),
@@ -2143,17 +2167,17 @@ impl IC {
};
let network_id = vm
.get_device_same_network(this.device, device_id)
.map(|device| device.borrow().get_network_id(connection as usize))
.map(|device| device.borrow().get_network_id(connection))
.unwrap_or(Err(UnknownDeviceID(device_id as f64)))?;
let val = val.as_value(this, inst, 3)?;
vm.set_network_channel(network_id as usize, channel, val)?;
vm.set_network_channel(network_id, channel, val)?;
return Ok(());
}
let device = vm.get_device_same_network(this.device, device_id);
match device {
Some(device) => {
let val = val.as_value(this, inst, 1)?;
device.borrow_mut().set_field(lt, val)?;
device.borrow_mut().set_field(lt, val, vm)?;
vm.set_modified(device_id);
Ok(())
}
@@ -2168,13 +2192,13 @@ impl IC {
if device_id >= u16::MAX as f64 || device_id < u16::MIN as f64 {
return Err(DeviceIndexOutOfRange(device_id));
}
let device = vm.get_device_same_network(this.device, device_id as u16);
let device = vm.get_device_same_network(this.device, device_id as u32);
match device {
Some(device) => {
let lt = lt.as_logic_type(this, inst, 2)?;
let val = val.as_value(this, inst, 3)?;
device.borrow_mut().set_field(lt, val)?;
vm.set_modified(device_id as u16);
device.borrow_mut().set_field(lt, val, vm)?;
vm.set_modified(device_id as u32);
Ok(())
}
None => Err(UnknownDeviceID(device_id)),
@@ -2193,7 +2217,7 @@ impl IC {
let index = index.as_value(this, inst, 2)?;
let slt = slt.as_slot_logic_type(this, inst, 3)?;
let val = val.as_value(this, inst, 4)?;
device.borrow_mut().set_slot_field(index, slt, val)?;
device.borrow_mut().set_slot_field(index, slt, val, vm)?;
vm.set_modified(device_id);
Ok(())
}
@@ -2252,16 +2276,16 @@ impl IC {
};
let network_id = vm
.get_device_same_network(this.device, device_id)
.map(|device| device.borrow().get_network_id(connection as usize))
.map(|device| device.borrow().get_network_id(connection))
.unwrap_or(Err(UnknownDeviceID(device_id as f64)))?;
let val = vm.get_network_channel(network_id as usize, channel)?;
let val = vm.get_network_channel(network_id, channel)?;
this.set_register(indirection, target, val)?;
return Ok(());
}
let device = vm.get_device_same_network(this.device, device_id);
match device {
Some(device) => {
let val = device.borrow().get_field(lt)?;
let val = device.borrow().get_field(lt, vm)?;
this.set_register(indirection, target, val)?;
Ok(())
}
@@ -2280,11 +2304,11 @@ impl IC {
if device_id >= u16::MAX as f64 || device_id < u16::MIN as f64 {
return Err(DeviceIndexOutOfRange(device_id));
}
let device = vm.get_device_same_network(this.device, device_id as u16);
let device = vm.get_device_same_network(this.device, device_id as u32);
match device {
Some(device) => {
let lt = lt.as_logic_type(this, inst, 3)?;
let val = device.borrow().get_field(lt)?;
let val = device.borrow().get_field(lt, vm)?;
this.set_register(indirection, target, val)?;
Ok(())
}
@@ -2307,7 +2331,7 @@ impl IC {
Some(device) => {
let index = index.as_value(this, inst, 3)?;
let slt = slt.as_slot_logic_type(this, inst, 4)?;
let val = device.borrow().get_slot_field(index, slt)?;
let val = device.borrow().get_slot_field(index, slt, vm)?;
this.set_register(indirection, target, val)?;
Ok(())
}

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,11 @@ serde_with = "3.7.0"
tsify = { version = "0.4.5", default-features = false, features = ["js", "wasm-bindgen"] }
thiserror = "1.0.58"
[build-dependencies]
ic10emu = { path = "../ic10emu" }
strum = { version = "0.26.2"}
itertools = "0.12.1"
[features]
default = ["console_error_panic_hook"]
console_error_panic_hook = ["dep:console_error_panic_hook"]

View File

@@ -5,18 +5,59 @@ use std::{
path::Path,
};
use itertools::Itertools;
use strum::IntoEnumIterator;
fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("ts_types.rs");
let output_file = File::create(dest_path).unwrap();
let mut writer = BufWriter::new(&output_file);
let mut ts_types: String = String::new();
let lt_tsunion: String = Itertools::intersperse(
ic10emu::grammar::generated::LogicType::iter().map(|lt| format!("\"{}\"", lt.as_ref())),
"\n | ".to_owned(),
)
.collect();
let lt_tstype = format!("\nexport type LogicType = {};", lt_tsunion);
ts_types.push_str(&lt_tstype);
let slt_tsunion: String = Itertools::intersperse(
ic10emu::grammar::generated::SlotLogicType::iter().map(|slt| format!("\"{}\"", slt.as_ref())),
"\n | ".to_owned(),
)
.collect();
let slt_tstype = format!("\nexport type SlotLogicType = {};", slt_tsunion);
ts_types.push_str(&slt_tstype);
let bm_tsunion: String = Itertools::intersperse(
ic10emu::grammar::generated::BatchMode::iter().map(|bm| format!("\"{}\"", bm.as_ref())),
"\n | ".to_owned(),
)
.collect();
let bm_tstype = format!("\nexport type BatchMode = {};", bm_tsunion);
ts_types.push_str(&bm_tstype);
let rm_tsunion: String = Itertools::intersperse(
ic10emu::grammar::generated::ReagentMode::iter().map(|rm| format!("\"{}\"", rm.as_ref())),
"\n | ".to_owned(),
)
.collect();
let rm_tstype = format!("\nexport type ReagentMode = {};", rm_tsunion);
ts_types.push_str(&rm_tstype);
let infile = Path::new("src/types.ts");
let contents = fs::read_to_string(infile).unwrap();
ts_types.push('\n');
ts_types.push_str(&contents);
write!(
&mut writer,
"#[wasm_bindgen(typescript_custom_section)]\n\
const TYPES: &'static str = r#\"{contents}\"#;
const TYPES: &'static str = r#\"{ts_types}\"#;
"
)
.unwrap();

View File

@@ -4,7 +4,7 @@ mod types;
use ic10emu::{
grammar::{LogicType, SlotLogicType},
Connection,
DeviceTemplate,
};
use serde::{Deserialize, Serialize};
use types::{Registers, Stack};
@@ -43,38 +43,59 @@ impl DeviceRef {
}
#[wasm_bindgen(getter)]
pub fn id(&self) -> u16 {
pub fn id(&self) -> u32 {
self.device.borrow().id
}
#[wasm_bindgen(getter)]
pub fn ic(&self) -> Option<u32> {
self.device.borrow().ic
}
#[wasm_bindgen(getter)]
pub fn name(&self) -> Option<String> {
self.device.borrow().name.clone()
}
#[wasm_bindgen(getter, js_name = "nameHash")]
pub fn name_hash(&self) -> Option<f64> {
pub fn name_hash(&self) -> Option<i32> {
self.device.borrow().name_hash
}
#[wasm_bindgen(getter, js_name = "prefabName")]
pub fn prefab_name(&self) -> Option<String> {
self.device.borrow().prefab_name.clone()
self.device
.borrow()
.prefab
.as_ref()
.map(|prefab| prefab.name.clone())
}
#[wasm_bindgen(getter, js_name = "prefabHash")]
pub fn prefab_hash(&self) -> Option<i32> {
self.device.borrow().prefab_hash
self.device
.borrow()
.prefab
.as_ref()
.map(|prefab| prefab.hash)
}
#[wasm_bindgen(getter, skip_typescript)]
pub fn fields(&self) -> JsValue {
serde_wasm_bindgen::to_value(&self.device.borrow().fields).unwrap()
serde_wasm_bindgen::to_value(&self.device.borrow().get_fields(&self.vm.borrow())).unwrap()
}
#[wasm_bindgen(getter, skip_typescript)]
pub fn slots(&self) -> JsValue {
serde_wasm_bindgen::to_value(&self.device.borrow().slots).unwrap()
pub fn slots(&self) -> Vec<JsValue> {
self.device
.borrow()
.slots
.iter()
.map(|slot| {
let flat_slot: types::Slot = slot.into();
serde_wasm_bindgen::to_value(&flat_slot).unwrap()
})
.collect_vec()
}
#[wasm_bindgen(getter, skip_typescript)]
@@ -267,67 +288,55 @@ impl DeviceRef {
}
#[wasm_bindgen(js_name = "setField")]
pub fn set_field(&self, field: &str, value: f64) -> Result<f64, JsError> {
pub fn set_field(&self, field: &str, value: f64) -> Result<(), JsError> {
let logic_typ = LogicType::from_str(field)?;
let mut device_ref = self.device.borrow_mut();
let logic_field = device_ref
.fields
.get_mut(&logic_typ)
.ok_or_else(|| BindingError::InvalidEnumVariant(field.to_owned()))?;
let last = logic_field.value;
logic_field.value = value;
Ok(last)
}
#[wasm_bindgen(js_name = "setSlotField")]
pub fn set_slot_field(&self, slot: usize, field: &str, value: f64) -> Result<f64, JsError> {
let logic_typ = SlotLogicType::from_str(field)?;
let mut device_ref = self.device.borrow_mut();
let slots_len = device_ref.slots.len();
let slot = device_ref
.slots
.get_mut(slot)
.ok_or(BindingError::OutOfBounds(slot, slots_len))?;
let logic_field = slot
.fields
.get_mut(&logic_typ)
.ok_or_else(|| BindingError::InvalidEnumVariant(field.to_owned()))?;
let last = logic_field.value;
logic_field.value = value;
Ok(last)
}
#[wasm_bindgen(js_name = "setConnection")]
pub fn set_connection(&self, conn: usize, net: Option<u16>) -> Result<(), JsError> {
let mut device_ref = self.device.borrow_mut();
let conn_len = device_ref.connections.len();
let conn_ref = device_ref
.connections
.get_mut(conn)
.ok_or(BindingError::OutOfBounds(conn, conn_len))?;
match conn_ref {
&mut Connection::CableNetwork(ref mut net_ref) => *net_ref = net,
_ => {
*conn_ref = Connection::CableNetwork(net);
}
}
device_ref.set_field(logic_typ, value, &self.vm.borrow())?;
Ok(())
}
#[wasm_bindgen(js_name = "addDeviceToNetwork")]
pub fn add_device_to_network(&self, network_id: u16, connection: usize) -> Result<bool, JsError> {
let id = self.device.borrow().id;
Ok(self.vm.borrow().add_device_to_network(id, network_id, connection)?)
#[wasm_bindgen(js_name = "setSlotField")]
pub fn set_slot_field(&self, slot: f64, field: &str, value: f64) -> Result<(), JsError> {
let logic_typ = SlotLogicType::from_str(field)?;
let mut device_ref = self.device.borrow_mut();
device_ref.set_slot_field(slot, logic_typ, value, &self.vm.borrow())?;
Ok(())
}
#[wasm_bindgen(js_name = "getSlotField")]
pub fn get_slot_field(&self, slot: f64, field: &str) -> Result<f64, JsError> {
let logic_typ = SlotLogicType::from_str(field)?;
let device_ref = self.device.borrow_mut();
Ok(device_ref.get_slot_field(slot, logic_typ, &self.vm.borrow())?)
}
#[wasm_bindgen(js_name = "getSlotFields", skip_typescript)]
pub fn get_slot_fields(&self, slot: f64) -> Result<JsValue, JsError> {
let device_ref = self.device.borrow_mut();
let fields = device_ref.get_slot_fields(slot, &self.vm.borrow())?;
Ok(serde_wasm_bindgen::to_value(&fields).unwrap())
}
#[wasm_bindgen(js_name = "setConnection")]
pub fn set_connection(&self, conn: usize, net: Option<u32>) -> Result<(), JsError> {
let device_id = self.device.borrow().id;
self.vm
.borrow()
.set_device_connection(device_id, conn, net)?;
Ok(())
}
#[wasm_bindgen(js_name = "removeDeviceFromNetwork")]
pub fn remove_device_from_network(&self, network_id: u16) -> Result<bool, JsError> {
pub fn remove_device_from_network(&self, network_id: u32) -> Result<bool, JsError> {
let id = self.device.borrow().id;
Ok(self.vm.borrow().remove_device_from_network(id, network_id)?)
Ok(self
.vm
.borrow()
.remove_device_from_network(id, network_id)?)
}
#[wasm_bindgen(js_name = "setPin")]
pub fn set_pin(&self, pin: usize, val: Option<u16>) -> Result<bool, JsError> {
pub fn set_pin(&self, pin: usize, val: Option<u32>) -> Result<bool, JsError> {
let id = self.device.borrow().id;
Ok(self.vm.borrow().set_pin(id, pin, val)?)
}
@@ -349,89 +358,118 @@ impl VM {
}
#[wasm_bindgen(js_name = "addDevice")]
pub fn add_device(&self, network: Option<u16>) -> Result<u16, JsError> {
pub fn add_device(&self, network: Option<u32>) -> Result<u32, JsError> {
Ok(self.vm.borrow_mut().add_device(network)?)
}
#[wasm_bindgen(js_name = "addDeviceFromTemplate", skip_typescript)]
pub fn add_device_from_template(&self, template: JsValue) -> Result<u32, JsError> {
let template: DeviceTemplate = serde_wasm_bindgen::from_value(template)?;
web_sys::console::log_2(
&"(wasm) adding device".into(),
&serde_wasm_bindgen::to_value(&template).unwrap(),
);
Ok(self.vm.borrow_mut().add_device_from_template(template)?)
}
#[wasm_bindgen(js_name = "getDevice")]
pub fn get_device(&self, id: u16) -> Option<DeviceRef> {
pub fn get_device(&self, id: u32) -> Option<DeviceRef> {
let device = self.vm.borrow().get_device(id);
device.map(|d| DeviceRef::from_device(d.clone(), self.vm.clone()))
}
#[wasm_bindgen(js_name = "setCode")]
/// Set program code if it's valid
pub fn set_code(&self, id: u16, code: &str) -> Result<bool, JsError> {
pub fn set_code(&self, id: u32, code: &str) -> Result<bool, JsError> {
Ok(self.vm.borrow().set_code(id, code)?)
}
#[wasm_bindgen(js_name = "setCodeInvalid")]
/// Set program code and translate invalid lines to Nop, collecting errors
pub fn set_code_invalid(&self, id: u16, code: &str) -> Result<bool, JsError> {
pub fn set_code_invalid(&self, id: u32, code: &str) -> Result<bool, JsError> {
Ok(self.vm.borrow().set_code_invalid(id, code)?)
}
#[wasm_bindgen(js_name = "stepIC")]
pub fn step_ic(&self, id: u16, advance_ip_on_err: bool) -> Result<bool, JsError> {
pub fn step_ic(&self, id: u32, advance_ip_on_err: bool) -> Result<bool, JsError> {
Ok(self.vm.borrow().step_ic(id, advance_ip_on_err)?)
}
#[wasm_bindgen(js_name = "runIC")]
pub fn run_ic(&self, id: u16, ignore_errors: bool) -> Result<bool, JsError> {
pub fn run_ic(&self, id: u32, ignore_errors: bool) -> Result<bool, JsError> {
Ok(self.vm.borrow().run_ic(id, ignore_errors)?)
}
#[wasm_bindgen(js_name = "resetIC")]
pub fn reset_ic(&self, id: u16) -> Result<bool, JsError> {
pub fn reset_ic(&self, id: u32) -> Result<bool, JsError> {
Ok(self.vm.borrow().reset_ic(id)?)
}
#[wasm_bindgen(getter, js_name = "defaultNetwork")]
pub fn default_network(&self) -> u16 {
pub fn default_network(&self) -> u32 {
self.vm.borrow().default_network
}
#[wasm_bindgen(getter)]
pub fn devices(&self) -> Vec<u16> {
pub fn devices(&self) -> Vec<u32> {
self.vm.borrow().devices.keys().copied().collect_vec()
}
#[wasm_bindgen(getter)]
pub fn networks(&self) -> Vec<u16> {
pub fn networks(&self) -> Vec<u32> {
self.vm.borrow().networks.keys().copied().collect_vec()
}
#[wasm_bindgen(getter)]
pub fn ics(&self) -> Vec<u16> {
pub fn ics(&self) -> Vec<u32> {
self.vm.borrow().ics.keys().copied().collect_vec()
}
#[wasm_bindgen(getter, js_name = "lastOperationModified")]
pub fn last_operation_modified(&self) -> Vec<u16> {
pub fn last_operation_modified(&self) -> Vec<u32> {
self.vm.borrow().last_operation_modified()
}
#[wasm_bindgen(js_name = "visibleDevices")]
pub fn visible_devices(&self, source: u16) -> Vec<u16> {
pub fn visible_devices(&self, source: u32) -> Vec<u32> {
self.vm.borrow().visible_devices(source)
}
#[wasm_bindgen(js_name = "addDeviceToNetwork")]
pub fn add_device_to_network(&self, id: u16, network_id: u16, connection: usize) -> Result<bool, JsError> {
Ok(self.vm.borrow().add_device_to_network(id, network_id, connection)?)
#[wasm_bindgen(js_name = "setDeviceConnection")]
pub fn set_device_connection(
&self,
id: u32,
connection: usize,
network_id: Option<u32>,
) -> Result<bool, JsError> {
Ok(self
.vm
.borrow()
.set_device_connection(id, connection, network_id)?)
}
#[wasm_bindgen(js_name = "removeDeviceFromNetwork")]
pub fn remove_device_from_network(&self, id: u16, network_id: u16) -> Result<bool, JsError> {
Ok(self.vm.borrow().remove_device_from_network(id, network_id)?)
pub fn remove_device_from_network(&self, id: u32, network_id: u32) -> Result<bool, JsError> {
Ok(self
.vm
.borrow()
.remove_device_from_network(id, network_id)?)
}
#[wasm_bindgen(js_name = "setPin")]
pub fn set_pin(&self, id: u16, pin: usize, val: Option<u16>) -> Result<bool, JsError> {
pub fn set_pin(&self, id: u32, pin: usize, val: Option<u32>) -> Result<bool, JsError> {
Ok(self.vm.borrow().set_pin(id, pin, val)?)
}
#[wasm_bindgen(js_name = "changeDeviceId")]
pub fn change_device_id(&self, old_id: u32, new_id: u32) -> Result<(), JsError> {
Ok(self.vm.borrow_mut().change_device_id(old_id, new_id)?)
}
#[wasm_bindgen(js_name = "removeDevice")]
pub fn remove_device(&self, id: u32) -> Result<(), JsError> {
Ok(self.vm.borrow_mut().remove_device(id)?)
}
}
impl Default for VM {

View File

@@ -1,3 +1,4 @@
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
@@ -14,4 +15,45 @@ pub struct Stack(#[serde_as(as = "[_; 512]")] pub [f64; 512]);
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct Registers(#[serde_as(as = "[_; 18]")] pub [f64; 18]);
include!(concat!(env!("OUT_DIR"), "/ts_types.rs"));
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SlotOccupant {
pub id: u32,
pub prefab_hash: i32,
pub quantity: u32,
pub max_quantity: u32,
pub damage: f64,
pub fields: HashMap<ic10emu::grammar::SlotLogicType, ic10emu::LogicField>,
}
impl From<&ic10emu::SlotOccupant> for SlotOccupant {
fn from(value: &ic10emu::SlotOccupant) -> Self {
SlotOccupant {
id: value.id,
prefab_hash: value.prefab_hash,
quantity: value.quantity,
max_quantity: value.max_quantity,
damage: value.damage,
fields: value.get_fields(),
}
}
}
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct Slot {
pub typ: ic10emu::SlotType,
pub occupant: Option<SlotOccupant>,
pub fields: HashMap<ic10emu::grammar::SlotLogicType, ic10emu::LogicField>,
}
impl From<&ic10emu::Slot> for Slot {
fn from(value: &ic10emu::Slot) -> Self {
Slot {
typ: value.typ,
occupant: value.occupant.as_ref().map(|occupant| occupant.into()),
fields: value.get_fields(),
}
}
}
include!(concat!(env!("OUT_DIR"), "/ts_types.rs"));

View File

@@ -4,7 +4,8 @@ export interface LogicField {
field_type: FieldType;
value: number;
}
export type Fields = Map<string, LogicField>;
export type LogicFields = Map<LogicType, LogicField>;
export type SlotLogicFields = Map<SlotLogicType, LogicField>;
export type SlotType =
| "AccessCard"
@@ -40,39 +41,63 @@ export type SlotType =
| "Torpedo"
| "None";
export interface SlotOccupant {
readonly id: number;
readonly prefab_hash: number;
readonly quantity: number;
readonly max_quantity: number;
readonly damage: number;
readonly fields: SlotLogicFields;
}
export interface Slot {
typ: SlotType;
fields: Fields;
readonly typ: SlotType;
readonly occupant: SlotOccupant | undefined;
readonly fields: SlotLogicFields;
}
export type Reagents = Map<string, Map<number, number>>;
export type Connection = { CableNetwork: number } | "Other";
export interface ConnectionCableNetwork {
CableNetwork: {
net: number | undefined;
typ: string;
};
}
export type Connection = ConnectionCableNetwork | "Other";
export type RegisterSpec = {
RegisterSpec: { indirection: number; target: number };
readonly RegisterSpec: {
readonly indirection: number;
readonly target: number;
};
};
export type DeviceSpec = {
DeviceSpec: {
device:
readonly DeviceSpec: {
readonly device:
| "Db"
| { Numbered: number }
| { Indirect: { indirection: number; target: number } };
| { readonly Numbered: number }
| {
readonly Indirect: {
readonly indirection: number;
readonly target: number;
};
};
};
connection: number | undefined;
readonly connection: number | undefined;
};
export type LogicType = { LogicType: string };
export type SlotLogicType = { SlotLogicType: string };
export type BatchMode = { BatchMode: string };
export type ReagentMode = { ReagentMode: string };
export type Identifier = { Identifier: { name: string } };
export type OperandLogicType = { readonly LogicType: string };
export type OperandSlotLogicType = { readonly SlotLogicType: string };
export type OperandBatchMode = { readonly BatchMode: string };
export type OperandReagentMode = { readonly ReagentMode: string };
export type Identifier = { readonly Identifier: { name: string } };
export type NumberFloat = { Float: number };
export type NumberBinary = { Binary: number };
export type NumberHexadecimal = { Hexadecimal: number };
export type NumberConstant = { Constant: number };
export type NumberString = { String: string };
export type NumberEnum = { Enum: number };
export type NumberFloat = { readonly Float: number };
export type NumberBinary = { readonly Binary: number };
export type NumberHexadecimal = { readonly Hexadecimal: number };
export type NumberConstant = { readonly Constant: number };
export type NumberString = { readonly String: string };
export type NumberEnum = { readonly Enum: number };
export type NumberOperand = {
Number:
@@ -87,10 +112,10 @@ export type Operand =
| RegisterSpec
| DeviceSpec
| NumberOperand
| LogicType
| SlotLogicType
| BatchMode
| ReagentMode
| OperandLogicType
| OperandSlotLogicType
| OperandBatchMode
| OperandReagentMode
| Identifier;
export type Alias = RegisterSpec | DeviceSpec;
@@ -102,22 +127,27 @@ export type Defines = Map<string, number>;
export type Pins = (number | undefined)[];
export interface Instruction {
instruction: string;
operands: Operand[];
readonly instruction: string;
readonly operands: Operand[];
}
export type ICError = {
ParseError: { line: number; start: number; end: number; msg: string };
readonly ParseError: {
readonly line: number;
readonly start: number;
readonly end: number;
readonly msg: string;
};
};
export interface Program {
instructions: Instruction[];
errors: ICError[];
labels: Map<string, number>;
readonly instructions: Instruction[];
readonly errors: ICError[];
readonly labels: Map<string, number>;
}
export interface DeviceRef {
readonly fields: Fields;
readonly fields: LogicFields;
readonly slots: Slot[];
readonly reagents: Reagents;
readonly connections: Connection[];
@@ -125,4 +155,29 @@ export interface DeviceRef {
readonly defines?: Defines | undefined;
readonly pins?: Pins;
readonly program?: Program;
getSlotFields(slot: number): SlotLogicFields;
}
export interface SlotOccupantTemplate {
id?: number;
fields: { [key in SlotLogicType]?: LogicField };
}
export interface SlotTemplate {
typ: SlotType;
occupant?: SlotOccupantTemplate;
}
export interface DeviceTemplate {
id?: number;
name?: string;
prefab_name?: string;
slots: SlotTemplate[];
// reagents: { [key: string]: float}
connections: Connection[];
fields: { [key in LogicType]?: LogicField };
}
export interface VM {
addDeviceFromTemplate(template: DeviceTemplate): number;
}

View File

@@ -15,7 +15,7 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
@@ -38,7 +38,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
@@ -58,7 +58,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
@@ -80,7 +80,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
@@ -178,8 +178,7 @@
" candidates.append((name, entry[\"name\"].removeprefix(\"Item\"), entry[\"name\"]))\n",
" if entry[\"name\"].removeprefix(\"Structure\") in name:\n",
" candidates.append((name, entry[\"name\"].removeprefix(\"Structure\"), entry[\"name\"]))\n",
" image_candidates[entry[\"name\"]] = filter_candidates(candidates)\n",
"\n"
" image_candidates[entry[\"name\"]] = filter_candidates(candidates)"
]
},
{
@@ -191,7 +190,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
@@ -212,30 +211,30 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"ItemBiomass []\n",
"StructureBlocker []\n",
"CartridgePlantAnalyser []\n",
"StructureElevatorLevelIndustrial []\n",
"ItemPlantEndothermic_Creative []\n",
"Flag_ODA_10m []\n",
"Flag_ODA_4m []\n",
"Flag_ODA_6m []\n",
"Flag_ODA_8m []\n",
"ItemBiomass []\n",
"ItemHorticultureBelt []\n",
"ItemKitLiquidRegulator []\n",
"ItemKitPortablesConnector []\n",
"ItemMushroom ['ItemMushroom-resources.assets-3022.png', 'ItemMushroom-resources.assets-9304.png']\n",
"ItemPlantEndothermic_Creative []\n",
"ItemPlantThermogenic_Creative []\n",
"Landingpad_GasConnectorInwardPiece []\n",
"Landingpad_LiquidConnectorInwardPiece []\n",
"ItemMushroom ['ItemMushroom-resources.assets-3022.png', 'ItemMushroom-resources.assets-9304.png']\n",
"StructurePlinth []\n",
"ItemPlantThermogenic_Creative []\n"
"StructureBlocker []\n",
"StructureElevatorLevelIndustrial []\n",
"StructurePlinth []\n"
]
}
],
@@ -254,14 +253,95 @@
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": 21,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1223 of 1223 | 100.00% \n",
"missing Egg\n",
"missing Appliance\n",
"missing Ingot\n",
"missing Torpedo\n",
"missing Magazine\n",
"missing SensorProcessingUnit\n",
"missing LiquidCanister\n",
"missing LiquidBottle\n",
"missing Wreckage\n",
"missing SoundCartridge\n",
"missing DrillHead\n",
"missing ScanningHead\n",
"missing Flare\n",
"missing Blocked\n"
]
}
],
"source": [
"slot_types = [\n",
" \"Helmet\",\n",
" \"Suit\",\n",
" \"Back\",\n",
" \"GasFilter\",\n",
" \"GasCanister\",\n",
" \"MotherBoard\",\n",
" \"Circuitboard\",\n",
" \"DataDisk\",\n",
" \"Organ\",\n",
" \"Ore\",\n",
" \"Plant\",\n",
" \"Uniform\",\n",
" \"Entity\",\n",
" \"Battery\",\n",
" \"Egg\",\n",
" \"Belt\",\n",
" \"Tool\",\n",
" \"Appliance\",\n",
" \"Ingot\",\n",
" \"Torpedo\",\n",
" \"Cartridge\",\n",
" \"AccessCard\",\n",
" \"Magazine\",\n",
" \"Circuit\",\n",
" \"Bottle\",\n",
" \"ProgrammableChip\",\n",
" \"Glasses\",\n",
" \"CreditCard\",\n",
" \"DirtCanister\",\n",
" \"SensorProcessingUnit\",\n",
" \"LiquidCanister\",\n",
" \"LiquidBottle\",\n",
" \"Wreckage\",\n",
" \"SoundCartridge\",\n",
" \"DrillHead\",\n",
" \"ScanningHead\",\n",
" \"Flare\",\n",
" \"Blocked\",\n",
"]\n",
"sloticons = []\n",
"for typ in slot_types:\n",
" try_name = f\"sloticon_{typ.lower()}\"\n",
" found = False\n",
" for name in names:\n",
" if name.startswith(try_name):\n",
" sloticons.append([f\"SlotIcon_{typ}\", name])\n",
" found = True\n",
" if not found:\n",
" print(f\"missing {typ}\")\n",
"\n",
"to_copy.extend(sloticons)"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1266 of 1266 | 100.00% \n",
"Done\n"
]
}
@@ -284,13 +364,6 @@
"print(\"Done\")\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {

View File

@@ -1 +1,128 @@
{"words":["Astroloy","Autolathe","bapal","bapz","bapzal","batchmode","batchmodes","bdns","bdnsal","bdse","bdseal","beqal","beqz","beqzal","bgeal","bgez","bgezal","bgtal","bgtz","bgtzal","bleal","blez","blezal","bltal","bltz","bltzal","bnaal","bnan","bnaz","bnazal","bneal","bnez","bnezal","brap","brapz","brdns","brdse","breq","breqz","brge","brgez","brgt","brgtz","brle","brlez","brlt","brltz","brna","brnan","brnaz","brne","brnez","Circuitboard","codegen","Depressurising","endpos","getd","Hardsuit","hardwrap","hashables","hstack","infile","jetpack","Keybind","lbns","logicable","logicslottypes","logictype","logictypes","lparen","Mineables","modelist","ninf","noconflict","offcanvas","overcolumn","Overlength","pedia","pinf","popperjs","preproc","Pressurising","putd","QUICKFIX","reagentmode","reagentmodes","rocketstation","rparen","sapz","sattellite","sdns","sdse","seqz","serde","sgez","sgtz","slez","slotlogic","slotlogicable","slotlogictype","slotlogictypes","slottype","sltz","snan","snanz","snaz","snez","splitn","Stationeers","stationpedia","themelist","tokentype","trunc","whos","regen","regen","tablist","tabpanel","labelledby"],"flagWords":[],"language":"en","version":"0.2"}
{
"words": [
"Astroloy",
"Autolathe",
"bapal",
"bapz",
"bapzal",
"batchmode",
"batchmodes",
"bdns",
"bdnsal",
"bdse",
"bdseal",
"beqal",
"beqz",
"beqzal",
"bgeal",
"bgez",
"bgezal",
"bgtal",
"bgtz",
"bgtzal",
"bleal",
"blez",
"blezal",
"bltal",
"bltz",
"bltzal",
"bnaal",
"bnan",
"bnaz",
"bnazal",
"bneal",
"bnez",
"bnezal",
"brap",
"brapz",
"brdns",
"brdse",
"breq",
"breqz",
"brge",
"brgez",
"brgt",
"brgtz",
"brle",
"brlez",
"brlt",
"brltz",
"brna",
"brnan",
"brnaz",
"brne",
"brnez",
"Circuitboard",
"codegen",
"Depressurising",
"deviceslength",
"endpos",
"getd",
"Hardsuit",
"hardwrap",
"hashables",
"hstack",
"infile",
"jetpack",
"Keybind",
"labelledby",
"lbns",
"logicable",
"logicslottypes",
"logictype",
"logictypes",
"lparen",
"Mineables",
"modelist",
"ninf",
"noconflict",
"offcanvas",
"overcolumn",
"Overlength",
"pedia",
"pinf",
"popperjs",
"preproc",
"Pressurising",
"putd",
"QUICKFIX",
"reagentmode",
"reagentmodes",
"regen",
"rocketstation",
"rparen",
"sapz",
"sattellite",
"sdns",
"sdse",
"seqz",
"serde",
"sgez",
"sgtz",
"slez",
"slotclass",
"slotlogic",
"slotlogicable",
"slotlogictype",
"slotlogictypes",
"slottype",
"sltz",
"snan",
"snanz",
"snaz",
"snez",
"sortingclass",
"splitn",
"Stationeers",
"stationpedia",
"tablist",
"tabpanel",
"themelist",
"tokentype",
"trunc",
"whos"
],
"flagWords": [],
"language": "en",
"version": "0.2"
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -30,7 +30,7 @@
"@types/wicg-file-system-access": "^2023.10.5",
"autoprefixer": "^10.4.19",
"copy-webpack-plugin": "^12.0.2",
"css-loader": "^6.10.0",
"css-loader": "^6.11.0",
"css-minimizer-webpack-plugin": "^6.0.0",
"esbuild": "^0.20.2",
"esbuild-loader": "^4.1.0",
@@ -45,15 +45,15 @@
"imagemin-optipng": "^8.0.0",
"imagemin-svgo": "^10.0.1",
"lit-scss-loader": "^2.0.1",
"mini-css-extract-plugin": "^2.8.1",
"mini-css-extract-plugin": "^2.9.0",
"postcss-loader": "^8.1.1",
"sass": "^1.72.0",
"sass-loader": "^14.1.1",
"sass": "^1.75.0",
"sass-loader": "^14.2.1",
"style-loader": "^3.3.4",
"thread-loader": "^4.0.2",
"ts-lit-plugin": "^2.0.2",
"ts-loader": "^9.5.1",
"typescript": "^5.4.3",
"typescript": "^5.4.5",
"typescript-lit-html-plugin": "^0.9.0",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4",
@@ -61,19 +61,19 @@
},
"dependencies": {
"@leeoniya/ufuzzy": "^1.0.14",
"@lit/context": "^1.1.0",
"@lit/context": "^1.1.1",
"@popperjs/core": "^2.11.8",
"@shoelace-style/shoelace": "^2.15.0",
"ace-builds": "^1.32.9",
"ace-linters": "^1.1.2",
"ace-builds": "^1.33.0",
"ace-linters": "^1.2.0",
"bootstrap": "^5.3.3",
"bson": "^6.5.0",
"bson": "^6.6.0",
"buffer": "^6.0.3",
"crypto-browserify": "^3.12.0",
"ic10emu_wasm": "file:..\\ic10emu_wasm\\pkg",
"ic10lsp_wasm": "file:..\\ic10lsp_wasm\\pkg",
"jquery": "^3.7.1",
"lit": "^3.1.2",
"lit": "^3.1.3",
"lzma-web": "^3.0.1",
"stream-browserify": "^3.0.0",
"uuid": "^9.0.1",

293
www/pnpm-lock.yaml generated
View File

@@ -9,26 +9,26 @@ dependencies:
specifier: ^1.0.14
version: 1.0.14
'@lit/context':
specifier: ^1.1.0
version: 1.1.0
specifier: ^1.1.1
version: 1.1.1
'@popperjs/core':
specifier: ^2.11.8
version: 2.11.8
'@shoelace-style/shoelace':
specifier: ^2.15.0
version: 2.15.0(@types/react@18.2.74)
version: 2.15.0(@types/react@18.2.79)
ace-builds:
specifier: ^1.32.9
version: 1.32.9
specifier: ^1.33.0
version: 1.33.0
ace-linters:
specifier: ^1.1.2
version: 1.1.2
specifier: ^1.2.0
version: 1.2.0
bootstrap:
specifier: ^5.3.3
version: 5.3.3(@popperjs/core@2.11.8)
bson:
specifier: ^6.5.0
version: 6.5.0
specifier: ^6.6.0
version: 6.6.0
buffer:
specifier: ^6.0.3
version: 6.0.3
@@ -45,8 +45,8 @@ dependencies:
specifier: ^3.7.1
version: 3.7.1
lit:
specifier: ^3.1.2
version: 3.1.2
specifier: ^3.1.3
version: 3.1.3
lzma-web:
specifier: ^3.0.1
version: 3.0.1
@@ -80,8 +80,8 @@ devDependencies:
specifier: ^12.0.2
version: 12.0.2(webpack@5.91.0)
css-loader:
specifier: ^6.10.0
version: 6.10.0(webpack@5.91.0)
specifier: ^6.11.0
version: 6.11.0(webpack@5.91.0)
css-minimizer-webpack-plugin:
specifier: ^6.0.0
version: 6.0.0(esbuild@0.20.2)(webpack@5.91.0)
@@ -96,7 +96,7 @@ devDependencies:
version: 5.1.0
fork-ts-checker-webpack-plugin:
specifier: ^9.0.2
version: 9.0.2(typescript@5.4.3)(webpack@5.91.0)
version: 9.0.2(typescript@5.4.5)(webpack@5.91.0)
hello-wasm-pack:
specifier: ^0.1.0
version: 0.1.0
@@ -125,17 +125,17 @@ devDependencies:
specifier: ^2.0.1
version: 2.0.1(webpack@5.91.0)
mini-css-extract-plugin:
specifier: ^2.8.1
version: 2.8.1(webpack@5.91.0)
specifier: ^2.9.0
version: 2.9.0(webpack@5.91.0)
postcss-loader:
specifier: ^8.1.1
version: 8.1.1(postcss@8.4.38)(typescript@5.4.3)(webpack@5.91.0)
version: 8.1.1(postcss@8.4.38)(typescript@5.4.5)(webpack@5.91.0)
sass:
specifier: ^1.72.0
version: 1.72.0
specifier: ^1.75.0
version: 1.75.0
sass-loader:
specifier: ^14.1.1
version: 14.1.1(sass@1.72.0)(webpack@5.91.0)
specifier: ^14.2.1
version: 14.2.1(sass@1.75.0)(webpack@5.91.0)
style-loader:
specifier: ^3.3.4
version: 3.3.4(webpack@5.91.0)
@@ -147,10 +147,10 @@ devDependencies:
version: 2.0.2
ts-loader:
specifier: ^9.5.1
version: 9.5.1(typescript@5.4.3)(webpack@5.91.0)
version: 9.5.1(typescript@5.4.5)(webpack@5.91.0)
typescript:
specifier: ^5.4.3
version: 5.4.3
specifier: ^5.4.5
version: 5.4.5
typescript-lit-html-plugin:
specifier: ^0.9.0
version: 0.9.0
@@ -196,8 +196,8 @@ packages:
regenerator-runtime: 0.14.1
dev: true
/@ctrl/tinycolor@4.0.3:
resolution: {integrity: sha512-e9nEVehVJwkymQpkGhdSNzLT2Lr9UTTby+JePq4Z2SxBbOQjY7pLgSouAaXvfaGQVSAaY0U4eJdwfSDmCbItcw==}
/@ctrl/tinycolor@4.1.0:
resolution: {integrity: sha512-WyOx8cJQ+FQus4Mm4uPIZA64gbk3Wxh0so5Lcii0aJifqwoVOlfFtorjLE0Hen4OYyHZMXDWqMmaQemBhgxFRQ==}
engines: {node: '>=14'}
dev: false
@@ -460,7 +460,7 @@ packages:
'@jest/schemas': 29.6.3
'@types/istanbul-lib-coverage': 2.0.6
'@types/istanbul-reports': 3.0.4
'@types/node': 20.12.2
'@types/node': 20.12.7
'@types/yargs': 17.0.32
chalk: 4.1.2
dev: true
@@ -514,18 +514,18 @@ packages:
resolution: {integrity: sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g==}
dev: false
/@lit/context@1.1.0:
resolution: {integrity: sha512-fCyv4dsH05wCNm3AKbB+PdYbXGJd/XT8OOwo4hVmD4COq5wOWJlQreGAMDvmHZ7osqxuu06Y4nmP6ooXpN7ErA==}
/@lit/context@1.1.1:
resolution: {integrity: sha512-q/Rw7oWSJidUP43f/RUPwqZ6f5VlY8HzinTWxL/gW1Hvm2S5q2hZvV+qM8WFcC+oLNNknc3JKsd5TwxLk1hbdg==}
dependencies:
'@lit/reactive-element': 2.0.4
dev: false
/@lit/react@1.0.4(@types/react@18.2.74):
/@lit/react@1.0.4(@types/react@18.2.79):
resolution: {integrity: sha512-6HBvk3AwF46z17fTkZp5F7/EdCJW9xqqQgYKr3sQGgoEJv0TKV1voWydG4UQQA2RWkoD4SHjy08snSpzyoyd0w==}
peerDependencies:
'@types/react': 17 || 18
dependencies:
'@types/react': 18.2.74
'@types/react': 18.2.79
dev: false
/@lit/reactive-element@2.0.4:
@@ -579,17 +579,17 @@ packages:
resolution: {integrity: sha512-Hf45HeO+vdQblabpyZOTxJ4ZeZsmIUYXXPmoYrrR4OJ5OKxL+bhMz5mK8JXgl7HsoEowfz7+e248UGi861de9Q==}
dev: false
/@shoelace-style/shoelace@2.15.0(@types/react@18.2.74):
/@shoelace-style/shoelace@2.15.0(@types/react@18.2.79):
resolution: {integrity: sha512-Lcg938Y8U2VsHqIYewzlt+H1rbrXC4GRSUkTJgXyF8/0YAOlI+srd5OSfIw+/LYmwLP2Peyh398Kae/6tg4PDA==}
engines: {node: '>=14.17.0'}
dependencies:
'@ctrl/tinycolor': 4.0.3
'@ctrl/tinycolor': 4.1.0
'@floating-ui/dom': 1.6.3
'@lit/react': 1.0.4(@types/react@18.2.74)
'@lit/react': 1.0.4(@types/react@18.2.79)
'@shoelace-style/animations': 1.1.0
'@shoelace-style/localize': 3.1.2
composed-offset-position: 0.0.4
lit: 3.1.2
lit: 3.1.3
qr-creator: 1.0.0
transitivePeerDependencies:
- '@types/react'
@@ -626,13 +626,13 @@ packages:
resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
dependencies:
'@types/connect': 3.4.38
'@types/node': 20.12.2
'@types/node': 20.12.7
dev: true
/@types/bonjour@3.5.13:
resolution: {integrity: sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==}
dependencies:
'@types/node': 20.12.2
'@types/node': 20.12.7
dev: true
/@types/bootstrap@5.2.10:
@@ -644,14 +644,14 @@ packages:
/@types/connect-history-api-fallback@1.5.4:
resolution: {integrity: sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==}
dependencies:
'@types/express-serve-static-core': 4.17.43
'@types/node': 20.12.2
'@types/express-serve-static-core': 4.19.0
'@types/node': 20.12.7
dev: true
/@types/connect@3.4.38:
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
dependencies:
'@types/node': 20.12.2
'@types/node': 20.12.7
dev: true
/@types/emscripten@1.39.10:
@@ -661,12 +661,12 @@ packages:
/@types/eslint-scope@3.7.7:
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
dependencies:
'@types/eslint': 8.56.6
'@types/eslint': 8.56.9
'@types/estree': 1.0.5
dev: true
/@types/eslint@8.56.6:
resolution: {integrity: sha512-ymwc+qb1XkjT/gfoQwxIeHZ6ixH23A+tCT2ADSA/DPVKzAjwYkTXBMCQ/f6fe4wEa85Lhp26VPeUxI7wMhAi7A==}
/@types/eslint@8.56.9:
resolution: {integrity: sha512-W4W3KcqzjJ0sHg2vAq9vfml6OhsJ53TcUjUqfzzZf/EChUtwspszj/S0pzMxnfRcO55/iGq47dscXw71Fxc4Zg==}
dependencies:
'@types/estree': 1.0.5
'@types/json-schema': 7.0.15
@@ -676,11 +676,11 @@ packages:
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
dev: true
/@types/express-serve-static-core@4.17.43:
resolution: {integrity: sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==}
/@types/express-serve-static-core@4.19.0:
resolution: {integrity: sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==}
dependencies:
'@types/node': 20.12.2
'@types/qs': 6.9.14
'@types/node': 20.12.7
'@types/qs': 6.9.15
'@types/range-parser': 1.2.7
'@types/send': 0.17.4
dev: true
@@ -689,9 +689,9 @@ packages:
resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
dependencies:
'@types/body-parser': 1.19.5
'@types/express-serve-static-core': 4.17.43
'@types/qs': 6.9.14
'@types/serve-static': 1.15.5
'@types/express-serve-static-core': 4.19.0
'@types/qs': 6.9.15
'@types/serve-static': 1.15.7
dev: true
/@types/html-minifier-terser@6.1.0:
@@ -705,7 +705,7 @@ packages:
/@types/http-proxy@1.17.14:
resolution: {integrity: sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==}
dependencies:
'@types/node': 20.12.2
'@types/node': 20.12.7
dev: true
/@types/istanbul-lib-coverage@2.0.6:
@@ -731,28 +731,21 @@ packages:
/@types/keyv@3.1.4:
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
dependencies:
'@types/node': 20.12.2
'@types/node': 20.12.7
dev: true
/@types/mime@1.3.5:
resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
dev: true
/@types/mime@4.0.0:
resolution: {integrity: sha512-5eEkJZ/BLvTE3vXGKkWlyTSUVZuzj23Wj8PoyOq2lt5I3CYbiLBOPb3XmCW6QcuOibIUE6emHXHt9E/F/rCa6w==}
deprecated: This is a stub types definition. mime provides its own type definitions, so you do not need this installed.
dependencies:
mime: 4.0.1
dev: true
/@types/node-forge@1.3.11:
resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==}
dependencies:
'@types/node': 20.12.2
'@types/node': 20.12.7
dev: true
/@types/node@20.12.2:
resolution: {integrity: sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==}
/@types/node@20.12.7:
resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==}
dependencies:
undici-types: 5.26.5
dev: true
@@ -761,16 +754,16 @@ packages:
resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
dev: false
/@types/qs@6.9.14:
resolution: {integrity: sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==}
/@types/qs@6.9.15:
resolution: {integrity: sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==}
dev: true
/@types/range-parser@1.2.7:
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
dev: true
/@types/react@18.2.74:
resolution: {integrity: sha512-9AEqNZZyBx8OdZpxzQlaFEVCSFUM2YXJH46yPOiOpm078k6ZLOCcuAzGum/zK8YBwY+dbahVNbHrbgrAwIRlqw==}
/@types/react@18.2.79:
resolution: {integrity: sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==}
dependencies:
'@types/prop-types': 15.7.12
csstype: 3.1.3
@@ -779,7 +772,7 @@ packages:
/@types/responselike@1.0.3:
resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==}
dependencies:
'@types/node': 20.12.2
'@types/node': 20.12.7
dev: true
/@types/retry@0.12.2:
@@ -790,7 +783,7 @@ packages:
resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==}
dependencies:
'@types/mime': 1.3.5
'@types/node': 20.12.2
'@types/node': 20.12.7
dev: true
/@types/serve-index@1.9.4:
@@ -799,18 +792,18 @@ packages:
'@types/express': 4.17.21
dev: true
/@types/serve-static@1.15.5:
resolution: {integrity: sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==}
/@types/serve-static@1.15.7:
resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==}
dependencies:
'@types/http-errors': 2.0.4
'@types/mime': 4.0.0
'@types/node': 20.12.2
'@types/node': 20.12.7
'@types/send': 0.17.4
dev: true
/@types/sockjs@0.3.36:
resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==}
dependencies:
'@types/node': 20.12.2
'@types/node': 20.12.7
dev: true
/@types/trusted-types@2.0.7:
@@ -824,7 +817,7 @@ packages:
/@types/ws@8.5.10:
resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==}
dependencies:
'@types/node': 20.12.2
'@types/node': 20.12.7
dev: true
/@types/yargs-parser@21.0.3:
@@ -1055,12 +1048,12 @@ packages:
negotiator: 0.6.3
dev: true
/ace-builds@1.32.9:
resolution: {integrity: sha512-dqBLPj//Gq0b92YUtRIsdWsORf4J+4xW3r8/4Wr2Vqid7O1j7YBV/ZsVvWBjZFy+EnvMCRFCFOEIM1cbt4BQ/g==}
/ace-builds@1.33.0:
resolution: {integrity: sha512-PDvytkZNvAfuh+PaP5Oy3l3sBGd7xMk4NsB+4w/w1e3gjBqEOGeJwcX+wF/SB6mLtT3VfJLrhDNPT3eaCjtR3w==}
dev: false
/ace-linters@1.1.2:
resolution: {integrity: sha512-P7jXG8Q/TdXekVaFoso+ci+PcbuWu6+jpU6F5Djdpu3znIgsv88ZMr4TK1YHk+npmJiY8cY4cnYUfJn/XQqMdA==}
/ace-linters@1.2.0:
resolution: {integrity: sha512-xvayDhn3iCmB1oEloK7ZNRZHvRwDIGu+EWtlpXNL8wAwSdQjo05bTbnXEpSCy/sBlJg5tyEwsTYesNrx05DiAg==}
dependencies:
'@xml-tools/ast': 5.0.5
'@xml-tools/constraints': 1.1.1
@@ -1242,7 +1235,7 @@ packages:
postcss: ^8.1.0
dependencies:
browserslist: 4.23.0
caniuse-lite: 1.0.30001603
caniuse-lite: 1.0.30001610
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.0.0
@@ -1964,8 +1957,8 @@ packages:
resolution: {integrity: sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==}
hasBin: true
dependencies:
caniuse-lite: 1.0.30001603
electron-to-chromium: 1.4.722
caniuse-lite: 1.0.30001610
electron-to-chromium: 1.4.739
dev: true
/browserslist@4.23.0:
@@ -1973,14 +1966,14 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
caniuse-lite: 1.0.30001603
electron-to-chromium: 1.4.722
caniuse-lite: 1.0.30001610
electron-to-chromium: 1.4.739
node-releases: 2.0.14
update-browserslist-db: 1.0.13(browserslist@4.23.0)
dev: true
/bson@6.5.0:
resolution: {integrity: sha512-DXf1BTAS8vKyR90BO4x5v3rKVarmkdkzwOrnYDFdjAY694ILNDkmA3uRh1xXJEl+C1DAh8XCvAQ+Gh3kzubtpg==}
/bson@6.6.0:
resolution: {integrity: sha512-BVINv2SgcMjL4oYbBuCQTpE3/VKOSxrOA8Cj/wQP7izSzlBGVomdm+TcUd0Pzy0ytLSSDweCKQ6X3f5veM5LQA==}
engines: {node: '>=16.20.1'}
dev: false
@@ -2100,13 +2093,13 @@ packages:
resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==}
dependencies:
browserslist: 4.23.0
caniuse-lite: 1.0.30001603
caniuse-lite: 1.0.30001610
lodash.memoize: 4.1.2
lodash.uniq: 4.5.0
dev: true
/caniuse-lite@1.0.30001603:
resolution: {integrity: sha512-iL2iSS0eDILMb9n5yKQoTBim9jMZ0Yrk8g0N9K7UzYyWnfIKzXBZD5ngpM37ZcL/cv0Mli8XtVMRYMQAfFpi5Q==}
/caniuse-lite@1.0.30001610:
resolution: {integrity: sha512-QFutAY4NgaelojVMjY63o6XlZyORPaLfyMnsl3HgnWdJUcX6K0oaJymHjH8PT5Gk7sTm8rvC/c5COUQKXqmOMA==}
dev: true
/caw@2.0.1:
@@ -2368,7 +2361,7 @@ packages:
/core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
/cosmiconfig@8.3.6(typescript@5.4.3):
/cosmiconfig@8.3.6(typescript@5.4.5):
resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==}
engines: {node: '>=14'}
peerDependencies:
@@ -2381,10 +2374,10 @@ packages:
js-yaml: 4.1.0
parse-json: 5.2.0
path-type: 4.0.0
typescript: 5.4.3
typescript: 5.4.5
dev: true
/cosmiconfig@9.0.0(typescript@5.4.3):
/cosmiconfig@9.0.0(typescript@5.4.5):
resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==}
engines: {node: '>=14'}
peerDependencies:
@@ -2397,7 +2390,7 @@ packages:
import-fresh: 3.3.0
js-yaml: 4.1.0
parse-json: 5.2.0
typescript: 5.4.3
typescript: 5.4.5
dev: true
/create-ecdh@4.0.4:
@@ -2481,8 +2474,8 @@ packages:
postcss: 8.4.38
dev: true
/css-loader@6.10.0(webpack@5.91.0):
resolution: {integrity: sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==}
/css-loader@6.11.0(webpack@5.91.0):
resolution: {integrity: sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==}
engines: {node: '>= 12.13.0'}
peerDependencies:
'@rspack/core': 0.x || 1.x
@@ -2495,9 +2488,9 @@ packages:
dependencies:
icss-utils: 5.1.0(postcss@8.4.38)
postcss: 8.4.38
postcss-modules-extract-imports: 3.0.0(postcss@8.4.38)
postcss-modules-local-by-default: 4.0.4(postcss@8.4.38)
postcss-modules-scope: 3.1.1(postcss@8.4.38)
postcss-modules-extract-imports: 3.1.0(postcss@8.4.38)
postcss-modules-local-by-default: 4.0.5(postcss@8.4.38)
postcss-modules-scope: 3.2.0(postcss@8.4.38)
postcss-modules-values: 4.0.0(postcss@8.4.38)
postcss-value-parser: 4.2.0
semver: 7.6.0
@@ -2984,8 +2977,8 @@ packages:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
dev: true
/electron-to-chromium@1.4.722:
resolution: {integrity: sha512-5nLE0TWFFpZ80Crhtp4pIp8LXCztjYX41yUcV6b+bKR2PqzjskTMOOlBi1VjBHlvHwS+4gar7kNKOrsbsewEZQ==}
/electron-to-chromium@1.4.739:
resolution: {integrity: sha512-koRkawXOuN9w/ymhTNxGfB8ta4MRKVW0nzifU17G1UwTWlBg0vv7xnz4nxDnRFSBe9nXMGRgICcAzqXc0PmLeA==}
dev: true
/elliptic@6.5.5:
@@ -3046,8 +3039,8 @@ packages:
engines: {node: '>=6'}
dev: true
/envinfo@7.11.1:
resolution: {integrity: sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==}
/envinfo@7.12.0:
resolution: {integrity: sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==}
engines: {node: '>=4'}
hasBin: true
dev: true
@@ -3490,7 +3483,7 @@ packages:
signal-exit: 4.1.0
dev: true
/fork-ts-checker-webpack-plugin@9.0.2(typescript@5.4.3)(webpack@5.91.0):
/fork-ts-checker-webpack-plugin@9.0.2(typescript@5.4.5)(webpack@5.91.0):
resolution: {integrity: sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==}
engines: {node: '>=12.13.0', yarn: '>=1.0.0'}
peerDependencies:
@@ -3500,7 +3493,7 @@ packages:
'@babel/code-frame': 7.24.2
chalk: 4.1.2
chokidar: 3.6.0
cosmiconfig: 8.3.6(typescript@5.4.3)
cosmiconfig: 8.3.6(typescript@5.4.5)
deepmerge: 4.3.1
fs-extra: 10.1.0
memfs: 3.5.3
@@ -3509,7 +3502,7 @@ packages:
schema-utils: 3.3.0
semver: 7.6.0
tapable: 2.2.1
typescript: 5.4.3
typescript: 5.4.5
webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4)
dev: true
@@ -3893,7 +3886,7 @@ packages:
he: 1.2.0
param-case: 3.0.4
relateurl: 0.2.7
terser: 5.30.0
terser: 5.30.3
dev: true
/html-webpack-plugin@5.6.0(webpack@5.91.0):
@@ -4357,7 +4350,7 @@ packages:
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
'@jest/types': 29.6.3
'@types/node': 20.12.2
'@types/node': 20.12.7
chalk: 4.1.2
ci-info: 3.9.0
graceful-fs: 4.2.11
@@ -4368,7 +4361,7 @@ packages:
resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}
engines: {node: '>= 10.13.0'}
dependencies:
'@types/node': 20.12.2
'@types/node': 20.12.7
merge-stream: 2.0.0
supports-color: 8.1.1
dev: true
@@ -4377,7 +4370,7 @@ packages:
resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
'@types/node': 20.12.2
'@types/node': 20.12.7
jest-util: 29.7.0
merge-stream: 2.0.0
supports-color: 8.1.1
@@ -4534,16 +4527,16 @@ packages:
web-component-analyzer: 2.0.0
dev: true
/lit-element@4.0.4:
resolution: {integrity: sha512-98CvgulX6eCPs6TyAIQoJZBCQPo80rgXR+dVBs61cstJXqtI+USQZAbA4gFHh6L/mxBx9MrgPLHLsUgDUHAcCQ==}
/lit-element@4.0.5:
resolution: {integrity: sha512-iTWskWZEtn9SyEf4aBG6rKT8GABZMrTWop1+jopsEOgEcugcXJGKuX5bEbkq9qfzY+XB4MAgCaSPwnNpdsNQ3Q==}
dependencies:
'@lit-labs/ssr-dom-shim': 1.2.0
'@lit/reactive-element': 2.0.4
lit-html: 3.1.2
lit-html: 3.1.3
dev: false
/lit-html@3.1.2:
resolution: {integrity: sha512-3OBZSUrPnAHoKJ9AMjRL/m01YJxQMf+TMHanNtTHG68ubjnZxK0RFl102DPzsw4mWnHibfZIBJm3LWCZ/LmMvg==}
/lit-html@3.1.3:
resolution: {integrity: sha512-FwIbqDD8O/8lM4vUZ4KvQZjPPNx7V1VhT7vmRB8RBAO0AU6wuTVdoXiu2CivVjEGdugvcbPNBLtPE1y0ifplHA==}
dependencies:
'@types/trusted-types': 2.0.7
dev: false
@@ -4557,12 +4550,12 @@ packages:
webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4)
dev: true
/lit@3.1.2:
resolution: {integrity: sha512-VZx5iAyMtX7CV4K8iTLdCkMaYZ7ipjJZ0JcSdJ0zIdGxxyurjIn7yuuSxNBD7QmjvcNJwr0JS4cAdAtsy7gZ6w==}
/lit@3.1.3:
resolution: {integrity: sha512-l4slfspEsnCcHVRTvaP7YnkTZEZggNFywLEIhQaGhYDczG+tu/vlgm/KaWIEjIp+ZyV20r2JnZctMb8LeLCG7Q==}
dependencies:
'@lit/reactive-element': 2.0.4
lit-element: 4.0.4
lit-html: 3.1.2
lit-element: 4.0.5
lit-html: 3.1.3
dev: false
/load-json-file@1.1.0:
@@ -4748,8 +4741,8 @@ packages:
fs-monkey: 1.0.5
dev: true
/memfs@4.8.1:
resolution: {integrity: sha512-7q/AdPzf2WpwPlPL4v1kE2KsJsHl7EF4+hAeVzlyanr2+YnR21NVn9mDqo+7DEaKDRsQy8nvxPlKH4WqMtiO0w==}
/memfs@4.8.2:
resolution: {integrity: sha512-j4WKth315edViMBGkHW6NTF0QBjsTrcRDmYNcGsPq+ozMEyCCCIlX2d2mJ5wuh6iHvJ3FevUrr48v58YRqVdYg==}
engines: {node: '>= 4.0.0'}
dependencies:
tslib: 2.6.2
@@ -4823,12 +4816,6 @@ packages:
hasBin: true
dev: true
/mime@4.0.1:
resolution: {integrity: sha512-5lZ5tyrIfliMXzFtkYyekWbtRXObT9OWa8IwQ5uxTBDHucNNwniRqo0yInflj+iYi5CBa6qxadGzGarDfuEOxA==}
engines: {node: '>=16'}
hasBin: true
dev: true
/mimic-fn@2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
@@ -4839,8 +4826,8 @@ packages:
engines: {node: '>=4'}
dev: true
/mini-css-extract-plugin@2.8.1(webpack@5.91.0):
resolution: {integrity: sha512-/1HDlyFRxWIZPI1ZpgqlZ8jMw/1Dp/dl3P0L1jtZ+zVcHqwPhGwaJwKL00WVgfnBy6PWCde9W65or7IIETImuA==}
/mini-css-extract-plugin@2.9.0(webpack@5.91.0):
resolution: {integrity: sha512-Zs1YsZVfemekSZG+44vBsYTLQORkPMwnlv+aehcxK/NLKC+EGhDB39/YePYYqx/sTk6NnYpuqikhSn7+JIevTA==}
engines: {node: '>= 12.13.0'}
peerDependencies:
webpack: ^5.0.0
@@ -5434,7 +5421,7 @@ packages:
postcss: 8.4.38
dev: true
/postcss-loader@8.1.1(postcss@8.4.38)(typescript@5.4.3)(webpack@5.91.0):
/postcss-loader@8.1.1(postcss@8.4.38)(typescript@5.4.5)(webpack@5.91.0):
resolution: {integrity: sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==}
engines: {node: '>= 18.12.0'}
peerDependencies:
@@ -5447,7 +5434,7 @@ packages:
webpack:
optional: true
dependencies:
cosmiconfig: 9.0.0(typescript@5.4.3)
cosmiconfig: 9.0.0(typescript@5.4.5)
jiti: 1.21.0
postcss: 8.4.38
semver: 7.6.0
@@ -5524,8 +5511,8 @@ packages:
postcss-selector-parser: 6.0.16
dev: true
/postcss-modules-extract-imports@3.0.0(postcss@8.4.38):
resolution: {integrity: sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==}
/postcss-modules-extract-imports@3.1.0(postcss@8.4.38):
resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==}
engines: {node: ^10 || ^12 || >= 14}
peerDependencies:
postcss: ^8.1.0
@@ -5533,8 +5520,8 @@ packages:
postcss: 8.4.38
dev: true
/postcss-modules-local-by-default@4.0.4(postcss@8.4.38):
resolution: {integrity: sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==}
/postcss-modules-local-by-default@4.0.5(postcss@8.4.38):
resolution: {integrity: sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==}
engines: {node: ^10 || ^12 || >= 14}
peerDependencies:
postcss: ^8.1.0
@@ -5545,8 +5532,8 @@ packages:
postcss-value-parser: 4.2.0
dev: true
/postcss-modules-scope@3.1.1(postcss@8.4.38):
resolution: {integrity: sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==}
/postcss-modules-scope@3.2.0(postcss@8.4.38):
resolution: {integrity: sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==}
engines: {node: ^10 || ^12 || >= 14}
peerDependencies:
postcss: ^8.1.0
@@ -6083,8 +6070,8 @@ packages:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
dev: true
/sass-loader@14.1.1(sass@1.72.0)(webpack@5.91.0):
resolution: {integrity: sha512-QX8AasDg75monlybel38BZ49JP5Z+uSKfKwF2rO7S74BywaRmGQMUBw9dtkS+ekyM/QnP+NOrRYq8ABMZ9G8jw==}
/sass-loader@14.2.1(sass@1.75.0)(webpack@5.91.0):
resolution: {integrity: sha512-G0VcnMYU18a4N7VoNDegg2OuMjYtxnqzQWARVWCIVSZwJeiL9kg8QMsuIZOplsJgTzZLF6jGxI3AClj8I9nRdQ==}
engines: {node: '>= 18.12.0'}
peerDependencies:
'@rspack/core': 0.x || 1.x
@@ -6105,12 +6092,12 @@ packages:
optional: true
dependencies:
neo-async: 2.6.2
sass: 1.72.0
sass: 1.75.0
webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4)
dev: true
/sass@1.72.0:
resolution: {integrity: sha512-Gpczt3WA56Ly0Mn8Sl21Vj94s1axi9hDIzDFn9Ph9x3C3p4nNyvsqJoQyVXKou6cBlfFWEgRW4rT8Tb4i3XnVA==}
/sass@1.75.0:
resolution: {integrity: sha512-ShMYi3WkrDWxExyxSZPst4/okE9ts46xZmJDSawJQrnte7M1V9fScVB+uNXOVKRBt0PggHOwoZcn8mYX4trnBw==}
engines: {node: '>=14.0.0'}
hasBin: true
dependencies:
@@ -6729,12 +6716,12 @@ packages:
jest-worker: 27.5.1
schema-utils: 3.3.0
serialize-javascript: 6.0.2
terser: 5.30.0
terser: 5.30.3
webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4)
dev: true
/terser@5.30.0:
resolution: {integrity: sha512-Y/SblUl5kEyEFzhMAQdsxVHh+utAxd4IuRNJzKywY/4uzSogh3G219jqbDDxYu4MXO9CzY3tSEqmZvW6AoEDJw==}
/terser@5.30.3:
resolution: {integrity: sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==}
engines: {node: '>=10'}
hasBin: true
dependencies:
@@ -6828,7 +6815,7 @@ packages:
web-component-analyzer: 2.0.0
dev: true
/ts-loader@9.5.1(typescript@5.4.3)(webpack@5.91.0):
/ts-loader@9.5.1(typescript@5.4.5)(webpack@5.91.0):
resolution: {integrity: sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==}
engines: {node: '>=12.0.0'}
peerDependencies:
@@ -6840,7 +6827,7 @@ packages:
micromatch: 4.0.5
semver: 7.6.0
source-map: 0.7.4
typescript: 5.4.3
typescript: 5.4.5
webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4)
dev: true
@@ -6895,8 +6882,8 @@ packages:
hasBin: true
dev: true
/typescript@5.4.3:
resolution: {integrity: sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==}
/typescript@5.4.5:
resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==}
engines: {node: '>=14.17'}
hasBin: true
dev: true
@@ -7179,7 +7166,7 @@ packages:
colorette: 2.0.20
commander: 10.0.1
cross-spawn: 7.0.3
envinfo: 7.11.1
envinfo: 7.12.0
fastest-levenshtein: 1.0.16
import-local: 3.1.0
interpret: 3.1.1
@@ -7189,8 +7176,8 @@ packages:
webpack-merge: 5.10.0
dev: true
/webpack-dev-middleware@7.2.0(webpack@5.91.0):
resolution: {integrity: sha512-VLzmsjJrf+3UVf3QsT3E7xZ9F9bdhUhQFGRxyl6bmYR+W519UWnK6/teZeqAFFjWEtpVs+JqNPCVqB/s7P4tGg==}
/webpack-dev-middleware@7.2.1(webpack@5.91.0):
resolution: {integrity: sha512-hRLz+jPQXo999Nx9fXVdKlg/aehsw1ajA9skAneGmT03xwmyuhvF93p6HUKKbWhXdcERtGTzUCtIQr+2IQegrA==}
engines: {node: '>= 18.12.0'}
peerDependencies:
webpack: ^5.0.0
@@ -7199,7 +7186,7 @@ packages:
optional: true
dependencies:
colorette: 2.0.20
memfs: 4.8.1
memfs: 4.8.2
mime-types: 2.1.35
on-finished: 2.4.1
range-parser: 1.2.1
@@ -7224,7 +7211,7 @@ packages:
'@types/connect-history-api-fallback': 1.5.4
'@types/express': 4.17.21
'@types/serve-index': 1.9.4
'@types/serve-static': 1.15.5
'@types/serve-static': 1.15.7
'@types/sockjs': 0.3.36
'@types/ws': 8.5.10
ansi-html-community: 0.0.8
@@ -7250,7 +7237,7 @@ packages:
spdy: 4.0.2
webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4)
webpack-cli: 5.1.4(webpack-dev-server@5.0.4)(webpack@5.91.0)
webpack-dev-middleware: 7.2.0(webpack@5.91.0)
webpack-dev-middleware: 7.2.1(webpack@5.91.0)
ws: 8.16.0
transitivePeerDependencies:
- bufferutil

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html data-bs-theme="dark">
<html data-bs-theme="dark" class="sl-theme-dark">
<head>
<meta charset="utf-8">

View File

@@ -65,6 +65,9 @@ $accordion-button-padding-y: 0.5rem;
// Utilities
@import "bootstrap/scss/utilities/api";
// Sholace theme
@import "@shoelace-style/shoelace/dist/themes/dark.css";
//
// Custom styles

View File

@@ -28,6 +28,9 @@ export const defaultCss = [
.mt-auto {
margin-top: auto !important;
}
.me-2 {
margin-right: 2rem !important;
}
.hstack {
display: flex;
flex-direction: row;
@@ -36,6 +39,9 @@ export const defaultCss = [
display: flex;
flex-direction: column;
}
.flex-g {
flex-grow: 1;
}
`,
];

View File

@@ -1,4 +1,10 @@
import { html, css, HTMLTemplateResult, PropertyValueMap } from "lit";
import {
html,
css,
HTMLTemplateResult,
PropertyValueMap,
CSSResultGroup,
} from "lit";
import { customElement, query, state } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
import SlDetails from "@shoelace-style/shoelace/dist/components/details/details.js";
@@ -7,6 +13,21 @@ import SlDetails from "@shoelace-style/shoelace/dist/components/details/details.
export class IC10Details extends SlDetails {
@query(".details__summary-icon") accessor summaryIcon: HTMLSpanElement;
static styles = [
SlDetails.styles,
css`
.details__header {
cursor: auto;
}
.details__summary-icon {
cursor: pointer;
}
.details__content {
padding-top: 0;
}
`,
];
constructor() {
super();
}
@@ -48,34 +69,16 @@ export class IC10Details extends SlDetails {
render() {
return html`
<details
part="base"
class=${classMap({
details: true,
"details--open": this.open,
"details--disabled": this.disabled,
})}
>
<summary
part="header"
id="header"
class="details__header"
role="button"
aria-expanded=${this.open ? "true" : "false"}
aria-controls="content"
aria-disabled=${this.disabled ? "true" : "false"}
tabindex=${this.disabled ? "-1" : "0"}
>
<slot name="summary" part="summary" class="details__summary"
>${this.summary}</slot
<details part="base" class=${classMap({ details: true, "details--open" : this.open, "details--disabled" : this.disabled,
})}>
<summary part="header" id="header" class="details__header" role="button" aria-expanded=${this.open ? "true" : "false"
} aria-controls="content" aria-disabled=${this.disabled ? "true" : "false" } tabindex=${this.disabled ? "-1" : "0" }
@click=${(e: Event)=> e.preventDefault()}
>
<slot name="summary" part="summary" class="details__summary">${this.summary}</slot>
<span
part="summary-icon"
class="details__summary-icon"
@click=${this.handleSummaryIconClick}
@keydown=${this.handleSummaryIconKeyDown}
>
<span part="summary-icon" class="details__summary-icon" @click=${this.handleSummaryIconClick}
@keydown=${this.handleSummaryIconKeyDown}>
<slot name="expand-icon">
<sl-icon library="system" name="chevron-right"></sl-icon>
</slot>

View File

@@ -28,11 +28,11 @@ declare global {
import { BaseElement, defaultCss } from "../components";
import { html } from "lit";
import { Ref, createRef, ref } from "lit/directives/ref.js";
import { customElement, property, query } from "lit/decorators.js";
import { customElement, state, query } from "lit/decorators.js";
import { editorStyles } from "./styles";
import "./shortcuts_ui";
import { AceKeyboardShortcuts } from "./shortcuts_ui";
import { LanguageClientConfig, ProviderOptions } from "ace-linters/types/types/language-service";
@customElement("ace-ic10")
export class IC10Editor extends BaseElement {
@@ -45,8 +45,7 @@ export class IC10Editor extends BaseElement {
};
sessions: Map<number, Ace.EditSession>;
@property({ type: Number })
accessor active_session: number = 0;
@state() active_session: number = 1;
active_line_markers: Map<number, number | null> = new Map();
languageProvider?: LanguageProvider;
@@ -291,7 +290,7 @@ export class IC10Editor extends BaseElement {
window.App!.session.onActiveLine(((e: CustomEvent) => {
const session = window.App?.session!;
const id = e.detail;
const id: number = e.detail;
const active_line = session.getActiveLine(id);
if (typeof active_line !== "undefined") {
const marker = that.active_line_markers.get(id);
@@ -485,14 +484,14 @@ export class IC10Editor extends BaseElement {
}
createOrSetSession(session_id: number, content: any) {
if (!this.sessions.hasOwnProperty(session_id)) {
if (!this.sessions.has(session_id)) {
this.newSession(session_id);
}
this.sessions.get(session_id)?.setValue(content);
}
newSession(session_id: number) {
if (this.sessions.hasOwnProperty(session_id)) {
if (this.sessions.has(session_id)) {
return false;
}
const session = ace.createEditSession("", this.mode as any);
@@ -504,14 +503,19 @@ export class IC10Editor extends BaseElement {
}
setupLsp(lsp_worker: Worker) {
const serverData = {
const serverData: LanguageClientConfig = {
module: () => import("ace-linters/build/language-client"),
modes: "ic10",
type: "webworker",
worker: lsp_worker,
};
const options: ProviderOptions = {
functionality: {
semanticTokens: true
}
}
// Create a language provider for web worker
this.languageProvider = AceLanguageClient.for(serverData as any);
this.languageProvider = AceLanguageClient.for(serverData, options);
this.languageProvider.registerEditor(this.editor);
}
@@ -564,7 +568,7 @@ export class IC10Editor extends BaseElement {
}
destroySession(session_id: number) {
if (!this.sessions.hasOwnProperty(session_id)) {
if (!this.sessions.has(session_id)) {
return false;
}
if (!(Object.keys(this.sessions).length > 1)) {

View File

@@ -74,7 +74,7 @@ export class Session extends EventTarget {
this._programs = new Map();
this._errors = new Map();
this._save_timeout = undefined;
this._activeIC = 0;
this._activeIC = 1;
this._activeLines = new Map();
this.loadFromFragment();
@@ -117,8 +117,11 @@ export class Session extends EventTarget {
}
setActiveLine(id: number, line: number) {
this._activeLines.set(id, line);
this._fireOnActiveLine(id);
const last = this._activeLines.get(id);
if (last !== line) {
this._activeLines.set(id, line);
this._fireOnActiveLine(id);
}
}
set activeLine(line: number) {
@@ -198,7 +201,7 @@ export class Session extends EventTarget {
async loadFromFragment() {
const fragment = window.location.hash.slice(1);
if (fragment === "demo") {
this._programs = new Map([[0, demoCode]]);
this._programs = new Map([[1, demoCode]]);
this._fireOnLoad();
return;
}
@@ -210,7 +213,7 @@ export class Session extends EventTarget {
const data = getJson(txt);
if (data === null) {
// backwards compatible
this._programs = new Map([[0, txt]]);
this._programs = new Map([[1, txt]]);
this, this._fireOnLoad();
return;
}

View File

@@ -175,5 +175,42 @@ export function parseNumber(s: string): number {
case 'epsilon':
return Number.EPSILON;
}
if (/^%[01]+$/.test(s)) {
return parseInt(s.slice(1), 2)
}
if (/^\$[0-9A-Fa-f]+$/.test(s)) {
return parseInt(s.slice(1), 16)
}
if (/[a-fA-F]/.test(s)) {
const hex = parseHex(s);
if (!isNaN(hex)) {
return hex;
}
}
return parseFloat(s);
}
export function parseHex(h: string) : number {
var val = parseInt(h, 16);
if (val.toString(16) === h.toLowerCase()) {
return val;
} else {
return NaN;
}
}
export function parseIntWithHexOrBinary(s: string): number {
if (/^%[01]+$/.test(s)) {
return parseInt(s.slice(1), 2)
}
if (/^\$[0-9A-Fa-f]+$/.test(s)) {
return parseInt(s.slice(1), 16)
}
if (/[a-fA-F]/.test(s)) {
const hex = parseHex(s);
if (!isNaN(hex)) {
return hex;
}
}
return parseInt(s);
}

View File

@@ -2,7 +2,7 @@ import { property, state } from "lit/decorators.js";
import {
DeviceRef,
Fields,
LogicFields,
Reagents,
Slot,
Connection,
@@ -25,7 +25,7 @@ export declare class VMDeviceMixinInterface {
name: string | null;
nameHash: number | null;
prefabName: string | null;
fields: Fields;
fields: LogicFields;
slots: Slot[];
reagents: Reagents;
connections: Connection[];
@@ -47,13 +47,23 @@ export const VMDeviceMixin = <T extends Constructor<LitElement>>(
superClass: T,
) => {
class VMDeviceMixinClass extends superClass {
@property({ type: Number }) accessor deviceID: number;
@state() accessor device: DeviceRef;
_deviceID: number;
get deviceID() {
return this._deviceID;
}
@property({ type: Number })
set deviceID(val: number) {
this._deviceID = val;
this.updateDevice();
}
device: DeviceRef;
@state() accessor name: string | null = null;
@state() accessor nameHash: number | null = null;
@state() accessor prefabName: string | null;
@state() accessor fields: Fields;
@state() accessor fields: LogicFields;
@state() accessor slots: Slot[];
@state() accessor reagents: Reagents;
@state() accessor connections: Connection[];
@@ -69,11 +79,14 @@ export const VMDeviceMixin = <T extends Constructor<LitElement>>(
connectedCallback(): void {
const root = super.connectedCallback();
this.device = window.VM!.devices.get(this.deviceID)!;
window.VM?.addEventListener(
"vm-device-modified",
this._handleDeviceModified.bind(this),
);
window.VM?.addEventListener(
"vm-devices-update",
this._handleDevicesModified.bind(this),
);
this.updateDevice();
return root;
}
@@ -82,10 +95,19 @@ export const VMDeviceMixin = <T extends Constructor<LitElement>>(
const id = e.detail;
if (this.deviceID === id) {
this.updateDevice();
} else {
this.requestUpdate();
}
}
_handleDevicesModified(e: CustomEvent) {
const ids = e.detail;
this.requestUpdate();
}
updateDevice() {
this.device = window.VM!.devices.get(this.deviceID)!;
const name = this.device.name ?? null;
if (this.name !== name) {
this.name = name;
@@ -114,7 +136,9 @@ export const VMDeviceMixin = <T extends Constructor<LitElement>>(
if (!structuralEqual(this.connections, connections)) {
this.connections = connections;
}
this.updateIC();
if (typeof this.device.ic !== "undefined") {
this.updateIC();
}
}
updateIC() {
@@ -130,7 +154,7 @@ export const VMDeviceMixin = <T extends Constructor<LitElement>>(
if (this.icState !== state) {
this.icState = state;
}
const errors = this.device.program!.errors ?? null;
const errors = this.device.program?.errors ?? null;
if (!structuralEqual(this.errors, errors)) {
this.errors = errors;
}
@@ -159,7 +183,9 @@ export const VMDeviceMixin = <T extends Constructor<LitElement>>(
return VMDeviceMixinClass as Constructor<VMDeviceMixinInterface> & T;
};
export const VMActiveICMixin = <T extends Constructor<LitElement>>(superClass: T) => {
export const VMActiveICMixin = <T extends Constructor<LitElement>>(
superClass: T,
) => {
class VMActiveICMixinClass extends VMDeviceMixin(superClass) {
constructor() {
super();
@@ -187,6 +213,6 @@ export const VMActiveICMixin = <T extends Constructor<LitElement>>(superClass: T
}
this.updateDevice();
}
};
}
return VMActiveICMixinClass as Constructor<VMDeviceMixinInterface> & T;
}
};

View File

@@ -52,6 +52,7 @@ export class VMICControls extends VMActiveICMixin(BaseElement) {
sl-button[variant="success"] {
/* Changes the success theme color to purple using primitives */
--sl-color-success-600: var(--sl-color-purple-700);
--sl-color-success-500: var(--sl-color-purple-600);
}
sl-button[variant="primary"] {
/* Changes the success theme color to purple using primitives */

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,139 @@
export type DeviceDBEntry = {
import { LogicType, SlotLogicType } from "ic10emu_wasm";
export type SortingClass =
| "Default"
| "Kits"
| "Tools"
| "Resources"
| "Food"
| "Clothing"
| "Appliances"
| "Atmospherics"
| "Storage"
| "Ores"
| "Ices";
export type SlotClass =
| "None"
| "Helmet"
| "Suit"
| "Back"
| "GasFilter"
| "GasCanister"
| "Motherboard"
| "Circuitboard"
| "DataDisk"
| "Organ"
| "Ore"
| "Plant"
| "Uniform"
| "Entity"
| "Battery"
| "Egg"
| "Belt"
| "Tool"
| "Appliance"
| "Ingot"
| "Torpedo"
| "Cartridge"
| "AccessCard"
| "Magazine"
| "Circuit"
| "Bottle"
| "ProgrammableChip"
| "Glasses"
| "CreditCard"
| "DirtCanister"
| "SensorProcessingUnit"
| "LiquidCanister"
| "LiquidBottle"
| "Wreckage"
| "SoundCartridge"
| "DrillHead"
| "ScanningHead"
| "Flare"
| "Blocked";
export type NetworkType =
| "None"
| "Pipe"
| "Power"
| "Data"
| "Chute"
| "Elevator"
| "PipeLiquid"
| "LandingPad"
| "LaunchPad"
| "PowerAndData"
| "All";
export type ConnectionRole =
| "None"
| "Input"
| "Input2"
| "Output"
| "Output2"
| "Waste";
export type FieldType = "Read" | "Write" | "ReadWrite";
export type ReagentMode = "Contents" | "Recipe" | "Required" | "TotalContents";
export type BatchMode = "Average" | "Maximum" | "Minimum" | "Sum";
export interface DeviceDBItem {
slotclass: SlotClass;
sorting: SortingClass;
maxquantity?: number;
filtertype?: string;
consumable?: boolean;
ingredient?: boolean;
reagents?: { [key: string]: number};
}
export interface DeviceDBDevice {
states: DBStates;
reagents: boolean;
atmosphere: boolean;
pins?: number;
}
export interface DeviceDBConnection {
typ: NetworkType;
role: ConnectionRole;
name: string;
}
export interface DeviceDBEntry {
name: string;
hash: number;
title: string;
desc: string;
logic?: { [key: string]: string };
slots?: { name: string; typ: string }[];
modes?: { [key: string]: string };
conn?: { [key: string]: string[] };
slots?: { name: string; typ: SlotClass }[];
logic?: { [key in LogicType]?: FieldType };
slotlogic?: { [key in SlotLogicType]?: number[] };
modes?: { [key: number]: string };
conn?: { [key: number]: DeviceDBConnection };
item?: DeviceDBItem;
device?: DeviceDBDevice;
};
export type DeviceDB = {
export interface DBStates {
activate: boolean;
color: boolean;
lock: boolean;
mode: boolean;
onoff: boolean;
open: boolean;
}
export interface DeviceDB {
logic_enabled: string[];
slot_logic_enabled: string[];
devices: string[];
items: string[];
strutures: string[];
structures: string[];
db: {
[key: string]: DeviceDBEntry;
};
names_by_hash: { [key: number]: string };
reagent_hashes: { [key: string]: number}
};

View File

@@ -1,5 +1,5 @@
import { DeviceRef, VM, init } from "ic10emu_wasm";
import { DeviceDB } from "./device_db"
import { DeviceRef, DeviceTemplate, VM, init } from "ic10emu_wasm";
import { DeviceDB } from "./device_db";
import "./base_device";
declare global {
@@ -8,6 +8,13 @@ declare global {
}
}
export interface ToastMessage {
variant: "warning" | "danger" | "success" | "primary" | "neutral";
icon: string;
title: string;
msg: string;
id: string;
}
class VirtualMachine extends EventTarget {
ic10vm: VM;
@@ -15,7 +22,7 @@ class VirtualMachine extends EventTarget {
_ics: Map<number, DeviceRef>;
accessor db: DeviceDB;
dbPromise: Promise<{ default: DeviceDB }>
dbPromise: Promise<{ default: DeviceDB }>;
constructor() {
super();
@@ -28,8 +35,13 @@ class VirtualMachine extends EventTarget {
this._devices = new Map();
this._ics = new Map();
this.dbPromise = import("../../../data/database.json");
this.dbPromise.then((module) => this.setupDeviceDatabase(module.default))
this.dbPromise = import("../../../data/database.json", {
assert: { type: "json" },
}) as Promise<{ default: DeviceDB }>;
this.dbPromise.then((module) =>
this.setupDeviceDatabase(module.default as DeviceDB),
);
this.updateDevices();
this.updateCode();
@@ -40,7 +52,9 @@ class VirtualMachine extends EventTarget {
}
get deviceIds() {
return Array.from(this.ic10vm.devices);
const ids = Array.from(this.ic10vm.devices);
ids.sort();
return ids;
}
get ics() {
@@ -79,29 +93,34 @@ class VirtualMachine extends EventTarget {
}
for (const id of this._devices.keys()) {
if (!device_ids.includes(id)) {
this._devices.get(id)!.free();
this._devices.delete(id);
update_flag = true;
}
}
const ics = this.ic10vm.ics;
for (const id of ics) {
if (!this._ics.has(id)) {
this._ics.set(id, this._devices.get(id)!);
update_flag = true;
for (const [id, device] of this._devices) {
if (typeof device.ic !== "undefined") {
if (!this._ics.has(id)) {
this._ics.set(id, device);
update_flag = true;
}
}
}
for (const id of this._ics.keys()) {
if (!ics.includes(id)) {
this._ics.get(id)!.free();
if (!this._devices.has(id)) {
this._ics.delete(id);
update_flag = true;
}
}
if (update_flag) {
const ids = Array.from(device_ids);
ids.sort();
this.dispatchEvent(
new CustomEvent("vm-devices-update", { detail: device_ids }),
new CustomEvent("vm-devices-update", {
detail: ids,
}),
);
}
}
@@ -113,18 +132,19 @@ class VirtualMachine extends EventTarget {
const ic = this._ics.get(id);
const prog = progs.get(id);
if (ic && prog) {
console.time(`CompileProgram_${id}_${attempt}`);
try {
console.time(`CompileProgram_${id}_${attempt}`);
this.ics.get(id)!.setCodeInvalid(progs.get(id)!);
const compiled = this.ics.get(id)?.program!;
window.App?.session.setProgramErrors(id, compiled.errors);
this.dispatchEvent(
new CustomEvent("vm-device-modified", { detail: id }),
);
} catch (e) {
console.log(e);
} catch (err) {
this.handleVmError(err);
} finally{
console.timeEnd(`CompileProgram_${id}_${attempt}`);
}
console.timeEnd(`CompileProgram_${id}_${attempt}`);
}
}
this.update();
@@ -135,8 +155,8 @@ class VirtualMachine extends EventTarget {
if (ic) {
try {
ic.step(false);
} catch (e) {
console.log(e);
} catch (err) {
this.handleVmError(err);
}
this.update();
this.dispatchEvent(
@@ -150,8 +170,8 @@ class VirtualMachine extends EventTarget {
if (ic) {
try {
ic.run(false);
} catch (e) {
console.log(e);
} catch (err) {
this.handleVmError(err);
}
this.update();
this.dispatchEvent(
@@ -177,71 +197,133 @@ class VirtualMachine extends EventTarget {
);
}
}, this);
const ic = this.activeIC!;
window.App!.session.setActiveLine(window.App!.session.activeIC, ic.ip!);
this.updateDevice(this.activeIC);
}
setRegister(index: number, val: number) {
const ic = this.activeIC!;
try {
ic.setRegister(index, val);
this.dispatchEvent(
new CustomEvent("vm-device-modified", { detail: ic.id }),
);
} catch (e) {
console.log(e);
updateDevice(device: DeviceRef) {
this.dispatchEvent(
new CustomEvent("vm-device-modified", { detail: device.id }),
);
if (typeof device.ic !== "undefined") {
window.App!.session.setActiveLine(device.id, device.ip!);
}
}
setStack(addr: number, val: number) {
handleVmError(err: Error) {
console.log("Error in Virtual Machine", err);
const message: ToastMessage = {
variant: "danger",
icon: "bug",
title: `Error in Virtual Machine ${err.name}`,
msg: err.message,
id: Date.now().toString(16),
};
this.dispatchEvent(new CustomEvent("vm-message", { detail: message }));
}
changeDeviceId(old_id: number, new_id: number): boolean {
try {
this.ic10vm.changeDeviceId(old_id, new_id);
this.updateDevices();
if (window.App.session.activeIC === old_id) {
window.App.session.activeIC = new_id;
}
return true;
} catch (err) {
this.handleVmError(err);
return false;
}
}
setRegister(index: number, val: number): boolean {
const ic = this.activeIC!;
try {
ic.setRegister(index, val);
this.updateDevice(ic);
return true;
} catch (err) {
this.handleVmError(err);
return false;
}
}
setStack(addr: number, val: number): boolean {
const ic = this.activeIC!;
try {
ic!.setStack(addr, val);
this.dispatchEvent(
new CustomEvent("vm-device-modified", { detail: ic.id }),
);
} catch (e) {
console.log(e);
this.updateDevice(ic);
return true;
} catch (err) {
this.handleVmError(err);
return false;
}
}
setDeviceName(id: number, name: string): boolean {
const device = this._devices.get(id);
if (device) {
device.setName(name);
this.dispatchEvent(new CustomEvent("vm-device-modified", { detail: id }));
return true;
}
return false;
}
setDeviceField(id: number, field: string, val: number) {
const device = this._devices.get(id);
if (device) {
try {
device.setField(field, val);
this.dispatchEvent(
new CustomEvent("vm-device-modified", { detail: id }),
);
device.setName(name);
this.dispatchEvent(new CustomEvent("vm-device-modified", { detail: id }));
return true;
} catch (e) {
console.log(e);
} catch(e) {
this.handleVmError(e);
}
}
return false;
}
setDeviceSlotField(id: number, slot: number, field: string, val: number) {
setDeviceField(id: number, field: string, val: number): boolean {
const device = this._devices.get(id);
if (device) {
try {
device.setField(field, val);
this.updateDevice(device);
return true;
} catch (err) {
this.handleVmError(err);
}
}
return false;
}
setDeviceSlotField(id: number, slot: number, field: string, val: number): boolean {
const device = this._devices.get(id);
if (device) {
try {
device.setSlotField(slot, field, val);
this.dispatchEvent(
new CustomEvent("vm-device-modified", { detail: id }),
);
this.updateDevice(device);
return true;
} catch (e) {
console.log(e);
} catch (err) {
this.handleVmError(err);
}
}
return false;
}
setDeviceConnection(id: number, conn: number, val: number | undefined): boolean {
const device = this._devices.get(id);
if (typeof device !== "undefined") {
try {
this.ic10vm.setDeviceConnection(id, conn, val);
this.updateDevice(device);
return true
} catch (err) {
this.handleVmError(err);
}
}
return false
}
setDevicePin(id: number, pin: number, val: number | undefined): boolean {
const device = this._devices.get(id);
if (typeof device !== "undefined") {
try {
this.ic10vm.setPin(id, pin, val);
this.updateDevice(device);
return true;
} catch (err) {
this.handleVmError(err);
}
}
return false;
@@ -254,6 +336,35 @@ class VirtualMachine extends EventTarget {
new CustomEvent("vm-device-db-loaded", { detail: this.db }),
);
}
addDeviceFromTemplate(template: DeviceTemplate): boolean {
try {
console.log("adding device", template);
const id = this.ic10vm.addDeviceFromTemplate(template);
this._devices.set(id, this.ic10vm.getDevice(id)!);
const device_ids = this.ic10vm.devices;
this.dispatchEvent(
new CustomEvent("vm-devices-update", {
detail: Array.from(device_ids),
}),
);
return true;
} catch (err) {
this.handleVmError(err);
return false;
}
}
removeDevice(id: number): boolean {
try {
this.ic10vm.removeDevice(id);
this.updateDevices();
return true;
} catch (err) {
this.handleVmError(err);
return false;
}
}
}
export { VirtualMachine };

View File

@@ -1,15 +1,17 @@
import { HTMLTemplateResult, html, css } from "lit";
import { customElement, property, query } from "lit/decorators.js";
import { customElement, property, query, state } from "lit/decorators.js";
import { BaseElement, defaultCss } from "../components";
import "@shoelace-style/shoelace/dist/components/details/details.js";
import "@shoelace-style/shoelace/dist/components/tab/tab.js";
import "@shoelace-style/shoelace/dist/components/tab-panel/tab-panel.js";
import "@shoelace-style/shoelace/dist/components/tab-group/tab-group.js";
import "@shoelace-style/shoelace/dist/components/alert/alert.js";
import "./controls";
import "./registers";
import "./stack";
import "./device";
import { ToastMessage } from ".";
@customElement("vm-ui")
export class VMUI extends BaseElement {
@@ -32,11 +34,29 @@ export class VMUI extends BaseElement {
margin-left: 1rem;
margin-right: 1rem;
margin-top: 0.5rem;
flex: 0 0 auto;
}
.side-container {
height: 100%
height: calc(100vh - 3.8rem);
display: flex;
flex-direction: column;
}
vm-device-list {
display: flex;
flex-direction: column;
flex: 1 1 auto;
overflow-y: auto;
}
.tab-panel {
height: calc(100vh - 19rem);
overflow-y: auto;
}
.tab-group {
flex: 1 1 auto;
}
sl-tab::part(base) {
padding: var(--sl-spacing-small) var(--sl-spacing-medium);
}
`,
];
@@ -44,14 +64,36 @@ export class VMUI extends BaseElement {
super();
}
connectedCallback(): void {
super.connectedCallback();
window.VM.addEventListener("vm-message", this._handleVMMessage.bind(this));
}
_handleVMMessage(e: CustomEvent) {
const msg: ToastMessage = e.detail;
const alert = Object.assign(document.createElement("sl-alert"), {
variant: msg.variant,
closable: true,
// duration: 5000,
innerHTML: `
<sl-icon slot="icon" name="${msg.icon}"></sl-icon>
<strong>${msg.title}</strong><br />
${msg.msg}
`,
});
document.body.append(alert);
alert.toast();
}
protected render() {
return html`
<div class="side-container">
<vm-ic-controls></vm-ic-controls>
<sl-tab-group>
<sl-tab-group class="tab-group">
<sl-tab slot="nav" panel="active-ic">Active IC</sl-tab>
<sl-tab slot="nav" panel="devices">Devices</sl-tab>
<sl-tab-panel name="active-ic">
<sl-tab-panel name="active-ic" class="tab-panel">
<sl-details summary="Registers" open>
<vm-ic-registers></vm-ic-registers>
</sl-details>
@@ -59,7 +101,7 @@ export class VMUI extends BaseElement {
<vm-ic-stack></vm-ic-stack>
</sl-details>
</sl-tab-panel>
<sl-tab-panel name="devices">
<sl-tab-panel name="devices" class="tab-panel">
<vm-device-list></vm-device-list>
</sl-tab-panel>
</sl-tab-group>

View File

@@ -0,0 +1,16 @@
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 {
CableNetwork: {
net: window.VM?.ic10vm.defaultNetwork,
typ: conn.typ
}
};
} else {
return "Other";
}
}

View File

@@ -3,8 +3,7 @@ import re
from collections import defaultdict
from pathlib import Path
from pprint import pprint
from typing import Any # type: ignore[Any]
from typing import TypedDict
from typing import Any, NotRequired, TypedDict # type: ignore[Any]
class SlotInsert(TypedDict):
@@ -18,6 +17,29 @@ class LInsert(TypedDict):
LogicAccessTypes: str
class PediaPageItem(TypedDict):
SlotClass: str
SortingClass: str
MaxQuantity: NotRequired[float]
FilterType: NotRequired[str]
Consumable: NotRequired[bool]
Ingredient: NotRequired[bool]
Reagents: NotRequired[dict[str, float]]
class PediaPageDevice(TypedDict):
ConnectionList: list[list[str]]
HasReagents: bool
HasAtmosphere: bool
HasLockState: bool
HasOpenState: bool
HasOnOffState: bool
HasActivateState: bool
HasModeState: bool
HasColorState: bool
DevicesLength: NotRequired[int]
class PediaPage(TypedDict):
Key: str
Title: str
@@ -29,42 +51,78 @@ class PediaPage(TypedDict):
LogicSlotInsert: list[LInsert]
ModeInsert: list[LInsert]
ConnectionInsert: list[LInsert]
ConnectionList: list[list[str]]
Device: NotRequired[PediaPageDevice]
Item: NotRequired[PediaPageItem]
class Pedia(TypedDict):
pages: list[PediaPage]
reagents: dict[str, int]
class DBSlot(TypedDict):
name: str
typ: str
class DBPageStates(TypedDict):
lock: NotRequired[bool]
open: NotRequired[bool]
mode: NotRequired[bool]
onoff: NotRequired[bool]
color: NotRequired[bool]
activate: NotRequired[bool]
class DBPageConnection(TypedDict):
typ: str
role: str
name: str
class DBPageDevice(TypedDict):
states: DBPageStates
reagents: bool
atmosphere: bool
pins: NotRequired[int]
class DBPageItem(TypedDict):
slotclass: str | None
sorting: str | None
filtertype: NotRequired[str]
maxquantity: NotRequired[int]
consumable: NotRequired[bool]
ingredient: NotRequired[bool]
reagents: NotRequired[dict[str, float]]
class DBPage(TypedDict):
name: str
hash: int
title: str
desc: str
slots: list[DBSlot] | None
logic: dict[str, str] | None
slotlogic: dict[str, list[int]] | None
modes: dict[int, str] | None
conn: dict[int, list[str]] | None
conn: dict[int, DBPageConnection] | None
item: NotRequired[DBPageItem]
device: NotRequired[DBPageDevice]
def extract_all() -> None:
db: dict[str, DBPage] = {}
pedia: Pedia = {"pages": []}
pedia: Pedia = {"pages": [], "reagents": {}}
linkPat = re.compile(r"<link=\w+><color=[\w#]+>(.+?)</color></link>")
with (Path("data") / "Stationpedia.json").open("r") as f:
pedia = json.load(f)
for page in pedia["pages"]:
item: DBPage = defaultdict(list) # type: ignore[reportAssignmenType]
item: DBPage = defaultdict(list) # type: ignore[reportAssignmentType]
match page:
case {
"Key": _,
"Title": _,
"Title": title,
"Description": desc,
"PrefabName": name,
"PrefabHash": name_hash,
@@ -72,17 +130,25 @@ def extract_all() -> None:
"LogicInsert": logic,
"LogicSlotInsert": slotlogic,
"ModeInsert": modes,
"ConnectionInsert": _,
"ConnectionList": connections,
"ConnectionInsert": conninsert,
}:
connNames = {
int(insert["LogicAccessTypes"]): insert["LogicName"]
for insert in conninsert
}
device = page.get("Device", None)
item_props = page.get("Item", None)
item["name"] = name
item["hash"] = name_hash
item["title"] = title
item["desc"] = re.sub(linkPat, r"\1", desc)
match slots:
case []:
item["slots"] = None
case _:
item["slots"] = [{}] * len(slots) # type: ignore[reportAssignmenType]
item["slots"] = [{}] * len(slots) # type: ignore[reportAssignmentType]
for slot in slots:
item["slots"][int(slot["SlotIndex"])] = {
"name": slot["SlotName"],
@@ -119,13 +185,112 @@ def extract_all() -> None:
"LogicName"
]
match connections:
case []:
item["conn"] = None
match device:
case None:
pass
case {
"ConnectionList": connections,
"HasReagents": hasReagents,
"HasAtmosphere": hasAtmosphere,
"HasLockState": hasLockState,
"HasOpenState": hasOpenState,
"HasModeState": hasModeState,
"HasOnOffState": hasOnOffState,
"HasActivateState": hasActivateState,
"HasColorState": hasColorState,
}:
match connections:
case []:
item["conn"] = None
case _:
item["conn"] = {}
for index, [conn_typ, conn_role] in enumerate(
connections
):
item["conn"][index] = {
"typ": conn_typ,
"role": conn_role,
"name": connNames.get(index, "Connection"),
}
states: DBPageStates = {}
states["lock"] = hasLockState
states["open"] = hasOpenState
states["mode"] = hasModeState
states["activate"] = hasActivateState
states["onoff"] = hasOnOffState
states["color"] = hasColorState
deviceslength = device.get("DevicesLength", None)
dbdevice: DBPageDevice = {
"states": states,
"reagents": hasReagents,
"atmosphere": hasAtmosphere,
}
match deviceslength:
case None:
pass
case _:
dbdevice["pins"] = deviceslength
item["device"] = dbdevice
case _:
item["conn"] = {}
for index, [conn_typ, conn_role] in enumerate(connections):
item["conn"][index] = [conn_typ, conn_role]
print(f"NON-CONFORMING: ")
pprint(device)
return
match item_props:
case None:
pass
case {"SlotClass": slotclass, "SortingClass": sortingclass}:
maxquantity = item_props.get("MaxQuantity", None)
filtertype = item_props.get("FilterType", None)
dbitem: DBPageItem = {
"sorting": sortingclass,
"slotclass": slotclass,
}
match maxquantity:
case None:
pass
case _:
dbitem["maxquantity"] = int(maxquantity)
match filtertype:
case None:
pass
case _:
dbitem["filtertype"] = filtertype
consumable = item_props.get("Consumable", None)
match consumable:
case None:
pass
case _:
dbitem["consumable"] = consumable
ingredient = item_props.get("Ingredient", None)
match ingredient:
case None:
pass
case _:
dbitem["ingredient"] = ingredient
reagents = item_props.get("Reagents", None)
match reagents:
case None:
pass
case _:
dbitem["reagents"] = reagents
item["item"] = dbitem
case _:
print(f"NON-CONFORMING: ")
pprint(item_props)
return
case _:
print(f"NON-CONFORMING: ")
@@ -139,17 +304,13 @@ def extract_all() -> None:
item["name"] for item in db.values() if item["slotlogic"] is not None
]
devices = [
item["name"]
for item in db.values()
if item["logic"] is not None and item["conn"] is not None
]
devices = [item["name"] for item in db.values() if "device" in item]
strutures = [
structures = [
item["name"] for item in db.values() if item["name"].startswith("Structure")
]
items = [item["name"] for item in db.values() if item["name"] not in strutures]
items = [item["name"] for item in db.values() if "item" in item]
def clean_nones(value: Any) -> Any: # type: ignore[Any]
if isinstance(value, list):
@@ -168,14 +329,21 @@ def extract_all() -> None:
"logic_enabled": logicable,
"slot_logic_enabled": slotlogicable,
"devices": devices,
"strutures": strutures,
"structures": structures,
"items": items,
"db": db,
"names_by_hash": {
page["hash"]: page["name"] for page in db.values()
},
"reagent_hashes": pedia["reagents"]
}
),
f,
indent=1,
sort_keys=True,
)
if __name__ == "__main__":
# extract_logicable()
extract_all()

View File

@@ -3,13 +3,15 @@
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"module": "es2022",
"module": "esnext",
"target": "es2021",
"allowJs": true,
"moduleResolution": "bundler",
"resolveJsonModule": true,
"esModuleInterop": true,
"isolatedModules": true,
"experimentalDecorators": true,
"useDefineForClassFields": false,
"types": ["@types/wicg-file-system-access", "@types/ace"],
"plugins": [
{

View File

@@ -26,7 +26,7 @@ module.exports = {
patterns: [
"img/*.png",
"img/*/*.png",
{ from: "data/database.json", to: "data" },
// { from: "data/database.json", to: "data" },
// Copy Shoelace assets to dist/shoelace
{
from: path.resolve(

View File

@@ -23,7 +23,7 @@ module.exports = {
patterns: [
"img/*.png",
"img/*/*.png",
{ from: "data/database.json", to: "data" },
// { from: "data/database.json", to: "data" },
// Copy Shoelace assets to dist/shoelace
{
from: path.resolve(