Refactor ExtinguisherCabinet->ItemCabinet and actually maps them in, adds EntityWhitelist (#4154)

* i probably shouldnt have done this in one commit

* map nonsense

* fix example code

* unnecessary

* test

* reviews

* little fix for open datafield

* add soul
This commit is contained in:
mirrorcult
2021-06-08 19:10:29 -07:00
committed by GitHub
parent 07494e4059
commit 1c7285825c
18 changed files with 795 additions and 191 deletions

View File

@@ -1,121 +0,0 @@
using System.Threading.Tasks;
using Content.Server.GameObjects.Components.GUI;
using Content.Server.GameObjects.Components.Items;
using Content.Server.GameObjects.Components.Items.Storage;
using Content.Server.Interfaces.GameObjects.Components.Items;
using Content.Shared.Audio;
using Content.Shared.GameObjects.Components;
using Content.Shared.Interfaces;
using Content.Shared.Interfaces.GameObjects.Components;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.Localization;
using Robust.Shared.Player;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components
{
[RegisterComponent]
[ComponentReference(typeof(IActivate))]
public class ExtinguisherCabinetComponent : Component, IInteractUsing, IInteractHand, IActivate
{
public override string Name => "ExtinguisherCabinet";
private bool _opened = false;
[DataField("doorSound")]
private string _doorSound = "/Audio/Machines/machine_switch.ogg";
[ViewVariables] protected ContainerSlot ItemContainer = default!;
[ViewVariables] public string DoorSound => _doorSound;
public override void Initialize()
{
base.Initialize();
ItemContainer =
ContainerHelpers.EnsureContainer<ContainerSlot>(Owner, "extinguisher_cabinet", out _);
}
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
{
if (!_opened)
{
_opened = true;
ClickLatchSound();
}
else
{
if (ItemContainer.ContainedEntity != null || !eventArgs.Using.HasComponent<FireExtinguisherComponent>())
{
return false;
}
var handsComponent = eventArgs.User.GetComponent<IHandsComponent>();
if (!handsComponent.Drop(eventArgs.Using, ItemContainer))
{
return false;
}
}
UpdateVisuals();
return true;
}
bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs)
{
if (_opened)
{
if (ItemContainer.ContainedEntity == null)
{
_opened = false;
ClickLatchSound();
}
else if (eventArgs.User.TryGetComponent(out HandsComponent? hands))
{
Owner.PopupMessage(eventArgs.User,
Loc.GetString("You take {0:extinguisherName} from the {1:cabinetName}", ItemContainer.ContainedEntity.Name, Owner.Name));
hands.PutInHandOrDrop(ItemContainer.ContainedEntity.GetComponent<ItemComponent>());
}
else if (ItemContainer.Remove(ItemContainer.ContainedEntity))
{
ItemContainer.ContainedEntity.Transform.Coordinates = Owner.Transform.Coordinates;
}
}
else
{
_opened = true;
ClickLatchSound();
}
UpdateVisuals();
return true;
}
void IActivate.Activate(ActivateEventArgs eventArgs)
{
_opened = !_opened;
ClickLatchSound();
UpdateVisuals();
}
private void UpdateVisuals()
{
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
{
appearance.SetData(ExtinguisherCabinetVisuals.IsOpen, _opened);
appearance.SetData(ExtinguisherCabinetVisuals.ContainsExtinguisher, ItemContainer.ContainedEntity != null);
}
}
private void ClickLatchSound()
{
// Don't have original click, this sounds close
SoundSystem.Play(Filter.Pvs(Owner), DoorSound, Owner, AudioHelpers.WithVariation(0.15f));
}
}
}

View File

@@ -1,17 +0,0 @@
using Robust.Shared.GameObjects;
namespace Content.Server.GameObjects.Components
{
[RegisterComponent]
public class ExtinguisherCabinetFilledComponent : ExtinguisherCabinetComponent
{
public override string Name => "ExtinguisherCabinetFilled";
public override void Initialize()
{
base.Initialize();
ItemContainer.Insert(Owner.EntityManager.SpawnEntity("FireExtinguisher", Owner.Transform.Coordinates));
}
}
}

View File

