Slay bobby pt. 1 (#5632)
This commit is contained in:
@@ -1,207 +0,0 @@
|
||||
#nullable enable
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Body.Behavior;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Body.Part;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Body
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(SharedBodyComponent))]
|
||||
[TestOf(typeof(SharedBodyPartComponent))]
|
||||
[TestOf(typeof(SharedMechanismComponent))]
|
||||
[TestOf(typeof(MechanismBehavior))]
|
||||
public class MechanismBehaviorEventsTest : ContentIntegrationTest
|
||||
{
|
||||
private class TestMechanismBehavior : MechanismBehavior
|
||||
{
|
||||
public bool WasAddedToBody;
|
||||
public bool WasAddedToPart;
|
||||
public bool WasAddedToPartInBody;
|
||||
public bool WasRemovedFromBody;
|
||||
public bool WasRemovedFromPart;
|
||||
public bool WasRemovedFromPartInBody;
|
||||
|
||||
public bool NoAdded()
|
||||
{
|
||||
return !WasAddedToBody && !WasAddedToPart && !WasAddedToPartInBody;
|
||||
}
|
||||
|
||||
public bool NoRemoved()
|
||||
{
|
||||
return !WasRemovedFromBody && !WasRemovedFromPart && !WasRemovedFromPartInBody;
|
||||
}
|
||||
|
||||
public void ResetAdded()
|
||||
{
|
||||
WasAddedToBody = false;
|
||||
WasAddedToPart = false;
|
||||
WasAddedToPartInBody = false;
|
||||
}
|
||||
|
||||
public void ResetRemoved()
|
||||
{
|
||||
WasRemovedFromBody = false;
|
||||
WasRemovedFromPart = false;
|
||||
WasRemovedFromPartInBody = false;
|
||||
}
|
||||
|
||||
public void ResetAll()
|
||||
{
|
||||
ResetAdded();
|
||||
ResetRemoved();
|
||||
}
|
||||
|
||||
protected override void OnAddedToBody(SharedBodyComponent body)
|
||||
{
|
||||
base.OnAddedToBody(body);
|
||||
|
||||
WasAddedToBody = true;
|
||||
}
|
||||
|
||||
protected override void OnAddedToPart(SharedBodyPartComponent part)
|
||||
{
|
||||
base.OnAddedToPart(part);
|
||||
|
||||
WasAddedToPart = true;
|
||||
}
|
||||
|
||||
protected override void OnAddedToPartInBody(SharedBodyComponent body, SharedBodyPartComponent part)
|
||||
{
|
||||
base.OnAddedToPartInBody(body, part);
|
||||
|
||||
WasAddedToPartInBody = true;
|
||||
}
|
||||
|
||||
protected override void OnRemovedFromBody(SharedBodyComponent old)
|
||||
{
|
||||
base.OnRemovedFromBody(old);
|
||||
|
||||
WasRemovedFromBody = true;
|
||||
}
|
||||
|
||||
protected override void OnRemovedFromPart(SharedBodyPartComponent old)
|
||||
{
|
||||
base.OnRemovedFromPart(old);
|
||||
|
||||
WasRemovedFromPart = true;
|
||||
}
|
||||
|
||||
protected override void OnRemovedFromPartInBody(SharedBodyComponent oldBody, SharedBodyPartComponent oldPart)
|
||||
{
|
||||
base.OnRemovedFromPartInBody(oldBody, oldPart);
|
||||
|
||||
WasRemovedFromPartInBody = true;
|
||||
}
|
||||
}
|
||||
|
||||
private const string Prototypes = @"
|
||||
- type: entity
|
||||
name: HumanBodyDummy
|
||||
id: HumanBodyDummy
|
||||
components:
|
||||
- type: Body
|
||||
template: HumanoidTemplate
|
||||
preset: HumanPreset
|
||||
centerSlot: torso
|
||||
";
|
||||
|
||||
[Test]
|
||||
public async Task EventsTest()
|
||||
{
|
||||
var options = new ServerContentIntegrationOption {ExtraPrototypes = Prototypes};
|
||||
var server = StartServer(options);
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var mapManager = IoCManager.Resolve<IMapManager>();
|
||||
|
||||
var mapId = mapManager.CreateMap();
|
||||
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
var human = entityManager.SpawnEntity("HumanBodyDummy", new MapCoordinates(Vector2.Zero, mapId));
|
||||
|
||||
Assert.That(human.TryGetComponent(out SharedBodyComponent? body));
|
||||
Assert.NotNull(body);
|
||||
|
||||
var centerPart = body!.CenterPart;
|
||||
Assert.NotNull(centerPart);
|
||||
|
||||
Assert.That(body.TryGetSlot(centerPart!, out var centerSlot));
|
||||
Assert.NotNull(centerSlot);
|
||||
|
||||
var mechanism = centerPart!.Mechanisms.First();
|
||||
Assert.NotNull(mechanism);
|
||||
|
||||
mechanism.EnsureBehavior<TestMechanismBehavior>(out var behavior);
|
||||
Assert.False(behavior.WasAddedToBody);
|
||||
Assert.False(behavior.WasAddedToPart);
|
||||
Assert.That(behavior.WasAddedToPartInBody);
|
||||
Assert.That(behavior.NoRemoved);
|
||||
|
||||
behavior.ResetAll();
|
||||
|
||||
Assert.That(behavior.NoAdded);
|
||||
Assert.That(behavior.NoRemoved);
|
||||
|
||||
centerPart.RemoveMechanism(mechanism);
|
||||
|
||||
Assert.That(behavior.NoAdded);
|
||||
Assert.False(behavior.WasRemovedFromBody);
|
||||
Assert.False(behavior.WasRemovedFromPart);
|
||||
Assert.That(behavior.WasRemovedFromPartInBody);
|
||||
|
||||
behavior.ResetAll();
|
||||
|
||||
centerPart.TryAddMechanism(mechanism, true);
|
||||
|
||||
Assert.False(behavior.WasAddedToBody);
|
||||
Assert.False(behavior.WasAddedToPart);
|
||||
Assert.That(behavior.WasAddedToPartInBody);
|
||||
Assert.That(behavior.NoRemoved());
|
||||
|
||||
behavior.ResetAll();
|
||||
|
||||
body.RemovePart(centerPart);
|
||||
|
||||
Assert.That(behavior.NoAdded);
|
||||
Assert.That(behavior.WasRemovedFromBody);
|
||||
Assert.False(behavior.WasRemovedFromPart);
|
||||
Assert.False(behavior.WasRemovedFromPartInBody);
|
||||
|
||||
behavior.ResetAll();
|
||||
|
||||
centerPart.RemoveMechanism(mechanism);
|
||||
|
||||
Assert.That(behavior.NoAdded);
|
||||
Assert.False(behavior.WasRemovedFromBody);
|
||||
Assert.That(behavior.WasRemovedFromPart);
|
||||
Assert.False(behavior.WasRemovedFromPartInBody);
|
||||
|
||||
behavior.ResetAll();
|
||||
|
||||
centerPart.TryAddMechanism(mechanism, true);
|
||||
|
||||
Assert.False(behavior.WasAddedToBody);
|
||||
Assert.That(behavior.WasAddedToPart);
|
||||
Assert.False(behavior.WasAddedToPartInBody);
|
||||
Assert.That(behavior.NoRemoved);
|
||||
|
||||
behavior.ResetAll();
|
||||
|
||||
body.SetPart(centerSlot!.Id, centerPart);
|
||||
|
||||
Assert.That(behavior.WasAddedToBody);
|
||||
Assert.False(behavior.WasAddedToPart);
|
||||
Assert.False(behavior.WasAddedToPartInBody);
|
||||
Assert.That(behavior.NoRemoved);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
using Content.Shared.Body.Behavior;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Body.Part;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Body.Behavior
|
||||
{
|
||||
public abstract class MechanismBehavior : SharedMechanismBehavior
|
||||
{
|
||||
private SharedMechanismComponent _parent = default!;
|
||||
|
||||
public override SharedBodyComponent? Body => Part?.Body;
|
||||
|
||||
public override SharedBodyPartComponent? Part => Parent.Part;
|
||||
|
||||
public override SharedMechanismComponent Parent => _parent;
|
||||
|
||||
public override IEntity Owner => Parent.Owner;
|
||||
|
||||
public override void Initialize(SharedMechanismComponent parent)
|
||||
{
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
if (Part == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Body == null)
|
||||
{
|
||||
AddedToPart(Part);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddedToPartInBody(Body, Part);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float frameTime) { }
|
||||
|
||||
public override void AddedToBody(SharedBodyComponent body)
|
||||
{
|
||||
DebugTools.AssertNotNull(Body);
|
||||
DebugTools.AssertNotNull(body);
|
||||
|
||||
OnAddedToBody(body);
|
||||
}
|
||||
|
||||
public override void AddedToPart(SharedBodyPartComponent part)
|
||||
{
|
||||
DebugTools.AssertNotNull(Part);
|
||||
DebugTools.AssertNotNull(part);
|
||||
|
||||
OnAddedToPart(part);
|
||||
}
|
||||
|
||||
public override void AddedToPartInBody(SharedBodyComponent body, SharedBodyPartComponent part)
|
||||
{
|
||||
DebugTools.AssertNotNull(Body);
|
||||
DebugTools.AssertNotNull(body);
|
||||
DebugTools.AssertNotNull(Part);
|
||||
DebugTools.AssertNotNull(part);
|
||||
|
||||
OnAddedToPartInBody(body, part);
|
||||
}
|
||||
|
||||
public override void RemovedFromBody(SharedBodyComponent old)
|
||||
{
|
||||
DebugTools.AssertNull(Body);
|
||||
DebugTools.AssertNotNull(old);
|
||||
|
||||
OnRemovedFromBody(old);
|
||||
}
|
||||
|
||||
public override void RemovedFromPart(SharedBodyPartComponent old)
|
||||
{
|
||||
DebugTools.AssertNull(Part);
|
||||
DebugTools.AssertNotNull(old);
|
||||
|
||||
OnRemovedFromPart(old);
|
||||
}
|
||||
|
||||
public override void RemovedFromPartInBody(SharedBodyComponent oldBody, SharedBodyPartComponent oldPart)
|
||||
{
|
||||
DebugTools.AssertNull(Body);
|
||||
DebugTools.AssertNull(Part);
|
||||
DebugTools.AssertNotNull(oldBody);
|
||||
DebugTools.AssertNotNull(oldPart);
|
||||
|
||||
OnRemovedFromPartInBody(oldBody, oldPart);
|
||||
}
|
||||
|
||||
protected virtual void OnAddedToBody(SharedBodyComponent body) { }
|
||||
|
||||
protected virtual void OnAddedToPart(SharedBodyPartComponent part) { }
|
||||
|
||||
protected virtual void OnAddedToPartInBody(SharedBodyComponent body, SharedBodyPartComponent part) { }
|
||||
|
||||
protected virtual void OnRemovedFromBody(SharedBodyComponent old) { }
|
||||
|
||||
protected virtual void OnRemovedFromPart(SharedBodyPartComponent old) { }
|
||||
|
||||
protected virtual void OnRemovedFromPartInBody(SharedBodyComponent oldBody, SharedBodyPartComponent oldPart) { }
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Alert;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Behavior;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Temperature.Components;
|
||||
using Content.Server.Temperature.Systems;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.MobState.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
using Content.Shared.Body.Components;
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -2,19 +2,15 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Shared.Body.Behavior;
|
||||
using Content.Shared.Body.Part;
|
||||
using Content.Shared.Body.Part.Property;
|
||||
using Content.Shared.Body.Prototypes;
|
||||
using Content.Shared.CharacterAppearance.Systems;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Standing;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
@@ -34,11 +30,11 @@ namespace Content.Shared.Body.Components
|
||||
|
||||
[ViewVariables]
|
||||
[DataField("template", required: true)]
|
||||
private string? TemplateId { get; } = default;
|
||||
private string? TemplateId { get; }
|
||||
|
||||
[ViewVariables]
|
||||
[DataField("preset", required: true)]
|
||||
private string? PresetId { get; } = default;
|
||||
private string? PresetId { get; }
|
||||
|
||||
[ViewVariables]
|
||||
public BodyTemplatePrototype? Template => TemplateId == null
|
||||
@@ -449,93 +445,11 @@ namespace Content.Shared.Body.Components
|
||||
}
|
||||
}
|
||||
|
||||
/// <returns>A list of parts with that property.</returns>
|
||||
public IEnumerable<(SharedBodyPartComponent part, IBodyPartProperty property)> GetPartsWithProperty(Type type)
|
||||
{
|
||||
foreach (var slot in SlotIds.Values)
|
||||
{
|
||||
if (slot.Part != null && slot.Part.TryGetProperty(type, out var property))
|
||||
{
|
||||
yield return (slot.Part, property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<(SharedBodyPartComponent part, T property)> GetPartsWithProperty<T>() where T : class, IBodyPartProperty
|
||||
{
|
||||
foreach (var part in SlotParts.Keys)
|
||||
{
|
||||
if (part.TryGetProperty<T>(out var property))
|
||||
{
|
||||
yield return (part, property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnBodyChanged()
|
||||
{
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public float DistanceToNearestFoot(SharedBodyPartComponent source)
|
||||
{
|
||||
if (source.PartType == BodyPartType.Foot &&
|
||||
source.TryGetProperty<ExtensionComponent>(out var extension))
|
||||
{
|
||||
return extension.Distance;
|
||||
}
|
||||
|
||||
return LookForFootRecursion(source);
|
||||
}
|
||||
|
||||
private float LookForFootRecursion(SharedBodyPartComponent current, HashSet<BodyPartSlot>? searched = null)
|
||||
{
|
||||
searched ??= new HashSet<BodyPartSlot>();
|
||||
|
||||
if (!current.TryGetProperty<ExtensionComponent>(out var extProperty))
|
||||
{
|
||||
return float.MinValue;
|
||||
}
|
||||
|
||||
if (!TryGetSlot(current, out var slot))
|
||||
{
|
||||
return float.MinValue;
|
||||
}
|
||||
|
||||
foreach (var connection in slot.Connections)
|
||||
{
|
||||
if (connection.PartType == BodyPartType.Foot &&
|
||||
!searched.Contains(connection))
|
||||
{
|
||||
return extProperty.Distance;
|
||||
}
|
||||
}
|
||||
|
||||
var distances = new List<float>();
|
||||
foreach (var connection in slot.Connections)
|
||||
{
|
||||
if (connection.Part == null || !searched.Contains(connection))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var result = LookForFootRecursion(connection.Part, searched);
|
||||
|
||||
if (Math.Abs(result - float.MinValue) > 0.001f)
|
||||
{
|
||||
distances.Add(result);
|
||||
}
|
||||
}
|
||||
|
||||
if (distances.Count > 0)
|
||||
{
|
||||
return distances.Min<float>() + extProperty.Distance;
|
||||
}
|
||||
|
||||
return float.MinValue;
|
||||
}
|
||||
|
||||
// TODO BODY optimize this
|
||||
public BodyPartSlot SlotAt(int index)
|
||||
{
|
||||
@@ -601,62 +515,6 @@ namespace Content.Shared.Body.Components
|
||||
part.Gib();
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetMechanismBehaviors([NotNullWhen(true)] out List<SharedMechanismBehavior>? behaviors)
|
||||
{
|
||||
behaviors = GetMechanismBehaviors().ToList();
|
||||
|
||||
if (behaviors.Count == 0)
|
||||
{
|
||||
behaviors = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool HasMechanismBehavior<T>() where T : SharedMechanismBehavior
|
||||
{
|
||||
return Parts.Any(p => p.Key.HasMechanismBehavior<T>());
|
||||
}
|
||||
|
||||
// TODO cache these 2 methods jesus
|
||||
public IEnumerable<SharedMechanismBehavior> GetMechanismBehaviors()
|
||||
{
|
||||
foreach (var (part, _) in Parts)
|
||||
foreach (var mechanism in part.Mechanisms)
|
||||
foreach (var behavior in mechanism.Behaviors.Values)
|
||||
{
|
||||
yield return behavior;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<T> GetMechanismBehaviors<T>() where T : SharedMechanismBehavior
|
||||
{
|
||||
foreach (var (part, _) in Parts)
|
||||
foreach (var mechanism in part.Mechanisms)
|
||||
foreach (var behavior in mechanism.Behaviors.Values)
|
||||
{
|
||||
if (behavior is T tBehavior)
|
||||
{
|
||||
yield return tBehavior;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetMechanismBehaviors<T>([NotNullWhen(true)] out List<T>? behaviors)
|
||||
where T : SharedMechanismBehavior
|
||||
{
|
||||
behaviors = GetMechanismBehaviors<T>().ToList();
|
||||
|
||||
if (behaviors.Count == 0)
|
||||
{
|
||||
behaviors = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Shared.Body.Behavior;
|
||||
using Content.Shared.Body.Events;
|
||||
using Content.Shared.Body.Part;
|
||||
using Content.Shared.Body.Part.Property;
|
||||
using Content.Shared.Body.Surgery;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -307,7 +304,7 @@ namespace Content.Shared.Body.Components
|
||||
|
||||
foreach (var mechanism in _mechanisms)
|
||||
{
|
||||
mechanism.AddedToBody(body);
|
||||
Owner.EntityManager.EventBus.RaiseLocalEvent(mechanism.OwnerUid, new AddedToBodyEvent(body));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,7 +319,7 @@ namespace Content.Shared.Body.Components
|
||||
|
||||
foreach (var mechanism in _mechanisms)
|
||||
{
|
||||
mechanism.RemovedFromBody(old);
|
||||
Owner.EntityManager.EventBus.RaiseLocalEvent(mechanism.OwnerUid, new RemovedFromBodyEvent(old));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,38 +337,6 @@ namespace Content.Shared.Body.Components
|
||||
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]
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Shared.Body.Behavior;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Body.Events;
|
||||
using Content.Shared.Body.Part;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Body.Components
|
||||
{
|
||||
@@ -23,10 +17,6 @@ namespace Content.Shared.Body.Components
|
||||
protected IEntity? PerformerCache;
|
||||
private SharedBodyPartComponent? _part;
|
||||
|
||||
[DataField("behaviors", serverOnly: true)] private HashSet<SharedMechanismBehavior> _behaviorTypes = new();
|
||||
|
||||
private readonly Dictionary<Type, SharedMechanismBehavior> _behaviors = new();
|
||||
|
||||
public SharedBodyComponent? Body => Part?.Body;
|
||||
|
||||
public SharedBodyPartComponent? Part
|
||||
@@ -46,11 +36,11 @@ namespace Content.Shared.Body.Components
|
||||
{
|
||||
if (old.Body == null)
|
||||
{
|
||||
RemovedFromPart(old);
|
||||
Owner.EntityManager.EventBus.RaiseLocalEvent(OwnerUid, new RemovedFromPartEvent(old));
|
||||
}
|
||||
else
|
||||
{
|
||||
RemovedFromPartInBody(old.Body, old);
|
||||
Owner.EntityManager.EventBus.RaiseLocalEvent(OwnerUid, new RemovedFromPartInBodyEvent(old.Body, old));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,18 +48,16 @@ namespace Content.Shared.Body.Components
|
||||
{
|
||||
if (value.Body == null)
|
||||
{
|
||||
AddedToPart(value);
|
||||
Owner.EntityManager.EventBus.RaiseLocalEvent(OwnerUid, new AddedToPartEvent(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
AddedToPartInBody(value.Body, value);
|
||||
Owner.EntityManager.EventBus.RaiseLocalEvent(OwnerUid, new AddedToPartInBodyEvent(value.Body, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<Type, SharedMechanismBehavior> Behaviors => _behaviors;
|
||||
|
||||
[DataField("maxDurability")] public int MaxDurability { get; set; } = 10;
|
||||
|
||||
[DataField("currentDurability")] public int CurrentDurability { get; set; } = 10;
|
||||
@@ -93,176 +81,5 @@ namespace Content.Shared.Body.Components
|
||||
/// </summary>
|
||||
[DataField("compatibility")]
|
||||
public BodyPartCompatibility Compatibility { get; set; } = BodyPartCompatibility.Universal;
|
||||
|
||||
void ISerializationHooks.BeforeSerialization()
|
||||
{
|
||||
_behaviorTypes = _behaviors.Values.ToHashSet();
|
||||
}
|
||||
|
||||
void ISerializationHooks.AfterDeserialization()
|
||||
{
|
||||
foreach (var behavior in _behaviorTypes)
|
||||
{
|
||||
var type = behavior.GetType();
|
||||
|
||||
if (!_behaviors.TryAdd(type, behavior))
|
||||
{
|
||||
Logger.Warning($"Duplicate behavior in {nameof(SharedMechanismComponent)}: {type}.");
|
||||
continue;
|
||||
}
|
||||
|
||||
IoCManager.InjectDependencies(behavior);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
foreach (var behavior in _behaviors.Values)
|
||||
{
|
||||
behavior.Initialize(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
foreach (var behavior in _behaviors.Values)
|
||||
{
|
||||
behavior.Startup();
|
||||
}
|
||||
}
|
||||
|
||||
public bool EnsureBehavior<T>(out T behavior) where T : SharedMechanismBehavior, new()
|
||||
{
|
||||
if (_behaviors.TryGetValue(typeof(T), out var rawBehavior))
|
||||
{
|
||||
behavior = (T) rawBehavior;
|
||||
return true;
|
||||
}
|
||||
|
||||
behavior = IoCManager.Resolve<IDynamicTypeFactory>().CreateInstance<T>();
|
||||
_behaviors.Add(typeof(T), behavior);
|
||||
behavior.Initialize(this);
|
||||
behavior.Startup();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool HasBehavior<T>() where T : SharedMechanismBehavior
|
||||
{
|
||||
return _behaviors.ContainsKey(typeof(T));
|
||||
}
|
||||
|
||||
public bool TryRemoveBehavior<T>() where T : SharedMechanismBehavior
|
||||
{
|
||||
return _behaviors.Remove(typeof(T));
|
||||
}
|
||||
|
||||
public void Update(float frameTime)
|
||||
{
|
||||
foreach (var behavior in _behaviors.Values)
|
||||
{
|
||||
behavior.Update(frameTime);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddedToBody(SharedBodyComponent body)
|
||||
{
|
||||
DebugTools.AssertNotNull(Body);
|
||||
DebugTools.AssertNotNull(body);
|
||||
|
||||
var ev = new AddedToBodyEvent(body);
|
||||
Owner.EntityManager.EventBus.RaiseLocalEvent(OwnerUid, ev, false);
|
||||
|
||||
foreach (var behavior in _behaviors.Values)
|
||||
{
|
||||
behavior.AddedToBody(body);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddedToPart(SharedBodyPartComponent part)
|
||||
{
|
||||
DebugTools.AssertNotNull(Part);
|
||||
DebugTools.AssertNotNull(part);
|
||||
|
||||
Owner.Transform.AttachParent(part.Owner);
|
||||
|
||||
var ev = new AddedToPartEvent(part);
|
||||
Owner.EntityManager.EventBus.RaiseLocalEvent(OwnerUid, ev, false);
|
||||
|
||||
foreach (var behavior in _behaviors.Values)
|
||||
{
|
||||
behavior.AddedToPart(part);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddedToPartInBody(SharedBodyComponent body, SharedBodyPartComponent part)
|
||||
{
|
||||
DebugTools.AssertNotNull(Body);
|
||||
DebugTools.AssertNotNull(body);
|
||||
DebugTools.AssertNotNull(Part);
|
||||
DebugTools.AssertNotNull(part);
|
||||
|
||||
Owner.Transform.AttachParent(part.Owner);
|
||||
|
||||
var ev = new AddedToPartInBodyEvent(body, part);
|
||||
Owner.EntityManager.EventBus.RaiseLocalEvent(OwnerUid, ev, false);
|
||||
|
||||
foreach (var behavior in _behaviors.Values)
|
||||
{
|
||||
behavior.AddedToPartInBody(body, part);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemovedFromBody(SharedBodyComponent old)
|
||||
{
|
||||
DebugTools.AssertNull(Body);
|
||||
DebugTools.AssertNotNull(old);
|
||||
|
||||
var ev = new RemovedFromBodyEvent(old);
|
||||
Owner.EntityManager.EventBus.RaiseLocalEvent(OwnerUid, ev, false);
|
||||
|
||||
foreach (var behavior in _behaviors.Values)
|
||||
{
|
||||
behavior.RemovedFromBody(old);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemovedFromPart(SharedBodyPartComponent old)
|
||||
{
|
||||
DebugTools.AssertNull(Part);
|
||||
DebugTools.AssertNotNull(old);
|
||||
|
||||
Owner.Transform.AttachToGridOrMap();
|
||||
|
||||
var ev = new RemovedFromPartEvent(old);
|
||||
Owner.EntityManager.EventBus.RaiseLocalEvent(OwnerUid, ev, false);
|
||||
|
||||
foreach (var behavior in _behaviors.Values)
|
||||
{
|
||||
behavior.RemovedFromPart(old);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemovedFromPartInBody(SharedBodyComponent oldBody, SharedBodyPartComponent oldPart)
|
||||
{
|
||||
DebugTools.AssertNull(Body);
|
||||
DebugTools.AssertNotNull(oldBody);
|
||||
DebugTools.AssertNull(Part);
|
||||
DebugTools.AssertNotNull(oldPart);
|
||||
|
||||
Owner.Transform.AttachToGridOrMap();
|
||||
|
||||
var ev = new RemovedFromPartInBodyEvent(oldBody, oldPart);
|
||||
Owner.EntityManager.EventBus.RaiseLocalEvent(OwnerUid, ev, false);
|
||||
|
||||
foreach (var behavior in _behaviors.Values)
|
||||
{
|
||||
behavior.RemovedFromPartInBody(oldBody, oldPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using Content.Shared.Body.Components;
|
||||
using Content.Shared.Body.Part;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Shared.Body
|
||||
namespace Content.Shared.Body.Part
|
||||
{
|
||||
public class BodyPartSlot
|
||||
{
|
||||
@@ -1,21 +0,0 @@
|
||||
using Content.Shared.Body.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Shared.Body.Part.Property
|
||||
{
|
||||
/// <summary>
|
||||
/// Property attachable to a <see cref="SharedBodyPartComponent"/>.
|
||||
/// For example, this is used to define the speed capabilities of a leg.
|
||||
/// The movement system will look for a <see cref="LegComponent"/> on all
|
||||
/// <see cref="SharedBodyPartComponent"/>.
|
||||
/// </summary>
|
||||
public abstract class BodyPartPropertyComponent : Component, IBodyPartProperty
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether this property is currently active.
|
||||
/// </summary>
|
||||
[DataField("active")]
|
||||
public bool Active { get; set; } = true;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using Content.Shared.Body.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Shared.Body.Part.Property
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the length of a <see cref="SharedBodyPartComponent"/>.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class ExtensionComponent : BodyPartPropertyComponent
|
||||
{
|
||||
public override string Name => "Extension";
|
||||
|
||||
/// <summary>
|
||||
/// Current distance in tiles.
|
||||
/// </summary>
|
||||
[DataField("distance")]
|
||||
public float Distance { get; set; } = 3f;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using Content.Shared.Body.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Shared.Body.Part.Property
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a <see cref="SharedBodyPartComponent"/> as being able to grasp around an entity,
|
||||
/// for example picking up an item.
|
||||
/// </summary>
|
||||
// TODO BODY Implement
|
||||
[RegisterComponent]
|
||||
public class GraspComponent : BodyPartPropertyComponent
|
||||
{
|
||||
public override string Name => "Grasp";
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using Content.Shared.Body.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Shared.Body.Part.Property
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a property for a <see cref="SharedBodyPartComponent"/>.
|
||||
/// </summary>
|
||||
public interface IBodyPartProperty : IComponent
|
||||
{
|
||||
bool Active { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using Content.Shared.Body.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Shared.Body.Part.Property
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the speed at which a <see cref="SharedBodyPartComponent"/> can move.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class LegComponent : BodyPartPropertyComponent
|
||||
{
|
||||
public override string Name => "Leg";
|
||||
|
||||
/// <summary>
|
||||
/// Speed in tiles per second.
|
||||
/// </summary>
|
||||
[DataField("speed")]
|
||||
public float Speed { get; set; } = 2.6f;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using Content.Shared.Body.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Shared.Body.Systems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class MechanismSystem : EntitySystem
|
||||
{
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
foreach (var mechanism in EntityManager.EntityQuery<SharedMechanismComponent>(true))
|
||||
{
|
||||
mechanism.Update(frameTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@
|
||||
size: 1
|
||||
compatibility: Biological
|
||||
symmetry: Left
|
||||
- type: Grasp
|
||||
|
||||
- type: entity
|
||||
id: LegsAnimal
|
||||
|
||||
@@ -83,8 +83,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 40
|
||||
# deadThreshold: 80
|
||||
- type: Extension
|
||||
distance: 2.4
|
||||
|
||||
- type: entity
|
||||
id: RightArmHuman
|
||||
@@ -106,8 +104,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 40
|
||||
# deadThreshold: 80
|
||||
- type: Extension
|
||||
distance: 2.4
|
||||
|
||||
- type: entity
|
||||
id: LeftHandHuman
|
||||
@@ -129,7 +125,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 30
|
||||
# deadThreshold: 60
|
||||
- type: Grasp
|
||||
|
||||
- type: entity
|
||||
id: RightHandHuman
|
||||
@@ -151,7 +146,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 30
|
||||
# deadThreshold: 60
|
||||
- type: Grasp
|
||||
|
||||
- type: entity
|
||||
id: LeftLegHuman
|
||||
@@ -173,10 +167,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 45
|
||||
# deadThreshold: 90
|
||||
- type: Leg
|
||||
speed: 2.6
|
||||
- type: Extension
|
||||
distance: 3.0
|
||||
|
||||
- type: entity
|
||||
id: RightLegHuman
|
||||
@@ -198,10 +188,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 45
|
||||
# deadThreshold: 90
|
||||
- type: Leg
|
||||
speed: 2.6
|
||||
- type: Extension
|
||||
distance: 3.0
|
||||
|
||||
- type: entity
|
||||
id: LeftFootHuman
|
||||
|
||||
@@ -82,8 +82,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 40
|
||||
# deadThreshold: 80
|
||||
- type: Extension
|
||||
distance: 2.4
|
||||
|
||||
- type: entity
|
||||
id: RightArmSlime
|
||||
@@ -105,8 +103,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 40
|
||||
# deadThreshold: 80
|
||||
- type: Extension
|
||||
distance: 2.4
|
||||
|
||||
- type: entity
|
||||
id: LeftHandSlime
|
||||
@@ -128,7 +124,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 30
|
||||
# deadThreshold: 60
|
||||
- type: Grasp
|
||||
|
||||
- type: entity
|
||||
id: RightHandSlime
|
||||
@@ -150,7 +145,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 30
|
||||
# deadThreshold: 60
|
||||
- type: Grasp
|
||||
|
||||
- type: entity
|
||||
id: LeftLegSlime
|
||||
@@ -170,10 +164,6 @@
|
||||
compatibility: Biological
|
||||
symmetry: Left
|
||||
- type: BiologicalSurgeryData
|
||||
- type: Leg
|
||||
speed: 2.6
|
||||
- type: Extension
|
||||
distance: 3.0
|
||||
|
||||
- type: entity
|
||||
id: RightLegSlime
|
||||
@@ -195,10 +185,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 45
|
||||
# deadThreshold: 90
|
||||
- type: Leg
|
||||
speed: 2.6
|
||||
- type: Extension
|
||||
distance: 3.0
|
||||
|
||||
- type: entity
|
||||
id: LeftFootSlime
|
||||
|
||||
@@ -84,8 +84,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 40
|
||||
# deadThreshold: 80
|
||||
- type: Extension
|
||||
distance: 2.4
|
||||
|
||||
- type: entity
|
||||
id: RightArmVox
|
||||
@@ -107,8 +105,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 40
|
||||
# deadThreshold: 80
|
||||
- type: Extension
|
||||
distance: 2.4
|
||||
|
||||
- type: entity
|
||||
id: LeftHandVox
|
||||
@@ -130,7 +126,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 30
|
||||
# deadThreshold: 60
|
||||
- type: Grasp
|
||||
|
||||
- type: entity
|
||||
id: RightHandVox
|
||||
@@ -152,7 +147,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 30
|
||||
# deadThreshold: 60
|
||||
- type: Grasp
|
||||
|
||||
- type: entity
|
||||
id: LeftLegVox
|
||||
@@ -174,10 +168,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 45
|
||||
# deadThreshold: 90
|
||||
- type: Leg
|
||||
speed: 2.6
|
||||
- type: Extension
|
||||
distance: 3.0
|
||||
|
||||
- type: entity
|
||||
id: RightLegVox
|
||||
@@ -199,10 +189,6 @@
|
||||
- type: BiologicalSurgeryData
|
||||
# criticalThreshold: 45
|
||||
# deadThreshold: 90
|
||||
- type: Leg
|
||||
speed: 2.6
|
||||
- type: Extension
|
||||
distance: 3.0
|
||||
|
||||
- type: entity
|
||||
id: LeftFootVox
|
||||
|
||||
Reference in New Issue
Block a user