refactor(vm): generic circuit holder + suit impl

This commit is contained in:
Rachel Powers
2024-05-26 00:54:19 -07:00
parent 24778b21b7
commit d70d3a2431
12 changed files with 1302 additions and 120 deletions

View File

@@ -139,7 +139,7 @@ impl Connection {
pub fn get_network(&self) -> Option<ObjectID> {
match self {
Self::CableNetwork { net, .. } => net.clone(),
Self::CableNetwork { net, .. } => *net,
_ => None,
}
}

View File

@@ -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(())
}

View File

@@ -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<LogicSlotType>,
pub occupant: Option<SlotOccupantInfo>,
}
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,
}
}
}

View File

@@ -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;

View File

@@ -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<Slot>,
}
#[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<BTreeMap<u32, String>>,
}
#[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<BTreeMap<i32, f64>>,
}
#[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<BTreeMap<i32, f64>>,
}
#[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<f64>,
}
#[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<f64>,
}
#[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<f64>,
}
#[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<f64>,
}
#[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<f32>,
}
#[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<Slot>,
}
#[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<BTreeMap<u32, String>>,
}
#[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<f64>,
}
#[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<f64>,
}
#[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<BTreeMap<u32, String>>,
}
#[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<ParentSlotInfo>,
pub damage: Option<f32>,
pub slots: Vec<Slot>,
pub suit_info: SuitInfo,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
}
#[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<ParentSlotInfo>,
pub damage: Option<f32>,
pub slots: Vec<Slot>,
pub suit_info: SuitInfo,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
pub memory: Vec<f64>,
}
#[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<ParentSlotInfo>,
pub damage: Option<f32>,
pub slots: Vec<Slot>,
pub suit_info: SuitInfo,
}

View File

@@ -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<T: GWThermal + Object> 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<T: GWInternalAtmo + Object> 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<T: GWLogicable + Object> 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<T: GWDevice + GWStorage + Object> 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<T: GWItem + Object> Item for T {
}
}
pub trait GWCircuitHolder: Logicable {}
pub trait GWSuit: Storage {
fn suit_info(&self) -> &SuitInfo;
}
impl<T: GWSuit + Item + Object> 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<T: GWCircuitHolder, H = <T as GWCircuitHolder>::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<usize>,
) -> Option<ObjectRef>;
/// i32::MAX is db
fn get_logicable_from_index_mut_gw(
&mut self,
device: i32,
connection: Option<usize>,
) -> Option<ObjectRefMut>;
fn get_logicable_from_id_gw(
&self,
device: ObjectID,
connection: Option<usize>,
) -> Option<ObjectRef>;
fn get_logicable_from_id_mut_gw(
&mut self,
device: ObjectID,
connection: Option<usize>,
) -> Option<ObjectRefMut>;
fn get_ic_gw(&self) -> Option<VMObject>;
fn hault_and_catch_fire_gw(&mut self);
}
impl<T> CircuitHolder for T
where
T: GWCircuitHolder,
Self: GWCircuitHolderWrapper<T>,
{
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<usize>,
) -> Option<ObjectRef> {
self.get_logicable_from_index_gw(device, connection)
}
/// i32::MAX is db
fn get_logicable_from_index_mut(
&mut self,
device: i32,
connection: Option<usize>,
) -> Option<ObjectRefMut> {
self.get_logicable_from_index_mut_gw(device, connection)
}
fn get_logicable_from_id(
&self,
device: ObjectID,
connection: Option<usize>,
) -> Option<ObjectRef> {
self.get_logicable_from_id_gw(device, connection)
}
fn get_logicable_from_id_mut(
&mut self,
device: ObjectID,
connection: Option<usize>,
) -> Option<ObjectRefMut> {
self.get_logicable_from_id_mut_gw(device, connection)
}
fn get_ic(&self) -> Option<VMObject> {
self.get_ic_gw()
}
fn hault_and_catch_fire(&mut self) {
self.hault_and_catch_fire_gw()
}
}
impl<T> GWCircuitHolderWrapper<T, DeviceCircuitHolder> for T
where
T: GWCircuitHolder<Holder = DeviceCircuitHolder> + 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<usize>,
) -> Option<ObjectRef> {
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<usize>,
) -> Option<ObjectRefMut> {
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<usize>,
) -> Option<ObjectRef> {
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<usize>,
) -> Option<ObjectRefMut> {
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<crate::vm::object::VMObject> {
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<T> GWCircuitHolderWrapper<T, SuitCircuitHolder> for T
where
T: GWCircuitHolder<Holder = SuitCircuitHolder> + 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<usize>,
) -> Option<ObjectRef> {
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<usize>,
) -> Option<ObjectRefMut> {
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<usize>,
) -> Option<ObjectRef> {
if device == *self.get_id() {
return Some(ObjectRef::from_ref(self.as_object()));
}
let contained_ids: Vec<ObjectID> = 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<usize>,
) -> Option<ObjectRefMut> {
if device == *self.get_id() {
return Some(ObjectRefMut::from_ref(self.as_mut_object()));
}
let contained_ids: Vec<ObjectID> = 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<crate::vm::object::VMObject> {
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<T> GWCircuitHolderWrapper<T, ItemCircuitHolder> for T
where
T: GWCircuitHolder<Holder = ItemCircuitHolder> + 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<usize>,
) -> Option<ObjectRef> {
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<usize>,
) -> Option<ObjectRefMut> {
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<usize>,
) -> Option<ObjectRef> {
if device == *self.get_id() {
return Some(ObjectRef::from_ref(self.as_object()));
}
let contained_ids: Vec<ObjectID> = 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<usize>,
) -> Option<ObjectRefMut> {
if device == *self.get_id() {
return Some(ObjectRefMut::from_ref(self.as_mut_object()));
}
let contained_ids: Vec<ObjectID> = 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<crate::vm::object::VMObject> {
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??
}
}

View File

@@ -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<VM>,
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<VM>) -> 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<super::VMObject> {
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
}
}

