0 days without buckle breaking (#1366)

This commit is contained in:
DrSmugleaf
2020-07-17 10:43:10 +02:00
committed by GitHub
parent 5c723ea70e
commit f313a9267a
13 changed files with 370 additions and 127 deletions

View File

@@ -1,10 +1,10 @@
using Content.Client.GameObjects.Components.Strap; using Content.Client.GameObjects.Components.Strap;
using Content.Client.Interfaces.GameObjects.Components.Interaction; using Content.Client.Interfaces.GameObjects.Components.Interaction;
using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.GameObjects.Components.Buckle;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
namespace Content.Client.GameObjects.Components.Mobs namespace Content.Client.GameObjects.Components.Buckle
{ {
[RegisterComponent] [RegisterComponent]
public class BuckleComponent : SharedBuckleComponent, IClientDraggable public class BuckleComponent : SharedBuckleComponent, IClientDraggable
@@ -12,7 +12,7 @@ namespace Content.Client.GameObjects.Components.Mobs
private bool _buckled; private bool _buckled;
private int? _originalDrawDepth; private int? _originalDrawDepth;
protected override bool Buckled => _buckled; public override bool Buckled => _buckled;
public override void HandleComponentState(ComponentState curState, ComponentState nextState) public override void HandleComponentState(ComponentState curState, ComponentState nextState)
{ {

View File

@@ -0,0 +1,68 @@
using System;
using Content.Shared.GameObjects.Components.Buckle;
using Content.Shared.GameObjects.Components.Strap;
using JetBrains.Annotations;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Client.GameObjects.Components.Animations;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Animations;
using Robust.Shared.Maths;
namespace Content.Client.GameObjects.Components.Buckle
{
[UsedImplicitly]
public class BuckleVisualizer : AppearanceVisualizer
{
public override void OnChangeData(AppearanceComponent component)
{
if (!component.TryGetData<bool>(BuckleVisuals.Buckled, out var buckled) ||
!buckled)
{
return;
}
if (!component.TryGetData<int>(StrapVisuals.RotationAngle, out var angle))
{
return;
}
SetRotation(component, Angle.FromDegrees(angle));
}
private void SetRotation(AppearanceComponent component, Angle rotation)
{
var sprite = component.Owner.GetComponent<ISpriteComponent>();
if (!sprite.Owner.TryGetComponent(out AnimationPlayerComponent animation))
{
sprite.Rotation = rotation;
return;
}
if (animation.HasRunningAnimation("rotate"))
{
animation.Stop("rotate");
}
animation.Play(new Animation
{
Length = TimeSpan.FromSeconds(0.125),
AnimationTracks =
{
new AnimationTrackComponentProperty
{
ComponentType = typeof(ISpriteComponent),
Property = nameof(ISpriteComponent.Rotation),
InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(sprite.Rotation, 0),
new AnimationTrackProperty.KeyFrame(rotation, 0.125f)
}
}
}
}, "rotate");
}
}
}

View File

@@ -1,28 +0,0 @@
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components.Strap;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Shared.Maths;
namespace Content.Client.GameObjects.Components.Mobs
{
[UsedImplicitly]
public class BuckleVisualizer2D : SpeciesVisualizer2D
{
public override void OnChangeData(AppearanceComponent component)
{
if (!component.TryGetData<bool>(SharedBuckleComponent.BuckleVisuals.Buckled, out var buckled) ||
!buckled)
{
return;
}
if (!component.TryGetData<int>(StrapVisuals.RotationAngle, out var angle))
{
return;
}
SetRotation(component, Angle.FromDegrees(angle));
}
}
}

View File

@@ -29,7 +29,7 @@ namespace Content.Client.GameObjects.Components.Mobs
} }
} }
protected void SetRotation(AppearanceComponent component, Angle rotation) private void SetRotation(AppearanceComponent component, Angle rotation)
{ {
var sprite = component.Owner.GetComponent<ISpriteComponent>(); var sprite = component.Owner.GetComponent<ISpriteComponent>();

View File

@@ -7,16 +7,5 @@ namespace Content.Client.GameObjects.Components.Strap
[RegisterComponent] [RegisterComponent]
public class StrapComponent : SharedStrapComponent public class StrapComponent : SharedStrapComponent
{ {
public override StrapPosition Position { get; protected set; }
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{
if (!(curState is StrapComponentState strap))
{
return;
}
Position = strap.Position;
}
} }
} }

