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 namespace Content.Client.Body.Components
{ {
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(IBody))] [ComponentReference(typeof(SharedBodyComponent))]
public class BodyComponent : SharedBodyComponent, IDraggable public class BodyComponent : SharedBodyComponent, IDraggable
{ {
bool IDraggable.CanStartDrag(StartDragDropEvent args) bool IDraggable.CanStartDrag(StartDragDropEvent args)

View File

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

View File

@@ -5,6 +5,7 @@ namespace Content.Client.Body.Components
{ {
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(SharedMechanismComponent))] [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 public sealed class BodyScannerDisplay : SS14Window
{ {
private IEntity? _currentEntity; 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) 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)}"; 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)); UpdateMechanismBox(_currentBodyPart?.Mechanisms.ElementAt(args.ItemIndex));
} }
private void UpdateMechanismBox(IMechanism? mechanism) private void UpdateMechanismBox(SharedMechanismComponent? mechanism)
{ {
// TODO BODY Improve UI // TODO BODY Improve UI
if (mechanism == null) if (mechanism == null)

View File

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

View File

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

View File

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

View File

@@ -46,7 +46,7 @@ namespace Content.IntegrationTests.Tests.Body
var entityManager = IoCManager.Resolve<IEntityManager>(); var entityManager = IoCManager.Resolve<IEntityManager>();
var human = entityManager.SpawnEntity("HumanBodyAndAppearanceDummy", new MapCoordinates(Vector2.Zero, mapId)); 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(human.TryGetComponent(out appearance));
Assert.That(!appearance.TryGetData(RotationVisuals.RotationState, out RotationState _)); 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)); 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(body.TryGetMechanismBehaviors(out List<LungBehavior> lungs));
Assert.That(lungs.Count, Is.EqualTo(1)); Assert.That(lungs.Count, Is.EqualTo(1));
Assert.That(human.TryGetComponent(out BloodstreamComponent bloodstream)); Assert.That(human.TryGetComponent(out BloodstreamComponent bloodstream));
@@ -167,7 +167,7 @@ namespace Content.IntegrationTests.Tests.Body
var coordinates = new EntityCoordinates(grid.GridEntityId, center); var coordinates = new EntityCoordinates(grid.GridEntityId, center);
human = entityManager.SpawnEntity("HumanBodyAndBloodstreamDummy", coordinates); 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(body.HasMechanismBehavior<LungBehavior>());
Assert.True(human.TryGetComponent(out metabolism)); Assert.True(human.TryGetComponent(out metabolism));
Assert.False(metabolism.Suffocating); Assert.False(metabolism.Suffocating);

View File

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

View File

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

View File

@@ -69,7 +69,7 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking
// Test for components existing // Test for components existing
Assert.True(human.TryGetComponent(out cuffed!), $"Human has no {nameof(CuffableComponent)}"); 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 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(cuffs.TryGetComponent(out HandcuffComponent _), $"Handcuff has no {nameof(HandcuffComponent)}");
Assert.True(secondCuffs.TryGetComponent(out HandcuffComponent _), $"Second handcuffs 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; 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; if (entity == Owner) continue;
result.Add(entity); result.Add(entity);

View File

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

View File

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

View File

@@ -8,22 +8,24 @@ using Robust.Shared.Utility;
namespace Content.Server.Body.Behavior 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) 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);
DebugTools.AssertNotNull(body); DebugTools.AssertNotNull(body);
@@ -48,7 +52,7 @@ namespace Content.Server.Body.Behavior
OnAddedToBody(body); OnAddedToBody(body);
} }
public void AddedToPart(IBodyPart part) public override void AddedToPart(SharedBodyPartComponent part)
{ {
DebugTools.AssertNotNull(Part); DebugTools.AssertNotNull(Part);
DebugTools.AssertNotNull(part); DebugTools.AssertNotNull(part);
@@ -56,7 +60,7 @@ namespace Content.Server.Body.Behavior
OnAddedToPart(part); OnAddedToPart(part);
} }
public void AddedToPartInBody(IBody body, IBodyPart part) public override void AddedToPartInBody(SharedBodyComponent body, SharedBodyPartComponent part)
{ {
DebugTools.AssertNotNull(Body); DebugTools.AssertNotNull(Body);
DebugTools.AssertNotNull(body); DebugTools.AssertNotNull(body);
@@ -66,7 +70,7 @@ namespace Content.Server.Body.Behavior
OnAddedToPartInBody(body, part); OnAddedToPartInBody(body, part);
} }
public void RemovedFromBody(IBody old) public override void RemovedFromBody(SharedBodyComponent old)
{ {
DebugTools.AssertNull(Body); DebugTools.AssertNull(Body);
DebugTools.AssertNotNull(old); DebugTools.AssertNotNull(old);
@@ -74,7 +78,7 @@ namespace Content.Server.Body.Behavior
OnRemovedFromBody(old); OnRemovedFromBody(old);
} }
public void RemovedFromPart(IBodyPart old) public override void RemovedFromPart(SharedBodyPartComponent old)
{ {
DebugTools.AssertNull(Part); DebugTools.AssertNull(Part);
DebugTools.AssertNotNull(old); DebugTools.AssertNotNull(old);
@@ -82,7 +86,7 @@ namespace Content.Server.Body.Behavior
OnRemovedFromPart(old); OnRemovedFromPart(old);
} }
public void RemovedFromPartInBody(IBody oldBody, IBodyPart oldPart) public override void RemovedFromPartInBody(SharedBodyComponent oldBody, SharedBodyPartComponent oldPart)
{ {
DebugTools.AssertNull(Body); DebugTools.AssertNull(Body);
DebugTools.AssertNull(Part); DebugTools.AssertNull(Part);
@@ -92,18 +96,16 @@ namespace Content.Server.Body.Behavior
OnRemovedFromPartInBody(oldBody, oldPart); 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) { } protected virtual void OnRemovedFromPartInBody(SharedBodyComponent oldBody, SharedBodyPartComponent oldPart) { }
public virtual void Update(float frameTime) { }
} }
} }

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] [RegisterComponent]
[ComponentReference(typeof(SharedBodyComponent))] [ComponentReference(typeof(SharedBodyComponent))]
[ComponentReference(typeof(IBody))]
[ComponentReference(typeof(IGhostOnMove))] [ComponentReference(typeof(IGhostOnMove))]
public class BodyComponent : SharedBodyComponent, IRelayMoveInput, IGhostOnMove public class BodyComponent : SharedBodyComponent, IRelayMoveInput, IGhostOnMove
{ {
private Container _partContainer = default!; private Container _partContainer = default!;
[Dependency] private readonly IGameTicker _gameTicker = 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) && return base.CanAddPart(slotId, part) &&
_partContainer.CanInsert(part.Owner); _partContainer.CanInsert(part.Owner);
} }
protected override void OnAddPart(BodyPartSlot slot, IBodyPart part) protected override void OnAddPart(BodyPartSlot slot, SharedBodyPartComponent part)
{ {
base.OnAddPart(slot, part); base.OnAddPart(slot, part);
_partContainer.Insert(part.Owner); _partContainer.Insert(part.Owner);
} }
protected override void OnRemovePart(BodyPartSlot slot, IBodyPart part) protected override void OnRemovePart(BodyPartSlot slot, SharedBodyPartComponent part)
{ {
base.OnRemovePart(slot, part); base.OnRemovePart(slot, part);
@@ -64,9 +63,9 @@ namespace Content.Server.Body
// a crash within the character preview menu in the lobby // a crash within the character preview menu in the lobby
var entity = Owner.EntityManager.SpawnEntity(preset.PartIDs[slot.Id], Owner.Transform.MapPosition); 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; continue;
} }