View File

@@ -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<crate::vm::VM>`
macro_rules! ObjectInterface {
{
@trt_cond_impl $trt:path => $trt_cond:path
} => {
paste::paste!{
#[inline(always)]
fn [<as_ $trt:snake>](&self) -> Option<[<$trt Ref>]> {
if $trt_cond(self) {
Some(self)
} else {
None
}
}
#[inline(always)]
fn [<as_mut_ $trt:snake>](&mut self) -> Option<[<$trt RefMut>]> {
if $trt_cond(self) {
Some(self)
} else {
None
}
}
}
};
{
@trt_cond_impl $trt:path
} => {
paste::paste!{
#[inline(always)]
fn [<as_ $trt:snake>](&self) -> Option<[<$trt Ref>]> {
Some(self)
}
#[inline(always)]
fn [<as_mut_ $trt:snake>](&mut self) -> Option<[<$trt RefMut>]> {
Some(self)
}
}
};
{
@body_final
@trt $trait_name:ident; $struct:ident;
@impls $($trt:path),*;
@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 [<as_ $trt:snake>](&self) -> Option<[<$trt Ref>]> {
Some(self)
}
#[inline(always)]
fn [<as_mut_ $trt:snake>](&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 )*
}

View File

@@ -14,13 +14,15 @@ pub mod structs;
#[allow(unused)]
pub fn object_from_frozen(obj: &ObjectInfo, id: ObjectID, vm: &Rc<VM>) -> Option<VMObject> {
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))

View File

@@ -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<VMObject> {
self.slot.occupant.and_then(|info| self.vm.get_object(info.id))
}
fn get_ic_mut(&self) -> Option<VMObject> {
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) {

View File

@@ -225,18 +225,19 @@ impl FrozenObject {
}
pub fn build_vm_obj(&self, id: ObjectID, vm: &Rc<VM>) -> Result<VMObject, TemplateError> {
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<ObjectID> {
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<ObjectID> {
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<ObjectTemplate, TemplateError> {
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),

View File

@@ -99,7 +99,6 @@ tag_object_traits! {
connection: Option<usize>,
) -> Option<ObjectRefMut>;
fn get_ic(&self) -> Option<VMObject>;
fn get_ic_mut(&self) -> Option<VMObject>;
fn hault_and_catch_fire(&mut self);
}
@@ -115,6 +114,20 @@ tag_object_traits! {
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>);
fn get_damage(&self) -> f32;
fn set_damage(&mut self, damage: f32);
fn root_parent_human(&self) -> Option<VMObject> {
self.get_parent_slot().and_then(|info| {
if let Some(obj) = self.get_vm().get_object(info.parent) {
if obj.borrow().as_human().is_some() {
return Some(obj);
}
let obj_ref = obj.borrow();
if let Some(item) = obj_ref.as_item() {
return item.root_parent_human()
}
}
None
})
}
}
pub trait Plant {
@@ -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<VMObject>;
fn suit_slot(&self) -> &Slot;
fn suit_slot_mut(&mut self) -> &mut Slot;
fn helmet_slot(&self) -> &Slot;
fn helmet_slot_mut(&mut self) -> &mut Slot;
fn glasses_slot(&self) -> &Slot;
fn glasses_slot_mut(&mut self) -> &mut Slot;
fn backpack_slot(&self) -> &Slot;
fn backpack_slot_mut(&mut self) -> &mut Slot;
fn left_hand_slot(&self) -> &Slot;
fn left_hand_slot_mut(&mut self) -> &mut Slot;
fn right_hand_slot(&self) -> &Slot;
fn right_hand_slot_mut(&mut self) -> &mut Slot;
fn uniform_slot(&self) -> &Slot;
fn uniform_slot_mut(&mut self) -> &mut Slot;
fn toolbelt_slot(&self) -> &Slot;
fn toolbelt_slot_mut(&mut self) -> &mut Slot;
}
}
impl Debug for dyn Object {