refactor(vm): generic circuit holder + suit impl
This commit is contained in:
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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??
|
||||
}
|
||||
}
|
||||
|
||||
219
ic10emu/src/vm/object/humans.rs
Normal file
219
ic10emu/src/vm/object/humans.rs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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 )*
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user