@@ -0,0 +1,97 @@
using System.Collections;
using System.Collections.Generic;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.EntitySystems.ActionBlocker;
using Content.Shared.GameObjects.Verbs;
using Content.Shared.Utility;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.Localization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components
{
/// <summary>
/// Used for entities that can hold one item that fits the whitelist, which can be extracted by interacting with
/// the entity, and can have an item fitting the whitelist placed back inside
/// </summary>
[RegisterComponent]
public class ItemCabinetComponent : Component
{
public override string Name => "ItemCabinet";
/// <summary>
/// Sound to be played when the cabinet door is opened.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("doorSound")]
public string? DoorSound { get; set; }
/// <summary>
/// The prototype that should be spawned inside the cabinet when it is map initialized.
/// </summary>
[ViewVariables]
[DataField("spawnPrototype")]
public string? SpawnPrototype { get; set; }
/// <summary>
/// A whitelist defining which entities are allowed into the cabinet.
/// </summary>
[ViewVariables]
[DataField("whitelist")]
public EntityWhitelist? Whitelist = null;
[ViewVariables]
public ContainerSlot ItemContainer = default!;
/// <summary>
/// Whether the cabinet is currently open or not.
/// </summary>
[ViewVariables]
[DataField("opened")]
public bool Opened { get; set; } = false;
[Verb]
public sealed class EjectItemFromCabinetVerb : Verb<ItemCabinetComponent>
{
protected override void GetData(IEntity user, ItemCabinetComponent component, VerbData data)
{
if (component.ItemContainer.ContainedEntity == null || !component.Opened || !ActionBlockerSystem.CanInteract(user))
data.Visibility = VerbVisibility.Invisible;
else
{
data.Text = Loc.GetString("comp-item-cabinet-eject-verb-text");
data.IconTexture = "/Textures/Interface/VerbIcons/eject.svg.192dpi.png";
data.Visibility = VerbVisibility.Visible;
}
}
protected override void Activate(IEntity user, ItemCabinetComponent component)
{
component.Owner.EntityManager.EventBus.RaiseLocalEvent(component.Owner.Uid, new TryEjectItemCabinetEvent(user), false);
}
}
[Verb]
public sealed class ToggleItemCabinetVerb : Verb<ItemCabinetComponent>
{
protected override void GetData(IEntity user, ItemCabinetComponent component, VerbData data)
{
if (!ActionBlockerSystem.CanInteract(user))
data.Visibility = VerbVisibility.Invisible;
else
{
data.Text = Loc.GetString(component.Opened ? "comp-item-cabinet-close-verb-text" : "comp-item-cabinet-open-verb-text");
data.IconTexture = component.Opened ? "/Textures/Interface/VerbIcons/close.svg.192dpi.png" : "/Textures/Interface/VerbIcons/open.svg.192dpi.png";
data.Visibility = VerbVisibility.Visible;
}
}
protected override void Activate(IEntity user, ItemCabinetComponent component)
{
component.Owner.EntityManager.EventBus.RaiseLocalEvent(component.Owner.Uid, new ToggleItemCabinetEvent(), false);
}
}
}
}

View File

@@ -25,6 +25,7 @@ namespace Content.Server.GameObjects.Components.Items.Storage
[RegisterComponent]
public class StorageCounterComponent : Component, ISerializationHooks
{
// TODO Convert to EntityWhitelist
[DataField("countTag")]
private string? _countTag;

View File

@@ -31,10 +31,10 @@ namespace Content.Server.GameObjects.EntitySystems
SubscribeLocalEvent<BuckleComponent, EntRemovedFromContainerMessage>(ContainerModifiedBuckle);
SubscribeLocalEvent<StrapComponent, EntRemovedFromContainerMessage>(ContainerModifiedStrap);
SubscribeLocalEvent<BuckleComponent, InteractHandEvent>(HandleAttackHand);
SubscribeLocalEvent<BuckleComponent, InteractHandEvent>(HandleInteractHand);
}
private void HandleAttackHand(EntityUid uid, BuckleComponent component, InteractHandEvent args)
private void HandleInteractHand(EntityUid uid, BuckleComponent component, InteractHandEvent args)
{
args.Handled = component.TryUnbuckle(args.User);
}

View File

