Remove IBody, IBodyPart, IMechanism and IMechanismBehavior (#4187)

* Remove IBody, IBodyPart, IMechanism and IMechanismBehavior interfaces

* Summary cleanup
This commit is contained in:
DrSmugleaf
2021-06-16 16:44:38 +02:00
committed by GitHub
parent 7cbfbad578
commit 69969bbdc6
72 changed files with 508 additions and 1142 deletions

View File

@@ -5,7 +5,7 @@ using Robust.Shared.GameObjects;
namespace Content.Client.Body.Components
{
[RegisterComponent]
[ComponentReference(typeof(IBody))]
[ComponentReference(typeof(SharedBodyComponent))]
public class BodyComponent : SharedBodyComponent, IDraggable
{
bool IDraggable.CanStartDrag(StartDragDropEvent args)

View File

@@ -5,7 +5,6 @@ namespace Content.Client.Body.Components
{
[RegisterComponent]
[ComponentReference(typeof(SharedBodyPartComponent))]
[ComponentReference(typeof(IBodyPart))]
public class BodyPartComponent : SharedBodyPartComponent
{
}

View File

@@ -5,6 +5,7 @@ namespace Content.Client.Body.Components
{
[RegisterComponent]
[ComponentReference(typeof(SharedMechanismComponent))]
[ComponentReference(typeof(IMechanism))]
public class MechanismComponent : SharedMechanismComponent { }
public class MechanismComponent : SharedMechanismComponent
{
}
}

View File

@@ -15,9 +15,9 @@ namespace Content.Client.Body.UI
public sealed class BodyScannerDisplay : SS14Window
{
private IEntity? _currentEntity;
private IBodyPart? _currentBodyPart;
private SharedBodyPartComponent? _currentBodyPart;
private IBody? CurrentBody => _currentEntity?.GetComponentOrNull<IBody>();
private SharedBodyComponent? CurrentBody => _currentEntity?.GetComponentOrNull<SharedBodyComponent>();
public BodyScannerDisplay(BodyScannerBoundUserInterface owner)
{
@@ -137,7 +137,7 @@ namespace Content.Client.Body.UI
}
}
private void UpdateBodyPartBox(IBodyPart part, string slotName)
private void UpdateBodyPartBox(SharedBodyPartComponent part, string slotName)
{
BodyPartLabel.Text = $"{Loc.GetString(slotName)}: {Loc.GetString(part.Owner.Name)}";
@@ -161,7 +161,7 @@ namespace Content.Client.Body.UI
UpdateMechanismBox(_currentBodyPart?.Mechanisms.ElementAt(args.ItemIndex));
}
private void UpdateMechanismBox(IMechanism? mechanism)
private void UpdateMechanismBox(SharedMechanismComponent? mechanism)
{
// TODO BODY Improve UI
if (mechanism == null)

View File

@@ -52,7 +52,7 @@ namespace Content.Client.CharacterAppearance
return;
}
if (Owner.TryGetComponent(out IBody? body))
if (Owner.TryGetComponent(out SharedBodyComponent? body))
{
foreach (var (part, _) in body.Parts)
{
@@ -115,7 +115,7 @@ namespace Content.Client.CharacterAppearance
return;
}
if (!args.Part.Owner.TryGetComponent(out SpriteComponent? partSprite))
if (!args.Part.Owner.HasComponent<SpriteComponent>())
{
return;
}
@@ -138,7 +138,7 @@ namespace Content.Client.CharacterAppearance
return;
}
if (!args.Part.Owner.TryGetComponent(out SpriteComponent? partSprite))
if (!args.Part.Owner.HasComponent<SpriteComponent>())
{
return;
}

View File

@@ -17,7 +17,7 @@ namespace Content.Client.Commands
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var componentManager = IoCManager.Resolve<IComponentManager>();
var mechanisms = componentManager.EntityQuery<IMechanism>(true);
var mechanisms = componentManager.EntityQuery<SharedMechanismComponent>(true);
foreach (var mechanism in mechanisms)
{

View File

@@ -19,7 +19,7 @@ namespace Content.Client.Commands
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var componentManager = IoCManager.Resolve<IComponentManager>();
var mechanisms = componentManager.EntityQuery<IMechanism>(true);
var mechanisms = componentManager.EntityQuery<SharedMechanismComponent>(true);
foreach (var mechanism in mechanisms)
{

View File

@@ -46,7 +46,7 @@ namespace Content.IntegrationTests.Tests.Body
var entityManager = IoCManager.Resolve<IEntityManager>();
var human = entityManager.SpawnEntity("HumanBodyAndAppearanceDummy", new MapCoordinates(Vector2.Zero, mapId));
Assert.That(human.TryGetComponent(out IBody body));
Assert.That(human.TryGetComponent(out SharedBodyComponent body));
Assert.That(human.TryGetComponent(out appearance));
Assert.That(!appearance.TryGetData(RotationVisuals.RotationState, out RotationState _));

View File

@@ -63,7 +63,7 @@ namespace Content.IntegrationTests.Tests.Body
var human = entityManager.SpawnEntity("HumanBodyAndBloodstreamDummy", new MapCoordinates(Vector2.Zero, mapId));
Assert.That(human.TryGetComponent(out IBody body));
Assert.That(human.TryGetComponent(out SharedBodyComponent body));
Assert.That(body.TryGetMechanismBehaviors(out List<LungBehavior> lungs));
Assert.That(lungs.Count, Is.EqualTo(1));
Assert.That(human.TryGetComponent(out BloodstreamComponent bloodstream));
@@ -167,7 +167,7 @@ namespace Content.IntegrationTests.Tests.Body
var coordinates = new EntityCoordinates(grid.GridEntityId, center);
human = entityManager.SpawnEntity("HumanBodyAndBloodstreamDummy", coordinates);
Assert.True(human.TryGetComponent(out IBody body));
Assert.True(human.TryGetComponent(out SharedBodyComponent body));
Assert.True(body.HasMechanismBehavior<LungBehavior>());
Assert.True(human.TryGetComponent(out metabolism));
Assert.False(metabolism.Suffocating);

View File

@@ -59,42 +59,42 @@ namespace Content.IntegrationTests.Tests.Body
ResetRemoved();
}
protected override void OnAddedToBody(IBody body)
protected override void OnAddedToBody(SharedBodyComponent body)
{
base.OnAddedToBody(body);
WasAddedToBody = true;
}
protected override void OnAddedToPart(IBodyPart part)
protected override void OnAddedToPart(SharedBodyPartComponent part)
{
base.OnAddedToPart(part);
WasAddedToPart = true;
}
protected override void OnAddedToPartInBody(IBody body, IBodyPart part)
protected override void OnAddedToPartInBody(SharedBodyComponent body, SharedBodyPartComponent part)
{
base.OnAddedToPartInBody(body, part);
WasAddedToPartInBody = true;
}
protected override void OnRemovedFromBody(IBody old)
protected override void OnRemovedFromBody(SharedBodyComponent old)
{
base.OnRemovedFromBody(old);
WasRemovedFromBody = true;
}
protected override void OnRemovedFromPart(IBodyPart old)
protected override void OnRemovedFromPart(SharedBodyPartComponent old)
{
base.OnRemovedFromPart(old);
WasRemovedFromPart = true;
}
protected override void OnRemovedFromPartInBody(IBody oldBody, IBodyPart oldPart)
protected override void OnRemovedFromPartInBody(SharedBodyComponent oldBody, SharedBodyPartComponent oldPart)
{
base.OnRemovedFromPartInBody(oldBody, oldPart);
@@ -128,7 +128,7 @@ namespace Content.IntegrationTests.Tests.Body
var entityManager = IoCManager.Resolve<IEntityManager>();
var human = entityManager.SpawnEntity("HumanBodyDummy", new MapCoordinates(Vector2.Zero, mapId));
Assert.That(human.TryGetComponent(out IBody? body));
Assert.That(human.TryGetComponent(out SharedBodyComponent? body));
Assert.NotNull(body);
var centerPart = body!.CenterPart;

View File

@@ -213,7 +213,7 @@ namespace Content.IntegrationTests.Tests.Buckle
IEntity human = null;
BuckleComponent buckle = null;
HandsComponent hands = null;
IBody body = null;
SharedBodyComponent body = null;
await server.WaitIdleAsync();

View File

@@ -69,7 +69,7 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking
// Test for components existing
Assert.True(human.TryGetComponent(out cuffed!), $"Human has no {nameof(CuffableComponent)}");
Assert.True(human.TryGetComponent(out hands!), $"Human has no {nameof(HandsComponent)}");
Assert.True(human.TryGetComponent(out IBody _), $"Human has no {nameof(IBody)}");
Assert.True(human.TryGetComponent(out SharedBodyComponent _), $"Human has no {nameof(SharedBodyComponent)}");
Assert.True(cuffs.TryGetComponent(out HandcuffComponent _), $"Handcuff has no {nameof(HandcuffComponent)}");
Assert.True(secondCuffs.TryGetComponent(out HandcuffComponent _), $"Second handcuffs has no {nameof(HandcuffComponent)}");

View File

@@ -21,7 +21,7 @@ namespace Content.Server.AI.WorldState.States.Mobs
return result;
}
foreach (var entity in Visibility.GetEntitiesInRange(Owner.Transform.Coordinates, typeof(IBody), controller.VisionRadius))
foreach (var entity in Visibility.GetEntitiesInRange(Owner.Transform.Coordinates, typeof(SharedBodyComponent), controller.VisionRadius))
{
if (entity == Owner) continue;
result.Add(entity);

View File

@@ -11,42 +11,42 @@ namespace Content.Server.Body.Behavior
{
public class BrainBehavior : MechanismBehavior
{
protected override void OnAddedToBody(IBody body)
protected override void OnAddedToBody(SharedBodyComponent body)
{
base.OnAddedToBody(body);
HandleMind(body.Owner, Owner);
}
protected override void OnAddedToPart(IBodyPart part)
protected override void OnAddedToPart(SharedBodyPartComponent part)
{
base.OnAddedToPart(part);
HandleMind(part.Owner, Owner);
}
protected override void OnAddedToPartInBody(IBody body, IBodyPart part)
protected override void OnAddedToPartInBody(SharedBodyComponent body, SharedBodyPartComponent part)
{
base.OnAddedToPartInBody(body, part);
HandleMind(body.Owner, Owner);
}
protected override void OnRemovedFromBody(IBody old)
protected override void OnRemovedFromBody(SharedBodyComponent old)
{
base.OnRemovedFromBody(old);
HandleMind(Part!.Owner, old.Owner);
}
protected override void OnRemovedFromPart(IBodyPart old)
protected override void OnRemovedFromPart(SharedBodyPartComponent old)
{
base.OnRemovedFromPart(old);
HandleMind(Owner, old.Owner);
}
protected override void OnRemovedFromPartInBody(IBody oldBody, IBodyPart oldPart)
protected override void OnRemovedFromPartInBody(SharedBodyComponent oldBody, SharedBodyPartComponent oldPart)
{
base.OnRemovedFromPartInBody(oldBody, oldPart);

View File

@@ -48,7 +48,7 @@ namespace Content.Server.Body.Behavior
IoCManager.InjectDependencies(this);
}
protected override void OnAddedToBody(IBody body)
protected override void OnAddedToBody(SharedBodyComponent body)
{
base.OnAddedToBody(body);
Inhale(CycleDelay);

View File

@@ -8,22 +8,24 @@ using Robust.Shared.Utility;
namespace Content.Server.Body.Behavior
{
public abstract class MechanismBehavior : IMechanismBehavior
public abstract class MechanismBehavior : SharedMechanismBehavior
{
public IBody? Body => Part?.Body;
private SharedMechanismComponent _parent = default!;
public IBodyPart? Part => Parent.Part;
public override SharedBodyComponent? Body => Part?.Body;
public IMechanism Parent { get; private set; } = default!;
public override SharedBodyPartComponent? Part => Parent.Part;
public IEntity Owner => Parent.Owner;
public override SharedMechanismComponent Parent => _parent;
public virtual void Initialize(IMechanism parent)
public override IEntity Owner => Parent.Owner;
public override void Initialize(SharedMechanismComponent parent)
{
Parent = parent;
_parent = parent;
}
public virtual void Startup()
public override void Startup()
{
if (Part == null)
{
@@ -40,7 +42,9 @@ namespace Content.Server.Body.Behavior
}
}
public void AddedToBody(IBody body)
public override void Update(float frameTime) { }
public override void AddedToBody(SharedBodyComponent body)
{
DebugTools.AssertNotNull(Body);
DebugTools.AssertNotNull(body);
@@ -48,7 +52,7 @@ namespace Content.Server.Body.Behavior
OnAddedToBody(body);
}
public void AddedToPart(IBodyPart part)
public override void AddedToPart(SharedBodyPartComponent part)
{
DebugTools.AssertNotNull(Part);
DebugTools.AssertNotNull(part);
@@ -56,7 +60,7 @@ namespace Content.Server.Body.Behavior
OnAddedToPart(part);
}
public void AddedToPartInBody(IBody body, IBodyPart part)
public override void AddedToPartInBody(SharedBodyComponent body, SharedBodyPartComponent part)
{
DebugTools.AssertNotNull(Body);
DebugTools.AssertNotNull(body);
@@ -66,7 +70,7 @@ namespace Content.Server.Body.Behavior
OnAddedToPartInBody(body, part);
}
public void RemovedFromBody(IBody old)
public override void RemovedFromBody(SharedBodyComponent old)
{
DebugTools.AssertNull(Body);
DebugTools.AssertNotNull(old);
@@ -74,7 +78,7 @@ namespace Content.Server.Body.Behavior
OnRemovedFromBody(old);
}
public void RemovedFromPart(IBodyPart old)
public override void RemovedFromPart(SharedBodyPartComponent old)
{
DebugTools.AssertNull(Part);
DebugTools.AssertNotNull(old);
@@ -82,7 +86,7 @@ namespace Content.Server.Body.Behavior
OnRemovedFromPart(old);
}
public void RemovedFromPartInBody(IBody oldBody, IBodyPart oldPart)
public override void RemovedFromPartInBody(SharedBodyComponent oldBody, SharedBodyPartComponent oldPart)
{
DebugTools.AssertNull(Body);
DebugTools.AssertNull(Part);
@@ -92,18 +96,16 @@ namespace Content.Server.Body.Behavior
OnRemovedFromPartInBody(oldBody, oldPart);
}
protected virtual void OnAddedToBody(IBody body) { }
protected virtual void OnAddedToBody(SharedBodyComponent body) { }
protected virtual void OnAddedToPart(IBodyPart part) { }
protected virtual void OnAddedToPart(SharedBodyPartComponent part) { }
protected virtual void OnAddedToPartInBody(IBody body, IBodyPart part) { }
protected virtual void OnAddedToPartInBody(SharedBodyComponent body, SharedBodyPartComponent part) { }
protected virtual void OnRemovedFromBody(IBody old) { }
protected virtual void OnRemovedFromBody(SharedBodyComponent old) { }
protected virtual void OnRemovedFromPart(IBodyPart old) { }
protected virtual void OnRemovedFromPart(SharedBodyPartComponent old) { }
protected virtual void OnRemovedFromPartInBody(IBody oldBody, IBodyPart oldPart) { }
public virtual void Update(float frameTime) { }
protected virtual void OnRemovedFromPartInBody(SharedBodyComponent oldBody, SharedBodyPartComponent oldPart) { }
}
}

View File

@@ -1,74 +0,0 @@
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Shared.Body.Behavior;
using Content.Shared.Body.Components;
using Content.Shared.Body.Part;
namespace Content.Server.Body.Behavior
{
public static class MechanismExtensions
{
public static bool HasMechanismBehavior<T>(this IBody body) where T : IMechanismBehavior
{
return body.Parts.Any(p => p.Key.HasMechanismBehavior<T>());
}
public static bool HasMechanismBehavior<T>(this IBodyPart part) where T : IMechanismBehavior
{
return part.Mechanisms.Any(m => m.HasBehavior<T>());
}
public static IEnumerable<IMechanismBehavior> GetMechanismBehaviors(this IBody body)
{
foreach (var (part, _) in body.Parts)
foreach (var mechanism in part.Mechanisms)
foreach (var behavior in mechanism.Behaviors.Values)
{
yield return behavior;
}
}
public static bool TryGetMechanismBehaviors(this IBody body,
[NotNullWhen(true)] out List<IMechanismBehavior>? behaviors)
{
behaviors = body.GetMechanismBehaviors().ToList();
if (behaviors.Count == 0)
{
behaviors = null;
return false;
}
return true;
}
public static IEnumerable<T> GetMechanismBehaviors<T>(this IBody body) where T : class, IMechanismBehavior
{
foreach (var (part, _) in body.Parts)
foreach (var mechanism in part.Mechanisms)
foreach (var behavior in mechanism.Behaviors.Values)
{
if (behavior is T tBehavior)
{
yield return tBehavior;
}
}
}
public static bool TryGetMechanismBehaviors<T>(this IBody entity, [NotNullWhen(true)] out List<T>? behaviors)
where T : class, IMechanismBehavior
{
behaviors = entity.GetMechanismBehaviors<T>().ToList();
if (behaviors.Count == 0)
{
behaviors = null;
return false;
}
return true;
}
}
}

View File

@@ -21,27 +21,26 @@ namespace Content.Server.Body
{
[RegisterComponent]
[ComponentReference(typeof(SharedBodyComponent))]
[ComponentReference(typeof(IBody))]
[ComponentReference(typeof(IGhostOnMove))]
public class BodyComponent : SharedBodyComponent, IRelayMoveInput, IGhostOnMove
{
private Container _partContainer = default!;
[Dependency] private readonly IGameTicker _gameTicker = default!;
protected override bool CanAddPart(string slotId, IBodyPart part)
protected override bool CanAddPart(string slotId, SharedBodyPartComponent part)
{
return base.CanAddPart(slotId, part) &&
_partContainer.CanInsert(part.Owner);
}
protected override void OnAddPart(BodyPartSlot slot, IBodyPart part)
protected override void OnAddPart(BodyPartSlot slot, SharedBodyPartComponent part)
{
base.OnAddPart(slot, part);
_partContainer.Insert(part.Owner);
}
protected override void OnRemovePart(BodyPartSlot slot, IBodyPart part)
protected override void OnRemovePart(BodyPartSlot slot, SharedBodyPartComponent part)
{
base.OnRemovePart(slot, part);
@@ -64,9 +63,9 @@ namespace Content.Server.Body
// a crash within the character preview menu in the lobby
var entity = Owner.EntityManager.SpawnEntity(preset.PartIDs[slot.Id], Owner.Transform.MapPosition);
if (!entity.TryGetComponent(out IBodyPart? part))
if (!entity.TryGetComponent(out SharedBodyPartComponent? part))
{
Logger.Error($"Entity {slot.Id} does not have a {nameof(IBodyPart)} component.");
Logger.Error($"Entity {slot.Id} does not have a {nameof(SharedBodyPartComponent)} component.");
continue;
}

View File

@@ -3,11 +3,13 @@ using Content.Shared.Damage;
namespace Content.Server.Body
{
// TODO BODY: Remove and pretend it never existed
public interface IBodyHealthChangeParams
{
BodyPartType Part { get; }
}
// TODO BODY: Remove and pretend it never existed
public class BodyDamageChangeParams : DamageChangeParams, IBodyHealthChangeParams
{
public BodyDamageChangeParams(BodyPartType part)

View File

@@ -122,7 +122,7 @@ namespace Content.Server.Body.Commands
}
}
if (!entity.TryGetComponent(out IBody? body))
if (!entity.TryGetComponent(out SharedBodyComponent? body))
{
var random = IoCManager.Resolve<IRobustRandom>();
var text = $"You have no body{(random.Prob(0.2f) ? " and you must scream." : ".")}";
@@ -131,9 +131,9 @@ namespace Content.Server.Body.Commands
return;
}
if (!hand.TryGetComponent(out IBodyPart? part))
if (!hand.TryGetComponent(out SharedBodyPartComponent? part))
{
shell.WriteLine($"Hand entity {hand} does not have a {nameof(IBodyPart)} component.");
shell.WriteLine($"Hand entity {hand} does not have a {nameof(SharedBodyPartComponent)} component.");
return;
}

View File

@@ -76,9 +76,9 @@ namespace Content.Server.Body.Commands
return;
}
if (!entity.TryGetComponent(out IBody? body))
if (!entity.TryGetComponent(out SharedBodyComponent? body))
{
shell.WriteLine($"Entity {entity.Name} with uid {entity.Uid} does not have a {nameof(IBody)} component.");
shell.WriteLine($"Entity {entity.Name} with uid {entity.Uid} does not have a {nameof(SharedBodyComponent)} component.");
return;
}
@@ -88,9 +88,9 @@ namespace Content.Server.Body.Commands
return;
}
if (!partEntity.TryGetComponent(out IBodyPart? part))
if (!partEntity.TryGetComponent(out SharedBodyPartComponent? part))
{
shell.WriteLine($"Entity {partEntity.Name} with uid {args[0]} does not have a {nameof(IBodyPart)} component.");
shell.WriteLine($"Entity {partEntity.Name} with uid {args[0]} does not have a {nameof(SharedBodyPartComponent)} component.");
return;
}

View File

@@ -37,7 +37,7 @@ namespace Content.Server.Body.Commands
return;
}
if (!player.AttachedEntity.TryGetComponent(out IBody? body))
if (!player.AttachedEntity.TryGetComponent(out SharedBodyComponent? body))
{
var random = IoCManager.Resolve<IRobustRandom>();
var text = $"You have no body{(random.Prob(0.2f) ? " and you must scream." : ".")}";

View File

@@ -33,7 +33,7 @@ namespace Content.Server.Body.Commands
return;
}
if (!player.AttachedEntity.TryGetComponent(out IBody? body))
if (!player.AttachedEntity.TryGetComponent(out SharedBodyComponent? body))
{
var random = IoCManager.Resolve<IRobustRandom>();
var text = $"You have no body{(random.Prob(0.2f) ? " and you must scream." : ".")}";

View File

@@ -20,7 +20,6 @@ namespace Content.Server.Body.Mechanism
{
[RegisterComponent]
[ComponentReference(typeof(SharedMechanismComponent))]
[ComponentReference(typeof(IMechanism))]
public class MechanismComponent : SharedMechanismComponent, IAfterInteract
{
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(SurgeryUIKey.Key);
@@ -47,11 +46,11 @@ namespace Content.Server.Body.Mechanism
PerformerCache = null;
BodyCache = null;
if (eventArgs.Target.TryGetComponent(out IBody? body))
if (eventArgs.Target.TryGetComponent(out SharedBodyComponent? body))
{
SendBodyPartListToUser(eventArgs, body);
}
else if (eventArgs.Target.TryGetComponent<IBodyPart>(out var part))
else if (eventArgs.Target.TryGetComponent<SharedBodyPartComponent>(out var part))
{
DebugTools.AssertNotNull(part);
@@ -64,7 +63,7 @@ namespace Content.Server.Body.Mechanism
return true;
}
private void SendBodyPartListToUser(AfterInteractEventArgs eventArgs, IBody body)
private void SendBodyPartListToUser(AfterInteractEventArgs eventArgs, SharedBodyComponent body)
{
// Create dictionary to send to client (text to be shown : data sent back if selected)
var toSend = new Dictionary<string, int>();
@@ -120,7 +119,7 @@ namespace Content.Server.Body.Mechanism
return;
}
var target = (IBodyPart) targetObject;
var target = (SharedBodyPartComponent) targetObject;
var message = target.TryAddMechanism(this)
? Loc.GetString("You jam {0:theName} inside {1:them}.", Owner, PerformerCache)
: Loc.GetString("You can't fit it in!");

View File

@@ -25,31 +25,30 @@ namespace Content.Server.Body.Part
{
[RegisterComponent]
[ComponentReference(typeof(SharedBodyPartComponent))]
[ComponentReference(typeof(IBodyPart))]
public class BodyPartComponent : SharedBodyPartComponent, IAfterInteract
{
private readonly Dictionary<int, object> _optionsCache = new();
private IBody? _owningBodyCache;
private SharedBodyComponent? _owningBodyCache;
private int _idHash;
private IEntity? _surgeonCache;
private Container _mechanismContainer = default!;
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(SurgeryUIKey.Key);
public override bool CanAddMechanism(IMechanism mechanism)
public override bool CanAddMechanism(SharedMechanismComponent mechanism)
{
return base.CanAddMechanism(mechanism) &&
_mechanismContainer.CanInsert(mechanism.Owner);
}
protected override void OnAddMechanism(IMechanism mechanism)
protected override void OnAddMechanism(SharedMechanismComponent mechanism)
{
base.OnAddMechanism(mechanism);
_mechanismContainer.Insert(mechanism.Owner);
}
protected override void OnRemoveMechanism(IMechanism mechanism)
protected override void OnRemoveMechanism(SharedMechanismComponent mechanism)
{
base.OnRemoveMechanism(mechanism);
@@ -70,9 +69,9 @@ namespace Content.Server.Body.Part
{
var entity = Owner.EntityManager.SpawnEntity(mechanismId, Owner.Transform.MapPosition);
if (!entity.TryGetComponent(out IMechanism? mechanism))
if (!entity.TryGetComponent(out SharedMechanismComponent? mechanism))
{
Logger.Error($"Entity {mechanismId} does not have a {nameof(IMechanism)} component.");
Logger.Error($"Entity {mechanismId} does not have a {nameof(SharedMechanismComponent)} component.");
continue;
}
@@ -108,7 +107,7 @@ namespace Content.Server.Body.Part
_surgeonCache = null;
_owningBodyCache = null;
if (eventArgs.Target.TryGetComponent(out IBody? body))
if (eventArgs.Target.TryGetComponent(out SharedBodyComponent? body))
{
SendSlots(eventArgs, body);
}
@@ -116,7 +115,7 @@ namespace Content.Server.Body.Part
return true;
}
private void SendSlots(AfterInteractEventArgs eventArgs, IBody body)
private void SendSlots(AfterInteractEventArgs eventArgs, SharedBodyComponent body)
{
// Create dictionary to send to client (text to be shown : data sent back if selected)
var toSend = new Dictionary<string, int>();
@@ -246,7 +245,7 @@ namespace Content.Server.Body.Part
return;
}
if (!user.TryGetComponent(out IBody? body))
if (!user.TryGetComponent(out SharedBodyComponent? body))
{
return;
}
@@ -262,7 +261,7 @@ namespace Content.Server.Body.Part
protected override void Activate(IEntity user, BodyPartComponent component)
{
if (!user.TryGetComponent(out IBody? body))
if (!user.TryGetComponent(out SharedBodyComponent? body))
{
return;
}

View File

@@ -30,7 +30,7 @@ namespace Content.Server.Body.Scanner
return;
}
if (session.AttachedEntity.TryGetComponent(out IBody? body))
if (session.AttachedEntity.TryGetComponent(out SharedBodyComponent? body))
{
var state = InterfaceState(body);
UserInterface?.SetState(state);
@@ -56,7 +56,7 @@ namespace Content.Server.Body.Scanner
/// <summary>
/// Copy BodyTemplate and BodyPart data into a common data class that the client can read.
/// </summary>
private BodyScannerUIState InterfaceState(IBody body)
private BodyScannerUIState InterfaceState(SharedBodyComponent body)
{
return new(body.Owner.Uid);
}

View File

@@ -25,7 +25,7 @@ namespace Content.Server.Body.Surgery
{
public override string Name => "BiologicalSurgeryData";
private readonly HashSet<IMechanism> _disconnectedOrgans = new();
private readonly HashSet<SharedMechanismComponent> _disconnectedOrgans = new();
private bool SkinOpened { get; set; }
@@ -33,11 +33,11 @@ namespace Content.Server.Body.Surgery
private bool VesselsClamped { get; set; }
public IBodyPart? Parent => Owner.GetComponentOrNull<IBodyPart>();
public SharedBodyPartComponent? Parent => Owner.GetComponentOrNull<SharedBodyPartComponent>();
public BodyPartType? ParentType => Parent?.PartType;
private void AddDisconnectedOrgan(IMechanism mechanism)
private void AddDisconnectedOrgan(SharedMechanismComponent mechanism)
{
if (_disconnectedOrgans.Add(mechanism))
{
@@ -45,7 +45,7 @@ namespace Content.Server.Body.Surgery
}
}
private void RemoveDisconnectedOrgan(IMechanism mechanism)
private void RemoveDisconnectedOrgan(SharedMechanismComponent mechanism)
{
if (_disconnectedOrgans.Remove(mechanism))
{
@@ -117,7 +117,7 @@ namespace Content.Server.Body.Surgery
return toReturn.ToString();
}
public bool CanAddMechanism(IMechanism mechanism)
public bool CanAddMechanism(SharedMechanismComponent mechanism)
{
return Parent != null &&
SkinOpened &&
@@ -125,7 +125,7 @@ namespace Content.Server.Body.Surgery
SkinRetracted;
}
public bool CanAttachBodyPart(IBodyPart part)
public bool CanAttachBodyPart(SharedBodyPartComponent part)
{
return Parent != null;
// TODO BODY if a part is disconnected, you should have to do some surgery to allow another body part to be attached.
@@ -276,7 +276,7 @@ namespace Content.Server.Body.Surgery
if (Parent == null) return;
if (Parent.Mechanisms.Count <= 0) return;
var toSend = new List<IMechanism>();
var toSend = new List<SharedMechanismComponent>();
foreach (var mechanism in Parent.Mechanisms)
{
if (!_disconnectedOrgans.Contains(mechanism))
@@ -291,7 +291,7 @@ namespace Content.Server.Body.Surgery
}
}
private async void LoosenOrganSurgeryCallback(IMechanism? target, IBodyPartContainer container, ISurgeon surgeon,
private async void LoosenOrganSurgeryCallback(SharedMechanismComponent? target, IBodyPartContainer container, ISurgeon surgeon,
IEntity performer)
{
if (Parent == null || target == null || !Parent.Mechanisms.Contains(target))
@@ -332,7 +332,7 @@ namespace Content.Server.Body.Surgery
}
}
private async void RemoveOrganSurgeryCallback(IMechanism? target, IBodyPartContainer container, ISurgeon surgeon,
private async void RemoveOrganSurgeryCallback(SharedMechanismComponent? target, IBodyPartContainer container, ISurgeon surgeon,
IEntity performer)
{
if (Parent == null || target == null || !Parent.Mechanisms.Contains(target))
@@ -359,7 +359,7 @@ namespace Content.Server.Body.Surgery
private async void RemoveBodyPartSurgery(IBodyPartContainer container, ISurgeon surgeon, IEntity performer)
{
if (Parent == null) return;
if (container is not IBody body) return;
if (container is not SharedBodyComponent body) return;
performer.PopupMessage(Loc.GetString("Sawing off the limb!"));

View File

@@ -47,7 +47,7 @@ namespace Content.Server.Body.Surgery.Components
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(SurgeryUIKey.Key);
public IBody? BodyCache { get; private set; }
public SharedBodyComponent? BodyCache { get; private set; }
public IEntity? PerformerCache { get; private set; }
@@ -66,7 +66,7 @@ namespace Content.Server.Body.Surgery.Components
CloseAllSurgeryUIs();
// Attempt surgery on a body by sending a list of operable parts for the client to choose from
if (eventArgs.Target.TryGetComponent(out IBody? body))
if (eventArgs.Target.TryGetComponent(out SharedBodyComponent? body))
{
// Create dictionary to send to client (text to be shown : data sent back if selected)
var toSend = new Dictionary<string, int>();
@@ -93,7 +93,7 @@ namespace Content.Server.Body.Surgery.Components
NotUsefulPopup();
}
}
else if (eventArgs.Target.TryGetComponent<IBodyPart>(out var part))
else if (eventArgs.Target.TryGetComponent<SharedBodyPartComponent>(out var part))
{
// Attempt surgery on a DroppedBodyPart - there's only one possible target so no need for selection UI
PerformerCache = eventArgs.User;
@@ -113,7 +113,7 @@ namespace Content.Server.Body.Surgery.Components
}
// Log error if the surgery fails somehow.
Logger.Debug($"Error when trying to perform surgery on ${nameof(IBodyPart)} {eventArgs.User.Name}");
Logger.Debug($"Error when trying to perform surgery on ${nameof(SharedBodyPartComponent)} {eventArgs.User.Name}");
throw new InvalidOperationException();
}
@@ -122,7 +122,7 @@ namespace Content.Server.Body.Surgery.Components
public float BaseOperationTime { get => _baseOperateTime; set => _baseOperateTime = value; }
public void RequestMechanism(IEnumerable<IMechanism> options, ISurgeon.MechanismRequestCallback callback)
public void RequestMechanism(IEnumerable<SharedMechanismComponent> options, ISurgeon.MechanismRequestCallback callback)
{
var toSend = new Dictionary<string, int>();
foreach (var mechanism in options)
@@ -211,7 +211,7 @@ namespace Content.Server.Body.Surgery.Components
/// <summary>
/// Called after the client chooses from a list of possible
/// <see cref="IBodyPart"/> that can be operated on.
/// <see cref="SharedBodyPartComponent"/> that can be operated on.
/// </summary>
private void HandleReceiveBodyPart(int key)
{
@@ -230,7 +230,7 @@ namespace Content.Server.Body.Surgery.Components
return;
}
var target = (IBodyPart) targetObject!;
var target = (SharedBodyPartComponent) targetObject!;
// TODO BODY Reconsider
if (!target.AttemptSurgery(_surgeryType, BodyCache, this, PerformerCache))
@@ -241,7 +241,7 @@ namespace Content.Server.Body.Surgery.Components
/// <summary>
/// Called after the client chooses from a list of possible
/// <see cref="IMechanism"/> to choose from.
/// <see cref="SharedMechanismComponent"/> to choose from.
/// </summary>
private void HandleReceiveMechanism(int key)
{

View File

@@ -16,7 +16,7 @@ namespace Content.Server.CharacterAppearance.Components
{
base.Appearance = value;
if (Owner.TryGetComponent(out IBody? body))
if (Owner.TryGetComponent(out SharedBodyComponent? body))
{
foreach (var (part, _) in body.Parts)
{
@@ -35,7 +35,7 @@ namespace Content.Server.CharacterAppearance.Components
{
base.Startup();
if (Appearance != null! && Owner.TryGetComponent(out IBody? body))
if (Appearance != null! && Owner.TryGetComponent(out SharedBodyComponent? body))
{
foreach (var (part, _) in body.Parts)
{

View File

@@ -70,7 +70,7 @@ namespace Content.Server.Chemistry.Components
var trueTarget = target ?? user;
if (!trueTarget.TryGetComponent(out IBody? body) ||
if (!trueTarget.TryGetComponent(out SharedBodyComponent? body) ||
!body.TryGetMechanismBehaviors<StomachBehavior>(out var stomachs))
{
return false;

View File

@@ -75,7 +75,7 @@ namespace Content.Server.Climbing.Components
}
if (!user.HasComponent<ClimbingComponent>() ||
!user.TryGetComponent(out IBody? body))
!user.TryGetComponent(out SharedBodyComponent? body))
{
reason = Loc.GetString("comp-climbable-cant-climb");
return false;

View File

@@ -13,7 +13,7 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
public void Execute(IEntity owner, DestructibleSystem system)
{
if (owner.TryGetComponent(out IBody? body))
if (owner.TryGetComponent(out SharedBodyComponent? body))
{
body.Gib(_recursive);
}

View File

@@ -161,7 +161,7 @@ namespace Content.Server.Disposal.Mailing
}
if (!entity.HasComponent<ItemComponent>() &&
!entity.HasComponent<IBody>())
!entity.HasComponent<SharedBodyComponent>())
{
return false;
}

View File

@@ -79,7 +79,7 @@ namespace Content.Server.Disposal.Unit.Components
}
return entity.HasComponent<ItemComponent>() ||
entity.HasComponent<IBody>();
entity.HasComponent<SharedBodyComponent>();
}
public bool TryInsert(IEntity entity)

View File

@@ -470,7 +470,7 @@ namespace Content.Server.Kitchen.Components
{
var headCount = 0;
if (victim.TryGetComponent<IBody>(out var body))
if (victim.TryGetComponent<SharedBodyComponent>(out var body))
{
var headSlots = body.GetSlotsOfType(BodyPartType.Head);

View File

@@ -26,7 +26,7 @@ namespace Content.Server.Metabolism
[RegisterComponent]
public class MetabolismComponent : Component
{
[ComponentDependency] private readonly IBody? _body = default!;
[ComponentDependency] private readonly SharedBodyComponent? _body = default!;
public override string Name => "Metabolism";

View File

@@ -44,7 +44,7 @@ namespace Content.Server.Morgue.Components
protected override bool AddToContents(IEntity entity)
{
if (entity.HasComponent<IBody>() && !EntitySystem.Get<StandingStateSystem>().IsDown(entity)) return false;
if (entity.HasComponent<SharedBodyComponent>() && !EntitySystem.Get<StandingStateSystem>().IsDown(entity)) return false;
return base.AddToContents(entity);
}

View File

@@ -64,7 +64,7 @@ namespace Content.Server.Morgue.Components
protected override bool AddToContents(IEntity entity)
{
if (entity.HasComponent<IBody>() && !EntitySystem.Get<StandingStateSystem>().IsDown(entity)) return false;
if (entity.HasComponent<SharedBodyComponent>() && !EntitySystem.Get<StandingStateSystem>().IsDown(entity)) return false;
return base.AddToContents(entity);
}
@@ -115,7 +115,7 @@ namespace Content.Server.Morgue.Components
foreach (var entity in Contents.ContainedEntities)
{
count++;
if (!hasMob && entity.HasComponent<IBody>()) hasMob = true;
if (!hasMob && entity.HasComponent<SharedBodyComponent>()) hasMob = true;
if (!hasSoul && entity.TryGetComponent<ActorComponent>(out var actor) && actor.PlayerSession != null) hasSoul = true;
}
Appearance?.SetData(MorgueVisuals.HasContents, count > 0);

View File

@@ -187,7 +187,7 @@ namespace Content.Server.Nutrition.Components
return false;
}
if (!target.TryGetComponent(out IBody? body) ||
if (!target.TryGetComponent(out SharedBodyComponent? body) ||
!body.TryGetMechanismBehaviors<StomachBehavior>(out var stomachs))
{
target.PopupMessage(Loc.GetString("You can't drink {0:theName}!", Owner));

View File

@@ -103,7 +103,7 @@ namespace Content.Server.Nutrition.Components
var trueTarget = target ?? user;
if (!trueTarget.TryGetComponent(out IBody? body) ||
if (!trueTarget.TryGetComponent(out SharedBodyComponent? body) ||
!body.TryGetMechanismBehaviors<StomachBehavior>(out var stomachs))
{
return false;

View File

@@ -69,7 +69,7 @@ namespace Content.Server.Recycling.Components
private bool CanGib(IEntity entity)
{
// We suppose this entity has a Recyclable component.
return entity.HasComponent<IBody>() && !_safe && Powered;
return entity.HasComponent<SharedBodyComponent>() && !_safe && Powered;
}
private void Recycle(IEntity entity)
@@ -87,7 +87,7 @@ namespace Content.Server.Recycling.Components
// Mobs are a special case!
if (CanGib(entity))
{
entity.GetComponent<IBody>().Gib(true);
entity.GetComponent<SharedBodyComponent>().Gib(true);
Bloodstain();
return;
}
@@ -159,7 +159,7 @@ namespace Content.Server.Recycling.Components
victim.PopupMessageOtherClients(Loc.GetString("{0:theName} tries to recycle {0:themself}!", victim));
if (victim.TryGetComponent<IBody>(out var body))
if (victim.TryGetComponent<SharedBodyComponent>(out var body))
{
body.Gib(true);
}

View File

@@ -208,7 +208,7 @@ namespace Content.Server.Storage.Components
// only items that can be stored in an inventory, or a mob, can be eaten by a locker
if (!entity.HasComponent<SharedItemComponent>() &&
!entity.HasComponent<IBody>())
!entity.HasComponent<SharedBodyComponent>())
continue;
if (!AddToContents(entity))

View File

@@ -144,7 +144,7 @@ namespace Content.Server.Toilet
SuicideKind ISuicideAct.Suicide(IEntity victim, IChatManager chat)
{
// check that victim even have head
if (victim.TryGetComponent<IBody>(out var body) &&
if (victim.TryGetComponent<SharedBodyComponent>(out var body) &&
body.HasPartOfType(BodyPartType.Head))
{
var othersMessage = Loc.GetString("{0:theName} sticks their head into {1:theName} and flushes it!", victim, Owner);

View File

@@ -1,142 +0,0 @@
#nullable enable
using Content.Shared.Body.Components;
using Content.Shared.Body.Mechanism;
using Content.Shared.Body.Part;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Shared.Body.Behavior
{
/// <summary>
/// Gives functionality to a <see cref="IMechanism"/> when added to it.
/// </summary>
[ImplicitDataDefinitionForInheritors]
public interface IMechanismBehavior
{
/// <summary>
/// The body that owns the <see cref="IBodyPart"/> in which the
/// <see cref="IMechanism"/> that owns this
/// <see cref="IMechanismBehavior"/> is in.
/// </summary>
IBody? Body { get; }
/// <summary>
/// The part in which the <see cref="IMechanism"/> that owns this
/// <see cref="IMechanismBehavior"/> is in.
/// </summary>
IBodyPart? Part { get; }
/// <summary>
/// Upward reference to the parent <see cref="IMechanism"/> that this
/// behavior is attached to.
/// </summary>
IMechanism Parent { get; }
/// <summary>
/// The entity that owns <see cref="Parent"/>.
/// For the entity owning the body that this mechanism may be in,
/// see <see cref="Body"/>'s <see cref="IBody.Owner"/>.
/// </summary>
IEntity Owner { get; }
/// <summary>
/// Called when this <see cref="IMechanismBehavior"/> is added to a
/// <see cref="IMechanism"/>, during <see cref="IComponent.Initialize"/>.
/// If it is added after component initialization,
/// it is called immediately.
/// </summary>
/// <param name="parent">
/// The mechanism that owns this <see cref="IMechanismBehavior"/>.
/// </param>
void Initialize(IMechanism parent);
/// <summary>
/// Called when this <see cref="IMechanismBehavior"/> is added to a
/// <see cref="IMechanism"/>, during <see cref="IComponent.Startup"/>.
/// If it is added after component startup, it is called immediately.
/// </summary>
void Startup();
/// <summary>
/// Runs an update cycle on this <see cref="IMechanismBehavior"/>.
/// </summary>
/// <param name="frameTime">
/// The amount of seconds that passed since the last update.
/// </param>
void Update(float frameTime);
/// <summary>
/// Called when the containing <see cref="IBodyPart"/> is attached to a
/// <see cref="IBody"/>.
/// For instance, attaching a head with a brain inside to a body.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="body">
/// The body that the containing <see cref="IMechanism"/> was added to.
/// </param>
void AddedToBody(IBody body);
/// <summary>
/// Called when the parent <see cref="IMechanism"/> is
/// added into a <see cref="IBodyPart"/> that is not attached to a
/// <see cref="IBody"/>.
/// For instance, adding a brain to a dismembered head.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="part">
/// The part that the containing <see cref="IMechanism"/> was added to.
/// </param>
void AddedToPart(IBodyPart part);
/// <summary>
/// Called when the parent <see cref="IMechanism"/> is added to a
/// <see cref="IBodyPart"/> that is attached to a <see cref="IBody"/>.
/// For instance, adding a brain to a head that is attached to a body.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="body">
/// The body that the containing <see cref="IMechanism"/> was added to.
/// </param>
/// <param name="part">
/// The part that the containing <see cref="IMechanism"/> was added to.
/// </param>
void AddedToPartInBody(IBody body, IBodyPart part);
/// <summary>
/// Called when the parent <see cref="IBodyPart"/> is removed from a
/// <see cref="IBody"/>.
/// For instance, removing a head with a brain inside from a body.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="old">
/// The body that the containing <see cref="IMechanism"/> was removed from.
/// </param>
void RemovedFromBody(IBody old);
/// <summary>
/// Called when the parent <see cref="IMechanism"/> is
/// removed from a <see cref="IBodyPart"/> that is not attached to a
/// <see cref="IBody"/>.
/// For instance, removing a brain from a dismembered head.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="old">
/// The part that the containing <see cref="IMechanism"/> was removed from.
/// </param>
void RemovedFromPart(IBodyPart old);
/// <summary>
/// Called when the parent <see cref="IMechanism"/> is removed from a
/// <see cref="IBodyPart"/> that is attached to a <see cref="IBody"/>.
/// For instance, removing a brain from a head that is attached to a body.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="oldBody">
/// The body that the containing <see cref="IMechanism"/> was removed from.
/// </param>
/// <param name="oldPart">
/// The part that the containing <see cref="IMechanism"/> was removed from.
/// </param>
void RemovedFromPartInBody(IBody oldBody, IBodyPart oldPart);
}
}

View File

@@ -0,0 +1,119 @@
#nullable enable
using Content.Shared.Body.Components;
using Content.Shared.Body.Mechanism;
using Content.Shared.Body.Part;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Shared.Body.Behavior
{
/// <summary>
/// Gives functionality to a mechanism when added to it.
/// </summary>
[ImplicitDataDefinitionForInheritors]
public abstract class SharedMechanismBehavior
{
public abstract SharedBodyComponent? Body { get; }
public abstract SharedBodyPartComponent? Part { get; }
public abstract SharedMechanismComponent Parent { get; }
/// <summary>
/// The entity that owns <see cref="Parent"/>.
/// For the entity owning the body that this mechanism may be in,
/// see <see cref="Body"/>'s <see cref="SharedBodyComponent.Owner"/>.
/// </summary>
public abstract IEntity Owner { get; }
/// <summary>
/// Called when this behavior is added to a mechanism, during <see cref="IComponent.Initialize"/>.
/// If it is added after component initialization,
/// it is called immediately.
/// </summary>
/// <param name="parent">
/// The mechanism that owns this behavior.
/// </param>
public abstract void Initialize(SharedMechanismComponent parent);
/// <summary>
/// Called when this behavior is added to a mechanism, during <see cref="Component.Startup"/>.
/// If it is added after component startup, it is called immediately.
/// </summary>
public abstract void Startup();
/// <summary>
/// Runs an update cycle on this behavior.
/// </summary>
/// <param name="frameTime">
/// The amount of seconds that passed since the last update.
/// </param>
public abstract void Update(float frameTime);
/// <summary>
/// Called when the containing part is attached to a body.
/// For instance, attaching a head with a brain inside to a body.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="body">
/// The body that the containing mechanism was added to.
/// </param>
public abstract void AddedToBody(SharedBodyComponent body);
/// <summary>
/// Called when the parent mechanism is added into a part that is not attached to a body.
/// For instance, adding a brain to a dismembered head.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="part">
/// The part that the containing mechanism was added to.
/// </param>
public abstract void AddedToPart(SharedBodyPartComponent part);
/// <summary>
/// Called when the parent mechanism is added to a part that is attached to a body.
/// For instance, adding a brain to a head that is attached to a body.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="body">
/// The body that the containing mechanism was added to.
/// </param>
/// <param name="part">
/// The part that the containing mechanism was added to.
/// </param>
public abstract void AddedToPartInBody(SharedBodyComponent body, SharedBodyPartComponent part);
/// <summary>
/// Called when the parent part is removed from a body.
/// For instance, removing a head with a brain inside from a body.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="old">
/// The body that the containing mechanism was removed from.
/// </param>
public abstract void RemovedFromBody(SharedBodyComponent old);
/// <summary>
/// Called when the parent mechanism is removed from a part that is not attached to a body.
/// For instance, removing a brain from a dismembered head.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="old">
/// The part that the containing mechanism was removed from.
/// </param>
public abstract void RemovedFromPart(SharedBodyPartComponent old);
/// <summary>
/// Called when the parent mechanism is removed from a part that is attached to a body.
/// For instance, removing a brain from a head that is attached to a body.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="oldBody">
/// The body that the containing mechanism was removed from.
/// </param>
/// <param name="oldPart">
/// The part that the containing mechanism was removed from.
/// </param>
public abstract void RemovedFromPartInBody(SharedBodyComponent oldBody, SharedBodyPartComponent oldPart);
}
}

View File

@@ -1,256 +0,0 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Body.Part;
using Content.Shared.Body.Part.Property;
using Content.Shared.Body.Preset;
using Content.Shared.Body.Slot;
using Content.Shared.Body.Template;
using Robust.Shared.GameObjects;
namespace Content.Shared.Body.Components
{
/// <summary>
/// Component representing a collection of <see cref="IBodyPart"/>s
/// attached to each other.
/// </summary>
public interface IBody : IComponent, IBodyPartContainer
{
/// <summary>
/// The <see cref="BodyTemplatePrototype"/> used to create this
/// <see cref="IBody"/>.
/// </summary>
public BodyTemplatePrototype? Template { get; }
/// <summary>
/// The <see cref="BodyPresetPrototype"/> used to create this
/// <see cref="IBody"/>.
/// </summary>
public BodyPresetPrototype? Preset { get; }
/// <summary>
/// An enumeration of the slots that make up this body, regardless
/// of if they contain a part or not.
/// </summary>
IEnumerable<BodyPartSlot> Slots { get; }
/// <summary>
/// An enumeration of the parts on this body paired with the slots
/// that they are in.
/// </summary>
IEnumerable<KeyValuePair<IBodyPart, BodyPartSlot>> Parts { get; }
/// <summary>
/// An enumeration of the slots on this body without a part in them.
/// </summary>
IEnumerable<BodyPartSlot> EmptySlots { get; }
/// <summary>
/// Finds the central <see cref="BodyPartSlot"/>, if any,
/// of this body.
/// </summary>
/// <returns>
/// The central <see cref="BodyPartSlot"/> if one exists,
/// null otherwise.
/// </returns>
BodyPartSlot? CenterSlot { get; }
/// <summary>
/// Finds the central <see cref="IBodyPart"/>, if any,
/// of this body.
/// </summary>
/// <returns>
/// The central <see cref="IBodyPart"/> if one exists,
/// null otherwise.
/// </returns>
IBodyPart? CenterPart { get; }
// TODO BODY Sensible templates
/// <summary>
/// Attempts to add a part to the given slot.
/// </summary>
/// <param name="slotId">The slot to add this part to.</param>
/// <param name="part">The part to add.</param>
/// <param name="checkSlotExists">
/// Whether to check if the slot exists, or create one otherwise.
/// </param>
/// <returns>
/// true if the part was added, false otherwise even if it was
/// already added.
/// </returns>
bool TryAddPart(string slotId, IBodyPart part);
void SetPart(string slotId, IBodyPart part);
/// <summary>
/// Checks if there is a <see cref="IBodyPart"/> in the given slot.
/// </summary>
/// <param name="slotId">The slot to look in.</param>
/// <returns>
/// true if there is a part in the given <see cref="slotId"/>,
/// false otherwise.
/// </returns>
bool HasPart(string slotId);
/// <summary>
/// Checks if this <see cref="IBody"/> contains the given <see cref="part"/>.
/// </summary>
/// <param name="part">The part to look for.</param>
/// <returns>
/// true if the given <see cref="part"/> is attached to the body,
/// false otherwise.
/// </returns>
bool HasPart(IBodyPart part);
/// <summary>
/// Removes the given <see cref="IBodyPart"/> from this body,
/// dropping other <see cref="IBodyPart"/> if they were hanging
/// off of it.
/// <param name="part">The part to remove.</param>
/// <returns>
/// true if the part was removed, false otherwise
/// even if the part was already removed previously.
/// </returns>
/// </summary>
bool RemovePart(IBodyPart part);
/// <summary>
/// Removes the body part in slot <see cref="slotId"/> from this body,
/// if one exists.
/// </summary>
/// <param name="slotId">The slot to remove it from.</param>
/// <returns>true if the part was removed, false otherwise.</returns>
bool RemovePart(string slotId);
/// <summary>
/// Removes the body part from this body, if one exists.
/// </summary>
/// <param name="part">The part to remove from this body.</param>
/// <param name="slotId">The slot that the part was in, if any.</param>
/// <returns>
/// true if <see cref="part"/> was removed, false otherwise.
/// </returns>
bool RemovePart(IBodyPart part, [NotNullWhen(true)] out BodyPartSlot? slotId);
/// <summary>
/// Disconnects the given <see cref="IBodyPart"/> reference, potentially
/// dropping other <see cref="IBodyPart">BodyParts</see> if they
/// were hanging off of it.
/// </summary>
/// <param name="slot">The part to drop.</param>
/// <param name="dropped">
/// All of the parts that were dropped, including the one in
/// <see cref="slot"/>.
/// </param>
/// <returns>
/// true if the part was dropped, false otherwise.
/// </returns>
bool TryDropPart(BodyPartSlot slot, [NotNullWhen(true)] out Dictionary<BodyPartSlot, IBodyPart>? dropped);
/// <summary>
/// Recursively searches for if <see cref="part"/> is connected to
/// the center.
/// </summary>
/// <param name="part">The body part to find the center for.</param>
/// <returns>
/// true if it is connected to the center, false otherwise.
/// </returns>
bool ConnectedToCenter(IBodyPart part);
/// <summary>
/// Returns whether the given part slot exists in this body.
/// </summary>
/// <param name="slot">The slot to check for.</param>
/// <returns>true if the slot exists in this body, false otherwise.</returns>
bool HasSlot(string slot);
BodyPartSlot? GetSlot(IBodyPart part);
/// <summary>
/// Finds the slot that the given <see cref="IBodyPart"/> resides in.
/// </summary>
/// <param name="part">
/// The <see cref="IBodyPart"/> to find the slot for.
/// </param>
/// <param name="slot">The slot found, if any.</param>
/// <returns>true if a slot was found, false otherwise</returns>
bool TryGetSlot(IBodyPart part, [NotNullWhen(true)] out BodyPartSlot? slot);
/// <summary>
/// Finds the <see cref="IBodyPart"/> in the given
/// <see cref="slotId"/> if one exists.
/// </summary>
/// <param name="slotId">The part slot to search in.</param>
/// <param name="result">The body part in that slot, if any.</param>
/// <returns>true if found, false otherwise.</returns>
bool TryGetPart(string slotId, [NotNullWhen(true)] out IBodyPart? result);
/// <summary>
/// Checks if a slot of the specified type exists on this body.
/// </summary>
/// <param name="type">The type to check for.</param>
/// <returns>true if present, false otherwise.</returns>
bool HasSlotOfType(BodyPartType type);
/// <summary>
/// Gets all slots of the specified type on this body.
/// </summary>
/// <param name="type">The type to check for.</param>
/// <returns>An enumerable of the found slots.</returns>
IEnumerable<BodyPartSlot> GetSlotsOfType(BodyPartType type);
/// <summary>
/// Checks if a part of the specified type exists on this body.
/// </summary>
/// <param name="type">The type to check for.</param>
/// <returns>true if present, false otherwise.</returns>
bool HasPartOfType(BodyPartType type);
/// <summary>
/// Gets all slots of the specified type on this body.
/// </summary>
/// <param name="type">The type to check for.</param>
/// <returns>An enumerable of the found slots.</returns>
IEnumerable<IBodyPart> GetPartsOfType(BodyPartType type);
/// <summary>
/// Finds all <see cref="IBodyPart"/>s with the given property in
/// this body.
/// </summary>
/// <type name="type">The property type to look for.</type>
/// <returns>A list of parts with that property.</returns>
IEnumerable<(IBodyPart part, IBodyPartProperty property)> GetPartsWithProperty(Type type);
/// <summary>
/// Finds all <see cref="IBodyPart"/>s with the given property in this body.
/// </summary>
/// <typeparam name="T">The property type to look for.</typeparam>
/// <returns>A list of parts with that property.</returns>
IEnumerable<(IBodyPart part, T property)> GetPartsWithProperty<T>() where T : class, IBodyPartProperty;
// TODO BODY Make a slot object that makes sense to the human mind, and make it serializable. Imagine the possibilities!
/// <summary>
/// Retrieves the slot at the given index.
/// </summary>
/// <param name="index">The index to look in.</param>
/// <returns>A pair of the slot name and part type occupying it.</returns>
BodyPartSlot SlotAt(int index);
/// <summary>
/// Retrieves the part at the given index.
/// </summary>
/// <param name="index">The index to look in.</param>
/// <returns>A pair of the part name and body part occupying it.</returns>
KeyValuePair<IBodyPart, BodyPartSlot> PartAt(int index);
/// <summary>
/// Gibs this body.
/// </summary>
/// <param name="gibParts">
/// Whether or not to also gib this body's parts.
/// </param>
void Gib(bool gibParts = false);
}
}

View File

@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Shared.Body.Behavior;
using Content.Shared.Body.Part;
using Content.Shared.Body.Part.Property;
using Content.Shared.Body.Preset;
@@ -25,7 +26,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Shared.Body.Components
{
// TODO BODY Damage methods for collections of IDamageableComponents
public abstract class SharedBodyComponent : Component, IBody, ISerializationHooks
public abstract class SharedBodyComponent : Component, IBodyPartContainer, ISerializationHooks
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
@@ -55,13 +56,13 @@ namespace Content.Shared.Body.Components
private Dictionary<string, BodyPartSlot> SlotIds { get; } = new();
[ViewVariables]
private Dictionary<IBodyPart, BodyPartSlot> SlotParts { get; } = new();
private Dictionary<SharedBodyPartComponent, BodyPartSlot> SlotParts { get; } = new();
[ViewVariables]
public IEnumerable<BodyPartSlot> Slots => SlotIds.Values;
[ViewVariables]
public IEnumerable<KeyValuePair<IBodyPart, BodyPartSlot>> Parts => SlotParts;
public IEnumerable<KeyValuePair<SharedBodyPartComponent, BodyPartSlot>> Parts => SlotParts;
[ViewVariables]
public IEnumerable<BodyPartSlot> EmptySlots => Slots.Where(slot => slot.Part == null);
@@ -71,7 +72,7 @@ namespace Content.Shared.Body.Components
? SlotIds.GetValueOrDefault(centerSlot)
: null;
public IBodyPart? CenterPart => CenterSlot?.Part;
public SharedBodyPartComponent? CenterPart => CenterSlot?.Part;
public override void Initialize()
{
@@ -119,9 +120,9 @@ namespace Content.Shared.Body.Components
return slot;
}
private Dictionary<BodyPartSlot, IBodyPart> GetHangingParts(BodyPartSlot from)
private Dictionary<BodyPartSlot, SharedBodyPartComponent> GetHangingParts(BodyPartSlot from)
{
var hanging = new Dictionary<BodyPartSlot, IBodyPart>();
var hanging = new Dictionary<BodyPartSlot, SharedBodyPartComponent>();
foreach (var connection in from.Connections)
{
@@ -135,7 +136,7 @@ namespace Content.Shared.Body.Components
return hanging;
}
protected virtual bool CanAddPart(string slotId, IBodyPart part)
protected virtual bool CanAddPart(string slotId, SharedBodyPartComponent part)
{
if (!SlotIds.TryGetValue(slotId, out var slot) ||
slot.CanAddPart(part))
@@ -146,7 +147,7 @@ namespace Content.Shared.Body.Components
return true;
}
protected virtual void OnAddPart(BodyPartSlot slot, IBodyPart part)
protected virtual void OnAddPart(BodyPartSlot slot, SharedBodyPartComponent part)
{
SlotParts[part] = slot;
part.Body = this;
@@ -162,7 +163,7 @@ namespace Content.Shared.Body.Components
OnBodyChanged();
}
protected virtual void OnRemovePart(BodyPartSlot slot, IBodyPart part)
protected virtual void OnRemovePart(BodyPartSlot slot, SharedBodyPartComponent part)
{
SlotParts.Remove(part);
@@ -203,7 +204,8 @@ namespace Content.Shared.Body.Components
OnBodyChanged();
}
public bool TryAddPart(string slotId, IBodyPart part)
// TODO BODY Sensible templates
public bool TryAddPart(string slotId, SharedBodyPartComponent part)
{
DebugTools.AssertNotNull(part);
DebugTools.AssertNotNull(slotId);
@@ -217,7 +219,7 @@ namespace Content.Shared.Body.Components
slot.TryAddPart(part);
}
public void SetPart(string slotId, IBodyPart part)
public void SetPart(string slotId, SharedBodyPartComponent part)
{
if (!SlotIds.TryGetValue(slotId, out var slot))
{
@@ -236,14 +238,14 @@ namespace Content.Shared.Body.Components
slot.Part != null;
}
public bool HasPart(IBodyPart part)
public bool HasPart(SharedBodyPartComponent part)
{
DebugTools.AssertNotNull(part);
return SlotParts.ContainsKey(part);
}
public bool RemovePart(IBodyPart part)
public bool RemovePart(SharedBodyPartComponent part)
{
DebugTools.AssertNotNull(part);
@@ -259,7 +261,7 @@ namespace Content.Shared.Body.Components
slot.RemovePart();
}
public bool RemovePart(IBodyPart part, [NotNullWhen(true)] out BodyPartSlot? slotId)
public bool RemovePart(SharedBodyPartComponent part, [NotNullWhen(true)] out BodyPartSlot? slotId)
{
DebugTools.AssertNotNull(part);
@@ -279,7 +281,7 @@ namespace Content.Shared.Body.Components
return true;
}
public bool TryDropPart(BodyPartSlot slot, [NotNullWhen(true)] out Dictionary<BodyPartSlot, IBodyPart>? dropped)
public bool TryDropPart(BodyPartSlot slot, [NotNullWhen(true)] out Dictionary<BodyPartSlot, SharedBodyPartComponent>? dropped)
{
DebugTools.AssertNotNull(slot);
@@ -304,7 +306,7 @@ namespace Content.Shared.Body.Components
return true;
}
public bool ConnectedToCenter(IBodyPart part)
public bool ConnectedToCenter(SharedBodyPartComponent part)
{
return TryGetSlot(part, out var result) &&
ConnectedToCenterPartRecursion(result);
@@ -343,7 +345,7 @@ namespace Content.Shared.Body.Components
return SlotIds.ContainsKey(slot);
}
public IEnumerable<IBodyPart> GetParts()
public IEnumerable<SharedBodyPartComponent> GetParts()
{
foreach (var slot in SlotIds.Values)
{
@@ -354,7 +356,7 @@ namespace Content.Shared.Body.Components
}
}
public bool TryGetPart(string slotId, [NotNullWhen(true)] out IBodyPart? result)
public bool TryGetPart(string slotId, [NotNullWhen(true)] out SharedBodyPartComponent? result)
{
result = null;
@@ -367,7 +369,7 @@ namespace Content.Shared.Body.Components
return SlotIds.GetValueOrDefault(id);
}
public BodyPartSlot? GetSlot(IBodyPart part)
public BodyPartSlot? GetSlot(SharedBodyPartComponent part)
{
return SlotParts.GetValueOrDefault(part);
}
@@ -377,12 +379,12 @@ namespace Content.Shared.Body.Components
return (slot = GetSlot(slotId)) != null;
}
public bool TryGetSlot(IBodyPart part, [NotNullWhen(true)] out BodyPartSlot? slot)
public bool TryGetSlot(SharedBodyPartComponent part, [NotNullWhen(true)] out BodyPartSlot? slot)
{
return (slot = GetSlot(part)) != null;
}
public bool TryGetPartConnections(string slotId, [NotNullWhen(true)] out List<IBodyPart>? connections)
public bool TryGetPartConnections(string slotId, [NotNullWhen(true)] out List<SharedBodyPartComponent>? connections)
{
if (!SlotIds.TryGetValue(slotId, out var slot))
{
@@ -390,7 +392,7 @@ namespace Content.Shared.Body.Components
return false;
}
connections = new List<IBodyPart>();
connections = new List<SharedBodyPartComponent>();
foreach (var connection in slot.Connections)
{
if (connection.Part != null)
@@ -439,7 +441,7 @@ namespace Content.Shared.Body.Components
return false;
}
public IEnumerable<IBodyPart> GetPartsOfType(BodyPartType type)
public IEnumerable<SharedBodyPartComponent> GetPartsOfType(BodyPartType type)
{
foreach (var slot in GetSlotsOfType(type))
{
@@ -450,7 +452,8 @@ namespace Content.Shared.Body.Components
}
}
public IEnumerable<(IBodyPart part, IBodyPartProperty property)> GetPartsWithProperty(Type type)
/// <returns>A list of parts with that property.</returns>
public IEnumerable<(SharedBodyPartComponent part, IBodyPartProperty property)> GetPartsWithProperty(Type type)
{
foreach (var slot in SlotIds.Values)
{
@@ -461,7 +464,7 @@ namespace Content.Shared.Body.Components
}
}
public IEnumerable<(IBodyPart part, T property)> GetPartsWithProperty<T>() where T : class, IBodyPartProperty
public IEnumerable<(SharedBodyPartComponent part, T property)> GetPartsWithProperty<T>() where T : class, IBodyPartProperty
{
foreach (var part in SlotParts.Keys)
{
@@ -509,9 +512,6 @@ namespace Content.Shared.Body.Components
}
}
/// <summary>
/// Called when the layout of this body changes.
/// </summary>
private void OnBodyChanged()
{
// Calculate move speed based on this body.
@@ -523,19 +523,7 @@ namespace Content.Shared.Body.Components
Dirty();
}
/// <summary>
/// Returns the combined length of the distance to the nearest
/// <see cref="IBodyPart"/> that is a foot.
/// If you consider a <see cref="IBody"/> a node map, then it will
/// look for a foot node from the given node. It can only search
/// through <see cref="IBodyPart"/>s with an
/// <see cref="ExtensionComponent"/>.
/// </summary>
/// <returns>
/// The distance to the foot if found, <see cref="float.MinValue"/>
/// otherwise.
/// </returns>
public float DistanceToNearestFoot(IBodyPart source)
public float DistanceToNearestFoot(SharedBodyPartComponent source)
{
if (source.PartType == BodyPartType.Foot &&
source.TryGetProperty<ExtensionComponent>(out var extension))
@@ -546,7 +534,7 @@ namespace Content.Shared.Body.Components
return LookForFootRecursion(source);
}
private float LookForFootRecursion(IBodyPart current, HashSet<BodyPartSlot>? searched = null)
private float LookForFootRecursion(SharedBodyPartComponent current, HashSet<BodyPartSlot>? searched = null)
{
searched ??= new HashSet<BodyPartSlot>();
@@ -555,13 +543,11 @@ namespace Content.Shared.Body.Components
return float.MinValue;
}
// Get all connected parts if the current part has an extension property
if (!TryGetSlot(current, out var slot))
{
return float.MinValue;
}
// If a connected BodyPart is a foot, return this BodyPart's length.
foreach (var connection in slot.Connections)
{
if (connection.PartType == BodyPartType.Foot &&
@@ -571,8 +557,6 @@ namespace Content.Shared.Body.Components
}
}
// Otherwise, get the recursion values of all connected BodyParts and
// store them in a list.
var distances = new List<float>();
foreach (var connection in slot.Connections)
{
@@ -589,8 +573,6 @@ namespace Content.Shared.Body.Components
}
}
// If one or more of the searches found a foot, return the smallest one
// and add this ones length.
if (distances.Count > 0)
{
return distances.Min<float>() + extProperty.Distance;
@@ -605,7 +587,7 @@ namespace Content.Shared.Body.Components
return SlotIds.Values.ElementAt(index);
}
public KeyValuePair<IBodyPart, BodyPartSlot> PartAt(int index)
public KeyValuePair<SharedBodyPartComponent, BodyPartSlot> PartAt(int index)
{
return SlotParts.ElementAt(index);
}
@@ -664,12 +646,68 @@ namespace Content.Shared.Body.Components
part.Gib();
}
}
public bool TryGetMechanismBehaviors([NotNullWhen(true)] out List<SharedMechanismBehavior>? behaviors)
{
behaviors = GetMechanismBehaviors().ToList();
if (behaviors.Count == 0)
{
behaviors = null;
return false;
}
return true;
}
public bool HasMechanismBehavior<T>() where T : SharedMechanismBehavior
{
return Parts.Any(p => p.Key.HasMechanismBehavior<T>());
}
// TODO cache these 2 methods jesus
public IEnumerable<SharedMechanismBehavior> GetMechanismBehaviors()
{
foreach (var (part, _) in Parts)
foreach (var mechanism in part.Mechanisms)
foreach (var behavior in mechanism.Behaviors.Values)
{
yield return behavior;
}
}
public IEnumerable<T> GetMechanismBehaviors<T>() where T : SharedMechanismBehavior
{
foreach (var (part, _) in Parts)
foreach (var mechanism in part.Mechanisms)
foreach (var behavior in mechanism.Behaviors.Values)
{
if (behavior is T tBehavior)
{
yield return tBehavior;
}
}
}
public bool TryGetMechanismBehaviors<T>([NotNullWhen(true)] out List<T>? behaviors)
where T : SharedMechanismBehavior
{
behaviors = GetMechanismBehaviors<T>().ToList();
if (behaviors.Count == 0)
{
behaviors = null;
return false;
}
return true;
}
}
[Serializable, NetSerializable]
public class BodyComponentState : ComponentState
{
private Dictionary<string, IBodyPart>? _parts;
private Dictionary<string, SharedBodyPartComponent>? _parts;
public readonly (string slot, EntityUid partId)[] PartIds;
@@ -678,7 +716,7 @@ namespace Content.Shared.Body.Components
PartIds = partIds;
}
public Dictionary<string, IBodyPart> Parts(IEntityManager? entityManager = null)
public Dictionary<string, SharedBodyPartComponent> Parts(IEntityManager? entityManager = null)
{
if (_parts != null)
{
@@ -687,7 +725,7 @@ namespace Content.Shared.Body.Components
entityManager ??= IoCManager.Resolve<IEntityManager>();
var parts = new Dictionary<string, IBodyPart>(PartIds.Length);
var parts = new Dictionary<string, SharedBodyPartComponent>(PartIds.Length);
foreach (var (slot, partId) in PartIds)
{
@@ -696,7 +734,7 @@ namespace Content.Shared.Body.Components
continue;
}
if (!entity.TryGetComponent(out IBodyPart? part))
if (!entity.TryGetComponent(out SharedBodyPartComponent? part))
{
continue;
}

View File

@@ -1,178 +0,0 @@
#nullable enable
using System;
using System.Collections.Generic;
using Content.Shared.Body.Behavior;
using Content.Shared.Body.Components;
using Content.Shared.Body.Part;
using Robust.Shared.GameObjects;
namespace Content.Shared.Body.Mechanism
{
public interface IMechanism : IComponent
{
/// <summary>
/// The body that owns the <see cref="IBodyPart"/> in which this
/// <see cref="IMechanism"/> is in.
/// </summary>
IBody? Body { get; }
/// <summary>
/// The part in which this <see cref="IMechanism"/> is in.
/// </summary>
IBodyPart? Part { get; set; }
/// <summary>
/// The behaviors attached to this <see cref="IMechanism"/>
/// mapped by their type.
/// </summary>
IReadOnlyDictionary<Type, IMechanismBehavior> Behaviors { get; }
/// <summary>
/// Max HP of this <see cref="IMechanism"/>.
/// </summary>
int MaxDurability { get; set; }
/// <summary>
/// Current HP of this <see cref="IMechanism"/>.
/// </summary>
int CurrentDurability { get; set; }
/// <summary>
/// At what HP this <see cref="IMechanism"/> is completely destroyed.
/// </summary>
int DestroyThreshold { get; set; }
/// <summary>
/// Armor of this <see cref="IMechanism"/> against attacks.
/// </summary>
int Resistance { get; set; }
/// <summary>
/// Determines a handful of things - mostly whether this
/// <see cref="IMechanism"/> can fit into a <see cref="IBodyPart"/>.
/// </summary>
// TODO BODY OnSizeChanged
int Size { get; set; }
/// <summary>
/// What kind of <see cref="IBodyPart"/> this
/// <see cref="IMechanism"/> can be easily installed into.
/// </summary>
BodyPartCompatibility Compatibility { get; set; }
/// <summary>
/// Adds a <see cref="IMechanismBehavior"/> if this
/// <see cref="IMechanism"/> does not have it already.
/// </summary>
/// <typeparam name="T">The behavior type to add.</typeparam>
/// <returns>
/// True if the behavior already existed, false if it had to be created.
/// </returns>
bool EnsureBehavior<T>(out T behavior) where T : IMechanismBehavior, new();
/// <summary>
/// Checks if this <see cref="IMechanism"/> has the specified
/// <see cref="IMechanismBehavior"/>.
/// </summary>
/// <typeparam name="T">
/// The type of <see cref="IMechanismBehavior"/> to check for.
/// </typeparam>
/// <returns>
/// true if it has the <see cref="IMechanismBehavior"/>, false otherwise.
/// </returns>
bool HasBehavior<T>() where T : IMechanismBehavior;
/// <summary>
/// Removes the specified <see cref="IMechanismBehavior"/> from this
/// <see cref="IMechanism"/> if it has it.
/// </summary>
/// <typeparam name="T">
/// The type of <see cref="IMechanismBehavior"/> to remove.
/// </typeparam>
/// <returns>true if it was removed, false otherwise.</returns>
bool TryRemoveBehavior<T>() where T : IMechanismBehavior;
/// <summary>
/// Runs an update cycle for this <see cref="IMechanism"/>.
/// </summary>
/// <param name="frameTime">
/// The amount of seconds that passed since the last update.
/// </param>
void Update(float frameTime);
// TODO BODY Turn these into event listeners so they dont need to be exposed
/// <summary>
/// Called when the containing <see cref="IBodyPart"/> is attached to a
/// <see cref="IBody"/>.
/// For instance, attaching a head with a brain inside to a body.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="body">
/// The body that this <see cref="IMechanism"/> was added to.
/// </param>
void AddedToBody(IBody body);
/// <summary>
/// Called when the parent <see cref="IMechanism"/> is
/// added into a <see cref="IBodyPart"/> that is not attached to a
/// <see cref="IBody"/>.
/// For instance, adding a brain to a dismembered head.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="part">
/// The part that this <see cref="IMechanism"/> was added to.
/// </param>
void AddedToPart(IBodyPart part);
/// <summary>
/// Called when the parent <see cref="IMechanism"/> is added to a
/// <see cref="IBodyPart"/> that is attached to a <see cref="IBody"/>.
/// For instance, adding a brain to a head that is attached to a body.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="body">
/// The body that this <see cref="IMechanism"/> was added to.
/// </param>
/// <param name="part">
/// The part that this <see cref="IMechanism"/> was added to.
/// </param>
void AddedToPartInBody(IBody body, IBodyPart part);
/// <summary>
/// Called when the parent <see cref="IBodyPart"/> is removed from a
/// <see cref="IBody"/>.
/// For instance, removing a head with a brain inside from a body.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="old">
/// The body that this <see cref="IMechanism"/> was removed from.
/// </param>
void RemovedFromBody(IBody old);
/// <summary>
/// Called when the parent <see cref="IMechanism"/> is
/// removed from a <see cref="IBodyPart"/> that is not attached to a
/// <see cref="IBody"/>.
/// For instance, removing a brain from a dismembered head.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="old">
/// The part that this <see cref="IMechanism"/> was removed from.
/// </param>
void RemovedFromPart(IBodyPart old);
/// <summary>
/// Called when the parent <see cref="IMechanism"/> is removed from a
/// <see cref="IBodyPart"/> that is attached to a <see cref="IBody"/>.
/// For instance, removing a brain from a head that is attached to a body.
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY SYSTEM CODE!
/// </summary>
/// <param name="oldBody">
/// The body that this <see cref="IMechanism"/> was removed from.
/// </param>
/// <param name="oldPart">
/// The part that this <see cref="IMechanism"/> was removed from.
/// </param>
void RemovedFromPartInBody(IBody oldBody, IBodyPart oldPart);
}
}

View File

@@ -11,7 +11,7 @@ namespace Content.Shared.Body.Mechanism
{
base.Update(frameTime);
foreach (var mechanism in ComponentManager.EntityQuery<IMechanism>(true))
foreach (var mechanism in ComponentManager.EntityQuery<SharedMechanismComponent>(true))
{
mechanism.Update(frameTime);
}

View File

@@ -14,23 +14,23 @@ using Robust.Shared.Utility;
namespace Content.Shared.Body.Mechanism
{
public abstract class SharedMechanismComponent : Component, IMechanism, ISerializationHooks
public abstract class SharedMechanismComponent : Component, ISerializationHooks
{
public override string Name => "Mechanism";
protected readonly Dictionary<int, object> OptionsCache = new();
protected IBody? BodyCache;
protected SharedBodyComponent? BodyCache;
protected int IdHash;
protected IEntity? PerformerCache;
private IBodyPart? _part;
private SharedBodyPartComponent? _part;
[DataField("behaviors", serverOnly: true)] private HashSet<IMechanismBehavior> _behaviorTypes = new();
[DataField("behaviors", serverOnly: true)] private HashSet<SharedMechanismBehavior> _behaviorTypes = new();
private readonly Dictionary<Type, IMechanismBehavior> _behaviors = new();
private readonly Dictionary<Type, SharedMechanismBehavior> _behaviors = new();
public IBody? Body => Part?.Body;
public SharedBodyComponent? Body => Part?.Body;
public IBodyPart? Part
public SharedBodyPartComponent? Part
{
get => _part;
set
@@ -69,7 +69,7 @@ namespace Content.Shared.Body.Mechanism
}
}
public IReadOnlyDictionary<Type, IMechanismBehavior> Behaviors => _behaviors;
public IReadOnlyDictionary<Type, SharedMechanismBehavior> Behaviors => _behaviors;
[DataField("maxDurability")] public int MaxDurability { get; set; } = 10;
@@ -82,8 +82,16 @@ namespace Content.Shared.Body.Mechanism
[DataField("resistance")] public int Resistance { get; set; } = 0;
// TODO BODY OnSizeChanged
/// <summary>
/// Determines whether this
/// <see cref="SharedMechanismComponent"/> can fit into a <see cref="SharedBodyPartComponent"/>.
/// </summary>
[DataField("size")] public int Size { get; set; } = 1;
/// <summary>
/// What kind of <see cref="SharedBodyPartComponent"/> this
/// <see cref="SharedMechanismComponent"/> can be easily installed into.
/// </summary>
[DataField("compatibility")]
public BodyPartCompatibility Compatibility { get; set; } = BodyPartCompatibility.Universal;
@@ -128,7 +136,7 @@ namespace Content.Shared.Body.Mechanism
}
}
public bool EnsureBehavior<T>(out T behavior) where T : IMechanismBehavior, new()
public bool EnsureBehavior<T>(out T behavior) where T : SharedMechanismBehavior, new()
{
if (_behaviors.TryGetValue(typeof(T), out var rawBehavior))
{
@@ -144,12 +152,12 @@ namespace Content.Shared.Body.Mechanism
return false;
}
public bool HasBehavior<T>() where T : IMechanismBehavior
public bool HasBehavior<T>() where T : SharedMechanismBehavior
{
return _behaviors.ContainsKey(typeof(T));
}
public bool TryRemoveBehavior<T>() where T : IMechanismBehavior
public bool TryRemoveBehavior<T>() where T : SharedMechanismBehavior
{
return _behaviors.Remove(typeof(T));
}
@@ -162,7 +170,8 @@ namespace Content.Shared.Body.Mechanism
}
}
public void AddedToBody(IBody body)
// TODO BODY Turn these into event listeners so they dont need to be exposed
public void AddedToBody(SharedBodyComponent body)
{
DebugTools.AssertNotNull(Body);
DebugTools.AssertNotNull(body);
@@ -173,7 +182,7 @@ namespace Content.Shared.Body.Mechanism
}
}
public void AddedToPart(IBodyPart part)
public void AddedToPart(SharedBodyPartComponent part)
{
DebugTools.AssertNotNull(Part);
DebugTools.AssertNotNull(part);
@@ -186,7 +195,7 @@ namespace Content.Shared.Body.Mechanism
}
}
public void AddedToPartInBody(IBody body, IBodyPart part)
public void AddedToPartInBody(SharedBodyComponent body, SharedBodyPartComponent part)
{
DebugTools.AssertNotNull(Body);
DebugTools.AssertNotNull(body);
@@ -201,7 +210,7 @@ namespace Content.Shared.Body.Mechanism
}
}
public void RemovedFromBody(IBody old)
public void RemovedFromBody(SharedBodyComponent old)
{
DebugTools.AssertNull(Body);
DebugTools.AssertNotNull(old);
@@ -212,7 +221,7 @@ namespace Content.Shared.Body.Mechanism
}
}
public void RemovedFromPart(IBodyPart old)
public void RemovedFromPart(SharedBodyPartComponent old)
{
DebugTools.AssertNull(Part);
DebugTools.AssertNotNull(old);
@@ -225,7 +234,7 @@ namespace Content.Shared.Body.Mechanism
}
}
public void RemovedFromPartInBody(IBody oldBody, IBodyPart oldPart)
public void RemovedFromPartInBody(SharedBodyComponent oldBody, SharedBodyPartComponent oldPart)
{
DebugTools.AssertNull(Body);
DebugTools.AssertNotNull(oldBody);

View File

@@ -5,7 +5,7 @@ using Robust.Shared.Serialization;
namespace Content.Shared.Body.Part
{
/// <summary>
/// Determines whether two <see cref="IBodyPart"/>s can connect.
/// Determines whether two <see cref="SharedBodyPartComponent"/>s can connect.
/// </summary>
[Serializable, NetSerializable]
public enum BodyPartCompatibility

View File

@@ -1,81 +0,0 @@
#nullable enable
using System;
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Body.Part.Property;
namespace Content.Shared.Body.Part
{
public static class BodyPartExtensions
{
/// <summary>
/// Checks if the given <see cref="IBodyPart"/> has the specified property.
/// </summary>
/// <param name="part">The <see cref="IBodyPart"/> to check in.</param>
/// <param name="type">
/// The type of <see cref="IBodyPartProperty"/> to check for.
/// </param>
/// <returns>true if found, false otherwise.</returns>
public static bool HasProperty(this IBodyPart part, Type type)
{
return part.Owner.HasComponent(type);
}
/// <summary>
/// Checks if the given <see cref="IBodyPart"/> has the specified property.
/// </summary>
/// <param name="part">The <see cref="IBodyPart"/> to check in.</param>
/// <typeparam name="T">
/// The type of <see cref="IBodyPartProperty"/> to check for.
/// </typeparam>
/// <returns>true if found, false otherwise.</returns>
public static bool HasProperty<T>(this IBodyPart part) where T : class, IBodyPartProperty
{
return part.HasProperty(typeof(T));
}
/// <summary>
/// Tries to retrieve the <see cref="IBodyPartProperty"/> with the
/// specified type.
/// </summary>
/// <param name="part">The <see cref="IBodyPart"/> to search in.</param>
/// <param name="type">
/// The type of <see cref="IBodyPartProperty"/> to search for.
/// </param>
/// <param name="property">
/// The property, if it was found. Null otherwise.
/// </param>
/// <returns>
/// true if a component with the specified type was found, false otherwise.
/// </returns>
public static bool TryGetProperty(this IBodyPart part, Type type,
[NotNullWhen(true)] out IBodyPartProperty? property)
{
if (!part.Owner.TryGetComponent(type, out var component))
{
property = null;
return false;
}
return (property = component as IBodyPartProperty) != null;
}
/// <summary>
/// Tries to retrieve the <see cref="IBodyPartProperty"/> with the
/// specified type.
/// </summary>
/// <param name="part">The <see cref="IBodyPart"/> to search in.</param>
/// <typeparam name="T">
/// The type of <see cref="IBodyPartProperty"/> to search for.
/// </typeparam>
/// <param name="property">
/// The property, if it was found. Null otherwise.
/// </param>
/// <returns>
/// true if a component with the specified type was found, false otherwise.
/// </returns>
public static bool TryGetProperty<T>(this IBodyPart part, [NotNullWhen(true)] out T? property) where T : class, IBodyPartProperty
{
return part.Owner.TryGetComponent(out property);
}
}
}

View File

@@ -5,7 +5,7 @@ using Robust.Shared.Serialization;
namespace Content.Shared.Body.Part
{
/// <summary>
/// Defines the symmetry of a <see cref="IBodyPart"/>.
/// Defines the symmetry of a <see cref="SharedBodyPartComponent"/>.
/// </summary>
[Serializable, NetSerializable]
public enum BodyPartSymmetry

View File

@@ -5,7 +5,7 @@ using Robust.Shared.Serialization;
namespace Content.Shared.Body.Part
{
/// <summary>
/// Defines the type of a <see cref="IBodyPart"/>.
/// Defines the type of a <see cref="SharedBodyPartComponent"/>.
/// </summary>
[Serializable, NetSerializable]
public enum BodyPartType

View File

@@ -1,131 +0,0 @@
#nullable enable
using System.Collections.Generic;
using Content.Shared.Body.Components;
using Content.Shared.Body.Mechanism;
using Content.Shared.Body.Surgery;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
namespace Content.Shared.Body.Part
{
public interface IBodyPart : IComponent, IBodyPartContainer
{
/// <summary>
/// The <see cref="IBody"/> to which this <see cref="IBodyPart"/> is
/// attached to.
/// </summary>
IBody? Body { get; set; }
/// <summary>
/// The string to show when displaying this part's name to players.
/// </summary>
string DisplayName { get; }
/// <summary>
/// <see cref="BodyPartType"/> that this <see cref="IBodyPart"/> is considered
/// to be.
/// For example, <see cref="BodyPartType.Arm"/>.
/// </summary>
BodyPartType PartType { get; }
/// <summary>
/// Determines how many mechanisms can be fit inside this
/// <see cref="IBodyPart"/>.
/// </summary>
int Size { get; }
// TODO BODY Mechanisms occupying different parts at the body level
/// <summary>
/// Collection of all <see cref="IMechanism"/>s currently inside this
/// <see cref="IBodyPart"/>.
/// To add and remove from this list see <see cref="TryAddMechanism"/> and
/// <see cref="RemoveMechanism"/>
/// </summary>
IReadOnlyCollection<IMechanism> Mechanisms { get; }
/// <summary>
/// Whether or not the owning <see cref="Body"/> will die if all
/// <see cref="IBodyPart"/>s of this type are removed from it.
/// </summary>
public bool IsVital { get; }
/// <summary>
/// The symmetry of this <see cref="IBodyPart"/>.
/// </summary>
public BodyPartSymmetry Symmetry { get; }
/// <summary>
/// Checks if the given <see cref="SurgeryType"/> can be used on
/// the current state of this <see cref="IBodyPart"/>.
/// </summary>
/// <returns>True if it can be used, false otherwise.</returns>
bool SurgeryCheck(SurgeryType surgery);
/// <summary>
/// Attempts to perform surgery on this <see cref="IBodyPart"/> with the given
/// tool.
/// </summary>
/// <returns>True if successful, false if there was an error.</returns>
public bool AttemptSurgery(SurgeryType toolType, IBodyPartContainer target, ISurgeon surgeon,
IEntity performer);
/// <summary>
/// Checks if another <see cref="IBodyPart"/> can be connected to this one.
/// </summary>
/// <param name="part">The part to connect.</param>
/// <returns>True if it can be connected, false otherwise.</returns>
bool CanAttachPart(IBodyPart part);
/// <summary>
/// Checks if a <see cref="IMechanism"/> can be added on this
/// <see cref="IBodyPart"/>.
/// </summary>
/// <returns>True if it can be added, false otherwise.</returns>
bool CanAddMechanism(IMechanism mechanism);
/// <summary>
/// Tries to add a <see cref="IMechanism"/> to this body.
/// </summary>
/// <param name="mechanism">The mechanism to add.</param>
/// <param name="force">
/// Whether or not to check if the mechanism is compatible.
/// Passing true does not guarantee it to be added, for example if
/// it was already added before.
/// </param>
/// <returns>true if added, false otherwise even if it was already added.</returns>
bool TryAddMechanism(IMechanism mechanism, bool force = false);
/// <summary>
/// Tries to remove the given <see cref="mechanism"/> from this
/// <see cref="IBodyPart"/>.
/// </summary>
/// <param name="mechanism">The mechanism to remove.</param>
/// <returns>True if it was removed, false otherwise.</returns>
bool RemoveMechanism(IMechanism mechanism);
/// <summary>
/// Tries to remove the given <see cref="mechanism"/> from this
/// <see cref="IBodyPart"/> and drops it at the specified coordinates.
/// </summary>
/// <param name="mechanism">The mechanism to remove.</param>
/// <param name="dropAt">The coordinates to drop it at.</param>
/// <returns>True if it was removed, false otherwise.</returns>
bool RemoveMechanism(IMechanism mechanism, EntityCoordinates dropAt);
/// <summary>
/// Tries to destroy the given <see cref="IMechanism"/> from
/// this <see cref="IBodyPart"/>.
/// The mechanism won't be deleted if it is not in this body part.
/// </summary>
/// <returns>
/// True if the mechanism was in this body part and destroyed,
/// false otherwise.
/// </returns>
bool DeleteMechanism(IMechanism mechanism);
/// <summary>
/// Gibs the body part.
/// </summary>
void Gib();
}
}

View File

@@ -11,7 +11,7 @@ namespace Content.Shared.Body.Part
public interface IBodyPartAdded : IComponent
{
/// <summary>
/// Called when a <see cref="IBodyPart"/> is added to the
/// Called when a <see cref="SharedBodyPartComponent"/> is added to the
/// entity owning this component.
/// </summary>
/// <param name="args">Information about the part that was added.</param>
@@ -20,7 +20,7 @@ namespace Content.Shared.Body.Part
public class BodyPartAddedEventArgs : EventArgs
{
public BodyPartAddedEventArgs(string slot, IBodyPart part)
public BodyPartAddedEventArgs(string slot, SharedBodyPartComponent part)
{
Slot = slot;
Part = part;
@@ -34,6 +34,6 @@ namespace Content.Shared.Body.Part
/// <summary>
/// The part that was added.
/// </summary>
public IBodyPart Part { get; }
public SharedBodyPartComponent Part { get; }
}
}

View File

@@ -10,7 +10,7 @@ namespace Content.Shared.Body.Part
public interface IBodyPartRemoved
{
/// <summary>
/// Called when a <see cref="IBodyPart"/> is removed from the
/// Called when a <see cref="SharedBodyPartComponent"/> is removed from the
/// entity owning this component.
/// </summary>
/// <param name="args">Information about the part that was removed.</param>
@@ -19,7 +19,7 @@ namespace Content.Shared.Body.Part
public class BodyPartRemovedEventArgs : EventArgs
{
public BodyPartRemovedEventArgs(string slot, IBodyPart part)
public BodyPartRemovedEventArgs(string slot, SharedBodyPartComponent part)
{
Slot = slot;
Part = part;
@@ -33,6 +33,6 @@ namespace Content.Shared.Body.Part
/// <summary>
/// The part that was removed.
/// </summary>
public IBodyPart Part { get; }
public SharedBodyPartComponent Part { get; }
}
}

View File

@@ -5,10 +5,10 @@ using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Shared.Body.Part.Property
{
/// <summary>
/// Property attachable to a <see cref="IBodyPart"/>.
/// Property attachable to a <see cref="SharedBodyPartComponent"/>.
/// For example, this is used to define the speed capabilities of a leg.
/// The movement system will look for a <see cref="LegComponent"/> on all
/// <see cref="IBodyPart"/>.
/// <see cref="SharedBodyPartComponent"/>.
/// </summary>
public abstract class BodyPartPropertyComponent : Component, IBodyPartProperty
{

View File

@@ -5,7 +5,7 @@ using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Shared.Body.Part.Property
{
/// <summary>
/// Defines the length of a <see cref="IBodyPart"/>.
/// Defines the length of a <see cref="SharedBodyPartComponent"/>.
/// </summary>
[RegisterComponent]
public class ExtensionComponent : BodyPartPropertyComponent

View File

@@ -4,7 +4,7 @@ using Robust.Shared.GameObjects;
namespace Content.Shared.Body.Part.Property
{
/// <summary>
/// Defines a <see cref="IBodyPart"/> as being able to grasp around an entity,
/// Defines a <see cref="SharedBodyPartComponent"/> as being able to grasp around an entity,
/// for example picking up an item.
/// </summary>
// TODO BODY Implement

View File

@@ -4,7 +4,7 @@ using Robust.Shared.GameObjects;
namespace Content.Shared.Body.Part.Property
{
/// <summary>
/// Defines a property for a <see cref="IBodyPart"/>.
/// Defines a property for a <see cref="SharedBodyPartComponent"/>.
/// </summary>
public interface IBodyPartProperty : IComponent
{

View File

@@ -5,7 +5,7 @@ using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Shared.Body.Part.Property
{
/// <summary>
/// Defines the speed at which a <see cref="IBodyPart"/> can move.
/// Defines the speed at which a <see cref="SharedBodyPartComponent"/> can move.
/// </summary>
[RegisterComponent]
public class LegComponent : BodyPartPropertyComponent

View File

@@ -1,9 +1,12 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Shared.Body.Behavior;
using Content.Shared.Body.Components;
using Content.Shared.Body.Mechanism;
using Content.Shared.Body.Part.Property;
using Content.Shared.Body.Surgery;
using Content.Shared.NetIDs;
using Robust.Shared.GameObjects;
@@ -17,24 +20,24 @@ using Robust.Shared.ViewVariables;
namespace Content.Shared.Body.Part
{
public abstract class SharedBodyPartComponent : Component, IBodyPart
public abstract class SharedBodyPartComponent : Component, IBodyPartContainer
{
public override string Name => "BodyPart";
public override uint? NetID => ContentNetIDs.BODY_PART;
private IBody? _body;
private SharedBodyComponent? _body;
// TODO BODY Remove
[DataField("mechanisms")]
private List<string> _mechanismIds = new();
private readonly List<string> _mechanismIds = new();
public IReadOnlyList<string> MechanismIds => _mechanismIds;
[ViewVariables]
private readonly HashSet<IMechanism> _mechanisms = new();
private readonly HashSet<SharedMechanismComponent> _mechanisms = new();
[ViewVariables]
public IBody? Body
public SharedBodyComponent? Body
{
get => _body;
set
@@ -59,13 +62,25 @@ namespace Content.Shared.Body.Part
}
}
/// <summary>
/// The string to show when displaying this part's name to players.
/// </summary>
[ViewVariables]
public string DisplayName => Name;
/// <summary>
/// <see cref="BodyPartType"/> that this <see cref="IBodyPart"/> is considered
/// to be.
/// For example, <see cref="BodyPartType.Arm"/>.
/// </summary>
[ViewVariables]
[DataField("partType")]
public BodyPartType PartType { get; private set; } = BodyPartType.Other;
/// <summary>
/// Determines how many mechanisms can be fit inside this
/// <see cref="SharedBodyPartComponent"/>.
/// </summary>
[ViewVariables] [DataField("size")] public int Size { get; private set; } = 1;
[ViewVariables] public int SizeUsed { get; private set; }
@@ -74,7 +89,7 @@ namespace Content.Shared.Body.Part
// TODO BODY surgerydata
/// <summary>
/// What types of BodyParts this <see cref="IBodyPart"/> can easily attach to.
/// What types of BodyParts this <see cref="SharedBodyPartComponent"/> can easily attach to.
/// For the most part, most limbs aren't universal and require extra work to
/// attach between types.
/// </summary>
@@ -82,17 +97,14 @@ namespace Content.Shared.Body.Part
[DataField("compatibility")]
public BodyPartCompatibility Compatibility { get; private set; } = BodyPartCompatibility.Universal;
/// <summary>
/// Set of all <see cref="IMechanism"/> currently inside this
/// <see cref="IBodyPart"/>.
/// </summary>
// TODO BODY Mechanisms occupying different parts at the body level
[ViewVariables]
public IReadOnlyCollection<IMechanism> Mechanisms => _mechanisms;
public IReadOnlyCollection<SharedMechanismComponent> Mechanisms => _mechanisms;
// TODO BODY Replace with a simulation of organs
/// <summary>
/// Represents if body part is vital for creature.
/// If the last vital body part is removed creature dies
/// Whether or not the owning <see cref="Body"/> will die if all
/// <see cref="SharedBodyPartComponent"/>s of this type are removed from it.
/// </summary>
[ViewVariables]
[DataField("vital")]
@@ -105,7 +117,7 @@ namespace Content.Shared.Body.Part
[ViewVariables]
public ISurgeryData? SurgeryDataComponent => Owner.GetComponentOrNull<ISurgeryData>();
protected virtual void OnAddMechanism(IMechanism mechanism)
protected virtual void OnAddMechanism(SharedMechanismComponent mechanism)
{
var prototypeId = mechanism.Owner.Prototype!.ID;
@@ -120,7 +132,7 @@ namespace Content.Shared.Body.Part
Dirty();
}
protected virtual void OnRemoveMechanism(IMechanism mechanism)
protected virtual void OnRemoveMechanism(SharedMechanismComponent mechanism)
{
_mechanismIds.Remove(mechanism.Owner.Prototype!.ID);
mechanism.Part = null;
@@ -176,11 +188,6 @@ namespace Content.Shared.Body.Part
return SurgeryDataComponent?.CheckSurgery(surgery) ?? false;
}
/// <summary>
/// Attempts to perform surgery on this <see cref="IBodyPart"/> with the given
/// tool.
/// </summary>
/// <returns>True if successful, false if there was an error.</returns>
public bool AttemptSurgery(SurgeryType toolType, IBodyPartContainer target, ISurgeon surgeon, IEntity performer)
{
DebugTools.AssertNotNull(toolType);
@@ -191,14 +198,14 @@ namespace Content.Shared.Body.Part
return SurgeryDataComponent?.PerformSurgery(toolType, target, surgeon, performer) ?? false;
}
public bool CanAttachPart(IBodyPart part)
public bool CanAttachPart(SharedBodyPartComponent part)
{
DebugTools.AssertNotNull(part);
return SurgeryDataComponent?.CanAttachBodyPart(part) ?? false;
}
public virtual bool CanAddMechanism(IMechanism mechanism)
public virtual bool CanAddMechanism(SharedMechanismComponent mechanism)
{
DebugTools.AssertNotNull(mechanism);
@@ -208,19 +215,16 @@ namespace Content.Shared.Body.Part
}
/// <summary>
/// Tries to add a mechanism onto this body part.
/// Tries to add a <see cref="SharedMechanismComponent"/> to this part.
/// </summary>
/// <param name="mechanism">The mechanism to try to add.</param>
/// <param name="mechanism">The mechanism to add.</param>
/// <param name="force">
/// Whether or not to check if the mechanism can be added.
/// Whether or not to check if the mechanism is compatible.
/// Passing true does not guarantee it to be added, for example if
/// it was already added before.
/// </param>
/// <returns>
/// True if successful, false if there was an error
/// (e.g. not enough room in <see cref="IBodyPart"/>).
/// Will return false even when forced if the mechanism is already
/// added in this <see cref="IBodyPart"/>.
/// </returns>
public bool TryAddMechanism(IMechanism mechanism, bool force = false)
/// <returns>true if added, false otherwise even if it was already added.</returns>
public bool TryAddMechanism(SharedMechanismComponent mechanism, bool force = false)
{
DebugTools.AssertNotNull(mechanism);
@@ -239,7 +243,12 @@ namespace Content.Shared.Body.Part
return true;
}
public bool RemoveMechanism(IMechanism mechanism)
/// <summary>
/// Tries to remove the given <see cref="mechanism"/> from this part.
/// </summary>
/// <param name="mechanism">The mechanism to remove.</param>
/// <returns>True if it was removed, false otherwise.</returns>
public bool RemoveMechanism(SharedMechanismComponent mechanism)
{
DebugTools.AssertNotNull(mechanism);
@@ -253,7 +262,14 @@ namespace Content.Shared.Body.Part
return true;
}
public bool RemoveMechanism(IMechanism mechanism, EntityCoordinates coordinates)
/// <summary>
/// Tries to remove the given <see cref="mechanism"/> from this
/// part and drops it at the specified coordinates.
/// </summary>
/// <param name="mechanism">The mechanism to remove.</param>
/// <param name="coordinates">The coordinates to drop it at.</param>
/// <returns>True if it was removed, false otherwise.</returns>
public bool RemoveMechanism(SharedMechanismComponent mechanism, EntityCoordinates coordinates)
{
if (RemoveMechanism(mechanism))
{
@@ -264,7 +280,16 @@ namespace Content.Shared.Body.Part
return false;
}
public bool DeleteMechanism(IMechanism mechanism)
/// <summary>
/// Tries to destroy the given <see cref="SharedMechanismComponent"/> from
/// this part.
/// The mechanism won't be deleted if it is not in this body part.
/// </summary>
/// <returns>
/// True if the mechanism was in this body part and destroyed,
/// false otherwise.
/// </returns>
public bool DeleteMechanism(SharedMechanismComponent mechanism)
{
DebugTools.AssertNotNull(mechanism);
@@ -277,7 +302,7 @@ namespace Content.Shared.Body.Part
return true;
}
private void AddedToBody(IBody body)
private void AddedToBody(SharedBodyComponent body)
{
Owner.Transform.LocalRotation = 0;
Owner.Transform.AttachParent(body.Owner);
@@ -289,7 +314,7 @@ namespace Content.Shared.Body.Part
}
}
private void RemovedFromBody(IBody old)
private void RemovedFromBody(SharedBodyComponent old)
{
if (!Owner.Transform.Deleted)
{
@@ -304,10 +329,13 @@ namespace Content.Shared.Body.Part
}
}
protected virtual void OnAddedToBody(IBody body) { }
protected virtual void OnAddedToBody(SharedBodyComponent body) { }
protected virtual void OnRemovedFromBody(IBody old) { }
protected virtual void OnRemovedFromBody(SharedBodyComponent old) { }
/// <summary>
/// Gibs the body part.
/// </summary>
public virtual void Gib()
{
foreach (var mechanism in _mechanisms)
@@ -315,12 +343,44 @@ namespace Content.Shared.Body.Part
RemoveMechanism(mechanism);
}
}
public bool HasProperty(Type type)
{
return Owner.HasComponent(type);
}
public bool HasProperty<T>() where T : class, IBodyPartProperty
{
return HasProperty(typeof(T));
}
public bool TryGetProperty(Type type,
[NotNullWhen(true)] out IBodyPartProperty? property)
{
if (!Owner.TryGetComponent(type, out var component))
{
property = null;
return false;
}
return (property = component as IBodyPartProperty) != null;
}
public bool TryGetProperty<T>([NotNullWhen(true)] out T? property) where T : class, IBodyPartProperty
{
return Owner.TryGetComponent(out property);
}
public bool HasMechanismBehavior<T>() where T : SharedMechanismBehavior
{
return Mechanisms.Any(m => m.HasBehavior<T>());
}
}
[Serializable, NetSerializable]
public class BodyPartComponentState : ComponentState
{
[NonSerialized] private List<IMechanism>? _mechanisms;
[NonSerialized] private List<SharedMechanismComponent>? _mechanisms;
public readonly EntityUid[] MechanismIds;
@@ -329,7 +389,7 @@ namespace Content.Shared.Body.Part
MechanismIds = mechanismIds;
}
public List<IMechanism> Mechanisms(IEntityManager? entityManager = null)
public List<SharedMechanismComponent> Mechanisms(IEntityManager? entityManager = null)
{
if (_mechanisms != null)
{
@@ -338,7 +398,7 @@ namespace Content.Shared.Body.Part
entityManager ??= IoCManager.Resolve<IEntityManager>();
var mechanisms = new List<IMechanism>(MechanismIds.Length);
var mechanisms = new List<SharedMechanismComponent>(MechanismIds.Length);
foreach (var id in MechanismIds)
{
@@ -347,7 +407,7 @@ namespace Content.Shared.Body.Part
continue;
}
if (!entity.TryGetComponent(out IMechanism? mechanism))
if (!entity.TryGetComponent(out SharedMechanismComponent? mechanism))
{
continue;
}

View File

@@ -11,7 +11,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Shared.Body.Preset
{
/// <summary>
/// Defines the <see cref="IBodyPart"/>s used in a <see cref="IBody"/>.
/// Defines the parts used in a body.
/// </summary>
[Prototype("bodyPreset")]
[Serializable, NetSerializable]

View File

@@ -37,7 +37,7 @@ namespace Content.Shared.Body.Slot
/// The part currently in this slot, if any.
/// </summary>
[ViewVariables]
public IBodyPart? Part { get; private set; }
public SharedBodyPartComponent? Part { get; private set; }
/// <summary>
/// List of slots that this slot connects to.
@@ -45,21 +45,21 @@ namespace Content.Shared.Body.Slot
[ViewVariables]
public HashSet<BodyPartSlot> Connections { get; private set; }
public event Action<IBodyPart>? PartAdded;
public event Action<SharedBodyPartComponent>? PartAdded;
public event Action<IBodyPart>? PartRemoved;
public event Action<SharedBodyPartComponent>? PartRemoved;
internal void SetConnectionsInternal(IEnumerable<BodyPartSlot> connections)
{
Connections = new HashSet<BodyPartSlot>(connections);
}
public bool CanAddPart(IBodyPart part)
public bool CanAddPart(SharedBodyPartComponent part)
{
return Part == null && part.PartType == PartType;
}
public bool TryAddPart(IBodyPart part)
public bool TryAddPart(SharedBodyPartComponent part)
{
if (!CanAddPart(part))
{
@@ -70,7 +70,7 @@ namespace Content.Shared.Body.Slot
return true;
}
public void SetPart(IBodyPart part)
public void SetPart(SharedBodyPartComponent part)
{
if (Part != null)
{

View File

@@ -12,7 +12,7 @@ namespace Content.Shared.Body.Surgery
public interface ISurgeon
{
public delegate void MechanismRequestCallback(
IMechanism target,
SharedMechanismComponent target,
IBodyPartContainer container,
ISurgeon surgeon,
IEntity performer);
@@ -25,10 +25,10 @@ namespace Content.Shared.Body.Surgery
/// <summary>
/// When performing a surgery, the <see cref="SurgeryDataComponent"/>
/// may sometimes require selecting from a set of
/// <see cref="IMechanism"/>s to operate on.
/// <see cref="SharedMechanismComponent"/>s to operate on.
/// This function is called in that scenario, and it is expected that you call
/// the callback with one <see cref="IMechanism"/> from the provided list.
/// the callback with one <see cref="SharedMechanismComponent"/> from the provided list.
/// </summary>
public void RequestMechanism(IEnumerable<IMechanism> options, MechanismRequestCallback callback);
public void RequestMechanism(IEnumerable<SharedMechanismComponent> options, MechanismRequestCallback callback);
}
}

View File

@@ -6,21 +6,21 @@ using Robust.Shared.GameObjects;
namespace Content.Shared.Body.Surgery
{
/// <summary>
/// Represents the current surgery state of a <see cref="IBodyPart"/>.
/// Represents the current surgery state of a <see cref="SharedBodyPartComponent"/>.
/// </summary>
public interface ISurgeryData : IComponent
{
public delegate void SurgeryAction(IBodyPartContainer container, ISurgeon surgeon, IEntity performer);
/// <summary>
/// The <see cref="IBodyPart"/> this
/// The <see cref="SharedBodyPartComponent"/> this
/// <see cref="ISurgeryData"/> is attached to.
/// </summary>
public IBodyPart? Parent { get; }
public SharedBodyPartComponent? Parent { get; }
/// <summary>
/// The <see cref="BodyPartType"/> of the parent
/// <see cref="IBodyPart"/>.
/// <see cref="SharedBodyPartComponent"/>.
/// </summary>
public BodyPartType? ParentType { get; }
@@ -31,18 +31,18 @@ namespace Content.Shared.Body.Surgery
public string GetDescription();
/// <summary>
/// Returns whether a <see cref="IMechanism"/> can be added into the
/// <see cref="IBodyPart"/> this <see cref="ISurgeryData"/>
/// Returns whether a <see cref="SharedMechanismComponent"/> can be added into the
/// <see cref="SharedBodyPartComponent"/> this <see cref="ISurgeryData"/>
/// represents.
/// </summary>
public bool CanAddMechanism(IMechanism mechanism);
public bool CanAddMechanism(SharedMechanismComponent mechanism);
/// <summary>
/// Returns whether the given <see cref="IBodyPart"/> can be connected
/// to the <see cref="IBodyPart"/> this <see cref="ISurgeryData"/>
/// Returns whether the given <see cref="SharedBodyPartComponent"/> can be connected
/// to the <see cref="SharedBodyPartComponent"/> this <see cref="ISurgeryData"/>
/// represents.
/// </summary>
public bool CanAttachBodyPart(IBodyPart part);
public bool CanAttachBodyPart(SharedBodyPartComponent part);
/// <summary>
/// Gets the delegate corresponding to the surgery step using the given
@@ -56,7 +56,7 @@ namespace Content.Shared.Body.Surgery
/// <summary>
/// Returns whether the given <see cref="SurgeryType"/> can be used to
/// perform a surgery on the <see cref="IBodyPart"/> this
/// perform a surgery on the <see cref="SharedBodyPartComponent"/> this
/// <see cref="ISurgeryData"/> represents.
/// </summary>
public bool CheckSurgery(SurgeryType toolType)

View File

@@ -11,7 +11,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Shared.Body.Template
{
/// <summary>
/// Defines the layout of a <see cref="IBody"/>.
/// Defines the layout of a body.
/// </summary>
[Prototype("bodyTemplate")]
[Serializable, NetSerializable]

View File

@@ -5,7 +5,7 @@ namespace Content.Shared.CharacterAppearance
{
public static class HumanoidVisualLayersExtension
{
public static HumanoidVisualLayers? ToHumanoidLayer(this IBodyPart part)
public static HumanoidVisualLayers? ToHumanoidLayer(this SharedBodyPartComponent part)
{
return part.PartType switch
{

View File

@@ -12,6 +12,7 @@ namespace Content.Shared.Damage
/// <see cref="SharedBodyComponent"/> may require it for extra data
/// (such as selecting which limb to target).
/// </summary>
// TODO BODY: Remove and pretend it never existed
public class DamageChangeParams : EventArgs
{
}

View File

@@ -131,7 +131,7 @@ namespace Content.Shared.Disposal.Components
// TODO: Probably just need a disposable tag.
if (!entity.TryGetComponent(out SharedItemComponent? storable) &&
!entity.HasComponent<IBody>())
!entity.HasComponent<SharedBodyComponent>())
{
return false;
}

View File

@@ -82,7 +82,7 @@ namespace Content.Shared.MedicalScanner
bool IDragDropOn.CanDragDropOn(DragDropEvent eventArgs)
{
return eventArgs.Dragged.HasComponent<IBody>();
return eventArgs.Dragged.HasComponent<SharedBodyComponent>();
}
public abstract bool DragDropOn(DragDropEvent eventArgs);