Change all of body system to use entities and components (#2074)
* Early commit * Early commit 2 * merging master broke my git * does anyone even read these * life is fleeting * it just works * this time passing integration tests * Remove hashset yaml serialization for now * You got a license for those nullables? * No examine, no context menu, part and mechanism parenting and visibility * Fix wrong brain sprite state * Removing layers was a mistake * just tear body system a new one and see if it still breathes * Remove redundant code * Add that comment back * Separate damage and body, component states, stomach rework * Add containers for body parts * Bring layers back pls * Fix parts magically changing color * Reimplement sprite layer visibility * Fix tests * Add leg test * Active legs is gone Crab rave * Merge fixes, rename DamageState to CurrentState * Remove IShowContextMenu and ICanExamine
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
#nullable enable
|
||||
using Content.Shared.GameObjects.Components.Body.Part;
|
||||
|
||||
namespace Content.Shared.GameObjects.Components.Body.Mechanism
|
||||
{
|
||||
public interface IMechanism : IHasBody
|
||||
{
|
||||
IBodyPart? Part { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Professional description of the <see cref="IMechanism"/>.
|
||||
/// </summary>
|
||||
string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The message to display upon examining a mob with this
|
||||
/// <see cref="IMechanism"/> added.
|
||||
/// If the string is empty (""), no message will be displayed.
|
||||
/// </summary>
|
||||
string ExamineMessage { get; set; }
|
||||
|
||||
/// <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>
|
||||
/// Called when the part housing this mechanism is added to a body.
|
||||
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY PART CODE!
|
||||
/// </summary>
|
||||
/// <param name="old">The previous body, if any.</param>
|
||||
/// <param name="current">The new body.</param>
|
||||
void OnBodyAdd(IBody? old, IBody current);
|
||||
|
||||
/// <summary>
|
||||
/// Called when the part housing this mechanism is removed from
|
||||
/// a body.
|
||||
/// DO NOT CALL THIS DIRECTLY FROM OUTSIDE BODY PART CODE!
|
||||
/// </summary>
|
||||
/// <param name="old">The old body.</param>
|
||||
void OnBodyRemove(IBody old);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Shared.GameObjects.Components.Body.Behavior;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
namespace Content.Shared.GameObjects.Components.Body.Mechanism
|
||||
{
|
||||
public static class MechanismExtensions
|
||||
{
|
||||
public static bool HasMechanismBehavior<T>(this IEntity entity) where T : IMechanismBehavior
|
||||
{
|
||||
// TODO BODY optimize
|
||||
return entity.TryGetBody(out var body) &&
|
||||
body.Parts.Values.Any(p => p.Mechanisms.Any(m => m.Owner.HasComponent<T>()));
|
||||
}
|
||||
|
||||
public static IEnumerable<T> GetMechanismBehaviors<T>(this IEntity entity) where T : class, IMechanismBehavior
|
||||
{
|
||||
if (!entity.TryGetBody(out var body))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var part in body.Parts.Values)
|
||||
foreach (var mechanism in part.Mechanisms)
|
||||
{
|
||||
if (mechanism.Owner.TryGetComponent(out T? behavior))
|
||||
{
|
||||
yield return behavior;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryGetMechanismBehaviors<T>(this IEntity 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.GameObjects.Components.Body.Part;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.GameObjects.Components.Body.Mechanism
|
||||
{
|
||||
public abstract class SharedMechanismComponent : Component, IMechanism
|
||||
{
|
||||
public override string Name => "Mechanism";
|
||||
|
||||
private IBodyPart? _part;
|
||||
|
||||
protected readonly Dictionary<int, object> OptionsCache = new Dictionary<int, object>();
|
||||
|
||||
protected IBody? BodyCache;
|
||||
|
||||
protected int IdHash;
|
||||
|
||||
protected IEntity? PerformerCache;
|
||||
|
||||
public IBody? Body => Part?.Body;
|
||||
|
||||
public IBodyPart? Part
|
||||
{
|
||||
get => _part;
|
||||
set
|
||||
{
|
||||
if (_part == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var old = _part;
|
||||
_part = value;
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
OnPartAdd(old, value);
|
||||
}
|
||||
else if (old != null)
|
||||
{
|
||||
OnPartRemove(old);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
public string ExamineMessage { get; set; } = string.Empty;
|
||||
|
||||
public int MaxDurability { get; set; }
|
||||
|
||||
public int CurrentDurability { get; set; }
|
||||
|
||||
public int DestroyThreshold { get; set; }
|
||||
|
||||
// TODO BODY
|
||||
public int Resistance { get; set; }
|
||||
|
||||
// TODO BODY OnSizeChanged
|
||||
public int Size { get; set; }
|
||||
|
||||
public BodyPartCompatibility Compatibility { get; set; }
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
|
||||
serializer.DataField(this, m => m.Description, "description", string.Empty);
|
||||
|
||||
serializer.DataField(this, m => m.ExamineMessage, "examineMessage", string.Empty);
|
||||
|
||||
serializer.DataField(this, m => m.MaxDurability, "maxDurability", 10);
|
||||
|
||||
serializer.DataField(this, m => m.CurrentDurability, "currentDurability", MaxDurability);
|
||||
|
||||
serializer.DataField(this, m => m.DestroyThreshold, "destroyThreshold", -MaxDurability);
|
||||
|
||||
serializer.DataField(this, m => m.Resistance, "resistance", 0);
|
||||
|
||||
serializer.DataField(this, m => m.Size, "size", 1);
|
||||
|
||||
serializer.DataField(this, m => m.Compatibility, "compatibility", BodyPartCompatibility.Universal);
|
||||
}
|
||||
|
||||
public virtual void OnBodyAdd(IBody? old, IBody current) { }
|
||||
|
||||
public virtual void OnBodyRemove(IBody old) { }
|
||||
|
||||
protected virtual void OnPartAdd(IBodyPart? old, IBodyPart current)
|
||||
{
|
||||
Owner.Transform.AttachParent(current.Owner);
|
||||
}
|
||||
|
||||
protected virtual void OnPartRemove(IBodyPart old)
|
||||
{
|
||||
Owner.Transform.AttachToGridOrMap();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user