move hot plate item placement stuff into its own system (#18923)

Co-authored-by: deltanedas <@deltanedas:kde.org>
This commit is contained in:
deltanedas
2023-08-20 01:37:19 +01:00
committed by GitHub
parent f25813a098
commit 00bae110e1
9 changed files with 160 additions and 124 deletions

View File

@@ -0,0 +1,31 @@
using Content.Shared.Whitelist;
using Robust.Shared.GameStates;
namespace Content.Shared.Placeable;
/// <summary>
/// Detects items placed on it that match a whitelist.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(ItemPlacerSystem))]
public sealed partial class ItemPlacerComponent : Component
{
/// <summary>
/// The entities that are currently on top of the placer.
/// Guaranteed to have less than <see cref="MaxEntities"/> enitites if it is set.
/// <summary>
[DataField("placedEntities"), AutoNetworkedField]
public HashSet<EntityUid> PlacedEntities = new();
/// <summary>
/// Whitelist for entities that can be placed.
/// </summary>
[DataField("whitelist"), ViewVariables(VVAccess.ReadWrite)]
public EntityWhitelist? Whitelist;
/// <summary>
/// The max amount of entities that can be placed at the same time.
/// If 0, there is no limit.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("maxEntities"), AutoNetworkedField]
public uint MaxEntities = 1;
}

View File

@@ -0,0 +1,72 @@
using Robust.Shared.Physics.Events;
using Robust.Shared.Physics.Systems;
using System.Linq;
namespace Content.Shared.Placeable;
/// <summary>
/// Tracks placed entities
/// Subscribe to <see cref="ItemPlacedEvent"/> or <see cref="ItemRemovedEvent"/> to do things when items or placed or removed.
/// </summary>
public sealed class ItemPlacerSystem : EntitySystem
{
[Dependency] private readonly PlaceableSurfaceSystem _placeableSurface = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ItemPlacerComponent, StartCollideEvent>(OnStartCollide);
SubscribeLocalEvent<ItemPlacerComponent, EndCollideEvent>(OnEndCollide);
}
private void OnStartCollide(EntityUid uid, ItemPlacerComponent comp, ref StartCollideEvent args)
{
if (comp.Whitelist != null && !comp.Whitelist.IsValid(args.OtherEntity))
return;
// Disallow sleeping so we can detect when entity is removed from the heater.
_physics.SetSleepingAllowed(args.OtherEntity, args.OtherBody, false);
var count = comp.PlacedEntities.Count;
if (comp.MaxEntities == 0 || count < comp.MaxEntities)
{
comp.PlacedEntities.Add(args.OtherEntity);
var ev = new ItemPlacedEvent(args.OtherEntity);
RaiseLocalEvent(uid, ref ev);
}
if (comp.MaxEntities > 0 && count >= (comp.MaxEntities - 1))
{
// Don't let any more items be placed if it's reached its limit.
_placeableSurface.SetPlaceable(uid, false);
}
}
private void OnEndCollide(EntityUid uid, ItemPlacerComponent comp, ref EndCollideEvent args)
{
// Re-allow sleeping.
_physics.SetSleepingAllowed(args.OtherEntity, args.OtherBody, true);
comp.PlacedEntities.Remove(args.OtherEntity);
var ev = new ItemRemovedEvent(args.OtherEntity);
RaiseLocalEvent(uid, ref ev);
_placeableSurface.SetPlaceable(uid, true);
}
}
/// <summary>
/// Raised on the <see cref="ItemPlacer"/> when an item is placed and it is under the item limit.
/// </summary>
[ByRefEvent]
public record struct ItemPlacedEvent(EntityUid OtherEntity);
/// <summary>
/// Raised on the <see cref="ItemPlacer"/> when an item is removed from it.
/// </summary>
[ByRefEvent]
public record struct ItemRemovedEvent(EntityUid OtherEntity);