View File

@@ -0,0 +1,154 @@
using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Buckle;
using Content.Shared.GameObjects.Components.Buckle;
using Content.Shared.GameObjects.EntitySystems;
using NUnit.Framework;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using StrapComponent = Content.Server.GameObjects.Components.Strap.StrapComponent;
namespace Content.IntegrationTests.Tests
{
[TestFixture]
[TestOf(typeof(BuckleComponent))]
[TestOf(typeof(StrapComponent))]
public class BuckleTest : ContentIntegrationTest
{
[Test]
public async Task Test()
{
var server = StartServerDummyTicker();
IEntity human = null;
IEntity chair = null;
BuckleComponent buckle = null;
StrapComponent strap = null;
server.Assert(() =>
{
var mapManager = IoCManager.Resolve<IMapManager>();
mapManager.CreateNewMapEntity(MapId.Nullspace);
var entityManager = IoCManager.Resolve<IEntityManager>();
human = entityManager.SpawnEntity("HumanMob_Content", MapCoordinates.Nullspace);
chair = entityManager.SpawnEntity("ChairWood", MapCoordinates.Nullspace);
// Default state, unbuckled
Assert.True(human.TryGetComponent(out buckle));
Assert.NotNull(buckle);
Assert.Null(buckle.BuckledTo);
Assert.False(buckle.Buckled);
Assert.True(ActionBlockerSystem.CanMove(human));
Assert.True(ActionBlockerSystem.CanChangeDirection(human));
Assert.True(EffectBlockerSystem.CanFall(human));
// Default state, no buckled entities, strap
Assert.True(chair.TryGetComponent(out strap));
Assert.NotNull(strap);
Assert.IsEmpty(strap.BuckledEntities);
Assert.Zero(strap.OccupiedSize);
// Side effects of buckling
Assert.True(buckle.TryBuckle(human, chair));
Assert.NotNull(buckle.BuckledTo);
Assert.True(buckle.Buckled);
Assert.True(((BuckleComponentState) buckle.GetComponentState()).Buckled);
Assert.False(ActionBlockerSystem.CanMove(human));
Assert.False(ActionBlockerSystem.CanChangeDirection(human));
Assert.False(EffectBlockerSystem.CanFall(human));
Assert.AreEqual(human.Transform.WorldPosition, chair.Transform.WorldPosition);
// Side effects of buckling for the strap
Assert.That(strap.BuckledEntities, Does.Contain(human));
Assert.That(strap.OccupiedSize, Is.EqualTo(buckle.Size));
Assert.Positive(strap.OccupiedSize);
// Trying to buckle while already buckled fails
Assert.False(buckle.TryBuckle(human, chair));
// Trying to unbuckle too quickly fails
Assert.False(buckle.TryUnbuckle(human));
Assert.False(buckle.ToggleBuckle(human, chair));
Assert.True(buckle.Buckled);
});
// Wait enough ticks for the unbuckling cooldown to run out
server.RunTicks(60);
server.Assert(() =>
{
// Still buckled
Assert.True(buckle.Buckled);
// Unbuckle
Assert.True(buckle.TryUnbuckle(human));
Assert.Null(buckle.BuckledTo);
Assert.False(buckle.Buckled);
Assert.True(ActionBlockerSystem.CanMove(human));
Assert.True(ActionBlockerSystem.CanChangeDirection(human));
Assert.True(EffectBlockerSystem.CanFall(human));
// Unbuckle, strap
Assert.IsEmpty(strap.BuckledEntities);
Assert.Zero(strap.OccupiedSize);
// Re-buckling has no cooldown
Assert.True(buckle.TryBuckle(human, chair));
Assert.True(buckle.Buckled);
// On cooldown
Assert.False(buckle.TryUnbuckle(human));
Assert.True(buckle.Buckled);
Assert.False(buckle.ToggleBuckle(human, chair));
Assert.True(buckle.Buckled);
Assert.False(buckle.ToggleBuckle(human, chair));
Assert.True(buckle.Buckled);
});
// Wait enough ticks for the unbuckling cooldown to run out
server.RunTicks(60);
server.Assert(() =>
{
// Still buckled
Assert.True(buckle.Buckled);
// Unbuckle
Assert.True(buckle.TryUnbuckle(human));
Assert.False(buckle.Buckled);
// Move away from the chair
human.Transform.WorldPosition += (1000, 1000);
// Out of range
Assert.False(buckle.TryBuckle(human, chair));
Assert.False(buckle.TryUnbuckle(human));
Assert.False(buckle.ToggleBuckle(human, chair));
// Move near the chair
human.Transform.WorldPosition = chair.Transform.WorldPosition + (0.5f, 0);
// In range
Assert.True(buckle.TryBuckle(human, chair));
Assert.True(buckle.Buckled);
Assert.False(buckle.TryUnbuckle(human));
Assert.True(buckle.Buckled);
Assert.False(buckle.ToggleBuckle(human, chair));
Assert.True(buckle.Buckled);
// Force unbuckle
Assert.True(buckle.TryUnbuckle(human, true));
Assert.False(buckle.Buckled);
Assert.True(ActionBlockerSystem.CanMove(human));
Assert.True(ActionBlockerSystem.CanChangeDirection(human));
Assert.True(EffectBlockerSystem.CanFall(human));
});
await server.WaitIdleAsync();
}
}
}

