nullable parts in body prototypes (#12935)
Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>
This commit is contained in:
@@ -5,13 +5,13 @@ using Content.Server.GameTicking;
|
|||||||
using Content.Server.Humanoid;
|
using Content.Server.Humanoid;
|
||||||
using Content.Server.Kitchen.Components;
|
using Content.Server.Kitchen.Components;
|
||||||
using Content.Server.Mind.Components;
|
using Content.Server.Mind.Components;
|
||||||
|
using Content.Server.MobState;
|
||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
using Content.Shared.Body.Part;
|
using Content.Shared.Body.Part;
|
||||||
using Content.Shared.Body.Prototypes;
|
using Content.Shared.Body.Prototypes;
|
||||||
using Content.Shared.Body.Systems;
|
using Content.Shared.Body.Systems;
|
||||||
using Content.Shared.Coordinates;
|
using Content.Shared.Coordinates;
|
||||||
using Content.Shared.Humanoid;
|
using Content.Shared.Humanoid;
|
||||||
using Content.Shared.MobState.Components;
|
|
||||||
using Content.Shared.Movement.Events;
|
using Content.Shared.Movement.Events;
|
||||||
using Content.Shared.Random.Helpers;
|
using Content.Shared.Random.Helpers;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
@@ -25,8 +25,8 @@ public sealed class BodySystem : SharedBodySystem
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly GameTicker _ticker = default!;
|
[Dependency] private readonly GameTicker _ticker = default!;
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
|
|
||||||
[Dependency] private readonly HumanoidSystem _humanoidSystem = default!;
|
[Dependency] private readonly HumanoidSystem _humanoidSystem = default!;
|
||||||
|
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -40,8 +40,7 @@ public sealed class BodySystem : SharedBodySystem
|
|||||||
|
|
||||||
private void OnRelayMoveInput(EntityUid uid, BodyComponent component, ref MoveInputEvent args)
|
private void OnRelayMoveInput(EntityUid uid, BodyComponent component, ref MoveInputEvent args)
|
||||||
{
|
{
|
||||||
if (EntityManager.TryGetComponent<MobStateComponent>(uid, out var mobState) &&
|
if (_mobState.IsDead(uid) &&
|
||||||
mobState.IsDead() &&
|
|
||||||
EntityManager.TryGetComponent<MindComponent>(uid, out var mind) &&
|
EntityManager.TryGetComponent<MindComponent>(uid, out var mind) &&
|
||||||
mind.HasMind)
|
mind.HasMind)
|
||||||
{
|
{
|
||||||
@@ -119,14 +118,15 @@ public sealed class BodySystem : SharedBodySystem
|
|||||||
protected override void InitBody(BodyComponent body, BodyPrototype prototype)
|
protected override void InitBody(BodyComponent body, BodyPrototype prototype)
|
||||||
{
|
{
|
||||||
var root = prototype.Slots[prototype.Root];
|
var root = prototype.Slots[prototype.Root];
|
||||||
|
Containers.EnsureContainer<Container>(body.Owner, BodyContainerId);
|
||||||
|
if (root.Part == null)
|
||||||
|
return;
|
||||||
var bodyId = Spawn(root.Part, body.Owner.ToCoordinates());
|
var bodyId = Spawn(root.Part, body.Owner.ToCoordinates());
|
||||||
var partComponent = Comp<BodyPartComponent>(bodyId);
|
var partComponent = Comp<BodyPartComponent>(bodyId);
|
||||||
var slot = new BodyPartSlot(root.Part, body.Owner, partComponent.PartType);
|
var slot = new BodyPartSlot(root.Part, body.Owner, partComponent.PartType);
|
||||||
body.Root = slot;
|
body.Root = slot;
|
||||||
partComponent.Body = bodyId;
|
partComponent.Body = bodyId;
|
||||||
|
|
||||||
Containers.EnsureContainer<Container>(body.Owner, BodyContainerId);
|
|
||||||
|
|
||||||
AttachPart(bodyId, slot, partComponent);
|
AttachPart(bodyId, slot, partComponent);
|
||||||
InitPart(partComponent, prototype, prototype.Root);
|
InitPart(partComponent, prototype, prototype.Root);
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ public sealed class BodySystem : SharedBodySystem
|
|||||||
if (bodyId == null || !Resolve(bodyId.Value, ref body, false))
|
if (bodyId == null || !Resolve(bodyId.Value, ref body, false))
|
||||||
return new HashSet<EntityUid>();
|
return new HashSet<EntityUid>();
|
||||||
|
|
||||||
var gibs = base.GibBody(bodyId, gibOrgans, body);
|
var gibs = base.GibBody(bodyId, gibOrgans, body, deleteItems);
|
||||||
|
|
||||||
var xform = Transform(bodyId.Value);
|
var xform = Transform(bodyId.Value);
|
||||||
var coordinates = xform.Coordinates;
|
var coordinates = xform.Coordinates;
|
||||||
@@ -157,7 +157,7 @@ public sealed class BodySystem : SharedBodySystem
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cont.ForceRemove(ent);
|
cont.Remove(ent, EntityManager, force: true);
|
||||||
Transform(ent).Coordinates = coordinates;
|
Transform(ent).Coordinates = coordinates;
|
||||||
ent.RandomOffset(0.25f);
|
ent.RandomOffset(0.25f);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
namespace Content.Shared.Body.Prototypes;
|
namespace Content.Shared.Body.Prototypes;
|
||||||
|
|
||||||
@@ -34,18 +35,19 @@ public sealed class BodyPrototype : IPrototype
|
|||||||
[DataRecord]
|
[DataRecord]
|
||||||
public sealed record BodyPrototypeSlot
|
public sealed record BodyPrototypeSlot
|
||||||
{
|
{
|
||||||
[DataField("part", required: true)] public readonly string Part = default!;
|
[DataField("part", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||||
|
public readonly string? Part;
|
||||||
public readonly HashSet<string> Connections = new();
|
public readonly HashSet<string> Connections = new();
|
||||||
public readonly Dictionary<string, string> Organs = new();
|
public readonly Dictionary<string, string> Organs = new();
|
||||||
|
|
||||||
public BodyPrototypeSlot(string part, HashSet<string>? connections, Dictionary<string, string>? organs)
|
public BodyPrototypeSlot(string? part, HashSet<string>? connections, Dictionary<string, string>? organs)
|
||||||
{
|
{
|
||||||
Part = part;
|
Part = part;
|
||||||
Connections = connections ?? new HashSet<string>();
|
Connections = connections ?? new HashSet<string>();
|
||||||
Organs = organs ?? new Dictionary<string, string>();
|
Organs = organs ?? new Dictionary<string, string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Deconstruct(out string part, out HashSet<string> connections, out Dictionary<string, string> organs)
|
public void Deconstruct(out string? part, out HashSet<string> connections, out Dictionary<string, string> organs)
|
||||||
{
|
{
|
||||||
part = Part;
|
part = Part;
|
||||||
connections = Connections;
|
connections = Connections;
|
||||||
|
|||||||
@@ -14,18 +14,10 @@ namespace Content.Shared.Body.Prototypes;
|
|||||||
[TypeSerializer]
|
[TypeSerializer]
|
||||||
public sealed class BodyPrototypeSerializer : ITypeReader<BodyPrototype, MappingDataNode>
|
public sealed class BodyPrototypeSerializer : ITypeReader<BodyPrototype, MappingDataNode>
|
||||||
{
|
{
|
||||||
private (ValidationNode Node, List<string> Connections) ValidateSlot(ISerializationManager serializationManager, MappingDataNode slot, string slotId, IDependencyCollection dependencies)
|
private (ValidationNode Node, List<string> Connections) ValidateSlot(MappingDataNode slot, IDependencyCollection dependencies)
|
||||||
{
|
{
|
||||||
var nodes = new List<ValidationNode>();
|
var nodes = new List<ValidationNode>();
|
||||||
var prototypes = dependencies.Resolve<IPrototypeManager>();
|
var prototypes = dependencies.Resolve<IPrototypeManager>();
|
||||||
if (!slot.TryGet("part", out ValueDataNode? part))
|
|
||||||
{
|
|
||||||
nodes.Add(new ErrorNode(slot, $"No part value data node found in root slot {slotId}"));
|
|
||||||
}
|
|
||||||
else if (!prototypes.HasIndex<EntityPrototype>(part.Value))
|
|
||||||
{
|
|
||||||
nodes.Add(new ErrorNode(slot, $"No entity prototype found with id {part.Value} for root slot {slotId}"));
|
|
||||||
}
|
|
||||||
|
|
||||||
var connections = new List<string>();
|
var connections = new List<string>();
|
||||||
if (slot.TryGet("connections", out SequenceDataNode? connectionsNode))
|
if (slot.TryGet("connections", out SequenceDataNode? connectionsNode))
|
||||||
@@ -79,8 +71,6 @@ public sealed class BodyPrototypeSerializer : ITypeReader<BodyPrototype, Mapping
|
|||||||
IDependencyCollection dependencies, ISerializationContext? context = null)
|
IDependencyCollection dependencies, ISerializationContext? context = null)
|
||||||
{
|
{
|
||||||
var nodes = new List<ValidationNode>();
|
var nodes = new List<ValidationNode>();
|
||||||
if (!node.TryGet("id", out ValueDataNode? id))
|
|
||||||
nodes.Add(new ErrorNode(node, "No id value data node found"));
|
|
||||||
|
|
||||||
if (!node.TryGet("root", out ValueDataNode? root))
|
if (!node.TryGet("root", out ValueDataNode? root))
|
||||||
nodes.Add(new ErrorNode(node, $"No root value data node found"));
|
nodes.Add(new ErrorNode(node, $"No root value data node found"));
|
||||||
@@ -111,7 +101,7 @@ public sealed class BodyPrototypeSerializer : ITypeReader<BodyPrototype, Mapping
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = ValidateSlot(serializationManager, slot, root.Value, dependencies);
|
var result = ValidateSlot(slot, dependencies);
|
||||||
nodes.Add(result.Node);
|
nodes.Add(result.Node);
|
||||||
|
|
||||||
foreach (var connection in result.Connections)
|
foreach (var connection in result.Connections)
|
||||||
@@ -134,13 +124,18 @@ public sealed class BodyPrototypeSerializer : ITypeReader<BodyPrototype, Mapping
|
|||||||
var name = node.Get<ValueDataNode>("name").Value;
|
var name = node.Get<ValueDataNode>("name").Value;
|
||||||
var root = node.Get<ValueDataNode>("root").Value;
|
var root = node.Get<ValueDataNode>("root").Value;
|
||||||
var slotNodes = node.Get<MappingDataNode>("slots");
|
var slotNodes = node.Get<MappingDataNode>("slots");
|
||||||
var allConnections = new Dictionary<string, (string Part, HashSet<string>? Connections, Dictionary<string, string>? Organs)>();
|
var allConnections = new Dictionary<string, (string? Part, HashSet<string>? Connections, Dictionary<string, string>? Organs)>();
|
||||||
|
|
||||||
foreach (var (keyNode, valueNode) in slotNodes)
|
foreach (var (keyNode, valueNode) in slotNodes)
|
||||||
{
|
{
|
||||||
var slotId = ((ValueDataNode) keyNode).Value;
|
var slotId = ((ValueDataNode) keyNode).Value;
|
||||||
var slot = ((MappingDataNode) valueNode);
|
var slot = ((MappingDataNode) valueNode);
|
||||||
var part = slot.Get<ValueDataNode>("part").Value;
|
|
||||||
|
string? part = null;
|
||||||
|
if (slot.TryGet<ValueDataNode>("part", out var value))
|
||||||
|
{
|
||||||
|
part = value.Value;
|
||||||
|
}
|
||||||
|
|
||||||
HashSet<string>? connections = null;
|
HashSet<string>? connections = null;
|
||||||
if (slot.TryGet("connections", out SequenceDataNode? slotConnectionsNode))
|
if (slot.TryGet("connections", out SequenceDataNode? slotConnectionsNode))
|
||||||
|
|||||||
@@ -88,6 +88,9 @@ public partial class SharedBodySystem
|
|||||||
foreach (var connection in connections)
|
foreach (var connection in connections)
|
||||||
{
|
{
|
||||||
var childSlot = prototype.Slots[connection];
|
var childSlot = prototype.Slots[connection];
|
||||||
|
if (childSlot.Part == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
var childPart = Spawn(childSlot.Part, coordinates);
|
var childPart = Spawn(childSlot.Part, coordinates);
|
||||||
var childPartComponent = Comp<BodyPartComponent>(childPart);
|
var childPartComponent = Comp<BodyPartComponent>(childPart);
|
||||||
var slot = CreatePartSlot(connection, parent.Owner, childPartComponent.PartType, parent);
|
var slot = CreatePartSlot(connection, parent.Owner, childPartComponent.PartType, parent);
|
||||||
|
|||||||
Reference in New Issue
Block a user