@@ -0,0 +1,195 @@
using Content.Server.GameObjects.Components;
using Content.Server.GameObjects.Components.GUI;
using Content.Server.GameObjects.Components.Items;
using Content.Server.GameObjects.Components.Items.Storage;
using Content.Shared.Audio;
using Content.Shared.GameObjects.Components;
using Content.Shared.GameObjects.EntitySystems.ActionBlocker;
using Content.Shared.GameObjects.Verbs;
using Content.Shared.Interfaces;
using Content.Shared.Interfaces.GameObjects.Components;
using Microsoft.EntityFrameworkCore;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Player;
namespace Content.Server.GameObjects.EntitySystems
{
public class ItemCabinetSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ItemCabinetComponent, MapInitEvent>(OnMapInitialize);
SubscribeLocalEvent<ItemCabinetComponent, InteractUsingEvent>(OnInteractUsing);
SubscribeLocalEvent<ItemCabinetComponent, InteractHandEvent>(OnInteractHand);
SubscribeLocalEvent<ItemCabinetComponent, ActivateInWorldEvent>(OnActivateInWorld);
SubscribeLocalEvent<ItemCabinetComponent, TryEjectItemCabinetEvent>(OnTryEjectItemCabinet);
SubscribeLocalEvent<ItemCabinetComponent, TryInsertItemCabinetEvent>(OnTryInsertItemCabinet);
SubscribeLocalEvent<ItemCabinetComponent, ToggleItemCabinetEvent>(OnToggleItemCabinet);
}
private void OnMapInitialize(EntityUid uid, ItemCabinetComponent comp, MapInitEvent args)
{
var owner = EntityManager.GetEntity(uid);
comp.ItemContainer =
owner.EnsureContainer<ContainerSlot>("item_cabinet", out _);
if(comp.SpawnPrototype != null)
comp.ItemContainer.Insert(EntityManager.SpawnEntity(comp.SpawnPrototype, owner.Transform.Coordinates));
UpdateVisuals(comp);
}
private void OnInteractUsing(EntityUid uid, ItemCabinetComponent comp, InteractUsingEvent args)
{
args.Handled = true;
if (!comp.Opened)
{
RaiseLocalEvent(uid, new ToggleItemCabinetEvent(), false);
}
else
{
RaiseLocalEvent(uid, new TryInsertItemCabinetEvent(args.User, args.Used), false);
}
args.Handled = true;
}
private void OnInteractHand(EntityUid uid, ItemCabinetComponent comp, InteractHandEvent args)
{
args.Handled = true;
if (comp.Opened)
{
if (comp.ItemContainer.ContainedEntity == null)
{
RaiseLocalEvent(uid, new ToggleItemCabinetEvent(), false);
return;
}
RaiseLocalEvent(uid, new TryEjectItemCabinetEvent(args.User), false);
}
else
{
RaiseLocalEvent(uid, new ToggleItemCabinetEvent(), false);
}
}
private void OnActivateInWorld(EntityUid uid, ItemCabinetComponent comp, ActivateInWorldEvent args)
{
args.Handled = true;
RaiseLocalEvent(uid, new ToggleItemCabinetEvent(), false);
}
/// <summary>
/// Toggles the ItemCabinet's state.
/// </summary>
private void OnToggleItemCabinet(EntityUid uid, ItemCabinetComponent comp, ToggleItemCabinetEvent args)
{
comp.Opened = !comp.Opened;
ClickLatchSound(comp);
UpdateVisuals(comp);
}
/// <summary>
/// Tries to insert an entity into the ItemCabinet's slot from the user's hands.
/// </summary>
private static void OnTryInsertItemCabinet(EntityUid uid, ItemCabinetComponent comp, TryInsertItemCabinetEvent args)
{
if (comp.ItemContainer.ContainedEntity != null || args.Cancelled || (comp.Whitelist != null && !comp.Whitelist.IsValid(args.Item)))
{
return;
}
if (!args.User.TryGetComponent<HandsComponent>(out var hands) || !hands.Drop(args.Item, comp.ItemContainer))
{
return;
}
UpdateVisuals(comp);
}
/// <summary>
/// Tries to eject the ItemCabinet's item, either into the user's hands or onto the floor.
/// </summary>
private static void OnTryEjectItemCabinet(EntityUid uid, ItemCabinetComponent comp, TryEjectItemCabinetEvent args)
{
if (comp.ItemContainer.ContainedEntity == null || args.Cancelled)
return;
if (args.User.TryGetComponent(out HandsComponent? hands))
{
if (comp.ItemContainer.ContainedEntity.TryGetComponent<ItemComponent>(out var item))
{
comp.Owner.PopupMessage(args.User,
Loc.GetString("comp-item-cabinet-successfully-taken",
("item", comp.ItemContainer.ContainedEntity),
("cabinet", comp.Owner)));
hands.PutInHandOrDrop(item);
}
}
else if (comp.ItemContainer.Remove(comp.ItemContainer.ContainedEntity))
{
comp.ItemContainer.ContainedEntity.Transform.Coordinates = args.User.Transform.Coordinates;
}
UpdateVisuals(comp);
}
private static void UpdateVisuals(ItemCabinetComponent comp)
{
if (comp.Owner.TryGetComponent(out SharedAppearanceComponent? appearance))
{
appearance.SetData(ItemCabinetVisuals.IsOpen, comp.Opened);
appearance.SetData(ItemCabinetVisuals.ContainsItem, comp.ItemContainer.ContainedEntity != null);
}
}
private static void ClickLatchSound(ItemCabinetComponent comp)
{
if (comp.DoorSound == null) return;
SoundSystem.Play(Filter.Pvs(comp.Owner), comp.DoorSound, comp.Owner, AudioHelpers.WithVariation(0.15f));
}
}
public class ToggleItemCabinetEvent : EntityEventArgs
{
}
public class TryEjectItemCabinetEvent : CancellableEntityEventArgs
{
/// <summary>
/// The user who tried to eject the item.
/// </summary>
public IEntity User;
public TryEjectItemCabinetEvent(IEntity user)
{
User = user;
}
}
public class TryInsertItemCabinetEvent : CancellableEntityEventArgs
{
/// <summary>
/// The user who tried to eject the item.
/// </summary>
public IEntity User;
/// <summary>
/// The item to be inserted.
/// </summary>
public IEntity Item;
public TryInsertItemCabinetEvent(IEntity user, IEntity item)
{
User = user;
Item = item;
}
}
}