refactor(vm): freeze concreet ic, add "humans", tsify feature

This commit is contained in:
Rachel Powers
2024-05-27 01:10:59 -07:00
parent d70d3a2431
commit 88ff2d1bdb
26 changed files with 997 additions and 163 deletions

19
Cargo.lock generated
View File

@@ -594,6 +594,19 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "gloo-utils"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e"
dependencies = [
"js-sys",
"serde",
"serde_json",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
@@ -690,6 +703,8 @@ dependencies = [
"strum_macros",
"thiserror",
"time",
"tsify",
"wasm-bindgen",
]
[[package]]
@@ -1594,6 +1609,8 @@ dependencies = [
"serde",
"serde_derive",
"strum",
"tsify",
"wasm-bindgen",
]
[[package]]
@@ -1943,8 +1960,10 @@ version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6b26cf145f2f3b9ff84e182c448eaf05468e247f148cf3d2a7d67d78ff023a0"
dependencies = [
"gloo-utils",
"serde",
"serde-wasm-bindgen 0.5.0",
"serde_json",
"tsify-macros",
"wasm-bindgen",
]

View File

@@ -29,6 +29,8 @@ time = { version = "0.3.36", features = [
"serde",
"local-offset",
] }
tsify = { version = "0.4.5", optional = true, features = ["js"] }
wasm-bindgen = { version = "0.2.92", optional = true }
[target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom = { version = "0.2", features = ["js"] }
@@ -42,3 +44,7 @@ time = { version = "0.3.36", features = [
[dev-dependencies]
color-eyre = "0.6.3"
serde_json = "1.0.117"
[features]
tsify = ["dep:tsify", "dep:wasm-bindgen", "stationeers_data/tsify"]
wasm-bindgen = ["dep:wasm-bindgen"]

View File

@@ -1,15 +1,23 @@
use crate::vm::{
instructions::enums::InstructionOp,
object::{
errors::{LogicError, MemoryError}, templates::Prefab, ObjectID
errors::{LogicError, MemoryError},
templates::Prefab,
ObjectID,
},
};
use serde_derive::{Deserialize, Serialize};
use std::error::Error as StdError;
use std::fmt::Display;
use thiserror::Error;
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
#[derive(Error, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum VMError {
#[error("device with id '{0}' does not exist")]
UnknownId(u32),
@@ -50,6 +58,8 @@ pub enum VMError {
}
#[derive(Error, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum TemplateError {
#[error("object id {0} has a non conforming set of interfaces")]
NonConformingObject(ObjectID),
@@ -59,9 +69,16 @@ pub enum TemplateError {
NoTemplateForPrefab(Prefab),
#[error("no prefab provided")]
MissingPrefab,
#[error("incorrect template for concreet impl {0} from prefab {1}")]
IncorrectTemplate(String, Prefab),
#[error("frozen memory size error: {0} is not {1}")]
MemorySize(usize, usize)
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct LineError {
pub error: ICError,
pub line: u32,
@@ -76,6 +93,8 @@ impl Display for LineError {
impl StdError for LineError {}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ParseError {
pub line: usize,
pub start: usize,
@@ -128,6 +147,8 @@ impl ParseError {
}
#[derive(Debug, Error, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum ICError {
#[error("error compiling code: {0}")]
ParseError(#[from] ParseError),

View File

@@ -7,18 +7,24 @@ use std::{
};
use itertools::Itertools;
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
use time::format_description;
use crate::{
errors::{ICError, LineError},
grammar,
vm::instructions::{enums::InstructionOp, Instruction},
vm::instructions::{enums::InstructionOp, operands::Operand, Instruction},
};
pub mod instructions;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum ICState {
Start,
Running,
@@ -29,6 +35,19 @@ pub enum ICState {
Ended,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ICInfo {
pub instruction_pointer: u32,
pub registers: Vec<f64>,
pub aliases: BTreeMap<String, Operand>,
pub defines: BTreeMap<String, f64>,
pub labels: BTreeMap<String, u32>,
pub state: ICState,
pub yield_instruciton_count: u16,
}
impl Display for ICState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let out = match self {
@@ -52,6 +71,8 @@ impl Display for ICState {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct Program {
pub instructions: Vec<Instruction>,
pub errors: Vec<ICError>,

View File

@@ -13,8 +13,14 @@ use stationeers_data::{
};
use strum_macros::{AsRefStr, EnumIter};
use thiserror::Error;
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum CableConnectionType {
Power,
Data,
@@ -23,6 +29,8 @@ pub enum CableConnectionType {
}
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum Connection {
CableNetwork {
net: Option<ObjectID>,
@@ -337,6 +345,8 @@ impl Network for CableNetwork {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct FrozenCableNetwork {
pub id: ObjectID,
pub devices: Vec<u32>,

View File

@@ -23,6 +23,10 @@ use std::{
collections::{BTreeMap, HashSet},
rc::Rc,
};
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
use itertools::Itertools;
use serde_derive::{Deserialize, Serialize};
@@ -119,15 +123,15 @@ impl VM {
.and_then(|db| db.get(&hash).cloned())
}
pub fn add_devices_frozen(
pub fn add_objects_frozen(
self: &Rc<Self>,
frozen_devices: impl IntoIterator<Item = FrozenObject>,
frozen_objects: impl IntoIterator<Item = FrozenObject>,
) -> Result<Vec<ObjectID>, VMError> {
let mut transaction = VMTransaction::new(self);
let mut obj_ids = Vec::new();
for frozen in frozen_devices {
let obj_id = transaction.add_device_from_frozen(frozen)?;
for frozen in frozen_objects {
let obj_id = transaction.add_object_from_frozen(frozen)?;
obj_ids.push(obj_id)
}
@@ -171,13 +175,13 @@ impl VM {
Ok(obj_ids)
}
pub fn add_device_from_frozen(
pub fn add_object_from_frozen(
self: &Rc<Self>,
frozen: FrozenObject,
) -> Result<ObjectID, VMError> {
let mut transaction = VMTransaction::new(self);
let obj_id = transaction.add_device_from_frozen(frozen)?;
let obj_id = transaction.add_object_from_frozen(frozen)?;
transaction.finialize()?;
@@ -274,12 +278,12 @@ impl VM {
self.circuit_holders.borrow_mut().iter_mut().for_each(|id| {
if *id == old_id {
*id = new_id
*id = new_id;
}
});
self.program_holders.borrow_mut().iter_mut().for_each(|id| {
if *id == old_id {
*id = new_id
*id = new_id;
}
});
self.networks.borrow().iter().for_each(|(_net_id, net)| {
@@ -1005,7 +1009,7 @@ impl VM {
state.default_network_key,
);
for frozen in state.objects {
let _ = transaction.add_device_from_frozen(frozen)?;
let _ = transaction.add_object_from_frozen(frozen)?;
}
transaction.finialize()?;
@@ -1101,7 +1105,7 @@ impl VMTransaction {
}
}
pub fn add_device_from_frozen(&mut self, frozen: FrozenObject) -> Result<ObjectID, VMError> {
pub fn add_object_from_frozen(&mut self, frozen: FrozenObject) -> Result<ObjectID, VMError> {
for net_id in &frozen.connected_networks() {
if !self.networks.contains_key(net_id) {
return Err(VMError::InvalidNetwork(*net_id));
@@ -1134,14 +1138,14 @@ impl VMTransaction {
self.program_holders.push(obj_id);
}
if let Some(device) = obj.borrow_mut().as_mut_device() {
for conn in device.connection_list().iter() {
for conn in device.connection_list() {
if let Connection::CableNetwork {
net: Some(net_id),
typ,
role: ConnectionRole::None,
} = conn
{
if let Some(net) = self.networks.get_mut(net_id) {
if let Some(net) = self.networks.get_mut(&net_id) {
match typ {
CableConnectionType::Power => net.power_only.push(obj_id),
_ => net.devices.push(obj_id),
@@ -1290,6 +1294,8 @@ impl IdSpace {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct FrozenVM {
pub objects: Vec<FrozenObject>,
pub circuit_holders: Vec<ObjectID>,

View File

@@ -1,6 +1,10 @@
use serde_derive::{Deserialize, Serialize};
use strum::{Display, EnumIter, EnumProperty, EnumString, FromRepr};
use crate::vm::object::traits::Programmable;
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
#[derive(
Debug,
Display,
@@ -14,6 +18,8 @@ use crate::vm::object::traits::Programmable;
Deserialize
)]
#[derive(EnumIter, EnumString, EnumProperty, FromRepr)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf, serialize_all = "lowercase")]
#[serde(rename_all = "lowercase")]
pub enum InstructionOp {

View File

@@ -6,8 +6,14 @@ use stationeers_data::enums::script::{
LogicBatchMethod as BatchMode, LogicReagentMode as ReagentMode, LogicSlotType, LogicType,
};
use strum::EnumProperty;
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
#[derive(PartialEq, Eq, Debug, Clone, Copy, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum Device {
Db,
Numbered(u32),
@@ -15,23 +21,31 @@ pub enum Device {
}
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct RegisterSpec {
pub indirection: u32,
pub target: u32,
}
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct DeviceSpec {
pub device: Device,
pub connection: Option<usize>,
}
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct Identifier {
pub name: String,
}
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum Number {
Float(f64),
Binary(i64),
@@ -42,6 +56,8 @@ pub enum Number {
}
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum Operand {
RegisterSpec(RegisterSpec),
DeviceSpec(DeviceSpec),

View File

@@ -2,8 +2,14 @@ use serde_derive::{Deserialize, Serialize};
use thiserror::Error;
use stationeers_data::enums::script::{LogicSlotType, LogicType};
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
#[derive(Error, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum LogicError {
#[error("can't read LogicType {0}")]
CantRead(LogicType),
@@ -18,6 +24,8 @@ pub enum LogicError {
}
#[derive(Error, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum MemoryError {
#[error("stack underflow: {0} < range [0..{1})")]
StackUnderflow(i32, usize),

View File

@@ -1,15 +1,50 @@
use std::collections::BTreeMap;
use macro_rules_attribute::derive;
use stationeers_data::enums::basic::Class as SlotClass;
use stationeers_data::{
enums::{basic::Class as SlotClass, Species},
templates::SlotInfo,
};
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
use crate::vm::{
object::{
macros::ObjectInterface,
traits::{Human, HumanRef, HumanRefMut, Object, Storage, StorageRef, StorageRefMut},
Name, ObjectID, Slot,
traits::{
Human, HumanRef, HumanRefMut, Object, StatState, Storage, StorageRef, StorageRefMut,
Thermal,
},
Name, ObjectID, Slot, SlotOccupantInfo,
},
VM,
};
static MAX_NUTRITION: f32 = 50.0;
// static FULL_NUTRITION: f32 = 45.0;
static WARNING_NUTRITION: f32 = 15.0;
static CRITICAL_NUTRITION: f32 = 5.0;
static MAX_HYDRATION: f32 = 8.75;
static WARNING_HYDRATION: f32 = 2.0;
static CRITICAL_HYDRATION: f32 = 1.0;
static MAX_OXYGENATION: f32 = 0.024;
static MAX_FOOD_QUALITY: f32 = 1.0;
static MAX_MOOD: f32 = 1.0;
static WARNING_MOOD: f32 = 0.5;
static CRITICAL_MOOD: f32 = 0.0;
static MAX_HYGIENE: f32 = 1.25;
static WARNING_HYGIENE: f32 = 0.25;
static CRITICAL_HYGIENE: f32 = 0.0;
use serde_derive::{Deserialize, Serialize};
#[derive(ObjectInterface!)]
#[custom(implements(Object {
Human, Storage
@@ -24,12 +59,15 @@ pub struct HumanPlayer {
#[custom(object_vm_ref)]
pub vm: std::rc::Rc<VM>,
pub species: Species,
pub damage: f32,
pub hydration: f32,
pub nutrition: f32,
pub oxygenation: f32,
pub food_quality: f32,
pub mood: f32,
pub hygine: f32,
pub hygiene: f32,
left_hand_slot: Slot,
right_hand_slot: Slot,
@@ -41,6 +79,18 @@ pub struct HumanPlayer {
toolbelt_slot: Slot,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct EntityInfo {
pub hydration: f32,
pub nutrition: f32,
pub oxygenation: f32,
pub food_quality: f32,
pub mood: f32,
pub hygiene: f32,
}
impl HumanPlayer {
pub fn new(id: ObjectID, vm: std::rc::Rc<VM>) -> Self {
HumanPlayer {
@@ -48,22 +98,103 @@ impl HumanPlayer {
prefab: Name::new(""),
name: Name::new(""),
vm,
species: Species::Human,
damage: 0.0,
hydration: 5.0,
nutrition: 5.0,
oxygenation: 1.0,
nutrition: 50.0,
oxygenation: 0.024,
food_quality: 0.75,
mood: 1.0,
hygine: 1.0,
hygiene: 1.0,
left_hand_slot: Slot::new(id, 0, "LeftHand".to_string(), SlotClass::None),
right_hand_slot: Slot::new(id, 1, "RightHand".to_string(), SlotClass::None),
suit_slot: Slot::new(id, 2, "Helmet".to_string(), SlotClass::Suit),
helmet_slot: Slot::new(id, 3, "LeftHand".to_string(), SlotClass::Helmet),
glasses_slot: Slot::new(id, 4, "LeftHand".to_string(), SlotClass::Glasses),
backpack_slot: Slot::new(id, 5, "LeftHand".to_string(), SlotClass::Back),
uniform_slot: Slot::new(id, 6, "LeftHand".to_string(), SlotClass::Uniform),
toolbelt_slot: Slot::new(id, 7, "LeftHand".to_string(), SlotClass::Belt),
suit_slot: Slot::new(id, 2, "Suit".to_string(), SlotClass::Suit),
helmet_slot: Slot::new(id, 3, "Helmet".to_string(), SlotClass::Helmet),
glasses_slot: Slot::new(id, 4, "Glasses".to_string(), SlotClass::Glasses),
backpack_slot: Slot::new(id, 5, "Back".to_string(), SlotClass::Back),
uniform_slot: Slot::new(id, 6, "Uniform".to_string(), SlotClass::Uniform),
toolbelt_slot: Slot::new(id, 7, "Belt".to_string(), SlotClass::Belt),
}
}
pub fn with_species(id: ObjectID, vm: std::rc::Rc<VM>, species: Species) -> Self {
let uniform_slot = if species == Species::Robot {
Slot::new(id, 6, "Battery".to_string(), SlotClass::Battery)
} else {
Slot::new(id, 6, "Uniform".to_string(), SlotClass::Uniform)
};
HumanPlayer {
id,
prefab: Name::new(""),
name: Name::new(""),
vm,
species,
damage: 0.0,
hydration: 5.0,
nutrition: 50.0,
oxygenation: 0.024,
food_quality: 0.75,
mood: 1.0,
hygiene: 1.0,
left_hand_slot: Slot::new(id, 0, "LeftHand".to_string(), SlotClass::None),
right_hand_slot: Slot::new(id, 1, "RightHand".to_string(), SlotClass::None),
suit_slot: Slot::new(id, 2, "Suit".to_string(), SlotClass::Suit),
helmet_slot: Slot::new(id, 3, "Helmet".to_string(), SlotClass::Helmet),
glasses_slot: Slot::new(id, 4, "Glasses".to_string(), SlotClass::Glasses),
backpack_slot: Slot::new(id, 5, "Back".to_string(), SlotClass::Back),
uniform_slot,
toolbelt_slot: Slot::new(id, 7, "Belt".to_string(), SlotClass::Belt),
}
}
pub fn update_entity_info(&mut self, info: &EntityInfo) {
self.hydration = info.hydration;
self.nutrition = info.nutrition;
self.oxygenation = info.oxygenation;
self.food_quality = info.food_quality;
self.mood = info.mood;
self.hygiene = info.hygiene;
}
pub fn update_slots_from_info(&mut self, info: &BTreeMap<u32, SlotOccupantInfo>) {
for (index, slot_info) in info {
match index {
0 => {
self.left_hand_slot.occupant.replace(slot_info.clone());
}
1 => {
self.right_hand_slot.occupant.replace(slot_info.clone());
}
2 => {
self.helmet_slot.occupant.replace(slot_info.clone());
}
3 => {
self.suit_slot.occupant.replace(slot_info.clone());
}
4 => {
self.backpack_slot.occupant.replace(slot_info.clone());
}
5 => {
self.uniform_slot.occupant.replace(slot_info.clone());
}
6 => {
self.toolbelt_slot.occupant.replace(slot_info.clone());
}
7 => {
self.glasses_slot.occupant.replace(slot_info.clone());
}
_ => {}
}
}
}
}
impl Thermal for HumanPlayer {
fn get_radiation_factor(&self) -> f32 {
0.1
}
fn get_convection_factor(&self) -> f32 {
0.1
}
}
impl Storage for HumanPlayer {
@@ -71,12 +202,12 @@ impl Storage for HumanPlayer {
vec![
&self.left_hand_slot,
&self.right_hand_slot,
&self.suit_slot,
&self.helmet_slot,
&self.glasses_slot,
&self.suit_slot,
&self.backpack_slot,
&self.uniform_slot,
&self.toolbelt_slot,
&self.glasses_slot,
]
}
@@ -84,12 +215,12 @@ impl Storage for HumanPlayer {
vec![
&mut self.left_hand_slot,
&mut self.right_hand_slot,
&mut self.suit_slot,
&mut self.helmet_slot,
&mut self.glasses_slot,
&mut self.suit_slot,
&mut self.backpack_slot,
&mut self.uniform_slot,
&mut self.toolbelt_slot,
&mut self.glasses_slot,
]
}
@@ -101,12 +232,12 @@ impl Storage for HumanPlayer {
match index {
0 => Some(&self.left_hand_slot),
1 => Some(&self.right_hand_slot),
2 => Some(&self.suit_slot),
3 => Some(&self.helmet_slot),
4 => Some(&self.glasses_slot),
5 => Some(&self.backpack_slot),
6 => Some(&self.uniform_slot),
7 => Some(&self.toolbelt_slot),
2 => Some(&self.helmet_slot),
3 => Some(&self.suit_slot),
4 => Some(&self.backpack_slot),
5 => Some(&self.uniform_slot),
6 => Some(&self.toolbelt_slot),
7 => Some(&self.glasses_slot),
_ => None,
}
}
@@ -114,59 +245,111 @@ impl Storage for HumanPlayer {
match index {
0 => Some(&mut self.left_hand_slot),
1 => Some(&mut self.right_hand_slot),
2 => Some(&mut self.suit_slot),
3 => Some(&mut self.helmet_slot),
4 => Some(&mut self.glasses_slot),
5 => Some(&mut self.backpack_slot),
6 => Some(&mut self.uniform_slot),
7 => Some(&mut self.toolbelt_slot),
2 => Some(&mut self.helmet_slot),
3 => Some(&mut self.suit_slot),
4 => Some(&mut self.backpack_slot),
5 => Some(&mut self.uniform_slot),
6 => Some(&mut self.toolbelt_slot),
7 => Some(&mut self.glasses_slot),
_ => None,
}
}
}
impl Human for HumanPlayer {
fn get_species(&self) -> Species {
self.species
}
fn get_damage(&self) -> f32 {
self.damage
}
fn set_damage(&mut self, damage: f32) {
self.damage = damage;
}
fn get_hydration(&self) -> f32 {
self.hydration
}
fn set_hydration(&mut self, hydration: f32) {
self.hydration = hydration;
self.hydration = hydration.clamp(0.0, MAX_HYDRATION);
}
fn hydration_state(&self) -> super::traits::StatState {
if self.hydration < CRITICAL_HYDRATION {
return StatState::Critical;
}
if self.hydration < WARNING_HYDRATION {
return StatState::Warning;
}
StatState::Normal
}
fn get_nutrition(&self) -> f32 {
self.nutrition
}
fn set_nutrition(&mut self, nutrition: f32) {
self.nutrition = nutrition;
self.nutrition = nutrition.clamp(0.0, MAX_NUTRITION);
}
fn nutrition_state(&self) -> StatState {
if self.nutrition < CRITICAL_NUTRITION {
return StatState::Critical;
}
if self.nutrition < WARNING_NUTRITION {
return StatState::Warning;
}
StatState::Normal
}
fn get_oxygenation(&self) -> f32 {
self.oxygenation
}
fn set_oxygenation(&mut self, oxygenation: f32) {
self.oxygenation = oxygenation;
self.oxygenation = oxygenation.clamp(0.0, MAX_OXYGENATION);
}
fn get_food_quality(&self) -> f32 {
self.food_quality
}
fn set_food_quality(&mut self, quality: f32) {
self.food_quality = quality;
self.food_quality = quality.clamp(0.0, MAX_FOOD_QUALITY);
}
fn get_mood(&self) -> f32 {
self.mood
}
fn set_mood(&mut self, mood: f32) {
self.mood = mood;
self.mood = mood.clamp(0.0, MAX_MOOD);
}
fn get_hygine(&self) -> f32 {
self.hygine
fn mood_state(&self) -> StatState {
if self.mood < CRITICAL_MOOD {
return StatState::Critical;
}
if self.mood < WARNING_MOOD {
return StatState::Warning;
}
StatState::Normal
}
fn set_hygine(&mut self, hygine: f32) {
self.hygine = hygine;
fn get_hygiene(&self) -> f32 {
self.hygiene
}
fn set_hygiene(&mut self, hygiene: f32) {
self.hygiene = hygiene.clamp(0.0, MAX_HYGIENE);
}
fn hygine_state(&self) -> StatState {
if self.hygiene < CRITICAL_HYGIENE {
return StatState::Critical;
}
if self.hygiene < WARNING_HYGIENE {
return StatState::Warning;
}
StatState::Normal
}
fn is_artificial(&self) -> bool {
false
self.species == Species::Robot
}
fn robot_battery(&self) -> Option<super::VMObject> {
None
if self.species != Species::Robot {
return None;
}
self.uniform_slot()
.occupant
.as_ref()
.and_then(|info| self.vm.get_object(info.id))
}
fn suit_slot(&self) -> &Slot {
&self.suit_slot

View File

@@ -1,34 +1,152 @@
use std::rc::Rc;
use stationeers_data::{enums::prefabs::StationpediaPrefab, templates::ObjectTemplate};
use crate::vm::object::{
templates::{FrozenObject, ObjectInfo, Prefab},
VMObject,
use stationeers_data::{
enums::prefabs::StationpediaPrefab,
templates::{ObjectTemplate, PrefabInfo},
};
use crate::vm::VM;
use crate::{
errors::TemplateError,
vm::object::{
templates::{FrozenObject, ObjectInfo, Prefab},
Name, VMObject,
},
};
use crate::{
interpreter::Program,
vm::{object::LogicField, VM},
};
use strum::EnumProperty;
use super::ObjectID;
pub mod structs;
#[allow(unused)]
pub fn object_from_frozen(obj: &ObjectInfo, id: ObjectID, vm: &Rc<VM>) -> Option<VMObject> {
pub fn object_from_frozen(
obj: &ObjectInfo,
id: ObjectID,
vm: &Rc<VM>,
) -> Result<Option<VMObject>, TemplateError> {
#[allow(clippy::cast_possible_wrap)]
let hash = match &obj.prefab {
Some(Prefab::Hash(hash)) => *hash,
Some(Prefab::Name(name)) => const_crc32::crc32(name.as_bytes()) as i32,
None => return None,
None => return Ok(None),
};
let prefab = StationpediaPrefab::from_repr(hash);
#[allow(clippy::match_single_binding)]
match prefab {
// Some(StationpediaPrefab::ItemIntegratedCircuit10) => {
// Some(VMObject::new(structs::ItemIntegratedCircuit10))
// }
Some(prefab @ StationpediaPrefab::ItemIntegratedCircuit10) => {
let template = vm
.get_template(Prefab::Hash(hash))
.ok_or(TemplateError::NoTemplateForPrefab(Prefab::Hash(hash)))?;
let ObjectTemplate::ItemLogicMemory(template) = template else {
return Err(TemplateError::IncorrectTemplate(
"ItemIntegratedCircuit10".to_string(),
Prefab::Name("ItemIntegratedCircuit10".to_string()),
));
};
Ok(Some(VMObject::new(structs::ItemIntegratedCircuit10 {
id,
vm: vm.clone(),
name: Name::new(
&(obj
.name
.clone()
.unwrap_or_else(|| prefab.get_str("name").unwrap().to_string())),
),
prefab: Name::from_prefab_name(&prefab.to_string()),
fields: template
.logic
.logic_types
.iter()
.map(|(key, access)| {
(
*key,
LogicField {
field_type: *access,
value: obj
.logic_values
.as_ref()
.and_then(|values| values.get(key))
.copied()
.unwrap_or(0.0),
},
)
})
.collect(),
memory: obj
.memory
.clone()
.map(TryInto::try_into)
.transpose()
.map_err(|vec: Vec<f64>| TemplateError::MemorySize(vec.len(), 512))?
.unwrap_or_else(|| [0.0f64; 512]),
parent_slot: None,
registers: obj
.circuit
.as_ref()
.map(|circuit| circuit.registers.clone().try_into())
.transpose()
.map_err(|vec: Vec<f64>| TemplateError::MemorySize(vec.len(), 18))?
.unwrap_or_else(|| [0.0f64; 18]),
ip: obj
.circuit
.as_ref()
.map(|circuit| circuit.instruction_pointer as usize)
.unwrap_or(0),
next_ip: 0,
ic: obj
.circuit
.as_ref()
.map(|circuit| circuit.yield_instruciton_count)
.unwrap_or(0),
aliases: obj
.circuit
.as_ref()
.map(|circuit| circuit.aliases.clone())
.unwrap_or_default(),
defines: obj
.circuit
.as_ref()
.map(|circuit| circuit.defines.clone())
.unwrap_or_default(),
pins: obj
.device_pins
.as_ref()
.map(|pins| {
(0..6)
.map(|index| pins.get(&index).copied())
.collect::<Vec<_>>()
.try_into()
.unwrap() // fixed sized iterator into array should not panic
})
.unwrap_or_default(),
state: obj
.circuit
.as_ref()
.map(|circuit| circuit.state.clone())
.unwrap_or(crate::interpreter::ICState::Start),
code: obj.source_code.clone().unwrap_or_default(),
damage: obj.damage.unwrap_or(0.0),
program: obj
.source_code
.as_ref()
.map(|code| {
if code.is_empty() {
Program::default()
} else {
Program::from_code_with_invalid(code)
}
})
.unwrap_or_default(),
})))
}
// Some(StationpediaPrefab::StructureCircuitHousing) => Some()
// Some(StationpediaPrefab::StructureRocketCircuitHousing) => Some()
_ => None,
_ => Ok(None),
}
}

View File

@@ -237,8 +237,8 @@ impl IntegratedCircuit for ItemIntegratedCircuit10 {
self.get_parent_slot()
.and_then(|parent_slot| self.get_vm().get_object(parent_slot.parent))
}
fn get_instruction_pointer(&self) -> f64 {
self.ip as f64
fn get_instruction_pointer(&self) -> u32 {
self.ip as u32
}
fn set_next_instruction(&mut self, next_instruction: f64) {
self.next_ip = next_instruction as usize;
@@ -285,6 +285,12 @@ impl IntegratedCircuit for ItemIntegratedCircuit10 {
self.registers[t as usize] = val;
Ok(old_val)
}
fn get_registers(&self) -> &[f64] {
&self.registers
}
fn get_registers_mut(&mut self) -> &mut [f64] {
&mut self.registers
}
fn set_return_address(&mut self, addr: f64) {
self.registers[RETURN_ADDRESS_INDEX] = addr;
}
@@ -364,6 +370,9 @@ impl IntegratedCircuit for ItemIntegratedCircuit10 {
fn set_state(&mut self, state: crate::interpreter::ICState) {
self.state = state;
}
fn get_instructions_since_yield(&self) -> u16 {
self.ic
}
}
impl IC10Marker for ItemIntegratedCircuit10 {}

View File

@@ -2,6 +2,7 @@ use std::{collections::BTreeMap, rc::Rc, str::FromStr};
use crate::{
errors::TemplateError,
interpreter::ICInfo,
network::Connection,
vm::{
object::{
@@ -16,6 +17,7 @@ use crate::{
GenericLogicableDeviceMemoryReadWriteable, GenericLogicableDeviceMemoryReadable,
GenericStorage,
},
humans::{EntityInfo, HumanPlayer},
traits::*,
LogicField, Name, Slot, SlotOccupantInfo,
},
@@ -33,10 +35,16 @@ use stationeers_data::{
templates::*,
};
use strum::{EnumProperty, IntoEnumIterator};
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
use super::{stationpedia, MemoryAccess, ObjectID, VMObject};
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum Prefab {
Hash(i32),
Name(String),
@@ -59,7 +67,9 @@ impl std::fmt::Display for Prefab {
}
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ObjectInfo {
pub name: Option<String>,
pub id: Option<ObjectID>,
@@ -71,6 +81,9 @@ pub struct ObjectInfo {
pub reagents: Option<BTreeMap<i32, f64>>,
pub memory: Option<Vec<f64>>,
pub logic_values: Option<BTreeMap<LogicType, f64>>,
pub entity: Option<EntityInfo>,
pub source_code: Option<String>,
pub circuit: Option<ICInfo>,
}
impl From<&VMObject> for ObjectInfo {
@@ -87,6 +100,9 @@ impl From<&VMObject> for ObjectInfo {
reagents: None,
memory: None,
logic_values: None,
entity: None,
source_code: None,
circuit: None,
}
}
}
@@ -108,6 +124,15 @@ impl ObjectInfo {
if let Some(item) = interfaces.item {
self.update_from_item(item);
}
if let Some(human) = interfaces.human {
self.update_from_human(human);
}
if let Some(source) = interfaces.source_code {
self.update_from_source_code(source);
}
if let Some(circuit) = interfaces.integrated_circuit {
self.update_from_circuit(circuit);
}
self
}
@@ -120,9 +145,10 @@ impl ObjectInfo {
slots
.into_iter()
.enumerate()
.filter_map(|(index, slot)| match slot.occupant.as_ref() {
Some(occupant) => Some((index as u32, occupant.clone())),
None => None,
.filter_map(|(index, slot)| {
slot.occupant
.as_ref()
.map(|occupant| (index as u32, occupant.clone()))
})
.collect(),
);
@@ -142,16 +168,13 @@ impl ObjectInfo {
pub fn update_from_device(&mut self, device: DeviceRef<'_>) -> &mut Self {
let pins = device.device_pins();
if pins.is_some_and(|pins| pins.is_empty()) {
if pins.is_some_and(<[Option<u32>]>::is_empty) {
self.device_pins = None;
} else {
self.device_pins = pins.map(|pins| {
pins.into_iter()
pins.iter()
.enumerate()
.filter_map(|(index, pin)| match pin {
Some(pin) => Some((index as u32, *pin)),
None => None,
})
.filter_map(|(index, pin)| pin.as_ref().map(|pin| (index as u32, *pin)))
.collect()
});
}
@@ -201,11 +224,65 @@ impl ObjectInfo {
);
self
}
pub fn update_from_human(&mut self, human: HumanRef<'_>) -> &mut Self {
let damage = human.get_damage();
if damage == 0.0 {
self.damage = None;
} else {
self.damage.replace(damage);
}
self.entity.replace(EntityInfo {
hydration: human.get_hydration(),
nutrition: human.get_nutrition(),
oxygenation: human.get_oxygenation(),
food_quality: human.get_food_quality(),
mood: human.get_mood(),
hygiene: human.get_hygiene(),
});
self
}
pub fn update_from_source_code(&mut self, source: SourceCodeRef<'_>) -> &mut Self {
let code = source.get_source_code();
if !code.is_empty() {
self.source_code.replace(code);
}
self
}
pub fn update_from_circuit(&mut self, circuit: IntegratedCircuitRef<'_>) -> &mut Self {
self.circuit.replace(ICInfo {
instruction_pointer: circuit.get_instruction_pointer(),
registers: circuit.get_registers().to_vec(),
aliases: circuit
.get_aliases()
.iter()
.map(|(key, val)| (key.clone(), val.clone()))
.collect(),
defines: circuit
.get_defines()
.iter()
.map(|(key, val)| (key.clone(), *val))
.collect(),
labels: circuit
.get_labels()
.iter()
.map(|(key, val)| (key.clone(), *val))
.collect(),
state: circuit.get_state(),
yield_instruciton_count: circuit.get_instructions_since_yield(),
});
self
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct FrozenObject {
pub obj_info: ObjectInfo,
pub database_template: bool,
pub template: Option<ObjectTemplate>,
}
@@ -213,6 +290,7 @@ impl FrozenObject {
pub fn new(obj_info: ObjectInfo) -> Self {
FrozenObject {
obj_info,
database_template: false,
template: None,
}
}
@@ -220,6 +298,7 @@ impl FrozenObject {
pub fn with_template(obj_info: ObjectInfo, template: ObjectTemplate) -> Self {
FrozenObject {
obj_info,
database_template: false,
template: Some(template),
}
}
@@ -239,7 +318,7 @@ impl FrozenObject {
},
|template| Ok(template.clone()),
)?;
if let Some(obj) = stationpedia::object_from_frozen(&self.obj_info, id, vm) {
if let Some(obj) = stationpedia::object_from_frozen(&self.obj_info, id, vm)? {
Ok(obj)
} else {
self.build_generic(id, &template, vm.clone())
@@ -251,7 +330,7 @@ impl FrozenObject {
.connections
.as_ref()
.map(|connections| connections.values().copied().collect())
.unwrap_or_else(Vec::new)
.unwrap_or_default()
}
pub fn contained_object_ids(&self) -> Vec<ObjectID> {
@@ -259,7 +338,7 @@ impl FrozenObject {
.slots
.as_ref()
.map(|slots| slots.values().map(|slot| slot.id).collect())
.unwrap_or_else(Vec::new)
.unwrap_or_default()
}
pub fn contained_object_slots(&self) -> Vec<(u32, ObjectID)> {
@@ -272,17 +351,17 @@ impl FrozenObject {
.map(|(index, slot)| (*index, slot.id))
.collect()
})
.unwrap_or_else(Vec::new)
.unwrap_or_default()
}
fn build_slots(
&self,
id: ObjectID,
slots_info: &Vec<SlotInfo>,
slots_info: &[SlotInfo],
logic_info: Option<&LogicInfo>,
) -> Vec<Slot> {
slots_info
.into_iter()
.iter()
.enumerate()
.map(|(index, info)| Slot {
parent: id,
@@ -402,7 +481,7 @@ impl FrozenObject {
Structure(s) => Ok(VMObject::new(Generic {
id,
prefab: Name::from_prefab_name(&s.prefab.prefab_name),
name: Name::new(&s.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(s.prefab.name.clone())),
vm,
internal_atmo_info: s.internal_atmo_info.clone(),
thermal_info: s.thermal_info.clone(),
@@ -411,7 +490,7 @@ impl FrozenObject {
StructureSlots(s) => Ok(VMObject::new(GenericStorage {
id,
prefab: Name::from_prefab_name(&s.prefab.prefab_name),
name: Name::new(&s.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(s.prefab.name.clone())),
vm,
internal_atmo_info: s.internal_atmo_info.clone(),
thermal_info: s.thermal_info.clone(),
@@ -421,7 +500,7 @@ impl FrozenObject {
StructureLogic(s) => Ok(VMObject::new(GenericLogicable {
id,
prefab: Name::from_prefab_name(&s.prefab.prefab_name),
name: Name::new(&s.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(s.prefab.name.clone())),
vm,
internal_atmo_info: s.internal_atmo_info.clone(),
thermal_info: s.thermal_info.clone(),
@@ -433,7 +512,7 @@ impl FrozenObject {
StructureLogicDevice(s) => Ok(VMObject::new(GenericLogicableDevice {
id,
prefab: Name::from_prefab_name(&s.prefab.prefab_name),
name: Name::new(&s.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(s.prefab.name.clone())),
vm,
internal_atmo_info: s.internal_atmo_info.clone(),
thermal_info: s.thermal_info.clone(),
@@ -449,7 +528,7 @@ impl FrozenObject {
StructureLogicDeviceConsumer(s) => Ok(VMObject::new(GenericLogicableDeviceConsumer {
id,
prefab: Name::from_prefab_name(&s.prefab.prefab_name),
name: Name::new(&s.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(s.prefab.name.clone())),
vm,
internal_atmo_info: s.internal_atmo_info.clone(),
thermal_info: s.thermal_info.clone(),
@@ -466,7 +545,7 @@ impl FrozenObject {
StructureCircuitHolder(s) => Ok(VMObject::new(GenericCircuitHolder {
id,
prefab: Name::from_prefab_name(&s.prefab.prefab_name),
name: Name::new(&s.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(s.prefab.name.clone())),
vm,
internal_atmo_info: s.internal_atmo_info.clone(),
thermal_info: s.thermal_info.clone(),
@@ -485,7 +564,7 @@ impl FrozenObject {
Ok(VMObject::new(GenericLogicableDeviceMemoryReadable {
id,
prefab: Name::from_prefab_name(&s.prefab.prefab_name),
name: Name::new(&s.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(s.prefab.name.clone())),
vm,
internal_atmo_info: s.internal_atmo_info.clone(),
thermal_info: s.thermal_info.clone(),
@@ -504,7 +583,7 @@ impl FrozenObject {
Ok(VMObject::new(GenericLogicableDeviceMemoryReadWriteable {
id,
prefab: Name::from_prefab_name(&s.prefab.prefab_name),
name: Name::new(&s.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(s.prefab.name.clone())),
vm,
internal_atmo_info: s.internal_atmo_info.clone(),
thermal_info: s.thermal_info.clone(),
@@ -526,7 +605,9 @@ impl FrozenObject {
GenericLogicableDeviceConsumerMemoryReadable {
id,
prefab: Name::from_prefab_name(&s.prefab.prefab_name),
name: Name::new(&s.prefab.name),
name: Name::new(
&self.obj_info.name.clone().unwrap_or(s.prefab.name.clone()),
),
vm,
internal_atmo_info: s.internal_atmo_info.clone(),
thermal_info: s.thermal_info.clone(),
@@ -548,7 +629,7 @@ impl FrozenObject {
GenericLogicableDeviceConsumerMemoryReadWriteable {
id,
prefab: Name::from_prefab_name(&s.prefab.prefab_name),
name: Name::new(&s.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(s.prefab.name.clone())),
vm,
internal_atmo_info: s.internal_atmo_info.clone(),
thermal_info: s.thermal_info.clone(),
@@ -568,7 +649,7 @@ impl FrozenObject {
Item(i) => Ok(VMObject::new(GenericItem {
id,
prefab: Name::from_prefab_name(&i.prefab.prefab_name),
name: Name::new(&i.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(i.prefab.name.clone())),
vm,
internal_atmo_info: i.internal_atmo_info.clone(),
thermal_info: i.thermal_info.clone(),
@@ -579,7 +660,7 @@ impl FrozenObject {
ItemSlots(i) => Ok(VMObject::new(GenericItemStorage {
id,
prefab: Name::from_prefab_name(&i.prefab.prefab_name),
name: Name::new(&i.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(i.prefab.name.clone())),
vm,
internal_atmo_info: i.internal_atmo_info.clone(),
thermal_info: i.thermal_info.clone(),
@@ -591,7 +672,7 @@ impl FrozenObject {
ItemConsumer(i) => Ok(VMObject::new(GenericItemConsumer {
id,
prefab: Name::from_prefab_name(&i.prefab.prefab_name),
name: Name::new(&i.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(i.prefab.name.clone())),
vm,
internal_atmo_info: i.internal_atmo_info.clone(),
thermal_info: i.thermal_info.clone(),
@@ -604,7 +685,7 @@ impl FrozenObject {
ItemLogic(i) => Ok(VMObject::new(GenericItemLogicable {
id,
prefab: Name::from_prefab_name(&i.prefab.prefab_name),
name: Name::new(&i.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(i.prefab.name.clone())),
vm,
internal_atmo_info: i.internal_atmo_info.clone(),
thermal_info: i.thermal_info.clone(),
@@ -619,7 +700,7 @@ impl FrozenObject {
Ok(VMObject::new(GenericItemLogicableMemoryReadable {
id,
prefab: Name::from_prefab_name(&i.prefab.prefab_name),
name: Name::new(&i.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(i.prefab.name.clone())),
vm,
internal_atmo_info: i.internal_atmo_info.clone(),
thermal_info: i.thermal_info.clone(),
@@ -635,7 +716,7 @@ impl FrozenObject {
ItemLogicMemory(i) => Ok(VMObject::new(GenericItemLogicableMemoryReadWriteable {
id,
prefab: Name::from_prefab_name(&i.prefab.prefab_name),
name: Name::new(&i.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(i.prefab.name.clone())),
vm,
internal_atmo_info: i.internal_atmo_info.clone(),
thermal_info: i.thermal_info.clone(),
@@ -650,7 +731,7 @@ impl FrozenObject {
ItemCircuitHolder(i) => Ok(VMObject::new(GenericItemCircuitHolder {
id,
prefab: Name::from_prefab_name(&i.prefab.prefab_name),
name: Name::new(&i.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(i.prefab.name.clone())),
vm,
internal_atmo_info: i.internal_atmo_info.clone(),
thermal_info: i.thermal_info.clone(),
@@ -664,7 +745,7 @@ impl FrozenObject {
ItemSuit(i) => Ok(VMObject::new(GenericItemSuit {
id,
prefab: Name::from_prefab_name(&i.prefab.prefab_name),
name: Name::new(&i.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(i.prefab.name.clone())),
vm,
internal_atmo_info: i.internal_atmo_info.clone(),
thermal_info: i.thermal_info.clone(),
@@ -677,7 +758,7 @@ impl FrozenObject {
ItemSuitLogic(i) => Ok(VMObject::new(GenericItemSuitLogic {
id,
prefab: Name::from_prefab_name(&i.prefab.prefab_name),
name: Name::new(&i.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(i.prefab.name.clone())),
vm,
internal_atmo_info: i.internal_atmo_info.clone(),
thermal_info: i.thermal_info.clone(),
@@ -692,7 +773,7 @@ impl FrozenObject {
ItemSuitCircuitHolder(i) => Ok(VMObject::new(GenericItemSuitCircuitHolder {
id,
prefab: Name::from_prefab_name(&i.prefab.prefab_name),
name: Name::new(&i.prefab.name),
name: Name::new(&self.obj_info.name.clone().unwrap_or(i.prefab.name.clone())),
vm,
internal_atmo_info: i.internal_atmo_info.clone(),
thermal_info: i.thermal_info.clone(),
@@ -705,6 +786,19 @@ impl FrozenObject {
modes: i.logic.modes.clone(),
memory: self.build_memory(&i.memory),
})),
Human(h) => {
let mut human = HumanPlayer::with_species(id, vm, h.species);
if let Some(info) = &self.obj_info.entity {
human.update_entity_info(info);
}
if let Some(slot_info) = &self.obj_info.slots {
human.update_slots_from_info(slot_info);
}
if let Some(damage) = &self.obj_info.damage {
human.damage = *damage;
}
Ok(VMObject::new(human))
}
}
}
@@ -714,15 +808,48 @@ impl FrozenObject {
let mut obj_info: ObjectInfo = obj.into();
obj_info.update_from_interfaces(&interfaces);
// if the template is known, omit it. else build it from interfaces
let mut database_template = false;
let template = vm
.get_template(Prefab::Hash(obj_ref.get_prefab().hash))
.map_or_else(
|| Some(try_template_from_interfaces(&interfaces, obj)),
|_| None,
|template| {
database_template = true;
Some(Ok(template))
},
)
.transpose()?;
Ok(FrozenObject { obj_info, template })
Ok(FrozenObject {
obj_info,
template,
database_template,
})
}
pub fn freeze_object_sparse(obj: &VMObject, vm: &Rc<VM>) -> Result<Self, TemplateError> {
let obj_ref = obj.borrow();
let interfaces = ObjectInterfaces::from_object(&*obj_ref);
let mut obj_info: ObjectInfo = obj.into();
obj_info.update_from_interfaces(&interfaces);
// if the template is known, omit it. else build it from interfaces
let mut database_template = false;
let template = vm
.get_template(Prefab::Hash(obj_ref.get_prefab().hash))
.map_or_else(
|| Some(try_template_from_interfaces(&interfaces, obj)),
|_| {
database_template = true;
None
},
)
.transpose()?;
Ok(FrozenObject {
obj_info,
template,
database_template,
})
}
}
@@ -804,7 +931,7 @@ fn try_template_from_interfaces(
memory_readable: None,
memory_writable: None,
logicable: Some(logic),
source_code: None,
source_code: _sc,
circuit_holder: _ch,
item: None,
integrated_circuit: None,
@@ -837,7 +964,7 @@ fn try_template_from_interfaces(
memory_readable: None,
memory_writable: None,
logicable: Some(logic),
source_code: None,
source_code: _sc,
circuit_holder: _ch,
item: None,
integrated_circuit: None,
@@ -873,7 +1000,7 @@ fn try_template_from_interfaces(
memory_readable: Some(mem_r),
memory_writable: _mem_w,
logicable: Some(logic),
source_code: None,
source_code: _sc,
circuit_holder: _ch,
item: None,
integrated_circuit: None,
@@ -975,7 +1102,7 @@ fn try_template_from_interfaces(
memory_readable: None,
memory_writable: None,
logicable: Some(logic),
source_code: None,
source_code: _sc,
circuit_holder: _ch,
item: Some(item),
integrated_circuit: None,
@@ -1008,10 +1135,10 @@ fn try_template_from_interfaces(
memory_readable: Some(mem_r),
memory_writable: _mem_w,
logicable: Some(logic),
source_code: None,
source_code: _sc,
circuit_holder: _ch,
item: Some(item),
integrated_circuit: None,
integrated_circuit: _ic,
programmable: None,
instructable: _inst,
logic_stack: _logic_stack,
@@ -1036,6 +1163,41 @@ fn try_template_from_interfaces(
logic: logic.into(),
memory: mem_r.into(),
})),
ObjectInterfaces {
structure: None,
storage: Some(storage),
memory_readable: None,
memory_writable: None,
logicable: None,
source_code: None,
circuit_holder: None,
item: None,
integrated_circuit: None,
programmable: None,
instructable: None,
logic_stack: None,
device: None,
wireless_transmit: None,
wireless_receive: None,
network: None,
plant: None,
suit: None,
chargeable: None,
reagent_interface: None,
fabricator: None,
internal_atmosphere: None,
thermal: Some(_),
human: Some(human),
} => Ok(ObjectTemplate::Human(HumanTemplate {
prefab: PrefabInfo {
prefab_name: "Character".to_string(),
prefab_hash: 294335127,
desc: "Charater".to_string(),
name: "Charater".to_string(),
},
species: human.get_species(),
slots: storage.into(),
})),
_ => Err(TemplateError::NonConformingObject(obj.get_id())),
}
}

View File

@@ -16,14 +16,52 @@ use crate::{
use stationeers_data::enums::{
basic::{Class as SlotClass, GasType, SortingClass},
script::{LogicSlotType, LogicType},
Species,
};
use std::{collections::BTreeMap, fmt::Debug};
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
use strum::{AsRefStr, Display, EnumIter, EnumProperty, EnumString, FromRepr};
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ParentSlotInfo {
pub parent: ObjectID,
pub slot: usize,
}
#[derive(
Default,
Debug,
Display,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
EnumString,
AsRefStr,
EnumProperty,
EnumIter,
FromRepr,
Serialize,
Deserialize,
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum StatState {
#[default]
Normal,
Warning,
Critical,
}
tag_object_traits! {
#![object_trait(Object: Debug)]
@@ -155,18 +193,20 @@ tag_object_traits! {
pub trait IntegratedCircuit: Logicable + MemoryWritable + SourceCode + Item {
fn get_circuit_holder(&self) -> Option<VMObject>;
fn get_instruction_pointer(&self) -> f64;
fn get_instruction_pointer(&self) -> u32;
fn set_next_instruction(&mut self, next_instruction: f64);
fn set_next_instruction_relative(&mut self, offset: f64) {
self.set_next_instruction(self.get_instruction_pointer() + offset);
self.set_next_instruction(self.get_instruction_pointer() as f64 + offset);
}
fn reset(&mut self);
fn get_real_target(&self, indirection: u32, target: u32) -> Result<f64, ICError>;
fn get_register(&self, indirection: u32, target: u32) -> Result<f64, ICError>;
fn get_registers(&self) -> &[f64];
fn get_registers_mut(&mut self) -> &mut [f64];
fn set_register(&mut self, indirection: u32, target: u32, val: f64) -> Result<f64, ICError>;
fn set_return_address(&mut self, addr: f64);
fn al(&mut self) {
self.set_return_address(self.get_instruction_pointer() + 1.0);
self.set_return_address(self.get_instruction_pointer() as f64 + 1.0);
}
fn push_stack(&mut self, val: f64) -> Result<f64, ICError>;
fn pop_stack(&mut self) -> Result<f64, ICError>;
@@ -180,6 +220,7 @@ tag_object_traits! {
fn get_labels(&self) -> &BTreeMap<String, u32>;
fn get_state(&self) -> ICState;
fn set_state(&mut self, state: ICState);
fn get_instructions_since_yield(&self) -> u16;
}
pub trait Programmable: ICInstructable {
@@ -270,24 +311,25 @@ tag_object_traits! {
}
pub trait Human : Storage {
fn get_hygine(&self) -> f32;
fn set_hygine(&mut self, hygine: f32);
fn hygine_ok(&self) -> bool {
self.get_hygine() > 0.25
}
fn hygine_low(&self) -> bool {
self.get_hygine() <= 0.0
}
fn get_mood(&self) -> f32;
fn set_mood(&mut self, mood: f32);
fn get_species(&self) -> Species;
fn get_damage(&self) -> f32;
fn set_damage(&mut self, damage: f32);
fn get_nutrition(&self) -> f32;
fn set_nutrition(&mut self, nutrition: f32);
fn get_food_quality(&self) -> f32;
fn set_food_quality(&mut self, quality: f32);
fn nutrition_state(&self) -> StatState;
fn get_hydration(&self) -> f32;
fn set_hydration(&mut self, hydration: f32);
fn hydration_state(&self) -> StatState;
fn get_oxygenation(&self) -> f32;
fn set_oxygenation(&mut self, oxygenation: f32);
fn get_food_quality(&self) -> f32;
fn set_food_quality(&mut self, quality: f32);
fn get_mood(&self) -> f32;
fn set_mood(&mut self, mood: f32);
fn mood_state(&self) -> StatState;
fn get_hygiene(&self) -> f32;
fn set_hygiene(&mut self, hygine: f32);
fn hygine_state(&self) -> StatState;
fn is_artificial(&self) -> bool;
fn robot_battery(&self) -> Option<VMObject>;
fn suit_slot(&self) -> &Slot;

View File

@@ -5,7 +5,7 @@ version.workspace = true
edition.workspace = true
[dependencies]
ic10emu = { path = "../ic10emu" }
ic10emu = { path = "../ic10emu", feaures = ["tsify"] }
console_error_panic_hook = {version = "0.1.7", optional = true}
js-sys = "0.3.69"
web-sys = { version = "0.3.69", features = ["WritableStream", "console"] }
@@ -18,7 +18,7 @@ serde-wasm-bindgen = "0.6.5"
itertools = "0.13.0"
serde = { version = "1.0.202", features = ["derive"] }
serde_with = "3.8.1"
tsify = { version = "0.4.5", default-features = false, features = ["js", "wasm-bindgen"] }
tsify = { version = "0.4.5", default-features = false, features = ["js"] }
thiserror = "1.0.61"
[build-dependencies]

View File

@@ -1,4 +1,5 @@
{
"rust-analyzer.cargo.features": [
"tsify"
]
}

View File

@@ -6,7 +6,9 @@ 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
tsify = ["dep:tsify", "dep:wasm-bindgen"]
wasm-bindgen = ["dep:wasm-bindgen"]
[dependencies]
num-integer = "0.1.46"
@@ -14,3 +16,5 @@ phf = "0.11.2"
serde = "1.0.202"
serde_derive = "1.0.202"
strum = { version = "0.26.2", features = ["derive", "phf", "strum_macros"] }
tsify = { version = "0.4.5", optional = true, features = ["js"] }
wasm-bindgen = { version = "0.2.92", optional = true }

View File

@@ -1,5 +1,9 @@
use serde_derive::{Deserialize, Serialize};
use strum::{AsRefStr, Display, EnumIter, EnumProperty, EnumString, FromRepr};
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
use super::script::{LogicSlotType, LogicType};
#[derive(
Debug,
@@ -19,6 +23,8 @@ use super::script::{LogicSlotType, LogicType};
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum AirConditioningMode {
@@ -65,6 +71,8 @@ impl TryFrom<f64> for AirConditioningMode {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum AirControlMode {
@@ -115,6 +123,8 @@ impl TryFrom<f64> for AirControlMode {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum ColorType {
@@ -189,6 +199,8 @@ impl TryFrom<f64> for ColorType {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum DaylightSensorMode {
@@ -238,6 +250,8 @@ impl TryFrom<f64> for DaylightSensorMode {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum ElevatorMode {
@@ -284,6 +298,8 @@ impl TryFrom<f64> for ElevatorMode {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum EntityState {
@@ -333,6 +349,8 @@ impl TryFrom<f64> for EntityState {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u32)]
pub enum GasType {
@@ -424,6 +442,8 @@ impl TryFrom<f64> for GasType {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum PowerMode {
@@ -477,6 +497,8 @@ impl TryFrom<f64> for PowerMode {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum PrinterInstruction {
@@ -548,6 +570,8 @@ impl TryFrom<f64> for PrinterInstruction {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum ReEntryProfile {
@@ -602,6 +626,8 @@ impl TryFrom<f64> for ReEntryProfile {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum RobotMode {
@@ -662,6 +688,8 @@ impl TryFrom<f64> for RobotMode {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum RocketMode {
@@ -719,6 +747,8 @@ impl TryFrom<f64> for RocketMode {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum Class {
@@ -878,6 +908,8 @@ impl TryFrom<f64> for Class {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum SorterInstruction {
@@ -938,6 +970,8 @@ impl TryFrom<f64> for SorterInstruction {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum SortingClass {
@@ -1010,6 +1044,8 @@ impl TryFrom<f64> for SortingClass {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum SoundAlert {
@@ -1186,6 +1222,8 @@ impl TryFrom<f64> for SoundAlert {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum LogicTransmitterMode {
@@ -1231,6 +1269,8 @@ impl TryFrom<f64> for LogicTransmitterMode {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum VentDirection {
@@ -1274,6 +1314,8 @@ impl TryFrom<f64> for VentDirection {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum ConditionOperation {

View File

@@ -1,5 +1,9 @@
use serde_derive::{Deserialize, Serialize};
use strum::{AsRefStr, Display, EnumIter, EnumProperty, EnumString, FromRepr};
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
#[derive(
Debug,
Display,
@@ -18,6 +22,8 @@ use strum::{AsRefStr, Display, EnumIter, EnumProperty, EnumString, FromRepr};
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(i32)]
pub enum StationpediaPrefab {

View File

@@ -1,5 +1,9 @@
use serde_derive::{Deserialize, Serialize};
use strum::{AsRefStr, Display, EnumIter, EnumProperty, EnumString, FromRepr};
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
#[derive(
Debug,
Display,
@@ -18,6 +22,8 @@ use strum::{AsRefStr, Display, EnumIter, EnumProperty, EnumString, FromRepr};
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum LogicBatchMethod {
@@ -67,6 +73,8 @@ impl TryFrom<f64> for LogicBatchMethod {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum LogicReagentMode {
@@ -117,6 +125,8 @@ impl TryFrom<f64> for LogicReagentMode {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u8)]
pub enum LogicSlotType {
@@ -310,6 +320,8 @@ impl TryFrom<f64> for LogicSlotType {
Serialize,
Deserialize
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf)]
#[repr(u16)]
pub enum LogicType {

View File

@@ -3,12 +3,18 @@ use std::collections::BTreeMap;
pub mod templates;
pub mod enums {
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
use std::fmt::Display;
use strum::{AsRefStr, EnumIter, EnumString, FromRepr};
pub mod basic;
pub mod script;
pub mod prefabs;
pub mod script;
#[derive(Debug)]
pub struct ParseError {
@@ -26,6 +32,8 @@ pub mod enums {
#[derive(
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, EnumString,
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum MemoryAccess {
Read,
Write,
@@ -49,6 +57,8 @@ pub mod enums {
FromRepr,
EnumString,
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum ConnectionType {
Pipe,
Power,
@@ -81,6 +91,8 @@ pub mod enums {
FromRepr,
EnumString,
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum ConnectionRole {
Input,
Input2,
@@ -92,7 +104,6 @@ pub mod enums {
None,
}
#[derive(
Debug,
Default,
@@ -110,6 +121,8 @@ pub mod enums {
FromRepr,
EnumString,
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[repr(u32)]
pub enum MachineTier {
#[default]
@@ -120,6 +133,33 @@ pub mod enums {
#[serde(other)]
Max,
}
#[derive(
Default,
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
EnumString,
AsRefStr,
EnumIter,
FromRepr,
Serialize,
Deserialize,
)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub enum Species {
None,
#[default]
Human,
Zrilian,
Robot,
}
}
#[must_use]

View File

@@ -3,11 +3,17 @@ use std::collections::BTreeMap;
use crate::enums::{
basic::{Class as SlotClass, GasType, SortingClass},
script::{LogicSlotType, LogicType},
ConnectionRole, ConnectionType, MachineTier, MemoryAccess,
ConnectionRole, ConnectionType, MachineTier, MemoryAccess, Species,
};
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[serde(untagged)]
pub enum ObjectTemplate {
Structure(StructureTemplate),
@@ -27,6 +33,7 @@ pub enum ObjectTemplate {
ItemSuit(ItemSuitTemplate),
ItemSuitLogic(ItemSuitLogicTemplate),
ItemSuitCircuitHolder(ItemSuitCircuitHolderTemplate),
Human(HumanTemplate),
}
#[allow(dead_code)]
@@ -53,6 +60,7 @@ impl ObjectTemplate {
ItemSuit(i) => &i.prefab,
ItemSuitLogic(i) => &i.prefab,
ItemSuitCircuitHolder(i) => &i.prefab,
Human(h) => &h.prefab,
}
}
}
@@ -158,20 +166,42 @@ impl From<StructureCircuitHolderTemplate> for ObjectTemplate {
}
}
impl From<HumanTemplate> for ObjectTemplate {
fn from(value: HumanTemplate) -> Self {
Self::Human(value)
}
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct HumanTemplate {
pub prefab: PrefabInfo,
pub species: Species,
pub slots: Vec<SlotInfo>,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct PrefabInfo {
pub prefab_name: String,
pub prefab_hash: i32,
pub desc: String,
pub name: String,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct SlotInfo {
pub name: String,
pub typ: SlotClass,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct LogicInfo {
pub logic_slot_types: BTreeMap<u32, BTreeMap<LogicSlotType, MemoryAccess>>,
pub logic_types: BTreeMap<LogicType, MemoryAccess>,
@@ -182,6 +212,8 @@ pub struct LogicInfo {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ItemInfo {
pub consumable: bool,
pub filter_type: Option<GasType>,
@@ -193,6 +225,8 @@ pub struct ItemInfo {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ConnectionInfo {
pub typ: ConnectionType,
pub role: ConnectionRole,
@@ -200,6 +234,8 @@ pub struct ConnectionInfo {
#[allow(clippy::struct_excessive_bools)]
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct DeviceInfo {
pub connection_list: Vec<ConnectionInfo>,
pub device_pins_length: Option<u32>,
@@ -214,12 +250,16 @@ pub struct DeviceInfo {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ConsumerInfo {
pub consumed_resouces: Vec<String>,
pub processed_reagents: Vec<i32>,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct RecipeRange {
pub start: f64,
pub stop: f64,
@@ -227,6 +267,8 @@ pub struct RecipeRange {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct RecipeGasMix {
pub rule: i64,
pub is_any: bool,
@@ -235,6 +277,8 @@ pub struct RecipeGasMix {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct Recipe {
pub tier: MachineTier,
pub time: f64,
@@ -243,21 +287,27 @@ pub struct Recipe {
pub pressure: RecipeRange,
pub required_mix: RecipeGasMix,
pub count_types: i64,
pub reagents: BTreeMap<String, f64>
pub reagents: BTreeMap<String, f64>,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct FabricatorInfo {
pub tier: MachineTier,
pub recipes: BTreeMap<String, Recipe>,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct StructureInfo {
pub small_grid: bool,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct Instruction {
pub description: String,
pub typ: String,
@@ -265,6 +315,8 @@ pub struct Instruction {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct MemoryInfo {
pub instructions: Option<BTreeMap<String, Instruction>>,
pub memory_access: MemoryAccess,
@@ -272,23 +324,31 @@ pub struct MemoryInfo {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ThermalInfo {
pub convection_factor: f32,
pub radiation_factor: f32,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct InternalAtmoInfo {
pub volume: f32,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct SuitInfo {
pub hygine_reduction_multiplier: f32,
pub waste_max_pressure: f32,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct StructureTemplate {
pub prefab: PrefabInfo,
pub structure: StructureInfo,
@@ -297,6 +357,8 @@ pub struct StructureTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct StructureSlotsTemplate {
pub prefab: PrefabInfo,
pub structure: StructureInfo,
@@ -306,6 +368,8 @@ pub struct StructureSlotsTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct StructureLogicTemplate {
pub prefab: PrefabInfo,
pub structure: StructureInfo,
@@ -316,6 +380,8 @@ pub struct StructureLogicTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct StructureLogicDeviceTemplate {
pub prefab: PrefabInfo,
pub structure: StructureInfo,
@@ -327,6 +393,8 @@ pub struct StructureLogicDeviceTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct StructureLogicDeviceConsumerTemplate {
pub prefab: PrefabInfo,
pub structure: StructureInfo,
@@ -340,6 +408,8 @@ pub struct StructureLogicDeviceConsumerTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct StructureLogicDeviceMemoryTemplate {
pub prefab: PrefabInfo,
pub structure: StructureInfo,
@@ -352,6 +422,8 @@ pub struct StructureLogicDeviceMemoryTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct StructureCircuitHolderTemplate {
pub prefab: PrefabInfo,
pub structure: StructureInfo,
@@ -363,6 +435,8 @@ pub struct StructureCircuitHolderTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct StructureLogicDeviceConsumerMemoryTemplate {
pub prefab: PrefabInfo,
pub structure: StructureInfo,
@@ -377,6 +451,8 @@ pub struct StructureLogicDeviceConsumerMemoryTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ItemTemplate {
pub prefab: PrefabInfo,
pub item: ItemInfo,
@@ -385,6 +461,8 @@ pub struct ItemTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ItemSlotsTemplate {
pub prefab: PrefabInfo,
pub item: ItemInfo,
@@ -394,6 +472,8 @@ pub struct ItemSlotsTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ItemConsumerTemplate {
pub prefab: PrefabInfo,
pub item: ItemInfo,
@@ -404,6 +484,8 @@ pub struct ItemConsumerTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ItemLogicTemplate {
pub prefab: PrefabInfo,
pub item: ItemInfo,
@@ -414,6 +496,8 @@ pub struct ItemLogicTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ItemLogicMemoryTemplate {
pub prefab: PrefabInfo,
pub item: ItemInfo,
@@ -425,6 +509,8 @@ pub struct ItemLogicMemoryTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ItemCircuitHolderTemplate {
pub prefab: PrefabInfo,
pub item: ItemInfo,
@@ -435,6 +521,8 @@ pub struct ItemCircuitHolderTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ItemSuitTemplate {
pub prefab: PrefabInfo,
pub item: ItemInfo,
@@ -445,6 +533,8 @@ pub struct ItemSuitTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ItemSuitLogicTemplate {
pub prefab: PrefabInfo,
pub item: ItemInfo,
@@ -456,6 +546,8 @@ pub struct ItemSuitLogicTemplate {
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ItemSuitCircuitHolderTemplate {
pub prefab: PrefabInfo,
pub item: ItemInfo,

View File

@@ -14,17 +14,15 @@ use crate::{
stationpedia::{self, Memory, Page, Stationpedia},
};
use stationeers_data::{
templates::{
ConnectionInfo, ConsumerInfo, DeviceInfo, FabricatorInfo, Instruction, InternalAtmoInfo,
ItemCircuitHolderTemplate, ItemConsumerTemplate, ItemInfo, ItemLogicMemoryTemplate,
ItemLogicTemplate, ItemSlotsTemplate, ItemSuitCircuitHolderTemplate, ItemSuitLogicTemplate,
ItemSuitTemplate, ItemTemplate, LogicInfo, MemoryInfo, ObjectTemplate, PrefabInfo, Recipe,
RecipeGasMix, RecipeRange, SlotInfo, StructureCircuitHolderTemplate, StructureInfo,
StructureLogicDeviceConsumerMemoryTemplate, StructureLogicDeviceConsumerTemplate,
StructureLogicDeviceMemoryTemplate, StructureLogicDeviceTemplate, StructureLogicTemplate,
StructureSlotsTemplate, StructureTemplate, SuitInfo, ThermalInfo,
},
use stationeers_data::templates::{
ConnectionInfo, ConsumerInfo, DeviceInfo, FabricatorInfo, Instruction, InternalAtmoInfo,
ItemCircuitHolderTemplate, ItemConsumerTemplate, ItemInfo, ItemLogicMemoryTemplate,
ItemLogicTemplate, ItemSlotsTemplate, ItemSuitCircuitHolderTemplate, ItemSuitLogicTemplate,
ItemSuitTemplate, ItemTemplate, LogicInfo, MemoryInfo, ObjectTemplate, PrefabInfo, Recipe,
RecipeGasMix, RecipeRange, SlotInfo, StructureCircuitHolderTemplate, StructureInfo,
StructureLogicDeviceConsumerMemoryTemplate, StructureLogicDeviceConsumerTemplate,
StructureLogicDeviceMemoryTemplate, StructureLogicDeviceTemplate, StructureLogicTemplate,
StructureSlotsTemplate, StructureTemplate, SuitInfo, ThermalInfo,
};
#[allow(clippy::too_many_lines)]
@@ -67,7 +65,8 @@ pub fn generate_database(
| ItemLogicMemory(_)
| ItemSuit(_)
| ItemSuitLogic(_)
| ItemSuitCircuitHolder(_) => None,
| ItemSuitCircuitHolder(_)
| Human(_) => None,
}
})
.collect();
@@ -83,7 +82,8 @@ pub fn generate_database(
| StructureCircuitHolder(_)
| StructureLogicDeviceConsumer(_)
| StructureLogicDeviceMemory(_)
| StructureLogicDeviceConsumerMemory(_) => None,
| StructureLogicDeviceConsumerMemory(_)
| Human(_) => None,
Item(_)
| ItemSlots(_)
| ItemConsumer(_)
@@ -112,7 +112,8 @@ pub fn generate_database(
| Item(_)
| ItemSlots(_)
| ItemSuit(_)
| ItemConsumer(_) => None,
| ItemConsumer(_)
| Human(_) => None,
ItemLogic(_)
| ItemCircuitHolder(_)
| ItemLogicMemory(_)
@@ -138,7 +139,8 @@ pub fn generate_database(
| ItemLogicMemory(_)
| ItemSuit(_)
| ItemSuitLogic(_)
| ItemSuitCircuitHolder(_) => None,
| ItemSuitCircuitHolder(_)
| Human(_) => None,
StructureLogicDevice(_)
| StructureCircuitHolder(_)
| StructureLogicDeviceMemory(_)

View File

@@ -27,15 +27,13 @@ pub fn generate(
.map(|enm| enm.enum_name.clone())
.collect::<Vec<_>>();
let mut writer =
std::io::BufWriter::new(std::fs::File::create(enums_path.join("script.rs"))?);
let mut writer = std::io::BufWriter::new(std::fs::File::create(enums_path.join("script.rs"))?);
write_repr_enum_use_header(&mut writer)?;
for enm in enums.script_enums.values() {
write_enum_listing(&mut writer, enm)?;
}
let mut writer =
std::io::BufWriter::new(std::fs::File::create(enums_path.join("basic.rs"))?);
let mut writer = std::io::BufWriter::new(std::fs::File::create(enums_path.join("basic.rs"))?);
write_repr_enum_use_header(&mut writer)?;
let script_enums_in_basic = enums
.script_enums
@@ -327,6 +325,11 @@ fn write_repr_enum_use_header<T: std::io::Write>(
use strum::{
AsRefStr, Display, EnumIter, EnumProperty, EnumString, FromRepr,
};
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
}
)?;
Ok(())
@@ -341,11 +344,7 @@ fn write_repr_basic_use_header<T: std::io::Write>(
.map(|enm| Ident::new(&enm.enum_name.to_case(Case::Pascal), Span::call_site()))
.collect::<Vec<_>>();
write!(
writer,
"{}",
quote! {use super::script::{ #(#enums),*};},
)?;
write!(writer, "{}", quote! {use super::script::{ #(#enums),*};},)?;
Ok(())
}
@@ -434,6 +433,8 @@ where
"{}",
quote! {
#[derive(#(#derives),*)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#additional_strum
#[repr(#repr)]
pub enum #name {

View File

@@ -56,6 +56,11 @@ fn write_instructions_enum<T: std::io::Write>(
Display, EnumIter, EnumProperty, EnumString, FromRepr,
};
use crate::vm::object::traits::Programmable;
#[cfg(feature = "tsify")]
use tsify::Tsify;
#[cfg(feature = "tsify")]
use wasm_bindgen::prelude::*;
}
)?;
@@ -78,10 +83,12 @@ fn write_instructions_enum<T: std::io::Write>(
writer,
"{}",
quote::quote! {#[derive(Debug, Display, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Serialize, Deserialize)]
#[derive(EnumIter, EnumString, EnumProperty, FromRepr)]
#[strum(use_phf, serialize_all = "lowercase")]
#[serde(rename_all = "lowercase")]
pub enum InstructionOp {
#[derive(EnumIter, EnumString, EnumProperty, FromRepr)]
#[cfg_attr(feature = "tsify", derive(Tsify))]
#[cfg_attr(feature = "tsify", tsify(into_wasm_abi, from_wasm_abi))]
#[strum(use_phf, serialize_all = "lowercase")]
#[serde(rename_all = "lowercase")]
pub enum InstructionOp {
Nop,
#(#inst_variants)*

View File

@@ -4,7 +4,7 @@ use stationeers_data::enums::MachineTier;
use std::collections::BTreeMap;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename = "Stationpedia", deny_unknown_fields)]
#[serde(rename = "Stationpedia")]
pub struct Stationpedia {
pub pages: Vec<Page>,
pub reagents: BTreeMap<String, Reagent>,