diff --git a/Content.Server/Body/BodyPart.cs b/Content.Server/Body/BodyPart.cs index acd984af53..b176118af4 100644 --- a/Content.Server/Body/BodyPart.cs +++ b/Content.Server/Body/BodyPart.cs @@ -36,7 +36,7 @@ namespace Content.Server.Body { private IBodyManagerComponent? _body; - private readonly HashSet _mechanisms = new HashSet(); + private readonly HashSet _mechanisms = new HashSet(); public BodyPart(BodyPartPrototype data) { @@ -146,11 +146,11 @@ namespace Content.Server.Body public BodyPartCompatibility Compatibility { get; private set; } /// - /// Set of all currently inside this + /// Set of all currently inside this /// . /// [ViewVariables] - public IReadOnlyCollection Mechanisms => _mechanisms; + public IReadOnlyCollection Mechanisms => _mechanisms; /// /// This method is called by @@ -258,7 +258,7 @@ namespace Content.Server.Body return SurgeryData.CanAttachBodyPart(part); } - public bool CanInstallMechanism(Mechanism mechanism) + public bool CanInstallMechanism(IMechanism mechanism) { return SizeUsed + mechanism.Size <= Size && SurgeryData.CanInstallMechanism(mechanism); @@ -275,7 +275,7 @@ namespace Content.Server.Body /// True if successful, false if there was an error /// (e.g. not enough room in ). /// - private bool TryInstallMechanism(Mechanism mechanism) + private bool TryInstallMechanism(IMechanism mechanism) { if (!CanInstallMechanism(mechanism)) { @@ -308,7 +308,7 @@ namespace Content.Server.Body return true; } - public bool TryDropMechanism(IEntity dropLocation, Mechanism mechanismTarget, + public bool TryDropMechanism(IEntity dropLocation, IMechanism mechanismTarget, [NotNullWhen(true)] out DroppedMechanismComponent dropped) { dropped = null!; @@ -331,16 +331,16 @@ namespace Content.Server.Body } /// - /// Tries to destroy the given in this + /// Tries to destroy the given in this /// . Does NOT spawn a dropped entity. /// /// - /// Tries to destroy the given in this + /// Tries to destroy the given in this /// . /// /// The mechanism to destroy. /// True if successful, false otherwise. - public bool DestroyMechanism(Mechanism mechanismTarget) + public bool DestroyMechanism(IMechanism mechanismTarget) { if (!RemoveMechanism(mechanismTarget)) { @@ -365,7 +365,7 @@ namespace Content.Server.Body return SurgeryData.PerformSurgery(toolType, target, surgeon, performer); } - private void AddMechanism(Mechanism mechanism) + private void AddMechanism(IMechanism mechanism) { DebugTools.AssertNotNull(mechanism); @@ -402,7 +402,7 @@ namespace Content.Server.Body /// /// The mechanism to remove. /// True if it was removed, false otherwise. - private bool RemoveMechanism(Mechanism mechanism) + private bool RemoveMechanism(IMechanism mechanism) { DebugTools.AssertNotNull(mechanism); diff --git a/Content.Server/Body/IBodyPart.cs b/Content.Server/Body/IBodyPart.cs index 12859fcdf7..19d1ae9123 100644 --- a/Content.Server/Body/IBodyPart.cs +++ b/Content.Server/Body/IBodyPart.cs @@ -54,12 +54,12 @@ namespace Content.Server.Body int CurrentDurability { get; } /// - /// Collection of all s currently inside this + /// Collection of all s currently inside this /// . /// To add and remove from this list see and /// /// - IReadOnlyCollection Mechanisms { get; } + IReadOnlyCollection Mechanisms { get; } /// /// Path to the RSI that represents this . @@ -109,23 +109,23 @@ namespace Content.Server.Body bool CanAttachPart(IBodyPart part); /// - /// Checks if a can be installed on this + /// Checks if a can be installed on this /// . /// /// True if it can be installed, false otherwise. - bool CanInstallMechanism(Mechanism mechanism); + bool CanInstallMechanism(IMechanism mechanism); /// - /// Tries to remove the given reference from + /// Tries to remove the given reference from /// this . /// /// /// The newly spawned , or null /// if there was an error in spawning the entity or removing the mechanism. /// - bool TryDropMechanism(IEntity dropLocation, Mechanism mechanismTarget, + bool TryDropMechanism(IEntity dropLocation, IMechanism mechanismTarget, [NotNullWhen(true)] out DroppedMechanismComponent dropped); - bool DestroyMechanism(Mechanism mechanism); + bool DestroyMechanism(IMechanism mechanism); } } diff --git a/Content.Server/Body/Mechanisms/IMechanism.cs b/Content.Server/Body/Mechanisms/IMechanism.cs new file mode 100644 index 0000000000..9037c0f4e9 --- /dev/null +++ b/Content.Server/Body/Mechanisms/IMechanism.cs @@ -0,0 +1,103 @@ +#nullable enable +using System.Collections.Generic; +using Content.Server.Body.Mechanisms.Behaviors; +using Content.Server.GameObjects.Components.Body; +using Content.Shared.GameObjects.Components.Body; + +namespace Content.Server.Body.Mechanisms +{ + public interface IMechanism + { + string Id { get; } + + string Name { get; set; } + + /// + /// Professional description of the . + /// + string Description { get; set; } + + /// + /// The message to display upon examining a mob with this Mechanism installed. + /// If the string is empty (""), no message will be displayed. + /// + string ExamineMessage { get; set; } + + // TODO: Make RSI properties sane + /// + /// Path to the RSI that represents this . + /// + string RSIPath { get; set; } + + /// + /// RSI state that represents this . + /// + string RSIState { get; set; } + + /// + /// Max HP of this . + /// + int MaxDurability { get; set; } + + /// + /// Current HP of this . + /// + int CurrentDurability { get; set; } + + /// + /// At what HP this is completely destroyed. + /// + int DestroyThreshold { get; set; } + + /// + /// Armor of this against attacks. + /// + int Resistance { get; set; } + + /// + /// Determines a handful of things - mostly whether this + /// can fit into a . + /// + // TODO: OnSizeChanged + int Size { get; set; } + + /// + /// What kind of this can be + /// easily installed into. + /// + BodyPartCompatibility Compatibility { get; set; } + + IReadOnlyList Behaviors { get; } + + IBodyManagerComponent? Body { get; } + + IBodyPart? Part { get; set; } + + void EnsureInitialize(); + + void InstalledIntoBody(); + + void RemovedFromBody(IBodyManagerComponent old); + + /// + /// This method is called by before + /// is called. + /// + void PreMetabolism(float frameTime); + + /// + /// This method is called by after + /// is called. + /// + void PostMetabolism(float frameTime); + + void AddBehavior(MechanismBehavior behavior); + + /// + /// Removes a behavior from this mechanism. + /// + /// The behavior to remove. + /// True if it was removed, false otherwise. + bool RemoveBehavior(MechanismBehavior behavior); + } +} diff --git a/Content.Server/Body/Mechanisms/Mechanism.cs b/Content.Server/Body/Mechanisms/Mechanism.cs index 1dfaf0ee67..9b7a254155 100644 --- a/Content.Server/Body/Mechanisms/Mechanism.cs +++ b/Content.Server/Body/Mechanisms/Mechanism.cs @@ -16,7 +16,7 @@ namespace Content.Server.Body.Mechanisms /// This includes livers, eyes, cameras, brains, explosive implants, /// binary communicators, and other things. /// - public class Mechanism + public class Mechanism : IMechanism { private IBodyPart? _part; @@ -29,7 +29,7 @@ namespace Content.Server.Body.Mechanisms ExamineMessage = null!; RSIPath = null!; RSIState = null!; - Behaviors = new List(); + _behaviors = new List(); } [ViewVariables] private bool Initialized { get; set; } @@ -40,74 +40,29 @@ namespace Content.Server.Body.Mechanisms [ViewVariables] public string Name { get; set; } - /// - /// Professional description of the . - /// - [ViewVariables] - public string Description { get; set; } + [ViewVariables] public string Description { get; set; } - /// - /// The message to display upon examining a mob with this Mechanism installed. - /// If the string is empty (""), no message will be displayed. - /// - [ViewVariables] - public string ExamineMessage { get; set; } + [ViewVariables] public string ExamineMessage { get; set; } - /// - /// Path to the RSI that represents this . - /// - [ViewVariables] - public string RSIPath { get; set; } + [ViewVariables] public string RSIPath { get; set; } - /// - /// RSI state that represents this . - /// - [ViewVariables] - public string RSIState { get; set; } + [ViewVariables] public string RSIState { get; set; } - /// - /// Max HP of this . - /// - [ViewVariables] - public int MaxDurability { get; set; } + [ViewVariables] public int MaxDurability { get; set; } - /// - /// Current HP of this . - /// - [ViewVariables] - public int CurrentDurability { get; set; } + [ViewVariables] public int CurrentDurability { get; set; } - /// - /// At what HP this is completely destroyed. - /// - [ViewVariables] - public int DestroyThreshold { get; set; } + [ViewVariables] public int DestroyThreshold { get; set; } - /// - /// Armor of this against attacks. - /// - [ViewVariables] - public int Resistance { get; set; } + [ViewVariables] public int Resistance { get; set; } - /// - /// Determines a handful of things - mostly whether this - /// can fit into a . - /// - [ViewVariables] - public int Size { get; set; } + [ViewVariables] public int Size { get; set; } - /// - /// What kind of this can be - /// easily installed into. - /// - [ViewVariables] - public BodyPartCompatibility Compatibility { get; set; } + [ViewVariables] public BodyPartCompatibility Compatibility { get; set; } - /// - /// The behaviors that this performs. - /// - [ViewVariables] - private List Behaviors { get; } + private readonly List _behaviors; + + [ViewVariables] public IReadOnlyList Behaviors => _behaviors; public IBodyManagerComponent? Body => Part?.Body; @@ -167,7 +122,7 @@ namespace Content.Server.Body.Mechanisms Size = data.Size; Compatibility = data.Compatibility; - foreach (var behavior in Behaviors.ToArray()) + foreach (var behavior in _behaviors.ToArray()) { RemoveBehavior(behavior); } @@ -210,10 +165,6 @@ namespace Content.Server.Body.Mechanisms } } - /// - /// This method is called by before - /// is called. - /// public void PreMetabolism(float frameTime) { foreach (var behavior in Behaviors) @@ -222,10 +173,6 @@ namespace Content.Server.Body.Mechanisms } } - /// - /// This method is called by after - /// is called. - /// public void PostMetabolism(float frameTime) { foreach (var behavior in Behaviors) @@ -234,16 +181,21 @@ namespace Content.Server.Body.Mechanisms } } - private void AddBehavior(MechanismBehavior behavior) + public void AddBehavior(MechanismBehavior behavior) { - Behaviors.Add(behavior); + _behaviors.Add(behavior); behavior.Initialize(this); } - private bool RemoveBehavior(MechanismBehavior behavior) + public bool RemoveBehavior(MechanismBehavior behavior) { - behavior.Remove(); - return Behaviors.Remove(behavior); + if (_behaviors.Remove(behavior)) + { + behavior.Remove(); + return true; + } + + return false; } } } diff --git a/Content.Server/Body/Surgery/BiologicalSurgeryData.cs b/Content.Server/Body/Surgery/BiologicalSurgeryData.cs index fb8769f116..30cbd2a56b 100644 --- a/Content.Server/Body/Surgery/BiologicalSurgeryData.cs +++ b/Content.Server/Body/Surgery/BiologicalSurgeryData.cs @@ -17,7 +17,7 @@ namespace Content.Server.Body.Surgery [UsedImplicitly] public class BiologicalSurgeryData : SurgeryData { - private readonly List _disconnectedOrgans = new List(); + private readonly List _disconnectedOrgans = new List(); private bool _skinOpened; private bool _skinRetracted; @@ -118,7 +118,7 @@ namespace Content.Server.Body.Surgery return toReturn; } - public override bool CanInstallMechanism(Mechanism mechanism) + public override bool CanInstallMechanism(IMechanism mechanism) { return _skinOpened && _vesselsClamped && _skinRetracted; } @@ -170,7 +170,7 @@ namespace Content.Server.Body.Surgery return; } - var toSend = new List(); + var toSend = new List(); foreach (var mechanism in Parent.Mechanisms) { if (!_disconnectedOrgans.Contains(mechanism)) @@ -185,7 +185,7 @@ namespace Content.Server.Body.Surgery } } - private void LoosenOrganSurgeryCallback(Mechanism target, IBodyPartContainer container, ISurgeon surgeon, + private void LoosenOrganSurgeryCallback(IMechanism target, IBodyPartContainer container, ISurgeon surgeon, IEntity performer) { if (target == null || !Parent.Mechanisms.Contains(target)) @@ -216,7 +216,7 @@ namespace Content.Server.Body.Surgery } } - private void RemoveOrganSurgeryCallback(Mechanism target, IBodyPartContainer container, ISurgeon surgeon, + private void RemoveOrganSurgeryCallback(IMechanism target, IBodyPartContainer container, ISurgeon surgeon, IEntity performer) { if (target == null || !Parent.Mechanisms.Contains(target)) diff --git a/Content.Server/Body/Surgery/ISurgeon.cs b/Content.Server/Body/Surgery/ISurgeon.cs index be2ed1135c..b15a2ae112 100644 --- a/Content.Server/Body/Surgery/ISurgeon.cs +++ b/Content.Server/Body/Surgery/ISurgeon.cs @@ -13,7 +13,7 @@ namespace Content.Server.Body.Surgery public interface ISurgeon { public delegate void MechanismRequestCallback( - Mechanism target, + IMechanism target, IBodyPartContainer container, ISurgeon surgeon, IEntity performer); @@ -29,6 +29,6 @@ namespace Content.Server.Body.Surgery /// This function is called in that scenario, and it is expected that you call the callback with one mechanism from the /// provided list. /// - public void RequestMechanism(IEnumerable options, MechanismRequestCallback callback); + public void RequestMechanism(IEnumerable options, MechanismRequestCallback callback); } } diff --git a/Content.Server/Body/Surgery/SurgeryData.cs b/Content.Server/Body/Surgery/SurgeryData.cs index 48b7d265da..1a0eec454f 100644 --- a/Content.Server/Body/Surgery/SurgeryData.cs +++ b/Content.Server/Body/Surgery/SurgeryData.cs @@ -38,10 +38,10 @@ namespace Content.Server.Body.Surgery public abstract string GetDescription(IEntity target); /// - /// Returns whether a can be installed into the + /// Returns whether a can be installed into the /// this represents. /// - public abstract bool CanInstallMechanism(Mechanism mechanism); + public abstract bool CanInstallMechanism(IMechanism mechanism); /// /// Returns whether the given can be connected to the diff --git a/Content.Server/GameObjects/Components/Body/DroppedMechanismComponent.cs b/Content.Server/GameObjects/Components/Body/DroppedMechanismComponent.cs index bc79929d38..4c16cc9b7d 100644 --- a/Content.Server/GameObjects/Components/Body/DroppedMechanismComponent.cs +++ b/Content.Server/GameObjects/Components/Body/DroppedMechanismComponent.cs @@ -40,7 +40,7 @@ namespace Content.Server.GameObjects.Components.Body private IEntity? _performerCache; - [ViewVariables] public Mechanism ContainedMechanism { get; private set; } = default!; + [ViewVariables] public IMechanism ContainedMechanism { get; private set; } = default!; [ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(GenericSurgeryUiKey.Key); @@ -81,7 +81,7 @@ namespace Content.Server.GameObjects.Components.Body } } - public void InitializeDroppedMechanism(Mechanism data) + public void InitializeDroppedMechanism(IMechanism data) { ContainedMechanism = data; Owner.Name = Loc.GetString(ContainedMechanism.Name); diff --git a/Content.Server/GameObjects/Components/Body/SurgeryToolComponent.cs b/Content.Server/GameObjects/Components/Body/SurgeryToolComponent.cs index 35057f7381..0a5d5136f7 100644 --- a/Content.Server/GameObjects/Components/Body/SurgeryToolComponent.cs +++ b/Content.Server/GameObjects/Components/Body/SurgeryToolComponent.cs @@ -128,7 +128,7 @@ namespace Content.Server.GameObjects.Components.Body public float BaseOperationTime { get => _baseOperateTime; set => _baseOperateTime = value; } - public void RequestMechanism(IEnumerable options, ISurgeon.MechanismRequestCallback callback) + public void RequestMechanism(IEnumerable options, ISurgeon.MechanismRequestCallback callback) { var toSend = new Dictionary(); foreach (var mechanism in options) @@ -230,7 +230,7 @@ namespace Content.Server.GameObjects.Components.Body /// /// Called after the client chooses from a list of possible - /// to choose from. + /// to choose from. /// private void HandleReceiveMechanism(int key) { @@ -251,23 +251,13 @@ namespace Content.Server.GameObjects.Components.Body private void SendNoUsefulWayToUsePopup() { - if (_bodyManagerComponentCache == null) - { - return; - } - - _bodyManagerComponentCache.Owner.PopupMessage(_performerCache, + _bodyManagerComponentCache?.Owner.PopupMessage(_performerCache, Loc.GetString("You see no useful way to use {0:theName}.", Owner)); } private void SendNoUsefulWayToUseAnymorePopup() { - if (_bodyManagerComponentCache == null) - { - return; - } - - _bodyManagerComponentCache.Owner.PopupMessage(_performerCache, + _bodyManagerComponentCache?.Owner.PopupMessage(_performerCache, Loc.GetString("You see no useful way to use {0:theName} anymore.", Owner)); }