From d70d3a243106ad69ec56032c371f41b16bbc2e5e Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Sun, 26 May 2024 00:54:19 -0700 Subject: [PATCH] refactor(vm): generic circuit holder + suit impl --- ic10emu/src/network.rs | 2 +- ic10emu/src/vm.rs | 18 +- ic10emu/src/vm/object.rs | 26 + ic10emu/src/vm/object/generic/macros.rs | 58 ++ ic10emu/src/vm/object/generic/structs.rs | 242 +++++-- ic10emu/src/vm/object/generic/traits.rs | 629 +++++++++++++++++- ic10emu/src/vm/object/humans.rs | 219 ++++++ ic10emu/src/vm/object/macros.rs | 103 ++- ic10emu/src/vm/object/stationpedia.rs | 6 +- .../stationpedia/structs/circuit_holder.rs | 12 +- ic10emu/src/vm/object/templates.rs | 51 +- ic10emu/src/vm/object/traits.rs | 56 +- 12 files changed, 1302 insertions(+), 120 deletions(-) create mode 100644 ic10emu/src/vm/object/humans.rs diff --git a/ic10emu/src/network.rs b/ic10emu/src/network.rs index cafbbe1..43d5a5a 100644 --- a/ic10emu/src/network.rs +++ b/ic10emu/src/network.rs @@ -139,7 +139,7 @@ impl Connection { pub fn get_network(&self) -> Option { match self { - Self::CableNetwork { net, .. } => net.clone(), + Self::CableNetwork { net, .. } => *net, _ => None, } } diff --git a/ic10emu/src/vm.rs b/ic10emu/src/vm.rs index 2998d28..81fe336 100644 --- a/ic10emu/src/vm.rs +++ b/ic10emu/src/vm.rs @@ -1141,7 +1141,7 @@ impl VMTransaction { 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), @@ -1159,19 +1159,19 @@ impl VMTransaction { } pub fn finialize(&mut self) -> Result<(), VMError> { - for (child, (slot, parent)) in self.object_parents { + for (child, (slot, parent)) in &self.object_parents { let child_obj = self .objects - .get(&child) - .ok_or(VMError::MissingChild(child))?; - let child_obj_ref = child_obj.borrow_mut(); + .get(child) + .ok_or(VMError::MissingChild(*child))?; + let mut child_obj_ref = child_obj.borrow_mut(); let item = child_obj_ref .as_mut_item() - .ok_or(VMError::NotParentable(child))?; + .ok_or(VMError::NotParentable(*child))?; item.set_parent_slot(Some(ParentSlotInfo { - slot: slot as usize, - parent, - })) + slot: *slot as usize, + parent: *parent, + })); } Ok(()) } diff --git a/ic10emu/src/vm/object.rs b/ic10emu/src/vm/object.rs index 3170533..44edeb9 100644 --- a/ic10emu/src/vm/object.rs +++ b/ic10emu/src/vm/object.rs @@ -9,6 +9,7 @@ use serde_derive::{Deserialize, Serialize}; pub mod errors; pub mod generic; +pub mod humans; pub mod macros; pub mod stationpedia; pub mod templates; @@ -122,3 +123,28 @@ pub struct Slot { pub writeable_logic: Vec, pub occupant: Option, } + +impl Slot { + #[must_use] + pub fn new(parent: ObjectID, index: usize, name: String, typ: SlotClass) -> Self { + Slot { + parent, + index, + name, + typ, + readable_logic: vec![ + LogicSlotType::Class, + LogicSlotType::Damage, + LogicSlotType::MaxQuantity, + LogicSlotType::OccupantHash, + LogicSlotType::Occupied, + LogicSlotType::PrefabHash, + LogicSlotType::Quantity, + LogicSlotType::ReferenceId, + LogicSlotType::SortingClass, + ], + writeable_logic: vec![], + occupant: None, + } + } +} diff --git a/ic10emu/src/vm/object/generic/macros.rs b/ic10emu/src/vm/object/generic/macros.rs index c536a92..23d6985 100644 --- a/ic10emu/src/vm/object/generic/macros.rs +++ b/ic10emu/src/vm/object/generic/macros.rs @@ -1,3 +1,45 @@ +macro_rules! GWThermal { + ( + $( #[$attr:meta] )* + $viz:vis struct $struct:ident { + $($body:tt)* + } + ) => { + impl GWThermal for $struct { + fn is_thermal(&self) -> bool { + self.thermal_info.is_some() + } + fn thermal_info(&self) -> &ThermalInfo { + self.thermal_info + .as_ref() + .expect("GWTherml::thermal_info called on non thermal") + } + } + }; +} +pub(crate) use GWThermal; + +macro_rules! GWInternalAtmo { + ( + $( #[$attr:meta] )* + $viz:vis struct $struct:ident { + $($body:tt)* + } + ) => { + impl GWInternalAtmo for $struct { + fn is_internal_atmo(&self) -> bool { + self.internal_atmo_info.is_some() + } + fn internal_atmo_info(&self) -> &InternalAtmoInfo { + self.internal_atmo_info + .as_ref() + .expect("GWInternalAtmo::internal_atmo_info called on non internal atmo") + } + } + }; +} +pub(crate) use GWInternalAtmo; + macro_rules! GWStructure { ( $( #[$attr:meta] )* @@ -152,3 +194,19 @@ macro_rules! GWItem { }; } pub(crate) use GWItem; + +macro_rules! GWSuit { + ( + $( #[$attr:meta] )* + $viz:vis struct $struct:ident { + $($body:tt)* + } + ) => { + impl GWSuit for $struct { + fn suit_info(&self) -> &SuitInfo { + &self.suit_info + } + } + }; +} +pub(crate) use GWSuit; diff --git a/ic10emu/src/vm/object/generic/structs.rs b/ic10emu/src/vm/object/generic/structs.rs index 401dec1..85a11ca 100644 --- a/ic10emu/src/vm/object/generic/structs.rs +++ b/ic10emu/src/vm/object/generic/structs.rs @@ -10,12 +10,18 @@ use crate::{ use macro_rules_attribute::derive; use stationeers_data::{ enums::script::LogicType, - templates::{ConsumerInfo, DeviceInfo, FabricatorInfo, InternalAtmoInfo, ItemInfo, ThermalInfo}, + templates::{ + ConsumerInfo, DeviceInfo, FabricatorInfo, InternalAtmoInfo, ItemInfo, SuitInfo, ThermalInfo, + }, }; use std::{collections::BTreeMap, rc::Rc}; -#[derive(ObjectInterface!, GWStructure!)] -#[custom(implements(Object { Structure }))] +#[derive(ObjectInterface!, GWThermal!, GWInternalAtmo!, GWStructure!)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Structure +}))] pub struct Generic { #[custom(object_id)] pub id: ObjectID, @@ -30,8 +36,12 @@ pub struct Generic { pub small_grid: bool, } -#[derive(ObjectInterface!, GWStructure!, GWStorage!)] -#[custom(implements(Object { Structure, Storage }))] +#[derive(ObjectInterface!, GWThermal!, GWInternalAtmo!, GWStructure!, GWStorage!)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Structure, Storage +}))] pub struct GenericStorage { #[custom(object_id)] pub id: ObjectID, @@ -47,8 +57,16 @@ pub struct GenericStorage { pub slots: Vec, } -#[derive(ObjectInterface!, GWStructure!, GWStorage!, GWLogicable!)] -#[custom(implements(Object { Structure, Storage, Logicable }))] +#[derive( + ObjectInterface!, + GWThermal!, GWInternalAtmo!, + GWStructure!, GWStorage!, GWLogicable! +)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Structure, Storage, Logicable +}))] pub struct GenericLogicable { #[custom(object_id)] pub id: ObjectID, @@ -66,8 +84,17 @@ pub struct GenericLogicable { pub modes: Option>, } -#[derive(ObjectInterface!, GWStructure!, GWStorage!, GWLogicable!, GWDevice!)] -#[custom(implements(Object { Structure, Storage, Logicable, Device }))] +#[derive( + ObjectInterface!, + GWThermal!, GWInternalAtmo!, + GWStructure!, GWStorage!, GWLogicable!, + GWDevice! +)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Structure, Storage, Logicable, Device +}))] pub struct GenericLogicableDevice { #[custom(object_id)] pub id: ObjectID, @@ -89,8 +116,17 @@ pub struct GenericLogicableDevice { pub reagents: Option>, } -#[derive(ObjectInterface!, GWStructure!, GWStorage!, GWLogicable!, GWDevice!)] -#[custom(implements(Object { Structure, Storage, Logicable, Device }))] +#[derive( + ObjectInterface!, + GWThermal!, GWInternalAtmo!, + GWStructure!, GWStorage!, GWLogicable!, + GWDevice! +)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Structure, Storage, Logicable, Device +}))] pub struct GenericCircuitHolder { #[custom(object_id)] pub id: ObjectID, @@ -112,8 +148,17 @@ pub struct GenericCircuitHolder { pub reagents: Option>, } -#[derive(ObjectInterface!, GWStructure!, GWStorage!, GWLogicable!, GWDevice!)] -#[custom(implements(Object { Structure, Storage, Logicable, Device }))] +#[derive( + ObjectInterface!, + GWThermal!, GWInternalAtmo!, + GWStructure!, GWStorage!, GWLogicable!, + GWDevice! +)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Structure, Storage, Logicable, Device +}))] pub struct GenericLogicableDeviceConsumer { #[custom(object_id)] pub id: ObjectID, @@ -136,8 +181,18 @@ pub struct GenericLogicableDeviceConsumer { pub consumer_info: ConsumerInfo, } -#[derive(ObjectInterface!, GWStructure!, GWStorage!, GWLogicable!, GWDevice!, GWMemoryReadable!, GWMemoryWritable!)] -#[custom(implements(Object { Structure, Storage, Logicable, Device, MemoryReadable }))] +#[derive( + ObjectInterface!, + GWThermal!, GWInternalAtmo!, + GWStructure!, GWStorage!, + GWLogicable!, GWDevice!, + GWMemoryReadable!, GWMemoryWritable! +)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Structure, Storage, Logicable, Device, MemoryReadable +}))] pub struct GenericLogicableDeviceMemoryReadable { #[custom(object_id)] pub id: ObjectID, @@ -160,8 +215,17 @@ pub struct GenericLogicableDeviceMemoryReadable { pub memory: Vec, } -#[derive(ObjectInterface!, GWStructure!, GWStorage!, GWLogicable!, GWDevice!, GWMemoryReadable!, GWMemoryWritable!)] -#[custom(implements(Object { Structure, Storage, Logicable, Device, MemoryReadable }))] +#[derive( + ObjectInterface!, + GWThermal!, GWInternalAtmo!, + GWStructure!, GWStorage!, GWLogicable!, + GWDevice!, GWMemoryReadable!, GWMemoryWritable! +)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Structure, Storage, Logicable, Device, MemoryReadable +}))] pub struct GenericLogicableDeviceConsumerMemoryReadable { #[custom(object_id)] pub id: ObjectID, @@ -186,8 +250,17 @@ pub struct GenericLogicableDeviceConsumerMemoryReadable { pub memory: Vec, } -#[derive(ObjectInterface!, GWStructure!, GWStorage!, GWLogicable!, GWDevice!, GWMemoryReadable!, GWMemoryWritable!)] -#[custom(implements(Object { Structure, Storage, Logicable, Device, MemoryReadable, MemoryWritable }))] +#[derive( + ObjectInterface!, + GWThermal!, GWInternalAtmo!, + GWStructure!, GWStorage!, + GWLogicable!, GWDevice!, GWMemoryReadable!, GWMemoryWritable! +)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Structure, Storage, Logicable, Device, MemoryReadable, MemoryWritable +}))] pub struct GenericLogicableDeviceMemoryReadWriteable { #[custom(object_id)] pub id: ObjectID, @@ -210,9 +283,17 @@ pub struct GenericLogicableDeviceMemoryReadWriteable { pub memory: Vec, } - -#[derive(ObjectInterface!, GWStructure!, GWStorage!, GWLogicable!, GWDevice!, GWMemoryReadable!, GWMemoryWritable!)] -#[custom(implements(Object { Structure, Storage, Logicable, Device, MemoryReadable, MemoryWritable }))] +#[derive( + ObjectInterface!, + GWThermal!, GWInternalAtmo!, + GWStructure!, GWStorage!, GWLogicable!, + GWDevice!, GWMemoryReadable!, GWMemoryWritable! +)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Structure, Storage, Logicable, Device, MemoryReadable, MemoryWritable +}))] pub struct GenericLogicableDeviceConsumerMemoryReadWriteable { #[custom(object_id)] pub id: ObjectID, @@ -237,8 +318,12 @@ pub struct GenericLogicableDeviceConsumerMemoryReadWriteable { pub memory: Vec, } -#[derive(ObjectInterface!, GWItem!)] -#[custom(implements(Object { Item }))] +#[derive(ObjectInterface!, GWThermal!, GWInternalAtmo!, GWItem!)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Item +}))] pub struct GenericItem { #[custom(object_id)] pub id: ObjectID, @@ -255,8 +340,12 @@ pub struct GenericItem { pub damage: Option, } -#[derive(ObjectInterface!, GWItem!, GWStorage! )] -#[custom(implements(Object { Item, Storage }))] +#[derive(ObjectInterface!, GWThermal!, GWInternalAtmo!, GWItem!, GWStorage! )] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Item, Storage +}))] pub struct GenericItemStorage { #[custom(object_id)] pub id: ObjectID, @@ -274,8 +363,12 @@ pub struct GenericItemStorage { pub slots: Vec, } -#[derive(ObjectInterface!, GWItem!, GWStorage! )] -#[custom(implements(Object { Item, Storage }))] +#[derive(ObjectInterface!, GWThermal!, GWInternalAtmo!, GWItem!, GWStorage! )] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Item, Storage +}))] pub struct GenericItemConsumer { #[custom(object_id)] pub id: ObjectID, @@ -294,8 +387,16 @@ pub struct GenericItemConsumer { pub consumer_info: ConsumerInfo, } -#[derive(ObjectInterface!, GWItem!, GWStorage!, GWLogicable! )] -#[custom(implements(Object { Item, Storage, Logicable }))] +#[derive( + ObjectInterface!, + GWThermal!, GWInternalAtmo!, + GWItem!, GWStorage!, GWLogicable! +)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Item, Storage, Logicable +}))] pub struct GenericItemLogicable { #[custom(object_id)] pub id: ObjectID, @@ -315,8 +416,17 @@ pub struct GenericItemLogicable { pub modes: Option>, } -#[derive(ObjectInterface!, GWItem!, GWStorage!, GWLogicable!, GWMemoryReadable! )] -#[custom(implements(Object { Item, Storage, Logicable, MemoryReadable }))] +#[derive( + ObjectInterface!, + GWThermal!, GWInternalAtmo!, + GWItem!, GWStorage!, GWLogicable!, + GWMemoryReadable! +)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Item, Storage, Logicable, MemoryReadable +}))] pub struct GenericItemLogicableMemoryReadable { #[custom(object_id)] pub id: ObjectID, @@ -337,8 +447,17 @@ pub struct GenericItemLogicableMemoryReadable { pub memory: Vec, } -#[derive(ObjectInterface!, GWItem!, GWStorage!, GWLogicable!, GWMemoryReadable!, GWMemoryWritable! )] -#[custom(implements(Object { Item, Storage, Logicable, MemoryReadable, MemoryWritable }))] +#[derive( + ObjectInterface!, + GWThermal!, GWInternalAtmo!, + GWItem!, GWStorage!, GWLogicable!, + GWMemoryReadable!, GWMemoryWritable! +)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Item, Storage, Logicable, MemoryReadable, MemoryWritable +}))] pub struct GenericItemLogicableMemoryReadWriteable { #[custom(object_id)] pub id: ObjectID, @@ -359,8 +478,16 @@ pub struct GenericItemLogicableMemoryReadWriteable { pub memory: Vec, } -#[derive(ObjectInterface!, GWItem!, GWStorage!, GWLogicable! )] -#[custom(implements(Object { Item, Storage, Logicable }))] +#[derive( + ObjectInterface!, + GWThermal!, GWInternalAtmo!, + GWItem!, GWStorage!, GWLogicable! +)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Item, Storage, Logicable +}))] pub struct GenericItemCircuitHolder { #[custom(object_id)] pub id: ObjectID, @@ -380,9 +507,17 @@ pub struct GenericItemCircuitHolder { pub modes: Option>, } - -#[derive(ObjectInterface!, GWItem!, GWStorage!, GWLogicable!)] -#[custom(implements(Object { Item, Storage, Suit, Logicable }))] +#[derive( + ObjectInterface!, + GWThermal!, GWInternalAtmo!, + GWItem!, GWStorage!, GWLogicable!, + GWSuit! +)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Item, Storage, Suit, Logicable +}))] pub struct GenericItemSuitLogic { #[custom(object_id)] pub id: ObjectID, @@ -398,12 +533,23 @@ pub struct GenericItemSuitLogic { pub parent_slot: Option, pub damage: Option, pub slots: Vec, + pub suit_info: SuitInfo, pub fields: BTreeMap, pub modes: Option>, } -#[derive(ObjectInterface!, GWItem!, GWStorage!, GWLogicable!, GWMemoryReadable!, GWMemoryWritable!)] -#[custom(implements(Object { Item, Storage, Suit, Logicable, MemoryReadable, MemoryWritable }))] +#[derive( + ObjectInterface!, + GWThermal!, GWInternalAtmo!, + GWItem!, GWStorage!, GWLogicable!, + GWMemoryReadable!, GWMemoryWritable!, + GWSuit! +)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Item, Storage, Suit, Logicable, MemoryReadable, MemoryWritable +}))] pub struct GenericItemSuitCircuitHolder { #[custom(object_id)] pub id: ObjectID, @@ -419,13 +565,22 @@ pub struct GenericItemSuitCircuitHolder { pub parent_slot: Option, pub damage: Option, pub slots: Vec, + pub suit_info: SuitInfo, pub fields: BTreeMap, pub modes: Option>, pub memory: Vec, } -#[derive(ObjectInterface!, GWItem!, GWStorage! )] -#[custom(implements(Object { Item, Storage, Suit }))] +#[derive( + ObjectInterface!, + GWThermal!, GWInternalAtmo!, + GWItem!, GWStorage!, GWSuit! +)] +#[custom(implements(Object { + Thermal[GWThermal::is_thermal], + InternalAtmosphere[GWInternalAtmo::is_internal_atmo], + Item, Storage, Suit +}))] pub struct GenericItemSuit { #[custom(object_id)] pub id: ObjectID, @@ -441,4 +596,5 @@ pub struct GenericItemSuit { pub parent_slot: Option, pub damage: Option, pub slots: Vec, + pub suit_info: SuitInfo, } diff --git a/ic10emu/src/vm/object/generic/traits.rs b/ic10emu/src/vm/object/generic/traits.rs index e0b9a8f..f721f56 100644 --- a/ic10emu/src/vm/object/generic/traits.rs +++ b/ic10emu/src/vm/object/generic/traits.rs @@ -3,7 +3,7 @@ use crate::{ vm::object::{ errors::{LogicError, MemoryError}, traits::*, - LogicField, MemoryAccess, ObjectID, Slot, + LogicField, MemoryAccess, ObjectID, Slot, VMObject, }, }; @@ -12,11 +12,36 @@ use stationeers_data::{ basic::{Class as SlotClass, GasType, SortingClass}, script::{LogicSlotType, LogicType}, }, - templates::{DeviceInfo, ItemInfo}, + templates::{DeviceInfo, InternalAtmoInfo, ItemInfo, SuitInfo, ThermalInfo}, }; use std::{collections::BTreeMap, usize}; use strum::IntoEnumIterator; +pub trait GWThermal { + fn is_thermal(&self) -> bool; + fn thermal_info(&self) -> &ThermalInfo; +} + +impl Thermal for T { + fn get_radiation_factor(&self) -> f32 { + self.thermal_info().radiation_factor + } + fn get_convection_factor(&self) -> f32 { + self.thermal_info().convection_factor + } +} + +pub trait GWInternalAtmo { + fn is_internal_atmo(&self) -> bool; + fn internal_atmo_info(&self) -> &InternalAtmoInfo; +} + +impl InternalAtmosphere for T { + fn get_volume(&self) -> f64 { + self.internal_atmo_info().volume as f64 + } +} + pub trait GWStructure { fn small_grid(&self) -> bool; } @@ -169,6 +194,7 @@ impl Logicable for T { use LogicSlotType::*; let occupant = slot .occupant + .as_ref() .and_then(|info| self.get_vm().get_object(info.id)); match slt { Occupied => { @@ -406,7 +432,10 @@ impl Device for T { return Ok(()); } if slot.writeable_logic.contains(&slt) { - let occupant = slot.occupant.and_then(|info| vm.get_object(info.id)); + let occupant = slot + .occupant + .as_ref() + .and_then(|info| vm.get_object(info.id)); if let Some(occupant) = occupant { let mut occupant_ref = occupant.borrow_mut(); let logicable = occupant_ref @@ -539,4 +568,596 @@ impl Item for T { } } -pub trait GWCircuitHolder: Logicable {} +pub trait GWSuit: Storage { + fn suit_info(&self) -> &SuitInfo; +} + +impl Suit for T { + fn pressure_waste_max(&self) -> f32 { + self.suit_info().waste_max_pressure + } + fn pressure_air(&self) -> f32 { + // Game "hard" codes air tank to first slot of suits + let result = self.get_slot(0).and_then(|slot| { + let canister = slot + .occupant + .as_ref() + .and_then(|info| self.get_vm().get_object(info.id)); + let pressure = canister.and_then(|canister| { + canister + .borrow() + .as_logicable() + .and_then(|logicable| logicable.get_logic(LogicType::Pressure).ok()) + }); + + pressure + }); + result.unwrap_or(0.0) as f32 + } + fn pressure_waste(&self) -> f32 { + // game hard codes waste tank to second slot of suits + let result = self.get_slot(1).and_then(|slot| { + let canister = slot + .occupant + .as_ref() + .and_then(|info| self.get_vm().get_object(info.id)); + let pressure = canister.and_then(|canister| { + canister + .borrow() + .as_logicable() + .and_then(|logicable| logicable.get_logic(LogicType::Pressure).ok()) + }); + + pressure + }); + result.unwrap_or(0.0) as f32 + } +} + +pub trait CircuitHolderType {} + +pub struct ItemCircuitHolder; +pub struct SuitCircuitHolder; +pub struct DeviceCircuitHolder; +impl CircuitHolderType for ItemCircuitHolder {} +impl CircuitHolderType for SuitCircuitHolder {} +impl CircuitHolderType for DeviceCircuitHolder {} + +pub trait GWCircuitHolder: Logicable { + type Holder: CircuitHolderType; + fn gw_get_error(&self) -> i32; + fn gw_set_error(&mut self, state: i32); +} + +pub trait GWCircuitHolderWrapper::Holder> { + fn clear_error_gw(&mut self); + fn set_error_gw(&mut self, state: i32); + /// i32::MAX is db + fn get_logicable_from_index_gw( + &self, + device: i32, + connection: Option, + ) -> Option; + /// i32::MAX is db + fn get_logicable_from_index_mut_gw( + &mut self, + device: i32, + connection: Option, + ) -> Option; + fn get_logicable_from_id_gw( + &self, + device: ObjectID, + connection: Option, + ) -> Option; + fn get_logicable_from_id_mut_gw( + &mut self, + device: ObjectID, + connection: Option, + ) -> Option; + fn get_ic_gw(&self) -> Option; + fn hault_and_catch_fire_gw(&mut self); +} + +impl CircuitHolder for T +where + T: GWCircuitHolder, + Self: GWCircuitHolderWrapper, +{ + fn clear_error(&mut self) { + self.clear_error_gw() + } + fn set_error(&mut self, state: i32) { + self.set_error_gw(state) + } + /// i32::MAX is db + fn get_logicable_from_index( + &self, + device: i32, + connection: Option, + ) -> Option { + self.get_logicable_from_index_gw(device, connection) + } + /// i32::MAX is db + fn get_logicable_from_index_mut( + &mut self, + device: i32, + connection: Option, + ) -> Option { + self.get_logicable_from_index_mut_gw(device, connection) + } + fn get_logicable_from_id( + &self, + device: ObjectID, + connection: Option, + ) -> Option { + self.get_logicable_from_id_gw(device, connection) + } + fn get_logicable_from_id_mut( + &mut self, + device: ObjectID, + connection: Option, + ) -> Option { + self.get_logicable_from_id_mut_gw(device, connection) + } + fn get_ic(&self) -> Option { + self.get_ic_gw() + } + fn hault_and_catch_fire(&mut self) { + self.hault_and_catch_fire_gw() + } +} + +impl GWCircuitHolderWrapper for T +where + T: GWCircuitHolder + Device + Object, +{ + fn clear_error_gw(&mut self) { + self.gw_set_error(0); + } + fn set_error_gw(&mut self, state: i32) { + self.gw_set_error(state); + } + + /// i32::MAX is db + fn get_logicable_from_index_gw( + &self, + device: i32, + connection: Option, + ) -> Option { + if device == i32::MAX { + // self + if let Some(connection) = connection { + self.connection_list().get(connection).and_then(|conn| { + if let Connection::CableNetwork { net: Some(net), .. } = conn { + self.get_vm() + .get_network(*net) + .map(ObjectRef::from_vm_object) + } else { + None + } + }) + } else { + Some(ObjectRef::from_ref(self.as_object())) + } + } else { + if device < 0 { + return None; + } + self.device_pins().and_then(|pins| { + pins.get(device as usize).and_then(|pin| { + pin.and_then(|id| self.get_vm().get_object(id).map(ObjectRef::from_vm_object)) + }) + }) + } + } + + /// i32::MAX is db + fn get_logicable_from_index_mut_gw( + &mut self, + device: i32, + connection: Option, + ) -> Option { + if device == i32::MAX { + // self + if let Some(connection) = connection { + self.connection_list().get(connection).and_then(|conn| { + if let Connection::CableNetwork { net: Some(net), .. } = conn { + self.get_vm() + .get_network(*net) + .map(ObjectRefMut::from_vm_object) + } else { + None + } + }) + } else { + Some(ObjectRefMut::from_ref(self.as_mut_object())) + } + } else { + if device < 0 { + return None; + } + self.device_pins().and_then(|pins| { + pins.get(device as usize).and_then(|pin| { + pin.and_then(|id| { + self.get_vm() + .get_object(id) + .map(ObjectRefMut::from_vm_object) + }) + }) + }) + } + } + + fn get_logicable_from_id_gw( + &self, + device: ObjectID, + connection: Option, + ) -> Option { + if connection.is_some() { + return None; // this functionality is disabled in the game, no network access via ReferenceId + } + if device == *self.get_id() { + return Some(ObjectRef::from_ref(self.as_object())); + } + self.get_vm() + .get_object(device) + .map(ObjectRef::from_vm_object) + } + + fn get_logicable_from_id_mut_gw( + &mut self, + device: ObjectID, + connection: Option, + ) -> Option { + if connection.is_some() { + return None; // this functionality is disabled in the game, no network access via ReferenceId + } + if device == *self.get_id() { + return Some(ObjectRefMut::from_ref(self.as_mut_object())); + } + self.get_vm() + .get_object(device) + .map(ObjectRefMut::from_vm_object) + } + + fn get_ic_gw(&self) -> Option { + self.get_slots() + .into_iter() + .find(|slot| slot.typ == SlotClass::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) { + // TODO: do something here?? + } +} + +impl GWCircuitHolderWrapper for T +where + T: GWCircuitHolder + Suit + Object, +{ + fn clear_error_gw(&mut self) { + self.gw_set_error(0); + } + fn set_error_gw(&mut self, state: i32) { + self.gw_set_error(state); + } + + /// 0 -> Helmet + /// 1 -> BackPack + /// 2 -> ToolBelt + fn get_logicable_from_index_gw( + &self, + device: i32, + _connection: Option, + ) -> Option { + match device { + i32::MAX => Some(ObjectRef::from_ref(self.as_object())), + 0 => self.root_parent_human().and_then(|obj| { + obj.borrow().as_human().and_then(|human| { + human.helmet_slot().occupant.as_ref().and_then(|info| { + self.get_vm() + .get_object(info.id) + .map(ObjectRef::from_vm_object) + }) + }) + }), + 1 => self.root_parent_human().and_then(|obj| { + obj.borrow().as_human().and_then(|human| { + human.backpack_slot().occupant.as_ref().and_then(|info| { + self.get_vm() + .get_object(info.id) + .map(ObjectRef::from_vm_object) + }) + }) + }), + 2 => self.root_parent_human().and_then(|obj| { + obj.borrow().as_human().and_then(|human| { + human.toolbelt_slot().occupant.as_ref().and_then(|info| { + self.get_vm() + .get_object(info.id) + .map(ObjectRef::from_vm_object) + }) + }) + }), + _ => None, + } + } + + /// i32::MAX is db + fn get_logicable_from_index_mut_gw( + &mut self, + device: i32, + _connection: Option, + ) -> Option { + match device { + i32::MAX => Some(ObjectRefMut::from_ref(self.as_mut_object())), + 0 => self.root_parent_human().and_then(|obj| { + obj.borrow().as_human().and_then(|human| { + human.helmet_slot().occupant.as_ref().and_then(|info| { + self.get_vm() + .get_object(info.id) + .map(ObjectRefMut::from_vm_object) + }) + }) + }), + 1 => self.root_parent_human().and_then(|obj| { + obj.borrow().as_human().and_then(|human| { + human.backpack_slot().occupant.as_ref().and_then(|info| { + self.get_vm() + .get_object(info.id) + .map(ObjectRefMut::from_vm_object) + }) + }) + }), + 2 => self.root_parent_human().and_then(|obj| { + obj.borrow().as_human().and_then(|human| { + human.toolbelt_slot().occupant.as_ref().and_then(|info| { + self.get_vm() + .get_object(info.id) + .map(ObjectRefMut::from_vm_object) + }) + }) + }), + _ => None, + } + } + + fn get_logicable_from_id_gw( + &self, + device: ObjectID, + _connection: Option, + ) -> Option { + if device == *self.get_id() { + return Some(ObjectRef::from_ref(self.as_object())); + } + let contained_ids: Vec = self + .get_slots() + .into_iter() + .filter_map(|slot| slot.occupant.as_ref().map(|info| info.id)) + .collect(); + if contained_ids.contains(&device) { + self.get_vm() + .get_object(device) + .map(ObjectRef::from_vm_object) + } else { + None + } + } + + fn get_logicable_from_id_mut_gw( + &mut self, + device: ObjectID, + _connection: Option, + ) -> Option { + if device == *self.get_id() { + return Some(ObjectRefMut::from_ref(self.as_mut_object())); + } + let contained_ids: Vec = self + .get_slots() + .into_iter() + .filter_map(|slot| slot.occupant.as_ref().map(|info| info.id)) + .collect(); + if contained_ids.contains(&device) { + self.get_vm() + .get_object(device) + .map(ObjectRefMut::from_vm_object) + } else { + None + } + } + + fn get_ic_gw(&self) -> Option { + self.get_slots() + .into_iter() + .find(|slot| slot.typ == SlotClass::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) { + // TODO: do something here?? + } +} + +impl GWCircuitHolderWrapper for T +where + T: GWCircuitHolder + Item + Object, +{ + fn clear_error_gw(&mut self) { + self.gw_set_error(0); + } + fn set_error_gw(&mut self, state: i32) { + self.gw_set_error(state); + } + + /// i32::MAX is db + /// 0 -> Helmet + /// 1 -> Suit + /// 2 -> BackPack + /// 3 -> ToolBelt + fn get_logicable_from_index_gw( + &self, + device: i32, + _connection: Option, + ) -> Option { + match device { + i32::MAX => Some(ObjectRef::from_ref(self.as_object())), + 0 => self.root_parent_human().and_then(|obj| { + obj.borrow().as_human().and_then(|human| { + human.helmet_slot().occupant.as_ref().and_then(|info| { + self.get_vm() + .get_object(info.id) + .map(ObjectRef::from_vm_object) + }) + }) + }), + 1 => self.root_parent_human().and_then(|obj| { + obj.borrow().as_human().and_then(|human| { + human.suit_slot().occupant.as_ref().and_then(|info| { + self.get_vm() + .get_object(info.id) + .map(ObjectRef::from_vm_object) + }) + }) + }), + 2 => self.root_parent_human().and_then(|obj| { + obj.borrow().as_human().and_then(|human| { + human.backpack_slot().occupant.as_ref().and_then(|info| { + self.get_vm() + .get_object(info.id) + .map(ObjectRef::from_vm_object) + }) + }) + }), + 3 => self.root_parent_human().and_then(|obj| { + obj.borrow().as_human().and_then(|human| { + human.toolbelt_slot().occupant.as_ref().and_then(|info| { + self.get_vm() + .get_object(info.id) + .map(ObjectRef::from_vm_object) + }) + }) + }), + _ => None, + } + } + + /// i32::MAX is db + /// 0 -> Helmet + /// 1 -> Suit + /// 2 -> BackPack + /// 3 -> ToolBelt + fn get_logicable_from_index_mut_gw( + &mut self, + device: i32, + _connection: Option, + ) -> Option { + match device { + i32::MAX => Some(ObjectRefMut::from_ref(self.as_mut_object())), + 0 => self.root_parent_human().and_then(|obj| { + obj.borrow().as_human().and_then(|human| { + human.helmet_slot().occupant.as_ref().and_then(|info| { + self.get_vm() + .get_object(info.id) + .map(ObjectRefMut::from_vm_object) + }) + }) + }), + 1 => self.root_parent_human().and_then(|obj| { + obj.borrow().as_human().and_then(|human| { + human.suit_slot().occupant.as_ref().and_then(|info| { + self.get_vm() + .get_object(info.id) + .map(ObjectRefMut::from_vm_object) + }) + }) + }), + 2 => self.root_parent_human().and_then(|obj| { + obj.borrow().as_human().and_then(|human| { + human.backpack_slot().occupant.as_ref().and_then(|info| { + self.get_vm() + .get_object(info.id) + .map(ObjectRefMut::from_vm_object) + }) + }) + }), + 3 => self.root_parent_human().and_then(|obj| { + obj.borrow().as_human().and_then(|human| { + human.toolbelt_slot().occupant.as_ref().and_then(|info| { + self.get_vm() + .get_object(info.id) + .map(ObjectRefMut::from_vm_object) + }) + }) + }), + _ => None, + } + } + + fn get_logicable_from_id_gw( + &self, + device: ObjectID, + _connection: Option, + ) -> Option { + if device == *self.get_id() { + return Some(ObjectRef::from_ref(self.as_object())); + } + let contained_ids: Vec = self + .get_slots() + .into_iter() + .filter_map(|slot| slot.occupant.as_ref().map(|info| info.id)) + .collect(); + if contained_ids.contains(&device) { + self.get_vm() + .get_object(device) + .map(ObjectRef::from_vm_object) + } else { + None + } + } + + fn get_logicable_from_id_mut_gw( + &mut self, + device: ObjectID, + _connection: Option, + ) -> Option { + if device == *self.get_id() { + return Some(ObjectRefMut::from_ref(self.as_mut_object())); + } + let contained_ids: Vec = self + .get_slots() + .into_iter() + .filter_map(|slot| slot.occupant.as_ref().map(|info| info.id)) + .collect(); + if contained_ids.contains(&device) { + self.get_vm() + .get_object(device) + .map(ObjectRefMut::from_vm_object) + } else { + None + } + } + + fn get_ic_gw(&self) -> Option { + self.get_slots() + .into_iter() + .find(|slot| slot.typ == SlotClass::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) { + // TODO: do something here?? + } +} diff --git a/ic10emu/src/vm/object/humans.rs b/ic10emu/src/vm/object/humans.rs new file mode 100644 index 0000000..9132f61 --- /dev/null +++ b/ic10emu/src/vm/object/humans.rs @@ -0,0 +1,219 @@ +use macro_rules_attribute::derive; +use stationeers_data::enums::basic::Class as SlotClass; + +use crate::vm::{ + object::{ + macros::ObjectInterface, + traits::{Human, HumanRef, HumanRefMut, Object, Storage, StorageRef, StorageRefMut}, + Name, ObjectID, Slot, + }, + VM, +}; + +#[derive(ObjectInterface!)] +#[custom(implements(Object { + Human, Storage +}))] +pub struct HumanPlayer { + #[custom(object_id)] + pub id: ObjectID, + #[custom(object_prefab)] + pub prefab: Name, + #[custom(object_name)] + pub name: Name, + #[custom(object_vm_ref)] + pub vm: std::rc::Rc, + + pub hydration: f32, + pub nutrition: f32, + pub oxygenation: f32, + pub food_quality: f32, + pub mood: f32, + pub hygine: f32, + + left_hand_slot: Slot, + right_hand_slot: Slot, + suit_slot: Slot, + helmet_slot: Slot, + glasses_slot: Slot, + backpack_slot: Slot, + uniform_slot: Slot, + toolbelt_slot: Slot, +} + +impl HumanPlayer { + pub fn new(id: ObjectID, vm: std::rc::Rc) -> Self { + HumanPlayer { + id, + prefab: Name::new(""), + name: Name::new(""), + vm, + hydration: 5.0, + nutrition: 5.0, + oxygenation: 1.0, + food_quality: 0.75, + mood: 1.0, + hygine: 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), + } + } +} + +impl Storage for HumanPlayer { + fn get_slots(&self) -> Vec<&Slot> { + vec![ + &self.left_hand_slot, + &self.right_hand_slot, + &self.suit_slot, + &self.helmet_slot, + &self.glasses_slot, + &self.backpack_slot, + &self.uniform_slot, + &self.toolbelt_slot, + ] + } + + fn get_slots_mut(&mut self) -> Vec<&mut Slot> { + 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.backpack_slot, + &mut self.uniform_slot, + &mut self.toolbelt_slot, + ] + } + + fn slots_count(&self) -> usize { + 8 + } + + fn get_slot(&self, index: usize) -> Option<&Slot> { + match index { + 0 => Some(&self.left_hand_slot), + 1 => Some(&self.right_hand_slot), + 2 => Some(&self.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), + _ => None, + } + } + fn get_slot_mut(&mut self, index: usize) -> Option<&mut Slot> { + match index { + 0 => Some(&mut self.left_hand_slot), + 1 => Some(&mut self.right_hand_slot), + 2 => Some(&mut self.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), + _ => None, + } + } +} + +impl Human for HumanPlayer { + fn get_hydration(&self) -> f32 { + self.hydration + } + fn set_hydration(&mut self, hydration: f32) { + self.hydration = hydration; + } + fn get_nutrition(&self) -> f32 { + self.nutrition + } + fn set_nutrition(&mut self, nutrition: f32) { + self.nutrition = nutrition; + } + fn get_oxygenation(&self) -> f32 { + self.oxygenation + } + fn set_oxygenation(&mut self, oxygenation: f32) { + self.oxygenation = oxygenation; + } + fn get_food_quality(&self) -> f32 { + self.food_quality + } + fn set_food_quality(&mut self, quality: f32) { + self.food_quality = quality; + } + fn get_mood(&self) -> f32 { + self.mood + } + fn set_mood(&mut self, mood: f32) { + self.mood = mood; + } + fn get_hygine(&self) -> f32 { + self.hygine + } + fn set_hygine(&mut self, hygine: f32) { + self.hygine = hygine; + } + fn is_artificial(&self) -> bool { + false + } + fn robot_battery(&self) -> Option { + None + } + fn suit_slot(&self) -> &Slot { + &self.suit_slot + } + fn suit_slot_mut(&mut self) -> &mut Slot { + &mut self.suit_slot + } + fn helmet_slot(&self) -> &Slot { + &self.helmet_slot + } + fn helmet_slot_mut(&mut self) -> &mut Slot { + &mut self.helmet_slot + } + fn glasses_slot(&self) -> &Slot { + &self.glasses_slot + } + fn glasses_slot_mut(&mut self) -> &mut Slot { + &mut self.glasses_slot + } + fn backpack_slot(&self) -> &Slot { + &self.backpack_slot + } + fn backpack_slot_mut(&mut self) -> &mut Slot { + &mut self.backpack_slot + } + fn uniform_slot(&self) -> &Slot { + &self.uniform_slot + } + fn uniform_slot_mut(&mut self) -> &mut Slot { + &mut self.uniform_slot + } + fn toolbelt_slot(&self) -> &Slot { + &self.toolbelt_slot + } + fn toolbelt_slot_mut(&mut self) -> &mut Slot { + &mut self.toolbelt_slot + } + fn left_hand_slot(&self) -> &Slot { + &self.left_hand_slot + } + fn left_hand_slot_mut(&mut self) -> &mut Slot { + &mut self.left_hand_slot + } + fn right_hand_slot(&self) -> &Slot { + &self.right_hand_slot + } + fn right_hand_slot_mut(&mut self) -> &mut Slot { + &mut self.right_hand_slot + } +} diff --git a/ic10emu/src/vm/object/macros.rs b/ic10emu/src/vm/object/macros.rs index 2712d3d..9a0f536 100644 --- a/ic10emu/src/vm/object/macros.rs +++ b/ic10emu/src/vm/object/macros.rs @@ -152,10 +152,49 @@ pub(crate) use object_trait; /// - `prefab` and `name` must be `crate::vm::object::Name` /// - `vm_ref` must be `std::rc::Rc` macro_rules! ObjectInterface { + { + @trt_cond_impl $trt:path => $trt_cond:path + } => { + paste::paste!{ + #[inline(always)] + fn [](&self) -> Option<[<$trt Ref>]> { + if $trt_cond(self) { + Some(self) + } else { + None + } + } + + #[inline(always)] + fn [](&mut self) -> Option<[<$trt RefMut>]> { + if $trt_cond(self) { + Some(self) + } else { + None + } + } + } + }; + { + @trt_cond_impl $trt:path + } => { + paste::paste!{ + #[inline(always)] + fn [](&self) -> Option<[<$trt Ref>]> { + Some(self) + } + + #[inline(always)] + fn [](&mut self) -> Option<[<$trt RefMut>]> { + Some(self) + } + } + + }; { @body_final @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; + @impls $($trt:path $([ $trt_cond:path ])?),*; @id $id_field:ident: $id_typ:ty; @prefab $prefab_field:ident: $prefab_typ:ty; @name $name_field:ident: $name_typ:ty; @@ -209,24 +248,16 @@ macro_rules! ObjectInterface { self } - paste::paste!{$( - #[inline(always)] - fn [](&self) -> Option<[<$trt Ref>]> { - Some(self) - } - - #[inline(always)] - fn [](&mut self) -> Option<[<$trt RefMut>]> { - Some(self) - } - )*} + $( + $crate::vm::object::macros::ObjectInterface!{@trt_cond_impl $trt $( => $trt_cond)? } + )* } }; { @body_final @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; + @impls $($trt:path $([ $trt_cond:path ])?),*; @id $id_field:ident: $id_typ:ty; @name $name_field:ident: $name_typ:ty; @prefab $prefab_field:ident: $prefab_typ:ty; @@ -235,7 +266,7 @@ macro_rules! ObjectInterface { $crate::vm::object::macros::ObjectInterface!{ @body_final @trt $trait_name; $struct; - @impls $($trt),*; + @impls $($trt $([ $trt_cond ])?),*; @id $id_field: $id_typ; @prefab $prefab_field: $prefab_typ; @name $name_field: $name_typ; @@ -245,7 +276,7 @@ macro_rules! ObjectInterface { { @body_final @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; + @impls $($trt:path $([ $trt_cond:path ])?),*; @prefab $prefab_field:ident: $prefab_typ:ty; @name $name_field:ident: $name_typ:ty; @id $id_field:ident: $id_typ:ty; @@ -254,7 +285,7 @@ macro_rules! ObjectInterface { $crate::vm::object::macros::ObjectInterface!{ @body_final @trt $trait_name; $struct; - @impls $($trt),*; + @impls $($trt $([ $trt_cond ])?),*; @id $id_field: $id_typ; @prefab $prefab_field: $prefab_typ; @name $name_field: $name_typ; @@ -264,7 +295,7 @@ macro_rules! ObjectInterface { { @body_final @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; + @impls $($trt:path $([ $trt_cond:path ])?),*; @prefab $prefab_field:ident: $prefab_typ:ty; @id $id_field:ident: $id_typ:ty; @name $name_field:ident: $name_typ:ty; @@ -273,7 +304,7 @@ macro_rules! ObjectInterface { $crate::vm::object::macros::ObjectInterface!{ @body_final @trt $trait_name; $struct; - @impls $($trt),*; + @impls $($trt $([ $trt_cond ])?),*; @id $id_field: $id_typ; @prefab $prefab_field: $prefab_typ; @name $name_field: $name_typ; @@ -283,7 +314,7 @@ macro_rules! ObjectInterface { { @body_final @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; + @impls $($trt:path $([ $trt_cond:path ])?),*; @name $name_field:ident: $name_typ:ty; @prefab $prefab_field:ident: $prefab_typ:ty; @id $id_field:ident: $id_typ:ty; @@ -292,7 +323,7 @@ macro_rules! ObjectInterface { $crate::vm::object::macros::ObjectInterface!{ @body_final @trt $trait_name; $struct; - @impls $($trt),*; + @impls $($trt $([ $trt_cond ])?),*; @id $id_field: $id_typ; @prefab $prefab_field: $prefab_typ; @name $name_field: $name_typ; @@ -302,7 +333,7 @@ macro_rules! ObjectInterface { { @body_final @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; + @impls $($trt:path $([ $trt_cond:path ])?),*; @name $name_field:ident: $name_typ:ty; @id $id_field:ident: $id_typ:ty; @prefab $prefab_field:ident: $prefab_typ:ty; @@ -311,7 +342,7 @@ macro_rules! ObjectInterface { $crate::vm::object::macros::ObjectInterface!{ @body_final @trt $trait_name; $struct; - @impls $($trt),*; + @impls $($trt $([ $trt_cond ])?),*; @id $id_field: $id_typ; @prefab $prefab_field: $prefab_typ; @name $name_field: $name_typ; @@ -320,7 +351,7 @@ macro_rules! ObjectInterface { };{ @body @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; + @impls $($trt:path $([ $trt_cond:path ])?),*; @tags { $(@$tag:tt $tag_field:ident: $tag_typ:ty;)* }; @@ -333,7 +364,7 @@ macro_rules! ObjectInterface { $crate::vm::object::macros::ObjectInterface!{ @body @trt $trait_name; $struct; - @impls $($trt),*; + @impls $($trt $([ $trt_cond ])?),*; @tags {$(@$tag $tag_field: $tag_typ;)* @vm_ref $vm_ref_field: $vm_ref_typ;}; $( $rest )* } @@ -341,7 +372,7 @@ macro_rules! ObjectInterface { { @body @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; + @impls $($trt:path $([ $trt_cond:path ])?),*; @tags { $(@$tag:tt $tag_field:ident: $tag_typ:ty;)* }; @@ -354,7 +385,7 @@ macro_rules! ObjectInterface { $crate::vm::object::macros::ObjectInterface!{ @body @trt $trait_name; $struct; - @impls $($trt),*; + @impls $($trt $([ $trt_cond ])?),*; @tags {$(@$tag $tag_field: $tag_typ;)* @name $name_field: $name_typ;}; $( $rest )* } @@ -362,7 +393,7 @@ macro_rules! ObjectInterface { { @body @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; + @impls $($trt:path $([ $trt_cond:path ])?),*; @tags { $(@$tag:tt $tag_field:ident: $tag_typ:ty;)* }; @@ -375,7 +406,7 @@ macro_rules! ObjectInterface { $crate::vm::object::macros::ObjectInterface!{ @body @trt $trait_name; $struct; - @impls $($trt),*; + @impls $($trt $([ $trt_cond ])?),*; @tags {$(@$tag $tag_field: $tag_typ;)* @prefab $prefab_field: $prefab_typ;}; $( $rest )* } @@ -383,7 +414,7 @@ macro_rules! ObjectInterface { { @body @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; + @impls $($trt:path $([ $trt_cond:path ])?),*; @tags { $(@$tag:tt $tag_field:ident: $tag_typ:ty;)* }; @@ -396,7 +427,7 @@ macro_rules! ObjectInterface { $crate::vm::object::macros::ObjectInterface!{ @body @trt $trait_name; $struct; - @impls $($trt),*; + @impls $($trt $([ $trt_cond ])?),*; @tags {$(@$tag $tag_field: $tag_typ;)* @id $id_field: $id_typ;}; $( $rest )* } @@ -404,7 +435,7 @@ macro_rules! ObjectInterface { { @body @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; + @impls $($trt:path $([ $trt_cond:path ])?),*; @tags { $(@$tag:tt $tag_field:ident: $tag_typ:ty;)* }; @@ -417,7 +448,7 @@ macro_rules! ObjectInterface { $crate::vm::object::macros::ObjectInterface!{ @body @trt $trait_name; $struct; - @impls $($trt),*; + @impls $($trt $([ $trt_cond ])?),*; @tags {$(@$tag $tag_field: $tag_typ;)*}; $( $rest )* } @@ -425,7 +456,7 @@ macro_rules! ObjectInterface { { @body @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; + @impls $($trt:path $([ $trt_cond:path ])?),*; @tags { $(@$tag:tt $tag_field:ident: $tag_typ:ty;)* }; @@ -433,14 +464,14 @@ macro_rules! ObjectInterface { $crate::vm::object::macros::ObjectInterface!{ @body_final @trt $trait_name; $struct; - @impls $($trt),*; + @impls $($trt $([ $trt_cond ])?),*; $( @$tag $tag_field: $tag_typ; )* } }; { - #[custom(implements($trait_name:ident {$($trt:path),*}))] + #[custom(implements($trait_name:ident {$($trt:path $([$trt_cond:path])?),*}))] $( #[$attr:meta] )* $viz:vis struct $struct:ident { $( $body:tt )* @@ -449,7 +480,7 @@ macro_rules! ObjectInterface { $crate::vm::object::macros::ObjectInterface!{ @body @trt $trait_name; $struct; - @impls $($trt),*; + @impls $($trt $([ $trt_cond ])?),*; @tags {}; $( $body )* } diff --git a/ic10emu/src/vm/object/stationpedia.rs b/ic10emu/src/vm/object/stationpedia.rs index 298464e..ec4419d 100644 --- a/ic10emu/src/vm/object/stationpedia.rs +++ b/ic10emu/src/vm/object/stationpedia.rs @@ -14,13 +14,15 @@ pub mod structs; #[allow(unused)] pub fn object_from_frozen(obj: &ObjectInfo, id: ObjectID, vm: &Rc) -> Option { - let hash = match obj.prefab { - Some(Prefab::Hash(hash)) => hash, + #[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, }; let prefab = StationpediaPrefab::from_repr(hash); + #[allow(clippy::match_single_binding)] match prefab { // Some(StationpediaPrefab::ItemIntegratedCircuit10) => { // Some(VMObject::new(structs::ItemIntegratedCircuit10)) diff --git a/ic10emu/src/vm/object/stationpedia/structs/circuit_holder.rs b/ic10emu/src/vm/object/stationpedia/structs/circuit_holder.rs index 5057ea1..71067ea 100644 --- a/ic10emu/src/vm/object/stationpedia/structs/circuit_holder.rs +++ b/ic10emu/src/vm/object/stationpedia/structs/circuit_holder.rs @@ -162,7 +162,7 @@ impl Logicable for StructureCircuitHousing { LogicType::ReferenceId => Ok(*self.get_id() as f64), LogicType::Error => Ok(self.error as f64), LogicType::LineNumber => { - let result = self.slot.occupant.and_then(|info| { + let result = self.slot.occupant.as_ref().and_then(|info| { self.vm.get_object(info.id).and_then(|obj| { obj.borrow() .as_logicable() @@ -207,6 +207,7 @@ impl Logicable for StructureCircuitHousing { LogicType::LineNumber => self .slot .occupant + .as_ref() .and_then(|info| { self.vm.get_object(info.id).and_then(|obj| { obj.borrow_mut().as_mut_logicable().map(|logicable| { @@ -404,11 +405,10 @@ impl CircuitHolder for StructureCircuitHousing { } fn get_ic(&self) -> Option { - self.slot.occupant.and_then(|info| self.vm.get_object(info.id)) - } - - fn get_ic_mut(&self) -> Option { - self.slot.occupant.and_then(|info| self.vm.get_object(info.id)) + self.slot + .occupant + .as_ref() + .and_then(|info| self.vm.get_object(info.id)) } fn hault_and_catch_fire(&mut self) { diff --git a/ic10emu/src/vm/object/templates.rs b/ic10emu/src/vm/object/templates.rs index 17ec12b..6f408b3 100644 --- a/ic10emu/src/vm/object/templates.rs +++ b/ic10emu/src/vm/object/templates.rs @@ -225,18 +225,19 @@ impl FrozenObject { } pub fn build_vm_obj(&self, id: ObjectID, vm: &Rc) -> Result { - let template = self.template.map_or_else( + let template = self.template.as_ref().map_or_else( || { self.obj_info .prefab + .as_ref() .map(|prefab| { - vm.get_template(prefab) - .ok_or(TemplateError::NoTemplateForPrefab(prefab)) + vm.get_template(prefab.clone()) + .ok_or(TemplateError::NoTemplateForPrefab(prefab.clone())) }) .transpose()? .ok_or(TemplateError::MissingPrefab) }, - |template| Ok(template), + |template| Ok(template.clone()), )?; if let Some(obj) = stationpedia::object_from_frozen(&self.obj_info, id, vm) { Ok(obj) @@ -248,6 +249,7 @@ impl FrozenObject { pub fn connected_networks(&self) -> Vec { self.obj_info .connections + .as_ref() .map(|connections| connections.values().copied().collect()) .unwrap_or_else(Vec::new) } @@ -255,6 +257,7 @@ impl FrozenObject { pub fn contained_object_ids(&self) -> Vec { self.obj_info .slots + .as_ref() .map(|slots| slots.values().map(|slot| slot.id).collect()) .unwrap_or_else(Vec::new) } @@ -262,6 +265,7 @@ impl FrozenObject { pub fn contained_object_slots(&self) -> Vec<(u32, ObjectID)> { self.obj_info .slots + .as_ref() .map(|slots| { slots .iter() @@ -316,6 +320,7 @@ impl FrozenObject { occupant: self .obj_info .slots + .as_ref() .and_then(|slots| slots.get(&(index as u32)).cloned()), }) .collect() @@ -569,7 +574,7 @@ impl FrozenObject { thermal_info: i.thermal_info.clone(), item_info: i.item.clone(), parent_slot: None, - damage: self.obj_info.damage.clone(), + damage: self.obj_info.damage, })), ItemSlots(i) => Ok(VMObject::new(GenericItemStorage { id, @@ -580,7 +585,7 @@ impl FrozenObject { thermal_info: i.thermal_info.clone(), item_info: i.item.clone(), parent_slot: None, - damage: self.obj_info.damage.clone(), + damage: self.obj_info.damage, slots: self.build_slots(id, &i.slots, None), })), ItemConsumer(i) => Ok(VMObject::new(GenericItemConsumer { @@ -592,7 +597,7 @@ impl FrozenObject { thermal_info: i.thermal_info.clone(), item_info: i.item.clone(), parent_slot: None, - damage: self.obj_info.damage.clone(), + damage: self.obj_info.damage, slots: self.build_slots(id, &i.slots, None), consumer_info: i.consumer_info.clone(), })), @@ -605,7 +610,7 @@ impl FrozenObject { thermal_info: i.thermal_info.clone(), item_info: i.item.clone(), parent_slot: None, - damage: self.obj_info.damage.clone(), + damage: self.obj_info.damage, slots: self.build_slots(id, &i.slots, Some(&i.logic)), fields: self.build_logic_fields(&i.logic), modes: i.logic.modes.clone(), @@ -620,7 +625,7 @@ impl FrozenObject { thermal_info: i.thermal_info.clone(), item_info: i.item.clone(), parent_slot: None, - damage: self.obj_info.damage.clone(), + damage: self.obj_info.damage, slots: self.build_slots(id, &i.slots, Some(&i.logic)), fields: self.build_logic_fields(&i.logic), modes: i.logic.modes.clone(), @@ -636,7 +641,7 @@ impl FrozenObject { thermal_info: i.thermal_info.clone(), item_info: i.item.clone(), parent_slot: None, - damage: self.obj_info.damage.clone(), + damage: self.obj_info.damage, slots: self.build_slots(id, &i.slots, Some(&i.logic)), fields: self.build_logic_fields(&i.logic), modes: i.logic.modes.clone(), @@ -651,7 +656,7 @@ impl FrozenObject { thermal_info: i.thermal_info.clone(), item_info: i.item.clone(), parent_slot: None, - damage: self.obj_info.damage.clone(), + damage: self.obj_info.damage, slots: self.build_slots(id, &i.slots, Some(&i.logic)), fields: self.build_logic_fields(&i.logic), modes: i.logic.modes.clone(), @@ -665,8 +670,9 @@ impl FrozenObject { thermal_info: i.thermal_info.clone(), item_info: i.item.clone(), parent_slot: None, - damage: self.obj_info.damage.clone(), + damage: self.obj_info.damage, slots: self.build_slots(id, &i.slots, None), + suit_info: i.suit_info.clone(), })), ItemSuitLogic(i) => Ok(VMObject::new(GenericItemSuitLogic { id, @@ -677,8 +683,9 @@ impl FrozenObject { thermal_info: i.thermal_info.clone(), item_info: i.item.clone(), parent_slot: None, - damage: self.obj_info.damage.clone(), + damage: self.obj_info.damage, slots: self.build_slots(id, &i.slots, Some(&i.logic)), + suit_info: i.suit_info.clone(), fields: self.build_logic_fields(&i.logic), modes: i.logic.modes.clone(), })), @@ -691,8 +698,9 @@ impl FrozenObject { thermal_info: i.thermal_info.clone(), item_info: i.item.clone(), parent_slot: None, - damage: self.obj_info.damage.clone(), + damage: self.obj_info.damage, slots: self.build_slots(id, &i.slots, Some(&i.logic)), + suit_info: i.suit_info.clone(), fields: self.build_logic_fields(&i.logic), modes: i.logic.modes.clone(), memory: self.build_memory(&i.memory), @@ -709,7 +717,7 @@ impl FrozenObject { let template = vm .get_template(Prefab::Hash(obj_ref.get_prefab().hash)) .map_or_else( - || Some(try_template_from_interfaces(interfaces, obj)), + || Some(try_template_from_interfaces(&interfaces, obj)), |_| None, ) .transpose()?; @@ -719,10 +727,10 @@ impl FrozenObject { } fn try_template_from_interfaces( - interfaces: ObjectInterfaces, + interfaces: &ObjectInterfaces, obj: &VMObject, ) -> Result { - match interfaces { + match *interfaces { ObjectInterfaces { structure: Some(structure), storage: None, @@ -747,6 +755,7 @@ fn try_template_from_interfaces( fabricator: None, internal_atmosphere, thermal, + human: None, } => { // completely generic structure? not sure how this got created but it technically // valid in the data model @@ -781,6 +790,7 @@ fn try_template_from_interfaces( fabricator: None, internal_atmosphere, thermal, + human: None, } => Ok(ObjectTemplate::StructureSlots(StructureSlotsTemplate { prefab: obj.into(), internal_atmo_info: internal_atmosphere.map(Into::into), @@ -812,6 +822,7 @@ fn try_template_from_interfaces( fabricator: None, internal_atmosphere, thermal, + human: None, } => Ok(ObjectTemplate::StructureLogic(StructureLogicTemplate { prefab: obj.into(), internal_atmo_info: internal_atmosphere.map(Into::into), @@ -844,6 +855,7 @@ fn try_template_from_interfaces( fabricator: None, internal_atmosphere, thermal, + human: None, } => Ok(ObjectTemplate::StructureLogicDevice( StructureLogicDeviceTemplate { prefab: obj.into(), @@ -879,6 +891,7 @@ fn try_template_from_interfaces( fabricator: None, internal_atmosphere, thermal, + human: None, } => Ok(ObjectTemplate::StructureLogicDeviceMemory( StructureLogicDeviceMemoryTemplate { prefab: obj.into(), @@ -917,6 +930,7 @@ fn try_template_from_interfaces( fabricator: None, internal_atmosphere, thermal, + human: None, } => Ok(ObjectTemplate::Item(ItemTemplate { prefab: obj.into(), internal_atmo_info: internal_atmosphere.map(Into::into), @@ -947,6 +961,7 @@ fn try_template_from_interfaces( fabricator: None, internal_atmosphere, thermal, + human: None, } => Ok(ObjectTemplate::ItemSlots(ItemSlotsTemplate { prefab: obj.into(), internal_atmo_info: internal_atmosphere.map(Into::into), @@ -978,6 +993,7 @@ fn try_template_from_interfaces( fabricator: None, internal_atmosphere, thermal, + human: None, } => Ok(ObjectTemplate::ItemLogic(ItemLogicTemplate { prefab: obj.into(), internal_atmo_info: internal_atmosphere.map(Into::into), @@ -1010,6 +1026,7 @@ fn try_template_from_interfaces( fabricator: None, internal_atmosphere, thermal, + human: None, } => Ok(ObjectTemplate::ItemLogicMemory(ItemLogicMemoryTemplate { prefab: obj.into(), internal_atmo_info: internal_atmosphere.map(Into::into), diff --git a/ic10emu/src/vm/object/traits.rs b/ic10emu/src/vm/object/traits.rs index 3ac453a..9355dd0 100644 --- a/ic10emu/src/vm/object/traits.rs +++ b/ic10emu/src/vm/object/traits.rs @@ -99,7 +99,6 @@ tag_object_traits! { connection: Option, ) -> Option; fn get_ic(&self) -> Option; - fn get_ic_mut(&self) -> Option; fn hault_and_catch_fire(&mut self); } @@ -115,6 +114,20 @@ tag_object_traits! { fn set_parent_slot(&mut self, info: Option); fn get_damage(&self) -> f32; fn set_damage(&mut self, damage: f32); + fn root_parent_human(&self) -> Option { + self.get_parent_slot().and_then(|info| { + if let Some(obj) = self.get_vm().get_object(info.parent) { + if obj.borrow().as_human().is_some() { + return Some(obj); + } + let obj_ref = obj.borrow(); + if let Some(item) = obj_ref.as_item() { + return item.root_parent_human() + } + } + None + }) + } } pub trait Plant { @@ -125,7 +138,7 @@ tag_object_traits! { fn is_seeding(&self) -> bool; } - pub trait Suit { + pub trait Suit: Item + Storage { fn pressure_waste(&self) -> f32; fn pressure_waste_max(&self) -> f32; fn pressure_air(&self) -> f32; @@ -256,6 +269,45 @@ tag_object_traits! { fn get_channel_data(&self) -> &[f64; 8]; } + 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_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 get_hydration(&self) -> f32; + fn set_hydration(&mut self, hydration: f32); + fn get_oxygenation(&self) -> f32; + fn set_oxygenation(&mut self, oxygenation: f32); + fn is_artificial(&self) -> bool; + fn robot_battery(&self) -> Option; + fn suit_slot(&self) -> &Slot; + fn suit_slot_mut(&mut self) -> &mut Slot; + fn helmet_slot(&self) -> &Slot; + fn helmet_slot_mut(&mut self) -> &mut Slot; + fn glasses_slot(&self) -> &Slot; + fn glasses_slot_mut(&mut self) -> &mut Slot; + fn backpack_slot(&self) -> &Slot; + fn backpack_slot_mut(&mut self) -> &mut Slot; + fn left_hand_slot(&self) -> &Slot; + fn left_hand_slot_mut(&mut self) -> &mut Slot; + fn right_hand_slot(&self) -> &Slot; + fn right_hand_slot_mut(&mut self) -> &mut Slot; + fn uniform_slot(&self) -> &Slot; + fn uniform_slot_mut(&mut self) -> &mut Slot; + fn toolbelt_slot(&self) -> &Slot; + fn toolbelt_slot_mut(&mut self) -> &mut Slot; + } + } impl Debug for dyn Object {