View File

@@ -1,11 +1,13 @@
#nullable enable #nullable enable
using System; using System;
using Content.Server.GameObjects.Components.Mobs;
using Content.Server.GameObjects.Components.Strap; using Content.Server.GameObjects.Components.Strap;
using Content.Server.Interfaces; using Content.Server.Interfaces;
using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces.GameObjects.Components.Interaction;
using Content.Server.Mobs; using Content.Server.Mobs;
using Content.Server.Utility; using Content.Server.Utility;
using Content.Shared.GameObjects; using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Buckle;
using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components.Strap; using Content.Shared.GameObjects.Components.Strap;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
@@ -22,7 +24,7 @@ using Robust.Shared.Maths;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Mobs namespace Content.Server.GameObjects.Components.Buckle
{ {
[RegisterComponent] [RegisterComponent]
public class BuckleComponent : SharedBuckleComponent, IInteractHand, IDragDrop public class BuckleComponent : SharedBuckleComponent, IInteractHand, IDragDrop
@@ -34,29 +36,32 @@ namespace Content.Server.GameObjects.Components.Mobs
[Dependency] private readonly IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
#pragma warning restore 649 #pragma warning restore 649
/// <summary>
/// The amount of space that this entity occupies in a <see cref="StrapComponent"/>.
/// </summary>
private int _size; private int _size;
/// <summary> /// <summary>
/// The range from which this entity can buckle to a <see cref="StrapComponent"/>. /// The range from which this entity can buckle to a <see cref="StrapComponent"/>.
/// </summary> /// </summary>
[ViewVariables]
private float _range; private float _range;
/// <summary> /// <summary>
/// The amount of time that must pass for this entity to /// The amount of time that must pass for this entity to
/// be able to unbuckle after recently buckling. /// be able to unbuckle after recently buckling.
/// </summary> /// </summary>
[ViewVariables]
private TimeSpan _unbuckleDelay; private TimeSpan _unbuckleDelay;
/// <summary> /// <summary>
/// The time that this entity buckled at. /// The time that this entity buckled at.
/// </summary> /// </summary>
[ViewVariables]
private TimeSpan _buckleTime; private TimeSpan _buckleTime;
private StrapComponent? _buckledTo; private StrapComponent? _buckledTo;
/// <summary>
/// The strap that this component is buckled to.
/// </summary>
[ViewVariables] [ViewVariables]
public StrapComponent? BuckledTo public StrapComponent? BuckledTo
{ {
@@ -70,13 +75,25 @@ namespace Content.Server.GameObjects.Components.Mobs
} }
[ViewVariables] [ViewVariables]
protected override bool Buckled => BuckledTo != null; public override bool Buckled => BuckledTo != null;
public bool ContainerChanged { get; private set; } /// <summary>
/// True if the entity was inserted or removed from a container
/// before updating, false otherwise.
/// </summary>
[ViewVariables]
private bool ContainerChanged { get; set; }
/// <summary>
/// The amount of space that this entity occupies in a <see cref="StrapComponent"/>.
/// </summary>
[ViewVariables] [ViewVariables]
public int Size => _size; public int Size => _size;
/// <summary>
/// Shows or hides the buckled status effect depending on if the
/// entity is buckled or not.
/// </summary>
private void BuckleStatus() private void BuckleStatus()
{ {
if (Owner.TryGetComponent(out ServerStatusEffectsComponent status)) if (Owner.TryGetComponent(out ServerStatusEffectsComponent status))
@@ -88,6 +105,10 @@ namespace Content.Server.GameObjects.Components.Mobs
} }
} }
/// <summary>
/// Reattaches this entity to the strap, modifying its position and rotation
/// </summary>
/// <param name="strap">The strap to reattach to</param>
private void ReAttach(StrapComponent strap) private void ReAttach(StrapComponent strap)
{ {
var ownTransform = Owner.Transform; var ownTransform = Owner.Transform;
@@ -112,7 +133,18 @@ namespace Content.Server.GameObjects.Components.Mobs
} }
} }
private bool TryBuckle(IEntity user, IEntity to) /// <summary>
/// Tries to make an entity buckle the owner of this component to another.
/// </summary>
/// <param name="user">
/// The entity buckling the owner of this component, can be the owner itself.
/// </param>
/// <param name="to">The entity to buckle the owner of this component to.</param>
/// <returns>
/// true if the owner was buckled, otherwise false even if the owner was
/// previously already buckled.
/// </returns>
public bool TryBuckle(IEntity user, IEntity to)
{ {
if (user == null || user == to) if (user == null || user == to)
{ {
@@ -142,8 +174,10 @@ namespace Content.Server.GameObjects.Components.Mobs
return false; return false;
} }
// If in a container
if (ContainerHelpers.TryGetContainer(Owner, out var ownerContainer)) if (ContainerHelpers.TryGetContainer(Owner, out var ownerContainer))
{ {
// And not in the same container as the strap
if (!ContainerHelpers.TryGetContainer(strap.Owner, out var strapContainer) || if (!ContainerHelpers.TryGetContainer(strap.Owner, out var strapContainer) ||
ownerContainer != strapContainer) ownerContainer != strapContainer)
{ {
@@ -218,6 +252,18 @@ namespace Content.Server.GameObjects.Components.Mobs
return true; return true;
} }
/// <summary>
/// Tries to unbuckle the Owner of this component from its current strap.
/// </summary>
/// <param name="user">The entity doing the unbuckling.</param>
/// <param name="force">
/// Whether to force the unbuckling or not. Does not guarantee true to
/// be returned, but guarantees the owner to be unbuckled afterwards.
/// </param>
/// <returns>
/// true if the owner was unbuckled, otherwise false even if the owner
/// was previously already unbuckled.
/// </returns>
public bool TryUnbuckle(IEntity user, bool force = false) public bool TryUnbuckle(IEntity user, bool force = false)
{ {
if (BuckledTo == null) if (BuckledTo == null)
@@ -288,16 +334,35 @@ namespace Content.Server.GameObjects.Components.Mobs
return true; return true;
} }
public bool ToggleBuckle(IEntity user, IEntity to) /// <summary>
/// Makes an entity toggle the buckling status of the owner to a
/// specific entity.
/// </summary>
/// <param name="user">The entity doing the buckling/unbuckling.</param>
/// <param name="to">
/// The entity to toggle the buckle status of the owner to.
/// </param>
/// <param name="force">
/// Whether to force the unbuckling or not, if it happens. Does not
/// guarantee true to be returned, but guarantees the owner to be
/// unbuckled afterwards.
/// </param>
/// <returns>true if the buckling status was changed, false otherwise.</returns>
public bool ToggleBuckle(IEntity user, IEntity to, bool force = false)
{ {
if (BuckledTo?.Owner == to) if (BuckledTo?.Owner == to)
{ {
return TryUnbuckle(user); return TryUnbuckle(user, force);
} }
return TryBuckle(user, to); return TryBuckle(user, to);
} }
/// <summary>
/// Called when the owner is inserted or removed from a container,
/// to synchronize the state of buckling.
/// </summary>
/// <param name="message">The message received</param>
private void InsertIntoContainer(ContainerModifiedMessage message) private void InsertIntoContainer(ContainerModifiedMessage message)
{ {
if (message.Entity != Owner) if (message.Entity != Owner)
@@ -308,6 +373,12 @@ namespace Content.Server.GameObjects.Components.Mobs
ContainerChanged = true; ContainerChanged = true;
} }
/// <summary>
/// Synchronizes the state of buckling depending on whether the entity
/// was inserted or removed from a container, and whether or not
/// its current strap (if there is one) has also been put into or removed
/// from the same container as well.
/// </summary>
public void Update() public void Update()
{ {
if (!ContainerChanged || BuckledTo == null) if (!ContainerChanged || BuckledTo == null)
@@ -401,6 +472,10 @@ namespace Content.Server.GameObjects.Components.Mobs
return TryBuckle(eventArgs.User, eventArgs.Target); return TryBuckle(eventArgs.User, eventArgs.Target);
} }
/// <summary>
/// Allows the unbuckling of the owning entity through a verb if
/// anyone right clicks them.
/// </summary>
[Verb] [Verb]
private sealed class BuckleVerb : Verb<BuckleComponent> private sealed class BuckleVerb : Verb<BuckleComponent>
{ {

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.GameObjects.Components.Buckle;
using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.GameObjects.Components.Mobs;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;

View File

@@ -1,5 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Buckle;
using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces.GameObjects.Components.Interaction;
using Content.Shared.GameObjects; using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Strap; using Content.Shared.GameObjects.Components.Strap;
@@ -17,30 +17,34 @@ namespace Content.Server.GameObjects.Components.Strap
[RegisterComponent] [RegisterComponent]
public class StrapComponent : SharedStrapComponent, IInteractHand public class StrapComponent : SharedStrapComponent, IInteractHand
{ {
private HashSet<IEntity> _buckledEntities;
private StrapPosition _position; private StrapPosition _position;
private string _buckleSound; private string _buckleSound;
private string _unbuckleSound; private string _unbuckleSound;
private string _buckledIcon; private string _buckledIcon;
/// <summary>
/// The angle in degrees to rotate the player by when they get strapped
/// </summary>
[ViewVariables]
private int _rotation; private int _rotation;
/// <summary>
/// The size of the strap which is compared against when buckling entities
/// </summary>
[ViewVariables]
private int _size; private int _size;
private int _occupiedSize;
/// <summary> /// <summary>
/// The entity that is currently buckled here, synced from <see cref="BuckleComponent.BuckledTo"/> /// The entity that is currently buckled here, synced from <see cref="BuckleComponent.BuckledTo"/>
/// </summary> /// </summary>
private HashSet<IEntity> BuckledEntities { get; set; } public IReadOnlyCollection<IEntity> BuckledEntities => _buckledEntities;
/// <summary> /// <summary>
/// The change in position to the strapped mob /// The change in position to the strapped mob
/// </summary> /// </summary>
public override StrapPosition Position public StrapPosition Position => _position;
{
get => _position;
protected set
{
_position = value;
Dirty();
}
}
/// <summary> /// <summary>
/// The sound to be played when a mob is buckled /// The sound to be played when a mob is buckled
@@ -60,24 +64,17 @@ namespace Content.Server.GameObjects.Components.Strap
[ViewVariables] [ViewVariables]
public string BuckledIcon => _buckledIcon; public string BuckledIcon => _buckledIcon;
/// <summary>
/// The angle in degrees to rotate the player by when they get strapped
/// </summary>
[ViewVariables]
public int Rotation => _rotation;
/// <summary>
/// The size of the strap which is compared against when buckling entities
/// </summary>
[ViewVariables]
public int Size => _size;
/// <summary> /// <summary>
/// The sum of the sizes of all the buckled entities in this strap /// The sum of the sizes of all the buckled entities in this strap
/// </summary> /// </summary>
[ViewVariables] [ViewVariables]
private int OccupiedSize { get; set; } public int OccupiedSize => _occupiedSize;
/// <summary>
/// Checks if this strap has enough space for a new occupant.
/// </summary>
/// <param name="buckle">The new occupant</param>
/// <returns>true if there is enough space, false otherwise</returns>
public bool HasSpace(BuckleComponent buckle) public bool HasSpace(BuckleComponent buckle)
{ {
return OccupiedSize + buckle.Size <= _size; return OccupiedSize + buckle.Size <= _size;
@@ -87,7 +84,9 @@ namespace Content.Server.GameObjects.Components.Strap
/// Adds a buckled entity. Called from <see cref="BuckleComponent.TryBuckle"/> /// Adds a buckled entity. Called from <see cref="BuckleComponent.TryBuckle"/>
/// </summary> /// </summary>
/// <param name="buckle">The component to add</param> /// <param name="buckle">The component to add</param>
/// <param name="force">Whether or not to check if the strap has enough space</param> /// <param name="force">
/// Whether or not to check if the strap has enough space
/// </param>
/// <returns>True if added, false otherwise</returns> /// <returns>True if added, false otherwise</returns>
public bool TryAdd(BuckleComponent buckle, bool force = false) public bool TryAdd(BuckleComponent buckle, bool force = false)
{ {
@@ -96,12 +95,12 @@ namespace Content.Server.GameObjects.Components.Strap
return false; return false;
} }
if (!BuckledEntities.Add(buckle.Owner)) if (!_buckledEntities.Add(buckle.Owner))
{ {
return false; return false;
} }
OccupiedSize += buckle.Size; _occupiedSize += buckle.Size;
if (buckle.Owner.TryGetComponent(out AppearanceComponent appearance)) if (buckle.Owner.TryGetComponent(out AppearanceComponent appearance))
{ {
@@ -112,14 +111,15 @@ namespace Content.Server.GameObjects.Components.Strap
} }
/// <summary> /// <summary>
/// Removes a buckled entity. Called from <see cref="BuckleComponent.TryUnbuckle"/> /// Removes a buckled entity.
/// Called from <see cref="BuckleComponent.TryUnbuckle"/>
/// </summary> /// </summary>
/// <param name="buckle">The component to remove</param> /// <param name="buckle">The component to remove</param>
public void Remove(BuckleComponent buckle) public void Remove(BuckleComponent buckle)
{ {
if (BuckledEntities.Remove(buckle.Owner)) if (_buckledEntities.Remove(buckle.Owner))
{ {
OccupiedSize -= buckle.Size; _occupiedSize -= buckle.Size;
} }
} }
@@ -136,16 +136,16 @@ namespace Content.Server.GameObjects.Components.Strap
var defaultSize = 100; var defaultSize = 100;
serializer.DataField(ref _size, "size", defaultSize); serializer.DataField(ref _size, "size", defaultSize);
BuckledEntities = new HashSet<IEntity>(_size / defaultSize); _buckledEntities = new HashSet<IEntity>(_size / defaultSize);
OccupiedSize = 0; _occupiedSize = 0;
} }
public override void OnRemove() public override void OnRemove()
{ {
base.OnRemove(); base.OnRemove();
foreach (var entity in BuckledEntities) foreach (var entity in _buckledEntities)
{ {
if (entity.TryGetComponent(out BuckleComponent buckle)) if (entity.TryGetComponent(out BuckleComponent buckle))
{ {
@@ -153,13 +153,8 @@ namespace Content.Server.GameObjects.Components.Strap
} }
} }
BuckledEntities.Clear(); _buckledEntities.Clear();
OccupiedSize = 0; _occupiedSize = 0;
}
public override ComponentState GetComponentState()
{
return new StrapComponentState(Position);
} }
bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs) bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs)

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Buckle;
using Content.Server.GameObjects.Components.Mobs;
using Content.Server.GameObjects.EntitySystems.Click; using Content.Server.GameObjects.EntitySystems.Click;
using Robust.Server.GameObjects.EntitySystems; using Robust.Server.GameObjects.EntitySystems;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;

View File

@@ -3,7 +3,7 @@ using Content.Shared.GameObjects.EntitySystems;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Shared.GameObjects.Components.Mobs namespace Content.Shared.GameObjects.Components.Buckle
{ {
public abstract class SharedBuckleComponent : Component, IActionBlocker, IEffectBlocker public abstract class SharedBuckleComponent : Component, IActionBlocker, IEffectBlocker
{ {
@@ -11,7 +11,10 @@ namespace Content.Shared.GameObjects.Components.Mobs
public sealed override uint? NetID => ContentNetIDs.BUCKLE; public sealed override uint? NetID => ContentNetIDs.BUCKLE;
protected abstract bool Buckled { get; } /// <summary>
/// True if the entity is buckled, false otherwise.
/// </summary>
public abstract bool Buckled { get; }
bool IActionBlocker.CanMove() bool IActionBlocker.CanMove()
{ {
@@ -27,9 +30,10 @@ namespace Content.Shared.GameObjects.Components.Mobs
{ {
return !Buckled; return !Buckled;
} }
}
[Serializable, NetSerializable] [Serializable, NetSerializable]
protected sealed class BuckleComponentState : ComponentState public sealed class BuckleComponentState : ComponentState
{ {
public BuckleComponentState(bool buckled, int? drawDepth) : base(ContentNetIDs.BUCKLE) public BuckleComponentState(bool buckled, int? drawDepth) : base(ContentNetIDs.BUCKLE)
{ {
@@ -47,4 +51,3 @@ namespace Content.Shared.GameObjects.Components.Mobs
Buckled Buckled
} }
} }
}

View File

@@ -27,21 +27,6 @@ namespace Content.Shared.GameObjects.Components.Strap
public sealed override string Name => "Strap"; public sealed override string Name => "Strap";
public sealed override uint? NetID => ContentNetIDs.STRAP; public sealed override uint? NetID => ContentNetIDs.STRAP;
public abstract StrapPosition Position { get; protected set; }
}
[Serializable, NetSerializable]
public sealed class StrapComponentState : ComponentState
{
public readonly StrapPosition Position;
public StrapComponentState(StrapPosition position) : base(ContentNetIDs.BUCKLE)
{
Position = position;
}
public bool Buckled { get; }
} }
[Serializable, NetSerializable] [Serializable, NetSerializable]

View File

@@ -127,7 +127,7 @@
- type: Appearance - type: Appearance
visuals: visuals:
- type: SpeciesVisualizer2D - type: SpeciesVisualizer2D
- type: BuckleVisualizer2D - type: BuckleVisualizer
- type: CombatMode - type: CombatMode
- type: Teleportable - type: Teleportable
- type: CharacterInfo - type: CharacterInfo