refactor(vm): add proper reagent interface, trace VM, fix slot serialization

Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
Rachel Powers
2024-09-16 18:00:10 -07:00
parent c81080659e
commit 08c42a2618
27 changed files with 8728 additions and 5852 deletions

View File

@@ -26,11 +26,13 @@ strum_macros = "0.26.2"
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"] }
@@ -54,3 +56,7 @@ 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

View File

@@ -35,7 +35,7 @@ pub enum VMError {
IdInUse(u32),
#[error("device(s) with ids {0:?} already exist")]
IdsInUse(Vec<u32>),
#[error("atempt to use a set of id's with duplicates: id(s) {0:?} exsist more than once")]
#[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),
@@ -64,7 +64,7 @@ pub enum VMError {
#[error("object {0} is not logicable")]
NotLogicable(ObjectID),
#[error("network object {0} is not a network")]
NonNetworkNetwork(ObjectID)
NonNetworkNetwork(ObjectID),
}
#[derive(Error, Debug, Serialize, Deserialize)]
@@ -81,8 +81,7 @@ pub enum TemplateError {
#[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)
MemorySize(usize, usize),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -90,6 +89,7 @@ pub enum TemplateError {
pub struct LineError {
pub error: ICError,
pub line: u32,
pub msg: String,
}
impl Display for LineError {
@@ -154,6 +154,7 @@ impl ParseError {
}
#[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}")]
@@ -162,8 +163,12 @@ pub enum ICError {
LogicError(#[from] LogicError),
#[error("{0}")]
MemoryError(#[from] MemoryError),
#[error("duplicate label {0}")]
DuplicateLabel(String),
#[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}'")]
@@ -176,8 +181,8 @@ pub enum ICError {
SlotIndexOutOfRange(f64),
#[error("pin index {0} out of range 0-6")]
PinIndexOutOfRange(usize),
#[error("connection index {0} out of range {1}")]
ConnectionIndexOutOfRange(usize, 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}'")]
@@ -240,11 +245,16 @@ pub enum ICError {
SlotNotOccupied,
#[error("generated Enum {0} has no value attached. Report this error.")]
NoGeneratedValue(String),
#[error("generated Enum {0}'s value does not parse as {1} . Report this error.")]
BadGeneratedValueParse(String, String),
#[error("IC with id {0} is not sloted into a circuit holder")]
#[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 sloted into a circuit holder with no logic interface?")]
#[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),
@@ -254,8 +264,12 @@ pub enum ICError {
NotLogicable(ObjectID),
#[error("{0} is not a valid number of sleep seconds")]
SleepDurationError(f64),
#[error("{0} can not be added to {1} ")]
SleepAddtionError(time::Duration, #[cfg_attr(feature = "tsify", tsify(type = "Date"))] time::OffsetDateTime),
#[error("{duration} can not be added to {time} ")]
SleepAdditionError {
duration: time::Duration,
#[cfg_attr(feature = "tsify", tsify(type = "Date"))]
time: time::OffsetDateTime,
},
}
impl ICError {

View File

@@ -29,7 +29,9 @@ pub enum ICState {
Running,
Yield,
Sleep(
#[cfg_attr(feature = "tsify", tsify(type = "Date"))] time::OffsetDateTime,
#[cfg_attr(feature = "tsify", tsify(type = "string"))]
#[serde(with = "time::serde::rfc3339")]
time::OffsetDateTime,
f64,
),
Error(LineError),
@@ -119,7 +121,13 @@ impl Program {
Some(code) => match code {
grammar::Code::Label(label) => {
if labels_set.contains(&label.id.name) {
Err(ICError::DuplicateLabel(label.id.name))
let source_line =
labels.get(&label.id.name).copied().unwrap_or_default();
Err(ICError::DuplicateLabel {
label: label.id.name,
line: line_number as u32,
source_line,
})
} else {
labels_set.insert(label.id.name.clone());
labels.insert(label.id.name, line_number as u32);
@@ -157,7 +165,13 @@ impl Program {
Some(code) => match code {
grammar::Code::Label(label) => {
if labels_set.contains(&label.id.name) {
errors.push(ICError::DuplicateLabel(label.id.name));
let source_line =
labels.get(&label.id.name).copied().unwrap_or_default();
errors.push(ICError::DuplicateLabel {
label: label.id.name,
line: line_number as u32,
source_line,
});
} else {
labels_set.insert(label.id.name.clone());
labels.insert(label.id.name, line_number as u32);

View File

@@ -2485,6 +2485,7 @@ impl<T: IC10Marker> LrInstruction for T {
indirection,
target,
} = r.as_register(self)?;
let vm = self.get_vm();
let (device, connection) = d.as_device(self)?;
let reagent_mode = reagent_mode.as_reagent_mode(self)?;
let int = int.as_value(self)?;
@@ -2526,7 +2527,7 @@ impl<T: IC10Marker> LrInstruction for T {
}
LogicReagentMode::Required => {
let reagent_interface = logicable
.as_reagent_interface()
.as_reagent_requirer()
.ok_or(ICError::NotReagentReadable(*logicable.get_id()))?;
reagent_interface
.get_current_required()
@@ -2537,13 +2538,26 @@ impl<T: IC10Marker> LrInstruction for T {
}
LogicReagentMode::Recipe => {
let reagent_interface = logicable
.as_reagent_interface()
.as_reagent_requirer()
.ok_or(ICError::NotReagentReadable(*logicable.get_id()))?;
reagent_interface
.get_current_recipe()
.iter()
.find(|(hash, _)| *hash as f64 == int)
.map(|(_, quantity)| *quantity)
.and_then(|recipe_order| {
recipe_order
.recipe
.reagents
.iter()
.map(|(name, quantity)| {
(
vm.lookup_reagent_by_name(name)
.map(|reagent| reagent.hash)
.unwrap_or(0),
quantity,
)
})
.find(|(hash, _)| *hash as f64 == int)
.map(|(_, quantity)| *quantity)
})
.unwrap_or(0.0)
}
};
@@ -2709,6 +2723,34 @@ impl<T: IC10Marker> RmapInstruction for T {
d: &crate::vm::instructions::operands::InstOperand,
reagent_hash: &crate::vm::instructions::operands::InstOperand,
) -> Result<(), crate::errors::ICError> {
todo!()
let RegisterSpec {
indirection,
target,
} = r.as_register(self)?;
let (device, connection) = d.as_device(self)?;
let reagent_hash = reagent_hash.as_value_i32(self, true)?;
let val = self
.get_circuit_holder()
.ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.borrow()
.as_circuit_holder()
.ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.get_logicable_from_index(device, connection)
.ok_or(ICError::DeviceNotSet)
.and_then(|obj| {
obj.map(|obj_ref| {
obj_ref
.as_reagent_requirer()
.ok_or(ICError::NotReagentReadable(*obj_ref.get_id()))
.map(|reagent_interface| {
reagent_interface
.get_prefab_hash_from_reagent_hash(reagent_hash)
.unwrap_or(0)
})
})
})?;
self.set_register(indirection, target, val as f64)?;
Ok(())
}
}

View File

@@ -27,6 +27,7 @@ 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 {
@@ -146,7 +147,7 @@ impl Connection {
},
Self::RoboticArmRail { role } => ConnectionInfo {
typ: ConnectionType::RoboticArmRail,
role: *role
role: *role,
},
}
}
@@ -181,6 +182,9 @@ pub struct CableNetwork {
}
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
}
@@ -190,15 +194,18 @@ impl Storage for CableNetwork {
fn get_slot_mut(&mut self, _index: usize) -> Option<&mut crate::vm::object::Slot> {
None
}
fn get_slots(&self) -> Vec<&crate::vm::object::Slot> {
fn get_slots(&self) -> Vec<(usize, &crate::vm::object::Slot)> {
vec![]
}
fn get_slots_mut(&mut self) -> Vec<&mut crate::vm::object::Slot> {
fn get_slots_mut(&mut self) -> Vec<(usize, &mut crate::vm::object::Slot)> {
vec![]
}
}
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
}
@@ -282,6 +289,9 @@ impl Logicable for CableNetwork {
}
impl Network for CableNetwork {
fn debug_network(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "UNIMPLEMENTED") //TODO: Implement
}
fn contains(&self, id: &ObjectID) -> bool {
self.devices.contains(id) || self.power_only.contains(id)
}

View File

@@ -16,7 +16,7 @@ use stationeers_data::{
script::{LogicBatchMethod, LogicSlotType, LogicType},
ConnectionRole,
},
templates::ObjectTemplate,
templates::{ObjectTemplate, Reagent},
};
use std::{
cell::RefCell,
@@ -47,6 +47,7 @@ pub struct VM {
/// list of object id's touched on the last operation
operation_modified: RefCell<Vec<ObjectID>>,
template_database: RefCell<Option<BTreeMap<i32, ObjectTemplate>>>,
reagent_database: RefCell<Option<BTreeMap<u8, Reagent>>>,
}
#[derive(Debug, Default)]
@@ -93,6 +94,7 @@ impl VM {
random: Rc::new(RefCell::new(crate::rand_mscorlib::Random::new())),
operation_modified: RefCell::new(Vec::new()),
template_database: RefCell::new(stationeers_data::build_prefab_database()),
reagent_database: RefCell::new(stationeers_data::build_reagent_database()),
});
let default_network = VMObject::new(CableNetwork::new(default_network_key, vm.clone()));
@@ -109,7 +111,7 @@ impl VM {
self.random.borrow_mut().next_f64()
}
/// Take ownership of an iterable the produces (prefab hash, ObjectTemplate) pairs and build a prefab
/// Take ownership of an iterable that produces (prefab hash, ObjectTemplate) pairs and build a prefab
/// database
pub fn import_template_database(
self: &Rc<Self>,
@@ -120,6 +122,53 @@ impl VM {
.replace(db.into_iter().collect());
}
pub fn import_reagent_database(self: &Rc<Self>, db: impl IntoIterator<Item = (u8, Reagent)>) {
self.reagent_database
.borrow_mut()
.replace(db.into_iter().collect());
}
pub fn lookup_reagent_by_hash(self: &Rc<Self>, hash: i32) -> Option<Reagent> {
self.reagent_database.borrow().as_ref().and_then(|db| {
db.iter().find_map(|(_id, reagent)| {
if reagent.hash == hash {
Some(reagent.clone())
} else {
None
}
})
})
}
pub fn lookup_reagent_by_name(self: &Rc<Self>, name: impl AsRef<str>) -> Option<Reagent> {
let name = name.as_ref();
self.reagent_database.borrow().as_ref().and_then(|db| {
db.iter().find_map(|(_id, reagent)| {
if reagent.name.as_str() == name {
Some(reagent.clone())
} else {
None
}
})
})
}
pub fn lookup_template_by_name(
self: &Rc<Self>,
name: impl AsRef<str>,
) -> Option<ObjectTemplate> {
let name = name.as_ref();
self.template_database.borrow().as_ref().and_then(|db| {
db.iter().find_map(|(_hash, template)| {
if &template.prefab().prefab_name == name {
Some(template.clone())
} else {
None
}
})
})
}
/// Get a Object Template by either prefab name or hash
pub fn get_template(self: &Rc<Self>, prefab: Prefab) -> Option<ObjectTemplate> {
let hash = match prefab {
@@ -140,7 +189,7 @@ impl VM {
.unwrap_or_default()
}
/// Add an number of object to the VM state using Frozen Object strusts.
/// Add an number of object to the VM state using Frozen Object structs.
/// See also `add_objects_frozen`
/// Returns the built objects' IDs
pub fn add_objects_frozen(
@@ -293,17 +342,20 @@ impl VM {
for obj in self.objects.borrow().values() {
let mut obj_ref = obj.borrow_mut();
if let Some(device) = obj_ref.as_mut_device() {
device.get_slots_mut().iter_mut().for_each(|slot| {
if slot.parent == old_id {
slot.parent = new_id;
}
match slot.occupant.as_mut() {
Some(info) if info.id == old_id => {
info.id = new_id;
device
.get_slots_mut()
.iter_mut()
.for_each(|(_index, slot)| {
if slot.parent == old_id {
slot.parent = new_id;
}
_ => (),
}
});
match slot.occupant.as_mut() {
Some(info) if info.id == old_id => {
info.id = new_id;
}
_ => (),
}
});
}
}
@@ -727,6 +779,7 @@ impl VM {
self.operation_modified.borrow_mut().push(id);
}
#[tracing::instrument]
pub fn reset_programmable(self: &Rc<Self>, id: ObjectID) -> Result<bool, VMError> {
let obj = self
.objects
@@ -734,12 +787,33 @@ impl VM {
.get(&id)
.cloned()
.ok_or(VMError::UnknownId(id))?;
let mut obj_ref = obj.borrow_mut();
let programmable = obj_ref
.as_mut_programmable()
.ok_or(VMError::NotProgrammable(id))?;
programmable.reset();
Ok(true)
{
let mut obj_ref = obj.borrow_mut();
if let Some(programmable) = obj_ref.as_mut_programmable() {
tracing::debug!(id, "resetting");
programmable.reset();
return Ok(true);
}
}
let ic_obj = {
let obj_ref = obj.borrow();
if let Some(circuit_holder) = obj_ref.as_circuit_holder() {
circuit_holder.get_ic()
} else {
return Err(VMError::NotCircuitHolderOrProgrammable(id));
}
};
if let Some(ic_obj) = ic_obj {
let mut ic_obj_ref = ic_obj.borrow_mut();
let ic_id = *ic_obj_ref.get_id();
if let Some(programmable) = ic_obj_ref.as_mut_programmable() {
tracing::debug!(id = ic_id, "resetting");
programmable.reset();
return Ok(true);
}
return Err(VMError::NotProgrammable(ic_id));
}
Err(VMError::NoIC(id))
}
pub fn get_object(self: &Rc<Self>, id: ObjectID) -> Option<VMObject> {
@@ -918,7 +992,11 @@ impl VM {
let connections = device.connection_list_mut();
if connection >= connections.len() {
let conn_len = connections.len();
return Err(ICError::ConnectionIndexOutOfRange(connection, conn_len).into());
return Err(ICError::ConnectionIndexOutOfRange {
index: connection,
range: conn_len,
}
.into());
}
// scope this borrow
@@ -1570,7 +1648,7 @@ impl LogicBatchMethodWrapper {
pub fn apply(&self, samples: &[f64]) -> f64 {
match self.0 {
LogicBatchMethod::Sum => samples.iter().sum(),
// Both c-charp and rust return NaN for 0.0/0.0 so we're good here
// Both c-sharp and rust return NaN for 0.0/0.0 so we're good here
LogicBatchMethod::Average => {
samples.iter().copied().sum::<f64>() / samples.len() as f64
}

View File

@@ -26,6 +26,7 @@ pub struct RegisterSpec {
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 {
@@ -50,6 +51,7 @@ pub enum Number {
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 {
@@ -133,32 +135,36 @@ impl InstOperand {
.get_str("value")
.ok_or_else(|| ICError::NoGeneratedValue(lt.to_string()))?
.parse::<u16>()
.map_err(|_| {
ICError::BadGeneratedValueParse(lt.to_string(), "u16".to_owned())
.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(slt.to_string(), "u8".to_owned())
.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(bm.to_string(), "u8".to_owned())
.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(rm.to_string(), "u8".to_owned())
.map_err(|_| ICError::BadGeneratedValueParse {
enum_name: rm.to_string(),
parse_type: "u8".to_owned(),
})? as f64)
} else {
Err(ICError::TypeValueNotKnown)

View File

@@ -122,27 +122,30 @@ pub struct SlotOccupantInfo {
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 typ: Class,
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, typ: Class) -> Self {
pub fn new(parent: ObjectID, index: usize, name: String, class: Class) -> Self {
Slot {
parent,
index,
name,
typ,
readable_logic: vec![
class,
readable_logic:
vec![
LogicSlotType::Class,
LogicSlotType::Damage,
LogicSlotType::MaxQuantity,
@@ -155,6 +158,7 @@ impl Slot {
],
writeable_logic: vec![],
occupant: None,
proxy: false,
}
}
}

View File

@@ -12,7 +12,7 @@ macro_rules! GWThermal {
fn thermal_info(&self) -> &ThermalInfo {
self.thermal_info
.as_ref()
.expect("GWTherml::thermal_info called on non thermal")
.expect("GWThermal::thermal_info called on non thermal")
}
}
};
@@ -64,10 +64,10 @@ macro_rules! GWStorage {
}
) => {
impl GWStorage for $struct {
fn slots(&self) -> &Vec<Slot> {
fn slots(&self) -> &BTreeMap<u32, Slot> {
&self.slots
}
fn slots_mut(&mut self) -> &mut Vec<Slot> {
fn slots_mut(&mut self) -> &mut BTreeMap<u32, Slot> {
&mut self.slots
}
}
@@ -156,10 +156,10 @@ macro_rules! GWDevice {
fn pins_mut(&mut self) -> Option<&mut [Option<ObjectID>]> {
self.pins.as_mut().map(|pins| pins.as_mut_slice())
}
fn reagents(&self) -> Option<&BTreeMap<i32, f64>> {
fn reagents(&self) -> Option<&BTreeMap<u8, f64>> {
self.reagents.as_ref()
}
fn reagents_mut(&mut self) -> &mut Option<BTreeMap<i32, f64>> {
fn reagents_mut(&mut self) -> &mut Option<BTreeMap<u8, f64>> {
&mut self.reagents
}
}
@@ -228,11 +228,9 @@ macro_rules! GWCircuitHolderItem {
}
}
};
}
pub(crate) use GWCircuitHolderItem;
macro_rules! GWCircuitHolderSuit {
(
$( #[$attr:meta] )*
@@ -250,11 +248,9 @@ macro_rules! GWCircuitHolderSuit {
}
}
};
}
pub(crate) use GWCircuitHolderSuit;
macro_rules! GWCircuitHolderDevice {
(
$( #[$attr:meta] )*
@@ -272,6 +268,61 @@ macro_rules! GWCircuitHolderDevice {
}
}
};
}
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;

View File

@@ -54,7 +54,7 @@ pub struct GenericStorage {
pub thermal_info: Option<ThermalInfo>,
pub internal_atmo_info: Option<InternalAtmoInfo>,
pub small_grid: bool,
pub slots: Vec<Slot>,
pub slots: BTreeMap<u32, Slot>,
}
#[derive(
@@ -79,7 +79,7 @@ pub struct GenericLogicable {
pub thermal_info: Option<ThermalInfo>,
pub internal_atmo_info: Option<InternalAtmoInfo>,
pub small_grid: bool,
pub slots: Vec<Slot>,
pub slots: BTreeMap<u32, Slot>,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
}
@@ -107,13 +107,13 @@ pub struct GenericLogicableDevice {
pub thermal_info: Option<ThermalInfo>,
pub internal_atmo_info: Option<InternalAtmoInfo>,
pub small_grid: bool,
pub slots: Vec<Slot>,
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<i32, f64>>,
pub reagents: Option<BTreeMap<u8, f64>>,
}
#[derive(
@@ -140,13 +140,13 @@ pub struct GenericCircuitHolder {
pub thermal_info: Option<ThermalInfo>,
pub internal_atmo_info: Option<InternalAtmoInfo>,
pub small_grid: bool,
pub slots: Vec<Slot>,
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<i32, f64>>,
pub reagents: Option<BTreeMap<u8, f64>>,
pub error: i32,
}
@@ -154,12 +154,12 @@ pub struct GenericCircuitHolder {
ObjectInterface!,
GWThermal!, GWInternalAtmo!,
GWStructure!, GWStorage!, GWLogicable!,
GWDevice!
GWDevice!, GWReagentConsumer!,
)]
#[custom(implements(Object {
Thermal[GWThermal::is_thermal],
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
Structure, Storage, Logicable, Device
Structure, Storage, Logicable, Device, ReagentConsumer
}))]
pub struct GenericLogicableDeviceConsumer {
#[custom(object_id)]
@@ -173,13 +173,13 @@ pub struct GenericLogicableDeviceConsumer {
pub thermal_info: Option<ThermalInfo>,
pub internal_atmo_info: Option<InternalAtmoInfo>,
pub small_grid: bool,
pub slots: Vec<Slot>,
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<i32, f64>>,
pub reagents: Option<BTreeMap<u8, f64>>,
pub consumer_info: ConsumerInfo,
}
@@ -207,13 +207,13 @@ pub struct GenericLogicableDeviceMemoryReadable {
pub thermal_info: Option<ThermalInfo>,
pub internal_atmo_info: Option<InternalAtmoInfo>,
pub small_grid: bool,
pub slots: Vec<Slot>,
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<i32, f64>>,
pub reagents: Option<BTreeMap<u8, f64>>,
pub memory: Vec<f64>,
}
@@ -221,12 +221,15 @@ pub struct GenericLogicableDeviceMemoryReadable {
ObjectInterface!,
GWThermal!, GWInternalAtmo!,
GWStructure!, GWStorage!, GWLogicable!,
GWDevice!, GWMemoryReadable!, GWMemoryWritable!
GWDevice!, GWMemoryReadable!, GWMemoryWritable!,
GWReagentConsumer!, GWReagentRequirer!, GWFabricator!,
)]
#[custom(implements(Object {
Thermal[GWThermal::is_thermal],
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
Structure, Storage, Logicable, Device, MemoryReadable
Structure, Storage, Logicable, Device, MemoryReadable,
ReagentConsumer, ReagentRequirer,
Fabricator[GWFabricator::is_fabricator]
}))]
pub struct GenericLogicableDeviceConsumerMemoryReadable {
#[custom(object_id)]
@@ -240,15 +243,17 @@ pub struct GenericLogicableDeviceConsumerMemoryReadable {
pub thermal_info: Option<ThermalInfo>,
pub internal_atmo_info: Option<InternalAtmoInfo>,
pub small_grid: bool,
pub slots: Vec<Slot>,
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<i32, f64>>,
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>,
}
@@ -275,13 +280,13 @@ pub struct GenericLogicableDeviceMemoryReadWriteable {
pub thermal_info: Option<ThermalInfo>,
pub internal_atmo_info: Option<InternalAtmoInfo>,
pub small_grid: bool,
pub slots: Vec<Slot>,
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<i32, f64>>,
pub reagents: Option<BTreeMap<u8, f64>>,
pub memory: Vec<f64>,
}
@@ -289,12 +294,15 @@ pub struct GenericLogicableDeviceMemoryReadWriteable {
ObjectInterface!,
GWThermal!, GWInternalAtmo!,
GWStructure!, GWStorage!, GWLogicable!,
GWDevice!, GWMemoryReadable!, GWMemoryWritable!
GWDevice!, GWMemoryReadable!, GWMemoryWritable!,
GWReagentConsumer!, GWReagentRequirer!, GWFabricator!,
)]
#[custom(implements(Object {
Thermal[GWThermal::is_thermal],
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
Structure, Storage, Logicable, Device, MemoryReadable, MemoryWritable
Structure, Storage, Logicable, Device, MemoryReadable, MemoryWritable,
ReagentConsumer, ReagentRequirer,
Fabricator[GWFabricator::is_fabricator]
}))]
pub struct GenericLogicableDeviceConsumerMemoryReadWriteable {
#[custom(object_id)]
@@ -308,15 +316,17 @@ pub struct GenericLogicableDeviceConsumerMemoryReadWriteable {
pub thermal_info: Option<ThermalInfo>,
pub internal_atmo_info: Option<InternalAtmoInfo>,
pub small_grid: bool,
pub slots: Vec<Slot>,
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<i32, f64>>,
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>,
}
@@ -362,14 +372,18 @@ pub struct GenericItemStorage {
pub item_info: ItemInfo,
pub parent_slot: Option<ParentSlotInfo>,
pub damage: Option<f32>,
pub slots: Vec<Slot>,
pub slots: BTreeMap<u32, Slot>,
}
#[derive(ObjectInterface!, GWThermal!, GWInternalAtmo!, GWItem!, GWStorage! )]
#[derive(
ObjectInterface!, GWThermal!,
GWInternalAtmo!, GWItem!, GWStorage!,
GWReagentConsumer!
)]
#[custom(implements(Object {
Thermal[GWThermal::is_thermal],
InternalAtmosphere[GWInternalAtmo::is_internal_atmo],
Item, Storage
Item, Storage, ReagentConsumer
}))]
pub struct GenericItemConsumer {
#[custom(object_id)]
@@ -385,7 +399,7 @@ pub struct GenericItemConsumer {
pub item_info: ItemInfo,
pub parent_slot: Option<ParentSlotInfo>,
pub damage: Option<f32>,
pub slots: Vec<Slot>,
pub slots: BTreeMap<u32, Slot>,
pub consumer_info: ConsumerInfo,
}
@@ -413,7 +427,7 @@ pub struct GenericItemLogicable {
pub item_info: ItemInfo,
pub parent_slot: Option<ParentSlotInfo>,
pub damage: Option<f32>,
pub slots: Vec<Slot>,
pub slots: BTreeMap<u32, Slot>,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
}
@@ -443,7 +457,7 @@ pub struct GenericItemLogicableMemoryReadable {
pub item_info: ItemInfo,
pub parent_slot: Option<ParentSlotInfo>,
pub damage: Option<f32>,
pub slots: Vec<Slot>,
pub slots: BTreeMap<u32, Slot>,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
pub memory: Vec<f64>,
@@ -474,7 +488,7 @@ pub struct GenericItemLogicableMemoryReadWriteable {
pub item_info: ItemInfo,
pub parent_slot: Option<ParentSlotInfo>,
pub damage: Option<f32>,
pub slots: Vec<Slot>,
pub slots: BTreeMap<u32, Slot>,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
pub memory: Vec<f64>,
@@ -506,7 +520,7 @@ pub struct GenericItemCircuitHolder {
pub item_info: ItemInfo,
pub parent_slot: Option<ParentSlotInfo>,
pub damage: Option<f32>,
pub slots: Vec<Slot>,
pub slots: BTreeMap<u32, Slot>,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
pub error: i32,
@@ -537,7 +551,7 @@ pub struct GenericItemSuitLogic {
pub item_info: ItemInfo,
pub parent_slot: Option<ParentSlotInfo>,
pub damage: Option<f32>,
pub slots: Vec<Slot>,
pub slots: BTreeMap<u32, Slot>,
pub suit_info: SuitInfo,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
@@ -570,7 +584,7 @@ pub struct GenericItemSuitCircuitHolder {
pub item_info: ItemInfo,
pub parent_slot: Option<ParentSlotInfo>,
pub damage: Option<f32>,
pub slots: Vec<Slot>,
pub slots: BTreeMap<u32, Slot>,
pub suit_info: SuitInfo,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
@@ -602,6 +616,6 @@ pub struct GenericItemSuit {
pub item_info: ItemInfo,
pub parent_slot: Option<ParentSlotInfo>,
pub damage: Option<f32>,
pub slots: Vec<Slot>,
pub slots: BTreeMap<u32, Slot>,
pub suit_info: SuitInfo,
}

View File

@@ -7,14 +7,18 @@ use crate::{
},
};
use itertools::Itertools;
use stationeers_data::{
enums::{
basic::{Class, GasType, SortingClass},
script::{LogicSlotType, LogicType},
},
templates::{DeviceInfo, InternalAtmoInfo, ItemInfo, SuitInfo, ThermalInfo},
templates::{
ConsumerInfo, DeviceInfo, FabricatorInfo, InternalAtmoInfo, ItemInfo, RecipeOrder,
SuitInfo, ThermalInfo,
},
};
use std::{collections::BTreeMap, usize};
use std::collections::BTreeMap;
use strum::IntoEnumIterator;
pub trait GWThermal {
@@ -29,6 +33,9 @@ impl<T: GWThermal + Object> Thermal for T {
fn get_convection_factor(&self) -> f32 {
self.thermal_info().convection_factor
}
fn debug_thermal(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "thermal_info: {:?}", self.thermal_info())
}
}
pub trait GWInternalAtmo {
@@ -40,6 +47,9 @@ impl<T: GWInternalAtmo + Object> InternalAtmosphere for T {
fn get_volume(&self) -> f64 {
self.internal_atmo_info().volume as f64
}
fn debug_internal_atmosphere(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "internal_atmo_info: {:?}", self.internal_atmo_info())
}
}
pub trait GWStructure {
@@ -50,11 +60,14 @@ impl<T: GWStructure + Object> Structure for T {
fn is_small_grid(&self) -> bool {
self.small_grid()
}
fn debug_structure(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "small_grid: {}", self.small_grid())
}
}
pub trait GWStorage {
fn slots(&self) -> &Vec<Slot>;
fn slots_mut(&mut self) -> &mut Vec<Slot>;
fn slots(&self) -> &BTreeMap<u32, Slot>;
fn slots_mut(&mut self) -> &mut BTreeMap<u32, Slot>;
}
impl<T: GWStorage + Object> Storage for T {
@@ -62,16 +75,25 @@ impl<T: GWStorage + Object> Storage for T {
self.slots().len()
}
fn get_slot(&self, index: usize) -> Option<&Slot> {
self.slots().get(index)
self.slots().get(&(index as u32))
}
fn get_slot_mut(&mut self, index: usize) -> Option<&mut Slot> {
self.slots_mut().get_mut(index)
self.slots_mut().get_mut(&(index as u32))
}
fn get_slots(&self) -> Vec<&Slot> {
self.slots().iter().collect()
fn get_slots(&self) -> Vec<(usize, &Slot)> {
self.slots()
.iter()
.map(|(index, slot)| (*index as usize, slot))
.collect()
}
fn get_slots_mut(&mut self) -> Vec<&mut Slot> {
self.slots_mut().iter_mut().collect()
fn get_slots_mut(&mut self) -> Vec<(usize, &mut Slot)> {
self.slots_mut()
.iter_mut()
.map(|(index, slot)| (*index as usize, slot))
.collect()
}
fn debug_storage(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "slots: {:?}", self.slots())
}
}
@@ -82,6 +104,14 @@ pub trait GWLogicable: Storage {
}
impl<T: GWLogicable + Object> Logicable for T {
fn debug_logicable(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"fields: {:?}, modes: {:?}",
self.fields(),
self.known_modes()
)
}
fn prefab_hash(&self) -> i32 {
self.get_prefab().hash
}
@@ -213,7 +243,7 @@ impl<T: GWLogicable + Object> Logicable for T {
}
Class => {
if slot.occupant.is_some() {
Ok(slot.typ as i32 as f64)
Ok(slot.class as i32 as f64)
} else {
Ok(0.0)
}
@@ -349,6 +379,14 @@ pub trait GWMemoryReadable {
}
impl<T: GWMemoryReadable + Object> MemoryReadable for T {
fn debug_memory_readable(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"size: {}, values: {:?}",
self.memory_size(),
self.memory()
)
}
fn memory_size(&self) -> usize {
self.memory_size()
}
@@ -371,6 +409,14 @@ pub trait GWMemoryWritable: MemoryReadable {
}
impl<T: GWMemoryWritable + MemoryReadable + Object> MemoryWritable for T {
fn debug_memory_writable(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"size: {}, values: {:?}",
self.memory_size(),
self.get_memory_slice()
)
}
fn set_memory(&mut self, index: i32, val: f64) -> Result<(), MemoryError> {
if index < 0 {
Err(MemoryError::StackUnderflow(index, self.memory_size()))
@@ -392,11 +438,20 @@ pub trait GWDevice: GWLogicable + Logicable {
fn connections_mut(&mut self) -> &mut [Connection];
fn pins(&self) -> Option<&[Option<ObjectID>]>;
fn pins_mut(&mut self) -> Option<&mut [Option<ObjectID>]>;
fn reagents(&self) -> Option<&BTreeMap<i32, f64>>;
fn reagents_mut(&mut self) -> &mut Option<BTreeMap<i32, f64>>;
fn reagents(&self) -> Option<&BTreeMap<u8, f64>>;
fn reagents_mut(&mut self) -> &mut Option<BTreeMap<u8, f64>>;
}
impl<T: GWDevice + GWStorage + Object> Device for T {
fn debug_device(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"device_info: {:?}, connections: {:?}, pins: {:?}",
self.device_info(),
self.connections(),
self.pins()
)
}
fn can_slot_logic_write(&self, slt: LogicSlotType, index: f64) -> bool {
if index < 0.0 {
false
@@ -499,7 +554,7 @@ impl<T: GWDevice + GWStorage + Object> Device for T {
fn has_atmosphere(&self) -> bool {
self.device_info().has_atmosphere
}
fn get_reagents(&self) -> Vec<(i32, f64)> {
fn get_reagents(&self) -> Vec<(u8, f64)> {
self.reagents()
.map(|reagents| {
reagents
@@ -509,11 +564,11 @@ impl<T: GWDevice + GWStorage + Object> Device for T {
})
.unwrap_or_default()
}
fn set_reagents(&mut self, reagents: &[(i32, f64)]) {
fn set_reagents(&mut self, reagents: &[(u8, f64)]) {
let reagents_ref = self.reagents_mut();
*reagents_ref = Some(reagents.iter().copied().collect());
}
fn add_reagents(&mut self, reagents: &[(i32, f64)]) {
fn add_reagents(&mut self, reagents: &[(u8, f64)]) {
let reagents_ref = self.reagents_mut();
if let Some(ref mut reagents_ref) = reagents_ref {
reagents_ref.extend(reagents.iter().map(|(hash, quant)| (hash, quant)));
@@ -532,6 +587,15 @@ pub trait GWItem {
}
impl<T: GWItem + Object> Item for T {
fn debug_item(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"item_info: {:?}, parent_slot: {:?}, damage: {:?}",
self.item_info(),
self.parent_slot(),
self.damage()
)
}
fn consumable(&self) -> bool {
self.item_info().consumable
}
@@ -572,6 +636,9 @@ pub trait GWSuit: Storage {
}
impl<T: GWSuit + Item + Object> Suit for T {
fn debug_suit(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "suit_info: {:?}", self.suit_info())
}
fn pressure_waste_max(&self) -> f32 {
self.suit_info().waste_max_pressure
}
@@ -654,7 +721,7 @@ pub trait GWCircuitHolderWrapper<T: GWCircuitHolder, H = <T as GWCircuitHolder>:
connection: Option<usize>,
) -> Option<ObjectRefMut>;
fn get_ic_gw(&self) -> Option<VMObject>;
fn hault_and_catch_fire_gw(&mut self);
fn halt_and_catch_fire_gw(&mut self);
}
impl<T> CircuitHolder for T
@@ -662,6 +729,9 @@ where
T: GWCircuitHolder,
Self: GWCircuitHolderWrapper<T>,
{
fn debug_circuit_holder(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "GenericCircuitHolder, Limited Info")
}
fn clear_error(&mut self) {
self.clear_error_gw()
}
@@ -702,7 +772,7 @@ where
self.get_ic_gw()
}
fn halt_and_catch_fire(&mut self) {
self.hault_and_catch_fire_gw()
self.halt_and_catch_fire_gw()
}
}
@@ -822,15 +892,15 @@ where
fn get_ic_gw(&self) -> Option<crate::vm::object::VMObject> {
self.get_slots()
.into_iter()
.find(|slot| slot.typ == Class::ProgrammableChip)
.and_then(|slot| {
.find(|(_, slot)| slot.class == Class::ProgrammableChip)
.and_then(|(_, slot)| {
slot.occupant
.as_ref()
.and_then(|info| self.get_vm().get_object(info.id))
})
}
fn hault_and_catch_fire_gw(&mut self) {
fn halt_and_catch_fire_gw(&mut self) {
// TODO: do something here??
}
}
@@ -937,7 +1007,7 @@ where
let contained_ids: Vec<ObjectID> = self
.get_slots()
.into_iter()
.filter_map(|slot| slot.occupant.as_ref().map(|info| info.id))
.filter_map(|(_, slot)| slot.occupant.as_ref().map(|info| info.id))
.collect();
if contained_ids.contains(&device) {
self.get_vm()
@@ -959,7 +1029,7 @@ where
let contained_ids: Vec<ObjectID> = self
.get_slots()
.into_iter()
.filter_map(|slot| slot.occupant.as_ref().map(|info| info.id))
.filter_map(|(_, slot)| slot.occupant.as_ref().map(|info| info.id))
.collect();
if contained_ids.contains(&device) {
self.get_vm()
@@ -973,15 +1043,15 @@ where
fn get_ic_gw(&self) -> Option<crate::vm::object::VMObject> {
self.get_slots()
.into_iter()
.find(|slot| slot.typ == Class::ProgrammableChip)
.and_then(|slot| {
.find(|(_, slot)| slot.class == Class::ProgrammableChip)
.and_then(|(_, slot)| {
slot.occupant
.as_ref()
.and_then(|info| self.get_vm().get_object(info.id))
})
}
fn hault_and_catch_fire_gw(&mut self) {
fn halt_and_catch_fire_gw(&mut self) {
// TODO: do something here??
}
}
@@ -1112,7 +1182,7 @@ where
let contained_ids: Vec<ObjectID> = self
.get_slots()
.into_iter()
.filter_map(|slot| slot.occupant.as_ref().map(|info| info.id))
.filter_map(|(_, slot)| slot.occupant.as_ref().map(|info| info.id))
.collect();
if contained_ids.contains(&device) {
self.get_vm()
@@ -1134,7 +1204,7 @@ where
let contained_ids: Vec<ObjectID> = self
.get_slots()
.into_iter()
.filter_map(|slot| slot.occupant.as_ref().map(|info| info.id))
.filter_map(|(_, slot)| slot.occupant.as_ref().map(|info| info.id))
.collect();
if contained_ids.contains(&device) {
self.get_vm()
@@ -1148,15 +1218,130 @@ where
fn get_ic_gw(&self) -> Option<crate::vm::object::VMObject> {
self.get_slots()
.into_iter()
.find(|slot| slot.typ == Class::ProgrammableChip)
.and_then(|slot| {
.find(|(_, slot)| slot.class == Class::ProgrammableChip)
.and_then(|(_, slot)| {
slot.occupant
.as_ref()
.and_then(|info| self.get_vm().get_object(info.id))
})
}
fn hault_and_catch_fire_gw(&mut self) {
fn halt_and_catch_fire_gw(&mut self) {
// TODO: do something here??
}
}
pub trait GWReagentConsumer {
fn consumer_info(&self) -> &ConsumerInfo;
}
impl<T: GWReagentConsumer + Object> ReagentConsumer for T {
fn debug_reagent_consumer(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "") // TODO: implement
}
fn get_resources_used(&self) -> Vec<i32> {
let info = self.consumer_info();
let vm = self.get_vm();
info.consumed_resources
.iter()
.filter_map(|resource| {
let prefab = vm.lookup_template_by_name(resource);
prefab.map(|prefab| prefab.prefab().prefab_hash)
})
.collect_vec()
}
fn can_process_reagent(&self, reagent_id: u8) -> bool {
let info = self.consumer_info();
let vm = self.get_vm();
let processed = info
.processed_reagents
.iter()
.filter_map(|reagent_hash| vm.lookup_reagent_by_hash(*reagent_hash))
.collect_vec();
processed
.iter()
.find(|reagent| reagent.id == reagent_id)
.is_some()
}
}
pub trait GWReagentRequirer: Device {
fn get_current_recipe_gw(&self) -> Option<(u32, u32)>;
fn get_fab_info_gw(&self) -> Option<&FabricatorInfo>;
}
impl<T: GWReagentRequirer + Object> ReagentRequirer for T {
fn debug_reagent_requirer(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"current: {:?}, required: {:?}",
self.get_current_recipe(),
self.get_current_required()
)
}
fn get_current_recipe(&self) -> Option<RecipeOrder> {
if let Some((current, quantity)) = self.get_current_recipe_gw() {
let info = self.get_fab_info_gw();
let recipe = info.and_then(|info| info.recipes.get(current as usize));
recipe.map(|recipe| RecipeOrder {
recipe: recipe.clone(),
quantity,
})
} else {
return None;
}
}
fn get_current_required(&self) -> Vec<(u8, f64)> {
let current = self.get_current_recipe();
let vm = self.get_vm();
let have = self.get_reagents();
let needed = current.map_or_else(std::default::Default::default, |current| {
current
.recipe
.reagents
.iter()
.filter_map(|(reagent_name, reagent_quantity)| {
if let Some(reagent) = vm.lookup_reagent_by_name(&reagent_name) {
if let Some((_id, have_quantity)) = have
.iter()
.find(|(id, quantity)| &reagent.id == id && quantity < reagent_quantity)
{
Some((reagent.id, reagent_quantity - have_quantity))
} else {
None
}
} else {
None
}
})
.collect_vec()
});
needed
}
fn get_prefab_hash_from_reagent_hash(&self, reagent_hash: i32) -> Option<i32> {
let vm = self.get_vm();
let reagent = vm.lookup_reagent_by_hash(reagent_hash);
reagent.and_then(|reagent| {
reagent
.sources
.iter()
.find(|(source_prefab, _quant)| source_prefab.contains("Ingot"))
.map(|(prefab, _quant)| {
vm.lookup_template_by_name(prefab)
.map(|template| template.prefab().prefab_hash)
})
.flatten()
})
}
}
pub trait GWFabricator: ReagentRequirer {
fn is_fabricator(&self) -> bool;
fn fabricator_info(&self) -> &FabricatorInfo;
}
impl<T: GWFabricator + Object> Fabricator for T {
fn debug_fabricator(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "UNIMPLEMENTED") // TODO: implement
}
}

View File

@@ -1,9 +1,7 @@
use std::collections::BTreeMap;
use macro_rules_attribute::derive;
use stationeers_data::{
enums::{basic::Class, Species},
};
use stationeers_data::enums::{basic::Class, Species};
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
@@ -193,32 +191,43 @@ impl Thermal for HumanPlayer {
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 get_slots(&self) -> Vec<&Slot> {
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![
&self.left_hand_slot,
&self.right_hand_slot,
&self.helmet_slot,
&self.suit_slot,
&self.backpack_slot,
&self.uniform_slot,
&self.toolbelt_slot,
&self.glasses_slot,
(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<&mut Slot> {
fn get_slots_mut(&mut self) -> Vec<(usize, &mut Slot)> {
vec![
&mut self.left_hand_slot,
&mut self.right_hand_slot,
&mut self.helmet_slot,
&mut self.suit_slot,
&mut self.backpack_slot,
&mut self.uniform_slot,
&mut self.toolbelt_slot,
&mut self.glasses_slot,
(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),
]
}
@@ -255,6 +264,20 @@ impl Storage for HumanPlayer {
}
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
}

View File

@@ -55,6 +55,15 @@ macro_rules! object_trait {
}
}
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),
@@ -524,6 +533,20 @@ macro_rules! tag_object_traits {
$(#[$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!{

View File

@@ -14,7 +14,7 @@ use stationeers_data::enums::{
script::{LogicSlotType, LogicType},
ConnectionRole,
};
use std::rc::Rc;
use std::{collections::BTreeMap, rc::Rc};
use strum::EnumProperty;
#[derive(ObjectInterface!)]
@@ -58,7 +58,7 @@ impl StructureCircuitHousing {
parent: id,
index: 0,
name: "Programmable Chip".to_string(),
typ: Class::ProgrammableChip,
class: Class::ProgrammableChip,
readable_logic: vec![
LogicSlotType::Class,
LogicSlotType::Damage,
@@ -73,6 +73,7 @@ impl StructureCircuitHousing {
],
writeable_logic: vec![],
occupant: None,
proxy: false,
},
pins: [None, None, None, None, None, None],
connections: [
@@ -95,9 +96,15 @@ 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
}
@@ -115,15 +122,31 @@ impl Storage for StructureCircuitHousing {
Some(&mut self.slot)
}
}
fn get_slots(&self) -> Vec<&Slot> {
vec![&self.slot]
fn get_slots(&self) -> Vec<(usize, &Slot)> {
vec![(0, &self.slot)]
}
fn get_slots_mut(&mut self) -> Vec<&mut Slot> {
vec![&mut 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
}
@@ -253,6 +276,13 @@ impl Logicable for StructureCircuitHousing {
}
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
}
@@ -277,13 +307,13 @@ impl Device for StructureCircuitHousing {
fn has_on_off_state(&self) -> bool {
true
}
fn get_reagents(&self) -> Vec<(i32, f64)> {
fn get_reagents(&self) -> Vec<(u8, f64)> {
vec![]
}
fn set_reagents(&mut self, _reagents: &[(i32, f64)]) {
fn set_reagents(&mut self, _reagents: &[(u8, f64)]) {
// nope
}
fn add_reagents(&mut self, _reagents: &[(i32, f64)]) {
fn add_reagents(&mut self, _reagents: &[(u8, f64)]) {
// nope
}
fn connection_list(&self) -> &[crate::network::Connection] {
@@ -313,6 +343,9 @@ impl Device for StructureCircuitHousing {
}
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
}

View File

@@ -1,5 +1,5 @@
use crate::{
errors::ICError,
errors::{ICError, LineError},
interpreter::{instructions::IC10Marker, ICState, Program},
vm::{
instructions::{operands::Operand, Instruction},
@@ -22,7 +22,7 @@ use std::{collections::BTreeMap, rc::Rc};
static RETURN_ADDRESS_INDEX: usize = 17;
static STACK_POINTER_INDEX: usize = 16;
#[derive(ObjectInterface!)]
#[derive(ObjectInterface!, Debug)]
#[custom(implements(Object {
Item, Storage, Logicable,
MemoryReadable, MemoryWritable,
@@ -57,6 +57,9 @@ pub struct ItemIntegratedCircuit10 {
}
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
}
@@ -93,6 +96,9 @@ impl Item for ItemIntegratedCircuit10 {
}
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
}
@@ -102,15 +108,18 @@ impl Storage for ItemIntegratedCircuit10 {
fn get_slot_mut(&mut self, _index: usize) -> Option<&mut Slot> {
None
}
fn get_slots(&self) -> Vec<&Slot> {
fn get_slots(&self) -> Vec<(usize, &Slot)> {
vec![]
}
fn get_slots_mut(&mut self) -> Vec<&mut Slot> {
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
}
@@ -170,7 +179,7 @@ impl Logicable for ItemIntegratedCircuit10 {
_ => Err(LogicError::CantWrite(lt)),
})
}
fn can_slot_logic_read(&self, _slt: LogicSlotType, _indexx: f64) -> bool {
fn can_slot_logic_read(&self, _slt: LogicSlotType, _index: f64) -> bool {
false
}
fn get_slot_logic(&self, _slt: LogicSlotType, index: f64) -> Result<f64, LogicError> {
@@ -185,6 +194,9 @@ impl Logicable for ItemIntegratedCircuit10 {
}
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()
}
@@ -203,6 +215,9 @@ impl MemoryReadable for ItemIntegratedCircuit10 {
}
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()))
@@ -219,6 +234,9 @@ impl MemoryWritable for ItemIntegratedCircuit10 {
}
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();
@@ -240,6 +258,9 @@ impl SourceCode for ItemIntegratedCircuit10 {
}
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))
@@ -388,31 +409,42 @@ impl IntegratedCircuit for ItemIntegratedCircuit10 {
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) {
if sleep_till
<= time::OffsetDateTime::now_local()
.unwrap_or_else(|_| time::OffsetDateTime::now_utc())
{
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::SleepAddtionError(duration, *then));
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(());
}
@@ -423,7 +455,13 @@ impl Programmable for ItemIntegratedCircuit10 {
let instruction = line.instruction;
let result = instruction.execute(self, operands);
let was_error = if let Err(_err) = result {
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()
@@ -437,7 +475,7 @@ impl Programmable for ItemIntegratedCircuit10 {
if !was_error || advance_ip_on_err {
self.ip = self.next_ip;
if self.ip >= self.program.len() {
if self.ip >= self.program.len() && !matches!(&self.state, ICState::Error(_)) {
self.state = ICState::Ended;
}
}

View File

@@ -27,6 +27,7 @@ use crate::{
use serde_derive::{Deserialize, Serialize};
use stationeers_data::{
enums::{
basic::Class,
prefabs::StationpediaPrefab,
script::{LogicSlotType, LogicType},
},
@@ -64,6 +65,7 @@ impl std::fmt::Display for Prefab {
}
}
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct ObjectInfo {
@@ -77,8 +79,7 @@ pub struct ObjectInfo {
pub damage: Option<f32>,
pub device_pins: Option<BTreeMap<u32, ObjectID>>,
pub connections: Option<BTreeMap<u32, ObjectID>>,
pub reagents: Option<BTreeMap<i32, f64>>,
pub memory: Option<Vec<f64>>,
pub reagents: Option<BTreeMap<u8, f64>>, pub memory: Option<Vec<f64>>,
pub logic_values: Option<BTreeMap<LogicType, f64>>,
pub slot_logic_values: Option<BTreeMap<u32, BTreeMap<LogicSlotType, f64>>>,
pub entity: Option<EntityInfo>,
@@ -201,7 +202,6 @@ impl ObjectInfo {
self.slots.replace(
slots
.into_iter()
.enumerate()
.filter_map(|(index, slot)| {
slot.occupant
.as_ref()
@@ -245,7 +245,7 @@ impl ObjectInfo {
.collect()
});
}
let reagents: BTreeMap<i32, f64> = device.get_reagents().iter().copied().collect();
let reagents: BTreeMap<u8, f64> = device.get_reagents().iter().copied().collect();
if reagents.is_empty() {
self.reagents = None;
} else {
@@ -393,6 +393,7 @@ pub struct FrozenObjectFull {
pub template: ObjectTemplate,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct FrozenObject {
@@ -480,53 +481,66 @@ impl FrozenObject {
.unwrap_or_default()
}
fn build_slots(
fn build_slots<'a>(
&self,
id: ObjectID,
slots_info: &[SlotInfo],
slots_info: impl IntoIterator<Item = (&'a u32, &'a SlotInfo)>,
logic_info: Option<&LogicInfo>,
) -> Vec<Slot> {
) -> BTreeMap<u32, Slot> {
slots_info
.iter()
.enumerate()
.map(|(index, info)| Slot {
parent: id,
index,
name: info.name.clone(),
typ: info.typ,
readable_logic: logic_info
.and_then(|info| {
info.logic_slot_types.get(&(index as u32)).map(|s_info| {
s_info
.iter()
.filter_map(|(key, access)| match access {
MemoryAccess::Read | MemoryAccess::ReadWrite => Some(key),
_ => None,
.into_iter()
.map(|(index, info)| {
let (name, class, proxy) = match info {
SlotInfo::Direct { name, class, .. } => (name.clone(), *class, false),
SlotInfo::Proxy { name, .. } => (name.clone(), Class::None, true),
};
(
*index,
Slot {
parent: id,
index: *index as usize,
name,
class,
proxy,
readable_logic: logic_info
.and_then(|info| {
info.logic_slot_types.get(index).map(|s_info| {
s_info
.iter()
.filter_map(|(key, access)| match access {
MemoryAccess::Read | MemoryAccess::ReadWrite => {
Some(key)
}
_ => None,
})
.copied()
.collect::<Vec<_>>()
})
.copied()
.collect::<Vec<_>>()
})
})
.unwrap_or_default(),
writeable_logic: logic_info
.and_then(|info| {
info.logic_slot_types.get(&(index as u32)).map(|s_info| {
s_info
.iter()
.filter_map(|(key, access)| match access {
MemoryAccess::Write | MemoryAccess::ReadWrite => Some(key),
_ => None,
})
.unwrap_or_default(),
writeable_logic: logic_info
.and_then(|info| {
info.logic_slot_types.get(index).map(|s_info| {
s_info
.iter()
.filter_map(|(key, access)| match access {
MemoryAccess::Write | MemoryAccess::ReadWrite => {
Some(key)
}
_ => None,
})
.copied()
.collect::<Vec<_>>()
})
.copied()
.collect::<Vec<_>>()
})
})
.unwrap_or_default(),
occupant: self
.obj_info
.slots
.as_ref()
.and_then(|slots| slots.get(&(index as u32)).cloned()),
})
.unwrap_or_default(),
occupant: self
.obj_info
.slots
.as_ref()
.and_then(|slots| slots.get(index).cloned()),
},
)
})
.collect()
}
@@ -748,6 +762,7 @@ impl FrozenObject {
reagents: self.obj_info.reagents.clone(),
consumer_info: s.consumer_info.clone(),
fabricator_info: s.fabricator_info.clone(),
current_recipe: None,
memory: self.build_memory(&s.memory),
},
))
@@ -771,6 +786,7 @@ impl FrozenObject {
consumer_info: s.consumer_info.clone(),
fabricator_info: s.fabricator_info.clone(),
memory: self.build_memory(&s.memory),
current_recipe: None,
},
)),
Item(i) => Ok(VMObject::new(GenericItem {
@@ -998,7 +1014,8 @@ fn try_template_from_interfaces(
plant: None,
suit: None,
chargeable: None,
reagent_interface: None,
reagent_requirer: None,
reagent_consumer: None,
fabricator: None,
internal_atmosphere,
thermal,
@@ -1033,7 +1050,8 @@ fn try_template_from_interfaces(
plant: None,
suit: None,
chargeable: None,
reagent_interface: None,
reagent_requirer: None,
reagent_consumer: None,
fabricator: None,
internal_atmosphere,
thermal,
@@ -1065,7 +1083,8 @@ fn try_template_from_interfaces(
plant: None,
suit: None,
chargeable: None,
reagent_interface: None,
reagent_requirer: None,
reagent_consumer: None,
fabricator: None,
internal_atmosphere,
thermal,
@@ -1098,7 +1117,8 @@ fn try_template_from_interfaces(
plant: None,
suit: None,
chargeable: None,
reagent_interface: None,
reagent_requirer: None,
reagent_consumer: None,
fabricator: None,
internal_atmosphere,
thermal,
@@ -1134,7 +1154,8 @@ fn try_template_from_interfaces(
plant: None,
suit: None,
chargeable: None,
reagent_interface: None,
reagent_requirer: None,
reagent_consumer: None,
fabricator: None,
internal_atmosphere,
thermal,
@@ -1173,7 +1194,8 @@ fn try_template_from_interfaces(
plant: None,
suit: None,
chargeable: None,
reagent_interface: None,
reagent_requirer: None,
reagent_consumer: None,
fabricator: None,
internal_atmosphere,
thermal,
@@ -1204,7 +1226,8 @@ fn try_template_from_interfaces(
plant: None,
suit: None,
chargeable: None,
reagent_interface: None,
reagent_requirer: None,
reagent_consumer: None,
fabricator: None,
internal_atmosphere,
thermal,
@@ -1236,7 +1259,8 @@ fn try_template_from_interfaces(
plant: None,
suit: None,
chargeable: None,
reagent_interface: None,
reagent_requirer: None,
reagent_consumer: None,
fabricator: None,
internal_atmosphere,
thermal,
@@ -1269,7 +1293,8 @@ fn try_template_from_interfaces(
plant: None,
suit: None,
chargeable: None,
reagent_interface: None,
reagent_requirer: None,
reagent_consumer: None,
fabricator: None,
internal_atmosphere,
thermal,
@@ -1303,7 +1328,8 @@ fn try_template_from_interfaces(
plant: None,
suit: None,
chargeable: None,
reagent_interface: None,
reagent_requirer: None,
reagent_consumer: None,
fabricator: None,
internal_atmosphere: None,
thermal: Some(_),
@@ -1312,13 +1338,16 @@ fn try_template_from_interfaces(
prefab: PrefabInfo {
prefab_name: "Character".to_string(),
prefab_hash: 294335127,
desc: "Charater".to_string(),
name: "Charater".to_string(),
desc: "Character".to_string(),
name: "Character".to_string(),
},
species: human.get_species(),
slots: storage.into(),
})),
_ => Err(TemplateError::NonConformingObject(obj.get_id())),
_ => {
tracing::error!("Object interface has a non conforming pattern: {:?}", obj);
Err(TemplateError::NonConformingObject(obj.get_id()))
}
}
}
@@ -1341,6 +1370,7 @@ impl From<&VMObject> for PrefabInfo {
}
}
}
impl From<LogicableRef<'_>> for LogicInfo {
fn from(logic: LogicableRef) -> Self {
// Logicable: Storage -> !None
@@ -1352,10 +1382,9 @@ impl From<LogicableRef<'_>> for LogicInfo {
logic_slot_types: storage
.get_slots()
.iter()
.enumerate()
.map(|(index, slot)| {
(
index as u32,
*index as u32,
LogicSlotType::iter()
.filter_map(|slt| {
let readable = slot.readable_logic.contains(&slt);
@@ -1418,7 +1447,7 @@ impl From<ItemRef<'_>> for ItemInfo {
impl From<DeviceRef<'_>> for DeviceInfo {
fn from(device: DeviceRef) -> Self {
let _reagents: BTreeMap<i32, f64> = device.get_reagents().iter().copied().collect();
let _reagents: BTreeMap<u8, f64> = device.get_reagents().iter().copied().collect();
DeviceInfo {
connection_list: device
.connection_list()
@@ -1478,14 +1507,27 @@ impl From<ThermalRef<'_>> for ThermalInfo {
}
}
impl From<StorageRef<'_>> for Vec<SlotInfo> {
impl From<StorageRef<'_>> for BTreeMap<u32, SlotInfo> {
fn from(storage: StorageRef<'_>) -> Self {
storage
.get_slots()
.iter()
.map(|slot| SlotInfo {
name: slot.name.clone(),
typ: slot.typ,
.map(|(_index, slot)| {
(
slot.index as u32,
if slot.proxy {
SlotInfo::Proxy {
name: slot.name.clone(),
index: slot.index as u32,
}
} else {
SlotInfo::Direct {
name: slot.name.clone(),
class: slot.class,
index: slot.index as u32,
}
},
)
})
.collect()
}

View File

@@ -13,10 +13,13 @@ use crate::{
},
},
};
use stationeers_data::enums::{
basic::{Class, GasType, SortingClass},
script::{LogicSlotType, LogicType},
Species,
use stationeers_data::{
enums::{
basic::{Class, GasType, SortingClass},
script::{LogicSlotType, LogicType},
Species,
},
templates::RecipeOrder,
};
use std::{collections::BTreeMap, fmt::Debug};
#[cfg(feature = "tsify")]
@@ -75,9 +78,9 @@ tag_object_traits! {
/// 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<&Slot>;
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<&mut Slot>;
fn get_slots_mut(&mut self) -> Vec<(usize, &mut Slot)>;
}
pub trait MemoryReadable {
@@ -394,21 +397,29 @@ tag_object_traits! {
/// Does the device store reagents
fn has_reagents(&self) -> bool;
/// Return vector of (reagent_hash, quantity) pairs
fn get_reagents(&self) -> Vec<(i32, f64)>;
fn get_reagents(&self) -> Vec<(u8, f64)>;
/// Overwrite present reagents
fn set_reagents(&mut self, reagents: &[(i32, f64)]);
fn set_reagents(&mut self, reagents: &[(u8, f64)]);
/// Adds the reagents to contents
fn add_reagents(&mut self, reagents: &[(i32, f64)]);
fn add_reagents(&mut self, reagents: &[(u8, f64)]);
}
pub trait ReagentInterface: Device {
/// Reagents required by current recipe
fn get_current_recipe(&self) -> Vec<(i32, 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<(i32, f64)>;
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: ReagentInterface {}
pub trait Fabricator: ReagentRequirer {
}
pub trait WirelessTransmit: Logicable {}
@@ -493,14 +504,18 @@ impl Debug for dyn Object {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Object: (ID = {:?}, Type = {})",
"Object{{id: {:?}, type: {}, interfaces: {:?}}}",
self.get_id(),
self.type_name()
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
@@ -546,4 +561,3 @@ impl<T: CircuitHolder> SourceCode for T {
.unwrap_or_default()
}
}

View File

@@ -26,6 +26,7 @@ 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"
[features]
default = ["console_error_panic_hook"]

View File

@@ -478,6 +478,7 @@ 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!");
vm

View File

@@ -6,11 +6,13 @@ 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
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"

File diff suppressed because it is too large Load Diff

View 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
}

View File

@@ -2001,6 +2001,12 @@ impl std::str::FromStr for BasicEnum {
"logictype.stress" => Ok(Self::LogicType(LogicType::Stress)),
"logictype.survey" => Ok(Self::LogicType(LogicType::Survey)),
"logictype.targetpadindex" => Ok(Self::LogicType(LogicType::TargetPadIndex)),
"logictype.targetprefabhash" => {
Ok(Self::LogicType(LogicType::TargetPrefabHash))
}
"logictype.targetslotindex" => {
Ok(Self::LogicType(LogicType::TargetSlotIndex))
}
"logictype.targetx" => Ok(Self::LogicType(LogicType::TargetX)),
"logictype.targety" => Ok(Self::LogicType(LogicType::TargetY)),
"logictype.targetz" => Ok(Self::LogicType(LogicType::TargetZ)),

View File

@@ -1255,6 +1255,9 @@ pub enum StationpediaPrefab {
)
)]
ItemWallCooler = -1567752627i32,
#[strum(serialize = "StructureLarreDockCargo")]
#[strum(props(name = "LARrE Dock (Cargo)", desc = "", value = "-1555459562"))]
StructureLarreDockCargo = -1555459562i32,
#[strum(serialize = "StructureSolarPanel45")]
#[strum(
props(
@@ -2153,6 +2156,9 @@ pub enum StationpediaPrefab {
props(name = "Kitchen Table (Simple Tall)", desc = "", value = "-1068629349")
)]
KitchenTableSimpleTall = -1068629349i32,
#[strum(serialize = "ItemKitLarreDockCargo")]
#[strum(props(name = "Kit (LArRE Dock Cargo)", desc = "", value = "-1067485367"))]
ItemKitLarreDockCargo = -1067485367i32,
#[strum(serialize = "ItemGasFilterOxygenM")]
#[strum(props(name = "Medium Filter (Oxygen)", desc = "", value = "-1067319543"))]
ItemGasFilterOxygenM = -1067319543i32,
@@ -2341,6 +2347,9 @@ pub enum StationpediaPrefab {
#[strum(serialize = "ItemKitElevator")]
#[strum(props(name = "Kit (Elevator)", desc = "", value = "-945806652"))]
ItemKitElevator = -945806652i32,
#[strum(serialize = "ItemKitLarreDockBypass")]
#[strum(props(name = "Kit (LArRE Dock Bypass)", desc = "", value = "-940470326"))]
ItemKitLarreDockBypass = -940470326i32,
#[strum(serialize = "StructureSolarPanelReinforced")]
#[strum(
props(
@@ -3086,6 +3095,15 @@ pub enum StationpediaPrefab {
#[strum(serialize = "StructurePipeLiquidOneWayValveLever")]
#[strum(props(name = "One Way Valve (Liquid)", desc = "", value = "-523832822"))]
StructurePipeLiquidOneWayValveLever = -523832822i32,
#[strum(serialize = "StructureLarreDockCollector")]
#[strum(
props(
name = "LARrE Dock (Collector)",
desc = "0.Outward\n1.Inward",
value = "-522428667"
)
)]
StructureLarreDockCollector = -522428667i32,
#[strum(serialize = "StructureWaterDigitalValve")]
#[strum(props(name = "Liquid Digital Valve", desc = "", value = "-517628750"))]
StructureWaterDigitalValve = -517628750i32,
@@ -4023,6 +4041,9 @@ pub enum StationpediaPrefab {
#[strum(serialize = "CartridgeTracker")]
#[strum(props(name = "Cartridge (Tracker)", desc = "", value = "81488783"))]
CartridgeTracker = 81488783i32,
#[strum(serialize = "StructureLarreDockHydroponics")]
#[strum(props(name = "LARrE Dock (Hydroponics)", desc = "", value = "85133079"))]
StructureLarreDockHydroponics = 85133079i32,
#[strum(serialize = "ToyLuna")]
#[strum(props(name = "Toy Luna", desc = "", value = "94730034"))]
ToyLuna = 94730034i32,
@@ -4604,6 +4625,9 @@ pub enum StationpediaPrefab {
)
)]
StructurePictureFrameThickMountLandscapeSmall = 347154462i32,
#[strum(serialize = "ItemKitLarreDockCollector")]
#[strum(props(name = "Kit (LArRE Dock Collector)", desc = "", value = "347658127"))]
ItemKitLarreDockCollector = 347658127i32,
#[strum(serialize = "RoverCargo")]
#[strum(
props(
@@ -4652,6 +4676,9 @@ pub enum StationpediaPrefab {
#[strum(serialize = "ItemMiningPackage")]
#[strum(props(name = "Mining Supplies Package", desc = "", value = "384478267"))]
ItemMiningPackage = 384478267i32,
#[strum(serialize = "ItemKitLarreDockAtmos")]
#[strum(props(name = "Kit (LArRE Dock Atmos)", desc = "", value = "385528206"))]
ItemKitLarreDockAtmos = 385528206i32,
#[strum(serialize = "ItemPureIceNitrous")]
#[strum(
props(
@@ -5086,6 +5113,11 @@ pub enum StationpediaPrefab {
)
)]
ItemRocketMiningDrillHeadHighSpeedIce = 653461728i32,
#[strum(serialize = "ItemKitLarreDockHydroponics")]
#[strum(
props(name = "Kit (LArRE Dock Hydroponics)", desc = "", value = "656181408")
)]
ItemKitLarreDockHydroponics = 656181408i32,
#[strum(serialize = "ItemWreckageStructureWeatherStation007")]
#[strum(props(name = "Wreckage", desc = "", value = "656649558"))]
ItemWreckageStructureWeatherStation007 = 656649558i32,
@@ -5724,6 +5756,9 @@ pub enum StationpediaPrefab {
)
)]
EntityChickenWhite = 1010807532i32,
#[strum(serialize = "StructureLarreDockBypass")]
#[strum(props(name = "LARrE Dock (Bypass)", desc = "", value = "1011275082"))]
StructureLarreDockBypass = 1011275082i32,
#[strum(serialize = "ItemKitStacker")]
#[strum(props(name = "Kit (Stacker)", desc = "", value = "1013244511"))]
ItemKitStacker = 1013244511i32,
@@ -7396,6 +7431,15 @@ pub enum StationpediaPrefab {
#[strum(serialize = "StructureRoboticArmRailCornerStop")]
#[strum(props(name = "Linear Rail Corner Station", desc = "", value = "1974053060"))]
StructureRoboticArmRailCornerStop = 1974053060i32,
#[strum(serialize = "StructureLarreDockAtmos")]
#[strum(
props(
name = "LARrE Dock (Atmos)",
desc = "0.Outward\n1.Inward",
value = "1978422481"
)
)]
StructureLarreDockAtmos = 1978422481i32,
#[strum(serialize = "StructureWallGeometryCorner")]
#[strum(props(name = "Wall (Geometry Corner)", desc = "", value = "1979212240"))]
StructureWallGeometryCorner = 1979212240i32,

View File

@@ -2103,6 +2103,17 @@ pub enum LogicType {
)
)]
Altitude = 269u16,
#[strum(serialize = "TargetSlotIndex")]
#[strum(
props(
docs = "The slot index that the target device that this device will try to interact with",
value = "270"
)
)]
TargetSlotIndex = 270u16,
#[strum(serialize = "TargetPrefabHash")]
#[strum(props(docs = "The prefab", value = "271"))]
TargetPrefabHash = 271u16,
}
impl TryFrom<f64> for LogicType {
type Error = super::ParseError;

View File

@@ -173,8 +173,22 @@ pub fn build_prefab_database() -> Option<BTreeMap<i32, templates::ObjectTemplate
map
}
#[cfg(feature = "prefab_database")]
pub mod database {
mod prefab_map;
pub use prefab_map::build_prefab_database;
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;
}

View File

@@ -179,7 +179,7 @@ impl From<HumanTemplate> for ObjectTemplate {
pub struct HumanTemplate {
pub prefab: PrefabInfo,
pub species: Species,
pub slots: Vec<SlotInfo>,
pub slots: BTreeMap<u32, SlotInfo>,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
@@ -193,21 +193,31 @@ pub struct PrefabInfo {
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct SlotInfo {
pub name: String,
pub typ: Class,
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>>"))]
#[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(type = "Map<string, string> | undefined"))]
#[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,
@@ -218,9 +228,11 @@ pub struct LogicInfo {
#[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,
@@ -238,6 +250,7 @@ pub struct ConnectionInfo {
#[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,
@@ -256,6 +269,24 @@ pub struct ConsumerInfo {
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 {
@@ -276,6 +307,8 @@ pub struct RecipeGasMix {
#[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,
@@ -286,11 +319,27 @@ pub struct Recipe {
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: BTreeMap<String, Recipe>,
pub recipes: Vec<Recipe>,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
@@ -334,6 +383,7 @@ pub struct Instruction {
#[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,
@@ -364,7 +414,9 @@ pub struct SuitInfo {
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>,
}
@@ -373,9 +425,11 @@ pub struct StructureTemplate {
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>,
pub slots: Vec<SlotInfo>,
pub slots: BTreeMap<u32, SlotInfo>,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
@@ -383,10 +437,12 @@ pub struct StructureSlotsTemplate {
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,
pub slots: Vec<SlotInfo>,
pub slots: BTreeMap<u32, SlotInfo>,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
@@ -394,10 +450,12 @@ pub struct StructureLogicTemplate {
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,
pub slots: Vec<SlotInfo>,
pub slots: BTreeMap<u32, SlotInfo>,
pub device: DeviceInfo,
}
@@ -406,12 +464,15 @@ pub struct StructureLogicDeviceTemplate {
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,
pub slots: Vec<SlotInfo>,
pub slots: BTreeMap<u32, SlotInfo>,
pub device: DeviceInfo,
pub consumer_info: ConsumerInfo,
#[cfg_attr(feature = "tsify", tsify(optional))]
pub fabricator_info: Option<FabricatorInfo>,
}
@@ -420,10 +481,12 @@ pub struct StructureLogicDeviceConsumerTemplate {
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,
pub slots: Vec<SlotInfo>,
pub slots: BTreeMap<u32, SlotInfo>,
pub device: DeviceInfo,
pub memory: MemoryInfo,
}
@@ -433,10 +496,12 @@ pub struct StructureLogicDeviceMemoryTemplate {
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,
pub slots: Vec<SlotInfo>,
pub slots: BTreeMap<u32, SlotInfo>,
pub device: DeviceInfo,
}
@@ -445,12 +510,15 @@ pub struct StructureCircuitHolderTemplate {
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,
pub slots: Vec<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,
}
@@ -460,7 +528,9 @@ pub struct StructureLogicDeviceConsumerMemoryTemplate {
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>,
}
@@ -469,9 +539,11 @@ pub struct ItemTemplate {
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>,
pub slots: Vec<SlotInfo>,
pub slots: BTreeMap<u32, SlotInfo>,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
@@ -479,9 +551,11 @@ pub struct ItemSlotsTemplate {
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>,
pub slots: Vec<SlotInfo>,
pub slots: BTreeMap<u32, SlotInfo>,
pub consumer_info: ConsumerInfo,
}
@@ -490,10 +564,12 @@ pub struct ItemConsumerTemplate {
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,
pub slots: Vec<SlotInfo>,
pub slots: BTreeMap<u32, SlotInfo>,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
@@ -501,10 +577,12 @@ pub struct ItemLogicTemplate {
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,
pub slots: Vec<SlotInfo>,
pub slots: BTreeMap<u32, SlotInfo>,
pub memory: MemoryInfo,
}
@@ -513,10 +591,12 @@ pub struct ItemLogicMemoryTemplate {
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,
pub slots: Vec<SlotInfo>,
pub slots: BTreeMap<u32, SlotInfo>,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
@@ -524,9 +604,11 @@ pub struct ItemCircuitHolderTemplate {
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>,
pub slots: Vec<SlotInfo>,
pub slots: BTreeMap<u32, SlotInfo>,
pub suit_info: SuitInfo,
}
@@ -535,10 +617,12 @@ pub struct ItemSuitTemplate {
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,
pub slots: Vec<SlotInfo>,
pub slots: BTreeMap<u32, SlotInfo>,
pub suit_info: SuitInfo,
}
@@ -547,10 +631,12 @@ pub struct ItemSuitLogicTemplate {
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,
pub slots: Vec<SlotInfo>,
pub slots: BTreeMap<u32, SlotInfo>,
pub suit_info: SuitInfo,
pub memory: MemoryInfo,
}