5
.vscode/settings.json
vendored
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"rust-analyzer.check.allTargets": false,
|
||||
"rust-analyzer.cargo.target": "wasm32-unknown-unknown"
|
||||
"rust-analyzer.cargo.target": "wasm32-unknown-unknown",
|
||||
"rust-analyzer.cargo.features": [
|
||||
"tsify",
|
||||
]
|
||||
}
|
||||
|
||||
552
Cargo.lock
generated
@@ -1,5 +1,11 @@
|
||||
[workspace]
|
||||
members = ["ic10lsp_wasm", "ic10emu_wasm", "ic10emu", "xtask"]
|
||||
members = [
|
||||
"ic10lsp_wasm",
|
||||
"stationeers_data",
|
||||
"ic10emu",
|
||||
"ic10emu_wasm",
|
||||
"xtask",
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
|
||||
223
cspell.json
@@ -1 +1,222 @@
|
||||
{"language":"en","flagWords":[],"version":"0.2","words":["Astroloy","Autolathe","bapal","bapz","bapzal","batchmode","batchmodes","bdns","bdnsal","bdse","bdseal","beqal","beqz","beqzal","bgeal","bgez","bgezal","bgtal","bgtz","bgtzal","bindgen","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","conv","cstyle","endpos","getd","Hardsuit","hashables","inext","inextp","infile","itertools","jetpack","kbshortcutmenu","Keybind","lbns","logicable","logictype","logictypes","lzma","Mineables","mscorlib","MSEED","ninf","nomatch","oprs","overcolumn","Overlength","pedia","peekable","prec","preproc","putd","QUICKFIX","reagentmode","reagentmodes","repr","retval","rocketstation","sapz","sattellite","sdns","sdse","searchbox","searchbtn","seqz","serde","settingsmenu","sgez","sgtz","slez","slotlogic","slotlogicable","slotlogictype","slotlogictypes","slottype","sltz","snan","snanz","snaz","snez","splitn","Stationeers","stationpedia","stdweb","thiserror","tokentype","trunc","Tsify","whos","Depressurising","Pressurising","logicslottypes","lparen","rparen","hstack","dylib"]}
|
||||
{
|
||||
"language": "en",
|
||||
"flagWords": [],
|
||||
"version": "0.2",
|
||||
"words": [
|
||||
"Agrizero",
|
||||
"aliasable",
|
||||
"Analyizer",
|
||||
"Analyser",
|
||||
"arn't",
|
||||
"Astroloy",
|
||||
"Asura",
|
||||
"Atmo",
|
||||
"autoignition",
|
||||
"Autolathe",
|
||||
"Autominer",
|
||||
"Autotagged",
|
||||
"bapal",
|
||||
"bapz",
|
||||
"bapzal",
|
||||
"batchmode",
|
||||
"batchmodes",
|
||||
"bdns",
|
||||
"bdnsal",
|
||||
"bdse",
|
||||
"bdseal",
|
||||
"beqal",
|
||||
"beqz",
|
||||
"beqzal",
|
||||
"bgeal",
|
||||
"bgez",
|
||||
"bgezal",
|
||||
"bgtal",
|
||||
"bgtz",
|
||||
"bgtzal",
|
||||
"bindgen",
|
||||
"bleal",
|
||||
"blez",
|
||||
"blezal",
|
||||
"bltal",
|
||||
"bltz",
|
||||
"bltzal",
|
||||
"bnaal",
|
||||
"bnan",
|
||||
"bnaz",
|
||||
"bnazal",
|
||||
"bneal",
|
||||
"bnez",
|
||||
"bnezal",
|
||||
"bools",
|
||||
"brap",
|
||||
"brapz",
|
||||
"brdns",
|
||||
"brdse",
|
||||
"breq",
|
||||
"breqz",
|
||||
"brge",
|
||||
"brgez",
|
||||
"brgt",
|
||||
"brgtz",
|
||||
"brle",
|
||||
"brlez",
|
||||
"brlt",
|
||||
"brltz",
|
||||
"brna",
|
||||
"brnan",
|
||||
"brnaz",
|
||||
"brne",
|
||||
"brnez",
|
||||
"Cannifier",
|
||||
"cannister",
|
||||
"Carrage",
|
||||
"CHAC",
|
||||
"Circuitboard",
|
||||
"Clrd",
|
||||
"codegen",
|
||||
"columnated",
|
||||
"composter",
|
||||
"conv",
|
||||
"Cryo",
|
||||
"cstyle",
|
||||
"Darga",
|
||||
"Datalink",
|
||||
"Depressurising",
|
||||
"desync",
|
||||
"dylib",
|
||||
"endpos",
|
||||
"Espaciais",
|
||||
"Exgress",
|
||||
"Faily",
|
||||
"Fenoxitone",
|
||||
"Frida",
|
||||
"fromstr",
|
||||
"getd",
|
||||
"glowstick",
|
||||
"glowy",
|
||||
"Hardsuit",
|
||||
"Harvie",
|
||||
"hashables",
|
||||
"Hastelloy",
|
||||
"headcrabs",
|
||||
"hstack",
|
||||
"Huxi",
|
||||
"Idents",
|
||||
"iface",
|
||||
"impls",
|
||||
"Inconel",
|
||||
"indexmap",
|
||||
"inext",
|
||||
"inextp",
|
||||
"infile",
|
||||
"Instructable",
|
||||
"insts",
|
||||
"intf",
|
||||
"itertools",
|
||||
"Jenk",
|
||||
"jetpack",
|
||||
"kbshortcutmenu",
|
||||
"Keybind",
|
||||
"Larre",
|
||||
"lbns",
|
||||
"logicable",
|
||||
"LogicSlotType",
|
||||
"logicslottypes",
|
||||
"LogicSlotTypes",
|
||||
"logictype",
|
||||
"logictypes",
|
||||
"lparen",
|
||||
"lzma",
|
||||
"Mineables",
|
||||
"MKII",
|
||||
"moondust",
|
||||
"Mothership",
|
||||
"mscorlib",
|
||||
"MSEED",
|
||||
"Murtons",
|
||||
"ninf",
|
||||
"Nitrice",
|
||||
"nomatch",
|
||||
"nops",
|
||||
"Norsec",
|
||||
"offworld",
|
||||
"Omni",
|
||||
"onsreen",
|
||||
"oprs",
|
||||
"overcolumn",
|
||||
"Overlength",
|
||||
"Padi",
|
||||
"parentable",
|
||||
"pedia",
|
||||
"peekable",
|
||||
"prec",
|
||||
"preproc",
|
||||
"Pressurising",
|
||||
"prettyplease",
|
||||
"PRNG",
|
||||
"putd",
|
||||
"QUICKFIX",
|
||||
"reagentmode",
|
||||
"reagentmodes",
|
||||
"reborrow",
|
||||
"Recurso",
|
||||
"repr",
|
||||
"Respawn",
|
||||
"retval",
|
||||
"Rmap",
|
||||
"rocketstation",
|
||||
"rparen",
|
||||
"sapz",
|
||||
"sattellite",
|
||||
"sdns",
|
||||
"sdse",
|
||||
"searchbox",
|
||||
"searchbtn",
|
||||
"seqz",
|
||||
"serde",
|
||||
"settingsmenu",
|
||||
"sgez",
|
||||
"sgtz",
|
||||
"Sinotai",
|
||||
"slez",
|
||||
"slotlogic",
|
||||
"slotlogicable",
|
||||
"slottype",
|
||||
"sltz",
|
||||
"snan",
|
||||
"snanz",
|
||||
"snaz",
|
||||
"snez",
|
||||
"spacepack",
|
||||
"spalling",
|
||||
"splitn",
|
||||
"stablizer",
|
||||
"Starck",
|
||||
"Stationeer",
|
||||
"Stationeers",
|
||||
"stationpedia",
|
||||
"stdweb",
|
||||
"stopo",
|
||||
"Stuppen",
|
||||
"superalloys",
|
||||
"tbody",
|
||||
"tepratures",
|
||||
"thiserror",
|
||||
"tokentype",
|
||||
"toolbelt",
|
||||
"Topo",
|
||||
"trunc",
|
||||
"Tsify",
|
||||
"undarkens",
|
||||
"uneval",
|
||||
"unparse",
|
||||
"unpowered",
|
||||
"WASD",
|
||||
"whos",
|
||||
"Wirecutters",
|
||||
"Xigo",
|
||||
"xtask",
|
||||
"Zoomer",
|
||||
"Zrilian"
|
||||
]
|
||||
}
|
||||
|
||||
12
data/instruction_help_patches.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"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 abs(a) <= max(b * abs(a), float.epsilon * 8), otherwise 0",
|
||||
"snaz": "Register = 1 if abs(a) > max(b * abs(a), float.epsilon), otherwise 0",
|
||||
"log": "Register = base e log(a) or ln(a)",
|
||||
"exp": "Register = exp(a) or e^a"
|
||||
}
|
||||
@@ -10,33 +10,53 @@ crate-type = ["lib", "cdylib"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
stationeers_data = { path = "../stationeers_data" }
|
||||
const-crc32 = "1.3.0"
|
||||
itertools = "0.12.1"
|
||||
phf = "0.11.2"
|
||||
itertools = "0.13.0"
|
||||
macro_rules_attribute = "0.2.0"
|
||||
paste = "1.0.15"
|
||||
phf = { version = "0.11.2", features = ["macros"] }
|
||||
rand = "0.8.5"
|
||||
regex = "1.10.3"
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
serde_with = "3.7.0"
|
||||
regex = "1.10.4"
|
||||
serde = "1.0.202"
|
||||
serde_derive = "1.0.202"
|
||||
serde_with = "3.8.1"
|
||||
strum = { version = "0.26.2", features = ["derive", "phf", "strum_macros"] }
|
||||
strum_macros = "0.26.2"
|
||||
thiserror = "1.0.58"
|
||||
time = { version = "0.3.34", features = [
|
||||
thiserror = "1.0.61"
|
||||
time = { version = "0.3.36", features = [
|
||||
"formatting",
|
||||
"parsing",
|
||||
"serde",
|
||||
"local-offset",
|
||||
] }
|
||||
tsify = { version = "0.4.5", optional = true, features = ["js"] }
|
||||
wasm-bindgen = { version = "0.2.92", optional = true }
|
||||
tracing = "0.1.40"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
getrandom = { version = "0.2", features = ["js"] }
|
||||
time = { version = "0.3.34", features = [
|
||||
time = { version = "0.3.36", features = [
|
||||
"formatting",
|
||||
"serde",
|
||||
"local-offset",
|
||||
"wasm-bindgen",
|
||||
] }
|
||||
|
||||
[dev-dependencies]
|
||||
color-eyre = "0.6.3"
|
||||
serde_json = "1.0.117"
|
||||
|
||||
[build-dependencies]
|
||||
convert_case = "0.6.0"
|
||||
phf_codegen = "0.11.2"
|
||||
regex = "1.10.3"
|
||||
# Self dev dependency to enable prefab_database feature for tests
|
||||
# ic10emu = { path = ".", features = ["prefab_database"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
tsify = ["dep:tsify", "dep:wasm-bindgen", "stationeers_data/tsify"]
|
||||
prefab_database = [
|
||||
"stationeers_data/prefab_database",
|
||||
] # compile with the prefab database enabled
|
||||
|
||||
reagent_database = [
|
||||
"stationeers_data/reagent_database",
|
||||
] # compile with the prefab database enabled
|
||||
|
||||
392
ic10emu/build.rs
@@ -1,392 +0,0 @@
|
||||
use convert_case::{Case, Casing};
|
||||
use std::{
|
||||
collections::BTreeSet,
|
||||
env,
|
||||
fmt::Display,
|
||||
fs::{self, File},
|
||||
io::{BufWriter, Write},
|
||||
path::Path,
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
struct EnumVariant<P>
|
||||
where
|
||||
P: Display + FromStr,
|
||||
{
|
||||
pub aliases: Vec<String>,
|
||||
pub value: Option<P>,
|
||||
pub deprecated: bool,
|
||||
}
|
||||
|
||||
fn write_repr_enum<'a, T: std::io::Write, I, P>(
|
||||
writer: &mut BufWriter<T>,
|
||||
name: &str,
|
||||
variants: I,
|
||||
use_phf: bool,
|
||||
) where
|
||||
P: Display + FromStr + 'a,
|
||||
I: IntoIterator<Item = &'a (String, EnumVariant<P>)>,
|
||||
{
|
||||
let additional_strum = if use_phf { "#[strum(use_phf)]\n" } else { "" };
|
||||
write!(
|
||||
writer,
|
||||
"#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, EnumString, AsRefStr, EnumProperty, EnumIter, Serialize, Deserialize)]\n\
|
||||
{additional_strum}\
|
||||
pub enum {name} {{\n"
|
||||
)
|
||||
.unwrap();
|
||||
for (name, variant) in variants {
|
||||
let variant_name = name.replace('.', "").to_case(Case::Pascal);
|
||||
let mut serialize = vec![name.clone()];
|
||||
serialize.extend(variant.aliases.iter().cloned());
|
||||
let serialize_str = serialize
|
||||
.into_iter()
|
||||
.map(|s| format!("serialize = \"{s}\""))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ");
|
||||
let mut props = Vec::new();
|
||||
if variant.deprecated {
|
||||
props.push("deprecated = \"true\"".to_owned());
|
||||
}
|
||||
if let Some(val) = &variant.value {
|
||||
props.push(format!("value = \"{val}\""));
|
||||
}
|
||||
let props_str = if !props.is_empty() {
|
||||
format!(", props( {} )", props.join(", "))
|
||||
} else {
|
||||
"".to_owned()
|
||||
};
|
||||
writeln!(
|
||||
writer,
|
||||
" #[strum({serialize_str}{props_str})] {variant_name},"
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
writeln!(writer, "}}").unwrap();
|
||||
}
|
||||
|
||||
fn write_logictypes() {
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
|
||||
let dest_path = Path::new(&out_dir).join("logictypes.rs");
|
||||
let output_file = File::create(dest_path).unwrap();
|
||||
let mut writer = BufWriter::new(&output_file);
|
||||
|
||||
let mut logictypes: Vec<(String, EnumVariant<u16>)> = Vec::new();
|
||||
let l_infile = Path::new("data/logictypes.txt");
|
||||
let l_contents = fs::read_to_string(l_infile).unwrap();
|
||||
|
||||
for line in l_contents.lines().filter(|l| !l.trim().is_empty()) {
|
||||
let mut it = line.splitn(3, ' ');
|
||||
let name = it.next().unwrap();
|
||||
let val_str = it.next().unwrap();
|
||||
let val: Option<u16> = val_str.parse().ok();
|
||||
let docs = it.next();
|
||||
let deprecated = docs
|
||||
.map(|docs| docs.trim().to_uppercase() == "DEPRECATED")
|
||||
.unwrap_or(false);
|
||||
|
||||
if let Some(val) = val {
|
||||
if let Some((_other_name, variant)) = logictypes
|
||||
.iter_mut()
|
||||
.find(|(_, variant)| variant.value == Some(val))
|
||||
{
|
||||
variant.aliases.push(name.to_string());
|
||||
variant.deprecated = deprecated;
|
||||
} else {
|
||||
logictypes.push((
|
||||
name.to_string(),
|
||||
EnumVariant {
|
||||
aliases: Vec::new(),
|
||||
value: Some(val),
|
||||
deprecated,
|
||||
},
|
||||
));
|
||||
}
|
||||
} else {
|
||||
logictypes.push((
|
||||
name.to_string(),
|
||||
EnumVariant {
|
||||
aliases: Vec::new(),
|
||||
value: val,
|
||||
deprecated,
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let mut slotlogictypes: Vec<(String, EnumVariant<u8>)> = Vec::new();
|
||||
let sl_infile = Path::new("data/slotlogictypes.txt");
|
||||
let sl_contents = fs::read_to_string(sl_infile).unwrap();
|
||||
|
||||
for line in sl_contents.lines().filter(|l| !l.trim().is_empty()) {
|
||||
let mut it = line.splitn(3, ' ');
|
||||
let name = it.next().unwrap();
|
||||
let val_str = it.next().unwrap();
|
||||
let val: Option<u8> = val_str.parse().ok();
|
||||
let docs = it.next();
|
||||
let deprecated = docs
|
||||
.map(|docs| docs.trim().to_uppercase() == "DEPRECATED")
|
||||
.unwrap_or(false);
|
||||
|
||||
if let Some(val) = val {
|
||||
if let Some((_other_name, variant)) = slotlogictypes
|
||||
.iter_mut()
|
||||
.find(|(_, variant)| variant.value == Some(val))
|
||||
{
|
||||
variant.aliases.push(name.to_string());
|
||||
variant.deprecated = deprecated;
|
||||
} else {
|
||||
slotlogictypes.push((
|
||||
name.to_string(),
|
||||
EnumVariant {
|
||||
aliases: Vec::new(),
|
||||
value: Some(val),
|
||||
deprecated,
|
||||
},
|
||||
));
|
||||
}
|
||||
} else {
|
||||
slotlogictypes.push((
|
||||
name.to_string(),
|
||||
EnumVariant {
|
||||
aliases: Vec::new(),
|
||||
value: val,
|
||||
deprecated,
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
write_repr_enum(&mut writer, "LogicType", &logictypes, true);
|
||||
|
||||
println!("cargo:rerun-if-changed=data/logictypes.txt");
|
||||
|
||||
write_repr_enum(&mut writer, "SlotLogicType", &slotlogictypes, true);
|
||||
|
||||
println!("cargo:rerun-if-changed=data/slotlogictypes.txt");
|
||||
}
|
||||
|
||||
fn write_enums() {
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
|
||||
let dest_path = Path::new(&out_dir).join("enums.rs");
|
||||
let output_file = File::create(dest_path).unwrap();
|
||||
let mut writer = BufWriter::new(&output_file);
|
||||
|
||||
let mut enums_map: Vec<(String, EnumVariant<u32>)> = Vec::new();
|
||||
let e_infile = Path::new("data/enums.txt");
|
||||
let e_contents = fs::read_to_string(e_infile).unwrap();
|
||||
|
||||
for line in e_contents.lines().filter(|l| !l.trim().is_empty()) {
|
||||
let mut it = line.splitn(3, ' ');
|
||||
let name = it.next().unwrap();
|
||||
let val_str = it.next().unwrap();
|
||||
let val: Option<u32> = val_str.parse().ok();
|
||||
let docs = it.next();
|
||||
let deprecated = docs
|
||||
.map(|docs| docs.trim().to_uppercase() == "DEPRECATED")
|
||||
.unwrap_or(false);
|
||||
|
||||
enums_map.push((
|
||||
name.to_string(),
|
||||
EnumVariant {
|
||||
aliases: Vec::new(),
|
||||
value: val,
|
||||
deprecated,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
write_repr_enum(&mut writer, "LogicEnums", &enums_map, true);
|
||||
|
||||
println!("cargo:rerun-if-changed=data/enums.txt");
|
||||
}
|
||||
|
||||
fn write_modes() {
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
|
||||
let dest_path = Path::new(&out_dir).join("modes.rs");
|
||||
let output_file = File::create(dest_path).unwrap();
|
||||
let mut writer = BufWriter::new(&output_file);
|
||||
|
||||
let mut batchmodes: Vec<(String, EnumVariant<u8>)> = Vec::new();
|
||||
let b_infile = Path::new("data/batchmodes.txt");
|
||||
let b_contents = fs::read_to_string(b_infile).unwrap();
|
||||
|
||||
for line in b_contents.lines().filter(|l| !l.trim().is_empty()) {
|
||||
let mut it = line.splitn(3, ' ');
|
||||
let name = it.next().unwrap();
|
||||
let val_str = it.next().unwrap();
|
||||
let val: Option<u8> = val_str.parse().ok();
|
||||
|
||||
if let Some(val) = val {
|
||||
if let Some((_other_name, variant)) = batchmodes
|
||||
.iter_mut()
|
||||
.find(|(_, variant)| variant.value == Some(val))
|
||||
{
|
||||
variant.aliases.push(name.to_string());
|
||||
} else {
|
||||
batchmodes.push((
|
||||
name.to_string(),
|
||||
EnumVariant {
|
||||
aliases: Vec::new(),
|
||||
value: Some(val),
|
||||
deprecated: false,
|
||||
},
|
||||
));
|
||||
}
|
||||
} else {
|
||||
batchmodes.push((
|
||||
name.to_string(),
|
||||
EnumVariant {
|
||||
aliases: Vec::new(),
|
||||
value: val,
|
||||
deprecated: false,
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let mut reagentmodes: Vec<(String, EnumVariant<u8>)> = Vec::new();
|
||||
let r_infile = Path::new("data/reagentmodes.txt");
|
||||
let r_contents = fs::read_to_string(r_infile).unwrap();
|
||||
|
||||
for line in r_contents.lines().filter(|l| !l.trim().is_empty()) {
|
||||
let mut it = line.splitn(3, ' ');
|
||||
let name = it.next().unwrap();
|
||||
let val_str = it.next().unwrap();
|
||||
let val: Option<u8> = val_str.parse().ok();
|
||||
|
||||
if let Some(val) = val {
|
||||
if let Some((_other_name, variant)) = reagentmodes
|
||||
.iter_mut()
|
||||
.find(|(_, variant)| variant.value == Some(val))
|
||||
{
|
||||
variant.aliases.push(name.to_string());
|
||||
} else {
|
||||
reagentmodes.push((
|
||||
name.to_string(),
|
||||
EnumVariant {
|
||||
aliases: Vec::new(),
|
||||
value: Some(val),
|
||||
deprecated: false,
|
||||
},
|
||||
));
|
||||
}
|
||||
} else {
|
||||
reagentmodes.push((
|
||||
name.to_string(),
|
||||
EnumVariant {
|
||||
aliases: Vec::new(),
|
||||
value: val,
|
||||
deprecated: false,
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
write_repr_enum(&mut writer, "BatchMode", &batchmodes, false);
|
||||
|
||||
println!("cargo:rerun-if-changed=data/batchmodes.txt");
|
||||
|
||||
write_repr_enum(&mut writer, "ReagentMode", &reagentmodes, false);
|
||||
|
||||
println!("cargo:rerun-if-changed=data/reagentmodes.txt");
|
||||
}
|
||||
|
||||
fn write_constants() {
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
|
||||
let dest_path = Path::new(&out_dir).join("constants.rs");
|
||||
let output_file = File::create(dest_path).unwrap();
|
||||
let mut writer = BufWriter::new(&output_file);
|
||||
|
||||
let mut constants_lookup_map_builder = ::phf_codegen::Map::new();
|
||||
let infile = Path::new("data/constants.txt");
|
||||
let contents = fs::read_to_string(infile).unwrap();
|
||||
|
||||
for line in contents.lines().filter(|l| !l.trim().is_empty()) {
|
||||
let mut it = line.splitn(3, ' ');
|
||||
let name = it.next().unwrap();
|
||||
let constant = it.next().unwrap();
|
||||
|
||||
constants_lookup_map_builder.entry(name, constant);
|
||||
}
|
||||
|
||||
writeln!(
|
||||
&mut writer,
|
||||
"#[allow(clippy::approx_constant)] pub(crate) const CONSTANTS_LOOKUP: phf::Map<&'static str, f64> = {};",
|
||||
constants_lookup_map_builder.build()
|
||||
)
|
||||
.unwrap();
|
||||
println!("cargo:rerun-if-changed=data/constants.txt");
|
||||
}
|
||||
|
||||
fn write_instructions_enum() {
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
|
||||
let dest_path = Path::new(&out_dir).join("instructions.rs");
|
||||
let output_file = File::create(dest_path).unwrap();
|
||||
let mut writer = BufWriter::new(&output_file);
|
||||
|
||||
let mut instructions = BTreeSet::new();
|
||||
let infile = Path::new("data/instructions.txt");
|
||||
let contents = fs::read_to_string(infile).unwrap();
|
||||
|
||||
for line in contents.lines() {
|
||||
let mut it = line.split(' ');
|
||||
let instruction = it.next().unwrap();
|
||||
instructions.insert(instruction.to_string());
|
||||
}
|
||||
|
||||
write!(
|
||||
&mut writer,
|
||||
"#[derive(Debug, Display, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]\n\
|
||||
pub enum InstructionOp {{\n\
|
||||
"
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
writeln!(&mut writer, " Nop,").unwrap();
|
||||
|
||||
for typ in &instructions {
|
||||
writeln!(&mut writer, " {},", typ.to_case(Case::Pascal)).unwrap();
|
||||
}
|
||||
writeln!(&mut writer, "}}").unwrap();
|
||||
|
||||
write!(
|
||||
&mut writer,
|
||||
"impl FromStr for InstructionOp {{\n \
|
||||
type Err = ParseError;\n \
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {{\n \
|
||||
let end = s.len();\n \
|
||||
match s {{\n"
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
for typ in &instructions {
|
||||
let name = typ.to_case(Case::Pascal);
|
||||
writeln!(&mut writer, " \"{typ}\" => Ok(Self::{name}),").unwrap();
|
||||
}
|
||||
write!(
|
||||
&mut writer,
|
||||
" _ => Err(crate::grammar::ParseError {{ line: 0, start: 0, end, msg: format!(\"Unknown instruction '{{}}'\", s) }})\n \
|
||||
}}\n \
|
||||
}}\n\
|
||||
}}"
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
println!("cargo:rerun-if-changed=data/instructions.txt");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// write_instructions();
|
||||
write_logictypes();
|
||||
write_modes();
|
||||
write_constants();
|
||||
write_enums();
|
||||
|
||||
write_instructions_enum();
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
Average 0 Average of all read values
|
||||
Maximum 3 Highest of all read values
|
||||
Minimum 2 Lowest of all read values
|
||||
Sum 1 All read values added together
|
||||
@@ -1,7 +0,0 @@
|
||||
nan f64::NAN A constant representing 'not a number'. This constants technically provides a 'quiet' NaN, a signal NaN from some instructions will result in an exception and halt execution
|
||||
pinf f64::INFINITY A constant representing a positive infinite value
|
||||
ninf f64::NEG_INFINITY A constant representing a negative infinite value
|
||||
pi 3.141592653589793f64 \nA constant representing the ratio of the circumference of a circle to its diameter, provided in double percision
|
||||
deg2rad 0.0174532923847437f64 \nDegrees to radians conversion constant
|
||||
rad2deg 57.2957801818848f64 \nRadians to degrees conversion constant
|
||||
epsilon f64::EPSILON A constant representing the smallest value representable in double precision
|
||||
@@ -1,455 +0,0 @@
|
||||
AirCon.Cold 0
|
||||
AirCon.Hot 1
|
||||
AirControl.Draught 4
|
||||
AirControl.None 0
|
||||
AirControl.Offline 1
|
||||
AirControl.Pressure 2
|
||||
Color.Black 7 Black
|
||||
Color.Blue 0 Blue
|
||||
Color.Brown 8 Brown
|
||||
Color.Gray 1 Gray
|
||||
Color.Green 2 Green
|
||||
Color.Khaki 9 Khaki
|
||||
Color.Orange 3 Orange
|
||||
Color.Pink 10 Pink
|
||||
Color.Purple 11 Purple
|
||||
Color.Red 4 Red
|
||||
Color.White 6 White
|
||||
Color.Yellow 5 Yellow
|
||||
DaylightSensorMode.Default 0
|
||||
DaylightSensorMode.Horizontal 1
|
||||
DaylightSensorMode.Vertical 2
|
||||
ElevatorMode.Downward 2
|
||||
ElevatorMode.Stationary 0
|
||||
ElevatorMode.Upward 1
|
||||
EntityState.Alive 0
|
||||
EntityState.Dead 1
|
||||
EntityState.Decay 3
|
||||
EntityState.Unconscious 2
|
||||
Equals 0
|
||||
GasType.CarbonDioxide 4
|
||||
GasType.Hydrogen 16384
|
||||
GasType.LiquidCarbonDioxide 2048
|
||||
GasType.LiquidHydrogen 32768
|
||||
GasType.LiquidNitrogen 128
|
||||
GasType.LiquidNitrousOxide 8192
|
||||
GasType.LiquidOxygen 256
|
||||
GasType.LiquidPollutant 4096
|
||||
GasType.LiquidVolatiles 512
|
||||
GasType.Nitrogen 2
|
||||
GasType.NitrousOxide 64
|
||||
GasType.Oxygen 1
|
||||
GasType.Pollutant 16
|
||||
GasType.PollutedWater 65536
|
||||
GasType.Steam 1024
|
||||
GasType.Undefined 0
|
||||
GasType.Volatiles 8
|
||||
GasType.Water 32
|
||||
Greater 1
|
||||
Less 2
|
||||
LogicSlotType.Charge 10 returns current energy charge the slot occupant is holding
|
||||
LogicSlotType.ChargeRatio 11 returns current energy charge the slot occupant is holding as a ratio between 0 and 1 of its maximum
|
||||
LogicSlotType.Class 12 returns integer representing the class of object
|
||||
LogicSlotType.Damage 4 returns the damage state of the item in the slot
|
||||
LogicSlotType.Efficiency 5 returns the growth efficiency of the plant in the slot
|
||||
LogicSlotType.FilterType 25
|
||||
LogicSlotType.Growth 7 returns the current growth state of the plant in the slot
|
||||
LogicSlotType.Health 6 returns the health of the plant in the slot
|
||||
LogicSlotType.LineNumber 19
|
||||
LogicSlotType.Lock 23
|
||||
LogicSlotType.Mature 16 returns 1 if the plant in this slot is mature, 0 when it isn't
|
||||
LogicSlotType.MaxQuantity 15 returns the max stack size of the item in the slot
|
||||
LogicSlotType.None 0 No description
|
||||
LogicSlotType.OccupantHash 2 returns the has of the current occupant, the unique identifier of the thing
|
||||
LogicSlotType.Occupied 1 returns 0 when slot is not occupied, 1 when it is
|
||||
LogicSlotType.On 22
|
||||
LogicSlotType.Open 21
|
||||
LogicSlotType.PrefabHash 17 returns the hash of the structure in the slot
|
||||
LogicSlotType.Pressure 8 returns pressure of the slot occupants internal atmosphere
|
||||
LogicSlotType.PressureAir 14 returns pressure in the air tank of the jetpack in this slot
|
||||
LogicSlotType.PressureWaste 13 returns pressure in the waste tank of the jetpack in this slot
|
||||
LogicSlotType.Quantity 3 returns the current quantity, such as stack size, of the item in the slot
|
||||
LogicSlotType.ReferenceId 26
|
||||
LogicSlotType.Seeding 18 Whether a plant is seeding (ready to harvest seeds from). Returns 1 if seeding or 0 if not.
|
||||
LogicSlotType.SortingClass 24
|
||||
LogicSlotType.Temperature 9 returns temperature of the slot occupants internal atmosphere
|
||||
LogicSlotType.Volume 20
|
||||
LogicType.Acceleration 216 Change in velocity. Rockets that are deccelerating when landing will show this as negative value.
|
||||
LogicType.Activate 9 1 if device is activated (usually means running), otherwise 0
|
||||
LogicType.AirRelease 75 The current state of the air release system, for example AirRelease = 1 for a Hardsuit sets Air Release to On
|
||||
LogicType.AlignmentError 243
|
||||
LogicType.Apex 238
|
||||
LogicType.AutoLand 226 Engages the automatic landing algorithm. The rocket will automatically throttle and turn on and off its engines to achieve a smooth landing.
|
||||
LogicType.AutoShutOff 218 Turns off all devices in the rocket upon reaching destination
|
||||
LogicType.Bpm 103 Bpm
|
||||
LogicType.BurnTimeRemaining 225 Estimated time in seconds until fuel is depleted. Calculated based on current fuel usage.
|
||||
LogicType.CelestialHash 242
|
||||
LogicType.CelestialParentHash 250
|
||||
LogicType.Channel0 165
|
||||
LogicType.Channel1 166
|
||||
LogicType.Channel2 167
|
||||
LogicType.Channel3 168
|
||||
LogicType.Channel4 169
|
||||
LogicType.Channel5 170
|
||||
LogicType.Channel6 171
|
||||
LogicType.Channel7 172
|
||||
LogicType.Charge 11 The current charge the device has
|
||||
LogicType.Chart 256
|
||||
LogicType.ChartedNavPoints 259
|
||||
LogicType.ClearMemory 62 When set to 1, clears the counter memory (e.g. ExportCount). Will set itself back to 0 when actioned
|
||||
LogicType.CollectableGoods 101
|
||||
LogicType.Color 38 \n Whether driven by concerns for clarity, safety or simple aesthetics, {LINK:Stationeers;Stationeers} have access to a small rainbow of colors for their constructions. These are the color setting for devices, represented as an integer.\n\n0: Blue\n1: Grey\n2: Green\n3: Orange\n4: Red\n5: Yellow\n6: White\n7: Black\n8: Brown\n9: Khaki\n10: Pink\n11: Purple\n\n It is an unwavering universal law that anything higher than 11 will be purple. The {LINK:ODA;ODA} is powerless to change this. Similarly, anything lower than 0 will be Blue.\n
|
||||
LogicType.Combustion 98 The assess atmosphere is on fire. Returns 1 if atmosphere is on fire, 0 if not.
|
||||
LogicType.CombustionInput 146 The assess atmosphere is on fire. Returns 1 if device's input network is on fire, 0 if not.
|
||||
LogicType.CombustionInput2 147 The assess atmosphere is on fire. Returns 1 if device's Input2 network is on fire, 0 if not.
|
||||
LogicType.CombustionLimiter 153 Retards the rate of combustion inside the machine (range: 0-100), with 0 being the slowest rate of combustion and 100 being the fastest
|
||||
LogicType.CombustionOutput 148 The assess atmosphere is on fire. Returns 1 if device's Output network is on fire, 0 if not.
|
||||
LogicType.CombustionOutput2 149 The assess atmosphere is on fire. Returns 1 if device's Output2 network is on fire, 0 if not.
|
||||
LogicType.CompletionRatio 61 How complete the current production is for this device, between 0 and 1
|
||||
LogicType.ContactTypeId 198 The type id of the contact.
|
||||
LogicType.CurrentCode 261
|
||||
LogicType.CurrentResearchPodType 93
|
||||
LogicType.Density 262
|
||||
LogicType.DestinationCode 215 Unique identifier code for a destination on the space map.
|
||||
LogicType.Discover 255
|
||||
LogicType.DistanceAu 244
|
||||
LogicType.DistanceKm 249
|
||||
LogicType.DrillCondition 240
|
||||
LogicType.DryMass 220 The Mass in kilograms of the rocket excluding fuel. The more massive the rocket the more fuel will be required to move to a new location in space.
|
||||
LogicType.Eccentricity 247
|
||||
LogicType.ElevatorLevel 40 Level the elevator is currently at
|
||||
LogicType.ElevatorSpeed 39 Current speed of the elevator
|
||||
LogicType.EntityState 239
|
||||
LogicType.EnvironmentEfficiency 104 The Environment Efficiency reported by the machine, as a float between 0 and 1
|
||||
LogicType.Error 4 1 if device is in error state, otherwise 0
|
||||
LogicType.ExhaustVelocity 235
|
||||
LogicType.ExportCount 63 How many items exported since last ClearMemory
|
||||
LogicType.ExportQuantity 31 Total quantity of items exported by the device
|
||||
LogicType.ExportSlotHash 42 DEPRECATED
|
||||
LogicType.ExportSlotOccupant 32 DEPRECATED
|
||||
LogicType.Filtration 74 The current state of the filtration system, for example Filtration = 1 for a Hardsuit sets filtration to On
|
||||
LogicType.FlightControlRule 236
|
||||
LogicType.Flush 174 Set to 1 to activate the flush function on the device
|
||||
LogicType.ForceWrite 85 Forces Logic Writer devices to rewrite value
|
||||
LogicType.ForwardX 227
|
||||
LogicType.ForwardY 228
|
||||
LogicType.ForwardZ 229
|
||||
LogicType.Fuel 99
|
||||
LogicType.Harvest 69 Performs the harvesting action for any plant based machinery
|
||||
LogicType.Horizontal 20 Horizontal setting of the device
|
||||
LogicType.HorizontalRatio 34 Radio of horizontal setting for device
|
||||
LogicType.Idle 37 Returns 1 if the device is currently idle, otherwise 0
|
||||
LogicType.ImportCount 64 How many items imported since last ClearMemory
|
||||
LogicType.ImportQuantity 29 Total quantity of items imported by the device
|
||||
LogicType.ImportSlotHash 43 DEPRECATED
|
||||
LogicType.ImportSlotOccupant 30 DEPRECATED
|
||||
LogicType.Inclination 246
|
||||
LogicType.Index 241
|
||||
LogicType.InterrogationProgress 157 Progress of this sattellite dish's interrogation of its current target, as a ratio from 0-1
|
||||
LogicType.LineNumber 173 The line number of current execution for an integrated circuit running on this device. While this number can be written, use with caution
|
||||
LogicType.Lock 10 1 if device is locked, otherwise 0, can be set in most devices and prevents the user from access the values
|
||||
LogicType.ManualResearchRequiredPod 94
|
||||
LogicType.Mass 219 The total Mass of the rocket in kilograms including fuel and cargo. The more massive the rocket the more fuel will be required to move to a new location in space.
|
||||
LogicType.Maximum 23 Maximum setting of the device
|
||||
LogicType.MineablesInQueue 96
|
||||
LogicType.MineablesInVicinity 95
|
||||
LogicType.MinedQuantity 266
|
||||
LogicType.MinimumWattsToContact 163
|
||||
LogicType.Mode 3 Integer for mode state, different devices will have different mode states available to them
|
||||
LogicType.NavPoints 258
|
||||
LogicType.NextWeatherEventTime 97
|
||||
LogicType.None 0 No description
|
||||
LogicType.On 28 The current state of the device, 0 for off, 1 for on
|
||||
LogicType.Open 2 1 if device is open, otherwise 0
|
||||
LogicType.OperationalTemperatureEfficiency 150 How the input pipe's temperature effects the machines efficiency
|
||||
LogicType.OrbitPeriod 245
|
||||
LogicType.Orientation 230
|
||||
LogicType.Output 70 The output operation for a sort handling device, such as a stacker or sorter, when in logic mode the device will only action one repetition when set zero or above and then back to -1 and await further instructions
|
||||
LogicType.PassedMoles 234
|
||||
LogicType.Plant 68 Performs the planting action for any plant based machinery
|
||||
LogicType.PlantEfficiency1 52 DEPRECATED
|
||||
LogicType.PlantEfficiency2 53 DEPRECATED
|
||||
LogicType.PlantEfficiency3 54 DEPRECATED
|
||||
LogicType.PlantEfficiency4 55 DEPRECATED
|
||||
LogicType.PlantGrowth1 48 DEPRECATED
|
||||
LogicType.PlantGrowth2 49 DEPRECATED
|
||||
LogicType.PlantGrowth3 50 DEPRECATED
|
||||
LogicType.PlantGrowth4 51 DEPRECATED
|
||||
LogicType.PlantHash1 56 DEPRECATED
|
||||
LogicType.PlantHash2 57 DEPRECATED
|
||||
LogicType.PlantHash3 58 DEPRECATED
|
||||
LogicType.PlantHash4 59 DEPRECATED
|
||||
LogicType.PlantHealth1 44 DEPRECATED
|
||||
LogicType.PlantHealth2 45 DEPRECATED
|
||||
LogicType.PlantHealth3 46 DEPRECATED
|
||||
LogicType.PlantHealth4 47 DEPRECATED
|
||||
LogicType.PositionX 76 The current position in X dimension in world coordinates
|
||||
LogicType.PositionY 77 The current position in Y dimension in world coordinates
|
||||
LogicType.PositionZ 78 The current position in Z dimension in world coordinates
|
||||
LogicType.Power 1 Can be read to return if the device is correctly powered or not, set via the power system, return 1 if powered and 0 if not
|
||||
LogicType.PowerActual 26 How much energy the device or network is actually using
|
||||
LogicType.PowerGeneration 65 Returns how much power is being generated
|
||||
LogicType.PowerPotential 25 How much energy the device or network potentially provides
|
||||
LogicType.PowerRequired 36 Power requested from the device and/or network
|
||||
LogicType.PrefabHash 84 The hash of the structure
|
||||
LogicType.Pressure 5 The current pressure reading of the device
|
||||
LogicType.PressureEfficiency 152 How the pressure of the input pipe and waste pipe effect the machines efficiency
|
||||
LogicType.PressureExternal 7 Setting for external pressure safety, in KPa
|
||||
LogicType.PressureInput 106 The current pressure reading of the device's Input Network
|
||||
LogicType.PressureInput2 116 The current pressure reading of the device's Input2 Network
|
||||
LogicType.PressureInternal 8 Setting for internal pressure safety, in KPa
|
||||
LogicType.PressureOutput 126 The current pressure reading of the device's Output Network
|
||||
LogicType.PressureOutput2 136 The current pressure reading of the device's Output2 Network
|
||||
LogicType.PressureSetting 71 The current setting for the internal pressure of the object (e.g. the Hardsuit Air release), in KPa
|
||||
LogicType.Progress 214 Progress of the rocket to the next node on the map expressed as a value between 0-1.
|
||||
LogicType.Quantity 27 Total quantity on the device
|
||||
LogicType.Ratio 24 Context specific value depending on device, 0 to 1 based ratio
|
||||
LogicType.RatioCarbonDioxide 15 The ratio of {GAS:CarbonDioxide} in device atmosphere
|
||||
LogicType.RatioCarbonDioxideInput 109 The ratio of {GAS:CarbonDioxide} in device's input network
|
||||
LogicType.RatioCarbonDioxideInput2 119 The ratio of {GAS:CarbonDioxide} in device's Input2 network
|
||||
LogicType.RatioCarbonDioxideOutput 129 The ratio of {GAS:CarbonDioxide} in device's Output network
|
||||
LogicType.RatioCarbonDioxideOutput2 139 The ratio of {GAS:CarbonDioxide} in device's Output2 network
|
||||
LogicType.RatioHydrogen 252 The ratio of {GAS:Hydrogen} in device's Atmopshere
|
||||
LogicType.RatioLiquidCarbonDioxide 199 The ratio of {GAS:LiquidCarbonDioxide} in device's Atmosphere
|
||||
LogicType.RatioLiquidCarbonDioxideInput 200 The ratio of {GAS:LiquidCarbonDioxide} in device's Input Atmosphere
|
||||
LogicType.RatioLiquidCarbonDioxideInput2 201 The ratio of {GAS:LiquidCarbonDioxide} in device's Input2 Atmosphere
|
||||
LogicType.RatioLiquidCarbonDioxideOutput 202 The ratio of {GAS:LiquidCarbonDioxide} in device's device's Output Atmosphere
|
||||
LogicType.RatioLiquidCarbonDioxideOutput2 203 The ratio of {GAS:LiquidCarbonDioxide} in device's Output2 Atmopshere
|
||||
LogicType.RatioLiquidHydrogen 253 The ratio of {GAS:LiquidHydrogen} in device's Atmopshere
|
||||
LogicType.RatioLiquidNitrogen 177 The ratio of {GAS:LiquidNitrogen} in device atmosphere
|
||||
LogicType.RatioLiquidNitrogenInput 178 The ratio of {GAS:LiquidNitrogen} in device's input network
|
||||
LogicType.RatioLiquidNitrogenInput2 179 The ratio of {GAS:LiquidNitrogen} in device's Input2 network
|
||||
LogicType.RatioLiquidNitrogenOutput 180 The ratio of {GAS:LiquidNitrogen} in device's Output network
|
||||
LogicType.RatioLiquidNitrogenOutput2 181 The ratio of {GAS:LiquidNitrogen} in device's Output2 network
|
||||
LogicType.RatioLiquidNitrousOxide 209 The ratio of {GAS:LiquidNitrousOxide} in device's Atmosphere
|
||||
LogicType.RatioLiquidNitrousOxideInput 210 The ratio of {GAS:LiquidNitrousOxide} in device's Input Atmosphere
|
||||
LogicType.RatioLiquidNitrousOxideInput2 211 The ratio of {GAS:LiquidNitrousOxide} in device's Input2 Atmosphere
|
||||
LogicType.RatioLiquidNitrousOxideOutput 212 The ratio of {GAS:LiquidNitrousOxide} in device's device's Output Atmosphere
|
||||
LogicType.RatioLiquidNitrousOxideOutput2 213 The ratio of {GAS:LiquidNitrousOxide} in device's Output2 Atmopshere
|
||||
LogicType.RatioLiquidOxygen 183 The ratio of {GAS:LiquidOxygen} in device's Atmosphere
|
||||
LogicType.RatioLiquidOxygenInput 184 The ratio of {GAS:LiquidOxygen} in device's Input Atmosphere
|
||||
LogicType.RatioLiquidOxygenInput2 185 The ratio of {GAS:LiquidOxygen} in device's Input2 Atmosphere
|
||||
LogicType.RatioLiquidOxygenOutput 186 The ratio of {GAS:LiquidOxygen} in device's device's Output Atmosphere
|
||||
LogicType.RatioLiquidOxygenOutput2 187 The ratio of {GAS:LiquidOxygen} in device's Output2 Atmopshere
|
||||
LogicType.RatioLiquidPollutant 204 The ratio of {GAS:LiquidPollutant} in device's Atmosphere
|
||||
LogicType.RatioLiquidPollutantInput 205 The ratio of {GAS:LiquidPollutant} in device's Input Atmosphere
|
||||
LogicType.RatioLiquidPollutantInput2 206 The ratio of {GAS:LiquidPollutant} in device's Input2 Atmosphere
|
||||
LogicType.RatioLiquidPollutantOutput 207 The ratio of {GAS:LiquidPollutant} in device's device's Output Atmosphere
|
||||
LogicType.RatioLiquidPollutantOutput2 208 The ratio of {GAS:LiquidPollutant} in device's Output2 Atmopshere
|
||||
LogicType.RatioLiquidVolatiles 188 The ratio of {GAS:LiquidVolatiles} in device's Atmosphere
|
||||
LogicType.RatioLiquidVolatilesInput 189 The ratio of {GAS:LiquidVolatiles} in device's Input Atmosphere
|
||||
LogicType.RatioLiquidVolatilesInput2 190 The ratio of {GAS:LiquidVolatiles} in device's Input2 Atmosphere
|
||||
LogicType.RatioLiquidVolatilesOutput 191 The ratio of {GAS:LiquidVolatiles} in device's device's Output Atmosphere
|
||||
LogicType.RatioLiquidVolatilesOutput2 192 The ratio of {GAS:LiquidVolatiles} in device's Output2 Atmopshere
|
||||
LogicType.RatioNitrogen 16 The ratio of nitrogen in device atmosphere
|
||||
LogicType.RatioNitrogenInput 110 The ratio of nitrogen in device's input network
|
||||
LogicType.RatioNitrogenInput2 120 The ratio of nitrogen in device's Input2 network
|
||||
LogicType.RatioNitrogenOutput 130 The ratio of nitrogen in device's Output network
|
||||
LogicType.RatioNitrogenOutput2 140 The ratio of nitrogen in device's Output2 network
|
||||
LogicType.RatioNitrousOxide 83 The ratio of {GAS:NitrousOxide} in device atmosphere
|
||||
LogicType.RatioNitrousOxideInput 114 The ratio of {GAS:NitrousOxide} in device's input network
|
||||
LogicType.RatioNitrousOxideInput2 124 The ratio of {GAS:NitrousOxide} in device's Input2 network
|
||||
LogicType.RatioNitrousOxideOutput 134 The ratio of {GAS:NitrousOxide} in device's Output network
|
||||
LogicType.RatioNitrousOxideOutput2 144 The ratio of {GAS:NitrousOxide} in device's Output2 network
|
||||
LogicType.RatioOxygen 14 The ratio of oxygen in device atmosphere
|
||||
LogicType.RatioOxygenInput 108 The ratio of oxygen in device's input network
|
||||
LogicType.RatioOxygenInput2 118 The ratio of oxygen in device's Input2 network
|
||||
LogicType.RatioOxygenOutput 128 The ratio of oxygen in device's Output network
|
||||
LogicType.RatioOxygenOutput2 138 The ratio of oxygen in device's Output2 network
|
||||
LogicType.RatioPollutant 17 The ratio of pollutant in device atmosphere
|
||||
LogicType.RatioPollutantInput 111 The ratio of pollutant in device's input network
|
||||
LogicType.RatioPollutantInput2 121 The ratio of pollutant in device's Input2 network
|
||||
LogicType.RatioPollutantOutput 131 The ratio of pollutant in device's Output network
|
||||
LogicType.RatioPollutantOutput2 141 The ratio of pollutant in device's Output2 network
|
||||
LogicType.RatioPollutedWater 254 The ratio of polluted water in device atmosphere
|
||||
LogicType.RatioSteam 193 The ratio of {GAS:Steam} in device's Atmosphere
|
||||
LogicType.RatioSteamInput 194 The ratio of {GAS:Steam} in device's Input Atmosphere
|
||||
LogicType.RatioSteamInput2 195 The ratio of {GAS:Steam} in device's Input2 Atmosphere
|
||||
LogicType.RatioSteamOutput 196 The ratio of {GAS:Steam} in device's device's Output Atmosphere
|
||||
LogicType.RatioSteamOutput2 197 The ratio of {GAS:Steam} in device's Output2 Atmopshere
|
||||
LogicType.RatioVolatiles 18 The ratio of volatiles in device atmosphere
|
||||
LogicType.RatioVolatilesInput 112 The ratio of volatiles in device's input network
|
||||
LogicType.RatioVolatilesInput2 122 The ratio of volatiles in device's Input2 network
|
||||
LogicType.RatioVolatilesOutput 132 The ratio of volatiles in device's Output network
|
||||
LogicType.RatioVolatilesOutput2 142 The ratio of volatiles in device's Output2 network
|
||||
LogicType.RatioWater 19 The ratio of water in device atmosphere
|
||||
LogicType.RatioWaterInput 113 The ratio of water in device's input network
|
||||
LogicType.RatioWaterInput2 123 The ratio of water in device's Input2 network
|
||||
LogicType.RatioWaterOutput 133 The ratio of water in device's Output network
|
||||
LogicType.RatioWaterOutput2 143 The ratio of water in device's Output2 network
|
||||
LogicType.ReEntryAltitude 237
|
||||
LogicType.Reagents 13 Total number of reagents recorded by the device
|
||||
LogicType.RecipeHash 41 Current hash of the recipe the device is set to produce
|
||||
LogicType.ReferenceId 217
|
||||
LogicType.RequestHash 60 When set to the unique identifier, requests an item of the provided type from the device
|
||||
LogicType.RequiredPower 33 Idle operating power quantity, does not necessarily include extra demand power
|
||||
LogicType.ReturnFuelCost 100
|
||||
LogicType.Richness 263
|
||||
LogicType.Rpm 155 The number of revolutions per minute that the device's spinning mechanism is doing
|
||||
LogicType.SemiMajorAxis 248
|
||||
LogicType.Setting 12 A variable setting that can be read or written, depending on the device
|
||||
LogicType.SettingInput 91
|
||||
LogicType.SettingOutput 92
|
||||
LogicType.SignalID 87 Returns the contact ID of the strongest signal from this Satellite
|
||||
LogicType.SignalStrength 86 Returns the degree offset of the strongest contact
|
||||
LogicType.Sites 260
|
||||
LogicType.Size 264
|
||||
LogicType.SizeX 160 Size on the X (right) axis of the object in largeGrids (a largeGrid is 2meters)
|
||||
LogicType.SizeY 161 Size on the Y(Up) axis of the object in largeGrids (a largeGrid is 2meters)
|
||||
LogicType.SizeZ 162 Size on the Z(Forward) axis of the object in largeGrids (a largeGrid is 2meters)
|
||||
LogicType.SolarAngle 22 Solar angle of the device
|
||||
LogicType.SolarIrradiance 176
|
||||
LogicType.SoundAlert 175 Plays a sound alert on the devices speaker
|
||||
LogicType.Stress 156 Machines get stressed when working hard. When Stress reaches 100 the machine will automatically shut down
|
||||
LogicType.Survey 257
|
||||
LogicType.TargetPadIndex 158 The index of the trader landing pad on this devices data network that it will try to call a trader in to land
|
||||
LogicType.TargetX 88 The target position in X dimension in world coordinates
|
||||
LogicType.TargetY 89 The target position in Y dimension in world coordinates
|
||||
LogicType.TargetZ 90 The target position in Z dimension in world coordinates
|
||||
LogicType.Temperature 6 The current temperature reading of the device
|
||||
LogicType.TemperatureDifferentialEfficiency 151 How the difference between the input pipe and waste pipe temperatures effect the machines efficiency
|
||||
LogicType.TemperatureExternal 73 The temperature of the outside of the device, usually the world atmosphere surrounding it
|
||||
LogicType.TemperatureInput 107 The current temperature reading of the device's Input Network
|
||||
LogicType.TemperatureInput2 117 The current temperature reading of the device's Input2 Network
|
||||
LogicType.TemperatureOutput 127 The current temperature reading of the device's Output Network
|
||||
LogicType.TemperatureOutput2 137 The current temperature reading of the device's Output2 Network
|
||||
LogicType.TemperatureSetting 72 The current setting for the internal temperature of the object (e.g. the Hardsuit A/C)
|
||||
LogicType.Throttle 154 Increases the rate at which the machine works (range: 0-100)
|
||||
LogicType.Thrust 221 Total current thrust of all rocket engines on the rocket in Newtons.
|
||||
LogicType.ThrustToWeight 223 Ratio of thrust to weight of rocket. Weight is effected by local body gravity. A rocket with a low thrust to weight will expend more fuel during launch and landing.
|
||||
LogicType.Time 102 Time
|
||||
LogicType.TimeToDestination 224 Estimated time in seconds until rocket arrives at target destination.
|
||||
LogicType.TotalMoles 66 Returns the total moles of the device
|
||||
LogicType.TotalMolesInput 115 Returns the total moles of the device's Input Network
|
||||
LogicType.TotalMolesInput2 125 Returns the total moles of the device's Input2 Network
|
||||
LogicType.TotalMolesOutput 135 Returns the total moles of the device's Output Network
|
||||
LogicType.TotalMolesOutput2 145 Returns the total moles of the device's Output2 Network
|
||||
LogicType.TotalQuantity 265
|
||||
LogicType.TrueAnomaly 251
|
||||
LogicType.VelocityMagnitude 79 The current magnitude of the velocity vector
|
||||
LogicType.VelocityRelativeX 80 The current velocity X relative to the forward vector of this
|
||||
LogicType.VelocityRelativeY 81 The current velocity Y relative to the forward vector of this
|
||||
LogicType.VelocityRelativeZ 82 The current velocity Z relative to the forward vector of this
|
||||
LogicType.VelocityX 231
|
||||
LogicType.VelocityY 232
|
||||
LogicType.VelocityZ 233
|
||||
LogicType.Vertical 21 Vertical setting of the device
|
||||
LogicType.VerticalRatio 35 Radio of vertical setting for device
|
||||
LogicType.Volume 67 Returns the device atmosphere volume
|
||||
LogicType.VolumeOfLiquid 182 The total volume of all liquids in Liters in the atmosphere
|
||||
LogicType.WattsReachingContact 164 The amount of watts actually hitting the contact. This is effected by the power of the dish and how far off-axis the dish is from the contact vector
|
||||
LogicType.Weight 222 Weight of Rocket in Newtons (Including fuel and cargo). Weight is effected by local body gravity.
|
||||
LogicType.WorkingGasEfficiency 105 The Working Gas Efficiency reported by the machine, as a float between 0 and 1
|
||||
NotEquals 3
|
||||
PowerMode.Charged 4
|
||||
PowerMode.Charging 3
|
||||
PowerMode.Discharged 1
|
||||
PowerMode.Discharging 2
|
||||
PowerMode.Idle 0
|
||||
RobotMode.Follow 1
|
||||
RobotMode.MoveToTarget 2
|
||||
RobotMode.None 0
|
||||
RobotMode.PathToTarget 5
|
||||
RobotMode.Roam 3
|
||||
RobotMode.StorageFull 6
|
||||
RobotMode.Unload 4
|
||||
SlotClass.AccessCard 22
|
||||
SlotClass.Appliance 18
|
||||
SlotClass.Back 3
|
||||
SlotClass.Battery 14
|
||||
SlotClass.Belt 16
|
||||
SlotClass.Blocked 38
|
||||
SlotClass.Bottle 25
|
||||
SlotClass.Cartridge 21
|
||||
SlotClass.Circuit 24
|
||||
SlotClass.Circuitboard 7
|
||||
SlotClass.CreditCard 28
|
||||
SlotClass.DataDisk 8
|
||||
SlotClass.DirtCanister 29
|
||||
SlotClass.DrillHead 35
|
||||
SlotClass.Egg 15
|
||||
SlotClass.Entity 13
|
||||
SlotClass.Flare 37
|
||||
SlotClass.GasCanister 5
|
||||
SlotClass.GasFilter 4
|
||||
SlotClass.Glasses 27
|
||||
SlotClass.Helmet 1
|
||||
SlotClass.Ingot 19
|
||||
SlotClass.LiquidBottle 32
|
||||
SlotClass.LiquidCanister 31
|
||||
SlotClass.Magazine 23
|
||||
SlotClass.Motherboard 6
|
||||
SlotClass.None 0
|
||||
SlotClass.Ore 10
|
||||
SlotClass.Organ 9
|
||||
SlotClass.Plant 11
|
||||
SlotClass.ProgrammableChip 26
|
||||
SlotClass.ScanningHead 36
|
||||
SlotClass.SensorProcessingUnit 30
|
||||
SlotClass.SoundCartridge 34
|
||||
SlotClass.Suit 2
|
||||
SlotClass.Tool 17
|
||||
SlotClass.Torpedo 20
|
||||
SlotClass.Uniform 12
|
||||
SlotClass.Wreckage 33
|
||||
SortingClass.Appliances 6
|
||||
SortingClass.Atmospherics 7
|
||||
SortingClass.Clothing 5
|
||||
SortingClass.Default 0
|
||||
SortingClass.Food 4
|
||||
SortingClass.Ices 10
|
||||
SortingClass.Kits 1
|
||||
SortingClass.Ores 9
|
||||
SortingClass.Resources 3
|
||||
SortingClass.Storage 8
|
||||
SortingClass.Tools 2
|
||||
Sound.AirlockCycling 22
|
||||
Sound.Alarm1 45
|
||||
Sound.Alarm10 12
|
||||
Sound.Alarm11 13
|
||||
Sound.Alarm12 14
|
||||
Sound.Alarm2 1
|
||||
Sound.Alarm3 2
|
||||
Sound.Alarm4 3
|
||||
Sound.Alarm5 4
|
||||
Sound.Alarm6 5
|
||||
Sound.Alarm7 6
|
||||
Sound.Alarm8 10
|
||||
Sound.Alarm9 11
|
||||
Sound.Alert 17
|
||||
Sound.Danger 15
|
||||
Sound.Depressurising 20
|
||||
Sound.FireFireFire 28
|
||||
Sound.Five 33
|
||||
Sound.Floor 34
|
||||
Sound.Four 32
|
||||
Sound.HaltWhoGoesThere 27
|
||||
Sound.HighCarbonDioxide 44
|
||||
Sound.IntruderAlert 19
|
||||
Sound.LiftOff 36
|
||||
Sound.MalfunctionDetected 26
|
||||
Sound.Music1 7
|
||||
Sound.Music2 8
|
||||
Sound.Music3 9
|
||||
Sound.None 0
|
||||
Sound.One 29
|
||||
Sound.PollutantsDetected 43
|
||||
Sound.PowerLow 23
|
||||
Sound.PressureHigh 39
|
||||
Sound.PressureLow 40
|
||||
Sound.Pressurising 21
|
||||
Sound.RocketLaunching 35
|
||||
Sound.StormIncoming 18
|
||||
Sound.SystemFailure 24
|
||||
Sound.TemperatureHigh 41
|
||||
Sound.TemperatureLow 42
|
||||
Sound.Three 31
|
||||
Sound.TraderIncoming 37
|
||||
Sound.TraderLanded 38
|
||||
Sound.Two 30
|
||||
Sound.Warning 16
|
||||
Sound.Welcome 25
|
||||
TransmitterMode.Active 1
|
||||
TransmitterMode.Passive 0
|
||||
Vent.Inward 1
|
||||
Vent.Outward 0
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"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 abs(a) <= max(b * abs(a), float.epsilon * 8), otherwise 0",
|
||||
"snaz": "Register = 1 if abs(a) > max(b * abs(a), float.epsilon), otherwise 0",
|
||||
"log": "Register = base e log(a) or ln(a)",
|
||||
"exp": "Register = exp(a) or e^a"
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
abs REGISTER VALUE
|
||||
acos REGISTER VALUE
|
||||
add REGISTER VALUE VALUE
|
||||
alias NAME REGISTER_DEVICE
|
||||
and REGISTER VALUE VALUE
|
||||
asin REGISTER VALUE
|
||||
atan REGISTER VALUE
|
||||
atan2 REGISTER VALUE VALUE
|
||||
bap VALUE VALUE VALUE VALUE
|
||||
bapal VALUE VALUE VALUE VALUE
|
||||
bapz VALUE VALUE VALUE
|
||||
bapzal VALUE VALUE VALUE
|
||||
bdns DEVICE VALUE
|
||||
bdnsal DEVICE VALUE
|
||||
bdse DEVICE VALUE
|
||||
bdseal DEVICE VALUE
|
||||
beq VALUE VALUE VALUE
|
||||
beqal VALUE VALUE VALUE
|
||||
beqz VALUE VALUE
|
||||
beqzal VALUE VALUE
|
||||
bge VALUE VALUE VALUE
|
||||
bgeal VALUE VALUE VALUE
|
||||
bgez VALUE VALUE
|
||||
bgezal VALUE VALUE
|
||||
bgt VALUE VALUE VALUE
|
||||
bgtal VALUE VALUE VALUE
|
||||
bgtz VALUE VALUE
|
||||
bgtzal VALUE VALUE
|
||||
ble VALUE VALUE VALUE
|
||||
bleal VALUE VALUE VALUE
|
||||
blez VALUE VALUE
|
||||
blezal VALUE VALUE
|
||||
blt VALUE VALUE VALUE
|
||||
bltal VALUE VALUE VALUE
|
||||
bltz VALUE VALUE
|
||||
bltzal VALUE VALUE
|
||||
bna VALUE VALUE VALUE VALUE
|
||||
bnaal VALUE VALUE VALUE VALUE
|
||||
bnan VALUE VALUE
|
||||
bnaz VALUE VALUE VALUE
|
||||
bnazal VALUE VALUE VALUE
|
||||
bne VALUE VALUE VALUE
|
||||
bneal VALUE VALUE VALUE
|
||||
bnez VALUE VALUE
|
||||
bnezal VALUE VALUE
|
||||
brap VALUE VALUE VALUE VALUE
|
||||
brapz VALUE VALUE VALUE
|
||||
brdns DEVICE VALUE
|
||||
brdse DEVICE VALUE
|
||||
breq VALUE VALUE VALUE
|
||||
breqz VALUE VALUE
|
||||
brge VALUE VALUE VALUE
|
||||
brgez VALUE VALUE
|
||||
brgt VALUE VALUE VALUE
|
||||
brgtz VALUE VALUE
|
||||
brle VALUE VALUE VALUE
|
||||
brlez VALUE VALUE
|
||||
brlt VALUE VALUE VALUE
|
||||
brltz VALUE VALUE
|
||||
brna VALUE VALUE VALUE VALUE
|
||||
brnan VALUE VALUE
|
||||
brnaz VALUE VALUE VALUE
|
||||
brne VALUE VALUE VALUE
|
||||
brnez VALUE VALUE
|
||||
ceil REGISTER VALUE
|
||||
cos REGISTER VALUE
|
||||
define NAME NUMBER
|
||||
div REGISTER VALUE VALUE
|
||||
exp REGISTER VALUE
|
||||
floor REGISTER VALUE
|
||||
get REGISTER DEVICE ADDRESS
|
||||
getd REGISTER DEVICE_ID ADDRESS
|
||||
hcf
|
||||
j VALUE
|
||||
jal VALUE
|
||||
jr VALUE
|
||||
l REGISTER DEVICE LOGIC_TYPE
|
||||
lb REGISTER DEVICE_TYPE LOGIC_TYPE BATCH_MODE
|
||||
lbn REGISTER DEVICE_TYPE DEVICE_NAME LOGIC_TYPE BATCH_MODE
|
||||
lbns REGISTER DEVICE_TYPE DEVICE_NAME INDEX SLOT_LOGIC_TYPE BATCH_MODE
|
||||
lbs REGISTER DEVICE_TYPE INDEX SLOT_LOGIC_TYPE BATCH_MODE
|
||||
ld REGISTER DEVICE_ID LOGIC_TYPE
|
||||
log REGISTER VALUE
|
||||
lr REGISTER DEVICE REAGENT_MODE VALUE
|
||||
ls REGISTER DEVICE VALUE SLOT_LOGIC_TYPE
|
||||
max REGISTER VALUE VALUE
|
||||
min REGISTER VALUE VALUE
|
||||
mod REGISTER VALUE VALUE
|
||||
move REGISTER VALUE
|
||||
mul REGISTER VALUE VALUE
|
||||
nor REGISTER VALUE VALUE
|
||||
not REGISTER VALUE
|
||||
or REGISTER VALUE VALUE
|
||||
peek REGISTER
|
||||
poke ADDRESS VALUE
|
||||
pop REGISTER
|
||||
push VALUE
|
||||
put DEVICE ADDRESS VALUE
|
||||
putd DEVICE_ID ADDRESS VALUE
|
||||
rand REGISTER
|
||||
round REGISTER VALUE
|
||||
s DEVICE LOGIC_TYPE VALUE
|
||||
sap REGISTER VALUE VALUE VALUE
|
||||
sapz REGISTER VALUE VALUE
|
||||
sb DEVICE_TYPE LOGIC_TYPE VALUE
|
||||
sbn DEVICE_TYPE DEVICE_NAME LOGIC_TYPE VALUE
|
||||
sbs DEVICE_TYPE INDEX SLOT_LOGIC_TYPE VALUE
|
||||
sd DEVICE_ID LOGIC_TYPE VALUE
|
||||
sdns REGISTER DEVICE
|
||||
sdse REGISTER DEVICE
|
||||
select REGISTER VALUE VALUE VALUE
|
||||
seq REGISTER VALUE VALUE
|
||||
seqz REGISTER VALUE
|
||||
sge REGISTER VALUE VALUE
|
||||
sgez REGISTER VALUE
|
||||
sgt REGISTER VALUE VALUE
|
||||
sgtz REGISTER VALUE
|
||||
sin REGISTER VALUE
|
||||
sla REGISTER VALUE VALUE
|
||||
sle REGISTER VALUE VALUE
|
||||
sleep VALUE
|
||||
slez REGISTER VALUE
|
||||
sll REGISTER VALUE VALUE
|
||||
slt REGISTER VALUE VALUE
|
||||
sltz REGISTER VALUE
|
||||
sna REGISTER VALUE VALUE VALUE
|
||||
snan REGISTER VALUE
|
||||
snanz REGISTER VALUE
|
||||
snaz REGISTER VALUE VALUE
|
||||
sne REGISTER VALUE VALUE
|
||||
snez REGISTER VALUE
|
||||
sqrt REGISTER VALUE
|
||||
sra REGISTER VALUE VALUE
|
||||
srl REGISTER VALUE VALUE
|
||||
ss DEVICE VALUE SLOT_LOGIC_TYPE REGISTER
|
||||
sub REGISTER VALUE VALUE
|
||||
tan REGISTER VALUE
|
||||
trunc REGISTER VALUE
|
||||
xor REGISTER VALUE VALUE
|
||||
yield
|
||||
@@ -1,136 +0,0 @@
|
||||
abs Register = the absolute value of a
|
||||
acos Returns the angle (radians) whos cosine is the specified value
|
||||
add Register = a + b.
|
||||
alias Labels register or device reference with name, device references also affect what shows on the screws on the IC base.
|
||||
and Performs a bitwise logical AND operation on the binary representation of two values. Each bit of the result is determined by evaluating the corresponding bits of the input values. If both bits are 1, the resulting bit is set to 1. Otherwise the resulting bit is set to 0.
|
||||
asin Returns the angle (radians) whos sine is the specified value
|
||||
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) <= 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
|
||||
bdseal Jump execution to line a and store next line number if device is set
|
||||
beq Branch to line c if a == b
|
||||
beqal Branch to line c if a == b and store next line number in ra
|
||||
beqz Branch to line b if a == 0
|
||||
beqzal Branch to line b if a == 0 and store next line number in ra
|
||||
bge Branch to line c if a >= b
|
||||
bgeal Branch to line c if a >= b and store next line number in ra
|
||||
bgez Branch to line b if a >= 0
|
||||
bgezal Branch to line b if a >= 0 and store next line number in ra
|
||||
bgt Branch to line c if a > b
|
||||
bgtal Branch to line c if a > b and store next line number in ra
|
||||
bgtz Branch to line b if a > 0
|
||||
bgtzal Branch to line b if a > 0 and store next line number in ra
|
||||
ble Branch to line c if a <= b
|
||||
bleal Branch to line c if a <= b and store next line number in ra
|
||||
blez Branch to line b if a <= 0
|
||||
blezal Branch to line b if a <= 0 and store next line number in ra
|
||||
blt Branch to line c if a < b
|
||||
bltal Branch to line c if a < b and store next line number in ra
|
||||
bltz Branch to line b if a < 0
|
||||
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) > 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) <= 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
|
||||
breqz Relative branch to line b if a == 0
|
||||
brge Relative jump to line c if a >= b
|
||||
brgez Relative branch to line b if a >= 0
|
||||
brgt relative jump to line c if a > b
|
||||
brgtz Relative branch to line b if a > 0
|
||||
brle Relative jump to line c if a <= b
|
||||
brlez Relative branch to line b if a <= 0
|
||||
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) > 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
|
||||
cos Returns the cosine of the specified angle (radians)
|
||||
define Creates a label that will be replaced throughout the program with the provided value.
|
||||
div Register = a / b
|
||||
exp Register = exp(a) or e^a
|
||||
floor Register = largest integer less than a
|
||||
hcf Halt and catch fire
|
||||
j Jump execution to line a
|
||||
jal Jump execution to line a and store next line number in ra
|
||||
jr Relative jump to line a
|
||||
l Loads device LogicType to register by housing index value.
|
||||
label DEPRECATED
|
||||
lb Loads LogicType from all output network devices with provided type hash using the provide batch mode. Average (0), Sum (1), Minimum (2), Maximum (3). Can use either the word, or the number.
|
||||
lbn Loads LogicType from all output network devices with provided type and name hashes using the provide batch mode. Average (0), Sum (1), Minimum (2), Maximum (3). Can use either the word, or the number.
|
||||
lbns Loads LogicSlotType from slotIndex from all output network devices with provided type and name hashes using the provide batch mode. Average (0), Sum (1), Minimum (2), Maximum (3). Can use either the word, or the number.
|
||||
lbs Loads LogicSlotType from slotIndex from all output network devices with provided type hash using the provide batch mode. Average (0), Sum (1), Minimum (2), Maximum (3). Can use either the word, or the number.
|
||||
ld Loads device LogicType to register by direct ID reference.
|
||||
log Register = base e log(a) or ln(a)
|
||||
lr Loads reagent of device's ReagentMode where a hash of the reagent type to check for. ReagentMode can be either Contents (0), Required (1), Recipe (2). Can use either the word, or the number.
|
||||
ls Loads slot LogicSlotType on device to register.
|
||||
max Register = max of a or b
|
||||
min Register = min of a or b
|
||||
mod Register = a mod b (note: NOT a % b)
|
||||
move Register = provided num or register value.
|
||||
mul Register = a * b
|
||||
nor Performs a bitwise logical NOR (NOT OR) operation on the binary representation of two values. Each bit of the result is determined by evaluating the corresponding bits of the input values. If both bits are 0, the resulting bit is set to 1. Otherwise, if at least one bit is 1, the resulting bit is set to 0.
|
||||
not Performs a bitwise logical NOT operation flipping each bit of the input value, resulting in a binary complement. If a bit is 1, it becomes 0, and if a bit is 0, it becomes 1.
|
||||
or Performs a bitwise logical OR operation on the binary representation of two values. Each bit of the result is determined by evaluating the corresponding bits of the input values. If either bit is 1, the resulting bit is set to 1. If both bits are 0, the resulting bit is set to 0.
|
||||
peek Register = the value at the top of the stack
|
||||
pop Register = the value at the top of the stack and decrements sp
|
||||
push Pushes the value of a to the stack at sp and increments sp
|
||||
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 abs(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.
|
||||
sd Stores register value to LogicType on device by direct ID reference.
|
||||
sdns Register = 1 if device is not set, otherwise 0
|
||||
sdse Register = 1 if device is set, otherwise 0.
|
||||
select Register = b if a is non-zero, otherwise c
|
||||
seq Register = 1 if a == b, otherwise 0
|
||||
seqz Register = 1 if a == 0, otherwise 0
|
||||
sge Register = 1 if a >= b, otherwise 0
|
||||
sgez Register = 1 if a >= 0, otherwise 0
|
||||
sgt Register = 1 if a > b, otherwise 0
|
||||
sgtz Register = 1 if a > 0, otherwise 0
|
||||
sin Returns the sine of the specified angle (radians)
|
||||
sla Performs a bitwise arithmetic left shift operation on the binary representation of a value. It shifts the bits to the left and fills the vacated rightmost bits with a copy of the sign bit (the most significant bit).
|
||||
sle Register = 1 if a <= b, otherwise 0
|
||||
sleep Pauses execution on the IC for a seconds
|
||||
slez Register = 1 if a <= 0, otherwise 0
|
||||
sll Performs a bitwise logical left shift operation on the binary representation of a value. It shifts the bits to the left and fills the vacated rightmost bits with zeros.
|
||||
slt Register = 1 if a < b, otherwise 0
|
||||
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 abs(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
|
||||
sra Performs a bitwise arithmetic right shift operation on the binary representation of a value. It shifts the bits to the right and fills the vacated leftmost bits with a copy of the sign bit (the most significant bit).
|
||||
srl Performs a bitwise logical right shift operation on the binary representation of a value. It shifts the bits to the right and fills the vacated leftmost bits with zeros
|
||||
ss Stores register value to device stored in a slot LogicSlotType on device.
|
||||
sub Register = a - b.
|
||||
tan Returns the tan of the specified angle (radians)
|
||||
trunc Register = a with fractional part removed
|
||||
xor Performs a bitwise logical XOR (exclusive OR) operation on the binary representation of two values. Each bit of the result is determined by evaluating the corresponding bits of the input values. If the bits are different (one bit is 0 and the other is 1), the resulting bit is set to 1. If the bits are the same (both 0 or both 1), the resulting bit is set to 0.
|
||||
yield Pauses execution for 1 tick
|
||||
@@ -1,269 +0,0 @@
|
||||
Acceleration 216 Change in velocity. Rockets that are deccelerating when landing will show this as negative value.
|
||||
Activate 9 1 if device is activated (usually means running), otherwise 0
|
||||
AirRelease 75 The current state of the air release system, for example AirRelease = 1 for a Hardsuit sets Air Release to On
|
||||
AlignmentError 243
|
||||
Apex 238
|
||||
AutoLand 226 Engages the automatic landing algorithm. The rocket will automatically throttle and turn on and off its engines to achieve a smooth landing.
|
||||
AutoShutOff 218 Turns off all devices in the rocket upon reaching destination
|
||||
Bpm 103 Bpm
|
||||
BurnTimeRemaining 225 Estimated time in seconds until fuel is depleted. Calculated based on current fuel usage.
|
||||
CelestialHash 242
|
||||
CelestialParentHash 250
|
||||
Channel0 165 Channel 0 on a cable network which should be considered volatile
|
||||
Channel1 166 Channel 1 on a cable network which should be considered volatile
|
||||
Channel2 167 Channel 2 on a cable network which should be considered volatile
|
||||
Channel3 168 Channel 3 on a cable network which should be considered volatile
|
||||
Channel4 169 Channel 4 on a cable network which should be considered volatile
|
||||
Channel5 170 Channel 5 on a cable network which should be considered volatile
|
||||
Channel6 171 Channel 6 on a cable network which should be considered volatile
|
||||
Channel7 172 Channel 7 on a cable network which should be considered volatile
|
||||
Charge 11 The current charge the device has
|
||||
Chart 256
|
||||
ChartedNavPoints 259
|
||||
ClearMemory 62 When set to 1, clears the counter memory (e.g. ExportCount). Will set itself back to 0 when actioned
|
||||
CollectableGoods 101
|
||||
Color 38 \n Whether driven by concerns for clarity, safety or simple aesthetics, {LINK:Stationeers;Stationeers} have access to a small rainbow of colors for their constructions. These are the color setting for devices, represented as an integer.\n\n0: Blue\n1: Grey\n2: Green\n3: Orange\n4: Red\n5: Yellow\n6: White\n7: Black\n8: Brown\n9: Khaki\n10: Pink\n11: Purple\n\n It is an unwavering universal law that anything higher than 11 will be purple. The {LINK:ODA;ODA} is powerless to change this. Similarly, anything lower than 0 will be Blue.\n
|
||||
Combustion 98 The assess atmosphere is on fire. Returns 1 if atmosphere is on fire, 0 if not.
|
||||
CombustionInput 146 The assess atmosphere is on fire. Returns 1 if device's input network is on fire, 0 if not.
|
||||
CombustionInput2 147 The assess atmosphere is on fire. Returns 1 if device's Input2 network is on fire, 0 if not.
|
||||
CombustionLimiter 153 Retards the rate of combustion inside the machine (range: 0-100), with 0 being the slowest rate of combustion and 100 being the fastest
|
||||
CombustionOutput 148 The assess atmosphere is on fire. Returns 1 if device's Output network is on fire, 0 if not.
|
||||
CombustionOutput2 149 The assess atmosphere is on fire. Returns 1 if device's Output2 network is on fire, 0 if not.
|
||||
CompletionRatio 61 How complete the current production is for this device, between 0 and 1
|
||||
ContactTypeId 198 The type id of the contact.
|
||||
CurrentCode 261
|
||||
CurrentResearchPodType 93
|
||||
Density 262
|
||||
DestinationCode 215 Unique identifier code for a destination on the space map.
|
||||
Discover 255
|
||||
DistanceAu 244
|
||||
DistanceKm 249
|
||||
DrillCondition 240
|
||||
DryMass 220 The Mass in kilograms of the rocket excluding fuel. The more massive the rocket the more fuel will be required to move to a new location in space.
|
||||
Eccentricity 247
|
||||
ElevatorLevel 40 Level the elevator is currently at
|
||||
ElevatorSpeed 39 Current speed of the elevator
|
||||
EntityState 239
|
||||
EnvironmentEfficiency 104 The Environment Efficiency reported by the machine, as a float between 0 and 1
|
||||
Error 4 1 if device is in error state, otherwise 0
|
||||
ExhaustVelocity 235
|
||||
ExportCount 63 How many items exported since last ClearMemory
|
||||
ExportQuantity 31 Total quantity of items exported by the device
|
||||
ExportSlotHash 42 DEPRECATED
|
||||
ExportSlotOccupant 32 DEPRECATED
|
||||
Filtration 74 The current state of the filtration system, for example Filtration = 1 for a Hardsuit sets filtration to On
|
||||
FlightControlRule 236
|
||||
Flush 174 Set to 1 to activate the flush function on the device
|
||||
ForceWrite 85 Forces Logic Writer devices to rewrite value
|
||||
ForwardX 227
|
||||
ForwardY 228
|
||||
ForwardZ 229
|
||||
Fuel 99
|
||||
Harvest 69 Performs the harvesting action for any plant based machinery
|
||||
Horizontal 20 Horizontal setting of the device
|
||||
HorizontalRatio 34 Radio of horizontal setting for device
|
||||
Idle 37 Returns 1 if the device is currently idle, otherwise 0
|
||||
ImportCount 64 How many items imported since last ClearMemory
|
||||
ImportQuantity 29 Total quantity of items imported by the device
|
||||
ImportSlotHash 43 DEPRECATED
|
||||
ImportSlotOccupant 30 DEPRECATED
|
||||
Inclination 246
|
||||
Index 241
|
||||
InterrogationProgress 157 Progress of this sattellite dish's interrogation of its current target, as a ratio from 0-1
|
||||
LineNumber 173 The line number of current execution for an integrated circuit running on this device. While this number can be written, use with caution
|
||||
Lock 10 1 if device is locked, otherwise 0, can be set in most devices and prevents the user from access the values
|
||||
ManualResearchRequiredPod 94
|
||||
Mass 219 The total Mass of the rocket in kilograms including fuel and cargo. The more massive the rocket the more fuel will be required to move to a new location in space.
|
||||
Maximum 23 Maximum setting of the device
|
||||
MinWattsToContact 163 Minimum required amount of watts from the dish hitting the target trader contact to start interrogating the contact
|
||||
MineablesInQueue 96
|
||||
MineablesInVicinity 95
|
||||
MinedQuantity 266
|
||||
MinimumWattsToContact 163 Minimum required amount of watts from the dish hitting the target trader contact to start interrogating the contact
|
||||
Mode 3 Integer for mode state, different devices will have different mode states available to them
|
||||
NavPoints 258
|
||||
NextWeatherEventTime 97
|
||||
None 0 No description
|
||||
On 28 The current state of the device, 0 for off, 1 for on
|
||||
Open 2 1 if device is open, otherwise 0
|
||||
OperationalTemperatureEfficiency 150 How the input pipe's temperature effects the machines efficiency
|
||||
OrbitPeriod 245
|
||||
Orientation 230
|
||||
Output 70 The output operation for a sort handling device, such as a stacker or sorter, when in logic mode the device will only action one repetition when set zero or above and then back to -1 and await further instructions
|
||||
PassedMoles 234
|
||||
Plant 68 Performs the planting action for any plant based machinery
|
||||
PlantEfficiency1 52 DEPRECATED
|
||||
PlantEfficiency2 53 DEPRECATED
|
||||
PlantEfficiency3 54 DEPRECATED
|
||||
PlantEfficiency4 55 DEPRECATED
|
||||
PlantGrowth1 48 DEPRECATED
|
||||
PlantGrowth2 49 DEPRECATED
|
||||
PlantGrowth3 50 DEPRECATED
|
||||
PlantGrowth4 51 DEPRECATED
|
||||
PlantHash1 56 DEPRECATED
|
||||
PlantHash2 57 DEPRECATED
|
||||
PlantHash3 58 DEPRECATED
|
||||
PlantHash4 59 DEPRECATED
|
||||
PlantHealth1 44 DEPRECATED
|
||||
PlantHealth2 45 DEPRECATED
|
||||
PlantHealth3 46 DEPRECATED
|
||||
PlantHealth4 47 DEPRECATED
|
||||
PositionX 76 The current position in X dimension in world coordinates
|
||||
PositionY 77 The current position in Y dimension in world coordinates
|
||||
PositionZ 78 The current position in Z dimension in world coordinates
|
||||
Power 1 Can be read to return if the device is correctly powered or not, set via the power system, return 1 if powered and 0 if not
|
||||
PowerActual 26 How much energy the device or network is actually using
|
||||
PowerGeneration 65 Returns how much power is being generated
|
||||
PowerPotential 25 How much energy the device or network potentially provides
|
||||
PowerRequired 36 Power requested from the device and/or network
|
||||
PrefabHash 84 The hash of the structure
|
||||
Pressure 5 The current pressure reading of the device
|
||||
PressureEfficiency 152 How the pressure of the input pipe and waste pipe effect the machines efficiency
|
||||
PressureExternal 7 Setting for external pressure safety, in KPa
|
||||
PressureInput 106 The current pressure reading of the device's Input Network
|
||||
PressureInput2 116 The current pressure reading of the device's Input2 Network
|
||||
PressureInternal 8 Setting for internal pressure safety, in KPa
|
||||
PressureOutput 126 The current pressure reading of the device's Output Network
|
||||
PressureOutput2 136 The current pressure reading of the device's Output2 Network
|
||||
PressureSetting 71 The current setting for the internal pressure of the object (e.g. the Hardsuit Air release), in KPa
|
||||
Progress 214 Progress of the rocket to the next node on the map expressed as a value between 0-1.
|
||||
Quantity 27 Total quantity on the device
|
||||
Ratio 24 Context specific value depending on device, 0 to 1 based ratio
|
||||
RatioCarbonDioxide 15 The ratio of {GAS:CarbonDioxide} in device atmosphere
|
||||
RatioCarbonDioxideInput 109 The ratio of {GAS:CarbonDioxide} in device's input network
|
||||
RatioCarbonDioxideInput2 119 The ratio of {GAS:CarbonDioxide} in device's Input2 network
|
||||
RatioCarbonDioxideOutput 129 The ratio of {GAS:CarbonDioxide} in device's Output network
|
||||
RatioCarbonDioxideOutput2 139 The ratio of {GAS:CarbonDioxide} in device's Output2 network
|
||||
RatioHydrogen 252 The ratio of {GAS:Hydrogen} in device's Atmopshere
|
||||
RatioLiquidCarbonDioxide 199 The ratio of {GAS:LiquidCarbonDioxide} in device's Atmosphere
|
||||
RatioLiquidCarbonDioxideInput 200 The ratio of {GAS:LiquidCarbonDioxide} in device's Input Atmosphere
|
||||
RatioLiquidCarbonDioxideInput2 201 The ratio of {GAS:LiquidCarbonDioxide} in device's Input2 Atmosphere
|
||||
RatioLiquidCarbonDioxideOutput 202 The ratio of {GAS:LiquidCarbonDioxide} in device's device's Output Atmosphere
|
||||
RatioLiquidCarbonDioxideOutput2 203 The ratio of {GAS:LiquidCarbonDioxide} in device's Output2 Atmopshere
|
||||
RatioLiquidHydrogen 253 The ratio of {GAS:LiquidHydrogen} in device's Atmopshere
|
||||
RatioLiquidNitrogen 177 The ratio of {GAS:LiquidNitrogen} in device atmosphere
|
||||
RatioLiquidNitrogenInput 178 The ratio of {GAS:LiquidNitrogen} in device's input network
|
||||
RatioLiquidNitrogenInput2 179 The ratio of {GAS:LiquidNitrogen} in device's Input2 network
|
||||
RatioLiquidNitrogenOutput 180 The ratio of {GAS:LiquidNitrogen} in device's Output network
|
||||
RatioLiquidNitrogenOutput2 181 The ratio of {GAS:LiquidNitrogen} in device's Output2 network
|
||||
RatioLiquidNitrousOxide 209 The ratio of {GAS:LiquidNitrousOxide} in device's Atmosphere
|
||||
RatioLiquidNitrousOxideInput 210 The ratio of {GAS:LiquidNitrousOxide} in device's Input Atmosphere
|
||||
RatioLiquidNitrousOxideInput2 211 The ratio of {GAS:LiquidNitrousOxide} in device's Input2 Atmosphere
|
||||
RatioLiquidNitrousOxideOutput 212 The ratio of {GAS:LiquidNitrousOxide} in device's device's Output Atmosphere
|
||||
RatioLiquidNitrousOxideOutput2 213 The ratio of {GAS:LiquidNitrousOxide} in device's Output2 Atmopshere
|
||||
RatioLiquidOxygen 183 The ratio of {GAS:LiquidOxygen} in device's Atmosphere
|
||||
RatioLiquidOxygenInput 184 The ratio of {GAS:LiquidOxygen} in device's Input Atmosphere
|
||||
RatioLiquidOxygenInput2 185 The ratio of {GAS:LiquidOxygen} in device's Input2 Atmosphere
|
||||
RatioLiquidOxygenOutput 186 The ratio of {GAS:LiquidOxygen} in device's device's Output Atmosphere
|
||||
RatioLiquidOxygenOutput2 187 The ratio of {GAS:LiquidOxygen} in device's Output2 Atmopshere
|
||||
RatioLiquidPollutant 204 The ratio of {GAS:LiquidPollutant} in device's Atmosphere
|
||||
RatioLiquidPollutantInput 205 The ratio of {GAS:LiquidPollutant} in device's Input Atmosphere
|
||||
RatioLiquidPollutantInput2 206 The ratio of {GAS:LiquidPollutant} in device's Input2 Atmosphere
|
||||
RatioLiquidPollutantOutput 207 The ratio of {GAS:LiquidPollutant} in device's device's Output Atmosphere
|
||||
RatioLiquidPollutantOutput2 208 The ratio of {GAS:LiquidPollutant} in device's Output2 Atmopshere
|
||||
RatioLiquidVolatiles 188 The ratio of {GAS:LiquidVolatiles} in device's Atmosphere
|
||||
RatioLiquidVolatilesInput 189 The ratio of {GAS:LiquidVolatiles} in device's Input Atmosphere
|
||||
RatioLiquidVolatilesInput2 190 The ratio of {GAS:LiquidVolatiles} in device's Input2 Atmosphere
|
||||
RatioLiquidVolatilesOutput 191 The ratio of {GAS:LiquidVolatiles} in device's device's Output Atmosphere
|
||||
RatioLiquidVolatilesOutput2 192 The ratio of {GAS:LiquidVolatiles} in device's Output2 Atmopshere
|
||||
RatioNitrogen 16 The ratio of nitrogen in device atmosphere
|
||||
RatioNitrogenInput 110 The ratio of nitrogen in device's input network
|
||||
RatioNitrogenInput2 120 The ratio of nitrogen in device's Input2 network
|
||||
RatioNitrogenOutput 130 The ratio of nitrogen in device's Output network
|
||||
RatioNitrogenOutput2 140 The ratio of nitrogen in device's Output2 network
|
||||
RatioNitrousOxide 83 The ratio of {GAS:NitrousOxide} in device atmosphere
|
||||
RatioNitrousOxideInput 114 The ratio of {GAS:NitrousOxide} in device's input network
|
||||
RatioNitrousOxideInput2 124 The ratio of {GAS:NitrousOxide} in device's Input2 network
|
||||
RatioNitrousOxideOutput 134 The ratio of {GAS:NitrousOxide} in device's Output network
|
||||
RatioNitrousOxideOutput2 144 The ratio of {GAS:NitrousOxide} in device's Output2 network
|
||||
RatioOxygen 14 The ratio of oxygen in device atmosphere
|
||||
RatioOxygenInput 108 The ratio of oxygen in device's input network
|
||||
RatioOxygenInput2 118 The ratio of oxygen in device's Input2 network
|
||||
RatioOxygenOutput 128 The ratio of oxygen in device's Output network
|
||||
RatioOxygenOutput2 138 The ratio of oxygen in device's Output2 network
|
||||
RatioPollutant 17 The ratio of pollutant in device atmosphere
|
||||
RatioPollutantInput 111 The ratio of pollutant in device's input network
|
||||
RatioPollutantInput2 121 The ratio of pollutant in device's Input2 network
|
||||
RatioPollutantOutput 131 The ratio of pollutant in device's Output network
|
||||
RatioPollutantOutput2 141 The ratio of pollutant in device's Output2 network
|
||||
RatioPollutedWater 254 The ratio of polluted water in device atmosphere
|
||||
RatioSteam 193 The ratio of {GAS:Steam} in device's Atmosphere
|
||||
RatioSteamInput 194 The ratio of {GAS:Steam} in device's Input Atmosphere
|
||||
RatioSteamInput2 195 The ratio of {GAS:Steam} in device's Input2 Atmosphere
|
||||
RatioSteamOutput 196 The ratio of {GAS:Steam} in device's device's Output Atmosphere
|
||||
RatioSteamOutput2 197 The ratio of {GAS:Steam} in device's Output2 Atmopshere
|
||||
RatioVolatiles 18 The ratio of volatiles in device atmosphere
|
||||
RatioVolatilesInput 112 The ratio of volatiles in device's input network
|
||||
RatioVolatilesInput2 122 The ratio of volatiles in device's Input2 network
|
||||
RatioVolatilesOutput 132 The ratio of volatiles in device's Output network
|
||||
RatioVolatilesOutput2 142 The ratio of volatiles in device's Output2 network
|
||||
RatioWater 19 The ratio of water in device atmosphere
|
||||
RatioWaterInput 113 The ratio of water in device's input network
|
||||
RatioWaterInput2 123 The ratio of water in device's Input2 network
|
||||
RatioWaterOutput 133 The ratio of water in device's Output network
|
||||
RatioWaterOutput2 143 The ratio of water in device's Output2 network
|
||||
ReEntryAltitude 237
|
||||
Reagents 13 Total number of reagents recorded by the device
|
||||
RecipeHash 41 Current hash of the recipe the device is set to produce
|
||||
ReferenceId 217
|
||||
RequestHash 60 When set to the unique identifier, requests an item of the provided type from the device
|
||||
RequiredPower 33 Idle operating power quantity, does not necessarily include extra demand power
|
||||
ReturnFuelCost 100
|
||||
Richness 263
|
||||
Rpm 155 The number of revolutions per minute that the device's spinning mechanism is doing
|
||||
SemiMajorAxis 248
|
||||
Setting 12 A variable setting that can be read or written, depending on the device
|
||||
SettingInput 91
|
||||
SettingInputHash 91 The input setting for the device
|
||||
SettingOutput 92
|
||||
SettingOutputHash 91 The output setting for the device
|
||||
SignalID 87 Returns the contact ID of the strongest signal from this Satellite
|
||||
SignalStrength 86 Returns the degree offset of the strongest contact
|
||||
Sites 260
|
||||
Size 264
|
||||
SizeX 160 Size on the X (right) axis of the object in largeGrids (a largeGrid is 2meters)
|
||||
SizeY 161 Size on the Y(Up) axis of the object in largeGrids (a largeGrid is 2meters)
|
||||
SizeZ 162 Size on the Z(Forward) axis of the object in largeGrids (a largeGrid is 2meters)
|
||||
SolarAngle 22 Solar angle of the device
|
||||
SolarIrradiance 176
|
||||
SoundAlert 175 Plays a sound alert on the devices speaker
|
||||
Stress 156 Machines get stressed when working hard. When Stress reaches 100 the machine will automatically shut down
|
||||
Survey 257
|
||||
TargetPadIndex 158 The index of the trader landing pad on this devices data network that it will try to call a trader in to land
|
||||
TargetX 88 The target position in X dimension in world coordinates
|
||||
TargetY 89 The target position in Y dimension in world coordinates
|
||||
TargetZ 90 The target position in Z dimension in world coordinates
|
||||
Temperature 6 The current temperature reading of the device
|
||||
TemperatureDifferentialEfficiency 151 How the difference between the input pipe and waste pipe temperatures effect the machines efficiency
|
||||
TemperatureExternal 73 The temperature of the outside of the device, usually the world atmosphere surrounding it
|
||||
TemperatureInput 107 The current temperature reading of the device's Input Network
|
||||
TemperatureInput2 117 The current temperature reading of the device's Input2 Network
|
||||
TemperatureOutput 127 The current temperature reading of the device's Output Network
|
||||
TemperatureOutput2 137 The current temperature reading of the device's Output2 Network
|
||||
TemperatureSetting 72 The current setting for the internal temperature of the object (e.g. the Hardsuit A/C)
|
||||
Throttle 154 Increases the rate at which the machine works (range: 0-100)
|
||||
Thrust 221 Total current thrust of all rocket engines on the rocket in Newtons.
|
||||
ThrustToWeight 223 Ratio of thrust to weight of rocket. Weight is effected by local body gravity. A rocket with a low thrust to weight will expend more fuel during launch and landing.
|
||||
Time 102 Time
|
||||
TimeToDestination 224 Estimated time in seconds until rocket arrives at target destination.
|
||||
TotalMoles 66 Returns the total moles of the device
|
||||
TotalMolesInput 115 Returns the total moles of the device's Input Network
|
||||
TotalMolesInput2 125 Returns the total moles of the device's Input2 Network
|
||||
TotalMolesOutput 135 Returns the total moles of the device's Output Network
|
||||
TotalMolesOutput2 145 Returns the total moles of the device's Output2 Network
|
||||
TotalQuantity 265
|
||||
TrueAnomaly 251
|
||||
VelocityMagnitude 79 The current magnitude of the velocity vector
|
||||
VelocityRelativeX 80 The current velocity X relative to the forward vector of this
|
||||
VelocityRelativeY 81 The current velocity Y relative to the forward vector of this
|
||||
VelocityRelativeZ 82 The current velocity Z relative to the forward vector of this
|
||||
VelocityX 231
|
||||
VelocityY 232
|
||||
VelocityZ 233
|
||||
Vertical 21 Vertical setting of the device
|
||||
VerticalRatio 35 Radio of vertical setting for device
|
||||
Volume 67 Returns the device atmosphere volume
|
||||
VolumeOfLiquid 182 The total volume of all liquids in Liters in the atmosphere
|
||||
WattsReachingContact 164 The amount of watts actually hitting the contact. This is effected by the power of the dish and how far off-axis the dish is from the contact vector
|
||||
Weight 222 Weight of Rocket in Newtons (Including fuel and cargo). Weight is effected by local body gravity.
|
||||
WorkingGasEfficiency 105 The Working Gas Efficiency reported by the machine, as a float between 0 and 1
|
||||
@@ -1,4 +0,0 @@
|
||||
Contents 0 The amount of this Reagent present in the machine
|
||||
Recipe 2 The amount of this Reagent required by the Machine's current recipe
|
||||
Required 1 The amount of this Reagent needed to complete the Machine's current recipe after subtracting the amount currently present
|
||||
TotalContents 3
|
||||
@@ -1,27 +0,0 @@
|
||||
Charge 10 returns current energy charge the slot occupant is holding
|
||||
ChargeRatio 11 returns current energy charge the slot occupant is holding as a ratio between 0 and 1 of its maximum
|
||||
Class 12 returns integer representing the class of object
|
||||
Damage 4 returns the damage state of the item in the slot
|
||||
Efficiency 5 returns the growth efficiency of the plant in the slot
|
||||
FilterType 25
|
||||
Growth 7 returns the current growth state of the plant in the slot
|
||||
Health 6 returns the health of the plant in the slot
|
||||
LineNumber 19
|
||||
Lock 23
|
||||
Mature 16 returns 1 if the plant in this slot is mature, 0 when it isn't
|
||||
MaxQuantity 15 returns the max stack size of the item in the slot
|
||||
None 0 No description
|
||||
OccupantHash 2 returns the has of the current occupant, the unique identifier of the thing
|
||||
Occupied 1 returns 0 when slot is not occupied, 1 when it is
|
||||
On 22
|
||||
Open 21
|
||||
PrefabHash 17 returns the hash of the structure in the slot
|
||||
Pressure 8 returns pressure of the slot occupants internal atmosphere
|
||||
PressureAir 14 returns pressure in the air tank of the jetpack in this slot
|
||||
PressureWaste 13 returns pressure in the waste tank of the jetpack in this slot
|
||||
Quantity 3 returns the current quantity, such as stack size, of the item in the slot
|
||||
ReferenceId 26
|
||||
Seeding 18 Whether a plant is seeding (ready to harvest seeds from). Returns 1 if seeding or 0 if not.
|
||||
SortingClass 24
|
||||
Temperature 9 returns temperature of the slot occupants internal atmosphere
|
||||
Volume 20
|
||||
@@ -210,7 +210,7 @@ def extract_data(install_path: Path, data_path: Path, language: str):
|
||||
continue
|
||||
key = key.text
|
||||
value = value.text
|
||||
if key is None:
|
||||
if key is None or any(bad in key for bad in "(){}|[]") :
|
||||
continue
|
||||
crc_u = binascii.crc32(key.encode('utf-8'))
|
||||
crc_i: int = struct.unpack("i", struct.pack("I", crc_u))[0]
|
||||
|
||||
@@ -1,994 +0,0 @@
|
||||
use crate::{
|
||||
grammar::{LogicType, ReagentMode, SlotLogicType},
|
||||
interpreter::{ICError, ICState},
|
||||
network::{CableConnectionType, Connection},
|
||||
vm::VM,
|
||||
};
|
||||
use std::{collections::BTreeMap, ops::Deref};
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::{AsRefStr, EnumIter, EnumString};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum FieldType {
|
||||
Read,
|
||||
Write,
|
||||
ReadWrite,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct LogicField {
|
||||
pub field_type: FieldType,
|
||||
pub value: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SlotOccupant {
|
||||
pub id: u32,
|
||||
pub prefab_hash: i32,
|
||||
pub quantity: u32,
|
||||
pub max_quantity: u32,
|
||||
pub sorting_class: SortingClass,
|
||||
pub damage: f64,
|
||||
fields: BTreeMap<SlotLogicType, LogicField>,
|
||||
}
|
||||
|
||||
impl SlotOccupant {
|
||||
pub fn from_template<F>(template: SlotOccupantTemplate, id_fn: F) -> Self
|
||||
where
|
||||
F: FnOnce() -> u32,
|
||||
{
|
||||
let mut fields = template.fields;
|
||||
SlotOccupant {
|
||||
id: template.id.unwrap_or_else(id_fn),
|
||||
prefab_hash: fields
|
||||
.remove(&SlotLogicType::PrefabHash)
|
||||
.map(|field| field.value as i32)
|
||||
.unwrap_or(0),
|
||||
quantity: fields
|
||||
.remove(&SlotLogicType::Quantity)
|
||||
.map(|field| field.value as u32)
|
||||
.unwrap_or(1),
|
||||
max_quantity: fields
|
||||
.remove(&SlotLogicType::MaxQuantity)
|
||||
.map(|field| field.value as u32)
|
||||
.unwrap_or(1),
|
||||
damage: fields
|
||||
.remove(&SlotLogicType::Damage)
|
||||
.map(|field| field.value)
|
||||
.unwrap_or(0.0),
|
||||
sorting_class: fields
|
||||
.remove(&SlotLogicType::SortingClass)
|
||||
.map(|field| (field.value as u32).into())
|
||||
.unwrap_or(SortingClass::Default),
|
||||
fields,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SlotOccupantTemplate {
|
||||
pub id: Option<u32>,
|
||||
pub fields: BTreeMap<SlotLogicType, LogicField>,
|
||||
}
|
||||
|
||||
impl SlotOccupant {
|
||||
pub fn new(id: u32, prefab_hash: i32) -> Self {
|
||||
SlotOccupant {
|
||||
id,
|
||||
prefab_hash,
|
||||
quantity: 1,
|
||||
max_quantity: 1,
|
||||
damage: 0.0,
|
||||
sorting_class: SortingClass::Default,
|
||||
fields: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// chainable constructor
|
||||
pub fn with_quantity(mut self, quantity: u32) -> Self {
|
||||
self.quantity = quantity;
|
||||
self
|
||||
}
|
||||
|
||||
/// chainable constructor
|
||||
pub fn with_max_quantity(mut self, max_quantity: u32) -> Self {
|
||||
self.max_quantity = max_quantity;
|
||||
self
|
||||
}
|
||||
|
||||
/// chainable constructor
|
||||
pub fn with_damage(mut self, damage: f64) -> Self {
|
||||
self.damage = damage;
|
||||
self
|
||||
}
|
||||
|
||||
/// chainable constructor
|
||||
pub fn with_fields(mut self, fields: BTreeMap<SlotLogicType, LogicField>) -> Self {
|
||||
self.fields.extend(fields);
|
||||
self
|
||||
}
|
||||
|
||||
/// chainable constructor
|
||||
pub fn get_fields(&self) -> BTreeMap<SlotLogicType, LogicField> {
|
||||
let mut copy = self.fields.clone();
|
||||
copy.insert(
|
||||
SlotLogicType::PrefabHash,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: self.prefab_hash as f64,
|
||||
},
|
||||
);
|
||||
copy.insert(
|
||||
SlotLogicType::SortingClass,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: self.sorting_class as u32 as f64,
|
||||
},
|
||||
);
|
||||
copy.insert(
|
||||
SlotLogicType::Quantity,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: self.quantity as f64,
|
||||
},
|
||||
);
|
||||
copy.insert(
|
||||
SlotLogicType::MaxQuantity,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: self.max_quantity as f64,
|
||||
},
|
||||
);
|
||||
copy.insert(
|
||||
SlotLogicType::Damage,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: self.damage,
|
||||
},
|
||||
);
|
||||
copy
|
||||
}
|
||||
|
||||
pub fn set_field(&mut self, typ: SlotLogicType, val: f64, force: bool) -> Result<(), ICError> {
|
||||
if (typ == SlotLogicType::Quantity) && force {
|
||||
self.quantity = val as u32;
|
||||
Ok(())
|
||||
} else if (typ == SlotLogicType::MaxQuantity) && force {
|
||||
self.max_quantity = val as u32;
|
||||
Ok(())
|
||||
} else if (typ == SlotLogicType::Damage) && force {
|
||||
self.damage = val;
|
||||
Ok(())
|
||||
} else if let Some(logic) = self.fields.get_mut(&typ) {
|
||||
match logic.field_type {
|
||||
FieldType::ReadWrite | FieldType::Write => {
|
||||
logic.value = val;
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
if force {
|
||||
logic.value = val;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ICError::ReadOnlyField(typ.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if force {
|
||||
self.fields.insert(
|
||||
typ,
|
||||
LogicField {
|
||||
field_type: FieldType::ReadWrite,
|
||||
value: val,
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ICError::ReadOnlyField(typ.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_logic_read(&self, field: SlotLogicType) -> bool {
|
||||
if let Some(logic) = self.fields.get(&field) {
|
||||
matches!(logic.field_type, FieldType::Read | FieldType::ReadWrite)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_logic_write(&self, field: SlotLogicType) -> bool {
|
||||
if let Some(logic) = self.fields.get(&field) {
|
||||
matches!(logic.field_type, FieldType::Write | FieldType::ReadWrite)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct Slot {
|
||||
pub typ: SlotType,
|
||||
pub occupant: Option<SlotOccupant>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct SlotTemplate {
|
||||
pub typ: SlotType,
|
||||
pub occupant: Option<SlotOccupantTemplate>,
|
||||
}
|
||||
|
||||
impl Slot {
|
||||
pub fn new(typ: SlotType) -> Self {
|
||||
Slot {
|
||||
typ,
|
||||
occupant: None,
|
||||
}
|
||||
}
|
||||
pub fn with_occupant(typ: SlotType, occupant: SlotOccupant) -> Self {
|
||||
Slot {
|
||||
typ,
|
||||
occupant: Some(occupant),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_fields(&self) -> BTreeMap<SlotLogicType, LogicField> {
|
||||
let mut copy = self
|
||||
.occupant
|
||||
.as_ref()
|
||||
.map(|occupant| occupant.get_fields())
|
||||
.unwrap_or_default();
|
||||
copy.insert(
|
||||
SlotLogicType::Occupied,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: if self.occupant.is_some() { 1.0 } else { 0.0 },
|
||||
},
|
||||
);
|
||||
copy.insert(
|
||||
SlotLogicType::OccupantHash,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: self
|
||||
.occupant
|
||||
.as_ref()
|
||||
.map(|occupant| occupant.prefab_hash as f64)
|
||||
.unwrap_or(0.0),
|
||||
},
|
||||
);
|
||||
copy.insert(
|
||||
SlotLogicType::Quantity,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: self
|
||||
.occupant
|
||||
.as_ref()
|
||||
.map(|occupant| occupant.quantity as f64)
|
||||
.unwrap_or(0.0),
|
||||
},
|
||||
);
|
||||
copy.insert(
|
||||
SlotLogicType::Damage,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: self
|
||||
.occupant
|
||||
.as_ref()
|
||||
.map(|occupant| occupant.damage)
|
||||
.unwrap_or(0.0),
|
||||
},
|
||||
);
|
||||
copy.insert(
|
||||
SlotLogicType::Class,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: self.typ as u32 as f64,
|
||||
},
|
||||
);
|
||||
copy.insert(
|
||||
SlotLogicType::MaxQuantity,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: self
|
||||
.occupant
|
||||
.as_ref()
|
||||
.map(|occupant| occupant.max_quantity as f64)
|
||||
.unwrap_or(0.0),
|
||||
},
|
||||
);
|
||||
copy.insert(
|
||||
SlotLogicType::PrefabHash,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: self
|
||||
.occupant
|
||||
.as_ref()
|
||||
.map(|occupant| occupant.prefab_hash as f64)
|
||||
.unwrap_or(0.0),
|
||||
},
|
||||
);
|
||||
copy.insert(
|
||||
SlotLogicType::SortingClass,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: self
|
||||
.occupant
|
||||
.as_ref()
|
||||
.map(|occupant| occupant.sorting_class as u32 as f64)
|
||||
.unwrap_or(0.0),
|
||||
},
|
||||
);
|
||||
copy.insert(
|
||||
SlotLogicType::ReferenceId,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: self
|
||||
.occupant
|
||||
.as_ref()
|
||||
.map(|occupant| occupant.id as f64)
|
||||
.unwrap_or(0.0),
|
||||
},
|
||||
);
|
||||
copy
|
||||
}
|
||||
|
||||
pub fn get_field(&self, field: SlotLogicType) -> f64 {
|
||||
let fields = self.get_fields();
|
||||
fields
|
||||
.get(&field)
|
||||
.map(|field| match field.field_type {
|
||||
FieldType::Read | FieldType::ReadWrite => field.value,
|
||||
_ => 0.0,
|
||||
})
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
|
||||
pub fn can_logic_read(&self, field: SlotLogicType) -> bool {
|
||||
match field {
|
||||
SlotLogicType::Pressure | SlotLogicType::Temperature | SlotLogicType::Volume => {
|
||||
matches!(
|
||||
self.typ,
|
||||
SlotType::GasCanister | SlotType::LiquidCanister | SlotType::LiquidBottle
|
||||
)
|
||||
}
|
||||
SlotLogicType::Charge | SlotLogicType::ChargeRatio => {
|
||||
matches!(self.typ, SlotType::Battery)
|
||||
}
|
||||
SlotLogicType::Open => matches!(
|
||||
self.typ,
|
||||
SlotType::Helmet | SlotType::Tool | SlotType::Appliance
|
||||
),
|
||||
SlotLogicType::Lock => matches!(self.typ, SlotType::Helmet),
|
||||
SlotLogicType::FilterType => matches!(self.typ, SlotType::GasFilter),
|
||||
_ => {
|
||||
if let Some(occupant) = self.occupant.as_ref() {
|
||||
occupant.can_logic_read(field)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_logic_write(&self, field: SlotLogicType) -> bool {
|
||||
match field {
|
||||
SlotLogicType::Open => matches!(
|
||||
self.typ,
|
||||
SlotType::Helmet
|
||||
| SlotType::GasCanister
|
||||
| SlotType::LiquidCanister
|
||||
| SlotType::LiquidBottle
|
||||
),
|
||||
SlotLogicType::On => matches!(
|
||||
self.typ,
|
||||
SlotType::Helmet | SlotType::Tool | SlotType::Appliance
|
||||
),
|
||||
SlotLogicType::Lock => matches!(self.typ, SlotType::Helmet),
|
||||
_ => {
|
||||
if let Some(occupant) = self.occupant.as_ref() {
|
||||
occupant.can_logic_write(field)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_field(&mut self, typ: SlotLogicType, val: f64, force: bool) -> Result<(), ICError> {
|
||||
if matches!(
|
||||
typ,
|
||||
SlotLogicType::Occupied
|
||||
| SlotLogicType::OccupantHash
|
||||
| SlotLogicType::Class
|
||||
| SlotLogicType::PrefabHash
|
||||
| SlotLogicType::SortingClass
|
||||
| SlotLogicType::ReferenceId
|
||||
) {
|
||||
return Err(ICError::ReadOnlyField(typ.to_string()));
|
||||
}
|
||||
if let Some(occupant) = self.occupant.as_mut() {
|
||||
occupant.set_field(typ, val, force)
|
||||
} else {
|
||||
Err(ICError::SlotNotOccupied)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
strum_macros::Display,
|
||||
EnumString,
|
||||
EnumIter,
|
||||
AsRefStr,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[strum(serialize_all = "PascalCase")]
|
||||
pub enum SortingClass {
|
||||
#[default]
|
||||
Default = 0,
|
||||
Kits = 1,
|
||||
Tools = 2,
|
||||
Resources,
|
||||
Food = 4,
|
||||
Clothing,
|
||||
Appliances,
|
||||
Atmospherics,
|
||||
Storage = 8,
|
||||
Ores,
|
||||
Ices,
|
||||
}
|
||||
|
||||
impl From<u32> for SortingClass {
|
||||
fn from(value: u32) -> Self {
|
||||
match value {
|
||||
1 => Self::Kits,
|
||||
2 => Self::Tools,
|
||||
3 => Self::Resources,
|
||||
4 => Self::Food,
|
||||
5 => Self::Clothing,
|
||||
6 => Self::Appliances,
|
||||
7 => Self::Atmospherics,
|
||||
8 => Self::Storage,
|
||||
9 => Self::Ores,
|
||||
10 => Self::Ices,
|
||||
_ => Self::Default,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
strum_macros::Display,
|
||||
EnumString,
|
||||
EnumIter,
|
||||
AsRefStr,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[strum(serialize_all = "PascalCase")]
|
||||
pub enum SlotType {
|
||||
Helmet = 1,
|
||||
Suit = 2,
|
||||
Back,
|
||||
GasFilter = 4,
|
||||
GasCanister,
|
||||
MotherBoard,
|
||||
Circuitboard,
|
||||
DataDisk = 8,
|
||||
Organ,
|
||||
Ore,
|
||||
Plant,
|
||||
Uniform,
|
||||
Entity,
|
||||
Battery,
|
||||
Egg,
|
||||
Belt = 16,
|
||||
Tool,
|
||||
Appliance,
|
||||
Ingot,
|
||||
Torpedo,
|
||||
Cartridge,
|
||||
AccessCard,
|
||||
Magazine,
|
||||
Circuit = 24,
|
||||
Bottle,
|
||||
ProgrammableChip,
|
||||
Glasses,
|
||||
CreditCard,
|
||||
DirtCanister,
|
||||
SensorProcessingUnit,
|
||||
LiquidCanister,
|
||||
LiquidBottle = 32,
|
||||
Wreckage,
|
||||
SoundCartridge,
|
||||
DrillHead,
|
||||
ScanningHead,
|
||||
Flare,
|
||||
Blocked,
|
||||
#[default]
|
||||
None = 0,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct Prefab {
|
||||
pub name: String,
|
||||
pub hash: i32,
|
||||
}
|
||||
|
||||
impl Prefab {
|
||||
pub fn new(name: &str) -> Self {
|
||||
Prefab {
|
||||
name: name.to_owned(),
|
||||
hash: const_crc32::crc32(name.as_bytes()) as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Device {
|
||||
pub id: u32,
|
||||
pub name: Option<String>,
|
||||
pub name_hash: Option<i32>,
|
||||
pub prefab: Option<Prefab>,
|
||||
pub slots: Vec<Slot>,
|
||||
pub reagents: BTreeMap<ReagentMode, BTreeMap<i32, f64>>,
|
||||
pub ic: Option<u32>,
|
||||
pub connections: Vec<Connection>,
|
||||
fields: BTreeMap<LogicType, LogicField>,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
pub fn new(id: u32) -> Self {
|
||||
Device {
|
||||
id,
|
||||
name: None,
|
||||
name_hash: None,
|
||||
prefab: None,
|
||||
fields: BTreeMap::new(),
|
||||
slots: Vec::new(),
|
||||
reagents: BTreeMap::new(),
|
||||
ic: None,
|
||||
connections: vec![Connection::CableNetwork {
|
||||
net: None,
|
||||
typ: CableConnectionType::default(),
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_ic(id: u32, ic: u32) -> Self {
|
||||
let mut device = Device::new(id);
|
||||
device.ic = Some(ic);
|
||||
device.connections = vec![
|
||||
Connection::CableNetwork {
|
||||
net: None,
|
||||
typ: CableConnectionType::Data,
|
||||
},
|
||||
Connection::CableNetwork {
|
||||
net: None,
|
||||
typ: CableConnectionType::Power,
|
||||
},
|
||||
];
|
||||
device.prefab = Some(Prefab::new("StructureCircuitHousing"));
|
||||
device.fields.extend(vec![
|
||||
(
|
||||
LogicType::Setting,
|
||||
LogicField {
|
||||
field_type: FieldType::ReadWrite,
|
||||
value: 0.0,
|
||||
},
|
||||
),
|
||||
(
|
||||
LogicType::RequiredPower,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: 0.0,
|
||||
},
|
||||
),
|
||||
(
|
||||
LogicType::PrefabHash,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: -128473777.0,
|
||||
},
|
||||
),
|
||||
]);
|
||||
let occupant = SlotOccupant::new(ic, -744098481);
|
||||
device.slots.push(Slot::with_occupant(
|
||||
SlotType::ProgrammableChip,
|
||||
// -744098481 = ItemIntegratedCircuit10
|
||||
occupant,
|
||||
));
|
||||
|
||||
device
|
||||
}
|
||||
|
||||
pub fn get_fields(&self, vm: &VM) -> BTreeMap<LogicType, LogicField> {
|
||||
let mut copy = self.fields.clone();
|
||||
if let Some(ic_id) = &self.ic {
|
||||
let ic = vm.ics.get(ic_id).expect("our own ic to exist").borrow();
|
||||
copy.insert(
|
||||
LogicType::LineNumber,
|
||||
LogicField {
|
||||
field_type: FieldType::ReadWrite,
|
||||
value: ic.ip() as f64,
|
||||
},
|
||||
);
|
||||
copy.insert(
|
||||
LogicType::Error,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: match *ic.state.borrow() {
|
||||
ICState::Error(_) => 1.0,
|
||||
_ => 0.0,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
if self.has_power_state() {
|
||||
copy.insert(
|
||||
LogicType::Power,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: if self.has_power_connection() {
|
||||
1.0
|
||||
} else {
|
||||
0.0
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
copy.insert(
|
||||
LogicType::ReferenceId,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: self.id as f64,
|
||||
},
|
||||
);
|
||||
copy
|
||||
}
|
||||
|
||||
pub fn get_network_id(&self, connection: usize) -> Result<u32, ICError> {
|
||||
if connection >= self.connections.len() {
|
||||
Err(ICError::ConnectionIndexOutOfRange(
|
||||
connection,
|
||||
self.connections.len(),
|
||||
))
|
||||
} else if let Connection::CableNetwork {
|
||||
net: network_id, ..
|
||||
} = self.connections[connection]
|
||||
{
|
||||
if let Some(network_id) = network_id {
|
||||
Ok(network_id)
|
||||
} else {
|
||||
Err(ICError::NetworkNotConnected(connection))
|
||||
}
|
||||
} else {
|
||||
Err(ICError::NotACableConnection(connection))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_logic_read(&self, field: LogicType) -> bool {
|
||||
match field {
|
||||
LogicType::ReferenceId => true,
|
||||
LogicType::LineNumber | LogicType::Error if self.ic.is_some() => true,
|
||||
LogicType::Power if self.has_power_state() => true,
|
||||
_ => {
|
||||
if let Some(logic) = self.fields.get(&field) {
|
||||
matches!(logic.field_type, FieldType::Read | FieldType::ReadWrite)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_logic_write(&self, field: LogicType) -> bool {
|
||||
match field {
|
||||
LogicType::ReferenceId => false,
|
||||
LogicType::LineNumber if self.ic.is_some() => true,
|
||||
_ => {
|
||||
if let Some(logic) = self.fields.get(&field) {
|
||||
matches!(logic.field_type, FieldType::Write | FieldType::ReadWrite)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_slot_logic_read(&self, field: SlotLogicType, slot: usize) -> bool {
|
||||
if self.slots.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let Some(slot) = self.slots.get(slot) else {
|
||||
return false;
|
||||
};
|
||||
slot.can_logic_read(field)
|
||||
}
|
||||
|
||||
pub fn can_slot_logic_write(&self, field: SlotLogicType, slot: usize) -> bool {
|
||||
if self.slots.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let Some(slot) = self.slots.get(slot) else {
|
||||
return false;
|
||||
};
|
||||
slot.can_logic_write(field)
|
||||
}
|
||||
|
||||
pub fn get_field(&self, typ: LogicType, vm: &VM) -> Result<f64, ICError> {
|
||||
if typ == LogicType::LineNumber && self.ic.is_some() {
|
||||
let ic = vm
|
||||
.ics
|
||||
.get(&self.ic.unwrap())
|
||||
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
|
||||
.borrow();
|
||||
Ok(ic.ip() as f64)
|
||||
} else if let Some(field) = self.get_fields(vm).get(&typ) {
|
||||
if field.field_type == FieldType::Read || field.field_type == FieldType::ReadWrite {
|
||||
Ok(field.value)
|
||||
} else {
|
||||
Err(ICError::WriteOnlyField(typ.to_string()))
|
||||
}
|
||||
} else {
|
||||
Err(ICError::DeviceHasNoField(typ.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_field(
|
||||
&mut self,
|
||||
typ: LogicType,
|
||||
val: f64,
|
||||
vm: &VM,
|
||||
force: bool,
|
||||
) -> Result<(), ICError> {
|
||||
if typ == LogicType::ReferenceId
|
||||
|| (typ == LogicType::Error && self.ic.is_some())
|
||||
|| (typ == LogicType::Power && self.has_power_state())
|
||||
{
|
||||
Err(ICError::ReadOnlyField(typ.to_string()))
|
||||
} else if typ == LogicType::LineNumber && self.ic.is_some() {
|
||||
let ic = vm
|
||||
.ics
|
||||
.get(&self.ic.unwrap())
|
||||
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
|
||||
.borrow();
|
||||
ic.set_ip(val as u32);
|
||||
Ok(())
|
||||
} else if let Some(field) = self.fields.get_mut(&typ) {
|
||||
if field.field_type == FieldType::Write
|
||||
|| field.field_type == FieldType::ReadWrite
|
||||
|| force
|
||||
{
|
||||
field.value = val;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ICError::ReadOnlyField(typ.to_string()))
|
||||
}
|
||||
} else if force {
|
||||
self.fields.insert(
|
||||
typ,
|
||||
LogicField {
|
||||
field_type: FieldType::ReadWrite,
|
||||
value: val,
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ICError::DeviceHasNoField(typ.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_slot_field(&self, index: f64, typ: SlotLogicType, vm: &VM) -> Result<f64, ICError> {
|
||||
let slot = self
|
||||
.slots
|
||||
.get(index as usize)
|
||||
.ok_or(ICError::SlotIndexOutOfRange(index))?;
|
||||
if slot.typ == SlotType::ProgrammableChip
|
||||
&& slot.occupant.is_some()
|
||||
&& self.ic.is_some()
|
||||
&& typ == SlotLogicType::LineNumber
|
||||
{
|
||||
let ic = vm
|
||||
.ics
|
||||
.get(&self.ic.unwrap())
|
||||
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
|
||||
.borrow();
|
||||
Ok(ic.ip() as f64)
|
||||
} else {
|
||||
Ok(slot.get_field(typ))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_slot_fields(
|
||||
&self,
|
||||
index: f64,
|
||||
vm: &VM,
|
||||
) -> Result<BTreeMap<SlotLogicType, LogicField>, ICError> {
|
||||
let slot = self
|
||||
.slots
|
||||
.get(index as usize)
|
||||
.ok_or(ICError::SlotIndexOutOfRange(index))?;
|
||||
let mut fields = slot.get_fields();
|
||||
if slot.typ == SlotType::ProgrammableChip && slot.occupant.is_some() && self.ic.is_some() {
|
||||
let ic = vm
|
||||
.ics
|
||||
.get(&self.ic.unwrap())
|
||||
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
|
||||
.borrow();
|
||||
fields.insert(
|
||||
SlotLogicType::LineNumber,
|
||||
LogicField {
|
||||
field_type: FieldType::ReadWrite,
|
||||
value: ic.ip() as f64,
|
||||
},
|
||||
);
|
||||
}
|
||||
Ok(fields)
|
||||
}
|
||||
|
||||
pub fn set_slot_field(
|
||||
&mut self,
|
||||
index: f64,
|
||||
typ: SlotLogicType,
|
||||
val: f64,
|
||||
_vm: &VM,
|
||||
force: bool,
|
||||
) -> Result<(), ICError> {
|
||||
let slot = self
|
||||
.slots
|
||||
.get_mut(index as usize)
|
||||
.ok_or(ICError::SlotIndexOutOfRange(index))?;
|
||||
slot.set_field(typ, val, force)
|
||||
}
|
||||
|
||||
pub fn get_slot(&self, index: f64) -> Result<&Slot, ICError> {
|
||||
self.slots
|
||||
.get(index as usize)
|
||||
.ok_or(ICError::SlotIndexOutOfRange(index))
|
||||
}
|
||||
|
||||
pub fn get_reagent(&self, rm: &ReagentMode, reagent: f64) -> f64 {
|
||||
if let Some(mode) = self.reagents.get(rm) {
|
||||
if let Some(val) = mode.get(&(reagent as i32)) {
|
||||
return *val;
|
||||
}
|
||||
}
|
||||
0.0
|
||||
}
|
||||
|
||||
pub fn set_name(&mut self, name: &str) {
|
||||
self.name_hash = Some(const_crc32::crc32(name.as_bytes()) as i32);
|
||||
self.name = Some(name.to_owned());
|
||||
}
|
||||
|
||||
pub fn has_power_state(&self) -> bool {
|
||||
self.connections.iter().any(|conn| {
|
||||
matches!(
|
||||
conn,
|
||||
Connection::CableNetwork {
|
||||
typ: CableConnectionType::Power | CableConnectionType::PowerAndData,
|
||||
..
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn has_power_connection(&self) -> bool {
|
||||
self.connections.iter().any(|conn| {
|
||||
matches!(
|
||||
conn,
|
||||
Connection::CableNetwork {
|
||||
net: Some(_),
|
||||
typ: CableConnectionType::Power | CableConnectionType::PowerAndData,
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct DeviceTemplate {
|
||||
pub id: Option<u32>,
|
||||
pub name: Option<String>,
|
||||
pub prefab_name: Option<String>,
|
||||
pub slots: Vec<SlotTemplate>,
|
||||
// pub reagents: BTreeMap<ReagentMode, BTreeMap<i32, f64>>,
|
||||
pub connections: Vec<Connection>,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
/// create a devive from a template and return the device, does not create it's own IC
|
||||
pub fn from_template<F>(template: DeviceTemplate, mut id_fn: F) -> Self
|
||||
where
|
||||
F: FnMut() -> u32,
|
||||
{
|
||||
// id_fn *must* be captured not moved
|
||||
#[allow(clippy::redundant_closure)]
|
||||
let device_id = template.id.unwrap_or_else(|| id_fn());
|
||||
let name_hash = template
|
||||
.name
|
||||
.as_ref()
|
||||
.map(|name| const_crc32::crc32(name.as_bytes()) as i32);
|
||||
|
||||
#[allow(clippy::redundant_closure)]
|
||||
let slots = template
|
||||
.slots
|
||||
.into_iter()
|
||||
.map(|slot| Slot {
|
||||
typ: slot.typ,
|
||||
occupant: slot
|
||||
.occupant
|
||||
.map(|occupant| SlotOccupant::from_template(occupant, || id_fn())),
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
let ic = slots
|
||||
.iter()
|
||||
.find_map(|slot| {
|
||||
if slot.typ == SlotType::ProgrammableChip && slot.occupant.is_some() {
|
||||
Some(slot.occupant.clone()).flatten()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|occupant| occupant.id);
|
||||
|
||||
let fields = template.fields;
|
||||
|
||||
Device {
|
||||
id: device_id,
|
||||
name: template.name,
|
||||
name_hash,
|
||||
prefab: template.prefab_name.map(|name| Prefab::new(&name)),
|
||||
slots,
|
||||
// reagents: template.reagents,
|
||||
reagents: BTreeMap::new(),
|
||||
ic,
|
||||
connections: template.connections,
|
||||
fields,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for DeviceTemplate
|
||||
where
|
||||
T: Deref<Target = Device>,
|
||||
{
|
||||
fn from(device: T) -> Self {
|
||||
DeviceTemplate {
|
||||
id: Some(device.id),
|
||||
name: device.name.clone(),
|
||||
prefab_name: device.prefab.as_ref().map(|prefab| prefab.name.clone()),
|
||||
slots: device
|
||||
.slots
|
||||
.iter()
|
||||
.map(|slot| SlotTemplate {
|
||||
typ: slot.typ,
|
||||
occupant: slot.occupant.as_ref().map(|occupant| SlotOccupantTemplate {
|
||||
id: Some(occupant.id),
|
||||
fields: occupant.get_fields(),
|
||||
}),
|
||||
})
|
||||
.collect_vec(),
|
||||
connections: device.connections.clone(),
|
||||
fields: device.fields.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
297
ic10emu/src/errors.rs
Normal file
@@ -0,0 +1,297 @@
|
||||
use crate::vm::{
|
||||
instructions::enums::InstructionOp,
|
||||
object::{
|
||||
errors::{LogicError, MemoryError},
|
||||
templates::Prefab,
|
||||
ObjectID,
|
||||
},
|
||||
};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use stationeers_data::templates::ObjectTemplate;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt::Display;
|
||||
use thiserror::Error;
|
||||
#[cfg(feature = "tsify")]
|
||||
use tsify::Tsify;
|
||||
#[cfg(feature = "tsify")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[derive(Error, Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum VMError {
|
||||
#[error("device with id '{0}' does not exist")]
|
||||
UnknownId(ObjectID),
|
||||
#[error("ic with id '{0}' does not exist")]
|
||||
UnknownIcId(ObjectID),
|
||||
#[error("ic encountered an error: {0}")]
|
||||
ICError(#[from] ICError),
|
||||
#[error("ic encountered an error: {0}")]
|
||||
LineError(#[from] LineError),
|
||||
#[error("invalid network id {0}")]
|
||||
InvalidNetwork(ObjectID),
|
||||
#[error("device {0} not visible to device {1} (not on the same networks)")]
|
||||
DeviceNotVisible(u32, u32),
|
||||
#[error("a device with id {0} already exists")]
|
||||
IdInUse(u32),
|
||||
#[error("device(s) with ids {0:?} already exist")]
|
||||
IdsInUse(Vec<u32>),
|
||||
#[error("attempt to use a set of id's with duplicates: id(s) {0:?} exist more than once")]
|
||||
DuplicateIds(Vec<u32>),
|
||||
#[error("object {0} is not a device")]
|
||||
NotADevice(ObjectID),
|
||||
#[error("device object {0} has no pins")]
|
||||
NoDevicePins(ObjectID),
|
||||
#[error("object {0} has no slots")]
|
||||
NotStorage(ObjectID),
|
||||
#[error("object {0} is not an item")]
|
||||
NotAnItem(ObjectID),
|
||||
#[error("object {0} is not programmable")]
|
||||
NotProgrammable(ObjectID),
|
||||
#[error("object {0} is not memory writable")]
|
||||
NotMemoryWritable(ObjectID),
|
||||
#[error("object {0} is not a circuit holder or programmable")]
|
||||
NotCircuitHolderOrProgrammable(ObjectID),
|
||||
#[error("object {0} is not a circuit holder or memory writable")]
|
||||
NotCircuitHolderOrMemoryWritable(ObjectID),
|
||||
#[error("object {0} is a circuit holder but there is no programmable ic present")]
|
||||
NoIC(ObjectID),
|
||||
#[error("{0}")]
|
||||
TemplateError(#[from] TemplateError),
|
||||
#[error("missing child object {0}")]
|
||||
MissingChild(ObjectID),
|
||||
#[error("object {0} is not parentable")]
|
||||
NotParentable(ObjectID),
|
||||
#[error("object {0} is not logicable")]
|
||||
NotLogicable(ObjectID),
|
||||
#[error("network object {0} is not a network")]
|
||||
NonNetworkNetwork(ObjectID),
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum TemplateError {
|
||||
#[error("object id {0} has a non conforming set of interfaces")]
|
||||
NonConformingObject(ObjectID),
|
||||
#[error("object id {0} is missing from the VM")]
|
||||
MissingVMObject(ObjectID),
|
||||
#[error("database has no template for prefab {0}")]
|
||||
NoTemplateForPrefab(Prefab),
|
||||
#[error("no prefab provided")]
|
||||
MissingPrefab,
|
||||
#[error("incorrect template for concrete impl {0} from prefab {1}: {2:?}")]
|
||||
IncorrectTemplate(String, Prefab, ObjectTemplate),
|
||||
#[error("frozen memory size error: {0} is not {1}")]
|
||||
MemorySize(usize, usize),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct LineError {
|
||||
pub error: ICError,
|
||||
pub line: u32,
|
||||
pub msg: String,
|
||||
}
|
||||
|
||||
impl Display for LineError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Error on line {}: {}", self.line, self.error)
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for LineError {}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct ParseError {
|
||||
pub line: usize,
|
||||
pub start: usize,
|
||||
pub end: usize,
|
||||
pub msg: String,
|
||||
}
|
||||
|
||||
impl Display for ParseError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{} at line {} {}:{}",
|
||||
self.msg, self.line, self.start, self.end
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for ParseError {}
|
||||
|
||||
impl ParseError {
|
||||
/// Offset the ParseError in it's line, adding the passed values to it's `start` and `end`
|
||||
#[must_use]
|
||||
pub fn offset(self, offset: usize) -> Self {
|
||||
ParseError {
|
||||
start: self.start + offset,
|
||||
end: self.end + offset,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Offset the ParseError line, adding the passed value to it's `line`
|
||||
#[must_use]
|
||||
pub fn offset_line(self, offset: usize) -> Self {
|
||||
ParseError {
|
||||
line: self.line + offset,
|
||||
start: self.start,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Mark the parse error as extending 'length' bytes from `start`
|
||||
#[must_use]
|
||||
pub fn span(self, length: usize) -> Self {
|
||||
ParseError {
|
||||
start: self.start,
|
||||
end: self.start + length,
|
||||
..self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "typ")]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum ICError {
|
||||
#[error("error compiling code: {0}")]
|
||||
ParseError(#[from] ParseError),
|
||||
#[error("{0}")]
|
||||
LogicError(#[from] LogicError),
|
||||
#[error("{0}")]
|
||||
MemoryError(#[from] MemoryError),
|
||||
#[error("duplicate label {label}: first encountered on line {source_line}")]
|
||||
DuplicateLabel {
|
||||
label: String,
|
||||
line: u32,
|
||||
source_line: u32,
|
||||
},
|
||||
#[error("instruction pointer out of range: '{0}'")]
|
||||
InstructionPointerOutOfRange(usize),
|
||||
#[error("register pointer out of range: '{0}'")]
|
||||
RegisterIndexOutOfRange(f64),
|
||||
#[error("device pointer out of range: '{0}'")]
|
||||
DeviceIndexOutOfRange(f64),
|
||||
#[error("stack index out of range: '{0}'")]
|
||||
StackIndexOutOfRange(f64),
|
||||
#[error("slot index out of range: '{0}'")]
|
||||
SlotIndexOutOfRange(f64),
|
||||
#[error("pin index {0} out of range 0-6")]
|
||||
PinIndexOutOfRange(usize),
|
||||
#[error("connection index {index} out of range {range}")]
|
||||
ConnectionIndexOutOfRange { index: usize, range: usize },
|
||||
#[error("unknown device ID '{0}'")]
|
||||
UnknownDeviceID(f64),
|
||||
#[error("too few operands!: provide: '{provided}', desired: '{desired}'")]
|
||||
TooFewOperands { provided: u32, desired: u32 },
|
||||
#[error("too many operands!: provide: '{provided}', desired: '{desired}'")]
|
||||
TooManyOperands { provided: u32, desired: u32 },
|
||||
#[error("incorrect operand type for instruction `{inst}` operand {index}, not a {desired} ")]
|
||||
IncorrectOperandType {
|
||||
inst: InstructionOp,
|
||||
index: usize,
|
||||
desired: String,
|
||||
},
|
||||
#[error("unknown identifier {0}")]
|
||||
UnknownIdentifier(String),
|
||||
#[error("device Not Set")]
|
||||
DeviceNotSet,
|
||||
#[error("shift Underflow i64(signed long)")]
|
||||
ShiftUnderflowI64,
|
||||
#[error("shift Overflow i64(signed long)")]
|
||||
ShiftOverflowI64,
|
||||
#[error("shift underflow i32(signed int)")]
|
||||
ShiftUnderflowI32,
|
||||
#[error("shift overflow i32(signed int)")]
|
||||
ShiftOverflowI32,
|
||||
#[error("duplicate define '{0}'")]
|
||||
DuplicateDefine(String),
|
||||
#[error("read only field '{0}'")]
|
||||
ReadOnlyField(String),
|
||||
#[error("write only field '{0}'")]
|
||||
WriteOnlyField(String),
|
||||
#[error("device has no field '{0}'")]
|
||||
DeviceHasNoField(String),
|
||||
#[error("device has no ic")]
|
||||
DeviceHasNoIC,
|
||||
#[error("unknown device '{0}'")]
|
||||
UnknownDeviceId(f64),
|
||||
#[error("unknown logic type '{0}'")]
|
||||
UnknownLogicType(f64),
|
||||
#[error("unknown slot logic type '{0}'")]
|
||||
UnknownLogicSlotType(f64),
|
||||
#[error("unknown batch mode '{0}'")]
|
||||
UnknownBatchMode(f64),
|
||||
#[error("unknown reagent mode '{0}'")]
|
||||
UnknownReagentMode(f64),
|
||||
#[error("type value not known")]
|
||||
TypeValueNotKnown,
|
||||
#[error("empty device list")]
|
||||
EmptyDeviceList,
|
||||
#[error("connection specifier missing")]
|
||||
MissingConnectionSpecifier,
|
||||
#[error("no data network on connection '{0}'")]
|
||||
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),
|
||||
#[error("slot has no occupant")]
|
||||
SlotNotOccupied,
|
||||
#[error("generated Enum {0} has no value attached. Report this error.")]
|
||||
NoGeneratedValue(String),
|
||||
#[error(
|
||||
"generated Enum {enum_name}'s value does not parse as {parse_type} . Report this error."
|
||||
)]
|
||||
BadGeneratedValueParse {
|
||||
enum_name: String,
|
||||
parse_type: String,
|
||||
},
|
||||
#[error("IC with id {0} is not slotted into a circuit holder")]
|
||||
NoCircuitHolder(ObjectID),
|
||||
#[error("IC with id {0} is slotted into a circuit holder with no logic interface?")]
|
||||
CircuitHolderNotLogicable(ObjectID),
|
||||
#[error("object {0} is not slot writeable")]
|
||||
NotSlotWriteable(ObjectID),
|
||||
#[error("object {0} does not use reagents ")]
|
||||
NotReagentReadable(ObjectID),
|
||||
#[error("object {0} is not slot logicable")]
|
||||
NotLogicable(ObjectID),
|
||||
#[error("{0} is not a valid number of sleep seconds")]
|
||||
SleepDurationError(f64),
|
||||
#[error("{duration} can not be added to {time} ")]
|
||||
SleepAdditionError {
|
||||
duration: time::Duration,
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Date"))]
|
||||
time: time::OffsetDateTime,
|
||||
},
|
||||
}
|
||||
|
||||
impl ICError {
|
||||
pub const fn too_few_operands(provided: usize, desired: u32) -> Self {
|
||||
ICError::TooFewOperands {
|
||||
provided: provided as u32,
|
||||
desired,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn too_many_operands(provided: usize, desired: u32) -> Self {
|
||||
ICError::TooManyOperands {
|
||||
provided: provided as u32,
|
||||
desired,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn mismatch_operands(provided: usize, desired: u32) -> Self {
|
||||
if provided < desired as usize {
|
||||
ICError::too_few_operands(provided, desired)
|
||||
} else {
|
||||
ICError::too_many_operands(provided, desired)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,144 +1,19 @@
|
||||
use crate::interpreter::{self, ICError};
|
||||
use crate::tokens::{SplitConsecutiveIndicesExt, SplitConsecutiveWithIndices};
|
||||
use crate::{
|
||||
errors::ParseError,
|
||||
interpreter,
|
||||
tokens::{SplitConsecutiveIndicesExt, SplitConsecutiveWithIndices},
|
||||
vm::instructions::{
|
||||
enums::InstructionOp,
|
||||
operands::{Device, DeviceSpec, Identifier, Number, Operand, RegisterSpec},
|
||||
Instruction, CONSTANTS_LOOKUP,
|
||||
},
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use std::error::Error;
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
use strum::EnumProperty;
|
||||
|
||||
pub mod generated {
|
||||
use super::ParseError;
|
||||
use crate::interpreter::ICError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::str::FromStr;
|
||||
use strum::AsRefStr;
|
||||
use strum::Display;
|
||||
use strum::EnumIter;
|
||||
use strum::EnumProperty;
|
||||
use strum::EnumString;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/instructions.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/logictypes.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/modes.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/constants.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/enums.rs"));
|
||||
|
||||
impl TryFrom<f64> for LogicType {
|
||||
type Error = ICError;
|
||||
fn try_from(value: f64) -> Result<Self, <LogicType as TryFrom<f64>>::Error> {
|
||||
if let Some(lt) = LogicType::iter().find(|lt| {
|
||||
lt.get_str("value")
|
||||
.map(|val| val.parse::<u16>().unwrap() as f64 == value)
|
||||
.unwrap_or(false)
|
||||
}) {
|
||||
Ok(lt)
|
||||
} else {
|
||||
Err(crate::interpreter::ICError::UnknownLogicType(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<f64> for SlotLogicType {
|
||||
type Error = ICError;
|
||||
fn try_from(value: f64) -> Result<Self, <SlotLogicType as TryFrom<f64>>::Error> {
|
||||
if let Some(slt) = SlotLogicType::iter().find(|lt| {
|
||||
lt.get_str("value")
|
||||
.map(|val| val.parse::<u8>().unwrap() as f64 == value)
|
||||
.unwrap_or(false)
|
||||
}) {
|
||||
Ok(slt)
|
||||
} else {
|
||||
Err(crate::interpreter::ICError::UnknownSlotLogicType(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<f64> for BatchMode {
|
||||
type Error = ICError;
|
||||
fn try_from(value: f64) -> Result<Self, <BatchMode as TryFrom<f64>>::Error> {
|
||||
if let Some(bm) = BatchMode::iter().find(|lt| {
|
||||
lt.get_str("value")
|
||||
.map(|val| val.parse::<u8>().unwrap() as f64 == value)
|
||||
.unwrap_or(false)
|
||||
}) {
|
||||
Ok(bm)
|
||||
} else {
|
||||
Err(crate::interpreter::ICError::UnknownBatchMode(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<f64> for ReagentMode {
|
||||
type Error = ICError;
|
||||
fn try_from(value: f64) -> Result<Self, <ReagentMode as TryFrom<f64>>::Error> {
|
||||
if let Some(rm) = ReagentMode::iter().find(|lt| {
|
||||
lt.get_str("value")
|
||||
.map(|val| val.parse::<u8>().unwrap() as f64 == value)
|
||||
.unwrap_or(false)
|
||||
}) {
|
||||
Ok(rm)
|
||||
} else {
|
||||
Err(crate::interpreter::ICError::UnknownReagentMode(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub use generated::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct ParseError {
|
||||
pub line: usize,
|
||||
pub start: usize,
|
||||
pub end: usize,
|
||||
pub msg: String,
|
||||
}
|
||||
|
||||
impl Display for ParseError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{} at line {} {}:{}",
|
||||
self.msg, self.line, self.start, self.end
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for ParseError {}
|
||||
|
||||
impl ParseError {
|
||||
/// Offset the ParseError in it's line, adding the passed values to it's `start` and `end`
|
||||
#[must_use]
|
||||
pub fn offset(self, offset: usize) -> Self {
|
||||
ParseError {
|
||||
start: self.start + offset,
|
||||
end: self.end + offset,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Offset the ParseError line, adding the passed value to it's `line`
|
||||
#[must_use]
|
||||
pub fn offset_line(self, offset: usize) -> Self {
|
||||
ParseError {
|
||||
line: self.line + offset,
|
||||
start: self.start,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Mark the parse error as extending 'length' bytes from `start`
|
||||
#[must_use]
|
||||
pub fn span(self, length: usize) -> Self {
|
||||
ParseError {
|
||||
start: self.start,
|
||||
end: self.start + length,
|
||||
..self
|
||||
}
|
||||
}
|
||||
}
|
||||
use stationeers_data::enums::{
|
||||
basic::BasicEnum,
|
||||
script::{LogicBatchMethod, LogicReagentMode, LogicSlotType, LogicType},
|
||||
};
|
||||
use std::{fmt::Display, str::FromStr};
|
||||
|
||||
pub fn parse(code: &str) -> Result<Vec<Line>, ParseError> {
|
||||
code.lines()
|
||||
@@ -148,7 +23,7 @@ pub fn parse(code: &str) -> Result<Vec<Line>, ParseError> {
|
||||
}
|
||||
|
||||
/// Like `parse` but can return Code::Invalid for some lines
|
||||
pub fn parse_with_invlaid(code: &str) -> Vec<Line> {
|
||||
pub fn parse_with_invalid(code: &str) -> Vec<Line> {
|
||||
code.lines()
|
||||
.enumerate()
|
||||
.map(|(n, l)| Line::from_str_with_invalid(n, l))
|
||||
@@ -249,12 +124,6 @@ impl FromStr for Comment {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Instruction {
|
||||
pub instruction: InstructionOp,
|
||||
pub operands: Vec<Operand>,
|
||||
}
|
||||
|
||||
impl FromStr for Instruction {
|
||||
type Err = ParseError;
|
||||
/// parse a non-empty string for an instruction and it's operands
|
||||
@@ -262,9 +131,16 @@ impl FromStr for Instruction {
|
||||
let mut tokens_iter = s.split_consecutive_with_indices(&[' ', '\t'][..]);
|
||||
let instruction: InstructionOp = {
|
||||
if let Some((index, token)) = tokens_iter.next() {
|
||||
token
|
||||
.parse::<InstructionOp>()
|
||||
.map_err(|e| e.offset(index).span(token.len()))
|
||||
token.parse::<InstructionOp>().map_err(|_e| {
|
||||
ParseError {
|
||||
line: 0,
|
||||
start: 0,
|
||||
end: 0,
|
||||
msg: format!("unknown instruction '{token}'"),
|
||||
}
|
||||
.offset(index)
|
||||
.span(token.len())
|
||||
})
|
||||
} else {
|
||||
Err(ParseError {
|
||||
line: 0,
|
||||
@@ -323,290 +199,6 @@ fn get_operand_tokens<'a>(
|
||||
operand_tokens
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum Device {
|
||||
Db,
|
||||
Numbered(u32),
|
||||
Indirect { indirection: u32, target: u32 },
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RegisterSpec {
|
||||
pub indirection: u32,
|
||||
pub target: u32,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DeviceSpec {
|
||||
pub device: Device,
|
||||
pub connection: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum Operand {
|
||||
RegisterSpec(RegisterSpec),
|
||||
DeviceSpec(DeviceSpec),
|
||||
Number(Number),
|
||||
Type {
|
||||
logic_type: Option<LogicType>,
|
||||
slot_logic_type: Option<SlotLogicType>,
|
||||
batch_mode: Option<BatchMode>,
|
||||
reagent_mode: Option<ReagentMode>,
|
||||
identifier: Identifier,
|
||||
},
|
||||
Identifier(Identifier),
|
||||
}
|
||||
|
||||
impl Operand {
|
||||
pub fn as_value(
|
||||
&self,
|
||||
ic: &interpreter::IC,
|
||||
inst: InstructionOp,
|
||||
index: u32,
|
||||
) -> Result<f64, interpreter::ICError> {
|
||||
match self.translate_alias(ic) {
|
||||
Operand::RegisterSpec(RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
}) => ic.get_register(indirection, target),
|
||||
Operand::Number(num) => Ok(num.value()),
|
||||
Operand::Type {
|
||||
logic_type,
|
||||
slot_logic_type,
|
||||
batch_mode,
|
||||
reagent_mode,
|
||||
identifier: _,
|
||||
} => {
|
||||
if let Some(lt) = logic_type {
|
||||
Ok(lt
|
||||
.get_str("value")
|
||||
.ok_or_else(|| ICError::NoGeneratedValue(lt.to_string()))?
|
||||
.parse::<u16>()
|
||||
.map_err(|_| {
|
||||
ICError::BadGeneratedValueParse(lt.to_string(), "u16".to_owned())
|
||||
})? as f64)
|
||||
} else if let Some(slt) = slot_logic_type {
|
||||
Ok(slt
|
||||
.get_str("value")
|
||||
.ok_or_else(|| ICError::NoGeneratedValue(slt.to_string()))?
|
||||
.parse::<u8>()
|
||||
.map_err(|_| {
|
||||
ICError::BadGeneratedValueParse(slt.to_string(), "u8".to_owned())
|
||||
})? as f64)
|
||||
} else if let Some(bm) = batch_mode {
|
||||
Ok(bm
|
||||
.get_str("value")
|
||||
.ok_or_else(|| ICError::NoGeneratedValue(bm.to_string()))?
|
||||
.parse::<u8>()
|
||||
.map_err(|_| {
|
||||
ICError::BadGeneratedValueParse(bm.to_string(), "u8".to_owned())
|
||||
})? as f64)
|
||||
} else if let Some(rm) = reagent_mode {
|
||||
Ok(rm
|
||||
.get_str("value")
|
||||
.ok_or_else(|| ICError::NoGeneratedValue(rm.to_string()))?
|
||||
.parse::<u8>()
|
||||
.map_err(|_| {
|
||||
ICError::BadGeneratedValueParse(rm.to_string(), "u8".to_owned())
|
||||
})? as f64)
|
||||
} else {
|
||||
Err(interpreter::ICError::TypeValueNotKnown)
|
||||
}
|
||||
}
|
||||
Operand::Identifier(id) => {
|
||||
Err(interpreter::ICError::UnknownIdentifier(id.name.to_string()))
|
||||
}
|
||||
Operand::DeviceSpec { .. } => Err(interpreter::ICError::IncorrectOperandType {
|
||||
inst,
|
||||
index,
|
||||
desired: "Value".to_owned(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_value_i64(
|
||||
&self,
|
||||
ic: &interpreter::IC,
|
||||
signed: bool,
|
||||
inst: InstructionOp,
|
||||
index: u32,
|
||||
) -> Result<i64, interpreter::ICError> {
|
||||
match self {
|
||||
Self::Number(num) => Ok(num.value_i64(signed)),
|
||||
_ => {
|
||||
let val = self.as_value(ic, inst, index)?;
|
||||
if val < -9.223_372_036_854_776E18 {
|
||||
Err(interpreter::ICError::ShiftUnderflowI64)
|
||||
} else if val <= 9.223_372_036_854_776E18 {
|
||||
Ok(interpreter::f64_to_i64(val, signed))
|
||||
} else {
|
||||
Err(interpreter::ICError::ShiftOverflowI64)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn as_value_i32(
|
||||
&self,
|
||||
ic: &interpreter::IC,
|
||||
signed: bool,
|
||||
inst: InstructionOp,
|
||||
index: u32,
|
||||
) -> Result<i32, interpreter::ICError> {
|
||||
match self {
|
||||
Self::Number(num) => Ok(num.value_i64(signed) as i32),
|
||||
_ => {
|
||||
let val = self.as_value(ic, inst, index)?;
|
||||
if val < -2147483648.0 {
|
||||
Err(interpreter::ICError::ShiftUnderflowI32)
|
||||
} else if val <= 2147483647.0 {
|
||||
Ok(val as i32)
|
||||
} else {
|
||||
Err(interpreter::ICError::ShiftOverflowI32)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_register(
|
||||
&self,
|
||||
ic: &interpreter::IC,
|
||||
inst: InstructionOp,
|
||||
index: u32,
|
||||
) -> Result<RegisterSpec, interpreter::ICError> {
|
||||
match self.translate_alias(ic) {
|
||||
Operand::RegisterSpec(reg) => Ok(reg),
|
||||
Operand::Identifier(id) => {
|
||||
Err(interpreter::ICError::UnknownIdentifier(id.name.to_string()))
|
||||
}
|
||||
_ => Err(interpreter::ICError::IncorrectOperandType {
|
||||
inst,
|
||||
index,
|
||||
desired: "Register".to_owned(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_device(
|
||||
&self,
|
||||
ic: &interpreter::IC,
|
||||
inst: InstructionOp,
|
||||
index: u32,
|
||||
) -> 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)),
|
||||
Device::Numbered(p) => {
|
||||
let dp = ic
|
||||
.pins
|
||||
.borrow()
|
||||
.get(p as usize)
|
||||
.ok_or(interpreter::ICError::DeviceIndexOutOfRange(p as f64))
|
||||
.copied()?;
|
||||
Ok((dp, connection))
|
||||
}
|
||||
Device::Indirect {
|
||||
indirection,
|
||||
target,
|
||||
} => {
|
||||
let val = ic.get_register(indirection, target)?;
|
||||
let dp = ic
|
||||
.pins
|
||||
.borrow()
|
||||
.get(val as usize)
|
||||
.ok_or(interpreter::ICError::DeviceIndexOutOfRange(val))
|
||||
.copied()?;
|
||||
Ok((dp, connection))
|
||||
}
|
||||
},
|
||||
Operand::Identifier(id) => {
|
||||
Err(interpreter::ICError::UnknownIdentifier(id.name.to_string()))
|
||||
}
|
||||
_ => Err(interpreter::ICError::IncorrectOperandType {
|
||||
inst,
|
||||
index,
|
||||
desired: "Value".to_owned(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_logic_type(
|
||||
&self,
|
||||
ic: &interpreter::IC,
|
||||
inst: InstructionOp,
|
||||
index: u32,
|
||||
) -> Result<LogicType, ICError> {
|
||||
match &self {
|
||||
Operand::Type {
|
||||
logic_type: Some(lt),
|
||||
..
|
||||
} => Ok(*lt),
|
||||
_ => LogicType::try_from(self.as_value(ic, inst, index)?),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_slot_logic_type(
|
||||
&self,
|
||||
ic: &interpreter::IC,
|
||||
inst: InstructionOp,
|
||||
index: u32,
|
||||
) -> Result<SlotLogicType, ICError> {
|
||||
match &self {
|
||||
Operand::Type {
|
||||
slot_logic_type: Some(slt),
|
||||
..
|
||||
} => Ok(*slt),
|
||||
_ => SlotLogicType::try_from(self.as_value(ic, inst, index)?),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_batch_mode(
|
||||
&self,
|
||||
ic: &interpreter::IC,
|
||||
inst: InstructionOp,
|
||||
index: u32,
|
||||
) -> Result<BatchMode, ICError> {
|
||||
match &self {
|
||||
Operand::Type {
|
||||
batch_mode: Some(bm),
|
||||
..
|
||||
} => Ok(*bm),
|
||||
_ => BatchMode::try_from(self.as_value(ic, inst, index)?),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_reagent_mode(
|
||||
&self,
|
||||
ic: &interpreter::IC,
|
||||
inst: InstructionOp,
|
||||
index: u32,
|
||||
) -> Result<ReagentMode, ICError> {
|
||||
match &self {
|
||||
Operand::Type {
|
||||
reagent_mode: Some(rm),
|
||||
..
|
||||
} => Ok(*rm),
|
||||
_ => ReagentMode::try_from(self.as_value(ic, inst, index)?),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn translate_alias(&self, ic: &interpreter::IC) -> Self {
|
||||
match &self {
|
||||
Operand::Identifier(id) | Operand::Type { identifier: id, .. } => {
|
||||
if let Some(alias) = ic.aliases.borrow().get(&id.name) {
|
||||
alias.clone()
|
||||
} else if let Some(define) = ic.defines.borrow().get(&id.name) {
|
||||
Operand::Number(Number::Float(*define))
|
||||
} else if let Some(label) = ic.program.borrow().labels.get(&id.name) {
|
||||
Operand::Number(Number::Float(*label as f64))
|
||||
} else {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
_ => self.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Operand {
|
||||
type Err = ParseError;
|
||||
/// Parse a str containing an single instruction operand
|
||||
@@ -877,15 +469,13 @@ impl FromStr for Operand {
|
||||
}
|
||||
} else if let Some(val) = CONSTANTS_LOOKUP.get(s) {
|
||||
Ok(Operand::Number(Number::Constant(*val)))
|
||||
} else if let Ok(val) = LogicEnums::from_str(s) {
|
||||
Ok(Operand::Number(Number::Enum(
|
||||
val.get_str("value").unwrap().parse().unwrap(),
|
||||
)))
|
||||
} else if let Ok(val) = BasicEnum::from_str(s) {
|
||||
Ok(Operand::Number(Number::Enum(val.get_value() as f64)))
|
||||
} else {
|
||||
let lt = LogicType::from_str(s).ok();
|
||||
let slt = SlotLogicType::from_str(s).ok();
|
||||
let bm = BatchMode::from_str(s).ok();
|
||||
let rm = ReagentMode::from_str(s).ok();
|
||||
let slt = LogicSlotType::from_str(s).ok();
|
||||
let bm = LogicBatchMethod::from_str(s).ok();
|
||||
let rm = LogicReagentMode::from_str(s).ok();
|
||||
let identifier = Identifier::from_str(s)?;
|
||||
if lt.is_some() || slt.is_some() || bm.is_some() || rm.is_some() {
|
||||
Ok(Operand::Type {
|
||||
@@ -1010,11 +600,6 @@ impl FromStr for Label {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Identifier {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl FromStr for Identifier {
|
||||
type Err = ParseError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
@@ -1060,16 +645,6 @@ impl Display for Identifier {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum Number {
|
||||
Float(f64),
|
||||
Binary(i64),
|
||||
Hexadecimal(i64),
|
||||
Constant(f64),
|
||||
String(String),
|
||||
Enum(f64),
|
||||
}
|
||||
|
||||
impl Number {
|
||||
pub fn value(&self) -> f64 {
|
||||
match self {
|
||||
@@ -1081,7 +656,9 @@ impl Number {
|
||||
}
|
||||
pub fn value_i64(&self, signed: bool) -> i64 {
|
||||
match self {
|
||||
Number::Enum(val) | Number::Float(val) | Number::Constant(val) => interpreter::f64_to_i64(*val, signed),
|
||||
Number::Enum(val) | Number::Float(val) | Number::Constant(val) => {
|
||||
interpreter::f64_to_i64(*val, signed)
|
||||
}
|
||||
Number::Binary(val) | Number::Hexadecimal(val) => *val,
|
||||
Number::String(s) => const_crc32::crc32(s.as_bytes()) as i32 as i64,
|
||||
}
|
||||
@@ -1090,10 +667,22 @@ impl Number {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use color_eyre::eyre::Ok;
|
||||
use strum::EnumProperty;
|
||||
|
||||
use super::*;
|
||||
|
||||
static INIT: std::sync::Once = std::sync::Once::new();
|
||||
|
||||
fn setup() {
|
||||
INIT.call_once(|| {
|
||||
let _ = color_eyre::install();
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_register() {
|
||||
fn parse_register() -> color_eyre::Result<()> {
|
||||
setup();
|
||||
let op = "requestingot".parse::<Operand>();
|
||||
assert_eq!(
|
||||
op.unwrap(),
|
||||
@@ -1101,10 +690,12 @@ mod tests {
|
||||
name: "requestingot".to_owned()
|
||||
})
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn successful_parse() {
|
||||
fn successful_parse() -> color_eyre::Result<()> {
|
||||
setup();
|
||||
let parsed = parse("s d0 Setting 0 # This is a comment\n");
|
||||
dbg!(&parsed);
|
||||
assert_eq!(
|
||||
@@ -1152,10 +743,12 @@ mod tests {
|
||||
comment: None,
|
||||
},],
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_code_chunk() {
|
||||
fn parse_code_chunk() -> color_eyre::Result<()> {
|
||||
setup();
|
||||
let code = "# This is a comment\n\
|
||||
define a_def 10\n\
|
||||
define a_hash HASH(\"This is a String\")\n\
|
||||
@@ -1250,7 +843,7 @@ mod tests {
|
||||
}),
|
||||
Operand::Type {
|
||||
logic_type: Some(LogicType::On),
|
||||
slot_logic_type: Some(SlotLogicType::On),
|
||||
slot_logic_type: Some(LogicSlotType::On),
|
||||
batch_mode: None,
|
||||
reagent_mode: None,
|
||||
identifier: Identifier {
|
||||
@@ -1425,15 +1018,19 @@ mod tests {
|
||||
},
|
||||
],
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_operand_display() {
|
||||
fn test_operand_display() -> color_eyre::Result<()> {
|
||||
setup();
|
||||
|
||||
#[track_caller]
|
||||
fn test_roundtrip(s: &str) {
|
||||
let o: Operand = s.parse().expect("test string should parse with FromStr");
|
||||
assert_eq!(o.to_string(), s);
|
||||
}
|
||||
|
||||
test_roundtrip("r0");
|
||||
test_roundtrip("r15");
|
||||
test_roundtrip("rr4");
|
||||
@@ -1459,9 +1056,9 @@ mod tests {
|
||||
test_roundtrip("1.2345");
|
||||
test_roundtrip("-1.2345");
|
||||
test_roundtrip(LogicType::Pressure.as_ref());
|
||||
test_roundtrip(SlotLogicType::Occupied.as_ref());
|
||||
test_roundtrip(BatchMode::Average.as_ref());
|
||||
test_roundtrip(ReagentMode::Recipe.as_ref());
|
||||
test_roundtrip(LogicSlotType::Occupied.as_ref());
|
||||
test_roundtrip(LogicBatchMethod::Average.as_ref());
|
||||
test_roundtrip(LogicReagentMode::Recipe.as_ref());
|
||||
test_roundtrip("pi");
|
||||
test_roundtrip("pinf");
|
||||
test_roundtrip("ninf");
|
||||
@@ -1469,48 +1066,58 @@ mod tests {
|
||||
test_roundtrip(r#"HASH("StructureFurnace")"#);
|
||||
test_roundtrip("$abcd");
|
||||
test_roundtrip("%1001");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_generated_enums_have_value() {
|
||||
fn all_generated_enums_have_value() -> color_eyre::Result<()> {
|
||||
setup();
|
||||
use strum::IntoEnumIterator;
|
||||
for lt in LogicType::iter() {
|
||||
println!("testing LogicType.{lt}");
|
||||
let value = lt.get_str("value");
|
||||
assert!(value.is_some());
|
||||
assert!(value.unwrap().parse::<u16>().is_ok());
|
||||
assert_eq!(lt as u16, value.unwrap().parse::<u16>().unwrap());
|
||||
}
|
||||
for slt in SlotLogicType::iter() {
|
||||
println!("testing SlotLogicType.{slt}");
|
||||
for slt in LogicSlotType::iter() {
|
||||
println!("testing LogicSlotType.{slt}");
|
||||
let value = slt.get_str("value");
|
||||
assert!(value.is_some());
|
||||
assert!(value.unwrap().parse::<u8>().is_ok());
|
||||
assert_eq!(slt as u8, value.unwrap().parse::<u8>().unwrap());
|
||||
}
|
||||
for bm in BatchMode::iter() {
|
||||
for bm in LogicReagentMode::iter() {
|
||||
println!("testing BatchMode.{bm}");
|
||||
let value = bm.get_str("value");
|
||||
assert!(value.is_some());
|
||||
assert!(value.unwrap().parse::<u8>().is_ok());
|
||||
assert_eq!(bm as u8, value.unwrap().parse::<u8>().unwrap());
|
||||
}
|
||||
for rm in ReagentMode::iter() {
|
||||
for rm in LogicReagentMode::iter() {
|
||||
println!("testing ReagentMode.{rm}");
|
||||
let value = rm.get_str("value");
|
||||
assert!(value.is_some());
|
||||
assert!(value.unwrap().parse::<u8>().is_ok());
|
||||
assert_eq!(rm as u8, value.unwrap().parse::<u8>().unwrap());
|
||||
}
|
||||
for le in LogicEnums::iter() {
|
||||
println!("testing Enum.{le}");
|
||||
for le in BasicEnum::iter() {
|
||||
println!("testing BasicEnum {le}");
|
||||
let value = le.get_str("value");
|
||||
assert!(value.is_some());
|
||||
assert!(value.unwrap().parse::<u32>().is_ok());
|
||||
assert_eq!(le.get_value(), value.unwrap().parse::<u32>().unwrap());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_parse_does_not_panic() {
|
||||
fn bad_parse_does_not_panic() -> color_eyre::Result<()> {
|
||||
setup();
|
||||
let code = "move foo -";
|
||||
let parsed = parse(code);
|
||||
assert!(parsed.is_err());
|
||||
println!("{}", parsed.unwrap_err());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
2756
ic10emu/src/interpreter/instructions.rs
Normal file
@@ -1,8 +1,7 @@
|
||||
pub mod errors;
|
||||
pub mod grammar;
|
||||
pub mod interpreter;
|
||||
pub mod network;
|
||||
mod rand_mscorlib;
|
||||
pub mod tokens;
|
||||
pub mod device;
|
||||
pub mod vm;
|
||||
pub mod network;
|
||||
|
||||
|
||||
@@ -1,12 +1,25 @@
|
||||
use std::{collections::HashSet, ops::Deref};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::{AsRefStr, EnumIter};
|
||||
use thiserror::Error;
|
||||
use std::{collections::HashSet, ops::Deref, rc::Rc};
|
||||
|
||||
use crate::vm::{
|
||||
object::{errors::LogicError, macros::ObjectInterface, traits::*, Name, ObjectID},
|
||||
VM,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use macro_rules_attribute::derive;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use stationeers_data::{
|
||||
enums::{script::LogicType, ConnectionRole, ConnectionType},
|
||||
templates::ConnectionInfo,
|
||||
};
|
||||
|
||||
use thiserror::Error;
|
||||
#[cfg(feature = "tsify")]
|
||||
use tsify::Tsify;
|
||||
#[cfg(feature = "tsify")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum CableConnectionType {
|
||||
Power,
|
||||
Data,
|
||||
@@ -14,158 +27,296 @@ pub enum CableConnectionType {
|
||||
PowerAndData,
|
||||
}
|
||||
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum Connection {
|
||||
CableNetwork {
|
||||
net: Option<u32>,
|
||||
net: Option<ObjectID>,
|
||||
typ: CableConnectionType,
|
||||
role: ConnectionRole,
|
||||
},
|
||||
Chute {
|
||||
role: ConnectionRole,
|
||||
},
|
||||
Pipe {
|
||||
role: ConnectionRole,
|
||||
},
|
||||
Elevator {
|
||||
role: ConnectionRole,
|
||||
},
|
||||
LandingPad {
|
||||
role: ConnectionRole,
|
||||
},
|
||||
LaunchPad {
|
||||
role: ConnectionRole,
|
||||
},
|
||||
PipeLiquid {
|
||||
role: ConnectionRole,
|
||||
},
|
||||
RoboticArmRail {
|
||||
role: ConnectionRole,
|
||||
},
|
||||
#[default]
|
||||
Other,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, EnumIter, AsRefStr,
|
||||
)]
|
||||
pub enum ConnectionType {
|
||||
Pipe,
|
||||
Power,
|
||||
Data,
|
||||
Chute,
|
||||
Elevator,
|
||||
PipeLiquid,
|
||||
LandingPad,
|
||||
LaunchPad,
|
||||
PowerAndData,
|
||||
#[serde(other)]
|
||||
#[default]
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, EnumIter, AsRefStr,
|
||||
)]
|
||||
pub enum ConnectionRole {
|
||||
Input,
|
||||
Input2,
|
||||
Output,
|
||||
Output2,
|
||||
Waste,
|
||||
#[serde(other)]
|
||||
#[default]
|
||||
None,
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
#[allow(dead_code)]
|
||||
fn from(typ: ConnectionType, _role: ConnectionRole) -> Self {
|
||||
pub fn from_info(typ: ConnectionType, role: ConnectionRole, net: Option<ObjectID>) -> Self {
|
||||
match typ {
|
||||
ConnectionType::None
|
||||
| ConnectionType::Chute
|
||||
| ConnectionType::Pipe
|
||||
| ConnectionType::Elevator
|
||||
| ConnectionType::LandingPad
|
||||
| ConnectionType::LaunchPad
|
||||
| ConnectionType::PipeLiquid => Self::Other,
|
||||
ConnectionType::None => Self::None,
|
||||
ConnectionType::Data => Self::CableNetwork {
|
||||
net: None,
|
||||
net,
|
||||
typ: CableConnectionType::Data,
|
||||
role,
|
||||
},
|
||||
ConnectionType::Power => Self::CableNetwork {
|
||||
net: None,
|
||||
net,
|
||||
typ: CableConnectionType::Power,
|
||||
role,
|
||||
},
|
||||
ConnectionType::PowerAndData => Self::CableNetwork {
|
||||
net: None,
|
||||
net,
|
||||
typ: CableConnectionType::PowerAndData,
|
||||
role,
|
||||
},
|
||||
ConnectionType::Chute => Self::Chute { role },
|
||||
ConnectionType::Pipe => Self::Pipe { role },
|
||||
ConnectionType::Elevator => Self::Elevator { role },
|
||||
ConnectionType::LandingPad => Self::LandingPad { role },
|
||||
ConnectionType::LaunchPad => Self::LaunchPad { role },
|
||||
ConnectionType::PipeLiquid => Self::PipeLiquid { role },
|
||||
ConnectionType::RoboticArmRail => Self::RoboticArmRail { role },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_info(&self) -> ConnectionInfo {
|
||||
match self {
|
||||
Self::None => ConnectionInfo {
|
||||
typ: ConnectionType::None,
|
||||
role: ConnectionRole::None,
|
||||
},
|
||||
Self::CableNetwork {
|
||||
typ: CableConnectionType::Data,
|
||||
role,
|
||||
..
|
||||
} => ConnectionInfo {
|
||||
typ: ConnectionType::Data,
|
||||
role: *role,
|
||||
},
|
||||
Self::CableNetwork {
|
||||
typ: CableConnectionType::Power,
|
||||
role,
|
||||
..
|
||||
} => ConnectionInfo {
|
||||
typ: ConnectionType::Power,
|
||||
role: *role,
|
||||
},
|
||||
Self::CableNetwork {
|
||||
typ: CableConnectionType::PowerAndData,
|
||||
role,
|
||||
..
|
||||
} => ConnectionInfo {
|
||||
typ: ConnectionType::PowerAndData,
|
||||
role: *role,
|
||||
},
|
||||
Self::Chute { role } => ConnectionInfo {
|
||||
typ: ConnectionType::Chute,
|
||||
role: *role,
|
||||
},
|
||||
Self::Pipe { role } => ConnectionInfo {
|
||||
typ: ConnectionType::Pipe,
|
||||
role: *role,
|
||||
},
|
||||
Self::PipeLiquid { role } => ConnectionInfo {
|
||||
typ: ConnectionType::PipeLiquid,
|
||||
role: *role,
|
||||
},
|
||||
Self::Elevator { role } => ConnectionInfo {
|
||||
typ: ConnectionType::Elevator,
|
||||
role: *role,
|
||||
},
|
||||
Self::LandingPad { role } => ConnectionInfo {
|
||||
typ: ConnectionType::LandingPad,
|
||||
role: *role,
|
||||
},
|
||||
Self::LaunchPad { role } => ConnectionInfo {
|
||||
typ: ConnectionType::LaunchPad,
|
||||
role: *role,
|
||||
},
|
||||
Self::RoboticArmRail { role } => ConnectionInfo {
|
||||
typ: ConnectionType::RoboticArmRail,
|
||||
role: *role,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_network(&self) -> Option<ObjectID> {
|
||||
match self {
|
||||
Self::CableNetwork { net, .. } => *net,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Network {
|
||||
pub id: u32,
|
||||
pub devices: HashSet<u32>,
|
||||
pub power_only: HashSet<u32>,
|
||||
#[derive(ObjectInterface!, Debug)]
|
||||
#[custom(implements(Object { Storage, Logicable, Network}))]
|
||||
pub struct CableNetwork {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
/// required by object interface but atm unused by network
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
/// required by object interface but atm unused by network
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
/// data enabled objects (must be devices)
|
||||
pub devices: HashSet<ObjectID>,
|
||||
/// power only connections
|
||||
pub power_only: HashSet<ObjectID>,
|
||||
/// channel data
|
||||
pub channels: [f64; 8],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FrozenNetwork {
|
||||
pub id: u32,
|
||||
pub devices: Vec<u32>,
|
||||
pub power_only: Vec<u32>,
|
||||
pub channels: [f64; 8],
|
||||
}
|
||||
|
||||
impl<T> From<T> for FrozenNetwork
|
||||
where
|
||||
T: Deref<Target = Network>,
|
||||
{
|
||||
fn from(value: T) -> Self {
|
||||
FrozenNetwork {
|
||||
id: value.id,
|
||||
devices: value.devices.iter().copied().collect_vec(),
|
||||
power_only: value.power_only.iter().copied().collect_vec(),
|
||||
channels: value.channels,
|
||||
}
|
||||
impl Storage for CableNetwork {
|
||||
fn debug_storage(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "UNIMPLEMENTED") //TODO: Implement
|
||||
}
|
||||
fn slots_count(&self) -> usize {
|
||||
0
|
||||
}
|
||||
fn get_slot(&self, _index: usize) -> Option<&crate::vm::object::Slot> {
|
||||
None
|
||||
}
|
||||
fn get_slot_mut(&mut self, _index: usize) -> Option<&mut crate::vm::object::Slot> {
|
||||
None
|
||||
}
|
||||
fn get_slots(&self) -> Vec<(usize, &crate::vm::object::Slot)> {
|
||||
vec![]
|
||||
}
|
||||
fn get_slots_mut(&mut self) -> Vec<(usize, &mut crate::vm::object::Slot)> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FrozenNetwork> for Network {
|
||||
fn from(value: FrozenNetwork) -> Self {
|
||||
Network {
|
||||
id: value.id,
|
||||
devices: value.devices.into_iter().collect(),
|
||||
power_only: value.power_only.into_iter().collect(),
|
||||
channels: value.channels,
|
||||
}
|
||||
impl Logicable for CableNetwork {
|
||||
fn debug_logicable(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "UNIMPLEMENTED") //TODO: Implement
|
||||
}
|
||||
fn prefab_hash(&self) -> i32 {
|
||||
0
|
||||
}
|
||||
fn name_hash(&self) -> i32 {
|
||||
0
|
||||
}
|
||||
fn is_logic_readable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn is_logic_writeable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn can_logic_read(&self, lt: LogicType) -> bool {
|
||||
use LogicType::*;
|
||||
matches!(
|
||||
lt,
|
||||
Channel0 | Channel1 | Channel2 | Channel3 | Channel4 | Channel5 | Channel6 | Channel7
|
||||
)
|
||||
}
|
||||
fn can_logic_write(&self, lt: LogicType) -> bool {
|
||||
use LogicType::*;
|
||||
matches!(
|
||||
lt,
|
||||
Channel0 | Channel1 | Channel2 | Channel3 | Channel4 | Channel5 | Channel6 | Channel7
|
||||
)
|
||||
}
|
||||
fn get_logic(&self, lt: LogicType) -> Result<f64, crate::vm::object::errors::LogicError> {
|
||||
use LogicType::*;
|
||||
let index: usize = match lt {
|
||||
Channel0 => 0,
|
||||
Channel1 => 1,
|
||||
Channel2 => 2,
|
||||
Channel3 => 3,
|
||||
Channel4 => 4,
|
||||
Channel5 => 5,
|
||||
Channel6 => 6,
|
||||
Channel7 => 7,
|
||||
_ => return Err(LogicError::CantRead(lt)),
|
||||
};
|
||||
Ok(self.channels[index])
|
||||
}
|
||||
fn set_logic(&mut self, lt: LogicType, value: f64, _force: bool) -> Result<(), LogicError> {
|
||||
use LogicType::*;
|
||||
let index: usize = match lt {
|
||||
Channel0 => 0,
|
||||
Channel1 => 1,
|
||||
Channel2 => 2,
|
||||
Channel3 => 3,
|
||||
Channel4 => 4,
|
||||
Channel5 => 5,
|
||||
Channel6 => 6,
|
||||
Channel7 => 7,
|
||||
_ => return Err(LogicError::CantWrite(lt)),
|
||||
};
|
||||
self.channels[index] = value;
|
||||
Ok(())
|
||||
}
|
||||
fn can_slot_logic_read(
|
||||
&self,
|
||||
_slt: stationeers_data::enums::script::LogicSlotType,
|
||||
_index: f64,
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
fn get_slot_logic(
|
||||
&self,
|
||||
slt: stationeers_data::enums::script::LogicSlotType,
|
||||
index: f64,
|
||||
) -> Result<f64, LogicError> {
|
||||
Err(LogicError::CantSlotRead(slt, index))
|
||||
}
|
||||
fn valid_logic_types(&self) -> Vec<LogicType> {
|
||||
use LogicType::*;
|
||||
vec![
|
||||
Channel0, Channel1, Channel2, Channel3, Channel4, Channel5, Channel6, Channel7,
|
||||
]
|
||||
}
|
||||
fn known_modes(&self) -> Option<Vec<(u32, String)>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum NetworkError {
|
||||
#[error("")]
|
||||
ChannelIndexOutOfRange,
|
||||
}
|
||||
|
||||
impl Network {
|
||||
|
||||
pub fn new(id: u32) -> Self {
|
||||
Network {
|
||||
id,
|
||||
devices: HashSet::new(),
|
||||
power_only: HashSet::new(),
|
||||
channels: [f64::NAN; 8],
|
||||
}
|
||||
impl Network for CableNetwork {
|
||||
fn debug_network(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "UNIMPLEMENTED") //TODO: Implement
|
||||
}
|
||||
|
||||
pub fn contains(&self, id: &u32) -> bool {
|
||||
fn contains(&self, id: &ObjectID) -> bool {
|
||||
self.devices.contains(id) || self.power_only.contains(id)
|
||||
}
|
||||
|
||||
pub fn contains_all(&self, ids: &[u32]) -> bool {
|
||||
fn contains_all(&self, ids: &[ObjectID]) -> bool {
|
||||
ids.iter().all(|id| self.contains(id))
|
||||
}
|
||||
|
||||
pub fn contains_data(&self, id: &u32) -> bool {
|
||||
fn contains_data(&self, id: &ObjectID) -> bool {
|
||||
self.devices.contains(id)
|
||||
}
|
||||
|
||||
pub fn contains_all_data(&self, ids: &[u32]) -> bool {
|
||||
fn contains_all_data(&self, ids: &[ObjectID]) -> bool {
|
||||
ids.iter().all(|id| self.contains_data(id))
|
||||
}
|
||||
|
||||
pub fn contains_power(&self, id: &u32) -> bool {
|
||||
fn contains_power(&self, id: &ObjectID) -> bool {
|
||||
self.power_only.contains(id)
|
||||
}
|
||||
|
||||
pub fn contains_all_power(&self, ids: &[u32]) -> bool {
|
||||
fn contains_all_power(&self, ids: &[ObjectID]) -> bool {
|
||||
ids.iter().all(|id| self.contains_power(id))
|
||||
}
|
||||
|
||||
pub fn data_visible(&self, source: &u32) -> Vec<u32> {
|
||||
fn data_visible(&self, source: &ObjectID) -> Vec<ObjectID> {
|
||||
if self.contains_data(source) {
|
||||
self.devices
|
||||
.iter()
|
||||
@@ -177,25 +328,102 @@ impl Network {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_data(&mut self, id: u32) -> bool {
|
||||
fn add_data(&mut self, id: ObjectID) -> bool {
|
||||
self.devices.insert(id)
|
||||
}
|
||||
|
||||
pub fn add_power(&mut self, id: u32) -> bool {
|
||||
fn add_power(&mut self, id: ObjectID) -> bool {
|
||||
self.power_only.insert(id)
|
||||
}
|
||||
|
||||
pub fn remove_all(&mut self, id: u32) -> bool {
|
||||
fn remove_all(&mut self, id: ObjectID) -> bool {
|
||||
self.devices.remove(&id) || self.power_only.remove(&id)
|
||||
}
|
||||
pub fn remove_data(&mut self, id: u32) -> bool {
|
||||
fn remove_data(&mut self, id: ObjectID) -> bool {
|
||||
self.devices.remove(&id)
|
||||
}
|
||||
|
||||
pub fn remove_power(&mut self, id: u32) -> bool {
|
||||
fn remove_power(&mut self, id: ObjectID) -> bool {
|
||||
self.devices.remove(&id)
|
||||
}
|
||||
|
||||
fn get_devices(&self) -> Vec<ObjectID> {
|
||||
self.devices.iter().copied().collect_vec()
|
||||
}
|
||||
|
||||
fn get_power_only(&self) -> Vec<ObjectID> {
|
||||
self.power_only.iter().copied().collect_vec()
|
||||
}
|
||||
|
||||
fn get_channel_data(&self) -> &[f64; 8] {
|
||||
&self.channels
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct FrozenCableNetwork {
|
||||
pub id: ObjectID,
|
||||
pub devices: Vec<u32>,
|
||||
pub power_only: Vec<u32>,
|
||||
pub channels: [f64; 8],
|
||||
}
|
||||
|
||||
impl<T> From<T> for FrozenCableNetwork
|
||||
where
|
||||
T: Deref<Target = CableNetwork>,
|
||||
{
|
||||
fn from(value: T) -> Self {
|
||||
FrozenCableNetwork {
|
||||
id: value.id,
|
||||
devices: value.devices.iter().copied().collect_vec(),
|
||||
power_only: value.power_only.iter().copied().collect_vec(),
|
||||
channels: value.channels,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NetworkRef<'_>> for FrozenCableNetwork {
|
||||
fn from(value: NetworkRef) -> Self {
|
||||
FrozenCableNetwork {
|
||||
id: *value.get_id(),
|
||||
devices: value.get_devices(),
|
||||
power_only: value.get_power_only(),
|
||||
channels: *value.get_channel_data(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum NetworkError {
|
||||
#[error("")]
|
||||
ChannelIndexOutOfRange,
|
||||
}
|
||||
|
||||
impl CableNetwork {
|
||||
pub fn new(id: u32, vm: Rc<VM>) -> Self {
|
||||
CableNetwork {
|
||||
id,
|
||||
prefab: Name::new(""),
|
||||
name: Name::new(""),
|
||||
vm,
|
||||
devices: HashSet::new(),
|
||||
power_only: HashSet::new(),
|
||||
channels: [f64::NAN; 8],
|
||||
}
|
||||
}
|
||||
pub fn from_frozen(value: FrozenCableNetwork, vm: Rc<VM>) -> Self {
|
||||
CableNetwork {
|
||||
id: value.id,
|
||||
prefab: Name::new(""),
|
||||
name: Name::new(""),
|
||||
vm,
|
||||
devices: value.devices.into_iter().collect(),
|
||||
power_only: value.power_only.into_iter().collect(),
|
||||
channels: value.channels,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_channel(&mut self, chan: usize, val: f64) -> Result<f64, NetworkError> {
|
||||
if chan > 7 {
|
||||
Err(NetworkError::ChannelIndexOutOfRange)
|
||||
|
||||
2045
ic10emu/src/vm.rs
27
ic10emu/src/vm/instructions.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
mod codegen;
|
||||
pub mod operands;
|
||||
pub use codegen::enums;
|
||||
pub use codegen::traits;
|
||||
|
||||
use enums::InstructionOp;
|
||||
use operands::Operand;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use phf::phf_map;
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Instruction {
|
||||
pub instruction: InstructionOp,
|
||||
pub operands: Vec<Operand>,
|
||||
}
|
||||
|
||||
#[allow(clippy::approx_constant)]
|
||||
pub static CONSTANTS_LOOKUP: phf::Map<&'static str, f64> = phf_map! {
|
||||
"nan" => f64::NAN,
|
||||
"ninf" => f64::NEG_INFINITY,
|
||||
"deg2rad" => 0.0174532923847437f64,
|
||||
"rad2deg" => 57.2957801818848f64,
|
||||
"epsilon" => f64::EPSILON,
|
||||
"pinf" => f64::INFINITY,
|
||||
"pi" => 3.141592653589793f64,
|
||||
};
|
||||
2
ic10emu/src/vm/instructions/codegen.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod traits;
|
||||
pub mod enums;
|
||||
1592
ic10emu/src/vm/instructions/codegen/enums.rs
Normal file
4664
ic10emu/src/vm/instructions/codegen/traits.rs
Normal file
336
ic10emu/src/vm/instructions/operands.rs
Normal file
@@ -0,0 +1,336 @@
|
||||
use crate::errors::ICError;
|
||||
use crate::interpreter;
|
||||
use crate::vm::{instructions::enums::InstructionOp, object::traits::IntegratedCircuit};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use stationeers_data::enums::script::{
|
||||
LogicBatchMethod, LogicReagentMode, LogicSlotType, LogicType,
|
||||
};
|
||||
use strum::EnumProperty;
|
||||
#[cfg(feature = "tsify")]
|
||||
use tsify::Tsify;
|
||||
#[cfg(feature = "tsify")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum Device {
|
||||
Db,
|
||||
Numbered(u32),
|
||||
Indirect { indirection: u32, target: u32 },
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct RegisterSpec {
|
||||
pub indirection: u32,
|
||||
pub target: u32,
|
||||
}
|
||||
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct DeviceSpec {
|
||||
pub device: Device,
|
||||
pub connection: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct Identifier {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum Number {
|
||||
Float(f64),
|
||||
Binary(i64),
|
||||
Hexadecimal(i64),
|
||||
Constant(f64),
|
||||
String(String),
|
||||
Enum(f64),
|
||||
}
|
||||
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum Operand {
|
||||
RegisterSpec(RegisterSpec),
|
||||
DeviceSpec(DeviceSpec),
|
||||
Number(Number),
|
||||
Type {
|
||||
logic_type: Option<LogicType>,
|
||||
slot_logic_type: Option<LogicSlotType>,
|
||||
batch_mode: Option<LogicBatchMethod>,
|
||||
reagent_mode: Option<LogicReagentMode>,
|
||||
identifier: Identifier,
|
||||
},
|
||||
Identifier(Identifier),
|
||||
}
|
||||
|
||||
pub struct InstOperand {
|
||||
pub operand: Operand,
|
||||
pub inst: InstructionOp,
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
impl InstOperand {
|
||||
pub fn new(operand: &Operand, inst: InstructionOp, index: usize) -> Self {
|
||||
InstOperand {
|
||||
operand: operand.clone(),
|
||||
inst,
|
||||
index,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_ident(&self) -> Result<Identifier, ICError> {
|
||||
let Operand::Identifier(ident) = &self.operand else {
|
||||
return Err(ICError::IncorrectOperandType {
|
||||
inst: self.inst,
|
||||
index: self.index,
|
||||
desired: "Name".to_owned(),
|
||||
});
|
||||
};
|
||||
Ok(ident.clone())
|
||||
}
|
||||
|
||||
pub fn as_number(&self) -> Result<Number, ICError> {
|
||||
let Operand::Number(num) = &self.operand else {
|
||||
return Err(ICError::IncorrectOperandType {
|
||||
inst: self.inst,
|
||||
index: self.index,
|
||||
desired: "Number".to_owned(),
|
||||
});
|
||||
};
|
||||
Ok(num.clone())
|
||||
}
|
||||
|
||||
pub fn as_aliasable(&self) -> Result<Operand, ICError> {
|
||||
match &self.operand {
|
||||
Operand::RegisterSpec { .. } | Operand::DeviceSpec { .. } => Ok(self.operand.clone()),
|
||||
_ => Err(ICError::IncorrectOperandType {
|
||||
inst: self.inst,
|
||||
index: self.index,
|
||||
desired: "Device Or Register".to_owned(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_value<IC: IntegratedCircuit>(&self, ic: &IC) -> Result<f64, ICError> {
|
||||
match self.translate_alias(ic) {
|
||||
Operand::RegisterSpec(RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
}) => ic.get_register(indirection, target),
|
||||
Operand::Number(num) => Ok(num.value()),
|
||||
Operand::Type {
|
||||
logic_type,
|
||||
slot_logic_type,
|
||||
batch_mode,
|
||||
reagent_mode,
|
||||
identifier: _,
|
||||
} => {
|
||||
if let Some(lt) = logic_type {
|
||||
Ok(lt
|
||||
.get_str("value")
|
||||
.ok_or_else(|| ICError::NoGeneratedValue(lt.to_string()))?
|
||||
.parse::<u16>()
|
||||
.map_err(|_| ICError::BadGeneratedValueParse {
|
||||
enum_name: lt.to_string(),
|
||||
parse_type: "u16".to_owned(),
|
||||
})? as f64)
|
||||
} else if let Some(slt) = slot_logic_type {
|
||||
Ok(slt
|
||||
.get_str("value")
|
||||
.ok_or_else(|| ICError::NoGeneratedValue(slt.to_string()))?
|
||||
.parse::<u8>()
|
||||
.map_err(|_| ICError::BadGeneratedValueParse {
|
||||
enum_name: slt.to_string(),
|
||||
parse_type: "u8".to_owned(),
|
||||
})? as f64)
|
||||
} else if let Some(bm) = batch_mode {
|
||||
Ok(bm
|
||||
.get_str("value")
|
||||
.ok_or_else(|| ICError::NoGeneratedValue(bm.to_string()))?
|
||||
.parse::<u8>()
|
||||
.map_err(|_| ICError::BadGeneratedValueParse {
|
||||
enum_name: bm.to_string(),
|
||||
parse_type: "u8".to_owned(),
|
||||
})? as f64)
|
||||
} else if let Some(rm) = reagent_mode {
|
||||
Ok(rm
|
||||
.get_str("value")
|
||||
.ok_or_else(|| ICError::NoGeneratedValue(rm.to_string()))?
|
||||
.parse::<u8>()
|
||||
.map_err(|_| ICError::BadGeneratedValueParse {
|
||||
enum_name: rm.to_string(),
|
||||
parse_type: "u8".to_owned(),
|
||||
})? as f64)
|
||||
} else {
|
||||
Err(ICError::TypeValueNotKnown)
|
||||
}
|
||||
}
|
||||
Operand::Identifier(id) => Err(ICError::UnknownIdentifier(id.name.to_string())),
|
||||
Operand::DeviceSpec { .. } => Err(ICError::IncorrectOperandType {
|
||||
inst: self.inst,
|
||||
index: self.index,
|
||||
desired: "Value".to_owned(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_value_i64<IC: IntegratedCircuit>(
|
||||
&self,
|
||||
ic: &IC,
|
||||
signed: bool,
|
||||
) -> Result<i64, ICError> {
|
||||
match &self.operand {
|
||||
Operand::Number(num) => Ok(num.value_i64(signed)),
|
||||
_ => {
|
||||
let val = self.as_value(ic)?;
|
||||
if val < i64::MIN as f64 {
|
||||
Err(ICError::ShiftUnderflowI64)
|
||||
} else if val <= i64::MAX as f64 {
|
||||
Ok(interpreter::f64_to_i64(val, signed))
|
||||
} else {
|
||||
Err(ICError::ShiftOverflowI64)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn as_value_i32<IC: IntegratedCircuit>(
|
||||
&self,
|
||||
ic: &IC,
|
||||
signed: bool,
|
||||
) -> Result<i32, ICError> {
|
||||
match &self.operand {
|
||||
Operand::Number(num) => Ok(num.value_i64(signed) as i32),
|
||||
_ => {
|
||||
let val = self.as_value(ic)?;
|
||||
if val < i32::MIN as f64 {
|
||||
Err(ICError::ShiftUnderflowI32)
|
||||
} else if val <= i32::MAX as f64 {
|
||||
Ok(val as i32)
|
||||
} else {
|
||||
Err(ICError::ShiftOverflowI32)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_register<IC: IntegratedCircuit>(&self, ic: &IC) -> Result<RegisterSpec, ICError> {
|
||||
match self.translate_alias(ic) {
|
||||
Operand::RegisterSpec(reg) => Ok(reg),
|
||||
Operand::Identifier(id) => Err(ICError::UnknownIdentifier(id.name.to_string())),
|
||||
_ => Err(ICError::IncorrectOperandType {
|
||||
inst: self.inst,
|
||||
index: self.index,
|
||||
desired: "Register".to_owned(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// interpret the operand as a device index, i32::MAX is db
|
||||
pub fn as_device<IC: IntegratedCircuit>(
|
||||
&self,
|
||||
ic: &IC,
|
||||
) -> Result<(i32, Option<usize>), ICError> {
|
||||
match self.translate_alias(ic) {
|
||||
Operand::DeviceSpec(DeviceSpec { device, connection }) => match device {
|
||||
Device::Db => Ok((i32::MAX, connection)),
|
||||
Device::Numbered(p) => Ok((p as i32, connection)),
|
||||
Device::Indirect {
|
||||
indirection,
|
||||
target,
|
||||
} => {
|
||||
let val = ic.get_register(indirection, target)?;
|
||||
Ok((val as i32, connection))
|
||||
}
|
||||
},
|
||||
Operand::Identifier(id) => Err(ICError::UnknownIdentifier(id.name.to_string())),
|
||||
_ => Err(ICError::IncorrectOperandType {
|
||||
inst: self.inst,
|
||||
index: self.index,
|
||||
desired: "Value".to_owned(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_logic_type<IC: IntegratedCircuit>(&self, ic: &IC) -> Result<LogicType, ICError> {
|
||||
match &self.operand {
|
||||
Operand::Type {
|
||||
logic_type: Some(lt),
|
||||
..
|
||||
} => Ok(*lt),
|
||||
_ => {
|
||||
let val = self.as_value(ic)?;
|
||||
LogicType::try_from(val).map_err(|_| ICError::UnknownLogicType(val))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_slot_logic_type<IC: IntegratedCircuit>(
|
||||
&self,
|
||||
ic: &IC,
|
||||
) -> Result<LogicSlotType, ICError> {
|
||||
match &self.operand {
|
||||
Operand::Type {
|
||||
slot_logic_type: Some(slt),
|
||||
..
|
||||
} => Ok(*slt),
|
||||
_ => {
|
||||
let val = self.as_value(ic)?;
|
||||
LogicSlotType::try_from(val).map_err(|_| ICError::UnknownLogicSlotType(val))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_batch_mode<IC: IntegratedCircuit>(
|
||||
&self,
|
||||
ic: &IC,
|
||||
) -> Result<LogicBatchMethod, ICError> {
|
||||
match &self.operand {
|
||||
Operand::Type {
|
||||
batch_mode: Some(bm),
|
||||
..
|
||||
} => Ok(*bm),
|
||||
_ => {
|
||||
let val = self.as_value(ic)?;
|
||||
LogicBatchMethod::try_from(val).map_err(|_| ICError::UnknownBatchMode(val))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_reagent_mode<IC: IntegratedCircuit>(
|
||||
&self,
|
||||
ic: &IC,
|
||||
) -> Result<LogicReagentMode, ICError> {
|
||||
match &self.operand {
|
||||
Operand::Type {
|
||||
reagent_mode: Some(rm),
|
||||
..
|
||||
} => Ok(*rm),
|
||||
_ => {
|
||||
let val = self.as_value(ic)?;
|
||||
LogicReagentMode::try_from(val).map_err(|_| ICError::UnknownReagentMode(val))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn translate_alias<IC: IntegratedCircuit>(&self, ic: &IC) -> Operand {
|
||||
match &self.operand {
|
||||
Operand::Identifier(id) | Operand::Type { identifier: id, .. } => {
|
||||
if let Some(alias) = ic.get_aliases().get(&id.name) {
|
||||
alias.clone()
|
||||
} else if let Some(define) = ic.get_defines().get(&id.name) {
|
||||
Operand::Number(Number::Float(*define))
|
||||
} else if let Some(label) = ic.get_labels().get(&id.name) {
|
||||
Operand::Number(Number::Float(*label as f64))
|
||||
} else {
|
||||
self.operand.clone()
|
||||
}
|
||||
}
|
||||
_ => self.operand.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
164
ic10emu/src/vm/object.rs
Normal file
@@ -0,0 +1,164 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
ops::{Deref, DerefMut},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use macro_rules_attribute::derive;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
pub mod errors;
|
||||
pub mod generic;
|
||||
pub mod humans;
|
||||
pub mod macros;
|
||||
pub mod stationpedia;
|
||||
pub mod templates;
|
||||
pub mod traits;
|
||||
|
||||
use traits::Object;
|
||||
|
||||
use crate::vm::VM;
|
||||
#[cfg(feature = "tsify")]
|
||||
use tsify::{declare, Tsify};
|
||||
#[cfg(feature = "tsify")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use stationeers_data::enums::{
|
||||
basic::Class, prefabs::StationpediaPrefab, script::LogicSlotType, MemoryAccess,
|
||||
};
|
||||
|
||||
#[cfg_attr(feature = "tsify", declare)]
|
||||
pub type ObjectID = u32;
|
||||
pub type BoxedObject = Rc<RefCell<dyn Object>>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "tsify", wasm_bindgen)]
|
||||
pub struct VMObject(BoxedObject);
|
||||
|
||||
impl Deref for VMObject {
|
||||
type Target = BoxedObject;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for VMObject {
|
||||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl VMObject {
|
||||
pub fn new<T>(val: T) -> Self
|
||||
where
|
||||
T: Object + 'static,
|
||||
{
|
||||
VMObject(Rc::new(RefCell::new(val)))
|
||||
}
|
||||
|
||||
pub fn set_vm(&mut self, vm: Rc<VM>) {
|
||||
self.borrow_mut().set_vm(vm);
|
||||
}
|
||||
|
||||
pub fn get_vm(&self) -> Rc<VM> {
|
||||
self.borrow().get_vm().clone()
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> ObjectID {
|
||||
*self.borrow().get_id()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct Name {
|
||||
pub value: String,
|
||||
pub hash: i32,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
impl Name {
|
||||
pub fn new(name: &str) -> Self {
|
||||
Name {
|
||||
value: name.to_owned(),
|
||||
hash: const_crc32::crc32(name.as_bytes()) as i32,
|
||||
}
|
||||
}
|
||||
pub fn from_prefab_name(name: &str) -> Self {
|
||||
Name {
|
||||
value: name.to_string(),
|
||||
hash: name
|
||||
.parse::<StationpediaPrefab>()
|
||||
.map(|prefab| prefab as i32)
|
||||
.unwrap_or_else(|_| const_crc32::crc32(name.as_bytes()) as i32),
|
||||
}
|
||||
}
|
||||
pub fn from_prefab_hash(hash: i32) -> Option<Self> {
|
||||
StationpediaPrefab::from_repr(hash).map(|prefab| Name {
|
||||
value: prefab.to_string(),
|
||||
hash,
|
||||
})
|
||||
}
|
||||
pub fn set(&mut self, name: &str) {
|
||||
self.value = name.to_owned();
|
||||
self.hash = const_crc32::crc32(name.as_bytes()) as i32;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct LogicField {
|
||||
pub field_type: MemoryAccess,
|
||||
pub value: f64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct SlotOccupantInfo {
|
||||
pub quantity: u32,
|
||||
pub id: ObjectID,
|
||||
}
|
||||
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct Slot {
|
||||
pub parent: ObjectID,
|
||||
pub index: usize,
|
||||
pub name: String,
|
||||
pub class: Class,
|
||||
pub readable_logic: Vec<LogicSlotType>,
|
||||
pub writeable_logic: Vec<LogicSlotType>,
|
||||
pub occupant: Option<SlotOccupantInfo>,
|
||||
pub proxy: bool,
|
||||
}
|
||||
|
||||
impl Slot {
|
||||
#[must_use]
|
||||
pub fn new(parent: ObjectID, index: usize, name: String, class: Class) -> Self {
|
||||
Slot {
|
||||
parent,
|
||||
index,
|
||||
name,
|
||||
class,
|
||||
readable_logic:
|
||||
vec![
|
||||
LogicSlotType::Class,
|
||||
LogicSlotType::Damage,
|
||||
LogicSlotType::MaxQuantity,
|
||||
LogicSlotType::OccupantHash,
|
||||
LogicSlotType::Occupied,
|
||||
LogicSlotType::PrefabHash,
|
||||
LogicSlotType::Quantity,
|
||||
LogicSlotType::ReferenceId,
|
||||
LogicSlotType::SortingClass,
|
||||
],
|
||||
writeable_logic: vec![],
|
||||
occupant: None,
|
||||
proxy: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
36
ic10emu/src/vm/object/errors.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
use stationeers_data::enums::script::{LogicSlotType, LogicType};
|
||||
#[cfg(feature = "tsify")]
|
||||
use tsify::Tsify;
|
||||
#[cfg(feature = "tsify")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[derive(Error, Debug, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum LogicError {
|
||||
#[error("can't read LogicType {0}")]
|
||||
CantRead(LogicType),
|
||||
#[error("can't read slot {1} LogicSlotType {0}")]
|
||||
CantSlotRead(LogicSlotType, f64),
|
||||
#[error("can't write LogicType {0}")]
|
||||
CantWrite(LogicType),
|
||||
#[error("can't write slot {1} LogicSlotType {0}")]
|
||||
CantSlotWrite(LogicSlotType, f64),
|
||||
#[error("slot id {0} is out of range 0..{1}")]
|
||||
SlotIndexOutOfRange(f64, usize),
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum MemoryError {
|
||||
#[error("stack underflow: {0} < range [0..{1})")]
|
||||
StackUnderflow(i32, usize),
|
||||
#[error("stack overflow: {0} > range [0..{1})")]
|
||||
StackOverflow(i32, usize),
|
||||
#[error("memory not readable")]
|
||||
NotReadable,
|
||||
#[error("memory not writeable")]
|
||||
NotWriteable,
|
||||
}
|
||||
3
ic10emu/src/vm/object/generic.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod macros;
|
||||
pub mod structs;
|
||||
pub mod traits;
|
||||
328
ic10emu/src/vm/object/generic/macros.rs
Normal file
@@ -0,0 +1,328 @@
|
||||
macro_rules! GWThermal {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWThermal for $struct {
|
||||
fn is_thermal(&self) -> bool {
|
||||
self.thermal_info.is_some()
|
||||
}
|
||||
fn thermal_info(&self) -> &ThermalInfo {
|
||||
self.thermal_info
|
||||
.as_ref()
|
||||
.expect("GWThermal::thermal_info called on non thermal")
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use GWThermal;
|
||||
|
||||
macro_rules! GWInternalAtmo {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWInternalAtmo for $struct {
|
||||
fn is_internal_atmo(&self) -> bool {
|
||||
self.internal_atmo_info.is_some()
|
||||
}
|
||||
fn internal_atmo_info(&self) -> &InternalAtmoInfo {
|
||||
self.internal_atmo_info
|
||||
.as_ref()
|
||||
.expect("GWInternalAtmo::internal_atmo_info called on non internal atmo")
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use GWInternalAtmo;
|
||||
|
||||
macro_rules! GWStructure {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWStructure for $struct {
|
||||
fn small_grid(&self) -> bool {
|
||||
self.small_grid
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use GWStructure;
|
||||
|
||||
macro_rules! GWStorage {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWStorage for $struct {
|
||||
fn slots(&self) -> &BTreeMap<u32, Slot> {
|
||||
&self.slots
|
||||
}
|
||||
fn slots_mut(&mut self) -> &mut BTreeMap<u32, Slot> {
|
||||
&mut self.slots
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use GWStorage;
|
||||
|
||||
macro_rules! GWLogicable {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWLogicable for $struct {
|
||||
fn fields(&self) -> &BTreeMap<LogicType, LogicField> {
|
||||
&self.fields
|
||||
}
|
||||
fn fields_mut(&mut self) -> &mut BTreeMap<LogicType, LogicField> {
|
||||
&mut self.fields
|
||||
}
|
||||
fn known_modes(&self) -> Option<&BTreeMap<u32, String>> {
|
||||
self.modes.as_ref()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use GWLogicable;
|
||||
|
||||
macro_rules! GWMemoryReadable {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWMemoryReadable for $struct {
|
||||
fn memory_size(&self) -> usize {
|
||||
self.memory.len()
|
||||
}
|
||||
fn memory(&self) -> &Vec<f64> {
|
||||
&self.memory
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use GWMemoryReadable;
|
||||
|
||||
macro_rules! GWMemoryWritable {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWMemoryWritable for $struct {
|
||||
fn memory_mut(&mut self) -> &mut Vec<f64> {
|
||||
&mut self.memory
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use GWMemoryWritable;
|
||||
|
||||
macro_rules! GWDevice {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWDevice for $struct {
|
||||
fn device_info(&self) -> &DeviceInfo {
|
||||
&self.device_info
|
||||
}
|
||||
fn connections(&self) -> &[Connection] {
|
||||
self.connections.as_slice()
|
||||
}
|
||||
fn connections_mut(&mut self) -> &mut [Connection] {
|
||||
self.connections.as_mut_slice()
|
||||
}
|
||||
fn pins(&self) -> Option<&[Option<ObjectID>]> {
|
||||
self.pins.as_ref().map(|pins| pins.as_slice())
|
||||
}
|
||||
fn pins_mut(&mut self) -> Option<&mut [Option<ObjectID>]> {
|
||||
self.pins.as_mut().map(|pins| pins.as_mut_slice())
|
||||
}
|
||||
fn reagents(&self) -> Option<&BTreeMap<u8, f64>> {
|
||||
self.reagents.as_ref()
|
||||
}
|
||||
fn reagents_mut(&mut self) -> &mut Option<BTreeMap<u8, f64>> {
|
||||
&mut self.reagents
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use GWDevice;
|
||||
|
||||
macro_rules! GWItem {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWItem for $struct {
|
||||
fn item_info(&self) -> &ItemInfo {
|
||||
&self.item_info
|
||||
}
|
||||
fn parent_slot(&self) -> Option<ParentSlotInfo> {
|
||||
self.parent_slot
|
||||
}
|
||||
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>) {
|
||||
self.parent_slot = info;
|
||||
}
|
||||
fn damage(&self) -> &Option<f32> {
|
||||
&self.damage
|
||||
}
|
||||
fn damage_mut(&mut self) -> &mut Option<f32> {
|
||||
&mut self.damage
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use GWItem;
|
||||
|
||||
macro_rules! GWSuit {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWSuit for $struct {
|
||||
fn suit_info(&self) -> &SuitInfo {
|
||||
&self.suit_info
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use GWSuit;
|
||||
|
||||
macro_rules! GWCircuitHolderItem {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWCircuitHolder for $struct {
|
||||
type Holder = ItemCircuitHolder;
|
||||
fn gw_get_error(&self) -> i32 {
|
||||
self.error
|
||||
}
|
||||
fn gw_set_error(&mut self, state: i32) {
|
||||
self.error = state;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use GWCircuitHolderItem;
|
||||
|
||||
macro_rules! GWCircuitHolderSuit {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWCircuitHolder for $struct {
|
||||
type Holder = SuitCircuitHolder;
|
||||
fn gw_get_error(&self) -> i32 {
|
||||
self.error
|
||||
}
|
||||
fn gw_set_error(&mut self, state: i32) {
|
||||
self.error = state;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use GWCircuitHolderSuit;
|
||||
|
||||
macro_rules! GWCircuitHolderDevice {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWCircuitHolder for $struct {
|
||||
type Holder = DeviceCircuitHolder;
|
||||
fn gw_get_error(&self) -> i32 {
|
||||
self.error
|
||||
}
|
||||
fn gw_set_error(&mut self, state: i32) {
|
||||
self.error = state;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use GWCircuitHolderDevice;
|
||||
|
||||
macro_rules! GWReagentConsumer {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWReagentConsumer for $struct {
|
||||
fn consumer_info(&self) -> &ConsumerInfo {
|
||||
&self.consumer_info
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use GWReagentConsumer;
|
||||
|
||||
macro_rules! GWReagentRequirer {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWReagentRequirer for $struct {
|
||||
fn get_current_recipe_gw(&self) -> Option<(u32, u32)> {
|
||||
self.current_recipe
|
||||
}
|
||||
fn get_fab_info_gw(&self) -> Option<&FabricatorInfo> {
|
||||
self.fabricator_info.as_ref()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use GWReagentRequirer;
|
||||
|
||||
macro_rules! GWFabricator {
|
||||
(
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
impl GWFabricator for $struct {
|
||||
fn is_fabricator(&self) -> bool {
|
||||
self.fabricator_info.is_some()
|
||||
}
|
||||
fn fabricator_info(&self) -> &FabricatorInfo {
|
||||
self.fabricator_info
|
||||
.as_ref()
|
||||
.expect("GWFabricator::fabricator_info call on non Fabricator")
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use GWFabricator;
|
||||
621
ic10emu/src/vm/object/generic/structs.rs
Normal file
@@ -0,0 +1,621 @@
|
||||
use super::{macros::*, traits::*};
|
||||
|
||||
use crate::{
|
||||
network::Connection,
|
||||
vm::{
|
||||
object::{macros::ObjectInterface, traits::*, LogicField, Name, ObjectID, Slot},
|
||||
VM,
|
||||
},
|
||||
};
|
||||
use macro_rules_attribute::derive;
|
||||
use stationeers_data::{
|
||||
enums::script::LogicType,
|
||||
templates::{
|
||||
ConsumerInfo, DeviceInfo, FabricatorInfo, InternalAtmoInfo, ItemInfo, SuitInfo, ThermalInfo,
|
||||
},
|
||||
};
|
||||
use std::{collections::BTreeMap, rc::Rc};
|
||||
|
||||
#[derive(ObjectInterface!, GWThermal!, GWInternalAtmo!, GWStructure!)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Structure
|
||||
}))]
|
||||
pub struct Generic {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub small_grid: bool,
|
||||
}
|
||||
|
||||
#[derive(ObjectInterface!, GWThermal!, GWInternalAtmo!, GWStructure!, GWStorage!)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Structure, Storage
|
||||
}))]
|
||||
pub struct GenericStorage {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub small_grid: bool,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!,
|
||||
GWThermal!, GWInternalAtmo!,
|
||||
GWStructure!, GWStorage!, GWLogicable!
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Structure, Storage, Logicable
|
||||
}))]
|
||||
pub struct GenericLogicable {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub small_grid: bool,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
pub modes: Option<BTreeMap<u32, String>>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!,
|
||||
GWThermal!, GWInternalAtmo!,
|
||||
GWStructure!, GWStorage!, GWLogicable!,
|
||||
GWDevice!
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Structure, Storage, Logicable, Device
|
||||
}))]
|
||||
pub struct GenericLogicableDevice {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub small_grid: bool,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
pub modes: Option<BTreeMap<u32, String>>,
|
||||
pub device_info: DeviceInfo,
|
||||
pub connections: Vec<Connection>,
|
||||
pub pins: Option<Vec<Option<ObjectID>>>,
|
||||
pub reagents: Option<BTreeMap<u8, f64>>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!,
|
||||
GWThermal!, GWInternalAtmo!,
|
||||
GWStructure!, GWStorage!, GWLogicable!,
|
||||
GWDevice!, GWCircuitHolderDevice!
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Structure, Storage, Logicable, Device,
|
||||
CircuitHolder
|
||||
}))]
|
||||
pub struct GenericCircuitHolder {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub small_grid: bool,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
pub modes: Option<BTreeMap<u32, String>>,
|
||||
pub device_info: DeviceInfo,
|
||||
pub connections: Vec<Connection>,
|
||||
pub pins: Option<Vec<Option<ObjectID>>>,
|
||||
pub reagents: Option<BTreeMap<u8, f64>>,
|
||||
pub error: i32,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!,
|
||||
GWThermal!, GWInternalAtmo!,
|
||||
GWStructure!, GWStorage!, GWLogicable!,
|
||||
GWDevice!, GWReagentConsumer!,
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Structure, Storage, Logicable, Device, ReagentConsumer
|
||||
}))]
|
||||
pub struct GenericLogicableDeviceConsumer {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub small_grid: bool,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
pub modes: Option<BTreeMap<u32, String>>,
|
||||
pub device_info: DeviceInfo,
|
||||
pub connections: Vec<Connection>,
|
||||
pub pins: Option<Vec<Option<ObjectID>>>,
|
||||
pub reagents: Option<BTreeMap<u8, f64>>,
|
||||
pub consumer_info: ConsumerInfo,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!,
|
||||
GWThermal!, GWInternalAtmo!,
|
||||
GWStructure!, GWStorage!,
|
||||
GWLogicable!, GWDevice!,
|
||||
GWMemoryReadable!, GWMemoryWritable!
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Structure, Storage, Logicable, Device, MemoryReadable
|
||||
}))]
|
||||
pub struct GenericLogicableDeviceMemoryReadable {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub small_grid: bool,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
pub modes: Option<BTreeMap<u32, String>>,
|
||||
pub device_info: DeviceInfo,
|
||||
pub connections: Vec<Connection>,
|
||||
pub pins: Option<Vec<Option<ObjectID>>>,
|
||||
pub reagents: Option<BTreeMap<u8, f64>>,
|
||||
pub memory: Vec<f64>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!,
|
||||
GWThermal!, GWInternalAtmo!,
|
||||
GWStructure!, GWStorage!, GWLogicable!,
|
||||
GWDevice!, GWMemoryReadable!, GWMemoryWritable!,
|
||||
GWReagentConsumer!, GWReagentRequirer!, GWFabricator!,
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Structure, Storage, Logicable, Device, MemoryReadable,
|
||||
ReagentConsumer, ReagentRequirer,
|
||||
Fabricator[GWFabricator::is_fabricator]
|
||||
}))]
|
||||
pub struct GenericLogicableDeviceConsumerMemoryReadable {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub small_grid: bool,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
pub modes: Option<BTreeMap<u32, String>>,
|
||||
pub device_info: DeviceInfo,
|
||||
pub connections: Vec<Connection>,
|
||||
pub pins: Option<Vec<Option<ObjectID>>>,
|
||||
pub reagents: Option<BTreeMap<u8, f64>>,
|
||||
pub consumer_info: ConsumerInfo,
|
||||
pub fabricator_info: Option<FabricatorInfo>,
|
||||
/// (fabricator_info.recipes index, quantity)
|
||||
pub current_recipe: Option<(u32, u32)>,
|
||||
pub memory: Vec<f64>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!,
|
||||
GWThermal!, GWInternalAtmo!,
|
||||
GWStructure!, GWStorage!,
|
||||
GWLogicable!, GWDevice!, GWMemoryReadable!, GWMemoryWritable!
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Structure, Storage, Logicable, Device, MemoryReadable, MemoryWritable
|
||||
}))]
|
||||
pub struct GenericLogicableDeviceMemoryReadWriteable {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub small_grid: bool,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
pub modes: Option<BTreeMap<u32, String>>,
|
||||
pub device_info: DeviceInfo,
|
||||
pub connections: Vec<Connection>,
|
||||
pub pins: Option<Vec<Option<ObjectID>>>,
|
||||
pub reagents: Option<BTreeMap<u8, f64>>,
|
||||
pub memory: Vec<f64>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!,
|
||||
GWThermal!, GWInternalAtmo!,
|
||||
GWStructure!, GWStorage!, GWLogicable!,
|
||||
GWDevice!, GWMemoryReadable!, GWMemoryWritable!,
|
||||
GWReagentConsumer!, GWReagentRequirer!, GWFabricator!,
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Structure, Storage, Logicable, Device, MemoryReadable, MemoryWritable,
|
||||
ReagentConsumer, ReagentRequirer,
|
||||
Fabricator[GWFabricator::is_fabricator]
|
||||
}))]
|
||||
pub struct GenericLogicableDeviceConsumerMemoryReadWriteable {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub small_grid: bool,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
pub modes: Option<BTreeMap<u32, String>>,
|
||||
pub device_info: DeviceInfo,
|
||||
pub connections: Vec<Connection>,
|
||||
pub pins: Option<Vec<Option<ObjectID>>>,
|
||||
pub reagents: Option<BTreeMap<u8, f64>>,
|
||||
pub consumer_info: ConsumerInfo,
|
||||
pub fabricator_info: Option<FabricatorInfo>,
|
||||
// index of target recipe in fabricator_info
|
||||
pub current_recipe: Option<(u32, u32)>,
|
||||
pub memory: Vec<f64>,
|
||||
}
|
||||
|
||||
#[derive(ObjectInterface!, GWThermal!, GWInternalAtmo!, GWItem!)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Item
|
||||
}))]
|
||||
pub struct GenericItem {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub item_info: ItemInfo,
|
||||
pub parent_slot: Option<ParentSlotInfo>,
|
||||
pub damage: Option<f32>,
|
||||
}
|
||||
|
||||
#[derive(ObjectInterface!, GWThermal!, GWInternalAtmo!, GWItem!, GWStorage! )]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Item, Storage
|
||||
}))]
|
||||
pub struct GenericItemStorage {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub item_info: ItemInfo,
|
||||
pub parent_slot: Option<ParentSlotInfo>,
|
||||
pub damage: Option<f32>,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!, GWThermal!,
|
||||
GWInternalAtmo!, GWItem!, GWStorage!,
|
||||
GWReagentConsumer!
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Item, Storage, ReagentConsumer
|
||||
}))]
|
||||
pub struct GenericItemConsumer {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub item_info: ItemInfo,
|
||||
pub parent_slot: Option<ParentSlotInfo>,
|
||||
pub damage: Option<f32>,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub consumer_info: ConsumerInfo,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!,
|
||||
GWThermal!, GWInternalAtmo!,
|
||||
GWItem!, GWStorage!, GWLogicable!
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Item, Storage, Logicable
|
||||
}))]
|
||||
pub struct GenericItemLogicable {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub item_info: ItemInfo,
|
||||
pub parent_slot: Option<ParentSlotInfo>,
|
||||
pub damage: Option<f32>,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
pub modes: Option<BTreeMap<u32, String>>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!,
|
||||
GWThermal!, GWInternalAtmo!,
|
||||
GWItem!, GWStorage!, GWLogicable!,
|
||||
GWMemoryReadable!
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Item, Storage, Logicable, MemoryReadable
|
||||
}))]
|
||||
pub struct GenericItemLogicableMemoryReadable {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub item_info: ItemInfo,
|
||||
pub parent_slot: Option<ParentSlotInfo>,
|
||||
pub damage: Option<f32>,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
pub modes: Option<BTreeMap<u32, String>>,
|
||||
pub memory: Vec<f64>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!,
|
||||
GWThermal!, GWInternalAtmo!,
|
||||
GWItem!, GWStorage!, GWLogicable!,
|
||||
GWMemoryReadable!, GWMemoryWritable!
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Item, Storage, Logicable, MemoryReadable, MemoryWritable
|
||||
}))]
|
||||
pub struct GenericItemLogicableMemoryReadWriteable {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub item_info: ItemInfo,
|
||||
pub parent_slot: Option<ParentSlotInfo>,
|
||||
pub damage: Option<f32>,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
pub modes: Option<BTreeMap<u32, String>>,
|
||||
pub memory: Vec<f64>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!,
|
||||
GWThermal!, GWInternalAtmo!,
|
||||
GWItem!, GWStorage!, GWLogicable!,
|
||||
GWCircuitHolderItem!
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Item, Storage, Logicable,
|
||||
CircuitHolder
|
||||
}))]
|
||||
pub struct GenericItemCircuitHolder {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub item_info: ItemInfo,
|
||||
pub parent_slot: Option<ParentSlotInfo>,
|
||||
pub damage: Option<f32>,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
pub modes: Option<BTreeMap<u32, String>>,
|
||||
pub error: i32,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!,
|
||||
GWThermal!, GWInternalAtmo!,
|
||||
GWItem!, GWStorage!, GWLogicable!,
|
||||
GWSuit!
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Item, Storage, Suit, Logicable
|
||||
}))]
|
||||
pub struct GenericItemSuitLogic {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub item_info: ItemInfo,
|
||||
pub parent_slot: Option<ParentSlotInfo>,
|
||||
pub damage: Option<f32>,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub suit_info: SuitInfo,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
pub modes: Option<BTreeMap<u32, String>>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!,
|
||||
GWThermal!, GWInternalAtmo!,
|
||||
GWItem!, GWStorage!, GWLogicable!,
|
||||
GWMemoryReadable!, GWMemoryWritable!,
|
||||
GWSuit!, GWCircuitHolderSuit!
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Item, Storage, Suit, Logicable, MemoryReadable, MemoryWritable,
|
||||
CircuitHolder
|
||||
}))]
|
||||
pub struct GenericItemSuitCircuitHolder {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub item_info: ItemInfo,
|
||||
pub parent_slot: Option<ParentSlotInfo>,
|
||||
pub damage: Option<f32>,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub suit_info: SuitInfo,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
pub modes: Option<BTreeMap<u32, String>>,
|
||||
pub memory: Vec<f64>,
|
||||
pub error: i32,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
ObjectInterface!,
|
||||
GWThermal!, GWInternalAtmo!,
|
||||
GWItem!, GWStorage!, GWSuit!
|
||||
)]
|
||||
#[custom(implements(Object {
|
||||
Thermal[GWThermal::is_thermal],
|
||||
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
|
||||
Item, Storage, Suit
|
||||
}))]
|
||||
pub struct GenericItemSuit {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub item_info: ItemInfo,
|
||||
pub parent_slot: Option<ParentSlotInfo>,
|
||||
pub damage: Option<f32>,
|
||||
pub slots: BTreeMap<u32, Slot>,
|
||||
pub suit_info: SuitInfo,
|
||||
}
|
||||
1347
ic10emu/src/vm/object/generic/traits.rs
Normal file
423
ic10emu/src/vm/object/humans.rs
Normal file
@@ -0,0 +1,423 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use macro_rules_attribute::derive;
|
||||
use stationeers_data::enums::{basic::Class, Species};
|
||||
#[cfg(feature = "tsify")]
|
||||
use tsify::Tsify;
|
||||
#[cfg(feature = "tsify")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use crate::vm::{
|
||||
object::{
|
||||
macros::ObjectInterface,
|
||||
traits::{
|
||||
Human, HumanRef, HumanRefMut, Object, StatState, Storage, StorageRef, StorageRefMut,
|
||||
Thermal,
|
||||
},
|
||||
Name, ObjectID, Slot, SlotOccupantInfo,
|
||||
},
|
||||
VM,
|
||||
};
|
||||
|
||||
static MAX_NUTRITION: f32 = 50.0;
|
||||
// static FULL_NUTRITION: f32 = 45.0;
|
||||
static WARNING_NUTRITION: f32 = 15.0;
|
||||
static CRITICAL_NUTRITION: f32 = 5.0;
|
||||
|
||||
static MAX_HYDRATION: f32 = 8.75;
|
||||
static WARNING_HYDRATION: f32 = 2.0;
|
||||
static CRITICAL_HYDRATION: f32 = 1.0;
|
||||
|
||||
static MAX_OXYGENATION: f32 = 0.024;
|
||||
|
||||
static MAX_FOOD_QUALITY: f32 = 1.0;
|
||||
|
||||
static MAX_MOOD: f32 = 1.0;
|
||||
static WARNING_MOOD: f32 = 0.5;
|
||||
static CRITICAL_MOOD: f32 = 0.0;
|
||||
|
||||
static MAX_HYGIENE: f32 = 1.25;
|
||||
static WARNING_HYGIENE: f32 = 0.25;
|
||||
static CRITICAL_HYGIENE: f32 = 0.0;
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(ObjectInterface!)]
|
||||
#[custom(implements(Object {
|
||||
Human, Storage
|
||||
}))]
|
||||
pub struct HumanPlayer {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: std::rc::Rc<VM>,
|
||||
|
||||
pub species: Species,
|
||||
|
||||
pub damage: f32,
|
||||
pub hydration: f32,
|
||||
pub nutrition: f32,
|
||||
pub oxygenation: f32,
|
||||
pub food_quality: f32,
|
||||
pub mood: f32,
|
||||
pub hygiene: f32,
|
||||
|
||||
left_hand_slot: Slot,
|
||||
right_hand_slot: Slot,
|
||||
suit_slot: Slot,
|
||||
helmet_slot: Slot,
|
||||
glasses_slot: Slot,
|
||||
backpack_slot: Slot,
|
||||
uniform_slot: Slot,
|
||||
toolbelt_slot: Slot,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct EntityInfo {
|
||||
pub hydration: f32,
|
||||
pub nutrition: f32,
|
||||
pub oxygenation: f32,
|
||||
pub food_quality: f32,
|
||||
pub mood: f32,
|
||||
pub hygiene: f32,
|
||||
}
|
||||
|
||||
impl HumanPlayer {
|
||||
pub fn new(id: ObjectID, vm: std::rc::Rc<VM>) -> Self {
|
||||
HumanPlayer {
|
||||
id,
|
||||
prefab: Name::new(""),
|
||||
name: Name::new(""),
|
||||
vm,
|
||||
species: Species::Human,
|
||||
damage: 0.0,
|
||||
hydration: 5.0,
|
||||
nutrition: 50.0,
|
||||
oxygenation: 0.024,
|
||||
food_quality: 0.75,
|
||||
mood: 1.0,
|
||||
hygiene: 1.0,
|
||||
left_hand_slot: Slot::new(id, 0, "LeftHand".to_string(), Class::None),
|
||||
right_hand_slot: Slot::new(id, 1, "RightHand".to_string(), Class::None),
|
||||
suit_slot: Slot::new(id, 2, "Suit".to_string(), Class::Suit),
|
||||
helmet_slot: Slot::new(id, 3, "Helmet".to_string(), Class::Helmet),
|
||||
glasses_slot: Slot::new(id, 4, "Glasses".to_string(), Class::Glasses),
|
||||
backpack_slot: Slot::new(id, 5, "Back".to_string(), Class::Back),
|
||||
uniform_slot: Slot::new(id, 6, "Uniform".to_string(), Class::Uniform),
|
||||
toolbelt_slot: Slot::new(id, 7, "Belt".to_string(), Class::Belt),
|
||||
}
|
||||
}
|
||||
pub fn with_species(id: ObjectID, vm: std::rc::Rc<VM>, species: Species) -> Self {
|
||||
let uniform_slot = if species == Species::Robot {
|
||||
Slot::new(id, 6, "Battery".to_string(), Class::Battery)
|
||||
} else {
|
||||
Slot::new(id, 6, "Uniform".to_string(), Class::Uniform)
|
||||
};
|
||||
HumanPlayer {
|
||||
id,
|
||||
prefab: Name::new(""),
|
||||
name: Name::new(""),
|
||||
vm,
|
||||
species,
|
||||
damage: 0.0,
|
||||
hydration: 5.0,
|
||||
nutrition: 50.0,
|
||||
oxygenation: 0.024,
|
||||
food_quality: 0.75,
|
||||
mood: 1.0,
|
||||
hygiene: 1.0,
|
||||
left_hand_slot: Slot::new(id, 0, "LeftHand".to_string(), Class::None),
|
||||
right_hand_slot: Slot::new(id, 1, "RightHand".to_string(), Class::None),
|
||||
suit_slot: Slot::new(id, 2, "Suit".to_string(), Class::Suit),
|
||||
helmet_slot: Slot::new(id, 3, "Helmet".to_string(), Class::Helmet),
|
||||
glasses_slot: Slot::new(id, 4, "Glasses".to_string(), Class::Glasses),
|
||||
backpack_slot: Slot::new(id, 5, "Back".to_string(), Class::Back),
|
||||
uniform_slot,
|
||||
toolbelt_slot: Slot::new(id, 7, "Belt".to_string(), Class::Belt),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_entity_info(&mut self, info: &EntityInfo) {
|
||||
self.hydration = info.hydration;
|
||||
self.nutrition = info.nutrition;
|
||||
self.oxygenation = info.oxygenation;
|
||||
self.food_quality = info.food_quality;
|
||||
self.mood = info.mood;
|
||||
self.hygiene = info.hygiene;
|
||||
}
|
||||
|
||||
pub fn update_slots_from_info(&mut self, info: &BTreeMap<u32, SlotOccupantInfo>) {
|
||||
for (index, slot_info) in info {
|
||||
match index {
|
||||
0 => {
|
||||
self.left_hand_slot.occupant.replace(slot_info.clone());
|
||||
}
|
||||
1 => {
|
||||
self.right_hand_slot.occupant.replace(slot_info.clone());
|
||||
}
|
||||
2 => {
|
||||
self.helmet_slot.occupant.replace(slot_info.clone());
|
||||
}
|
||||
3 => {
|
||||
self.suit_slot.occupant.replace(slot_info.clone());
|
||||
}
|
||||
4 => {
|
||||
self.backpack_slot.occupant.replace(slot_info.clone());
|
||||
}
|
||||
5 => {
|
||||
self.uniform_slot.occupant.replace(slot_info.clone());
|
||||
}
|
||||
6 => {
|
||||
self.toolbelt_slot.occupant.replace(slot_info.clone());
|
||||
}
|
||||
7 => {
|
||||
self.glasses_slot.occupant.replace(slot_info.clone());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Thermal for HumanPlayer {
|
||||
fn get_radiation_factor(&self) -> f32 {
|
||||
0.1
|
||||
}
|
||||
fn get_convection_factor(&self) -> f32 {
|
||||
0.1
|
||||
}
|
||||
fn debug_thermal(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"radiation: {}, convection: {}",
|
||||
self.get_radiation_factor(),
|
||||
self.get_convection_factor()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Storage for HumanPlayer {
|
||||
fn debug_storage(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "slots: {:?}", self.get_slots())
|
||||
}
|
||||
fn get_slots(&self) -> Vec<(usize, &Slot)> {
|
||||
vec![
|
||||
(0, &self.left_hand_slot),
|
||||
(1, &self.right_hand_slot),
|
||||
(2, &self.helmet_slot),
|
||||
(3, &self.suit_slot),
|
||||
(4, &self.backpack_slot),
|
||||
(5, &self.uniform_slot),
|
||||
(6, &self.toolbelt_slot),
|
||||
(7, &self.glasses_slot),
|
||||
]
|
||||
}
|
||||
|
||||
fn get_slots_mut(&mut self) -> Vec<(usize, &mut Slot)> {
|
||||
vec![
|
||||
(0, &mut self.left_hand_slot),
|
||||
(1, &mut self.right_hand_slot),
|
||||
(2, &mut self.helmet_slot),
|
||||
(3, &mut self.suit_slot),
|
||||
(4, &mut self.backpack_slot),
|
||||
(5, &mut self.uniform_slot),
|
||||
(6, &mut self.toolbelt_slot),
|
||||
(7, &mut self.glasses_slot),
|
||||
]
|
||||
}
|
||||
|
||||
fn slots_count(&self) -> usize {
|
||||
8
|
||||
}
|
||||
|
||||
fn get_slot(&self, index: usize) -> Option<&Slot> {
|
||||
match index {
|
||||
0 => Some(&self.left_hand_slot),
|
||||
1 => Some(&self.right_hand_slot),
|
||||
2 => Some(&self.helmet_slot),
|
||||
3 => Some(&self.suit_slot),
|
||||
4 => Some(&self.backpack_slot),
|
||||
5 => Some(&self.uniform_slot),
|
||||
6 => Some(&self.toolbelt_slot),
|
||||
7 => Some(&self.glasses_slot),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn get_slot_mut(&mut self, index: usize) -> Option<&mut Slot> {
|
||||
match index {
|
||||
0 => Some(&mut self.left_hand_slot),
|
||||
1 => Some(&mut self.right_hand_slot),
|
||||
2 => Some(&mut self.helmet_slot),
|
||||
3 => Some(&mut self.suit_slot),
|
||||
4 => Some(&mut self.backpack_slot),
|
||||
5 => Some(&mut self.uniform_slot),
|
||||
6 => Some(&mut self.toolbelt_slot),
|
||||
7 => Some(&mut self.glasses_slot),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Human for HumanPlayer {
|
||||
fn debug_human(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "species: {:?}, damage: {}, hydration: {}, nutrition:, {}, oxygenation: {}, food_quality: {}, mood: {}, hygiene: {}, artificial: {}, battery: {:?}",
|
||||
self.get_species(),
|
||||
self.get_damage(),
|
||||
self.get_hydration(),
|
||||
self.get_nutrition(),
|
||||
self.get_oxygenation(),
|
||||
self.get_food_quality(),
|
||||
self.get_mood(),
|
||||
self.get_hygiene(),
|
||||
self.is_artificial(),
|
||||
self.robot_battery()
|
||||
)
|
||||
}
|
||||
fn get_species(&self) -> Species {
|
||||
self.species
|
||||
}
|
||||
fn get_damage(&self) -> f32 {
|
||||
self.damage
|
||||
}
|
||||
fn set_damage(&mut self, damage: f32) {
|
||||
self.damage = damage;
|
||||
}
|
||||
fn get_hydration(&self) -> f32 {
|
||||
self.hydration
|
||||
}
|
||||
fn set_hydration(&mut self, hydration: f32) {
|
||||
self.hydration = hydration.clamp(0.0, MAX_HYDRATION);
|
||||
}
|
||||
fn hydration_state(&self) -> super::traits::StatState {
|
||||
if self.hydration < CRITICAL_HYDRATION {
|
||||
return StatState::Critical;
|
||||
}
|
||||
if self.hydration < WARNING_HYDRATION {
|
||||
return StatState::Warning;
|
||||
}
|
||||
StatState::Normal
|
||||
}
|
||||
fn get_nutrition(&self) -> f32 {
|
||||
self.nutrition
|
||||
}
|
||||
fn set_nutrition(&mut self, nutrition: f32) {
|
||||
self.nutrition = nutrition.clamp(0.0, MAX_NUTRITION);
|
||||
}
|
||||
fn nutrition_state(&self) -> StatState {
|
||||
if self.nutrition < CRITICAL_NUTRITION {
|
||||
return StatState::Critical;
|
||||
}
|
||||
if self.nutrition < WARNING_NUTRITION {
|
||||
return StatState::Warning;
|
||||
}
|
||||
StatState::Normal
|
||||
}
|
||||
fn get_oxygenation(&self) -> f32 {
|
||||
self.oxygenation
|
||||
}
|
||||
fn set_oxygenation(&mut self, oxygenation: f32) {
|
||||
self.oxygenation = oxygenation.clamp(0.0, MAX_OXYGENATION);
|
||||
}
|
||||
fn get_food_quality(&self) -> f32 {
|
||||
self.food_quality
|
||||
}
|
||||
fn set_food_quality(&mut self, quality: f32) {
|
||||
self.food_quality = quality.clamp(0.0, MAX_FOOD_QUALITY);
|
||||
}
|
||||
fn get_mood(&self) -> f32 {
|
||||
self.mood
|
||||
}
|
||||
fn set_mood(&mut self, mood: f32) {
|
||||
self.mood = mood.clamp(0.0, MAX_MOOD);
|
||||
}
|
||||
fn mood_state(&self) -> StatState {
|
||||
if self.mood < CRITICAL_MOOD {
|
||||
return StatState::Critical;
|
||||
}
|
||||
if self.mood < WARNING_MOOD {
|
||||
return StatState::Warning;
|
||||
}
|
||||
StatState::Normal
|
||||
}
|
||||
fn get_hygiene(&self) -> f32 {
|
||||
self.hygiene
|
||||
}
|
||||
fn set_hygiene(&mut self, hygiene: f32) {
|
||||
self.hygiene = hygiene.clamp(0.0, MAX_HYGIENE);
|
||||
}
|
||||
fn hygiene_state(&self) -> StatState {
|
||||
if self.hygiene < CRITICAL_HYGIENE {
|
||||
return StatState::Critical;
|
||||
}
|
||||
if self.hygiene < WARNING_HYGIENE {
|
||||
return StatState::Warning;
|
||||
}
|
||||
StatState::Normal
|
||||
}
|
||||
fn is_artificial(&self) -> bool {
|
||||
self.species == Species::Robot
|
||||
}
|
||||
fn robot_battery(&self) -> Option<super::VMObject> {
|
||||
if self.species != Species::Robot {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.uniform_slot()
|
||||
.occupant
|
||||
.as_ref()
|
||||
.and_then(|info| self.vm.get_object(info.id))
|
||||
}
|
||||
fn suit_slot(&self) -> &Slot {
|
||||
&self.suit_slot
|
||||
}
|
||||
fn suit_slot_mut(&mut self) -> &mut Slot {
|
||||
&mut self.suit_slot
|
||||
}
|
||||
fn helmet_slot(&self) -> &Slot {
|
||||
&self.helmet_slot
|
||||
}
|
||||
fn helmet_slot_mut(&mut self) -> &mut Slot {
|
||||
&mut self.helmet_slot
|
||||
}
|
||||
fn glasses_slot(&self) -> &Slot {
|
||||
&self.glasses_slot
|
||||
}
|
||||
fn glasses_slot_mut(&mut self) -> &mut Slot {
|
||||
&mut self.glasses_slot
|
||||
}
|
||||
fn backpack_slot(&self) -> &Slot {
|
||||
&self.backpack_slot
|
||||
}
|
||||
fn backpack_slot_mut(&mut self) -> &mut Slot {
|
||||
&mut self.backpack_slot
|
||||
}
|
||||
fn uniform_slot(&self) -> &Slot {
|
||||
&self.uniform_slot
|
||||
}
|
||||
fn uniform_slot_mut(&mut self) -> &mut Slot {
|
||||
&mut self.uniform_slot
|
||||
}
|
||||
fn toolbelt_slot(&self) -> &Slot {
|
||||
&self.toolbelt_slot
|
||||
}
|
||||
fn toolbelt_slot_mut(&mut self) -> &mut Slot {
|
||||
&mut self.toolbelt_slot
|
||||
}
|
||||
fn left_hand_slot(&self) -> &Slot {
|
||||
&self.left_hand_slot
|
||||
}
|
||||
fn left_hand_slot_mut(&mut self) -> &mut Slot {
|
||||
&mut self.left_hand_slot
|
||||
}
|
||||
fn right_hand_slot(&self) -> &Slot {
|
||||
&self.right_hand_slot
|
||||
}
|
||||
fn right_hand_slot_mut(&mut self) -> &mut Slot {
|
||||
&mut self.right_hand_slot
|
||||
}
|
||||
}
|
||||
594
ic10emu/src/vm/object/macros.rs
Normal file
@@ -0,0 +1,594 @@
|
||||
macro_rules! object_trait {
|
||||
(@intf {$trt:ident}) => {
|
||||
paste::paste! {
|
||||
#[allow(missing_docs, unused)]
|
||||
pub type [<$trt Ref>]<'a> = &'a dyn $trt;
|
||||
#[allow(missing_docs, unused)]
|
||||
pub type [<$trt RefMut>]<'a> = &'a mut dyn $trt;
|
||||
}
|
||||
};
|
||||
(@body $trait_name:ident { $($trt:ident),* }; ) => {
|
||||
fn get_id(&self) -> &crate::vm::object::ObjectID;
|
||||
fn set_id(&mut self, id: crate::vm::object::ObjectID);
|
||||
fn get_prefab(&self) -> &crate::vm::object::Name;
|
||||
fn get_mut_prefab(&mut self) -> &mut crate::vm::object::Name;
|
||||
fn get_name(&self) -> &crate::vm::object::Name;
|
||||
fn get_mut_name(&mut self) -> &mut crate::vm::object::Name;
|
||||
fn get_vm(&self) -> &std::rc::Rc<crate::vm::VM>;
|
||||
fn set_vm(&mut self, vm: std::rc::Rc<crate::vm::VM>);
|
||||
fn type_name(&self) -> &str;
|
||||
fn as_object(&self) -> &dyn $trait_name;
|
||||
fn as_mut_object(&mut self) -> &mut dyn $trait_name;
|
||||
|
||||
paste::paste! {
|
||||
$(
|
||||
#[doc = "Return a `& dyn " $trt "` if implemented by the object"]
|
||||
#[inline(always)]
|
||||
fn [<as_ $trt:snake>](&self) -> Option<[<$trt Ref>]> {
|
||||
None
|
||||
}
|
||||
|
||||
#[doc = "Return a `&mut dyn " $trt "` if implemented by the object"]
|
||||
#[inline(always)]
|
||||
fn [<as_mut_ $trt:snake>](&mut self) -> Option<[<$trt RefMut>]> {
|
||||
None
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
(@intf_struct $trait_name:ident { $($trt:ident),* };) => {
|
||||
paste::paste! {
|
||||
pub struct [<$trait_name Interfaces>]<'a> {
|
||||
$(
|
||||
pub [<$trt:snake>]: Option<[<$trt Ref>]<'a>>,
|
||||
)*
|
||||
}
|
||||
|
||||
impl<'a> [<$trait_name Interfaces>]<'a> {
|
||||
|
||||
pub fn [<from_ $trait_name:snake>](obj: &'a dyn $trait_name) -> [<$trait_name Interfaces>]<'a> {
|
||||
[<$trait_name Interfaces>] {
|
||||
$(
|
||||
[<$trt:snake>]: obj.[<as_ $trt:snake>](),
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Debug for [<$trait_name Interfaces>]<'a> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
$(
|
||||
write!(f, "{}: {:?}, ", stringify!([<$trt:snake>]), &self.[<$trt:snake>])?;
|
||||
)*
|
||||
write!(f, "")
|
||||
}
|
||||
}
|
||||
|
||||
pub enum [<$trait_name Ref>]<'a> {
|
||||
DynRef(&'a dyn $trait_name),
|
||||
VMObject(crate::vm::object::VMObject),
|
||||
}
|
||||
|
||||
impl<'a> [<$trait_name Ref>]<'a> {
|
||||
pub fn from_ref(reference: &'a dyn $trait_name) -> Self {
|
||||
Self::DynRef(reference)
|
||||
}
|
||||
pub fn from_vm_object(obj: crate::vm::object::VMObject) -> Self {
|
||||
Self::VMObject(obj)
|
||||
}
|
||||
pub fn get_id(&self) -> u32 {
|
||||
match self {
|
||||
Self::DynRef(reference) => *reference.get_id(),
|
||||
Self::VMObject(obj) => *obj.borrow().get_id(),
|
||||
|
||||
}
|
||||
}
|
||||
/// call func on the dyn reference or a borrow of the vm object
|
||||
pub fn map<F, R>(&self, mut func: F ) -> R
|
||||
where
|
||||
F: std::ops::FnMut(& dyn $trait_name) -> R
|
||||
{
|
||||
match self {
|
||||
Self::DynRef(reference) => func(*reference),
|
||||
Self::VMObject(obj) => {
|
||||
let obj_ref = obj.borrow();
|
||||
func(&*obj_ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum [<$trait_name RefMut>]<'a> {
|
||||
DynRef(&'a mut dyn $trait_name),
|
||||
VMObject(crate::vm::object::VMObject),
|
||||
}
|
||||
|
||||
impl<'a> [<$trait_name RefMut>]<'a> {
|
||||
pub fn from_ref(reference: &'a mut dyn $trait_name) -> Self {
|
||||
Self::DynRef(reference)
|
||||
}
|
||||
pub fn from_vm_object(obj: crate::vm::object::VMObject) -> Self {
|
||||
Self::VMObject(obj)
|
||||
}
|
||||
pub fn get_id(&self) -> u32 {
|
||||
match self {
|
||||
Self::DynRef(reference) => *reference.get_id(),
|
||||
Self::VMObject(obj) => *obj.borrow().get_id(),
|
||||
|
||||
}
|
||||
}
|
||||
/// call func on the dyn reference or a borrow of the vm object
|
||||
pub fn map<F, R>(&mut self, mut func: F ) -> R
|
||||
where
|
||||
F: std::ops::FnMut(&mut dyn $trait_name) -> R
|
||||
{
|
||||
match self {
|
||||
Self::DynRef(reference) => func(*reference),
|
||||
Self::VMObject(obj) => {
|
||||
let mut obj_ref = obj.borrow_mut();
|
||||
func(&mut *obj_ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
( $trait_name:ident $(: $($bound:tt)* )? {$($trt:ident),*}) => {
|
||||
$(
|
||||
$crate::vm::object::macros::object_trait!{@intf {$trt}}
|
||||
)*
|
||||
|
||||
|
||||
#[doc = concat!("Generated with: ", stringify!($($trt),*))]
|
||||
pub trait $trait_name $(: $($bound)* )? {
|
||||
|
||||
$crate::vm::object::macros::object_trait!{@body $trait_name {$($trt),*}; }
|
||||
}
|
||||
|
||||
$crate::vm::object::macros::object_trait!{@intf_struct $trait_name {$($trt),*}; }
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use object_trait;
|
||||
|
||||
/// use macro_rules_attribute::derive to apply this macro to a struct
|
||||
///
|
||||
/// use `#[custom(object_id)]`, `#[custom(object_prefab)]`, `#[custom(object_name)]`, and `#[custom(object_vm_ref)]`
|
||||
/// to tag struct fields appropriately
|
||||
///
|
||||
/// the tags for `id`, `prefab`, and `name` may appear in any order but `vm_ref` must come last
|
||||
///
|
||||
/// - `id` must be `crate::vm::object::ObjectID`
|
||||
/// - `prefab` and `name` must be `crate::vm::object::Name`
|
||||
/// - `vm_ref` must be `std::rc::Rc<crate::vm::VM>`
|
||||
macro_rules! ObjectInterface {
|
||||
{
|
||||
@trt_cond_impl $trt:path => $trt_cond:path
|
||||
} => {
|
||||
paste::paste!{
|
||||
#[inline(always)]
|
||||
fn [<as_ $trt:snake>](&self) -> Option<[<$trt Ref>]> {
|
||||
if $trt_cond(self) {
|
||||
Some(self)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn [<as_mut_ $trt:snake>](&mut self) -> Option<[<$trt RefMut>]> {
|
||||
if $trt_cond(self) {
|
||||
Some(self)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
{
|
||||
@trt_cond_impl $trt:path
|
||||
} => {
|
||||
paste::paste!{
|
||||
#[inline(always)]
|
||||
fn [<as_ $trt:snake>](&self) -> Option<[<$trt Ref>]> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn [<as_mut_ $trt:snake>](&mut self) -> Option<[<$trt RefMut>]> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
{
|
||||
@body_final
|
||||
@trt $trait_name:ident; $struct:ident;
|
||||
@impls $($trt:path $([ $trt_cond:path ])?),*;
|
||||
@id $id_field:ident: $id_typ:ty;
|
||||
@prefab $prefab_field:ident: $prefab_typ:ty;
|
||||
@name $name_field:ident: $name_typ:ty;
|
||||
@vm_ref $vm_ref_field:ident: $vm_ref_typ:ty;
|
||||
} => {
|
||||
impl $trait_name for $struct {
|
||||
|
||||
fn get_id(&self) -> &crate::vm::object::ObjectID {
|
||||
&self.$id_field
|
||||
}
|
||||
|
||||
fn set_id(&mut self, id: crate::vm::object::ObjectID) {
|
||||
self.$id_field = id;
|
||||
}
|
||||
|
||||
fn get_prefab(&self) -> &$prefab_typ {
|
||||
&self.$prefab_field
|
||||
}
|
||||
|
||||
fn get_mut_prefab(&mut self) -> &mut $prefab_typ {
|
||||
&mut self.$prefab_field
|
||||
}
|
||||
|
||||
fn get_name(&self) -> &$name_typ {
|
||||
&self.$name_field
|
||||
}
|
||||
|
||||
fn get_mut_name(&mut self) -> &mut $name_typ {
|
||||
&mut self.$name_field
|
||||
}
|
||||
|
||||
fn get_vm(&self) -> &std::rc::Rc<crate::vm::VM> {
|
||||
&self.$vm_ref_field
|
||||
}
|
||||
|
||||
fn set_vm(&mut self, vm: std::rc::Rc<crate::vm::VM>) {
|
||||
self.$vm_ref_field = vm;
|
||||
}
|
||||
|
||||
fn type_name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn as_object(&self) -> &dyn $trait_name {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn as_mut_object(&mut self) -> &mut dyn $trait_name {
|
||||
self
|
||||
}
|
||||
|
||||
$(
|
||||
$crate::vm::object::macros::ObjectInterface!{@trt_cond_impl $trt $( => $trt_cond)? }
|
||||
)*
|
||||
|
||||
}
|
||||
};
|
||||
{
|
||||
@body_final
|
||||
@trt $trait_name:ident; $struct:ident;
|
||||
@impls $($trt:path $([ $trt_cond:path ])?),*;
|
||||
@id $id_field:ident: $id_typ:ty;
|
||||
@name $name_field:ident: $name_typ:ty;
|
||||
@prefab $prefab_field:ident: $prefab_typ:ty;
|
||||
@vm_ref $vm_ref_field:ident: $vm_ref_typ:ty;
|
||||
} => {
|
||||
$crate::vm::object::macros::ObjectInterface!{
|
||||
@body_final
|
||||
@trt $trait_name; $struct;
|
||||
@impls $($trt $([ $trt_cond ])?),*;
|
||||
@id $id_field: $id_typ;
|
||||
@prefab $prefab_field: $prefab_typ;
|
||||
@name $name_field: $name_typ;
|
||||
@vm_ref $vm_ref_field: $vm_ref_typ;
|
||||
}
|
||||
};
|
||||
{
|
||||
@body_final
|
||||
@trt $trait_name:ident; $struct:ident;
|
||||
@impls $($trt:path $([ $trt_cond:path ])?),*;
|
||||
@prefab $prefab_field:ident: $prefab_typ:ty;
|
||||
@name $name_field:ident: $name_typ:ty;
|
||||
@id $id_field:ident: $id_typ:ty;
|
||||
@vm_ref $vm_ref_field:ident: $vm_ref_typ:ty;
|
||||
} => {
|
||||
$crate::vm::object::macros::ObjectInterface!{
|
||||
@body_final
|
||||
@trt $trait_name; $struct;
|
||||
@impls $($trt $([ $trt_cond ])?),*;
|
||||
@id $id_field: $id_typ;
|
||||
@prefab $prefab_field: $prefab_typ;
|
||||
@name $name_field: $name_typ;
|
||||
@vm_ref $vm_ref_field: $vm_ref_typ;
|
||||
}
|
||||
};
|
||||
{
|
||||
@body_final
|
||||
@trt $trait_name:ident; $struct:ident;
|
||||
@impls $($trt:path $([ $trt_cond:path ])?),*;
|
||||
@prefab $prefab_field:ident: $prefab_typ:ty;
|
||||
@id $id_field:ident: $id_typ:ty;
|
||||
@name $name_field:ident: $name_typ:ty;
|
||||
@vm_ref $vm_ref_field:ident: $vm_ref_typ:ty;
|
||||
} => {
|
||||
$crate::vm::object::macros::ObjectInterface!{
|
||||
@body_final
|
||||
@trt $trait_name; $struct;
|
||||
@impls $($trt $([ $trt_cond ])?),*;
|
||||
@id $id_field: $id_typ;
|
||||
@prefab $prefab_field: $prefab_typ;
|
||||
@name $name_field: $name_typ;
|
||||
@vm_ref $vm_ref_field: $vm_ref_typ;
|
||||
}
|
||||
};
|
||||
{
|
||||
@body_final
|
||||
@trt $trait_name:ident; $struct:ident;
|
||||
@impls $($trt:path $([ $trt_cond:path ])?),*;
|
||||
@name $name_field:ident: $name_typ:ty;
|
||||
@prefab $prefab_field:ident: $prefab_typ:ty;
|
||||
@id $id_field:ident: $id_typ:ty;
|
||||
@vm_ref $vm_ref_field:ident: $vm_ref_typ:ty;
|
||||
} => {
|
||||
$crate::vm::object::macros::ObjectInterface!{
|
||||
@body_final
|
||||
@trt $trait_name; $struct;
|
||||
@impls $($trt $([ $trt_cond ])?),*;
|
||||
@id $id_field: $id_typ;
|
||||
@prefab $prefab_field: $prefab_typ;
|
||||
@name $name_field: $name_typ;
|
||||
@vm_ref $vm_ref_field: $vm_ref_typ;
|
||||
}
|
||||
};
|
||||
{
|
||||
@body_final
|
||||
@trt $trait_name:ident; $struct:ident;
|
||||
@impls $($trt:path $([ $trt_cond:path ])?),*;
|
||||
@name $name_field:ident: $name_typ:ty;
|
||||
@id $id_field:ident: $id_typ:ty;
|
||||
@prefab $prefab_field:ident: $prefab_typ:ty;
|
||||
@vm_ref $vm_ref_field:ident: $vm_ref_typ:ty;
|
||||
} => {
|
||||
$crate::vm::object::macros::ObjectInterface!{
|
||||
@body_final
|
||||
@trt $trait_name; $struct;
|
||||
@impls $($trt $([ $trt_cond ])?),*;
|
||||
@id $id_field: $id_typ;
|
||||
@prefab $prefab_field: $prefab_typ;
|
||||
@name $name_field: $name_typ;
|
||||
@vm_ref $vm_ref_field: $vm_ref_typ;
|
||||
}
|
||||
};{
|
||||
@body
|
||||
@trt $trait_name:ident; $struct:ident;
|
||||
@impls $($trt:path $([ $trt_cond:path ])?),*;
|
||||
@tags {
|
||||
$(@$tag:tt $tag_field:ident: $tag_typ:ty;)*
|
||||
};
|
||||
#[custom(object_vm_ref)]
|
||||
$(#[$vm_ref_attr:meta])*
|
||||
$vm_ref_viz:vis $vm_ref_field:ident: $vm_ref_typ:ty,
|
||||
$( $rest:tt )*
|
||||
|
||||
} => {
|
||||
$crate::vm::object::macros::ObjectInterface!{
|
||||
@body
|
||||
@trt $trait_name; $struct;
|
||||
@impls $($trt $([ $trt_cond ])?),*;
|
||||
@tags {$(@$tag $tag_field: $tag_typ;)* @vm_ref $vm_ref_field: $vm_ref_typ;};
|
||||
$( $rest )*
|
||||
}
|
||||
};
|
||||
{
|
||||
@body
|
||||
@trt $trait_name:ident; $struct:ident;
|
||||
@impls $($trt:path $([ $trt_cond:path ])?),*;
|
||||
@tags {
|
||||
$(@$tag:tt $tag_field:ident: $tag_typ:ty;)*
|
||||
};
|
||||
#[custom(object_name)]
|
||||
$(#[$name_attr:meta])*
|
||||
$name_viz:vis $name_field:ident: $name_typ:ty,
|
||||
$( $rest:tt )*
|
||||
|
||||
} => {
|
||||
$crate::vm::object::macros::ObjectInterface!{
|
||||
@body
|
||||
@trt $trait_name; $struct;
|
||||
@impls $($trt $([ $trt_cond ])?),*;
|
||||
@tags {$(@$tag $tag_field: $tag_typ;)* @name $name_field: $name_typ;};
|
||||
$( $rest )*
|
||||
}
|
||||
};
|
||||
{
|
||||
@body
|
||||
@trt $trait_name:ident; $struct:ident;
|
||||
@impls $($trt:path $([ $trt_cond:path ])?),*;
|
||||
@tags {
|
||||
$(@$tag:tt $tag_field:ident: $tag_typ:ty;)*
|
||||
};
|
||||
#[custom(object_prefab)]
|
||||
$(#[$prefab_attr:meta])*
|
||||
$prefab_viz:vis $prefab_field:ident: $prefab_typ:ty,
|
||||
$( $rest:tt )*
|
||||
|
||||
} => {
|
||||
$crate::vm::object::macros::ObjectInterface!{
|
||||
@body
|
||||
@trt $trait_name; $struct;
|
||||
@impls $($trt $([ $trt_cond ])?),*;
|
||||
@tags {$(@$tag $tag_field: $tag_typ;)* @prefab $prefab_field: $prefab_typ;};
|
||||
$( $rest )*
|
||||
}
|
||||
};
|
||||
{
|
||||
@body
|
||||
@trt $trait_name:ident; $struct:ident;
|
||||
@impls $($trt:path $([ $trt_cond:path ])?),*;
|
||||
@tags {
|
||||
$(@$tag:tt $tag_field:ident: $tag_typ:ty;)*
|
||||
};
|
||||
#[custom(object_id)]
|
||||
$(#[$id_attr:meta])*
|
||||
$id_viz:vis $id_field:ident: $id_typ:ty,
|
||||
$( $rest:tt )*
|
||||
|
||||
} => {
|
||||
$crate::vm::object::macros::ObjectInterface!{
|
||||
@body
|
||||
@trt $trait_name; $struct;
|
||||
@impls $($trt $([ $trt_cond ])?),*;
|
||||
@tags {$(@$tag $tag_field: $tag_typ;)* @id $id_field: $id_typ;};
|
||||
$( $rest )*
|
||||
}
|
||||
};
|
||||
{
|
||||
@body
|
||||
@trt $trait_name:ident; $struct:ident;
|
||||
@impls $($trt:path $([ $trt_cond:path ])?),*;
|
||||
@tags {
|
||||
$(@$tag:tt $tag_field:ident: $tag_typ:ty;)*
|
||||
};
|
||||
$(#[$field:meta])*
|
||||
$field_viz:vis
|
||||
$field_name:ident : $field_ty:ty,
|
||||
$( $rest:tt )*
|
||||
|
||||
} => {
|
||||
$crate::vm::object::macros::ObjectInterface!{
|
||||
@body
|
||||
@trt $trait_name; $struct;
|
||||
@impls $($trt $([ $trt_cond ])?),*;
|
||||
@tags {$(@$tag $tag_field: $tag_typ;)*};
|
||||
$( $rest )*
|
||||
}
|
||||
};
|
||||
{
|
||||
@body
|
||||
@trt $trait_name:ident; $struct:ident;
|
||||
@impls $($trt:path $([ $trt_cond:path ])?),*;
|
||||
@tags {
|
||||
$(@$tag:tt $tag_field:ident: $tag_typ:ty;)*
|
||||
};
|
||||
} => {
|
||||
$crate::vm::object::macros::ObjectInterface!{
|
||||
@body_final
|
||||
@trt $trait_name; $struct;
|
||||
@impls $($trt $([ $trt_cond ])?),*;
|
||||
$(
|
||||
@$tag $tag_field: $tag_typ;
|
||||
)*
|
||||
}
|
||||
};
|
||||
{
|
||||
#[custom(implements($trait_name:ident {$($trt:path $([$trt_cond:path])?),*}))]
|
||||
$( #[$attr:meta] )*
|
||||
$viz:vis struct $struct:ident {
|
||||
$( $body:tt )*
|
||||
}
|
||||
} => {
|
||||
$crate::vm::object::macros::ObjectInterface!{
|
||||
@body
|
||||
@trt $trait_name; $struct;
|
||||
@impls $($trt $([ $trt_cond ])?),*;
|
||||
@tags {};
|
||||
$( $body )*
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use ObjectInterface;
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! ObjectTrait {
|
||||
{
|
||||
#[custom(object_trait = $trait_name:ident)]
|
||||
$(#[$attr:meta])*
|
||||
$viz:vis trait $trt:ident $(: $($bound:tt)* )? {
|
||||
$($tbody:tt)*
|
||||
}
|
||||
} => {
|
||||
$(#[$attr])*
|
||||
$viz trait $trt: $($($bound)* +)? $trait_name {
|
||||
$($tbody)*
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use ObjectTrait;
|
||||
|
||||
macro_rules! tag_object_traits {
|
||||
{
|
||||
@tag
|
||||
tag=$trt_name:ident $(: $($obj_bound:tt)* )?;
|
||||
acc={ $($tagged_trt:ident,)* };
|
||||
$(#[$attr:meta])*
|
||||
$viz:vis trait $trt:ident $(: $trt_bound_first:tt $(+ $trt_bound_others:tt)* )? {
|
||||
$($tbody:tt)*
|
||||
}
|
||||
$($used:tt)*
|
||||
} => {
|
||||
#[doc = concat!("Autotagged with ", stringify!($trt_name))]
|
||||
$(#[$attr])*
|
||||
$viz trait $trt : $( $trt_bound_first $(+ $trt_bound_others)* +)? $trt_name {
|
||||
$($tbody)*
|
||||
paste::paste! {
|
||||
fn [<debug_ $trt:snake>](&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Debug for dyn $trt + 'a {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{}{{", stringify!($trt))?;
|
||||
|
||||
paste::paste! {
|
||||
self.[<debug_ $trt:snake>](f)?;
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
}
|
||||
|
||||
$crate::vm::object::macros::tag_object_traits!{
|
||||
@tag
|
||||
tag=$trt_name $(: $($obj_bound)* )?;
|
||||
acc={ $($tagged_trt,)* $trt, };
|
||||
$($used)*
|
||||
}
|
||||
};
|
||||
{
|
||||
@tag
|
||||
tag=$trt_name:ident $(: $($obj_bound:tt)* )?;
|
||||
acc={ $($tagged_trt:ident,)* };
|
||||
impl $name:ident for $trt:path {
|
||||
$($body:tt)*
|
||||
}
|
||||
$($used:tt)*
|
||||
} => {
|
||||
/// Untouched by tag macro
|
||||
impl $name for $trt {
|
||||
$($body)*
|
||||
}
|
||||
$crate::vm::object::macros::tag_object_traits!{
|
||||
@tag
|
||||
tag=$trt_name $(: $($obj_bound)* )?;
|
||||
acc={ $($tagged_trt,)* };
|
||||
$($used)*
|
||||
}
|
||||
};
|
||||
{
|
||||
@tag
|
||||
tag=$trt_name:ident $(: $($obj_bound:tt)* )?;
|
||||
acc={ $($tagged_trt:ident,)* };
|
||||
} => {
|
||||
|
||||
// end tagged traits {$trt_name}
|
||||
|
||||
$crate::vm::object::macros::object_trait!($trt_name $(: $($obj_bound)* )? { $($tagged_trt),* });
|
||||
};
|
||||
{ #![object_trait($trt_name:ident $(: $($bound:tt)* )? )] $($tree:tt)* } => {
|
||||
$crate::vm::object::macros::tag_object_traits!{ @tag tag=$trt_name; acc={}; $($tree)* }
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use tag_object_traits;
|
||||
152
ic10emu/src/vm/object/stationpedia.rs
Normal file
@@ -0,0 +1,152 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use stationeers_data::{enums::prefabs::StationpediaPrefab, templates::ObjectTemplate};
|
||||
|
||||
use crate::{
|
||||
errors::TemplateError,
|
||||
vm::object::{
|
||||
templates::{ObjectInfo, Prefab},
|
||||
Name, VMObject,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
interpreter::Program,
|
||||
vm::{object::LogicField, VM},
|
||||
};
|
||||
use strum::EnumProperty;
|
||||
|
||||
use super::ObjectID;
|
||||
|
||||
pub mod structs;
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn object_from_frozen(
|
||||
obj: &ObjectInfo,
|
||||
id: ObjectID,
|
||||
vm: &Rc<VM>,
|
||||
) -> Result<Option<VMObject>, TemplateError> {
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
let Some(hash) = obj
|
||||
.prefab
|
||||
.as_ref()
|
||||
.map(|name| const_crc32::crc32(name.as_bytes()) as i32)
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let prefab = StationpediaPrefab::from_repr(hash);
|
||||
#[allow(clippy::match_single_binding)]
|
||||
match prefab {
|
||||
Some(prefab @ StationpediaPrefab::ItemIntegratedCircuit10) => {
|
||||
let template = vm
|
||||
.get_template(Prefab::Hash(hash))
|
||||
.ok_or(TemplateError::NoTemplateForPrefab(Prefab::Hash(hash)))?;
|
||||
let ObjectTemplate::ItemLogicMemory(template) = template else {
|
||||
return Err(TemplateError::IncorrectTemplate(
|
||||
"ItemIntegratedCircuit10".to_string(),
|
||||
Prefab::Name("ItemIntegratedCircuit10".to_string()),
|
||||
template,
|
||||
));
|
||||
};
|
||||
|
||||
Ok(Some(VMObject::new(structs::ItemIntegratedCircuit10 {
|
||||
id,
|
||||
vm: vm.clone(),
|
||||
name: Name::new(
|
||||
&(obj
|
||||
.name
|
||||
.clone()
|
||||
.unwrap_or_else(|| prefab.get_str("name").unwrap().to_string())),
|
||||
),
|
||||
prefab: Name::from_prefab_name(prefab.as_ref()),
|
||||
fields: template
|
||||
.logic
|
||||
.logic_types
|
||||
.iter()
|
||||
.map(|(key, access)| {
|
||||
(
|
||||
*key,
|
||||
LogicField {
|
||||
field_type: *access,
|
||||
value: obj
|
||||
.logic_values
|
||||
.as_ref()
|
||||
.and_then(|values| values.get(key))
|
||||
.copied()
|
||||
.unwrap_or(0.0),
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
memory: obj
|
||||
.memory
|
||||
.clone()
|
||||
.map(TryInto::try_into)
|
||||
.transpose()
|
||||
.map_err(|vec: Vec<f64>| TemplateError::MemorySize(vec.len(), 512))?
|
||||
.unwrap_or([0.0f64; 512]),
|
||||
parent_slot: None,
|
||||
registers: obj
|
||||
.circuit
|
||||
.as_ref()
|
||||
.map(|circuit| circuit.registers.clone().try_into())
|
||||
.transpose()
|
||||
.map_err(|vec: Vec<f64>| TemplateError::MemorySize(vec.len(), 18))?
|
||||
.unwrap_or([0.0f64; 18]),
|
||||
ip: obj
|
||||
.circuit
|
||||
.as_ref()
|
||||
.map(|circuit| circuit.instruction_pointer as usize)
|
||||
.unwrap_or(0),
|
||||
next_ip: 0,
|
||||
ic: obj
|
||||
.circuit
|
||||
.as_ref()
|
||||
.map(|circuit| circuit.yield_instruction_count)
|
||||
.unwrap_or(0),
|
||||
aliases: obj
|
||||
.circuit
|
||||
.as_ref()
|
||||
.map(|circuit| circuit.aliases.clone())
|
||||
.unwrap_or_default(),
|
||||
defines: obj
|
||||
.circuit
|
||||
.as_ref()
|
||||
.map(|circuit| circuit.defines.clone())
|
||||
.unwrap_or_default(),
|
||||
pins: obj
|
||||
.device_pins
|
||||
.as_ref()
|
||||
.map(|pins| {
|
||||
(0..6)
|
||||
.map(|index| pins.get(&index).copied())
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.unwrap() // fixed sized iterator into array should not panic
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
state: obj
|
||||
.circuit
|
||||
.as_ref()
|
||||
.map(|circuit| circuit.state.clone())
|
||||
.unwrap_or(crate::interpreter::ICState::Start),
|
||||
code: obj.source_code.clone().unwrap_or_default(),
|
||||
damage: obj.damage.unwrap_or(0.0),
|
||||
program: obj
|
||||
.source_code
|
||||
.as_ref()
|
||||
.map(|code| {
|
||||
if code.is_empty() {
|
||||
Program::default()
|
||||
} else {
|
||||
Program::from_code_with_invalid(code)
|
||||
}
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
})))
|
||||
}
|
||||
// Some(StationpediaPrefab::StructureCircuitHousing) => Some()
|
||||
// Some(StationpediaPrefab::StructureRocketCircuitHousing) => Some()
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
4
ic10emu/src/vm/object/stationpedia/structs.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
mod circuit_holder;
|
||||
mod integrated_circuit;
|
||||
|
||||
pub use integrated_circuit::ItemIntegratedCircuit10;
|
||||
450
ic10emu/src/vm/object/stationpedia/structs/circuit_holder.rs
Normal file
@@ -0,0 +1,450 @@
|
||||
use crate::{
|
||||
network::{CableConnectionType, Connection},
|
||||
vm::{
|
||||
object::{
|
||||
errors::LogicError, macros::ObjectInterface, traits::*, Name, ObjectID, Slot, VMObject,
|
||||
},
|
||||
VM,
|
||||
},
|
||||
};
|
||||
use macro_rules_attribute::derive;
|
||||
use stationeers_data::enums::{
|
||||
basic::Class,
|
||||
prefabs::StationpediaPrefab,
|
||||
script::{LogicSlotType, LogicType},
|
||||
ConnectionRole,
|
||||
};
|
||||
use std::{collections::BTreeMap, rc::Rc};
|
||||
use strum::EnumProperty;
|
||||
|
||||
#[derive(ObjectInterface!)]
|
||||
#[custom(implements(Object { Structure, Device, Storage, Logicable, CircuitHolder }))]
|
||||
pub struct StructureCircuitHousing {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub error: i32,
|
||||
pub on: bool,
|
||||
pub setting: f64,
|
||||
pub slot: Slot,
|
||||
pub pins: [Option<ObjectID>; 6],
|
||||
pub connections: [crate::network::Connection; 2],
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl StructureCircuitHousing {
|
||||
pub fn new(id: ObjectID, vm: Rc<VM>) -> Self {
|
||||
StructureCircuitHousing {
|
||||
id,
|
||||
prefab: Name {
|
||||
value: StationpediaPrefab::StructureCircuitHousing.to_string(),
|
||||
hash: StationpediaPrefab::StructureCircuitHousing as i32,
|
||||
},
|
||||
name: Name::new(
|
||||
StationpediaPrefab::StructureCircuitHousing
|
||||
.get_str("name")
|
||||
.unwrap(),
|
||||
),
|
||||
vm,
|
||||
error: 0,
|
||||
on: true,
|
||||
setting: 0.0,
|
||||
slot: Slot {
|
||||
parent: id,
|
||||
index: 0,
|
||||
name: "Programmable Chip".to_string(),
|
||||
class: Class::ProgrammableChip,
|
||||
readable_logic: vec![
|
||||
LogicSlotType::Class,
|
||||
LogicSlotType::Damage,
|
||||
LogicSlotType::LineNumber,
|
||||
LogicSlotType::MaxQuantity,
|
||||
LogicSlotType::OccupantHash,
|
||||
LogicSlotType::Occupied,
|
||||
LogicSlotType::PrefabHash,
|
||||
LogicSlotType::Quantity,
|
||||
LogicSlotType::ReferenceId,
|
||||
LogicSlotType::SortingClass,
|
||||
],
|
||||
writeable_logic: vec![],
|
||||
occupant: None,
|
||||
proxy: false,
|
||||
},
|
||||
pins: [None, None, None, None, None, None],
|
||||
connections: [
|
||||
Connection::CableNetwork {
|
||||
net: None,
|
||||
typ: CableConnectionType::Data,
|
||||
role: ConnectionRole::Input,
|
||||
},
|
||||
Connection::CableNetwork {
|
||||
net: None,
|
||||
typ: CableConnectionType::Power,
|
||||
role: ConnectionRole::None,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Structure for StructureCircuitHousing {
|
||||
fn is_small_grid(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn debug_structure(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "small_grid: {}", self.is_small_grid())
|
||||
}
|
||||
}
|
||||
|
||||
impl Storage for StructureCircuitHousing {
|
||||
fn debug_storage(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "slots: {:?}", self.get_slots())
|
||||
}
|
||||
fn slots_count(&self) -> usize {
|
||||
1
|
||||
}
|
||||
fn get_slot(&self, index: usize) -> Option<&Slot> {
|
||||
if index != 0 {
|
||||
None
|
||||
} else {
|
||||
Some(&self.slot)
|
||||
}
|
||||
}
|
||||
fn get_slot_mut(&mut self, index: usize) -> Option<&mut Slot> {
|
||||
if index != 0 {
|
||||
None
|
||||
} else {
|
||||
Some(&mut self.slot)
|
||||
}
|
||||
}
|
||||
fn get_slots(&self) -> Vec<(usize, &Slot)> {
|
||||
vec![(0, &self.slot)]
|
||||
}
|
||||
fn get_slots_mut(&mut self) -> Vec<(usize, &mut Slot)> {
|
||||
vec![(0, &mut self.slot)]
|
||||
}
|
||||
}
|
||||
|
||||
impl Logicable for StructureCircuitHousing {
|
||||
fn debug_logicable(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
let values: BTreeMap<LogicType, Option<f64>> = self
|
||||
.valid_logic_types()
|
||||
.into_iter()
|
||||
.map(|lt| (lt, self.get_logic(lt).ok()))
|
||||
.collect();
|
||||
write!(
|
||||
f,
|
||||
"prefab_hash: {}, name_hash: {}, readable: {}, writable: {}, values{:?}",
|
||||
self.prefab_hash(),
|
||||
self.name_hash(),
|
||||
self.is_logic_readable(),
|
||||
self.is_logic_writeable(),
|
||||
values
|
||||
)
|
||||
}
|
||||
fn prefab_hash(&self) -> i32 {
|
||||
self.get_prefab().hash
|
||||
}
|
||||
fn name_hash(&self) -> i32 {
|
||||
self.get_name().hash
|
||||
}
|
||||
fn is_logic_readable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn is_logic_writeable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn can_logic_read(&self, lt: LogicType) -> bool {
|
||||
use LogicType::*;
|
||||
matches!(
|
||||
lt,
|
||||
Error
|
||||
| LineNumber
|
||||
| NameHash
|
||||
| On
|
||||
| Power
|
||||
| PrefabHash
|
||||
| ReferenceId
|
||||
| RequiredPower
|
||||
| Setting
|
||||
)
|
||||
}
|
||||
fn can_logic_write(&self, lt: LogicType) -> bool {
|
||||
use LogicType::*;
|
||||
matches!(lt, LineNumber | On | Setting)
|
||||
}
|
||||
fn get_logic(&self, lt: LogicType) -> Result<f64, LogicError> {
|
||||
match lt {
|
||||
LogicType::PrefabHash => Ok(self.get_prefab().hash as f64),
|
||||
LogicType::NameHash => Ok(self.get_name().hash as f64),
|
||||
LogicType::ReferenceId => Ok(*self.get_id() as f64),
|
||||
LogicType::Error => Ok(self.error as f64),
|
||||
LogicType::LineNumber => {
|
||||
let result = self.slot.occupant.as_ref().and_then(|info| {
|
||||
self.vm.get_object(info.id).and_then(|obj| {
|
||||
obj.borrow()
|
||||
.as_logicable()
|
||||
.map(|logicable| logicable.get_logic(LogicType::LineNumber))
|
||||
})
|
||||
});
|
||||
result.unwrap_or(Ok(0.0))
|
||||
}
|
||||
LogicType::On => Ok(self.on as i32 as f64),
|
||||
LogicType::Power => {
|
||||
if let Connection::CableNetwork { net, .. } = self.connections[1] {
|
||||
if net.is_some() {
|
||||
Ok(1.0)
|
||||
} else {
|
||||
Ok(0.0)
|
||||
}
|
||||
} else {
|
||||
Ok(0.0)
|
||||
}
|
||||
}
|
||||
LogicType::RequiredPower => {
|
||||
if let Connection::CableNetwork { net, .. } = self.connections[1] {
|
||||
if net.is_some() {
|
||||
if self.on {
|
||||
Ok(10.0)
|
||||
} else {
|
||||
Ok(0.0)
|
||||
}
|
||||
} else {
|
||||
Ok(-1.0)
|
||||
}
|
||||
} else {
|
||||
Ok(-1.0)
|
||||
}
|
||||
} // 10 if on
|
||||
LogicType::Setting => Ok(self.setting),
|
||||
_ => Err(LogicError::CantRead(lt)),
|
||||
}
|
||||
}
|
||||
fn set_logic(&mut self, lt: LogicType, value: f64, force: bool) -> Result<(), LogicError> {
|
||||
match lt {
|
||||
LogicType::LineNumber => self
|
||||
.slot
|
||||
.occupant
|
||||
.as_ref()
|
||||
.and_then(|info| {
|
||||
self.vm.get_object(info.id).and_then(|obj| {
|
||||
obj.borrow_mut().as_mut_logicable().map(|logicable| {
|
||||
logicable.set_logic(LogicType::LineNumber, value, force)
|
||||
})
|
||||
})
|
||||
})
|
||||
.unwrap_or(Err(LogicError::CantWrite(lt))),
|
||||
LogicType::On => {
|
||||
self.on = value != 0.0;
|
||||
Ok(())
|
||||
}
|
||||
LogicType::Setting => {
|
||||
self.setting = value;
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(LogicError::CantWrite(lt)),
|
||||
}
|
||||
}
|
||||
fn can_slot_logic_read(&self, _slt: LogicSlotType, _indexx: f64) -> bool {
|
||||
false
|
||||
}
|
||||
fn get_slot_logic(&self, _slt: LogicSlotType, index: f64) -> Result<f64, LogicError> {
|
||||
Err(LogicError::SlotIndexOutOfRange(index, self.slots_count()))
|
||||
}
|
||||
fn valid_logic_types(&self) -> Vec<LogicType> {
|
||||
use LogicType::*;
|
||||
vec![
|
||||
Error,
|
||||
LineNumber,
|
||||
NameHash,
|
||||
On,
|
||||
Power,
|
||||
PrefabHash,
|
||||
ReferenceId,
|
||||
RequiredPower,
|
||||
Setting,
|
||||
]
|
||||
}
|
||||
fn known_modes(&self) -> Option<Vec<(u32, String)>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for StructureCircuitHousing {
|
||||
fn debug_device(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"pins: {:?}, connections: {:?}",
|
||||
self.pins, self.connections
|
||||
)
|
||||
}
|
||||
fn has_reagents(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn has_atmosphere(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn has_lock_state(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn has_mode_state(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn has_open_state(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn has_color_state(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn has_activate_state(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn has_on_off_state(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn get_reagents(&self) -> Vec<(u8, f64)> {
|
||||
vec![]
|
||||
}
|
||||
fn set_reagents(&mut self, _reagents: &[(u8, f64)]) {
|
||||
// nope
|
||||
}
|
||||
fn add_reagents(&mut self, _reagents: &[(u8, f64)]) {
|
||||
// nope
|
||||
}
|
||||
fn connection_list(&self) -> &[crate::network::Connection] {
|
||||
&self.connections
|
||||
}
|
||||
fn connection_list_mut(&mut self) -> &mut [crate::network::Connection] {
|
||||
&mut self.connections
|
||||
}
|
||||
fn device_pins(&self) -> Option<&[Option<ObjectID>]> {
|
||||
Some(&self.pins)
|
||||
}
|
||||
fn device_pins_mut(&mut self) -> Option<&mut [Option<ObjectID>]> {
|
||||
Some(&mut self.pins)
|
||||
}
|
||||
fn can_slot_logic_write(&self, _slt: LogicSlotType, _index: f64) -> bool {
|
||||
false
|
||||
}
|
||||
fn set_slot_logic(
|
||||
&mut self,
|
||||
slt: LogicSlotType,
|
||||
index: f64,
|
||||
_value: f64,
|
||||
_force: bool,
|
||||
) -> Result<(), LogicError> {
|
||||
Err(LogicError::CantSlotWrite(slt, index))
|
||||
}
|
||||
}
|
||||
|
||||
impl CircuitHolder for StructureCircuitHousing {
|
||||
fn debug_circuit_holder(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "error: {}, setting: {}", self.error, self.setting)
|
||||
}
|
||||
fn clear_error(&mut self) {
|
||||
self.error = 0
|
||||
}
|
||||
fn set_error(&mut self, state: i32) {
|
||||
self.error = state;
|
||||
}
|
||||
/// i32::MAX is db
|
||||
fn get_logicable_from_index(
|
||||
&self,
|
||||
device: i32,
|
||||
connection: Option<usize>,
|
||||
) -> Option<ObjectRef> {
|
||||
if device == i32::MAX {
|
||||
// self
|
||||
if let Some(connection) = connection {
|
||||
self.connections.get(connection).and_then(|conn| {
|
||||
if let Connection::CableNetwork { net: Some(net), .. } = conn {
|
||||
self.vm.get_network(*net).map(ObjectRef::from_vm_object)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Some(ObjectRef::from_ref(self.as_object()))
|
||||
}
|
||||
} else {
|
||||
if device < 0 {
|
||||
return None;
|
||||
}
|
||||
self.pins.get(device as usize).and_then(|pin| {
|
||||
pin.and_then(|id| self.vm.get_object(id).map(ObjectRef::from_vm_object))
|
||||
})
|
||||
}
|
||||
}
|
||||
/// i32::MAX is db
|
||||
fn get_logicable_from_index_mut(
|
||||
&mut self,
|
||||
device: i32,
|
||||
connection: Option<usize>,
|
||||
) -> Option<ObjectRefMut> {
|
||||
if device == i32::MAX {
|
||||
// self
|
||||
if let Some(connection) = connection {
|
||||
self.connections.get(connection).and_then(|conn| {
|
||||
if let Connection::CableNetwork { net: Some(net), .. } = conn {
|
||||
self.vm.get_network(*net).map(ObjectRefMut::from_vm_object)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Some(ObjectRefMut::from_ref(self.as_mut_object()))
|
||||
}
|
||||
} else {
|
||||
if device < 0 {
|
||||
return None;
|
||||
}
|
||||
self.pins.get(device as usize).and_then(|pin| {
|
||||
pin.and_then(|id| self.vm.get_object(id).map(ObjectRefMut::from_vm_object))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn get_logicable_from_id(
|
||||
&self,
|
||||
device: ObjectID,
|
||||
connection: Option<usize>,
|
||||
) -> Option<ObjectRef> {
|
||||
if connection.is_some() {
|
||||
return None; // this functionality is disabled in the game, no network access via ReferenceId
|
||||
}
|
||||
if device == self.id {
|
||||
return Some(ObjectRef::from_ref(self.as_object()));
|
||||
}
|
||||
self.vm.get_object(device).map(ObjectRef::from_vm_object)
|
||||
}
|
||||
|
||||
fn get_logicable_from_id_mut(
|
||||
&mut self,
|
||||
device: ObjectID,
|
||||
connection: Option<usize>,
|
||||
) -> Option<ObjectRefMut> {
|
||||
if connection.is_some() {
|
||||
return None; // this functionality is disabled in the game, no network access via ReferenceId
|
||||
}
|
||||
if device == self.id {
|
||||
return Some(ObjectRefMut::from_ref(self.as_mut_object()));
|
||||
}
|
||||
self.vm.get_object(device).map(ObjectRefMut::from_vm_object)
|
||||
}
|
||||
|
||||
fn get_ic(&self) -> Option<VMObject> {
|
||||
self.slot
|
||||
.occupant
|
||||
.as_ref()
|
||||
.and_then(|info| self.vm.get_object(info.id))
|
||||
}
|
||||
|
||||
fn halt_and_catch_fire(&mut self) {
|
||||
// TODO: do something here??
|
||||
}
|
||||
}
|
||||
492
ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs
Normal file
@@ -0,0 +1,492 @@
|
||||
use crate::{
|
||||
errors::{ICError, LineError},
|
||||
interpreter::{instructions::IC10Marker, ICState, Program},
|
||||
vm::{
|
||||
instructions::{operands::Operand, Instruction},
|
||||
object::{
|
||||
errors::{LogicError, MemoryError},
|
||||
macros::ObjectInterface,
|
||||
traits::*,
|
||||
LogicField, MemoryAccess, Name, ObjectID, Slot, VMObject,
|
||||
},
|
||||
VM,
|
||||
},
|
||||
};
|
||||
use macro_rules_attribute::derive;
|
||||
use stationeers_data::enums::{
|
||||
basic::{Class, GasType, SortingClass},
|
||||
script::{LogicSlotType, LogicType},
|
||||
};
|
||||
use std::{collections::BTreeMap, rc::Rc};
|
||||
|
||||
static RETURN_ADDRESS_INDEX: usize = 17;
|
||||
static STACK_POINTER_INDEX: usize = 16;
|
||||
|
||||
#[derive(ObjectInterface!, Debug)]
|
||||
#[custom(implements(Object {
|
||||
Item, Storage, Logicable,
|
||||
MemoryReadable, MemoryWritable,
|
||||
SourceCode, IntegratedCircuit,
|
||||
Programmable
|
||||
}))]
|
||||
pub struct ItemIntegratedCircuit10 {
|
||||
#[custom(object_id)]
|
||||
pub id: ObjectID,
|
||||
#[custom(object_prefab)]
|
||||
pub prefab: Name,
|
||||
#[custom(object_name)]
|
||||
pub name: Name,
|
||||
#[custom(object_vm_ref)]
|
||||
pub vm: Rc<VM>,
|
||||
pub fields: BTreeMap<LogicType, LogicField>,
|
||||
pub memory: [f64; 512],
|
||||
pub parent_slot: Option<ParentSlotInfo>,
|
||||
pub registers: [f64; 18],
|
||||
/// Instruction Pointer
|
||||
pub ip: usize,
|
||||
pub next_ip: usize,
|
||||
/// Instruction Count since last yield
|
||||
pub ic: u16,
|
||||
pub aliases: BTreeMap<String, Operand>,
|
||||
pub defines: BTreeMap<String, f64>,
|
||||
pub pins: [Option<u32>; 6],
|
||||
pub state: ICState,
|
||||
pub code: String,
|
||||
pub program: Program,
|
||||
pub damage: f32,
|
||||
}
|
||||
|
||||
impl Item for ItemIntegratedCircuit10 {
|
||||
fn debug_item(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "UNIMPLEMENTED") //TODO: Implement
|
||||
}
|
||||
fn consumable(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn filter_type(&self) -> Option<GasType> {
|
||||
None
|
||||
}
|
||||
fn ingredient(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn max_quantity(&self) -> u32 {
|
||||
1
|
||||
}
|
||||
fn reagents(&self) -> Option<&BTreeMap<String, f64>> {
|
||||
None
|
||||
}
|
||||
fn slot_class(&self) -> Class {
|
||||
Class::ProgrammableChip
|
||||
}
|
||||
fn sorting_class(&self) -> SortingClass {
|
||||
SortingClass::Default
|
||||
}
|
||||
fn get_parent_slot(&self) -> Option<ParentSlotInfo> {
|
||||
self.parent_slot
|
||||
}
|
||||
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>) {
|
||||
self.parent_slot = info;
|
||||
}
|
||||
fn get_damage(&self) -> f32 {
|
||||
self.damage
|
||||
}
|
||||
fn set_damage(&mut self, damage: f32) {
|
||||
self.damage = damage.clamp(0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl Storage for ItemIntegratedCircuit10 {
|
||||
fn debug_storage(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "UNIMPLEMENTED") //TODO: Implement
|
||||
}
|
||||
fn slots_count(&self) -> usize {
|
||||
0
|
||||
}
|
||||
fn get_slot(&self, _index: usize) -> Option<&Slot> {
|
||||
None
|
||||
}
|
||||
fn get_slot_mut(&mut self, _index: usize) -> Option<&mut Slot> {
|
||||
None
|
||||
}
|
||||
fn get_slots(&self) -> Vec<(usize, &Slot)> {
|
||||
vec![]
|
||||
}
|
||||
fn get_slots_mut(&mut self) -> Vec<(usize, &mut Slot)> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl Logicable for ItemIntegratedCircuit10 {
|
||||
fn debug_logicable(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "UNIMPLEMENTED") //TODO: Implement
|
||||
}
|
||||
fn prefab_hash(&self) -> i32 {
|
||||
self.get_prefab().hash
|
||||
}
|
||||
fn name_hash(&self) -> i32 {
|
||||
self.get_name().hash
|
||||
}
|
||||
fn is_logic_readable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn is_logic_writeable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn can_logic_read(&self, lt: LogicType) -> bool {
|
||||
self.fields
|
||||
.get(<)
|
||||
.map(|field| {
|
||||
matches!(
|
||||
field.field_type,
|
||||
MemoryAccess::Read | MemoryAccess::ReadWrite
|
||||
)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
fn can_logic_write(&self, lt: LogicType) -> bool {
|
||||
self.fields
|
||||
.get(<)
|
||||
.map(|field| {
|
||||
matches!(
|
||||
field.field_type,
|
||||
MemoryAccess::Write | MemoryAccess::ReadWrite
|
||||
)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
fn get_logic(&self, lt: LogicType) -> Result<f64, LogicError> {
|
||||
self.fields
|
||||
.get(<)
|
||||
.and_then(|field| match field.field_type {
|
||||
MemoryAccess::Read | MemoryAccess::ReadWrite => Some(field.value),
|
||||
_ => None,
|
||||
})
|
||||
.ok_or(LogicError::CantRead(lt))
|
||||
}
|
||||
fn set_logic(&mut self, lt: LogicType, value: f64, force: bool) -> Result<(), LogicError> {
|
||||
self.fields
|
||||
.get_mut(<)
|
||||
.ok_or(LogicError::CantWrite(lt))
|
||||
.and_then(|field| match field.field_type {
|
||||
MemoryAccess::Write | MemoryAccess::ReadWrite => {
|
||||
field.value = value;
|
||||
Ok(())
|
||||
}
|
||||
_ if force => {
|
||||
field.value = value;
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(LogicError::CantWrite(lt)),
|
||||
})
|
||||
}
|
||||
fn can_slot_logic_read(&self, _slt: LogicSlotType, _index: f64) -> bool {
|
||||
false
|
||||
}
|
||||
fn get_slot_logic(&self, _slt: LogicSlotType, index: f64) -> Result<f64, LogicError> {
|
||||
Err(LogicError::SlotIndexOutOfRange(index, self.slots_count()))
|
||||
}
|
||||
fn valid_logic_types(&self) -> Vec<LogicType> {
|
||||
self.fields.keys().copied().collect()
|
||||
}
|
||||
fn known_modes(&self) -> Option<Vec<(u32, String)>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl MemoryReadable for ItemIntegratedCircuit10 {
|
||||
fn debug_memory_readable(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "UNIMPLEMENTED") //TODO: Implement
|
||||
}
|
||||
fn memory_size(&self) -> usize {
|
||||
self.memory.len()
|
||||
}
|
||||
fn get_memory(&self, index: i32) -> Result<f64, MemoryError> {
|
||||
if index < 0 {
|
||||
Err(MemoryError::StackUnderflow(index, self.memory.len()))
|
||||
} else if index as usize >= self.memory.len() {
|
||||
Err(MemoryError::StackOverflow(index, self.memory.len()))
|
||||
} else {
|
||||
Ok(self.memory[index as usize])
|
||||
}
|
||||
}
|
||||
fn get_memory_slice(&self) -> &[f64] {
|
||||
&self.memory
|
||||
}
|
||||
}
|
||||
|
||||
impl MemoryWritable for ItemIntegratedCircuit10 {
|
||||
fn debug_memory_writable(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "UNIMPLEMENTED") //TODO: Implement
|
||||
}
|
||||
fn set_memory(&mut self, index: i32, val: f64) -> Result<(), MemoryError> {
|
||||
if index < 0 {
|
||||
Err(MemoryError::StackUnderflow(index, self.memory.len()))
|
||||
} else if index as usize >= self.memory.len() {
|
||||
Err(MemoryError::StackOverflow(index, self.memory.len()))
|
||||
} else {
|
||||
self.memory[index as usize] = val;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
fn clear_memory(&mut self) {
|
||||
self.memory.fill(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl SourceCode for ItemIntegratedCircuit10 {
|
||||
fn debug_source_code(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "UNIMPLEMENTED") //TODO: Implement
|
||||
}
|
||||
fn set_source_code(&mut self, code: &str) -> Result<(), ICError> {
|
||||
self.program = Program::try_from_code(code)?;
|
||||
self.code = code.to_string();
|
||||
Ok(())
|
||||
}
|
||||
fn set_source_code_with_invalid(&mut self, code: &str) {
|
||||
self.program = Program::from_code_with_invalid(code);
|
||||
self.code = code.to_string();
|
||||
}
|
||||
fn get_source_code(&self) -> String {
|
||||
self.code.clone()
|
||||
}
|
||||
fn get_line(&self, line: usize) -> Result<Instruction, ICError> {
|
||||
self.program.get_line(line)
|
||||
}
|
||||
fn get_compile_errors(&self) -> Vec<ICError> {
|
||||
self.program.errors.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntegratedCircuit for ItemIntegratedCircuit10 {
|
||||
fn debug_integrated_circuit(&self,f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "UNIMPLEMENTED") //TODO: Implement
|
||||
}
|
||||
fn get_circuit_holder(&self) -> Option<VMObject> {
|
||||
self.get_parent_slot()
|
||||
.and_then(|parent_slot| self.get_vm().get_object(parent_slot.parent))
|
||||
}
|
||||
fn get_instruction_pointer(&self) -> u32 {
|
||||
self.ip as u32
|
||||
}
|
||||
fn set_next_instruction(&mut self, next_instruction: f64) {
|
||||
self.next_ip = next_instruction as usize;
|
||||
}
|
||||
fn set_next_instruction_relative(&mut self, offset: f64) {
|
||||
self.next_ip = (self.ip as f64 + offset) as usize
|
||||
}
|
||||
fn reset(&mut self) {
|
||||
self.ip = 0;
|
||||
self.ic = 0;
|
||||
self.registers.fill(0.0);
|
||||
self.memory.fill(0.0);
|
||||
self.aliases.clear();
|
||||
self.defines.clear();
|
||||
self.state = ICState::Start;
|
||||
}
|
||||
fn get_real_target(&self, indirection: u32, target: u32) -> Result<f64, ICError> {
|
||||
let mut i = indirection;
|
||||
let mut t = target as f64;
|
||||
while i > 0 {
|
||||
if let Some(new_t) = self.registers.get(t as usize) {
|
||||
t = *new_t;
|
||||
} else {
|
||||
return Err(ICError::RegisterIndexOutOfRange(t));
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
Ok(t)
|
||||
}
|
||||
fn get_register(&self, indirection: u32, target: u32) -> Result<f64, ICError> {
|
||||
let t = self.get_real_target(indirection, target)?;
|
||||
self.registers
|
||||
.get(t as usize)
|
||||
.ok_or(ICError::RegisterIndexOutOfRange(t))
|
||||
.copied()
|
||||
}
|
||||
fn set_register(&mut self, indirection: u32, target: u32, val: f64) -> Result<f64, ICError> {
|
||||
let t = self.get_real_target(indirection, target)?;
|
||||
let old_val = self
|
||||
.registers
|
||||
.get(t as usize)
|
||||
.ok_or(ICError::RegisterIndexOutOfRange(t))
|
||||
.copied()?;
|
||||
self.registers[t as usize] = val;
|
||||
Ok(old_val)
|
||||
}
|
||||
fn get_registers(&self) -> &[f64] {
|
||||
&self.registers
|
||||
}
|
||||
fn get_registers_mut(&mut self) -> &mut [f64] {
|
||||
&mut self.registers
|
||||
}
|
||||
fn set_return_address(&mut self, addr: f64) {
|
||||
self.registers[RETURN_ADDRESS_INDEX] = addr;
|
||||
}
|
||||
fn push_stack(&mut self, val: f64) -> Result<f64, ICError> {
|
||||
let sp = (self.registers[STACK_POINTER_INDEX].round()) as i32;
|
||||
if sp < 0 {
|
||||
Err(MemoryError::StackUnderflow(sp, self.memory.len()).into())
|
||||
} else if sp as usize >= self.memory.len() {
|
||||
Err(MemoryError::StackOverflow(sp, self.memory.len()).into())
|
||||
} else {
|
||||
let last = self.memory[sp as usize];
|
||||
self.memory[sp as usize] = val;
|
||||
self.registers[STACK_POINTER_INDEX] += 1.0;
|
||||
Ok(last)
|
||||
}
|
||||
}
|
||||
fn pop_stack(&mut self) -> Result<f64, ICError> {
|
||||
self.registers[STACK_POINTER_INDEX] -= 1.0;
|
||||
let sp = (self.registers[STACK_POINTER_INDEX].round()) as i32;
|
||||
if sp < 0 {
|
||||
Err(MemoryError::StackUnderflow(sp, self.memory.len()).into())
|
||||
} else if sp as usize >= self.memory.len() {
|
||||
Err(MemoryError::StackOverflow(sp, self.memory.len()).into())
|
||||
} else {
|
||||
let last = self.memory[sp as usize];
|
||||
Ok(last)
|
||||
}
|
||||
}
|
||||
fn peek_stack(&self) -> Result<f64, ICError> {
|
||||
let sp = (self.registers[STACK_POINTER_INDEX] - 1.0).round() as i32;
|
||||
if sp < 0 {
|
||||
Err(MemoryError::StackUnderflow(sp, self.memory.len()).into())
|
||||
} else if sp as usize >= self.memory.len() {
|
||||
Err(MemoryError::StackOverflow(sp, self.memory.len()).into())
|
||||
} else {
|
||||
let last = self.memory[sp as usize];
|
||||
Ok(last)
|
||||
}
|
||||
}
|
||||
fn get_stack(&self, addr: f64) -> Result<f64, ICError> {
|
||||
let sp = (addr) as i32;
|
||||
if !(0..(self.memory.len() as i32)).contains(&sp) {
|
||||
Err(ICError::StackIndexOutOfRange(addr))
|
||||
} else {
|
||||
let val = self.memory[sp as usize];
|
||||
Ok(val)
|
||||
}
|
||||
}
|
||||
fn put_stack(&mut self, addr: f64, val: f64) -> Result<f64, ICError> {
|
||||
let sp = addr.round() as i32;
|
||||
if !(0..(self.memory.len() as i32)).contains(&sp) {
|
||||
Err(ICError::StackIndexOutOfRange(addr))
|
||||
} else {
|
||||
let last = self.memory[sp as usize];
|
||||
self.memory[sp as usize] = val;
|
||||
Ok(last)
|
||||
}
|
||||
}
|
||||
fn get_aliases(&self) -> &BTreeMap<String, Operand> {
|
||||
&self.aliases
|
||||
}
|
||||
fn get_aliases_mut(&mut self) -> &mut BTreeMap<String, Operand> {
|
||||
&mut self.aliases
|
||||
}
|
||||
fn get_defines(&self) -> &BTreeMap<String, f64> {
|
||||
&self.defines
|
||||
}
|
||||
fn get_defines_mut(&mut self) -> &mut BTreeMap<String, f64> {
|
||||
&mut self.defines
|
||||
}
|
||||
fn get_labels(&self) -> &BTreeMap<String, u32> {
|
||||
&self.program.labels
|
||||
}
|
||||
fn get_state(&self) -> crate::interpreter::ICState {
|
||||
self.state.clone()
|
||||
}
|
||||
fn set_state(&mut self, state: crate::interpreter::ICState) {
|
||||
self.state = state;
|
||||
if matches!(self.state, ICState::Yield | ICState::Sleep(..)) {
|
||||
self.ic = 0;
|
||||
}
|
||||
}
|
||||
fn get_instructions_since_yield(&self) -> u16 {
|
||||
self.ic
|
||||
}
|
||||
}
|
||||
|
||||
impl IC10Marker for ItemIntegratedCircuit10 {}
|
||||
|
||||
impl Programmable for ItemIntegratedCircuit10 {
|
||||
fn debug_programmable(&self,f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "UNIMPLEMENTED") //TODO: Implement
|
||||
}
|
||||
#[tracing::instrument]
|
||||
fn step(&mut self, advance_ip_on_err: bool) -> Result<(), crate::errors::ICError> {
|
||||
tracing::trace!(ignore_error = advance_ip_on_err, "stepping IC");
|
||||
if matches!(&self.state, ICState::HasCaughtFire) {
|
||||
tracing::debug!("IC on Fire!");
|
||||
return Ok(());
|
||||
}
|
||||
if matches!(&self.state, ICState::Error(_)) && !advance_ip_on_err {
|
||||
tracing::debug!("IC in an error state, not advancing");
|
||||
return Ok(());
|
||||
}
|
||||
if let ICState::Sleep(then, sleep_for) = &self.state {
|
||||
if let Some(duration) = time::Duration::checked_seconds_f64(*sleep_for) {
|
||||
if let Some(sleep_till) = then.checked_add(duration) {
|
||||
let now = time::OffsetDateTime::now_local()
|
||||
.unwrap_or_else(|_| time::OffsetDateTime::now_utc());
|
||||
if sleep_till > now {
|
||||
tracing::debug!("Sleeping: {sleep_till} > {now}");
|
||||
return Ok(());
|
||||
}
|
||||
// else sleep duration ended, continue
|
||||
} else {
|
||||
return Err(ICError::SleepAdditionError {
|
||||
duration,
|
||||
time: *then,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return Err(ICError::SleepDurationError(*sleep_for));
|
||||
}
|
||||
}
|
||||
if self.ip >= self.program.len() || self.program.is_empty() {
|
||||
tracing::debug!("IC at end of program");
|
||||
self.state = ICState::Ended;
|
||||
return Ok(());
|
||||
}
|
||||
self.next_ip = self.ip + 1;
|
||||
self.state = ICState::Running;
|
||||
let line = self.program.get_line(self.ip)?.clone();
|
||||
let operands = &line.operands;
|
||||
let instruction = line.instruction;
|
||||
let result = instruction.execute(self, operands);
|
||||
|
||||
let was_error = if let Err(err) = result {
|
||||
let msg = err.to_string();
|
||||
self.state = ICState::Error(LineError {
|
||||
error: err,
|
||||
line: self.ip as u32,
|
||||
msg,
|
||||
});
|
||||
self.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.id))?
|
||||
.borrow_mut()
|
||||
.as_mut_circuit_holder()
|
||||
.ok_or(ICError::CircuitHolderNotLogicable(self.id))?
|
||||
.set_error(1);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if !was_error || advance_ip_on_err {
|
||||
self.ip = self.next_ip;
|
||||
if self.ip >= self.program.len() && !matches!(&self.state, ICState::Error(_)) {
|
||||
self.state = ICState::Ended;
|
||||
}
|
||||
}
|
||||
|
||||
self.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.id))?
|
||||
.borrow_mut()
|
||||
.as_mut_logicable()
|
||||
.ok_or(ICError::CircuitHolderNotLogicable(self.id))?
|
||||
.set_logic(LogicType::LineNumber, self.ip as f64, true)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
1534
ic10emu/src/vm/object/templates.rs
Normal file
563
ic10emu/src/vm/object/traits.rs
Normal file
@@ -0,0 +1,563 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
errors::ICError,
|
||||
interpreter::ICState,
|
||||
network::Connection,
|
||||
vm::{
|
||||
instructions::{traits::ICInstructable, Instruction},
|
||||
object::{
|
||||
errors::{LogicError, MemoryError},
|
||||
macros::tag_object_traits,
|
||||
ObjectID, Slot, VMObject,
|
||||
},
|
||||
},
|
||||
};
|
||||
use stationeers_data::{
|
||||
enums::{
|
||||
basic::{Class, GasType, SortingClass},
|
||||
script::{LogicSlotType, LogicType},
|
||||
Species,
|
||||
},
|
||||
templates::RecipeOrder,
|
||||
};
|
||||
use std::{collections::BTreeMap, fmt::Debug};
|
||||
#[cfg(feature = "tsify")]
|
||||
use tsify::Tsify;
|
||||
#[cfg(feature = "tsify")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use strum::{AsRefStr, Display, EnumIter, EnumProperty, EnumString, FromRepr};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct ParentSlotInfo {
|
||||
pub parent: ObjectID,
|
||||
pub slot: usize,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Default,
|
||||
Debug,
|
||||
Display,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Hash,
|
||||
EnumString,
|
||||
AsRefStr,
|
||||
EnumProperty,
|
||||
EnumIter,
|
||||
FromRepr,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum StatState {
|
||||
#[default]
|
||||
Normal,
|
||||
Warning,
|
||||
Critical,
|
||||
}
|
||||
|
||||
tag_object_traits! {
|
||||
#![object_trait(Object: Debug)]
|
||||
|
||||
pub trait Structure {
|
||||
fn is_small_grid(&self) -> bool;
|
||||
}
|
||||
|
||||
pub trait Storage {
|
||||
/// Number of storage slots this object has
|
||||
fn slots_count(&self) -> usize;
|
||||
/// Get a reference to a indexed slot
|
||||
fn get_slot(&self, index: usize) -> Option<&Slot>;
|
||||
/// Get a mutable reference to a indexed slot
|
||||
fn get_slot_mut(&mut self, index: usize) -> Option<&mut Slot>;
|
||||
/// Get a vector of references to all an object's slots
|
||||
fn get_slots(&self) -> Vec<(usize, &Slot)>;
|
||||
/// Get a vector a mutable references to all an object's slots
|
||||
fn get_slots_mut(&mut self) -> Vec<(usize, &mut Slot)>;
|
||||
}
|
||||
|
||||
pub trait MemoryReadable {
|
||||
/// Size of an object memory, the count of f64 elements stored
|
||||
fn memory_size(&self) -> usize;
|
||||
/// Get the value at the indexed memory.
|
||||
/// Errors if the index over or under flows the memory
|
||||
fn get_memory(&self, index: i32) -> Result<f64, MemoryError>;
|
||||
/// get a slice of the objects' memory
|
||||
fn get_memory_slice(&self) -> &[f64];
|
||||
}
|
||||
|
||||
pub trait MemoryWritable: MemoryReadable {
|
||||
/// Set the value at the indexed memory
|
||||
/// Errors if the index over or under flows the memory
|
||||
fn set_memory(&mut self, index: i32, val: f64) -> Result<(), MemoryError>;
|
||||
/// Reset all an object's memory (typically to all zero values)
|
||||
fn clear_memory(&mut self);
|
||||
}
|
||||
|
||||
pub trait Logicable: Storage {
|
||||
/// The crc32 hash of the object's prefab name
|
||||
fn prefab_hash(&self) -> i32;
|
||||
/// The crc32 hash of an object's name
|
||||
fn name_hash(&self) -> i32;
|
||||
/// If the object has *any* readable logic fields
|
||||
fn is_logic_readable(&self) -> bool;
|
||||
/// If the object has *any* writable logic fields
|
||||
fn is_logic_writeable(&self) -> bool;
|
||||
/// Can the logic type be read form this object
|
||||
fn can_logic_read(&self, lt: LogicType) -> bool;
|
||||
/// Can the logic type be written to this object
|
||||
fn can_logic_write(&self, lt: LogicType) -> bool;
|
||||
/// Write the value of the logic type on this object.
|
||||
/// Errors if the type can not be written to.
|
||||
/// force will allow special cases for existing values that arn't
|
||||
/// normally writable.
|
||||
/// This is for use outside of ic10 code but does not guarantee the
|
||||
/// value will write or that no error will result.
|
||||
/// If a logic type is not present on an object the force write will still error.
|
||||
fn set_logic(&mut self, lt: LogicType, value: f64, force: bool) -> Result<(), LogicError>;
|
||||
/// Read the value of the logic type on this object.
|
||||
/// Errors if a logic type is not readable
|
||||
fn get_logic(&self, lt: LogicType) -> Result<f64, LogicError>;
|
||||
/// Can a slot logic type be read from the indexed slot
|
||||
fn can_slot_logic_read(&self, slt: LogicSlotType, index: f64) -> bool;
|
||||
/// Read a slot logic type value from an index slot
|
||||
fn get_slot_logic(&self, slt: LogicSlotType, index: f64) -> Result<f64, LogicError>;
|
||||
/// Returns a vector of the `LogicType`'s that could be read or written to or form this
|
||||
/// object
|
||||
fn valid_logic_types(&self) -> Vec<LogicType>;
|
||||
/// If this object has modes returns a vector of (value, name) pairs
|
||||
fn known_modes(&self) -> Option<Vec<(u32, String)>>;
|
||||
}
|
||||
|
||||
pub trait SourceCode {
|
||||
/// Set the source code for this object.
|
||||
/// Errors if the source code has compilation errors.
|
||||
fn set_source_code(&mut self, code: &str) -> Result<(), ICError>;
|
||||
/// Set the source code for this object, lines that fail to compile are reduced to nops.
|
||||
fn set_source_code_with_invalid(&mut self, code: &str);
|
||||
/// Return the source code form this object
|
||||
fn get_source_code(&self) -> String;
|
||||
/// Return the compiled instruction and it's operands at the indexed line in the source
|
||||
/// code.
|
||||
fn get_line(&self, line: usize) -> Result<Instruction, ICError>;
|
||||
/// Return a vector of any errors encountered while compiling the source with `set_source_code_with_invalid`
|
||||
fn get_compile_errors(&self) -> Vec<ICError>;
|
||||
}
|
||||
|
||||
pub trait CircuitHolder: Logicable + Storage {
|
||||
/// Clear any error set on the circuit holder
|
||||
fn clear_error(&mut self);
|
||||
/// Set an int error value on the circuit holder
|
||||
fn set_error(&mut self, state: i32);
|
||||
/// Get a reference (which may be self) to a logicable object based on an index
|
||||
/// (`db`, `d0`, `d1` etc.).
|
||||
/// for a StructureCircuitHolder this would be the set pins
|
||||
/// fpr a tablet or suit this would be the parent human's equipment
|
||||
/// i32::MAX is db
|
||||
fn get_logicable_from_index(
|
||||
&self,
|
||||
device: i32,
|
||||
connection: Option<usize>,
|
||||
) -> Option<ObjectRef>;
|
||||
/// Get a mutable reference (which may be self) to a logicable object based on an index
|
||||
/// (`db`, `d0`, `d1` etc.).
|
||||
/// for a StructureCircuitHolder this would be the set pins
|
||||
/// fpr a tablet or suit this would be the parent human's equipment
|
||||
/// i32::MAX is db
|
||||
fn get_logicable_from_index_mut(
|
||||
&mut self,
|
||||
device: i32,
|
||||
connection: Option<usize>,
|
||||
) -> Option<ObjectRefMut>;
|
||||
/// Use an object id to get a reference to an object network visible object.
|
||||
/// uses ObjectRef in case the object ID is it's own ID
|
||||
fn get_logicable_from_id(
|
||||
&self,
|
||||
device: ObjectID,
|
||||
connection: Option<usize>,
|
||||
) -> Option<ObjectRef>;
|
||||
/// Use an object id to get a mutable reference to an object network visible object.
|
||||
/// uses ObjectRefMut in case the object ID is it's own ID
|
||||
fn get_logicable_from_id_mut(
|
||||
&mut self,
|
||||
device: ObjectID,
|
||||
connection: Option<usize>,
|
||||
) -> Option<ObjectRefMut>;
|
||||
/// Get the programmable circuit object slotted into this circuit holder
|
||||
fn get_ic(&self) -> Option<VMObject>;
|
||||
/// Execute a `hcf` instruction
|
||||
fn halt_and_catch_fire(&mut self);
|
||||
}
|
||||
|
||||
pub trait Item {
|
||||
/// Is an item consumable?
|
||||
fn consumable(&self) -> bool;
|
||||
/// If an item is a filter what gas is it for?
|
||||
fn filter_type(&self) -> Option<GasType>;
|
||||
/// Is this item an ingredient ?
|
||||
fn ingredient(&self) -> bool;
|
||||
/// The max quantity this item stacks to
|
||||
fn max_quantity(&self) -> u32;
|
||||
/// Map of the reagents to the quantity produces by processing this item
|
||||
fn reagents(&self) -> Option<&BTreeMap<String, f64>>;
|
||||
/// The class of item this is for storage slots
|
||||
fn slot_class(&self) -> Class;
|
||||
/// The sorting class of the item
|
||||
fn sorting_class(&self) -> SortingClass;
|
||||
/// The parent object and slot index this item is stored in
|
||||
fn get_parent_slot(&self) -> Option<ParentSlotInfo>;
|
||||
/// Set the parent object and slot index this object is stored in
|
||||
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>);
|
||||
/// Get the damage 0.0 is no damage, 1.0 is full damage
|
||||
fn get_damage(&self) -> f32;
|
||||
/// Set the damage of the object, 0.0 is no damage, 1.0 is full damage
|
||||
fn set_damage(&mut self, damage: f32);
|
||||
/// If this object is stored in a human's inventory or in an inventory down the chain from
|
||||
/// a human, return that human
|
||||
fn root_parent_human(&self) -> Option<VMObject> {
|
||||
self.get_parent_slot().and_then(|info| {
|
||||
if let Some(obj) = self.get_vm().get_object(info.parent) {
|
||||
if obj.borrow().as_human().is_some() {
|
||||
return Some(obj);
|
||||
}
|
||||
let obj_ref = obj.borrow();
|
||||
if let Some(item) = obj_ref.as_item() {
|
||||
return item.root_parent_human()
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Plant {
|
||||
fn get_efficiency(&self) -> f64;
|
||||
fn get_health(&self) -> f64;
|
||||
fn get_growth(&self) -> f64;
|
||||
fn is_mature(&self) -> bool;
|
||||
fn is_seeding(&self) -> bool;
|
||||
}
|
||||
|
||||
pub trait Suit: Item + Storage {
|
||||
fn pressure_waste(&self) -> f32;
|
||||
fn pressure_waste_max(&self) -> f32;
|
||||
fn pressure_air(&self) -> f32;
|
||||
}
|
||||
|
||||
pub trait InternalAtmosphere {
|
||||
fn get_volume(&self) -> f64;
|
||||
}
|
||||
|
||||
pub trait Thermal {
|
||||
fn get_convection_factor(&self) -> f32;
|
||||
fn get_radiation_factor(&self) -> f32;
|
||||
}
|
||||
|
||||
pub trait IntegratedCircuit: Logicable + MemoryWritable + SourceCode + Item {
|
||||
/// Get the object that acts as the circuit holder for this object
|
||||
fn get_circuit_holder(&self) -> Option<VMObject>;
|
||||
/// Get the current instruction pointer
|
||||
fn get_instruction_pointer(&self) -> u32;
|
||||
/// Set the next instruction to execute. The instruction pointer is set to this value once
|
||||
/// execution of the current instruction is complete.
|
||||
fn set_next_instruction(&mut self, next_instruction: f64);
|
||||
/// Set the next instruction to execute relative to the current instruction pointer.
|
||||
/// The instruction pointer is set to this value once execution of the current
|
||||
/// instruction is complete.
|
||||
fn set_next_instruction_relative(&mut self, offset: f64) {
|
||||
self.set_next_instruction(self.get_instruction_pointer() as f64 + offset);
|
||||
}
|
||||
/// Reset the circuit. The instruction pointer, instruction count since last yield, all
|
||||
/// registers and memory are set to 0; aliases and defines are cleared; state is set back
|
||||
/// to start.
|
||||
fn reset(&mut self);
|
||||
/// When given some indirection level and a first target read registers values as
|
||||
/// targets while reducing indirection level by one until it reaches to 0
|
||||
/// to find the real target.
|
||||
/// Errors if any index along the chain is out of range
|
||||
fn get_real_target(&self, indirection: u32, target: u32) -> Result<f64, ICError>;
|
||||
/// Return a register value through possible indirection
|
||||
/// Errors if any index along the chain is out of range
|
||||
fn get_register(&self, indirection: u32, target: u32) -> Result<f64, ICError>;
|
||||
/// Get a slice of all registers
|
||||
fn get_registers(&self) -> &[f64];
|
||||
/// Get a mutable slice of all registers
|
||||
fn get_registers_mut(&mut self) -> &mut [f64];
|
||||
/// Set a register value through possible indirection
|
||||
/// Errors if any index along the chain is out of range
|
||||
fn set_register(&mut self, indirection: u32, target: u32, val: f64) -> Result<f64, ICError>;
|
||||
/// Set the return address register's value
|
||||
fn set_return_address(&mut self, addr: f64);
|
||||
/// Set the return address to the instruction after the current instruction pointer
|
||||
fn al(&mut self) {
|
||||
self.set_return_address(self.get_instruction_pointer() as f64 + 1.0);
|
||||
}
|
||||
/// Write value to the stack memory at the current stack pointer and advance stack pointer
|
||||
/// Errors for stack under or overflow of the stack pointer
|
||||
fn push_stack(&mut self, val: f64) -> Result<f64, ICError>;
|
||||
/// Read value from the stack memory at the current stack pointer and decrement the stack pointer
|
||||
/// Errors for stack under or overflow of the stack pointer
|
||||
fn pop_stack(&mut self) -> Result<f64, ICError>;
|
||||
/// Read the value form the stack memory at the current stack pointer and leave the stack pointer
|
||||
/// at the same location
|
||||
/// Errors for stack under or overflow of the stack pointer
|
||||
fn peek_stack(&self) -> Result<f64, ICError>;
|
||||
/// Read the value from the stack memory at indexed address
|
||||
/// Errors for stack under or overflow of the address
|
||||
fn get_stack(&self, addr: f64) -> Result<f64, ICError>;
|
||||
/// Write the value to the stack memory at the indexed address
|
||||
/// Errors for stack under or overflow of the address
|
||||
fn put_stack(&mut self, addr: f64, val: f64) -> Result<f64, ICError>;
|
||||
/// Get a reference to the alias Map
|
||||
fn get_aliases(&self) -> &BTreeMap<String, crate::vm::instructions::operands::Operand>;
|
||||
/// Get a mutable reference to the alias Map
|
||||
fn get_aliases_mut(&mut self) -> &mut BTreeMap<String, crate::vm::instructions::operands::Operand>;
|
||||
/// Get a reference to the define Map
|
||||
fn get_defines(&self) -> &BTreeMap<String, f64>;
|
||||
/// Get a mutable reference to the define Map
|
||||
fn get_defines_mut(&mut self) -> &mut BTreeMap<String, f64>;
|
||||
/// Get a reference to the labels Map
|
||||
fn get_labels(&self) -> &BTreeMap<String, u32>;
|
||||
/// Get the current circuit state. (Start, Yield, Sleep, Error, etc.)
|
||||
fn get_state(&self) -> ICState;
|
||||
/// Set the current circuit state. (Start, Yield, Sleep, Error, etc.)
|
||||
fn set_state(&mut self, state: ICState);
|
||||
/// Get the count of instructions executed since the last yield
|
||||
fn get_instructions_since_yield(&self) -> u16;
|
||||
}
|
||||
|
||||
pub trait Programmable: ICInstructable {
|
||||
fn step(&mut self, advance_ip_on_err: bool) -> Result<(), crate::errors::ICError>;
|
||||
}
|
||||
|
||||
pub trait Chargeable {
|
||||
fn get_charge(&self) -> f32;
|
||||
fn set_charge(&mut self, charge: f32);
|
||||
fn get_max_charge(&self) -> f32;
|
||||
fn get_charge_ratio(&self) -> f32 {
|
||||
self.get_charge() / self.get_max_charge()
|
||||
}
|
||||
fn get_charge_delta(&self) -> f32 {
|
||||
self.get_charge() - self.get_max_charge()
|
||||
}
|
||||
fn is_empty(&self) -> bool {
|
||||
self.get_charge() == 0.0
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Instructable: MemoryWritable {
|
||||
// fn get_instructions(&self) -> Vec<LogicInstruction>
|
||||
}
|
||||
|
||||
pub trait LogicStack: MemoryWritable {
|
||||
// fn logic_stack(&self) -> LogicStack;
|
||||
}
|
||||
|
||||
pub trait Device: Logicable {
|
||||
/// Can the slot logic type be written to the object at the indexed slot
|
||||
fn can_slot_logic_write(&self, slt: LogicSlotType, index: f64) -> bool;
|
||||
/// Write to the slot logic type at the indexed slot
|
||||
/// Errors if the index is out of range or the slot logic type is not writable
|
||||
fn set_slot_logic(
|
||||
&mut self,
|
||||
slt: LogicSlotType,
|
||||
index: f64,
|
||||
value: f64,
|
||||
force: bool,
|
||||
) -> Result<(), LogicError>;
|
||||
/// Get a slice of the Device's network connections
|
||||
fn connection_list(&self) -> &[Connection];
|
||||
/// Get a mutable slice of the Device's network connections
|
||||
fn connection_list_mut(&mut self) -> &mut [Connection];
|
||||
/// Get a slice of the devices "pins" (connected object Ids) if the device has pins
|
||||
fn device_pins(&self) -> Option<&[Option<ObjectID>]>;
|
||||
/// Get a mutable slice of the devices "pins" (connected object Ids) if the device has pins
|
||||
fn device_pins_mut(&mut self) -> Option<&mut [Option<ObjectID>]>;
|
||||
/// Does the device respond to Activate
|
||||
fn has_activate_state(&self) -> bool;
|
||||
/// Does the device have an internal atmosphere
|
||||
fn has_atmosphere(&self) -> bool;
|
||||
/// Does the device have a Color state
|
||||
fn has_color_state(&self) -> bool;
|
||||
/// Does the device have a Lock state
|
||||
fn has_lock_state(&self) -> bool;
|
||||
/// Does the device have a mode state
|
||||
fn has_mode_state(&self) -> bool;
|
||||
/// Does the device have an On / off state
|
||||
fn has_on_off_state(&self) -> bool;
|
||||
/// Does the device have an Open state
|
||||
fn has_open_state(&self) -> bool;
|
||||
/// Does the device store reagents
|
||||
fn has_reagents(&self) -> bool;
|
||||
/// Return vector of (reagent_hash, quantity) pairs
|
||||
fn get_reagents(&self) -> Vec<(u8, f64)>;
|
||||
/// Overwrite present reagents
|
||||
fn set_reagents(&mut self, reagents: &[(u8, f64)]);
|
||||
/// Adds the reagents to contents
|
||||
fn add_reagents(&mut self, reagents: &[(u8, f64)]);
|
||||
}
|
||||
|
||||
pub trait ReagentConsumer {
|
||||
fn can_process_reagent(&self, reagent: u8) -> bool;
|
||||
fn get_resources_used(&self) -> Vec<i32>;
|
||||
}
|
||||
|
||||
pub trait ReagentRequirer: Device {
|
||||
/// the currently selected Recipe and Order
|
||||
fn get_current_recipe(&self) -> Option<RecipeOrder>;
|
||||
/// Reagents required to complete current recipe
|
||||
fn get_current_required(&self) -> Vec<(u8, f64)>;
|
||||
/// Map Reagent hash to Prefab Hash
|
||||
fn get_prefab_hash_from_reagent_hash(&self, reagent_hash: i32) -> Option<i32>;
|
||||
}
|
||||
|
||||
pub trait Fabricator: ReagentRequirer {
|
||||
}
|
||||
|
||||
pub trait WirelessTransmit: Logicable {}
|
||||
|
||||
pub trait WirelessReceive: Logicable {}
|
||||
|
||||
pub trait Network: Logicable {
|
||||
/// Does the network contain the Object id
|
||||
fn contains(&self, id: &ObjectID) -> bool;
|
||||
/// Does the network contain all the object ids
|
||||
fn contains_all(&self, ids: &[ObjectID]) -> bool;
|
||||
/// Does the network contain the object id on a data connection
|
||||
fn contains_data(&self, id: &ObjectID) -> bool;
|
||||
/// Does the network contain all the object ids on a data connection
|
||||
fn contains_all_data(&self, ids: &[ObjectID]) -> bool;
|
||||
/// Does the network contain the object id on a power connection
|
||||
fn contains_power(&self, id: &ObjectID) -> bool;
|
||||
/// Does the network contain all the object ids on a power connection
|
||||
fn contains_all_power(&self, ids: &[ObjectID]) -> bool;
|
||||
/// Return a vector of all object ids visible to the data connection of the source ID object
|
||||
fn data_visible(&self, source: &ObjectID) -> Vec<u32>;
|
||||
/// Add the object to the network as a data connection
|
||||
fn add_data(&mut self, id: ObjectID) -> bool;
|
||||
/// Add the object id as a power connection
|
||||
fn add_power(&mut self, id: ObjectID) -> bool;
|
||||
/// remove the object id for both power and data connections if present in either
|
||||
fn remove_all(&mut self, id: ObjectID) -> bool;
|
||||
/// remove the object id from data network
|
||||
fn remove_data(&mut self, id: ObjectID) -> bool;
|
||||
/// remove object id from power network
|
||||
fn remove_power(&mut self, id: ObjectID) -> bool;
|
||||
/// get all data connected devices
|
||||
fn get_devices(&self) -> Vec<ObjectID>;
|
||||
/// get all power connected devices
|
||||
fn get_power_only(&self) -> Vec<ObjectID>;
|
||||
/// get a slice of the channel data values
|
||||
fn get_channel_data(&self) -> &[f64; 8];
|
||||
}
|
||||
|
||||
pub trait Human : Storage {
|
||||
fn get_species(&self) -> Species;
|
||||
fn get_damage(&self) -> f32;
|
||||
fn set_damage(&mut self, damage: f32);
|
||||
fn get_nutrition(&self) -> f32;
|
||||
fn set_nutrition(&mut self, nutrition: f32);
|
||||
fn nutrition_state(&self) -> StatState;
|
||||
fn get_hydration(&self) -> f32;
|
||||
fn set_hydration(&mut self, hydration: f32);
|
||||
fn hydration_state(&self) -> StatState;
|
||||
fn get_oxygenation(&self) -> f32;
|
||||
fn set_oxygenation(&mut self, oxygenation: f32);
|
||||
fn get_food_quality(&self) -> f32;
|
||||
fn set_food_quality(&mut self, quality: f32);
|
||||
fn get_mood(&self) -> f32;
|
||||
fn set_mood(&mut self, mood: f32);
|
||||
fn mood_state(&self) -> StatState;
|
||||
fn get_hygiene(&self) -> f32;
|
||||
fn set_hygiene(&mut self, hygiene: f32);
|
||||
fn hygiene_state(&self) -> StatState;
|
||||
fn is_artificial(&self) -> bool;
|
||||
fn robot_battery(&self) -> Option<VMObject>;
|
||||
fn suit_slot(&self) -> &Slot;
|
||||
fn suit_slot_mut(&mut self) -> &mut Slot;
|
||||
fn helmet_slot(&self) -> &Slot;
|
||||
fn helmet_slot_mut(&mut self) -> &mut Slot;
|
||||
fn glasses_slot(&self) -> &Slot;
|
||||
fn glasses_slot_mut(&mut self) -> &mut Slot;
|
||||
fn backpack_slot(&self) -> &Slot;
|
||||
fn backpack_slot_mut(&mut self) -> &mut Slot;
|
||||
fn left_hand_slot(&self) -> &Slot;
|
||||
fn left_hand_slot_mut(&mut self) -> &mut Slot;
|
||||
fn right_hand_slot(&self) -> &Slot;
|
||||
fn right_hand_slot_mut(&mut self) -> &mut Slot;
|
||||
fn uniform_slot(&self) -> &Slot;
|
||||
fn uniform_slot_mut(&mut self) -> &mut Slot;
|
||||
fn toolbelt_slot(&self) -> &Slot;
|
||||
fn toolbelt_slot_mut(&mut self) -> &mut Slot;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Debug for dyn Object {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Object{{id: {:?}, type: {}, interfaces: {:?}}}",
|
||||
self.get_id(),
|
||||
self.type_name(),
|
||||
ObjectInterfaces::from_object(self),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CircuitHolder> SourceCode for T {
|
||||
fn debug_source_code(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "source_code: {:?}", self.get_source_code())
|
||||
}
|
||||
fn get_line(&self, line: usize) -> Result<Instruction, ICError> {
|
||||
let ic = self.get_ic().ok_or(ICError::DeviceHasNoIC)?;
|
||||
let result = ic
|
||||
.borrow()
|
||||
.as_source_code()
|
||||
.ok_or(ICError::DeviceHasNoIC)?
|
||||
.get_line(line);
|
||||
result.clone()
|
||||
}
|
||||
fn set_source_code(&mut self, code: &str) -> Result<(), ICError> {
|
||||
self.get_ic()
|
||||
.and_then(|obj| {
|
||||
obj.borrow_mut()
|
||||
.as_mut_source_code()
|
||||
.map(|source| source.set_source_code(code))
|
||||
})
|
||||
.transpose()?;
|
||||
Ok(())
|
||||
}
|
||||
fn set_source_code_with_invalid(&mut self, code: &str) {
|
||||
self.get_ic().and_then(|obj| {
|
||||
obj.borrow_mut()
|
||||
.as_mut_source_code()
|
||||
.map(|source| source.set_source_code_with_invalid(code))
|
||||
});
|
||||
}
|
||||
fn get_source_code(&self) -> String {
|
||||
self.get_ic()
|
||||
.and_then(|obj| {
|
||||
obj.borrow()
|
||||
.as_source_code()
|
||||
.map(|source| source.get_source_code())
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
fn get_compile_errors(&self) -> Vec<ICError> {
|
||||
self.get_ic()
|
||||
.and_then(|obj| {
|
||||
obj.borrow()
|
||||
.as_source_code()
|
||||
.map(|source| source.get_compile_errors())
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
@@ -5,30 +5,59 @@ version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
ic10emu = { path = "../ic10emu" }
|
||||
console_error_panic_hook = {version = "0.1.7", optional = true}
|
||||
stationeers_data = { path = "../stationeers_data", features = ["tsify"] }
|
||||
ic10emu = { path = "../ic10emu", features = ["tsify"] }
|
||||
console_error_panic_hook = { version = "0.1.7", optional = true }
|
||||
js-sys = "0.3.69"
|
||||
web-sys = { version = "0.3.69", features = ["WritableStream", "console"] }
|
||||
wasm-bindgen = "0.2.81"
|
||||
wasm-bindgen-futures = { version = "0.4.30", features = [
|
||||
wasm-bindgen = "0.2.92"
|
||||
wasm-bindgen-futures = { version = "0.4.42", features = [
|
||||
"futures-core-03-stream",
|
||||
] }
|
||||
wasm-streams = "0.4"
|
||||
serde-wasm-bindgen = "0.6.5"
|
||||
itertools = "0.12.1"
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
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"
|
||||
serde_path_to_error = "0.1.16"
|
||||
serde_ignored = "0.1.10"
|
||||
color-eyre = "0.6.3"
|
||||
itertools = "0.13.0"
|
||||
serde = { version = "1.0.202", features = ["derive"] }
|
||||
serde_with = "3.8.1"
|
||||
tsify = { version = "0.4.5", features = ["js"] }
|
||||
thiserror = "1.0.61"
|
||||
serde_derive = "1.0.203"
|
||||
serde_json = "1.0.117"
|
||||
tracing-wasm = "0.2.1"
|
||||
tracing = "0.1.40"
|
||||
|
||||
[features]
|
||||
default = ["console_error_panic_hook"]
|
||||
console_error_panic_hook = ["dep:console_error_panic_hook"]
|
||||
prefab_database = [
|
||||
"ic10emu/prefab_database",
|
||||
"stationeers_data/prefab_database",
|
||||
]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[package.metadata.wasm-pack.profile.dev]
|
||||
wasm-opt = ['-O']
|
||||
|
||||
[package.metadata.wasm-pack.profile.dev.wasm-bindgen]
|
||||
# Should we enable wasm-bindgen's debug assertions in its generated JS glue?
|
||||
debug-js-glue = true
|
||||
# Should wasm-bindgen demangle the symbols in the "name" custom section?
|
||||
demangle-name-section = true
|
||||
# Should we emit the DWARF debug info custom sections?
|
||||
dwarf-debug-info = false
|
||||
# Should we omit the default import path?
|
||||
omit-default-module-path = false
|
||||
|
||||
[package.metadata.wasm-pack.profile.release]
|
||||
wasm-opt = ['-Os']
|
||||
|
||||
[package.metadata.wasm-pack.profile.release.wasm-bindgen]
|
||||
debug-js-glue = false
|
||||
demangle-name-section = true
|
||||
dwarf-debug-info = false
|
||||
omit-default-module-path = false
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
use std::{
|
||||
env,
|
||||
fs::{self, File},
|
||||
io::{BufWriter, Write},
|
||||
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(<_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 sc_tsunion: String = Itertools::intersperse(
|
||||
ic10emu::device::SortingClass::iter().map(|rm| format!("\"{}\"", rm.as_ref())),
|
||||
"\n | ".to_owned(),
|
||||
)
|
||||
.collect();
|
||||
let sc_tstype = format!("\nexport type SortingClass = {};", sc_tsunion);
|
||||
ts_types.push_str(&sc_tstype);
|
||||
|
||||
let st_tsunion: String = Itertools::intersperse(
|
||||
ic10emu::device::SlotType::iter().map(|rm| format!("\"{}\"", rm.as_ref())),
|
||||
"\n | ".to_owned(),
|
||||
)
|
||||
.collect();
|
||||
let st_tstype = format!("\nexport type SlotType = {};", st_tsunion);
|
||||
ts_types.push_str(&st_tstype);
|
||||
|
||||
let ct_tsunion: String = Itertools::intersperse(
|
||||
ic10emu::network::ConnectionType::iter().map(|rm| format!("\"{}\"", rm.as_ref())),
|
||||
"\n | ".to_owned(),
|
||||
)
|
||||
.collect();
|
||||
let ct_tstype = format!("\nexport type ConnectionType = {};", ct_tsunion);
|
||||
ts_types.push_str(&ct_tstype);
|
||||
|
||||
let cr_tsunion: String = Itertools::intersperse(
|
||||
ic10emu::network::ConnectionRole::iter().map(|rm| format!("\"{}\"", rm.as_ref())),
|
||||
"\n | ".to_owned(),
|
||||
)
|
||||
.collect();
|
||||
let cr_tstype = format!("\nexport type ConnectionRole = {};", cr_tsunion);
|
||||
ts_types.push_str(&cr_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#\"{ts_types}\"#;
|
||||
"
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
@@ -1,20 +1,28 @@
|
||||
#[macro_use]
|
||||
mod utils;
|
||||
mod types;
|
||||
// mod types;
|
||||
|
||||
use ic10emu::{
|
||||
device::{Device, DeviceTemplate, SlotOccupantTemplate},
|
||||
grammar::{LogicType, SlotLogicType},
|
||||
vm::{FrozenVM, VMError, VM},
|
||||
errors::{ICError, TemplateError, VMError},
|
||||
network::FrozenCableNetwork,
|
||||
vm::{
|
||||
object::{
|
||||
templates::{FrozenObject, FrozenObjectFull},
|
||||
ObjectID,
|
||||
},
|
||||
FrozenVM, VM,
|
||||
},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use types::{Registers, Stack};
|
||||
|
||||
use std::{cell::RefCell, rc::Rc, str::FromStr};
|
||||
|
||||
use itertools::Itertools;
|
||||
// use std::iter::FromIterator;
|
||||
// use itertools::Itertools;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use stationeers_data::{
|
||||
enums::script::{LogicSlotType, LogicType},
|
||||
templates::{ObjectTemplate, Reagent},
|
||||
};
|
||||
|
||||
use std::{collections::BTreeMap, rc::Rc};
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
@@ -22,12 +30,6 @@ extern "C" {
|
||||
fn alert(s: &str);
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct DeviceRef {
|
||||
device: Rc<RefCell<Device>>,
|
||||
vm: Rc<RefCell<VM>>,
|
||||
}
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug, Serialize, Deserialize)]
|
||||
@@ -38,481 +40,451 @@ pub enum BindingError {
|
||||
OutOfBounds(usize, usize),
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl DeviceRef {
|
||||
fn from_device(device: Rc<RefCell<Device>>, vm: Rc<RefCell<VM>>) -> Self {
|
||||
DeviceRef { device, vm }
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
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<i32> {
|
||||
self.device.borrow().name_hash
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "prefabName")]
|
||||
pub fn prefab_name(&self) -> Option<String> {
|
||||
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
|
||||
.as_ref()
|
||||
.map(|prefab| prefab.hash)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, skip_typescript)]
|
||||
pub fn fields(&self) -> JsValue {
|
||||
serde_wasm_bindgen::to_value(&self.device.borrow().get_fields(&self.vm.borrow())).unwrap()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn slots(&self) -> types::Slots {
|
||||
types::Slots::from_iter(self.device.borrow().slots.iter())
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, skip_typescript)]
|
||||
pub fn reagents(&self) -> JsValue {
|
||||
serde_wasm_bindgen::to_value(&self.device.borrow().reagents).unwrap()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, skip_typescript)]
|
||||
pub fn connections(&self) -> JsValue {
|
||||
serde_wasm_bindgen::to_value(&self.device.borrow().connections).unwrap()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "ip")]
|
||||
pub fn ic_ip(&self) -> Option<u32> {
|
||||
self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
self.vm
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| ic.as_ref().borrow().ip())
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "instructionCount")]
|
||||
pub fn ic_instruction_count(&self) -> Option<u16> {
|
||||
self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
self.vm
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| ic.as_ref().borrow().ic.get())
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "stack")]
|
||||
pub fn ic_stack(&self) -> Option<Stack> {
|
||||
self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
self.vm
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| Stack(*ic.as_ref().borrow().stack.borrow()))
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "registers")]
|
||||
pub fn ic_registers(&self) -> Option<Registers> {
|
||||
self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
self.vm
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| Registers(*ic.as_ref().borrow().registers.borrow()))
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "aliases", skip_typescript)]
|
||||
pub fn ic_aliases(&self) -> JsValue {
|
||||
let aliases = &self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
self.vm
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| ic.as_ref().borrow().aliases.borrow().clone())
|
||||
});
|
||||
serde_wasm_bindgen::to_value(aliases).unwrap()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "defines", skip_typescript)]
|
||||
pub fn ic_defines(&self) -> JsValue {
|
||||
let defines = &self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
self.vm
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| ic.as_ref().borrow().defines.borrow().clone())
|
||||
});
|
||||
serde_wasm_bindgen::to_value(defines).unwrap()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "pins", skip_typescript)]
|
||||
pub fn ic_pins(&self) -> JsValue {
|
||||
let pins = &self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
self.vm
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| *ic.as_ref().borrow().pins.borrow())
|
||||
});
|
||||
serde_wasm_bindgen::to_value(pins).unwrap()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "state")]
|
||||
pub fn ic_state(&self) -> Option<String> {
|
||||
self.device
|
||||
.borrow()
|
||||
.ic
|
||||
.as_ref()
|
||||
.and_then(|ic| {
|
||||
self.vm
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| ic.borrow().state.clone())
|
||||
})
|
||||
.map(|state| state.borrow().to_string())
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "program", skip_typescript)]
|
||||
pub fn ic_program(&self) -> JsValue {
|
||||
let prog = &self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
self.vm
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| ic.borrow().program.borrow().clone())
|
||||
});
|
||||
serde_wasm_bindgen::to_value(prog).unwrap()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "code")]
|
||||
pub fn get_code(&self) -> Option<String> {
|
||||
self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
self.vm
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| ic.borrow().code.borrow().clone())
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "step")]
|
||||
pub fn step_ic(&self, advance_ip_on_err: bool) -> Result<bool, JsError> {
|
||||
let id = self.device.borrow().id;
|
||||
Ok(self.vm.borrow().step_ic(id, advance_ip_on_err)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "run")]
|
||||
pub fn run_ic(&self, ignore_errors: bool) -> Result<bool, JsError> {
|
||||
let id = self.device.borrow().id;
|
||||
Ok(self.vm.borrow().run_ic(id, ignore_errors)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "reset")]
|
||||
pub fn reset_ic(&self) -> Result<bool, JsError> {
|
||||
let id = self.device.borrow().id;
|
||||
Ok(self.vm.borrow().reset_ic(id)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setCode")]
|
||||
/// Set program code if it's valid
|
||||
pub fn set_code(&self, code: &str) -> Result<bool, JsError> {
|
||||
let id = self.device.borrow().id;
|
||||
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_invlaid(&self, code: &str) -> Result<bool, JsError> {
|
||||
let id = self.device.borrow().id;
|
||||
Ok(self.vm.borrow().set_code_invalid(id, code)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setRegister")]
|
||||
pub fn ic_set_register(&self, index: u32, val: f64) -> Result<f64, JsError> {
|
||||
let ic_id = *self
|
||||
.device
|
||||
.borrow()
|
||||
.ic
|
||||
.as_ref()
|
||||
.ok_or(VMError::NoIC(self.device.borrow().id))?;
|
||||
let vm_borrow = self.vm.borrow();
|
||||
let ic = vm_borrow
|
||||
.ics
|
||||
.get(&ic_id)
|
||||
.ok_or(VMError::NoIC(self.device.borrow().id))?;
|
||||
let result = ic.borrow_mut().set_register(0, index, val)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setStack")]
|
||||
pub fn ic_set_stack(&self, address: f64, val: f64) -> Result<f64, JsError> {
|
||||
let ic_id = *self
|
||||
.device
|
||||
.borrow()
|
||||
.ic
|
||||
.as_ref()
|
||||
.ok_or(VMError::NoIC(self.device.borrow().id))?;
|
||||
let vm_borrow = self.vm.borrow();
|
||||
let ic = vm_borrow
|
||||
.ics
|
||||
.get(&ic_id)
|
||||
.ok_or(VMError::NoIC(self.device.borrow().id))?;
|
||||
let result = ic.borrow_mut().poke(address, val)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setName")]
|
||||
pub fn set_name(&self, name: &str) {
|
||||
self.device.borrow_mut().set_name(name)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setField", skip_typescript)]
|
||||
pub fn set_field(&self, field: &str, value: f64, force: bool) -> Result<(), JsError> {
|
||||
let logic_typ = LogicType::from_str(field)?;
|
||||
let mut device_ref = self.device.borrow_mut();
|
||||
device_ref.set_field(logic_typ, value, &self.vm.borrow(), force)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setSlotField", skip_typescript)]
|
||||
pub fn set_slot_field(
|
||||
&self,
|
||||
slot: f64,
|
||||
field: &str,
|
||||
value: f64,
|
||||
force: bool,
|
||||
) -> 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(), force)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "getSlotField", skip_typescript)]
|
||||
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: u32) -> Result<bool, JsError> {
|
||||
let id = self.device.borrow().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<u32>) -> Result<bool, JsError> {
|
||||
let id = self.device.borrow().id;
|
||||
Ok(self.vm.borrow().set_pin(id, pin, val)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug)]
|
||||
pub struct VMRef {
|
||||
vm: Rc<RefCell<VM>>,
|
||||
vm: Rc<VM>,
|
||||
}
|
||||
|
||||
use tsify::Tsify;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Tsify)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
pub struct TemplateDatabase(BTreeMap<i32, ObjectTemplate>);
|
||||
|
||||
impl IntoIterator for TemplateDatabase {
|
||||
type Item = (i32, ObjectTemplate);
|
||||
type IntoIter = std::collections::btree_map::IntoIter<i32, ObjectTemplate>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Tsify)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
pub struct ReagentDatabase(BTreeMap<u8, Reagent>);
|
||||
|
||||
impl IntoIterator for ReagentDatabase {
|
||||
type Item = (u8, Reagent);
|
||||
type IntoIter = std::collections::btree_map::IntoIter<u8, Reagent>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Tsify)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
pub struct FrozenObjects(Vec<FrozenObjectFull>);
|
||||
|
||||
impl IntoIterator for FrozenObjects {
|
||||
type Item = FrozenObjectFull;
|
||||
type IntoIter = std::vec::IntoIter<FrozenObjectFull>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Tsify)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
pub struct FrozenObjectsSparse(Vec<FrozenObject>);
|
||||
|
||||
impl IntoIterator for FrozenObjectsSparse {
|
||||
type Item = FrozenObject;
|
||||
type IntoIter = std::vec::IntoIter<FrozenObject>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Tsify)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
pub struct FrozenNetworks(Vec<FrozenCableNetwork>);
|
||||
|
||||
impl IntoIterator for FrozenNetworks {
|
||||
type Item = FrozenCableNetwork;
|
||||
type IntoIter = std::vec::IntoIter<FrozenCableNetwork>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Tsify)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
pub struct CompileErrors(Vec<ICError>);
|
||||
|
||||
impl IntoIterator for CompileErrors {
|
||||
type Item = ICError;
|
||||
type IntoIter = std::vec::IntoIter<ICError>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
use color_eyre::eyre;
|
||||
pub fn parse_value<'a, T: serde::Deserialize<'a>>(
|
||||
jd: impl serde::Deserializer<'a>,
|
||||
) -> Result<T, color_eyre::Report> {
|
||||
let mut track = serde_path_to_error::Track::new();
|
||||
let path = serde_path_to_error::Deserializer::new(jd, &mut track);
|
||||
let mut fun = |path: serde_ignored::Path| {
|
||||
tracing::warn!("Found ignored key: {path}");
|
||||
};
|
||||
serde_ignored::deserialize(path, &mut fun).map_err(|e| {
|
||||
eyre::eyre!(
|
||||
"path: {track} | error = {e}",
|
||||
track = track.path().to_string(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[wasm_bindgen]
|
||||
impl VMRef {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
VMRef {
|
||||
vm: Rc::new(RefCell::new(VM::new())),
|
||||
}
|
||||
VMRef { vm: VM::new() }
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "addDevice")]
|
||||
pub fn add_device(&self, network: Option<u32>) -> Result<u32, JsError> {
|
||||
Ok(self.vm.borrow_mut().add_device(network)?)
|
||||
#[wasm_bindgen(js_name = "importTemplateDatabase")]
|
||||
pub fn import_template_database(&self, db: TemplateDatabase) {
|
||||
self.vm.import_template_database(db);
|
||||
}
|
||||
|
||||
#[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)?;
|
||||
#[wasm_bindgen(js_name = "importReagentDatabase")]
|
||||
pub fn import_reagent_database(&self, db: ReagentDatabase) {
|
||||
self.vm.import_reagent_database(db);
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "importTemplateDatabaseSerdeWasm")]
|
||||
pub fn import_template_database_serde_wasm(&self, db: JsValue) -> Result<(), JsError> {
|
||||
let parsed_db: BTreeMap<i32, ObjectTemplate> =
|
||||
parse_value(serde_wasm_bindgen::Deserializer::from(db)).map_err(|err| {
|
||||
<&dyn std::error::Error as std::convert::Into<JsError>>::into(
|
||||
std::convert::AsRef::<dyn std::error::Error>::as_ref(&err),
|
||||
)
|
||||
})?;
|
||||
self.vm.import_template_database(parsed_db);
|
||||
Ok(())
|
||||
}
|
||||
#[wasm_bindgen(js_name = "importTemplateDatabaseSerdeJson")]
|
||||
pub fn import_template_database_serde_json(&self, db: String) -> Result<(), JsError> {
|
||||
let parsed_db: BTreeMap<i32, ObjectTemplate> =
|
||||
parse_value(&mut serde_json::Deserializer::from_str(&db)).map_err(|err| {
|
||||
<&dyn std::error::Error as std::convert::Into<JsError>>::into(
|
||||
std::convert::AsRef::<dyn std::error::Error>::as_ref(&err),
|
||||
)
|
||||
})?;
|
||||
self.vm.import_template_database(parsed_db);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "getTemplateDatabase")]
|
||||
pub fn get_template_database(&self) -> TemplateDatabase {
|
||||
TemplateDatabase(self.vm.get_template_database())
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "addObjectFrozen")]
|
||||
pub fn add_object_frozen(&self, frozen: FrozenObject) -> Result<ObjectID, JsError> {
|
||||
web_sys::console::log_2(
|
||||
&"(wasm) adding device".into(),
|
||||
&serde_wasm_bindgen::to_value(&template).unwrap(),
|
||||
&serde_wasm_bindgen::to_value(&frozen).unwrap(),
|
||||
);
|
||||
Ok(self.vm.borrow_mut().add_device_from_template(template)?)
|
||||
Ok(self.vm.add_object_frozen(frozen)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "getDevice")]
|
||||
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 = "addObjectsFrozen")]
|
||||
pub fn add_objects_frozen(
|
||||
&self,
|
||||
frozen_objects: FrozenObjectsSparse,
|
||||
) -> Result<Vec<ObjectID>, JsError> {
|
||||
web_sys::console::log_2(
|
||||
&"(wasm) adding device".into(),
|
||||
&serde_wasm_bindgen::to_value(&frozen_objects).unwrap(),
|
||||
);
|
||||
|
||||
Ok(self.vm.add_objects_frozen(frozen_objects)?)
|
||||
}
|
||||
|
||||
// #[wasm_bindgen(js_name = "getDevice")]
|
||||
// pub fn get_object(&self, id: ObjectID) -> Option<VMObject> {
|
||||
// self.vm.get_object(id)
|
||||
// }
|
||||
|
||||
#[wasm_bindgen(js_name = "freezeObject")]
|
||||
pub fn freeze_object(&self, id: ObjectID) -> Result<FrozenObjectFull, JsError> {
|
||||
Ok(self.vm.freeze_object(id)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "freezeObjects")]
|
||||
pub fn freeze_objects(&self, ids: Vec<ObjectID>) -> Result<FrozenObjects, JsError> {
|
||||
Ok(FrozenObjects(self.vm.freeze_objects(ids)?))
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "freezeNetwork")]
|
||||
pub fn freeze_network(&self, id: ObjectID) -> Result<FrozenCableNetwork, JsError> {
|
||||
Ok(self.vm.freeze_network(id)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "freezeNetworks")]
|
||||
pub fn freeze_networks(&self, ids: Vec<ObjectID>) -> Result<FrozenNetworks, JsError> {
|
||||
Ok(FrozenNetworks(self.vm.freeze_networks(ids)?))
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setCode")]
|
||||
/// Set program code if it's valid
|
||||
pub fn set_code(&self, id: u32, code: &str) -> Result<bool, JsError> {
|
||||
Ok(self.vm.borrow().set_code(id, code)?)
|
||||
pub fn set_code(&self, id: ObjectID, code: &str) -> Result<bool, JsError> {
|
||||
Ok(self.vm.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: u32, code: &str) -> Result<bool, JsError> {
|
||||
Ok(self.vm.borrow().set_code_invalid(id, code)?)
|
||||
pub fn set_code_invalid(&self, id: ObjectID, code: &str) -> Result<bool, JsError> {
|
||||
Ok(self.vm.set_code_invalid(id, code)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "stepIC")]
|
||||
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 = "getCode")]
|
||||
/// Set program code if it's valid
|
||||
pub fn get_code(&self, id: ObjectID) -> Result<String, JsError> {
|
||||
Ok(self.vm.get_code(id)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "runIC")]
|
||||
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 = "getCompileErrors")]
|
||||
/// Set program code if it's valid
|
||||
pub fn get_compiler_errors(&self, id: ObjectID) -> Result<CompileErrors, JsError> {
|
||||
Ok(CompileErrors(self.vm.get_compile_errors(id)?))
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "resetIC")]
|
||||
pub fn reset_ic(&self, id: u32) -> Result<bool, JsError> {
|
||||
Ok(self.vm.borrow().reset_ic(id)?)
|
||||
#[wasm_bindgen(js_name = "stepProgrammable")]
|
||||
pub fn step_programmable(&self, id: ObjectID, advance_ip_on_err: bool) -> Result<(), JsError> {
|
||||
Ok(self.vm.step_programmable(id, advance_ip_on_err)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "defaultNetwork")]
|
||||
pub fn default_network(&self) -> u32 {
|
||||
self.vm.borrow().default_network
|
||||
#[wasm_bindgen(js_name = "runProgrammable")]
|
||||
pub fn run_programmable(&self, id: ObjectID, ignore_errors: bool) -> Result<bool, JsError> {
|
||||
Ok(self.vm.run_programmable(id, ignore_errors)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn devices(&self) -> Vec<u32> {
|
||||
self.vm.borrow().devices.keys().copied().collect_vec()
|
||||
#[wasm_bindgen(js_name = "resetProgrammable")]
|
||||
pub fn reset_ic(&self, id: ObjectID) -> Result<bool, JsError> {
|
||||
Ok(self.vm.reset_programmable(id)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn networks(&self) -> Vec<u32> {
|
||||
self.vm.borrow().networks.keys().copied().collect_vec()
|
||||
#[wasm_bindgen(js_name = "getDefaultNetwork")]
|
||||
pub fn get_default_network(&self) -> ObjectID {
|
||||
*self.vm.default_network_key.borrow()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn ics(&self) -> Vec<u32> {
|
||||
self.vm.borrow().ics.keys().copied().collect_vec()
|
||||
#[wasm_bindgen(js_name = "getObjects")]
|
||||
pub fn get_objects(&self) -> Vec<ObjectID> {
|
||||
self.vm.objects.borrow().keys().copied().collect_vec()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "lastOperationModified")]
|
||||
pub fn last_operation_modified(&self) -> Vec<u32> {
|
||||
self.vm.borrow().last_operation_modified()
|
||||
#[wasm_bindgen(js_name = "getNetworks")]
|
||||
pub fn get_networks(&self) -> Vec<ObjectID> {
|
||||
self.vm.networks.borrow().keys().copied().collect_vec()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "getCircuitHolders")]
|
||||
pub fn get_circuit_holders(&self) -> Vec<ObjectID> {
|
||||
self.vm.circuit_holders.borrow().clone()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "getProgramHolders")]
|
||||
pub fn get_program_holders(&self) -> Vec<ObjectID> {
|
||||
self.vm.program_holders.borrow().clone()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "getLastOperationModified")]
|
||||
pub fn get_last_operation_modified(&self) -> Vec<ObjectID> {
|
||||
self.vm.last_operation_modified()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "visibleDevices")]
|
||||
pub fn visible_devices(&self, source: u32) -> Vec<u32> {
|
||||
self.vm.borrow().visible_devices(source)
|
||||
pub fn visible_devices(&self, source: ObjectID) -> Vec<u32> {
|
||||
self.vm.visible_devices(source)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setDeviceConnection")]
|
||||
pub fn set_device_connection(
|
||||
&self,
|
||||
id: u32,
|
||||
id: ObjectID,
|
||||
connection: usize,
|
||||
network_id: Option<u32>,
|
||||
network_id: Option<ObjectID>,
|
||||
) -> Result<bool, JsError> {
|
||||
Ok(self
|
||||
.vm
|
||||
.borrow()
|
||||
.set_device_connection(id, connection, network_id)?)
|
||||
Ok(self.vm.set_device_connection(id, connection, network_id)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "removeDeviceFromNetwork")]
|
||||
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)?)
|
||||
pub fn remove_device_from_network(
|
||||
&self,
|
||||
id: ObjectID,
|
||||
network_id: u32,
|
||||
) -> Result<bool, JsError> {
|
||||
Ok(self.vm.remove_device_from_network(id, network_id)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setPin")]
|
||||
pub fn set_pin(&self, id: u32, pin: usize, val: Option<u32>) -> Result<bool, JsError> {
|
||||
Ok(self.vm.borrow().set_pin(id, pin, val)?)
|
||||
pub fn set_pin(&self, id: ObjectID, pin: usize, val: Option<u32>) -> Result<bool, JsError> {
|
||||
Ok(self.vm.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)?)
|
||||
pub fn change_device_id(&self, old_id: ObjectID, new_id: u32) -> Result<(), JsError> {
|
||||
Ok(self.vm.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)?)
|
||||
pub fn remove_device(&self, id: ObjectID) -> Result<(), JsError> {
|
||||
Ok(self.vm.remove_object(id)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setSlotOccupant", skip_typescript)]
|
||||
#[wasm_bindgen(js_name = "setSlotOccupant")]
|
||||
pub fn set_slot_occupant(
|
||||
&self,
|
||||
id: u32,
|
||||
id: ObjectID,
|
||||
index: usize,
|
||||
template: JsValue,
|
||||
) -> Result<(), JsError> {
|
||||
let template: SlotOccupantTemplate = serde_wasm_bindgen::from_value(template)?;
|
||||
frozen: FrozenObject,
|
||||
quantity: u32,
|
||||
) -> Result<Option<ObjectID>, JsError> {
|
||||
let Some(prefab) = frozen.obj_info.prefab.as_ref() else {
|
||||
return Err(TemplateError::MissingPrefab.into());
|
||||
};
|
||||
let obj_id = if let Some(obj) = frozen.obj_info.id.and_then(|id| self.vm.get_object(id)) {
|
||||
// TODO: we just assume if the ID is found that the frozen object passed is the same object..
|
||||
obj.get_id()
|
||||
} else {
|
||||
// check to see if frozen is using the same prefab as current occupant
|
||||
let obj_id = if let Some(occupant_id) = {
|
||||
let obj = self.vm.get_object(id).ok_or(VMError::UnknownId(id))?;
|
||||
let obj_ref = obj.borrow();
|
||||
let storage = obj_ref.as_storage().ok_or(VMError::NotStorage(id))?;
|
||||
let slot = storage
|
||||
.get_slot(index)
|
||||
.ok_or(ICError::SlotIndexOutOfRange(index as f64))?;
|
||||
slot.occupant.as_ref().map(|info| info.id)
|
||||
} {
|
||||
let occupant = self
|
||||
.vm
|
||||
.get_object(id)
|
||||
.ok_or(VMError::UnknownId(occupant_id))?;
|
||||
let occupant_ref = occupant.borrow();
|
||||
let occupant_prefab = occupant_ref.get_prefab();
|
||||
if prefab.as_str() == occupant_prefab.value.as_str() {
|
||||
Some(*occupant_ref.get_id())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(obj_id) = obj_id {
|
||||
obj_id
|
||||
} else {
|
||||
self.vm.add_object_frozen(frozen)?
|
||||
}
|
||||
};
|
||||
Ok(self
|
||||
.vm
|
||||
.borrow_mut()
|
||||
.set_slot_occupant(id, index, template)?)
|
||||
.set_slot_occupant(id, index, Some(obj_id), quantity)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "removeSlotOccupant")]
|
||||
pub fn remove_slot_occupant(&self, id: u32, index: usize) -> Result<(), JsError> {
|
||||
Ok(self.vm.borrow_mut().remove_slot_occupant(id, index)?)
|
||||
pub fn remove_slot_occupant(
|
||||
&self,
|
||||
id: ObjectID,
|
||||
index: usize,
|
||||
) -> Result<Option<ObjectID>, JsError> {
|
||||
Ok(self.vm.remove_slot_occupant(id, index)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "saveVMState", skip_typescript)]
|
||||
pub fn save_vm_state(&self) -> JsValue {
|
||||
let state = self.vm.borrow().save_vm_state();
|
||||
serde_wasm_bindgen::to_value(&state).unwrap()
|
||||
#[wasm_bindgen(js_name = "saveVMState")]
|
||||
pub fn save_vm_state(&self) -> Result<FrozenVM, JsError> {
|
||||
Ok(self.vm.save_vm_state()?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "restoreVMState", skip_typescript)]
|
||||
pub fn restore_vm_state(&self, state: JsValue) -> Result<(), JsError> {
|
||||
let state: FrozenVM = serde_wasm_bindgen::from_value(state)?;
|
||||
self.vm.borrow_mut().restore_vm_state(state)?;
|
||||
#[wasm_bindgen(js_name = "restoreVMState")]
|
||||
pub fn restore_vm_state(&self, state: FrozenVM) -> Result<(), JsError> {
|
||||
self.vm.restore_vm_state(state)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "getObjectName")]
|
||||
pub fn get_object_name(&self, id: ObjectID) -> Result<String, JsError> {
|
||||
let obj = self.vm.get_object(id).ok_or(VMError::UnknownId(id))?;
|
||||
let name = obj.borrow().get_name().value.clone();
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setObjectName")]
|
||||
pub fn set_object_name(&self, id: ObjectID, name: &str) -> Result<(), JsError> {
|
||||
let obj = self.vm.get_object(id).ok_or(VMError::UnknownId(id))?;
|
||||
obj.borrow_mut().get_mut_name().value = name.to_string();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "getObjectHash")]
|
||||
pub fn get_object_hash(&self, id: ObjectID) -> Result<i32, JsError> {
|
||||
let obj = self.vm.get_object(id).ok_or(VMError::UnknownId(id))?;
|
||||
let hash = obj.borrow().get_name().hash;
|
||||
Ok(hash)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "getObjectPrefabName")]
|
||||
pub fn get_object_prefab_name(&self, id: ObjectID) -> Result<String, JsError> {
|
||||
let obj = self.vm.get_object(id).ok_or(VMError::UnknownId(id))?;
|
||||
let name = obj.borrow().get_prefab().value.clone();
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "getObjectPrefabHash")]
|
||||
pub fn get_object_prefab_hash(&self, id: ObjectID) -> Result<i32, JsError> {
|
||||
let obj = self.vm.get_object(id).ok_or(VMError::UnknownId(id))?;
|
||||
let hash = obj.borrow().get_prefab().hash;
|
||||
Ok(hash)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "getObjectSourceCode")]
|
||||
pub fn get_object_source_code(&self, id: ObjectID) -> Result<Option<String>, JsError> {
|
||||
let obj = self.vm.get_object(id).ok_or(VMError::UnknownId(id))?;
|
||||
let code = obj
|
||||
.borrow()
|
||||
.as_source_code()
|
||||
.map(|source| source.get_source_code());
|
||||
Ok(code)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setRegister")]
|
||||
pub fn set_register(&self, id: ObjectID, index: u32, val: f64) -> Result<f64, JsError> {
|
||||
Ok(self.vm.set_register(id, index, val)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setMemory")]
|
||||
pub fn set_memory(&self, id: ObjectID, address: u32, val: f64) -> Result<f64, JsError> {
|
||||
Ok(self.vm.set_memory(id, address, val)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setLogicField")]
|
||||
pub fn set_logic_field(
|
||||
&self,
|
||||
id: ObjectID,
|
||||
lt: LogicType,
|
||||
val: f64,
|
||||
force: bool,
|
||||
) -> Result<(), JsError> {
|
||||
Ok(self.vm.set_logic_field(id, lt, val, force)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setSlotLogicField")]
|
||||
pub fn set_slot_logic_field(
|
||||
&self,
|
||||
id: ObjectID,
|
||||
slt: LogicSlotType,
|
||||
index: u32,
|
||||
val: f64,
|
||||
force: bool,
|
||||
) -> Result<(), JsError> {
|
||||
Ok(self.vm.set_slot_logic_field(id, slt, index, val, force)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for VMRef {
|
||||
@@ -524,7 +496,8 @@ impl Default for VMRef {
|
||||
#[wasm_bindgen]
|
||||
pub fn init() -> VMRef {
|
||||
utils::set_panic_hook();
|
||||
tracing_wasm::set_as_global_default();
|
||||
let vm = VMRef::new();
|
||||
log!("Hello from ic10emu!");
|
||||
tracing::info!("Hello from ic10emu!");
|
||||
vm
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::serde_as;
|
||||
use tsify::Tsify;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Tsify, Serialize, Deserialize)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
pub struct Stack(#[serde_as(as = "[_; 512]")] pub [f64; 512]);
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Tsify, Serialize, Deserialize)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
pub struct Registers(#[serde_as(as = "[_; 18]")] pub [f64; 18]);
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Tsify, Debug, Clone, Serialize, Deserialize)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
pub struct SlotOccupant {
|
||||
pub id: u32,
|
||||
pub prefab_hash: i32,
|
||||
pub quantity: u32,
|
||||
pub max_quantity: u32,
|
||||
pub damage: f64,
|
||||
pub fields: BTreeMap<ic10emu::grammar::SlotLogicType, ic10emu::device::LogicField>,
|
||||
}
|
||||
|
||||
impl From<&ic10emu::device::SlotOccupant> for SlotOccupant {
|
||||
fn from(value: &ic10emu::device::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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Tsify, Debug, Clone, Default, Serialize, Deserialize)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
pub struct Slot {
|
||||
pub typ: ic10emu::device::SlotType,
|
||||
pub occupant: Option<SlotOccupant>,
|
||||
pub fields: BTreeMap<ic10emu::grammar::SlotLogicType, ic10emu::device::LogicField>,
|
||||
}
|
||||
|
||||
impl From<&ic10emu::device::Slot> for Slot {
|
||||
fn from(value: &ic10emu::device::Slot) -> Self {
|
||||
Slot {
|
||||
typ: value.typ,
|
||||
occupant: value.occupant.as_ref().map(|occupant| occupant.into()),
|
||||
fields: value.get_fields(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Tsify, Debug, Clone, Serialize, Deserialize)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
pub struct Slots(pub Vec<Slot>);
|
||||
|
||||
impl<'a> FromIterator<&'a ic10emu::device::Slot> for Slots {
|
||||
fn from_iter<T: IntoIterator<Item = &'a ic10emu::device::Slot>>(iter: T) -> Self {
|
||||
Slots(iter.into_iter().map(|slot| slot.into()).collect_vec())
|
||||
}
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/ts_types.rs"));
|
||||
@@ -1,169 +0,0 @@
|
||||
export type FieldType = "Read" | "Write" | "ReadWrite";
|
||||
|
||||
export interface LogicField {
|
||||
field_type: FieldType;
|
||||
value: number;
|
||||
}
|
||||
export type LogicFields = Map<LogicType, LogicField>;
|
||||
export type SlotLogicFields = Map<SlotLogicType, LogicField>;
|
||||
|
||||
export type Reagents = Map<string, Map<number, number>>;
|
||||
|
||||
export interface ConnectionCableNetwork {
|
||||
CableNetwork: {
|
||||
net: number | undefined;
|
||||
typ: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type Connection = ConnectionCableNetwork | "Other";
|
||||
|
||||
export type RegisterSpec = {
|
||||
readonly RegisterSpec: {
|
||||
readonly indirection: number;
|
||||
readonly target: number;
|
||||
};
|
||||
};
|
||||
export type DeviceSpec = {
|
||||
readonly DeviceSpec: {
|
||||
readonly device:
|
||||
| "Db"
|
||||
| { readonly Numbered: number }
|
||||
| {
|
||||
readonly Indirect: {
|
||||
readonly indirection: number;
|
||||
readonly target: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
readonly connection: number | undefined;
|
||||
};
|
||||
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 = { readonly Float: number };
|
||||
export type NumberBinary = { readonly Binary: BigInt };
|
||||
export type NumberHexadecimal = { readonly Hexadecimal: BigInt };
|
||||
export type NumberConstant = { readonly Constant: number };
|
||||
export type NumberString = { readonly String: string };
|
||||
export type NumberEnum = { readonly Enum: number };
|
||||
|
||||
export type NumberOperand = {
|
||||
Number:
|
||||
| NumberFloat
|
||||
| NumberBinary
|
||||
| NumberHexadecimal
|
||||
| NumberConstant
|
||||
| NumberString
|
||||
| NumberEnum;
|
||||
};
|
||||
export type Operand =
|
||||
| RegisterSpec
|
||||
| DeviceSpec
|
||||
| NumberOperand
|
||||
| OperandLogicType
|
||||
| OperandSlotLogicType
|
||||
| OperandBatchMode
|
||||
| OperandReagentMode
|
||||
| Identifier;
|
||||
|
||||
export type Alias = RegisterSpec | DeviceSpec;
|
||||
|
||||
export type Aliases = Map<string, Alias>;
|
||||
|
||||
export type Defines = Map<string, number>;
|
||||
|
||||
export type Pins = (number | undefined)[];
|
||||
|
||||
export interface Instruction {
|
||||
readonly instruction: string;
|
||||
readonly operands: Operand[];
|
||||
}
|
||||
|
||||
export type ICError = {
|
||||
readonly ParseError: {
|
||||
readonly line: number;
|
||||
readonly start: number;
|
||||
readonly end: number;
|
||||
readonly msg: string;
|
||||
};
|
||||
};
|
||||
|
||||
export interface Program {
|
||||
readonly instructions: Instruction[];
|
||||
readonly errors: ICError[];
|
||||
readonly labels: Map<string, number>;
|
||||
}
|
||||
|
||||
export interface DeviceRef {
|
||||
readonly fields: LogicFields;
|
||||
readonly slots: Slot[];
|
||||
readonly reagents: Reagents;
|
||||
readonly connections: Connection[];
|
||||
readonly aliases?: Aliases | undefined;
|
||||
readonly defines?: Defines | undefined;
|
||||
readonly pins?: Pins;
|
||||
readonly program?: Program;
|
||||
getSlotFields(slot: number): SlotLogicFields;
|
||||
setField(field: LogicType, value: number, force: boolean): void;
|
||||
setSlotField(slot: number, field: SlotLogicType, value: number, force: boolean): void;
|
||||
getSlotField(slot: number, field: SlotLogicType): number;
|
||||
}
|
||||
|
||||
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 FrozenIC {
|
||||
device: number;
|
||||
id: number;
|
||||
registers: number[];
|
||||
ip: number;
|
||||
ic: number;
|
||||
stack: number[];
|
||||
aliases: Aliases;
|
||||
defines: Defines;
|
||||
pins: Pins;
|
||||
state: string;
|
||||
code: string;
|
||||
}
|
||||
|
||||
export interface FrozenNetwork {
|
||||
id: number;
|
||||
devices: number[];
|
||||
power_only: number[];
|
||||
channels: number[];
|
||||
}
|
||||
|
||||
export interface FrozenVM {
|
||||
ics: FrozenIC[];
|
||||
devices: DeviceTemplate[];
|
||||
networks: FrozenNetwork[];
|
||||
default_network: number;
|
||||
}
|
||||
|
||||
export interface VMRef {
|
||||
addDeviceFromTemplate(template: DeviceTemplate): number;
|
||||
setSlotOccupant(id: number, index: number, template: SlotOccupantTemplate);
|
||||
saveVMState(): FrozenVM;
|
||||
restoreVMState(state: FrozenVM): void;
|
||||
}
|
||||
@@ -8,17 +8,6 @@ pub fn set_panic_hook() {
|
||||
#[cfg(feature = "console_error_panic_hook")]
|
||||
{
|
||||
console_error_panic_hook::set_once();
|
||||
web_sys::console::log_1(&format!("Panic hook set...").into());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
extern crate web_sys;
|
||||
|
||||
// A macro to provide `println!(..)`-style syntax for `console.log` logging.
|
||||
macro_rules! log {
|
||||
( $( $t:tt )* ) => {
|
||||
web_sys::console::log_1(&format!( $( $t )* ).into());
|
||||
web_sys::console::log_1(&"Panic hook set...".into());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,19 +11,43 @@ crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
console_error_panic_hook = "0.1.7"
|
||||
futures = "0.3.21"
|
||||
futures = "0.3.30"
|
||||
js-sys = "0.3.69"
|
||||
web-sys = { version = "0.3.69", features = ["WritableStream", "console"] }
|
||||
tokio = { version = "1.26.0", features = ["sync"] }
|
||||
tokio = { version = "1.37.0", features = ["sync"] }
|
||||
tower-lsp = { version = "0.20.0", default-features = false, features = [
|
||||
"runtime-agnostic",
|
||||
] }
|
||||
# tree-sitter = { version = "0.9.0", package = "tree-sitter-facade" }
|
||||
wasm-bindgen = "0.2.81"
|
||||
wasm-bindgen-futures = { version = "0.4.30", features = [
|
||||
wasm-bindgen = "0.2.92"
|
||||
wasm-bindgen-futures = { version = "0.4.42", features = [
|
||||
"futures-core-03-stream",
|
||||
] }
|
||||
wasm-streams = "0.4"
|
||||
# web-tree-sitter-sys = "1.3"
|
||||
ic10lsp = { git = "https://github.com/Ryex/ic10lsp.git", branch = "wasm" }
|
||||
tracing-wasm = "0.2.1"
|
||||
tracing = "0.1.40"
|
||||
# ic10lsp = { path = "../../ic10lsp" }
|
||||
|
||||
[package.metadata.wasm-pack.profile.dev]
|
||||
wasm-opt = ['-O']
|
||||
|
||||
[package.metadata.wasm-pack.profile.dev.wasm-bindgen]
|
||||
# Should we enable wasm-bindgen's debug assertions in its generated JS glue?
|
||||
debug-js-glue = true
|
||||
# Should wasm-bindgen demangle the symbols in the "name" custom section?
|
||||
demangle-name-section = true
|
||||
# Should we emit the DWARF debug info custom sections?
|
||||
dwarf-debug-info = false
|
||||
# Should we omit the default import path?
|
||||
omit-default-module-path = false
|
||||
|
||||
[package.metadata.wasm-pack.profile.release]
|
||||
wasm-opt = ['-Oz']
|
||||
|
||||
[package.metadata.wasm-pack.profile.release.wasm-bindgen]
|
||||
debug-js-glue = false
|
||||
demangle-name-section = true
|
||||
dwarf-debug-info = false
|
||||
omit-default-module-path = false
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use futures::stream::TryStreamExt;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use tokio::sync::RwLock;
|
||||
use futures::stream::TryStreamExt;
|
||||
use tower_lsp::{LspService, Server};
|
||||
use wasm_bindgen::{prelude::*, JsCast};
|
||||
use wasm_bindgen_futures::stream::JsStream;
|
||||
@@ -30,8 +30,9 @@ impl ServerConfig {
|
||||
#[wasm_bindgen]
|
||||
pub async fn serve(config: ServerConfig) -> Result<(), JsValue> {
|
||||
console_error_panic_hook::set_once();
|
||||
tracing_wasm::set_as_global_default();
|
||||
|
||||
web_sys::console::log_1(&"server::serve".into());
|
||||
tracing::trace!("server::serv error:");
|
||||
|
||||
let ServerConfig {
|
||||
into_server,
|
||||
@@ -51,6 +52,7 @@ pub async fn serve(config: ServerConfig) -> Result<(), JsValue> {
|
||||
})
|
||||
.map_err(|err| {
|
||||
web_sys::console::log_2(&"server::input Error: ".into(), &err);
|
||||
tracing::error!("server::input error: {:?}", &err);
|
||||
|
||||
std::io::Error::from(std::io::ErrorKind::Other)
|
||||
})
|
||||
@@ -60,14 +62,14 @@ pub async fn serve(config: ServerConfig) -> Result<(), JsValue> {
|
||||
let output = wasm_streams::WritableStream::from_raw(output);
|
||||
let output = output.try_into_async_write().map_err(|err| err.0)?;
|
||||
|
||||
let (service, messages) = LspService::new(|client| ic10lsp_lib::server::Backend{
|
||||
let (service, messages) = LspService::new(|client| ic10lsp_lib::server::Backend {
|
||||
client,
|
||||
files: Arc::new(RwLock::new(HashMap::new())),
|
||||
config: Arc::new(RwLock::new(ic10lsp_lib::server::Configuration::default())),
|
||||
});
|
||||
Server::new(input, output, messages).serve(service).await;
|
||||
|
||||
web_sys::console::log_1(&"server::serve ic10lsp started".into());
|
||||
tracing::info!("server::serve ic10lsp started");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
6
rust-analyzer.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"rust-analyzer.cargo.features": [
|
||||
"tsify",
|
||||
"prefab_database"
|
||||
]
|
||||
}
|
||||
223
rust-testing.ipynb
Normal file
@@ -0,0 +1,223 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
":dep stationeers_data = { path = \"./stationeers_data\" }\n",
|
||||
":dep const-crc32 = \"1.3.0\"\n",
|
||||
":dep color-eyre\n",
|
||||
":dep serde_path_to_error\n",
|
||||
":dep serde_ignored\n",
|
||||
":dep serde\n",
|
||||
":dep serde_json\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 21,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"use color_eyre::eyre;\n",
|
||||
"pub fn parse_value<'a, T: serde::Deserialize<'a>>(\n",
|
||||
" jd: impl serde::Deserializer<'a>,\n",
|
||||
") -> Result<T, color_eyre::Report> {\n",
|
||||
" let mut track = serde_path_to_error::Track::new();\n",
|
||||
" let path = serde_path_to_error::Deserializer::new(jd, &mut track);\n",
|
||||
" let mut fun = |path: serde_ignored::Path| {\n",
|
||||
" eprintln!(\"Found ignored key: {path}\");\n",
|
||||
" };\n",
|
||||
" serde_ignored::deserialize(path, &mut fun).map_err(|e| {\n",
|
||||
" eyre::eyre!(\n",
|
||||
" \"path: {track} | error = {e}\",\n",
|
||||
" track = track.path().to_string(),\n",
|
||||
" )\n",
|
||||
" })\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 25,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{7274344: StructureLogicDevice(StructureLogicDeviceTemplate { prefab: PrefabInfo { prefab_name: \"StructureAutoMinerSmall\", prefab_hash: 7274344, desc: \"The <link=Recurso><color=#0080FFFF>Recurso</color></link> SquareDig autominer is a structure that when built will mine a vertical 2x2 shaft until it hits bedrock. The autominer can be connected to a chute system, and is controllable by a logic network. Note that the autominer outputs more <link=OrePage><color=#0080FFFF>ore</color></link> than a conventional <link=ThingItemMiningDrill><color=green>Mining Drill</color></link> over the same area.\", name: \"Autominer (Small)\" }, structure: StructureInfo { small_grid: true }, thermal_info: None, internal_atmo_info: None, logic: LogicInfo { logic_slot_types: {0: {}, 1: {}}, logic_types: {Power: Read, Open: ReadWrite, Error: Read, Activate: ReadWrite, On: ReadWrite, RequiredPower: Read, ClearMemory: Write, ExportCount: Read, ImportCount: Read, PrefabHash: Read, ReferenceId: Read, NameHash: Read}, modes: None, transmission_receiver: false, wireless_logic: false, circuit_holder: false }, slots: [SlotInfo { name: \"Import\", typ: None }, SlotInfo { name: \"Export\", typ: None }], device: DeviceInfo { connection_list: [ConnectionInfo { typ: Chute, role: Input }, ConnectionInfo { typ: Chute, role: Output }, ConnectionInfo { typ: Data, role: None }, ConnectionInfo { typ: Power, role: None }], device_pins_length: None, has_activate_state: true, has_atmosphere: false, has_color_state: false, has_lock_state: false, has_mode_state: false, has_on_off_state: true, has_open_state: true, has_reagents: false } }), 111280987: ItemLogic(ItemLogicTemplate { prefab: PrefabInfo { prefab_name: \"ItemTerrainManipulator\", prefab_hash: 111280987, desc: \"0.Mode0\\n1.Mode1\", name: \"Terrain Manipulator\" }, item: ItemInfo { consumable: false, filter_type: None, ingredient: false, max_quantity: 1, reagents: None, slot_class: Tool, sorting_class: Default }, thermal_info: None, internal_atmo_info: None, logic: LogicInfo { logic_slot_types: {0: {Occupied: Read, OccupantHash: Read, Quantity: Read, Damage: Read, Charge: Read, ChargeRatio: Read, Class: Read, MaxQuantity: Read, ReferenceId: Read}, 1: {Occupied: Read, OccupantHash: Read, Quantity: Read, Damage: Read, Class: Read, MaxQuantity: Read, ReferenceId: Read}}, logic_types: {Power: Read, Mode: ReadWrite, Error: Read, Activate: ReadWrite, On: ReadWrite, ReferenceId: Read}, modes: Some({0: \"Mode0\", 1: \"Mode1\"}), transmission_receiver: false, wireless_logic: false, circuit_holder: false }, slots: [SlotInfo { name: \"Battery\", typ: Battery }, SlotInfo { name: \"Dirt Canister\", typ: Ore }] })}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"let entries = r#\"\n",
|
||||
"{\n",
|
||||
"\"7274344\": {\n",
|
||||
" \"templateType\": \"StructureLogicDevice\",\n",
|
||||
" \"prefab\": {\n",
|
||||
" \"prefab_name\": \"StructureAutoMinerSmall\",\n",
|
||||
" \"prefab_hash\": 7274344,\n",
|
||||
" \"desc\": \"The <link=Recurso><color=#0080FFFF>Recurso</color></link> SquareDig autominer is a structure that when built will mine a vertical 2x2 shaft until it hits bedrock. The autominer can be connected to a chute system, and is controllable by a logic network. Note that the autominer outputs more <link=OrePage><color=#0080FFFF>ore</color></link> than a conventional <link=ThingItemMiningDrill><color=green>Mining Drill</color></link> over the same area.\",\n",
|
||||
" \"name\": \"Autominer (Small)\"\n",
|
||||
" },\n",
|
||||
" \"structure\": {\n",
|
||||
" \"small_grid\": true\n",
|
||||
" },\n",
|
||||
" \"logic\": {\n",
|
||||
" \"logic_slot_types\": {\n",
|
||||
" \"0\": {},\n",
|
||||
" \"1\": {}\n",
|
||||
" },\n",
|
||||
" \"logic_types\": {\n",
|
||||
" \"Power\": \"Read\",\n",
|
||||
" \"Open\": \"ReadWrite\",\n",
|
||||
" \"Error\": \"Read\",\n",
|
||||
" \"Activate\": \"ReadWrite\",\n",
|
||||
" \"On\": \"ReadWrite\",\n",
|
||||
" \"RequiredPower\": \"Read\",\n",
|
||||
" \"ClearMemory\": \"Write\",\n",
|
||||
" \"ExportCount\": \"Read\",\n",
|
||||
" \"ImportCount\": \"Read\",\n",
|
||||
" \"PrefabHash\": \"Read\",\n",
|
||||
" \"ReferenceId\": \"Read\",\n",
|
||||
" \"NameHash\": \"Read\"\n",
|
||||
" },\n",
|
||||
" \"transmission_receiver\": false,\n",
|
||||
" \"wireless_logic\": false,\n",
|
||||
" \"circuit_holder\": false\n",
|
||||
" },\n",
|
||||
" \"slots\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"Import\",\n",
|
||||
" \"typ\": \"None\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"Export\",\n",
|
||||
" \"typ\": \"None\"\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" \"device\": {\n",
|
||||
" \"connection_list\": [\n",
|
||||
" {\n",
|
||||
" \"typ\": \"Chute\",\n",
|
||||
" \"role\": \"Input\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"typ\": \"Chute\",\n",
|
||||
" \"role\": \"Output\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"typ\": \"Data\",\n",
|
||||
" \"role\": \"None\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"typ\": \"Power\",\n",
|
||||
" \"role\": \"None\"\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" \"has_activate_state\": true,\n",
|
||||
" \"has_atmosphere\": false,\n",
|
||||
" \"has_color_state\": false,\n",
|
||||
" \"has_lock_state\": false,\n",
|
||||
" \"has_mode_state\": false,\n",
|
||||
" \"has_on_off_state\": true,\n",
|
||||
" \"has_open_state\": true,\n",
|
||||
" \"has_reagents\": false\n",
|
||||
" }\n",
|
||||
" },\n",
|
||||
" \"111280987\": {\n",
|
||||
" \"templateType\": \"ItemLogic\",\n",
|
||||
" \"prefab\": {\n",
|
||||
" \"prefab_name\": \"ItemTerrainManipulator\",\n",
|
||||
" \"prefab_hash\": 111280987,\n",
|
||||
" \"desc\": \"0.Mode0\\n1.Mode1\",\n",
|
||||
" \"name\": \"Terrain Manipulator\"\n",
|
||||
" },\n",
|
||||
" \"item\": {\n",
|
||||
" \"consumable\": false,\n",
|
||||
" \"ingredient\": false,\n",
|
||||
" \"max_quantity\": 1,\n",
|
||||
" \"slot_class\": \"Tool\",\n",
|
||||
" \"sorting_class\": \"Default\"\n",
|
||||
" },\n",
|
||||
" \"logic\": {\n",
|
||||
" \"logic_slot_types\": {\n",
|
||||
" \"0\": {\n",
|
||||
" \"Occupied\": \"Read\",\n",
|
||||
" \"OccupantHash\": \"Read\",\n",
|
||||
" \"Quantity\": \"Read\",\n",
|
||||
" \"Damage\": \"Read\",\n",
|
||||
" \"Charge\": \"Read\",\n",
|
||||
" \"ChargeRatio\": \"Read\",\n",
|
||||
" \"Class\": \"Read\",\n",
|
||||
" \"MaxQuantity\": \"Read\",\n",
|
||||
" \"ReferenceId\": \"Read\"\n",
|
||||
" },\n",
|
||||
" \"1\": {\n",
|
||||
" \"Occupied\": \"Read\",\n",
|
||||
" \"OccupantHash\": \"Read\",\n",
|
||||
" \"Quantity\": \"Read\",\n",
|
||||
" \"Damage\": \"Read\",\n",
|
||||
" \"Class\": \"Read\",\n",
|
||||
" \"MaxQuantity\": \"Read\",\n",
|
||||
" \"ReferenceId\": \"Read\"\n",
|
||||
" }\n",
|
||||
" },\n",
|
||||
" \"logic_types\": {\n",
|
||||
" \"Power\": \"Read\",\n",
|
||||
" \"Mode\": \"ReadWrite\",\n",
|
||||
" \"Error\": \"Read\",\n",
|
||||
" \"Activate\": \"ReadWrite\",\n",
|
||||
" \"On\": \"ReadWrite\",\n",
|
||||
" \"ReferenceId\": \"Read\"\n",
|
||||
" },\n",
|
||||
" \"modes\": {\n",
|
||||
" \"0\": \"Mode0\",\n",
|
||||
" \"1\": \"Mode1\"\n",
|
||||
" },\n",
|
||||
" \"transmission_receiver\": false,\n",
|
||||
" \"wireless_logic\": false,\n",
|
||||
" \"circuit_holder\": false\n",
|
||||
" },\n",
|
||||
" \"slots\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"Battery\",\n",
|
||||
" \"typ\": \"Battery\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"Dirt Canister\",\n",
|
||||
" \"typ\": \"Ore\"\n",
|
||||
" }\n",
|
||||
" ]\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"\"#;\n",
|
||||
"use std::collections::BTreeMap;\n",
|
||||
"use stationeers_data::templates::ObjectTemplate;\n",
|
||||
"let parsed_db: BTreeMap<i32, ObjectTemplate> =\n",
|
||||
" parse_value(&mut serde_json::Deserializer::from_str(entries))?;\n",
|
||||
"println!(\"{parsed_db:?}\");"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Rust",
|
||||
"language": "rust",
|
||||
"name": "rust"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": "rust",
|
||||
"file_extension": ".rs",
|
||||
"mimetype": "text/rust",
|
||||
"name": "rust",
|
||||
"pygment_lexer": "rust",
|
||||
"version": ""
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
23
stationeers_data/Cargo.toml
Normal file
@@ -0,0 +1,23 @@
|
||||
[package]
|
||||
name = "stationeers_data"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
prefab_database = [] # compile with the prefab database enabled
|
||||
reagent_database = [] # compile with the reagent_database enabled
|
||||
tsify = ["dep:tsify", "dep:wasm-bindgen"]
|
||||
wasm-bindgen = ["dep:wasm-bindgen"]
|
||||
|
||||
[dependencies]
|
||||
const-crc32 = "1.3.0"
|
||||
num-integer = "0.1.46"
|
||||
phf = "0.11.2"
|
||||
serde = "1.0.202"
|
||||
serde_derive = "1.0.202"
|
||||
serde_with = "3.8.1"
|
||||
strum = { version = "0.26.2", features = ["derive", "phf", "strum_macros"] }
|
||||
tsify = { version = "0.4.5", optional = true, features = ["json"] }
|
||||
wasm-bindgen = { version = "0.2.92", optional = true }
|
||||
54801
stationeers_data/src/database/prefab_map.rs
Normal file
581
stationeers_data/src/database/reagent_map.rs
Normal file
@@ -0,0 +1,581 @@
|
||||
// =================================================
|
||||
// !! <-----> DO NOT MODIFY <-----> !!
|
||||
//
|
||||
// This module was automatically generated by an
|
||||
// xtask
|
||||
//
|
||||
// run
|
||||
//
|
||||
// `cargo xtask generate -m database`
|
||||
//
|
||||
// from the workspace to regenerate
|
||||
//
|
||||
// =================================================
|
||||
|
||||
use crate::templates::Reagent;
|
||||
pub fn build_reagent_database() -> std::collections::BTreeMap<
|
||||
u8,
|
||||
crate::templates::Reagent,
|
||||
> {
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
let mut map: std::collections::BTreeMap<u8, crate::templates::Reagent> = std::collections::BTreeMap::new();
|
||||
map.insert(
|
||||
20u8,
|
||||
Reagent {
|
||||
id: 20u8,
|
||||
name: "Alcohol".into(),
|
||||
hash: 1565803737i32,
|
||||
unit: "ml".into(),
|
||||
is_organic: true,
|
||||
sources: vec![].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
36u8,
|
||||
Reagent {
|
||||
id: 36u8,
|
||||
name: "Astroloy".into(),
|
||||
hash: -1493155787i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemAstroloyIngot".into(), 1f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
40u8,
|
||||
Reagent {
|
||||
id: 40u8,
|
||||
name: "Biomass".into(),
|
||||
hash: 925270362i32,
|
||||
unit: "".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemBiomass".into(), 1f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
5u8,
|
||||
Reagent {
|
||||
id: 5u8,
|
||||
name: "Carbon".into(),
|
||||
hash: 1582746610i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("HumanSkull".into(), 1f64), ("ItemCharcoal".into(), 1f64)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
37u8,
|
||||
Reagent {
|
||||
id: 37u8,
|
||||
name: "Cobalt".into(),
|
||||
hash: 1702246124i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemCobaltOre".into(), 1f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
44u8,
|
||||
Reagent {
|
||||
id: 44u8,
|
||||
name: "Cocoa".into(),
|
||||
hash: 678781198i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![
|
||||
("ItemCocoaPowder".into(), 1f64), ("ItemCocoaTree".into(), 1f64)
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
27u8,
|
||||
Reagent {
|
||||
id: 27u8,
|
||||
name: "ColorBlue".into(),
|
||||
hash: 557517660i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ReagentColorBlue".into(), 10f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
26u8,
|
||||
Reagent {
|
||||
id: 26u8,
|
||||
name: "ColorGreen".into(),
|
||||
hash: 2129955242i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ReagentColorGreen".into(), 10f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
29u8,
|
||||
Reagent {
|
||||
id: 29u8,
|
||||
name: "ColorOrange".into(),
|
||||
hash: 1728153015i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ReagentColorOrange".into(), 10f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
25u8,
|
||||
Reagent {
|
||||
id: 25u8,
|
||||
name: "ColorRed".into(),
|
||||
hash: 667001276i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ReagentColorRed".into(), 10f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
28u8,
|
||||
Reagent {
|
||||
id: 28u8,
|
||||
name: "ColorYellow".into(),
|
||||
hash: -1430202288i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ReagentColorYellow".into(), 10f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
15u8,
|
||||
Reagent {
|
||||
id: 15u8,
|
||||
name: "Constantan".into(),
|
||||
hash: 1731241392i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemConstantanIngot".into(), 1f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
7u8,
|
||||
Reagent {
|
||||
id: 7u8,
|
||||
name: "Copper".into(),
|
||||
hash: -1172078909i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![
|
||||
("ItemCopperIngot".into(), 1f64), ("ItemCopperOre".into(), 1f64)
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
38u8,
|
||||
Reagent {
|
||||
id: 38u8,
|
||||
name: "Corn".into(),
|
||||
hash: 1550709753i32,
|
||||
unit: "".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemCookedCorn".into(), 1f64), ("ItemCorn".into(), 1f64)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
2u8,
|
||||
Reagent {
|
||||
id: 2u8,
|
||||
name: "Egg".into(),
|
||||
hash: 1887084450i32,
|
||||
unit: "".into(),
|
||||
is_organic: true,
|
||||
sources: vec![
|
||||
("ItemCookedPowderedEggs".into(), 1f64), ("ItemEgg".into(), 1f64),
|
||||
("ItemFertilizedEgg".into(), 1f64)
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
13u8,
|
||||
Reagent {
|
||||
id: 13u8,
|
||||
name: "Electrum".into(),
|
||||
hash: 478264742i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemElectrumIngot".into(), 1f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
24u8,
|
||||
Reagent {
|
||||
id: 24u8,
|
||||
name: "Fenoxitone".into(),
|
||||
hash: -865687737i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemFern".into(), 1f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
0u8,
|
||||
Reagent {
|
||||
id: 0u8,
|
||||
name: "Flour".into(),
|
||||
hash: -811006991i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemFlour".into(), 50f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
4u8,
|
||||
Reagent {
|
||||
id: 4u8,
|
||||
name: "Gold".into(),
|
||||
hash: -409226641i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemGoldIngot".into(), 1f64), ("ItemGoldOre".into(), 1f64)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
35u8,
|
||||
Reagent {
|
||||
id: 35u8,
|
||||
name: "Hastelloy".into(),
|
||||
hash: 2019732679i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemHastelloyIngot".into(), 1f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
9u8,
|
||||
Reagent {
|
||||
id: 9u8,
|
||||
name: "Hydrocarbon".into(),
|
||||
hash: 2003628602i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemCoalOre".into(), 1f64), ("ItemSolidFuel".into(), 1f64)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
34u8,
|
||||
Reagent {
|
||||
id: 34u8,
|
||||
name: "Inconel".into(),
|
||||
hash: -586072179i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemInconelIngot".into(), 1f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
14u8,
|
||||
Reagent {
|
||||
id: 14u8,
|
||||
name: "Invar".into(),
|
||||
hash: -626453759i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemInvarIngot".into(), 1f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
3u8,
|
||||
Reagent {
|
||||
id: 3u8,
|
||||
name: "Iron".into(),
|
||||
hash: -666742878i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemIronIngot".into(), 1f64), ("ItemIronOre".into(), 1f64)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
12u8,
|
||||
Reagent {
|
||||
id: 12u8,
|
||||
name: "Lead".into(),
|
||||
hash: -2002530571i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemLeadIngot".into(), 1f64), ("ItemLeadOre".into(), 1f64)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
1u8,
|
||||
Reagent {
|
||||
id: 1u8,
|
||||
name: "Milk".into(),
|
||||
hash: 471085864i32,
|
||||
unit: "ml".into(),
|
||||
is_organic: true,
|
||||
sources: vec![
|
||||
("ItemCookedCondensedMilk".into(), 1f64), ("ItemMilk".into(), 1f64)
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
42u8,
|
||||
Reagent {
|
||||
id: 42u8,
|
||||
name: "Mushroom".into(),
|
||||
hash: 516242109i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![
|
||||
("ItemCookedMushroom".into(), 1f64), ("ItemMushroom".into(), 1f64)
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
11u8,
|
||||
Reagent {
|
||||
id: 11u8,
|
||||
name: "Nickel".into(),
|
||||
hash: 556601662i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![
|
||||
("ItemNickelIngot".into(), 1f64), ("ItemNickelOre".into(), 1f64)
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
21u8,
|
||||
Reagent {
|
||||
id: 21u8,
|
||||
name: "Oil".into(),
|
||||
hash: 1958538866i32,
|
||||
unit: "ml".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemSoyOil".into(), 1f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
17u8,
|
||||
Reagent {
|
||||
id: 17u8,
|
||||
name: "Plastic".into(),
|
||||
hash: 791382247i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
22u8,
|
||||
Reagent {
|
||||
id: 22u8,
|
||||
name: "Potato".into(),
|
||||
hash: -1657266385i32,
|
||||
unit: "".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemPotato".into(), 1f64), ("ItemPotatoBaked".into(), 1f64)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
30u8,
|
||||
Reagent {
|
||||
id: 30u8,
|
||||
name: "Pumpkin".into(),
|
||||
hash: -1250164309i32,
|
||||
unit: "".into(),
|
||||
is_organic: true,
|
||||
sources: vec![
|
||||
("ItemCookedPumpkin".into(), 1f64), ("ItemPumpkin".into(), 1f64)
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
31u8,
|
||||
Reagent {
|
||||
id: 31u8,
|
||||
name: "Rice".into(),
|
||||
hash: 1951286569i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemCookedRice".into(), 1f64), ("ItemRice".into(), 1f64)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
19u8,
|
||||
Reagent {
|
||||
id: 19u8,
|
||||
name: "SalicylicAcid".into(),
|
||||
hash: -2086114347i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
18u8,
|
||||
Reagent {
|
||||
id: 18u8,
|
||||
name: "Silicon".into(),
|
||||
hash: -1195893171i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![
|
||||
("ItemSiliconIngot".into(), 0.1f64), ("ItemSiliconOre".into(), 1f64)
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
10u8,
|
||||
Reagent {
|
||||
id: 10u8,
|
||||
name: "Silver".into(),
|
||||
hash: 687283565i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![
|
||||
("ItemSilverIngot".into(), 1f64), ("ItemSilverOre".into(), 1f64)
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
16u8,
|
||||
Reagent {
|
||||
id: 16u8,
|
||||
name: "Solder".into(),
|
||||
hash: -1206542381i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemSolderIngot".into(), 1f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
41u8,
|
||||
Reagent {
|
||||
id: 41u8,
|
||||
name: "Soy".into(),
|
||||
hash: 1510471435i32,
|
||||
unit: "".into(),
|
||||
is_organic: true,
|
||||
sources: vec![
|
||||
("ItemCookedSoybean".into(), 1f64), ("ItemSoybean".into(), 1f64)
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
8u8,
|
||||
Reagent {
|
||||
id: 8u8,
|
||||
name: "Steel".into(),
|
||||
hash: 1331613335i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemEmptyCan".into(), 1f64), ("ItemSteelIngot".into(), 1f64)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
33u8,
|
||||
Reagent {
|
||||
id: 33u8,
|
||||
name: "Stellite".into(),
|
||||
hash: -500544800i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemStelliteIngot".into(), 1f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
43u8,
|
||||
Reagent {
|
||||
id: 43u8,
|
||||
name: "Sugar".into(),
|
||||
hash: 1778746875i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemSugar".into(), 10f64), ("ItemSugarCane".into(), 1f64)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
23u8,
|
||||
Reagent {
|
||||
id: 23u8,
|
||||
name: "Tomato".into(),
|
||||
hash: 733496620i32,
|
||||
unit: "".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemCookedTomato".into(), 1f64), ("ItemTomato".into(), 1f64)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
6u8,
|
||||
Reagent {
|
||||
id: 6u8,
|
||||
name: "Uranium".into(),
|
||||
hash: -208860272i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemUraniumOre".into(), 1f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
32u8,
|
||||
Reagent {
|
||||
id: 32u8,
|
||||
name: "Waspaloy".into(),
|
||||
hash: 1787814293i32,
|
||||
unit: "g".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemWaspaloyIngot".into(), 1f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
39u8,
|
||||
Reagent {
|
||||
id: 39u8,
|
||||
name: "Wheat".into(),
|
||||
hash: -686695134i32,
|
||||
unit: "".into(),
|
||||
is_organic: true,
|
||||
sources: vec![("ItemWheat".into(), 1f64)].into_iter().collect(),
|
||||
},
|
||||
);
|
||||
map
|
||||
}
|
||||
2308
stationeers_data/src/enums/basic.rs
Normal file
7764
stationeers_data/src/enums/prefabs.rs
Normal file
2132
stationeers_data/src/enums/script.rs
Normal file
194
stationeers_data/src/lib.rs
Normal file
@@ -0,0 +1,194 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub mod templates;
|
||||
pub mod enums {
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "tsify")]
|
||||
use tsify::Tsify;
|
||||
#[cfg(feature = "tsify")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use std::fmt::Display;
|
||||
use strum::{AsRefStr, EnumIter, EnumString, FromRepr};
|
||||
|
||||
pub mod basic;
|
||||
pub mod prefabs;
|
||||
pub mod script;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParseError {
|
||||
pub enm: String,
|
||||
}
|
||||
|
||||
impl Display for ParseError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Unknown enum '{}'", self.enm)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ParseError {}
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, EnumString,
|
||||
)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify))]
|
||||
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum MemoryAccess {
|
||||
Read,
|
||||
Write,
|
||||
ReadWrite,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Eq,
|
||||
Ord,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
EnumIter,
|
||||
AsRefStr,
|
||||
FromRepr,
|
||||
EnumString,
|
||||
)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify))]
|
||||
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum ConnectionType {
|
||||
Pipe,
|
||||
Power,
|
||||
Data,
|
||||
Chute,
|
||||
Elevator,
|
||||
PipeLiquid,
|
||||
LandingPad,
|
||||
LaunchPad,
|
||||
PowerAndData,
|
||||
RoboticArmRail,
|
||||
#[serde(other)]
|
||||
#[default]
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Eq,
|
||||
Ord,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
EnumIter,
|
||||
AsRefStr,
|
||||
FromRepr,
|
||||
EnumString,
|
||||
)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify))]
|
||||
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum ConnectionRole {
|
||||
Input,
|
||||
Input2,
|
||||
Output,
|
||||
Output2,
|
||||
Waste,
|
||||
#[serde(other)]
|
||||
#[default]
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Eq,
|
||||
Ord,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
EnumIter,
|
||||
AsRefStr,
|
||||
FromRepr,
|
||||
EnumString,
|
||||
)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify))]
|
||||
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
|
||||
#[repr(u32)]
|
||||
pub enum MachineTier {
|
||||
#[default]
|
||||
Undefined = 0,
|
||||
TierOne = 1,
|
||||
TierTwo = 2,
|
||||
TierThree = 3,
|
||||
#[serde(other)]
|
||||
Max,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Default,
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Hash,
|
||||
EnumString,
|
||||
AsRefStr,
|
||||
EnumIter,
|
||||
FromRepr,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify))]
|
||||
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum Species {
|
||||
None,
|
||||
#[default]
|
||||
Human,
|
||||
Zrilian,
|
||||
Robot,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn build_prefab_database() -> Option<BTreeMap<i32, templates::ObjectTemplate>> {
|
||||
#[cfg(feature = "prefab_database")]
|
||||
let map = Some(database::build_prefab_database());
|
||||
#[cfg(not(feature = "prefab_database"))]
|
||||
let map = None;
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
pub fn build_reagent_database() -> Option<BTreeMap<u8, templates::Reagent>> {
|
||||
#[cfg(feature = "reagent_database")]
|
||||
let map = Some(database::build_reagent_database());
|
||||
#[cfg(not(feature = "reagent_database"))]
|
||||
let map = None;
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
pub mod database {
|
||||
#[cfg(feature = "prefab_database")]
|
||||
mod prefab_map;
|
||||
#[cfg(feature = "prefab_database")]
|
||||
pub use prefab_map::build_prefab_database;
|
||||
#[cfg(feature = "reagent_database")]
|
||||
mod reagent_map;
|
||||
#[cfg(feature = "reagent_database")]
|
||||
pub use reagent_map::build_reagent_database;
|
||||
}
|
||||
690
stationeers_data/src/templates.rs
Normal file
@@ -0,0 +1,690 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::enums::{
|
||||
basic::{Class, GasType, SortingClass},
|
||||
script::{LogicSlotType, LogicType},
|
||||
ConnectionRole, ConnectionType, MachineTier, MemoryAccess, Species,
|
||||
};
|
||||
|
||||
use serde_with::{serde_as, DisplayFromStr};
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
#[cfg(feature = "tsify")]
|
||||
use tsify::Tsify;
|
||||
#[cfg(feature = "tsify")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
#[serde(tag = "templateType")]
|
||||
pub enum ObjectTemplate {
|
||||
Structure(StructureTemplate),
|
||||
StructureSlots(StructureSlotsTemplate),
|
||||
StructureLogic(StructureLogicTemplate),
|
||||
StructureLogicDevice(StructureLogicDeviceTemplate),
|
||||
StructureLogicDeviceConsumer(StructureLogicDeviceConsumerTemplate),
|
||||
StructureLogicDeviceMemory(StructureLogicDeviceMemoryTemplate),
|
||||
StructureLogicDeviceConsumerMemory(StructureLogicDeviceConsumerMemoryTemplate),
|
||||
StructureCircuitHolder(StructureCircuitHolderTemplate),
|
||||
Item(ItemTemplate),
|
||||
ItemSlots(ItemSlotsTemplate),
|
||||
ItemConsumer(ItemConsumerTemplate),
|
||||
ItemLogic(ItemLogicTemplate),
|
||||
ItemLogicMemory(ItemLogicMemoryTemplate),
|
||||
ItemCircuitHolder(ItemCircuitHolderTemplate),
|
||||
ItemSuit(ItemSuitTemplate),
|
||||
ItemSuitLogic(ItemSuitLogicTemplate),
|
||||
ItemSuitCircuitHolder(ItemSuitCircuitHolderTemplate),
|
||||
Human(HumanTemplate),
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl ObjectTemplate {
|
||||
#[allow(clippy::must_use_candidate)]
|
||||
pub fn prefab(&self) -> &PrefabInfo {
|
||||
#[allow(clippy::enum_glob_use)]
|
||||
use ObjectTemplate::*;
|
||||
match self {
|
||||
Structure(s) => &s.prefab,
|
||||
StructureSlots(s) => &s.prefab,
|
||||
StructureLogic(s) => &s.prefab,
|
||||
StructureLogicDevice(s) => &s.prefab,
|
||||
StructureLogicDeviceConsumer(s) => &s.prefab,
|
||||
StructureLogicDeviceMemory(s) => &s.prefab,
|
||||
StructureLogicDeviceConsumerMemory(s) => &s.prefab,
|
||||
StructureCircuitHolder(s) => &s.prefab,
|
||||
Item(i) => &i.prefab,
|
||||
ItemSlots(i) => &i.prefab,
|
||||
ItemConsumer(i) => &i.prefab,
|
||||
ItemLogic(i) => &i.prefab,
|
||||
ItemLogicMemory(i) => &i.prefab,
|
||||
ItemCircuitHolder(i) => &i.prefab,
|
||||
ItemSuit(i) => &i.prefab,
|
||||
ItemSuitLogic(i) => &i.prefab,
|
||||
ItemSuitCircuitHolder(i) => &i.prefab,
|
||||
Human(h) => &h.prefab,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StructureTemplate> for ObjectTemplate {
|
||||
fn from(value: StructureTemplate) -> Self {
|
||||
Self::Structure(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StructureSlotsTemplate> for ObjectTemplate {
|
||||
fn from(value: StructureSlotsTemplate) -> Self {
|
||||
Self::StructureSlots(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StructureLogicTemplate> for ObjectTemplate {
|
||||
fn from(value: StructureLogicTemplate) -> Self {
|
||||
Self::StructureLogic(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StructureLogicDeviceTemplate> for ObjectTemplate {
|
||||
fn from(value: StructureLogicDeviceTemplate) -> Self {
|
||||
Self::StructureLogicDevice(value)
|
||||
}
|
||||
}
|
||||
impl From<StructureLogicDeviceConsumerTemplate> for ObjectTemplate {
|
||||
fn from(value: StructureLogicDeviceConsumerTemplate) -> Self {
|
||||
Self::StructureLogicDeviceConsumer(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StructureLogicDeviceMemoryTemplate> for ObjectTemplate {
|
||||
fn from(value: StructureLogicDeviceMemoryTemplate) -> Self {
|
||||
Self::StructureLogicDeviceMemory(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StructureLogicDeviceConsumerMemoryTemplate> for ObjectTemplate {
|
||||
fn from(value: StructureLogicDeviceConsumerMemoryTemplate) -> Self {
|
||||
Self::StructureLogicDeviceConsumerMemory(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ItemTemplate> for ObjectTemplate {
|
||||
fn from(value: ItemTemplate) -> Self {
|
||||
Self::Item(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ItemSlotsTemplate> for ObjectTemplate {
|
||||
fn from(value: ItemSlotsTemplate) -> Self {
|
||||
Self::ItemSlots(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ItemConsumerTemplate> for ObjectTemplate {
|
||||
fn from(value: ItemConsumerTemplate) -> Self {
|
||||
Self::ItemConsumer(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ItemLogicTemplate> for ObjectTemplate {
|
||||
fn from(value: ItemLogicTemplate) -> Self {
|
||||
Self::ItemLogic(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ItemLogicMemoryTemplate> for ObjectTemplate {
|
||||
fn from(value: ItemLogicMemoryTemplate) -> Self {
|
||||
Self::ItemLogicMemory(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ItemSuitCircuitHolderTemplate> for ObjectTemplate {
|
||||
fn from(value: ItemSuitCircuitHolderTemplate) -> Self {
|
||||
Self::ItemSuitCircuitHolder(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ItemSuitTemplate> for ObjectTemplate {
|
||||
fn from(value: ItemSuitTemplate) -> Self {
|
||||
Self::ItemSuit(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ItemSuitLogicTemplate> for ObjectTemplate {
|
||||
fn from(value: ItemSuitLogicTemplate) -> Self {
|
||||
Self::ItemSuitLogic(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ItemCircuitHolderTemplate> for ObjectTemplate {
|
||||
fn from(value: ItemCircuitHolderTemplate) -> Self {
|
||||
Self::ItemCircuitHolder(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StructureCircuitHolderTemplate> for ObjectTemplate {
|
||||
fn from(value: StructureCircuitHolderTemplate) -> Self {
|
||||
Self::StructureCircuitHolder(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HumanTemplate> for ObjectTemplate {
|
||||
fn from(value: HumanTemplate) -> Self {
|
||||
Self::Human(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct HumanTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub species: Species,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct PrefabInfo {
|
||||
pub prefab_name: String,
|
||||
pub prefab_hash: i32,
|
||||
pub desc: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum SlotInfo {
|
||||
Direct {
|
||||
name: String,
|
||||
class: Class,
|
||||
index: u32,
|
||||
},
|
||||
Proxy {
|
||||
name: String,
|
||||
index: u32,
|
||||
},
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct LogicInfo {
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(
|
||||
feature = "tsify",
|
||||
tsify(type = "Map<string, Map<LogicSlotType, MemoryAccess>>")
|
||||
)]
|
||||
pub logic_slot_types: BTreeMap<u32, BTreeMap<LogicSlotType, MemoryAccess>>,
|
||||
pub logic_types: BTreeMap<LogicType, MemoryAccess>,
|
||||
#[serde_as(as = "Option<BTreeMap<DisplayFromStr, _>>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(optional, type = "Map<string, string>"))]
|
||||
pub modes: Option<BTreeMap<u32, String>>,
|
||||
pub transmission_receiver: bool,
|
||||
pub wireless_logic: bool,
|
||||
pub circuit_holder: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct ItemInfo {
|
||||
pub consumable: bool,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub filter_type: Option<GasType>,
|
||||
pub ingredient: bool,
|
||||
pub max_quantity: u32,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub reagents: Option<BTreeMap<String, f64>>,
|
||||
pub slot_class: Class,
|
||||
pub sorting_class: SortingClass,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct ConnectionInfo {
|
||||
pub typ: ConnectionType,
|
||||
pub role: ConnectionRole,
|
||||
}
|
||||
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct DeviceInfo {
|
||||
pub connection_list: Vec<ConnectionInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub device_pins_length: Option<u32>,
|
||||
pub has_activate_state: bool,
|
||||
pub has_atmosphere: bool,
|
||||
pub has_color_state: bool,
|
||||
pub has_lock_state: bool,
|
||||
pub has_mode_state: bool,
|
||||
pub has_on_off_state: bool,
|
||||
pub has_open_state: bool,
|
||||
pub has_reagents: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct ConsumerInfo {
|
||||
pub consumed_resources: Vec<String>,
|
||||
pub processed_reagents: Vec<i32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct Reagent {
|
||||
pub id: u8,
|
||||
pub name: String,
|
||||
pub hash: i32,
|
||||
pub unit: String,
|
||||
pub is_organic: bool,
|
||||
pub sources: BTreeMap<String, f64>,
|
||||
}
|
||||
|
||||
impl Reagent {
|
||||
pub fn with_name(mut self, name: impl Into<String>) -> Self {
|
||||
self.name = name.into();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct RecipeRange {
|
||||
pub start: f64,
|
||||
pub stop: f64,
|
||||
pub is_valid: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct RecipeGasMix {
|
||||
pub rule: i64,
|
||||
pub is_any: bool,
|
||||
pub is_any_to_remove: bool,
|
||||
pub reagents: BTreeMap<String, f64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct Recipe {
|
||||
pub target_prefab: String,
|
||||
pub target_prefab_hash: i32,
|
||||
pub tier: MachineTier,
|
||||
pub time: f64,
|
||||
pub energy: f64,
|
||||
pub temperature: RecipeRange,
|
||||
pub pressure: RecipeRange,
|
||||
pub required_mix: RecipeGasMix,
|
||||
pub count_types: i64,
|
||||
pub reagents: BTreeMap<String, f64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct RecipeOrder {
|
||||
pub recipe: Recipe,
|
||||
pub quantity: u32,
|
||||
}
|
||||
|
||||
impl Recipe {
|
||||
pub fn with_target(mut self, prefab: impl Into<String>) -> Self {
|
||||
let prefab: String = prefab.into();
|
||||
self.target_prefab_hash = const_crc32::crc32(prefab.as_bytes()) as i32;
|
||||
self.target_prefab = prefab;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct FabricatorInfo {
|
||||
pub tier: MachineTier,
|
||||
pub recipes: Vec<Recipe>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct StructureInfo {
|
||||
pub small_grid: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub enum InstructionPartType {
|
||||
Bool8,
|
||||
Byte8,
|
||||
Int32,
|
||||
UInt32,
|
||||
Short16,
|
||||
UShort16,
|
||||
Unused(u32),
|
||||
Unknown(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct InstructionPart {
|
||||
pub range: (u32, u32),
|
||||
pub name: String,
|
||||
pub typ: InstructionPartType,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct Instruction {
|
||||
pub description: String,
|
||||
pub description_stripped: String,
|
||||
pub typ: String,
|
||||
pub value: i64,
|
||||
pub valid: (u32, Option<u32>),
|
||||
pub parts: Vec<InstructionPart>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct MemoryInfo {
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub instructions: Option<BTreeMap<String, Instruction>>,
|
||||
pub memory_access: MemoryAccess,
|
||||
pub memory_size: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct ThermalInfo {
|
||||
pub convection_factor: f32,
|
||||
pub radiation_factor: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct InternalAtmoInfo {
|
||||
pub volume: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct SuitInfo {
|
||||
pub hygiene_reduction_multiplier: f32,
|
||||
pub waste_max_pressure: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct StructureTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub structure: StructureInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct StructureSlotsTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub structure: StructureInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct StructureLogicTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub structure: StructureInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub logic: LogicInfo,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct StructureLogicDeviceTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub structure: StructureInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub logic: LogicInfo,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
pub device: DeviceInfo,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct StructureLogicDeviceConsumerTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub structure: StructureInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub logic: LogicInfo,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
pub device: DeviceInfo,
|
||||
pub consumer_info: ConsumerInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub fabricator_info: Option<FabricatorInfo>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct StructureLogicDeviceMemoryTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub structure: StructureInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub logic: LogicInfo,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
pub device: DeviceInfo,
|
||||
pub memory: MemoryInfo,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct StructureCircuitHolderTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub structure: StructureInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub logic: LogicInfo,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
pub device: DeviceInfo,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct StructureLogicDeviceConsumerMemoryTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub structure: StructureInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub logic: LogicInfo,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
pub device: DeviceInfo,
|
||||
pub consumer_info: ConsumerInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub fabricator_info: Option<FabricatorInfo>,
|
||||
pub memory: MemoryInfo,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct ItemTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub item: ItemInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct ItemSlotsTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub item: ItemInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct ItemConsumerTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub item: ItemInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
pub consumer_info: ConsumerInfo,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct ItemLogicTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub item: ItemInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub logic: LogicInfo,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct ItemLogicMemoryTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub item: ItemInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub logic: LogicInfo,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
pub memory: MemoryInfo,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct ItemCircuitHolderTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub item: ItemInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub logic: LogicInfo,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct ItemSuitTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub item: ItemInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
pub suit_info: SuitInfo,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct ItemSuitLogicTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub item: ItemInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub logic: LogicInfo,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
pub suit_info: SuitInfo,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
|
||||
pub struct ItemSuitCircuitHolderTemplate {
|
||||
pub prefab: PrefabInfo,
|
||||
pub item: ItemInfo,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub thermal_info: Option<ThermalInfo>,
|
||||
#[cfg_attr(feature = "tsify", tsify(optional))]
|
||||
pub internal_atmo_info: Option<InternalAtmoInfo>,
|
||||
pub logic: LogicInfo,
|
||||
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
|
||||
#[cfg_attr(feature = "tsify", tsify(type = "Map<string, SlotInfo>"))]
|
||||
pub slots: BTreeMap<u32, SlotInfo>,
|
||||
pub suit_info: SuitInfo,
|
||||
pub memory: MemoryInfo,
|
||||
}
|
||||
@@ -15,18 +15,20 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%matplotlib widget\n",
|
||||
"import json\n",
|
||||
"\n",
|
||||
"database = {}\n",
|
||||
"\n",
|
||||
"with open(\"data/database.json\", \"r\") as f:\n",
|
||||
" database = json.load(f)\n",
|
||||
"with open(\"src/ts/virtualMachine/prefabDatabase.ts\", \"r\") as f:\n",
|
||||
" contents = f.read().removeprefix(\"export default \").removesuffix(\" as const\")\n",
|
||||
" database = json.loads(contents)\n",
|
||||
"\n",
|
||||
"db = database[\"db\"]"
|
||||
"db = database[\"prefabs\"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -38,7 +40,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -58,7 +60,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -80,7 +82,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"execution_count": 35,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -105,9 +107,9 @@
|
||||
" better_matches = []\n",
|
||||
" for can in filtered_matches:\n",
|
||||
" name, match, mapping = can\n",
|
||||
" if mapping.startswith(\"Item\") and mapping in name:\n",
|
||||
" if mapping.startswith(\"Item\") and mapping in name or mapping.lower() in name:\n",
|
||||
" better_matches.append((name, match, mapping))\n",
|
||||
" elif mapping.startswith(\"Structure\") and mapping in name:\n",
|
||||
" elif mapping.startswith(\"Structure\") and mapping in name or mapping.lower() in name:\n",
|
||||
" better_matches.append((name, match, mapping))\n",
|
||||
" if len(better_matches) > 0:\n",
|
||||
" filtered_matches = better_matches\n",
|
||||
@@ -127,7 +129,7 @@
|
||||
" direct = []\n",
|
||||
" for can in filtered_matches:\n",
|
||||
" name, match, mapping = can\n",
|
||||
" if f\"{match}-\" in name:\n",
|
||||
" if f\"{match}-\" in name or f\"{match.lower()}-\" in name:\n",
|
||||
" direct.append((name, match, mapping))\n",
|
||||
" if len(direct) > 0:\n",
|
||||
" filtered_matches = direct\n",
|
||||
@@ -154,7 +156,7 @@
|
||||
" continue\n",
|
||||
" elif name.startswith(\"Kit\") and not mapping.startswith(\"Kit\"):\n",
|
||||
" continue\n",
|
||||
" elif not name.startswith(match):\n",
|
||||
" elif not (name.startswith(match) or name.startswith(match.lower())):\n",
|
||||
" continue\n",
|
||||
" not_worse.append((name, match, mapping))\n",
|
||||
" if len(not_worse) > 0:\n",
|
||||
@@ -171,14 +173,15 @@
|
||||
"\n",
|
||||
"for entry in db.values():\n",
|
||||
" candidates = []\n",
|
||||
" entry_name = entry[\"prefab\"][\"prefab_name\"]\n",
|
||||
" for name in names:\n",
|
||||
" if entry[\"name\"] in name:\n",
|
||||
" candidates.append((name, entry[\"name\"], entry[\"name\"]))\n",
|
||||
" if entry[\"name\"].removeprefix(\"Item\") in name:\n",
|
||||
" 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)"
|
||||
" if entry_name in name or entry_name.lower() in name:\n",
|
||||
" candidates.append((name, entry_name, entry_name))\n",
|
||||
" if entry_name.removeprefix(\"Item\") in name or entry_name.removeprefix(\"Item\").lower() in name:\n",
|
||||
" candidates.append((name, entry_name.removeprefix(\"Item\"), entry_name))\n",
|
||||
" if entry_name.removeprefix(\"Structure\") in name or entry_name.removeprefix(\"Structure\").lower() in name:\n",
|
||||
" candidates.append((name, entry_name.removeprefix(\"Structure\"), entry_name))\n",
|
||||
" image_candidates[entry_name] = filter_candidates(candidates)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -190,7 +193,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"execution_count": 36,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -206,12 +209,12 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Prepare out List of file copies. at this point a few items will never have a match. and one or two will have two choices but those choices will be arbitrary."
|
||||
"Prepare out List of file copies. at this point a few items will never have a match. and one or two will have two choices but those choices will be filtered again by passing them through some extra function."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"execution_count": 40,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
@@ -227,25 +230,87 @@
|
||||
"ItemHorticultureBelt []\n",
|
||||
"ItemKitLiquidRegulator []\n",
|
||||
"ItemKitPortablesConnector []\n",
|
||||
"ItemMushroom ['ItemMushroom-resources.assets-3022.png', 'ItemMushroom-resources.assets-9304.png']\n",
|
||||
"ItemPlantEndothermic_Creative []\n",
|
||||
"ItemPlantThermogenic_Creative []\n",
|
||||
"ItemSuitModCryogenicUpgrade []\n",
|
||||
"Landingpad_GasConnectorInwardPiece []\n",
|
||||
"Landingpad_LiquidConnectorInwardPiece []\n",
|
||||
"StructureBlocker []\n",
|
||||
"StructureElevatorLevelIndustrial []\n",
|
||||
"StructureLogicSorter []\n",
|
||||
"StructurePlinth []\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%matplotlib widget\n",
|
||||
"to_copy = []\n",
|
||||
"\n",
|
||||
"from IPython.display import Image, display\n",
|
||||
"\n",
|
||||
"gases = [(\"Oxygen\", \"White\"), (\"Nitrogen\", \"Black\"), (\"CarbonDioxide\", \"Yellow\"), (\"Fuel\", \"Orange\")]\n",
|
||||
"\n",
|
||||
"colors = [\"White\", \"Black\", \"Gray\", \"Khaki\", \"Brown\", \"Orange\", \"Yellow\", \"Red\", \"Green\", \"Blue\", \"Purple\"]\n",
|
||||
"\n",
|
||||
"def split_gas(name):\n",
|
||||
" for gas, color in gases:\n",
|
||||
" if name.endswith(gas):\n",
|
||||
" return (name.removesuffix(gas), gas, color)\n",
|
||||
" elif name.lower().endswith(gas):\n",
|
||||
" return (name.lower().removesuffix(gas), gas, color)\n",
|
||||
" elif name.lower().endswith(gas.lower()):\n",
|
||||
" return (name.lower().removesuffix(gas.lower()), gas.lower(), color.lower())\n",
|
||||
" return [name, None, None]\n",
|
||||
"\n",
|
||||
"def match_gas_color(name, candidates):\n",
|
||||
" mat, gas, color = split_gas(name)\n",
|
||||
" seek = f\"{mat}_{color}\"\n",
|
||||
" if gas is not None:\n",
|
||||
" for candidate in candidates:\n",
|
||||
" if seek in candidate or seek.lower() in candidate:\n",
|
||||
" return candidate\n",
|
||||
" return None\n",
|
||||
"\n",
|
||||
"def prefer_direct(name, candidates):\n",
|
||||
" for candidate in candidates:\n",
|
||||
" if f\"{name}-\" in candidate or f\"{name.lower()}-\" in candidate:\n",
|
||||
" return candidate\n",
|
||||
" return None\n",
|
||||
"\n",
|
||||
"def prefer_uncolored(name, candidates):\n",
|
||||
" for candidate in candidates:\n",
|
||||
" for color in colors:\n",
|
||||
" if f\"_{color}\" not in candidate and f\"_{color.lower()}\" not in candidate:\n",
|
||||
" return candidate\n",
|
||||
" return None\n",
|
||||
"\n",
|
||||
"def prefer_lower_match(name, candidates):\n",
|
||||
" for candidate in candidates:\n",
|
||||
" if f\"{name.lower()}-\" in candidate:\n",
|
||||
" return candidate\n",
|
||||
" return None\n",
|
||||
"\n",
|
||||
"filter_funcs = [prefer_lower_match, prefer_direct, match_gas_color, prefer_uncolored]\n",
|
||||
"\n",
|
||||
"for name, candidates in image_candidates.items():\n",
|
||||
" if len(candidates) != 1:\n",
|
||||
" found = False\n",
|
||||
" for func in filter_funcs:\n",
|
||||
" candidate = func(name, candidates)\n",
|
||||
" if candidate is not None:\n",
|
||||
" to_copy.append((name, candidate))\n",
|
||||
" found = True\n",
|
||||
" if found:\n",
|
||||
" continue\n",
|
||||
" print(name, candidates)\n",
|
||||
" if len(candidates) > 1:\n",
|
||||
" for candidate in candidates:\n",
|
||||
" print(candidate)\n",
|
||||
" display(Image(datapath / candidate))\n",
|
||||
" \n",
|
||||
" #take first as fallback\n",
|
||||
" to_copy.append((name, candidates[0]))\n",
|
||||
" # to_copy.append((name, candidates[0]))\n",
|
||||
" raise StopExecution\n",
|
||||
" else:\n",
|
||||
" # print(name, candidates)\n",
|
||||
" to_copy.append((name, candidates[0]))\n"
|
||||
@@ -253,7 +318,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 21,
|
||||
"execution_count": 41,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
@@ -334,14 +399,28 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"execution_count": 42,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "3497a8d33d6a45879586d4c7441e3f60",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"IntProgress(value=0, max=1288)"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"1266 of 1266 | 100.00% \n",
|
||||
"1288 of 1288 | 100.00% \n",
|
||||
"Done\n"
|
||||
]
|
||||
}
|
||||
@@ -352,6 +431,12 @@
|
||||
"destpath = Path(\"img/stationpedia\")\n",
|
||||
"total_files = len(to_copy)\n",
|
||||
"\n",
|
||||
"from ipywidgets import IntProgress\n",
|
||||
"from IPython.display import display\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"f = IntProgress(min=0, max=total_files)\n",
|
||||
"display(f)\n",
|
||||
"count = 0\n",
|
||||
"print ( f\"{count} of {total_files} | { count / total_files * 100}\", end=\"\\r\")\n",
|
||||
"for name, file in to_copy:\n",
|
||||
@@ -359,6 +444,7 @@
|
||||
" dest = destpath / f\"{name}.png\"\n",
|
||||
" shutil.copy(source, dest)\n",
|
||||
" count += 1\n",
|
||||
" f.value = count\n",
|
||||
" print ( f\"{count} of {total_files} | { (count / total_files) * 100 :.2f}% \", end=\"\\r\")\n",
|
||||
"print()\n",
|
||||
"print(\"Done\")\n",
|
||||
@@ -382,7 +468,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.2"
|
||||
"version": "3.12.5"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -52,23 +52,37 @@
|
||||
"brnaz",
|
||||
"brne",
|
||||
"brnez",
|
||||
"bson",
|
||||
"Circuitboard",
|
||||
"clazz",
|
||||
"codegen",
|
||||
"Comlink",
|
||||
"datapoints",
|
||||
"dbutils",
|
||||
"Depressurising",
|
||||
"deviceslength",
|
||||
"dodgerblue",
|
||||
"dont",
|
||||
"endpos",
|
||||
"getd",
|
||||
"Hardsuit",
|
||||
"hardwrap",
|
||||
"hashables",
|
||||
"hstack",
|
||||
"IDBP",
|
||||
"idxs",
|
||||
"infile",
|
||||
"jetpack",
|
||||
"Keybind",
|
||||
"labelledby",
|
||||
"lawngreen",
|
||||
"lbns",
|
||||
"leeoniya",
|
||||
"lightdom",
|
||||
"logicable",
|
||||
"LogicSlotType",
|
||||
"logicslottypes",
|
||||
"LogicSlotTypes",
|
||||
"logictype",
|
||||
"logictypes",
|
||||
"lparen",
|
||||
@@ -82,6 +96,7 @@
|
||||
"pedia",
|
||||
"pinf",
|
||||
"popperjs",
|
||||
"preact",
|
||||
"preproc",
|
||||
"Pressurising",
|
||||
"putd",
|
||||
@@ -91,20 +106,22 @@
|
||||
"regen",
|
||||
"rocketstation",
|
||||
"rparen",
|
||||
"rsbuild",
|
||||
"rspack",
|
||||
"sapz",
|
||||
"sattellite",
|
||||
"sdns",
|
||||
"sdse",
|
||||
"searchbtn",
|
||||
"seqz",
|
||||
"serde",
|
||||
"sgez",
|
||||
"sgtz",
|
||||
"slez",
|
||||
"Slotable",
|
||||
"slotclass",
|
||||
"slotlogic",
|
||||
"slotlogicable",
|
||||
"slotlogictype",
|
||||
"slotlogictypes",
|
||||
"slottype",
|
||||
"sltz",
|
||||
"snan",
|
||||
@@ -117,10 +134,17 @@
|
||||
"stationpedia",
|
||||
"tablist",
|
||||
"tabpanel",
|
||||
"tailwindcss",
|
||||
"themelist",
|
||||
"tokentype",
|
||||
"trunc",
|
||||
"whos"
|
||||
"ufuzzy",
|
||||
"VMIC",
|
||||
"VMUI",
|
||||
"vstack",
|
||||
"whitesmoke",
|
||||
"whos",
|
||||
"wicg"
|
||||
],
|
||||
"flagWords": [],
|
||||
"language": "en",
|
||||
|
||||
46799
www/data/database.json
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
BIN
www/img/stationpedia/ItemAdhesiveInsulation.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 11 KiB |
BIN
www/img/stationpedia/ItemCerealBarBag.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
www/img/stationpedia/ItemCerealBarBox.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
www/img/stationpedia/ItemChocolateBar.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
www/img/stationpedia/ItemChocolateCake.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
www/img/stationpedia/ItemChocolateCerealBar.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
www/img/stationpedia/ItemCocoaPowder.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
www/img/stationpedia/ItemCocoaTree.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 16 KiB |
BIN
www/img/stationpedia/ItemEmergencySuppliesBox.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
www/img/stationpedia/ItemInsulatedCanisterPackage.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
www/img/stationpedia/ItemKitInsulatedPipeUtility.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
www/img/stationpedia/ItemKitInsulatedPipeUtilityLiquid.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
www/img/stationpedia/ItemKitLinearRail.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 15 KiB |
BIN
www/img/stationpedia/ItemKitRobotArmDoor.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
www/img/stationpedia/ItemKitRoboticArm.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
www/img/stationpedia/ItemMiningPackage.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
www/img/stationpedia/ItemPlainCake.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
www/img/stationpedia/ItemPortablesPackage.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
www/img/stationpedia/ItemResidentialPackage.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
www/img/stationpedia/ItemSugar.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
www/img/stationpedia/ItemSugarCane.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
www/img/stationpedia/ItemWaterBottleBag.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
www/img/stationpedia/ItemWaterBottlePackage.png
Normal file
|
After Width: | Height: | Size: 11 KiB |