View File

@@ -3,11 +3,13 @@ using Content.Shared.Damage;
namespace Content.Server.Body namespace Content.Server.Body
{ {
// TODO BODY: Remove and pretend it never existed
public interface IBodyHealthChangeParams public interface IBodyHealthChangeParams
{ {
BodyPartType Part { get; } BodyPartType Part { get; }
} }
// TODO BODY: Remove and pretend it never existed
public class BodyDamageChangeParams : DamageChangeParams, IBodyHealthChangeParams public class BodyDamageChangeParams : DamageChangeParams, IBodyHealthChangeParams
{ {
public BodyDamageChangeParams(BodyPartType part) 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 random = IoCManager.Resolve<IRobustRandom>();
var text = $"You have no body{(random.Prob(0.2f) ? " and you must scream." : ".")}"; var text = $"You have no body{(random.Prob(0.2f) ? " and you must scream." : ".")}";
@@ -131,9 +131,9 @@ namespace Content.Server.Body.Commands
return; 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; return;
} }

View File

@@ -76,9 +76,9 @@ namespace Content.Server.Body.Commands
return; 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; return;
} }
@@ -88,9 +88,9 @@ namespace Content.Server.Body.Commands
return; 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; return;
} }

View File

@@ -37,7 +37,7 @@ namespace Content.Server.Body.Commands
return; return;
} }
if (!player.AttachedEntity.TryGetComponent(out IBody? body)) if (!player.AttachedEntity.TryGetComponent(out SharedBodyComponent? body))
{ {
var random = IoCManager.Resolve<IRobustRandom>(); var random = IoCManager.Resolve<IRobustRandom>();
var text = $"You have no body{(random.Prob(0.2f) ? " and you must scream." : ".")}"; 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; return;
} }
if (!player.AttachedEntity.TryGetComponent(out IBody? body)) if (!player.AttachedEntity.TryGetComponent(out SharedBodyComponent? body))
{ {
var random = IoCManager.Resolve<IRobustRandom>(); var random = IoCManager.Resolve<IRobustRandom>();
var text = $"You have no body{(random.Prob(0.2f) ? " and you must scream." : ".")}"; 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] [RegisterComponent]
[ComponentReference(typeof(SharedMechanismComponent))] [ComponentReference(typeof(SharedMechanismComponent))]
[ComponentReference(typeof(IMechanism))]
public class MechanismComponent : SharedMechanismComponent, IAfterInteract public class MechanismComponent : SharedMechanismComponent, IAfterInteract
{ {
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(SurgeryUIKey.Key); [ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(SurgeryUIKey.Key);
@@ -47,11 +46,11 @@ namespace Content.Server.Body.Mechanism
PerformerCache = null; PerformerCache = null;
BodyCache = null; BodyCache = null;
if (eventArgs.Target.TryGetComponent(out IBody? body)) if (eventArgs.Target.TryGetComponent(out SharedBodyComponent? body))
{ {
SendBodyPartListToUser(eventArgs, 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); DebugTools.AssertNotNull(part);
@@ -64,7 +63,7 @@ namespace Content.Server.Body.Mechanism
return true; 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) // Create dictionary to send to client (text to be shown : data sent back if selected)
var toSend = new Dictionary<string, int>(); var toSend = new Dictionary<string, int>();
@@ -120,7 +119,7 @@ namespace Content.Server.Body.Mechanism
return; return;
} }
var target = (IBodyPart) targetObject; var target = (SharedBodyPartComponent) targetObject;
var message = target.TryAddMechanism(this) var message = target.TryAddMechanism(this)
? Loc.GetString("You jam {0:theName} inside {1:them}.", Owner, PerformerCache) ? Loc.GetString("You jam {0:theName} inside {1:them}.", Owner, PerformerCache)
: Loc.GetString("You can't fit it in!"); : Loc.GetString("You can't fit it in!");

View File

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

View File

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

View File

@@ -25,7 +25,7 @@ namespace Content.Server.Body.Surgery
{ {
public override string Name => "BiologicalSurgeryData"; public override string Name => "BiologicalSurgeryData";
private readonly HashSet<IMechanism> _disconnectedOrgans = new(); private readonly HashSet<SharedMechanismComponent> _disconnectedOrgans = new();
private bool SkinOpened { get; set; } private bool SkinOpened { get; set; }
@@ -33,11 +33,11 @@ namespace Content.Server.Body.Surgery
private bool VesselsClamped { get; set; } private bool VesselsClamped { get; set; }
public IBodyPart? Parent => Owner.GetComponentOrNull<IBodyPart>(); public SharedBodyPartComponent? Parent => Owner.GetComponentOrNull<SharedBodyPartComponent>();
public BodyPartType? ParentType => Parent?.PartType; public BodyPartType? ParentType => Parent?.PartType;
private void AddDisconnectedOrgan(IMechanism mechanism) private void AddDisconnectedOrgan(SharedMechanismComponent mechanism)
{ {
if (_disconnectedOrgans.Add(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)) if (_disconnectedOrgans.Remove(mechanism))
{ {
@@ -117,7 +117,7 @@ namespace Content.Server.Body.Surgery
return toReturn.ToString(); return toReturn.ToString();
} }
public bool CanAddMechanism(IMechanism mechanism) public bool CanAddMechanism(SharedMechanismComponent mechanism)
{ {
return Parent != null && return Parent != null &&
SkinOpened && SkinOpened &&
@@ -125,7 +125,7 @@ namespace Content.Server.Body.Surgery
SkinRetracted; SkinRetracted;
} }
public bool CanAttachBodyPart(IBodyPart part) public bool CanAttachBodyPart(SharedBodyPartComponent part)
{ {
return Parent != null; 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. // 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 == null) return;
if (Parent.Mechanisms.Count <= 0) return; if (Parent.Mechanisms.Count <= 0) return;
var toSend = new List<IMechanism>(); var toSend = new List<SharedMechanismComponent>();
foreach (var mechanism in Parent.Mechanisms) foreach (var mechanism in Parent.Mechanisms)
{ {
if (!_disconnectedOrgans.Contains(mechanism)) 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) IEntity performer)
{ {
if (Parent == null || target == null || !Parent.Mechanisms.Contains(target)) 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) IEntity performer)
{ {
if (Parent == null || target == null || !Parent.Mechanisms.Contains(target)) 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) private async void RemoveBodyPartSurgery(IBodyPartContainer container, ISurgeon surgeon, IEntity performer)
{ {
if (Parent == null) return; 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!")); 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); [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; } public IEntity? PerformerCache { get; private set; }
@@ -66,7 +66,7 @@ namespace Content.Server.Body.Surgery.Components
CloseAllSurgeryUIs(); CloseAllSurgeryUIs();
// Attempt surgery on a body by sending a list of operable parts for the client to choose from // 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) // Create dictionary to send to client (text to be shown : data sent back if selected)
var toSend = new Dictionary<string, int>(); var toSend = new Dictionary<string, int>();
@@ -93,7 +93,7 @@ namespace Content.Server.Body.Surgery.Components
NotUsefulPopup(); 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 // Attempt surgery on a DroppedBodyPart - there's only one possible target so no need for selection UI
PerformerCache = eventArgs.User; PerformerCache = eventArgs.User;
@@ -113,7 +113,7 @@ namespace Content.Server.Body.Surgery.Components
} }
// Log error if the surgery fails somehow. // 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(); throw new InvalidOperationException();
} }
@@ -122,7 +122,7 @@ namespace Content.Server.Body.Surgery.Components
public float BaseOperationTime { get => _baseOperateTime; set => _baseOperateTime = value; } 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>(); var toSend = new Dictionary<string, int>();
foreach (var mechanism in options) foreach (var mechanism in options)
@@ -211,7 +211,7 @@ namespace Content.Server.Body.Surgery.Components
/// <summary> /// <summary>
/// Called after the client chooses from a list of possible /// 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> /// </summary>
private void HandleReceiveBodyPart(int key) private void HandleReceiveBodyPart(int key)
{ {
@@ -230,7 +230,7 @@ namespace Content.Server.Body.Surgery.Components
return; return;
} }
var target = (IBodyPart) targetObject!; var target = (SharedBodyPartComponent) targetObject!;
// TODO BODY Reconsider // TODO BODY Reconsider
if (!target.AttemptSurgery(_surgeryType, BodyCache, this, PerformerCache)) if (!target.AttemptSurgery(_surgeryType, BodyCache, this, PerformerCache))
@@ -241,7 +241,7 @@ namespace Content.Server.Body.Surgery.Components
/// <summary> /// <summary>
/// Called after the client chooses from a list of possible /// Called after the client chooses from a list of possible
/// <see cref="IMechanism"/> to choose from. /// <see cref="SharedMechanismComponent"/> to choose from.
/// </summary> /// </summary>
private void HandleReceiveMechanism(int key) private void HandleReceiveMechanism(int key)
{ {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -44,7 +44,7 @@ namespace Content.Server.Morgue.Components
protected override bool AddToContents(IEntity entity) 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); return base.AddToContents(entity);
} }

View File

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

View File

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

View File

@@ -69,7 +69,7 @@ namespace Content.Server.Recycling.Components
private bool CanGib(IEntity entity) private bool CanGib(IEntity entity)
{ {
// We suppose this entity has a Recyclable component. // 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) private void Recycle(IEntity entity)
@@ -87,7 +87,7 @@ namespace Content.Server.Recycling.Components
// Mobs are a special case! // Mobs are a special case!
if (CanGib(entity)) if (CanGib(entity))
{ {
entity.GetComponent<IBody>().Gib(true); entity.GetComponent<SharedBodyComponent>().Gib(true);
Bloodstain(); Bloodstain();
return; return;
} }
@@ -159,7 +159,7 @@ namespace Content.Server.Recycling.Components
victim.PopupMessageOtherClients(Loc.GetString("{0:theName} tries to recycle {0:themself}!", victim)); 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); 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 // only items that can be stored in an inventory, or a mob, can be eaten by a locker
if (!entity.HasComponent<SharedItemComponent>() && if (!entity.HasComponent<SharedItemComponent>() &&
!entity.HasComponent<IBody>()) !entity.HasComponent<SharedBodyComponent>())
continue; continue;
if (!AddToContents(entity)) if (!AddToContents(entity))

View File

@@ -144,7 +144,7 @@ namespace Content.Server.Toilet
SuicideKind ISuicideAct.Suicide(IEntity victim, IChatManager chat) SuicideKind ISuicideAct.Suicide(IEntity victim, IChatManager chat)
{ {
// check that victim even have head // check that victim even have head
if (victim.TryGetComponent<IBody>(out var body) && if (victim.TryGetComponent<SharedBodyComponent>(out var body) &&
body.HasPartOfType(BodyPartType.Head)) body.HasPartOfType(BodyPartType.Head))
{ {
var othersMessage = Loc.GetString("{0:theName} sticks their head into {1:theName} and flushes it!", victim, Owner); 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.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using Content.Shared.Body.Behavior;
using Content.Shared.Body.Part; using Content.Shared.Body.Part;
using Content.Shared.Body.Part.Property; using Content.Shared.Body.Part.Property;
using Content.Shared.Body.Preset; using Content.Shared.Body.Preset;
@@ -25,7 +26,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Shared.Body.Components namespace Content.Shared.Body.Components
{ {
// TODO BODY Damage methods for collections of IDamageableComponents // 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!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
@@ -55,13 +56,13 @@ namespace Content.Shared.Body.Components
private Dictionary<string, BodyPartSlot> SlotIds { get; } = new(); private Dictionary<string, BodyPartSlot> SlotIds { get; } = new();
[ViewVariables] [ViewVariables]
private Dictionary<IBodyPart, BodyPartSlot> SlotParts { get; } = new(); private Dictionary<SharedBodyPartComponent, BodyPartSlot> SlotParts { get; } = new();
[ViewVariables] [ViewVariables]
public IEnumerable<BodyPartSlot> Slots => SlotIds.Values; public IEnumerable<BodyPartSlot> Slots => SlotIds.Values;
[ViewVariables] [ViewVariables]
public IEnumerable<KeyValuePair<IBodyPart, BodyPartSlot>> Parts => SlotParts; public IEnumerable<KeyValuePair<SharedBodyPartComponent, BodyPartSlot>> Parts => SlotParts;
[ViewVariables] [ViewVariables]
public IEnumerable<BodyPartSlot> EmptySlots => Slots.Where(slot => slot.Part == null); public IEnumerable<BodyPartSlot> EmptySlots => Slots.Where(slot => slot.Part == null);
@@ -71,7 +72,7 @@ namespace Content.Shared.Body.Components
? SlotIds.GetValueOrDefault(centerSlot) ? SlotIds.GetValueOrDefault(centerSlot)
: null; : null;
public IBodyPart? CenterPart => CenterSlot?.Part; public SharedBodyPartComponent? CenterPart => CenterSlot?.Part;
public override void Initialize() public override void Initialize()
{ {
@@ -119,9 +120,9 @@ namespace Content.Shared.Body.Components
return slot; 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) foreach (var connection in from.Connections)
{ {
@@ -135,7 +136,7 @@ namespace Content.Shared.Body.Components
return hanging; 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) || if (!SlotIds.TryGetValue(slotId, out var slot) ||
slot.CanAddPart(part)) slot.CanAddPart(part))
@@ -146,7 +147,7 @@ namespace Content.Shared.Body.Components
return true; return true;
} }
protected virtual void OnAddPart(BodyPartSlot slot, IBodyPart part) protected virtual void OnAddPart(BodyPartSlot slot, SharedBodyPartComponent part)
{ {
SlotParts[part] = slot; SlotParts[part] = slot;
part.Body = this; part.Body = this;
@@ -162,7 +163,7 @@ namespace Content.Shared.Body.Components
OnBodyChanged(); OnBodyChanged();
} }
protected virtual void OnRemovePart(BodyPartSlot slot, IBodyPart part) protected virtual void OnRemovePart(BodyPartSlot slot, SharedBodyPartComponent part)
{ {
SlotParts.Remove(part); SlotParts.Remove(part);
@@ -203,7 +204,8 @@ namespace Content.Shared.Body.Components
OnBodyChanged(); OnBodyChanged();
} }
public bool TryAddPart(string slotId, IBodyPart part) // TODO BODY Sensible templates
public bool TryAddPart(string slotId, SharedBodyPartComponent part)
{ {
DebugTools.AssertNotNull(part); DebugTools.AssertNotNull(part);
DebugTools.AssertNotNull(slotId); DebugTools.AssertNotNull(slotId);
@@ -217,7 +219,7 @@ namespace Content.Shared.Body.Components
slot.TryAddPart(part); slot.TryAddPart(part);
} }
public void SetPart(string slotId, IBodyPart part) public void SetPart(string slotId, SharedBodyPartComponent part)
{ {
if (!SlotIds.TryGetValue(slotId, out var slot)) if (!SlotIds.TryGetValue(slotId, out var slot))
{ {
@@ -236,14 +238,14 @@ namespace Content.Shared.Body.Components
slot.Part != null; slot.Part != null;
} }
public bool HasPart(IBodyPart part) public bool HasPart(SharedBodyPartComponent part)
{ {
DebugTools.AssertNotNull(part); DebugTools.AssertNotNull(part);
return SlotParts.ContainsKey(part); return SlotParts.ContainsKey(part);
} }
public bool RemovePart(IBodyPart part) public bool RemovePart(SharedBodyPartComponent part)
{ {
DebugTools.AssertNotNull(part); DebugTools.AssertNotNull(part);
@@ -259,7 +261,7 @@ namespace Content.Shared.Body.Components
slot.RemovePart(); 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); DebugTools.AssertNotNull(part);
@@ -279,7 +281,7 @@ namespace Content.Shared.Body.Components
return true; 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); DebugTools.AssertNotNull(slot);
@@ -304,7 +306,7 @@ namespace Content.Shared.Body.Components
return true; return true;
} }
public bool ConnectedToCenter(IBodyPart part) public bool ConnectedToCenter(SharedBodyPartComponent part)
{ {
return TryGetSlot(part, out var result) && return TryGetSlot(part, out var result) &&
ConnectedToCenterPartRecursion(result); ConnectedToCenterPartRecursion(result);
@@ -343,7 +345,7 @@ namespace Content.Shared.Body.Components
return SlotIds.ContainsKey(slot); return SlotIds.ContainsKey(slot);
} }
public IEnumerable<IBodyPart> GetParts() public IEnumerable<SharedBodyPartComponent> GetParts()
{ {
foreach (var slot in SlotIds.Values) 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; result = null;
@@ -367,7 +369,7 @@ namespace Content.Shared.Body.Components
return SlotIds.GetValueOrDefault(id); return SlotIds.GetValueOrDefault(id);
} }
public BodyPartSlot? GetSlot(IBodyPart part) public BodyPartSlot? GetSlot(SharedBodyPartComponent part)
{ {
return SlotParts.GetValueOrDefault(part); return SlotParts.GetValueOrDefault(part);
} }
@@ -377,12 +379,12 @@ namespace Content.Shared.Body.Components
return (slot = GetSlot(slotId)) != null; 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; 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)) if (!SlotIds.TryGetValue(slotId, out var slot))
{ {
@@ -390,7 +392,7 @@ namespace Content.Shared.Body.Components
return false; return false;
} }
connections = new List<IBodyPart>(); connections = new List<SharedBodyPartComponent>();
foreach (var connection in slot.Connections) foreach (var connection in slot.Connections)
{ {
if (connection.Part != null) if (connection.Part != null)
@@ -439,7 +441,7 @@ namespace Content.Shared.Body.Components
return false; return false;
} }
public IEnumerable<IBodyPart> GetPartsOfType(BodyPartType type) public IEnumerable<SharedBodyPartComponent> GetPartsOfType(BodyPartType type)
{ {
foreach (var slot in GetSlotsOfType(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) 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) 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() private void OnBodyChanged()
{ {
// Calculate move speed based on this body. // Calculate move speed based on this body.
@@ -523,19 +523,7 @@ namespace Content.Shared.Body.Components
Dirty(); Dirty();
} }
/// <summary> public float DistanceToNearestFoot(SharedBodyPartComponent source)
/// 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)
{ {
if (source.PartType == BodyPartType.Foot && if (source.PartType == BodyPartType.Foot &&
source.TryGetProperty<ExtensionComponent>(out var extension)) source.TryGetProperty<ExtensionComponent>(out var extension))
@@ -546,7 +534,7 @@ namespace Content.Shared.Body.Components
return LookForFootRecursion(source); 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>(); searched ??= new HashSet<BodyPartSlot>();
@@ -555,13 +543,11 @@ namespace Content.Shared.Body.Components
return float.MinValue; return float.MinValue;
} }
// Get all connected parts if the current part has an extension property
if (!TryGetSlot(current, out var slot)) if (!TryGetSlot(current, out var slot))
{ {
return float.MinValue; return float.MinValue;
} }
// If a connected BodyPart is a foot, return this BodyPart's length.
foreach (var connection in slot.Connections) foreach (var connection in slot.Connections)
{ {
if (connection.PartType == BodyPartType.Foot && 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>(); var distances = new List<float>();
foreach (var connection in slot.Connections) 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) if (distances.Count > 0)
{ {
return distances.Min<float>() + extProperty.Distance; return distances.Min<float>() + extProperty.Distance;
@@ -605,7 +587,7 @@ namespace Content.Shared.Body.Components
return SlotIds.Values.ElementAt(index); return SlotIds.Values.ElementAt(index);
} }
public KeyValuePair<IBodyPart, BodyPartSlot> PartAt(int index) public KeyValuePair<SharedBodyPartComponent, BodyPartSlot> PartAt(int index)
{ {
return SlotParts.ElementAt(index); return SlotParts.ElementAt(index);
} }
@@ -664,12 +646,68 @@ namespace Content.Shared.Body.Components
part.Gib(); 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] [Serializable, NetSerializable]
public class BodyComponentState : ComponentState public class BodyComponentState : ComponentState
{ {
private Dictionary<string, IBodyPart>? _parts; private Dictionary<string, SharedBodyPartComponent>? _parts;
public readonly (string slot, EntityUid partId)[] PartIds; public readonly (string slot, EntityUid partId)[] PartIds;
@@ -678,7 +716,7 @@ namespace Content.Shared.Body.Components
PartIds = partIds; PartIds = partIds;
} }
public Dictionary<string, IBodyPart> Parts(IEntityManager? entityManager = null) public Dictionary<string, SharedBodyPartComponent> Parts(IEntityManager? entityManager = null)
{ {
if (_parts != null) if (_parts != null)
{ {
@@ -687,7 +725,7 @@ namespace Content.Shared.Body.Components
entityManager ??= IoCManager.Resolve<IEntityManager>(); 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) foreach (var (slot, partId) in PartIds)
{ {
@@ -696,7 +734,7 @@ namespace Content.Shared.Body.Components
continue; continue;
} }
if (!entity.TryGetComponent(out IBodyPart? part)) if (!entity.TryGetComponent(out SharedBodyPartComponent? part))
{ {
continue; 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); base.Update(frameTime);
foreach (var mechanism in ComponentManager.EntityQuery<IMechanism>(true)) foreach (var mechanism in ComponentManager.EntityQuery<SharedMechanismComponent>(true))
{ {
mechanism.Update(frameTime); mechanism.Update(frameTime);
} }

View File

@@ -14,23 +14,23 @@ using Robust.Shared.Utility;
namespace Content.Shared.Body.Mechanism namespace Content.Shared.Body.Mechanism
{ {
public abstract class SharedMechanismComponent : Component, IMechanism, ISerializationHooks public abstract class SharedMechanismComponent : Component, ISerializationHooks
{ {
public override string Name => "Mechanism"; public override string Name => "Mechanism";
protected readonly Dictionary<int, object> OptionsCache = new(); protected readonly Dictionary<int, object> OptionsCache = new();
protected IBody? BodyCache; protected SharedBodyComponent? BodyCache;
protected int IdHash; protected int IdHash;
protected IEntity? PerformerCache; 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; get => _part;
set 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; [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; [DataField("resistance")] public int Resistance { get; set; } = 0;
// TODO BODY OnSizeChanged // 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; [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")] [DataField("compatibility")]
public BodyPartCompatibility Compatibility { get; set; } = BodyPartCompatibility.Universal; 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)) if (_behaviors.TryGetValue(typeof(T), out var rawBehavior))
{ {
@@ -144,12 +152,12 @@ namespace Content.Shared.Body.Mechanism
return false; return false;
} }
public bool HasBehavior<T>() where T : IMechanismBehavior public bool HasBehavior<T>() where T : SharedMechanismBehavior
{ {
return _behaviors.ContainsKey(typeof(T)); return _behaviors.ContainsKey(typeof(T));
} }
public bool TryRemoveBehavior<T>() where T : IMechanismBehavior public bool TryRemoveBehavior<T>() where T : SharedMechanismBehavior
{ {
return _behaviors.Remove(typeof(T)); 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);
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);
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);
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.AssertNull(Body);
DebugTools.AssertNotNull(old); 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.AssertNull(Part);
DebugTools.AssertNotNull(old); 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.AssertNull(Body);
DebugTools.AssertNotNull(oldBody); DebugTools.AssertNotNull(oldBody);

View File

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

View File

@@ -5,7 +5,7 @@ using Robust.Shared.Serialization;
namespace Content.Shared.Body.Part namespace Content.Shared.Body.Part
{ {
/// <summary> /// <summary>
/// Defines the type of a <see cref="IBodyPart"/>. /// Defines the type of a <see cref="SharedBodyPartComponent"/>.
/// </summary> /// </summary>
[Serializable, NetSerializable] [Serializable, NetSerializable]
public enum BodyPartType 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 public interface IBodyPartAdded : IComponent
{ {
/// <summary> /// <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. /// entity owning this component.
/// </summary> /// </summary>
/// <param name="args">Information about the part that was added.</param> /// <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 class BodyPartAddedEventArgs : EventArgs
{ {
public BodyPartAddedEventArgs(string slot, IBodyPart part) public BodyPartAddedEventArgs(string slot, SharedBodyPartComponent part)
{ {
Slot = slot; Slot = slot;
Part = part; Part = part;
@@ -34,6 +34,6 @@ namespace Content.Shared.Body.Part
/// <summary> /// <summary>
/// The part that was added. /// The part that was added.
/// </summary> /// </summary>
public IBodyPart Part { get; } public SharedBodyPartComponent Part { get; }
} }
} }

View File

@@ -10,7 +10,7 @@ namespace Content.Shared.Body.Part
public interface IBodyPartRemoved public interface IBodyPartRemoved
{ {
/// <summary> /// <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. /// entity owning this component.
/// </summary> /// </summary>
/// <param name="args">Information about the part that was removed.</param> /// <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 class BodyPartRemovedEventArgs : EventArgs
{ {
public BodyPartRemovedEventArgs(string slot, IBodyPart part) public BodyPartRemovedEventArgs(string slot, SharedBodyPartComponent part)
{ {
Slot = slot; Slot = slot;
Part = part; Part = part;
@@ -33,6 +33,6 @@ namespace Content.Shared.Body.Part
/// <summary> /// <summary>
/// The part that was removed. /// The part that was removed.
/// </summary> /// </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 namespace Content.Shared.Body.Part.Property
{ {
/// <summary> /// <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. /// 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 /// The movement system will look for a <see cref="LegComponent"/> on all
/// <see cref="IBodyPart"/>. /// <see cref="SharedBodyPartComponent"/>.
/// </summary> /// </summary>
public abstract class BodyPartPropertyComponent : Component, IBodyPartProperty public abstract class BodyPartPropertyComponent : Component, IBodyPartProperty
{ {

View File

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

View File

@@ -4,7 +4,7 @@ using Robust.Shared.GameObjects;
namespace Content.Shared.Body.Part.Property namespace Content.Shared.Body.Part.Property
{ {
/// <summary> /// <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. /// for example picking up an item.
/// </summary> /// </summary>
// TODO BODY Implement // TODO BODY Implement

View File

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

View File

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

View File

@@ -1,9 +1,12 @@
#nullable enable #nullable enable
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using Content.Shared.Body.Behavior;
using Content.Shared.Body.Components; using Content.Shared.Body.Components;
using Content.Shared.Body.Mechanism; using Content.Shared.Body.Mechanism;
using Content.Shared.Body.Part.Property;
using Content.Shared.Body.Surgery; using Content.Shared.Body.Surgery;
using Content.Shared.NetIDs; using Content.Shared.NetIDs;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -17,24 +20,24 @@ using Robust.Shared.ViewVariables;
namespace Content.Shared.Body.Part namespace Content.Shared.Body.Part
{ {
public abstract class SharedBodyPartComponent : Component, IBodyPart public abstract class SharedBodyPartComponent : Component, IBodyPartContainer
{ {
public override string Name => "BodyPart"; public override string Name => "BodyPart";
public override uint? NetID => ContentNetIDs.BODY_PART; public override uint? NetID => ContentNetIDs.BODY_PART;
private IBody? _body; private SharedBodyComponent? _body;
// TODO BODY Remove // TODO BODY Remove
[DataField("mechanisms")] [DataField("mechanisms")]
private List<string> _mechanismIds = new(); private readonly List<string> _mechanismIds = new();
public IReadOnlyList<string> MechanismIds => _mechanismIds; public IReadOnlyList<string> MechanismIds => _mechanismIds;
[ViewVariables] [ViewVariables]
private readonly HashSet<IMechanism> _mechanisms = new(); private readonly HashSet<SharedMechanismComponent> _mechanisms = new();
[ViewVariables] [ViewVariables]
public IBody? Body public SharedBodyComponent? Body
{ {
get => _body; get => _body;
set 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] [ViewVariables]
public string DisplayName => Name; 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] [ViewVariables]
[DataField("partType")] [DataField("partType")]
public BodyPartType PartType { get; private set; } = BodyPartType.Other; 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] [DataField("size")] public int Size { get; private set; } = 1;
[ViewVariables] public int SizeUsed { get; private set; } [ViewVariables] public int SizeUsed { get; private set; }
@@ -74,7 +89,7 @@ namespace Content.Shared.Body.Part
// TODO BODY surgerydata // TODO BODY surgerydata
/// <summary> /// <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 /// For the most part, most limbs aren't universal and require extra work to
/// attach between types. /// attach between types.
/// </summary> /// </summary>
@@ -82,17 +97,14 @@ namespace Content.Shared.Body.Part
[DataField("compatibility")] [DataField("compatibility")]
public BodyPartCompatibility Compatibility { get; private set; } = BodyPartCompatibility.Universal; public BodyPartCompatibility Compatibility { get; private set; } = BodyPartCompatibility.Universal;
/// <summary> // TODO BODY Mechanisms occupying different parts at the body level
/// Set of all <see cref="IMechanism"/> currently inside this
/// <see cref="IBodyPart"/>.
/// </summary>
[ViewVariables] [ViewVariables]
public IReadOnlyCollection<IMechanism> Mechanisms => _mechanisms; public IReadOnlyCollection<SharedMechanismComponent> Mechanisms => _mechanisms;
// TODO BODY Replace with a simulation of organs // TODO BODY Replace with a simulation of organs
/// <summary> /// <summary>
/// Represents if body part is vital for creature. /// Whether or not the owning <see cref="Body"/> will die if all
/// If the last vital body part is removed creature dies /// <see cref="SharedBodyPartComponent"/>s of this type are removed from it.
/// </summary> /// </summary>
[ViewVariables] [ViewVariables]
[DataField("vital")] [DataField("vital")]
@@ -105,7 +117,7 @@ namespace Content.Shared.Body.Part
[ViewVariables] [ViewVariables]
public ISurgeryData? SurgeryDataComponent => Owner.GetComponentOrNull<ISurgeryData>(); public ISurgeryData? SurgeryDataComponent => Owner.GetComponentOrNull<ISurgeryData>();
protected virtual void OnAddMechanism(IMechanism mechanism) protected virtual void OnAddMechanism(SharedMechanismComponent mechanism)
{ {
var prototypeId = mechanism.Owner.Prototype!.ID; var prototypeId = mechanism.Owner.Prototype!.ID;
@@ -120,7 +132,7 @@ namespace Content.Shared.Body.Part
Dirty(); Dirty();
} }
protected virtual void OnRemoveMechanism(IMechanism mechanism) protected virtual void OnRemoveMechanism(SharedMechanismComponent mechanism)
{ {
_mechanismIds.Remove(mechanism.Owner.Prototype!.ID); _mechanismIds.Remove(mechanism.Owner.Prototype!.ID);
mechanism.Part = null; mechanism.Part = null;
@@ -176,11 +188,6 @@ namespace Content.Shared.Body.Part
return SurgeryDataComponent?.CheckSurgery(surgery) ?? false; 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) public bool AttemptSurgery(SurgeryType toolType, IBodyPartContainer target, ISurgeon surgeon, IEntity performer)
{ {
DebugTools.AssertNotNull(toolType); DebugTools.AssertNotNull(toolType);
@@ -191,14 +198,14 @@ namespace Content.Shared.Body.Part
return SurgeryDataComponent?.PerformSurgery(toolType, target, surgeon, performer) ?? false; return SurgeryDataComponent?.PerformSurgery(toolType, target, surgeon, performer) ?? false;
} }
public bool CanAttachPart(IBodyPart part) public bool CanAttachPart(SharedBodyPartComponent part)
{ {
DebugTools.AssertNotNull(part); DebugTools.AssertNotNull(part);
return SurgeryDataComponent?.CanAttachBodyPart(part) ?? false; return SurgeryDataComponent?.CanAttachBodyPart(part) ?? false;
} }
public virtual bool CanAddMechanism(IMechanism mechanism) public virtual bool CanAddMechanism(SharedMechanismComponent mechanism)
{ {
DebugTools.AssertNotNull(mechanism); DebugTools.AssertNotNull(mechanism);
@@ -208,19 +215,16 @@ namespace Content.Shared.Body.Part
} }
/// <summary> /// <summary>
/// Tries to add a mechanism onto this body part. /// Tries to add a <see cref="SharedMechanismComponent"/> to this part.
/// </summary> /// </summary>
/// <param name="mechanism">The mechanism to try to add.</param> /// <param name="mechanism">The mechanism to add.</param>
/// <param name="force"> /// <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> /// </param>
/// <returns> /// <returns>true if added, false otherwise even if it was already added.</returns>
/// True if successful, false if there was an error public bool TryAddMechanism(SharedMechanismComponent mechanism, bool force = false)
/// (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)
{ {
DebugTools.AssertNotNull(mechanism); DebugTools.AssertNotNull(mechanism);
@@ -239,7 +243,12 @@ namespace Content.Shared.Body.Part
return true; 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); DebugTools.AssertNotNull(mechanism);
@@ -253,7 +262,14 @@ namespace Content.Shared.Body.Part
return true; 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)) if (RemoveMechanism(mechanism))
{ {
@@ -264,7 +280,16 @@ namespace Content.Shared.Body.Part
return false; 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); DebugTools.AssertNotNull(mechanism);
@@ -277,7 +302,7 @@ namespace Content.Shared.Body.Part
return true; return true;
} }
private void AddedToBody(IBody body) private void AddedToBody(SharedBodyComponent body)
{ {
Owner.Transform.LocalRotation = 0; Owner.Transform.LocalRotation = 0;
Owner.Transform.AttachParent(body.Owner); 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) 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() public virtual void Gib()
{ {
foreach (var mechanism in _mechanisms) foreach (var mechanism in _mechanisms)
@@ -315,12 +343,44 @@ namespace Content.Shared.Body.Part
RemoveMechanism(mechanism); 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] [Serializable, NetSerializable]
public class BodyPartComponentState : ComponentState public class BodyPartComponentState : ComponentState
{ {
[NonSerialized] private List<IMechanism>? _mechanisms; [NonSerialized] private List<SharedMechanismComponent>? _mechanisms;
public readonly EntityUid[] MechanismIds; public readonly EntityUid[] MechanismIds;
@@ -329,7 +389,7 @@ namespace Content.Shared.Body.Part
MechanismIds = mechanismIds; MechanismIds = mechanismIds;
} }
public List<IMechanism> Mechanisms(IEntityManager? entityManager = null) public List<SharedMechanismComponent> Mechanisms(IEntityManager? entityManager = null)
{ {
if (_mechanisms != null) if (_mechanisms != null)
{ {
@@ -338,7 +398,7 @@ namespace Content.Shared.Body.Part
entityManager ??= IoCManager.Resolve<IEntityManager>(); entityManager ??= IoCManager.Resolve<IEntityManager>();
var mechanisms = new List<IMechanism>(MechanismIds.Length); var mechanisms = new List<SharedMechanismComponent>(MechanismIds.Length);
foreach (var id in MechanismIds) foreach (var id in MechanismIds)
{ {
@@ -347,7 +407,7 @@ namespace Content.Shared.Body.Part
continue; continue;
} }
if (!entity.TryGetComponent(out IMechanism? mechanism)) if (!entity.TryGetComponent(out SharedMechanismComponent? mechanism))
{ {
continue; continue;
} }

View File

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

View File

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

View File

@@ -12,7 +12,7 @@ namespace Content.Shared.Body.Surgery
public interface ISurgeon public interface ISurgeon
{ {
public delegate void MechanismRequestCallback( public delegate void MechanismRequestCallback(
IMechanism target, SharedMechanismComponent target,
IBodyPartContainer container, IBodyPartContainer container,
ISurgeon surgeon, ISurgeon surgeon,
IEntity performer); IEntity performer);
@@ -25,10 +25,10 @@ namespace Content.Shared.Body.Surgery
/// <summary> /// <summary>
/// When performing a surgery, the <see cref="SurgeryDataComponent"/> /// When performing a surgery, the <see cref="SurgeryDataComponent"/>
/// may sometimes require selecting from a set of /// 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 /// 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> /// </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 namespace Content.Shared.Body.Surgery
{ {
/// <summary> /// <summary>
/// Represents the current surgery state of a <see cref="IBodyPart"/>. /// Represents the current surgery state of a <see cref="SharedBodyPartComponent"/>.
/// </summary> /// </summary>
public interface ISurgeryData : IComponent public interface ISurgeryData : IComponent
{ {
public delegate void SurgeryAction(IBodyPartContainer container, ISurgeon surgeon, IEntity performer); public delegate void SurgeryAction(IBodyPartContainer container, ISurgeon surgeon, IEntity performer);
/// <summary> /// <summary>
/// The <see cref="IBodyPart"/> this /// The <see cref="SharedBodyPartComponent"/> this
/// <see cref="ISurgeryData"/> is attached to. /// <see cref="ISurgeryData"/> is attached to.
/// </summary> /// </summary>
public IBodyPart? Parent { get; } public SharedBodyPartComponent? Parent { get; }
/// <summary> /// <summary>
/// The <see cref="BodyPartType"/> of the parent /// The <see cref="BodyPartType"/> of the parent
/// <see cref="IBodyPart"/>. /// <see cref="SharedBodyPartComponent"/>.
/// </summary> /// </summary>
public BodyPartType? ParentType { get; } public BodyPartType? ParentType { get; }
@@ -31,18 +31,18 @@ namespace Content.Shared.Body.Surgery
public string GetDescription(); public string GetDescription();
/// <summary> /// <summary>
/// Returns whether a <see cref="IMechanism"/> can be added into the /// Returns whether a <see cref="SharedMechanismComponent"/> can be added into the
/// <see cref="IBodyPart"/> this <see cref="ISurgeryData"/> /// <see cref="SharedBodyPartComponent"/> this <see cref="ISurgeryData"/>
/// represents. /// represents.
/// </summary> /// </summary>
public bool CanAddMechanism(IMechanism mechanism); public bool CanAddMechanism(SharedMechanismComponent mechanism);
/// <summary> /// <summary>
/// Returns whether the given <see cref="IBodyPart"/> can be connected /// Returns whether the given <see cref="SharedBodyPartComponent"/> can be connected
/// to the <see cref="IBodyPart"/> this <see cref="ISurgeryData"/> /// to the <see cref="SharedBodyPartComponent"/> this <see cref="ISurgeryData"/>
/// represents. /// represents.
/// </summary> /// </summary>
public bool CanAttachBodyPart(IBodyPart part); public bool CanAttachBodyPart(SharedBodyPartComponent part);
/// <summary> /// <summary>
/// Gets the delegate corresponding to the surgery step using the given /// Gets the delegate corresponding to the surgery step using the given
@@ -56,7 +56,7 @@ namespace Content.Shared.Body.Surgery
/// <summary> /// <summary>
/// Returns whether the given <see cref="SurgeryType"/> can be used to /// 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. /// <see cref="ISurgeryData"/> represents.
/// </summary> /// </summary>
public bool CheckSurgery(SurgeryType toolType) public bool CheckSurgery(SurgeryType toolType)

View File

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

View File

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

View File

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

View File

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

View File

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