using Content.Server.Atmos.Piping.Components;
using Content.Server.Atmos.Piping.Unary.Components;
using Content.Server.Cargo.Systems;
-using Content.Server.Lock;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.NodeGroups;
using Content.Server.NodeContainer.Nodes;
using Content.Server.Popups;
-using Content.Server.Storage.Components;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping.Binary.Components;
using Content.Shared.Database;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
+using Content.Shared.Lock;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.Containers;
-using Robust.Shared.Player;
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
{
args.GasMixtures = new Dictionary<string, GasMixture?> { {Name(uid), component.Air} };
}
- private void OnLockToggled(EntityUid uid, GasCanisterComponent component, LockToggledEvent args)
+ private void OnLockToggled(EntityUid uid, GasCanisterComponent component, ref LockToggledEvent args)
{
_appearanceSystem.SetData(uid, GasCanisterVisuals.Locked, args.Locked);
}
using System.Diagnostics.CodeAnalysis;
using Content.Server.Administration.Logs;
-using Content.Server.Storage.Components;
using Content.Shared.Alert;
using Content.Shared.Bed.Sleep;
using Content.Shared.Buckle.Components;
using Content.Shared.Interaction;
using Content.Shared.Mobs.Components;
using Content.Shared.Pulling.Components;
+using Content.Shared.Storage.Components;
using Content.Shared.Stunnable;
using Content.Shared.Vehicle.Components;
using Content.Shared.Verbs;
TryUnbuckle(uid, buckle.Owner, true, buckle);
}
- private void OnEntityStorageInsertAttempt(EntityUid uid, BuckleComponent comp, InsertIntoEntityStorageAttemptEvent args)
+ private void OnEntityStorageInsertAttempt(EntityUid uid, BuckleComponent comp, ref InsertIntoEntityStorageAttemptEvent args)
{
if (comp.Buckled)
- args.Cancel();
+ args.Cancelled = true;
}
private void OnBuckleCanDrop(EntityUid uid, BuckleComponent component, CanDropEvent args)
using Content.Shared.Cabinet;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Interaction;
+using Content.Shared.Lock;
using Content.Shared.Verbs;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Content.Shared.Movement.Systems;
using Content.Shared.Stealth;
using Content.Shared.Stealth.Components;
+using Content.Shared.Storage.Components;
using Robust.Server.GameObjects;
using Robust.Shared.Containers;
using Robust.Shared.Player;
_storage.OpenStorage(uid);
}
- private void AfterStorageOpen(EntityUid uid, CardboardBoxComponent component, StorageAfterOpenEvent args)
+ private void AfterStorageOpen(EntityUid uid, CardboardBoxComponent component, ref StorageAfterOpenEvent args)
{
//Remove the mover after the box is opened and play the effect if it hasn't been played yet.
if (component.Mover != null)
_stealth.SetEnabled(uid, false);
}
- private void AfterStorageClosed(EntityUid uid, CardboardBoxComponent component, StorageAfterCloseEvent args)
+ private void AfterStorageClosed(EntityUid uid, CardboardBoxComponent component, ref StorageAfterCloseEvent args)
{
// If this box has a stealth/chameleon effect, enable the stealth effect.
if (TryComp(uid, out StealthComponent? stealth))
-using Content.Server.Storage.Components;
using Content.Shared.Construction;
using Content.Shared.Examine;
+using Content.Shared.Lock;
using JetBrains.Annotations;
namespace Content.Server.Construction.Conditions
using Content.Server.Storage.Components;
using Content.Shared.Buckle.Components;
using Content.Shared.Foldable;
+using Content.Shared.Storage.Components;
using Content.Shared.Verbs;
using JetBrains.Annotations;
using Robust.Shared.Containers;
[UsedImplicitly]
public sealed class FoldableSystem : SharedFoldableSystem
{
- [Dependency] private BuckleSystem _buckle = default!;
- [Dependency] private SharedContainerSystem _container = default!;
+ [Dependency] private readonly BuckleSystem _buckle = default!;
+ [Dependency] private readonly SharedContainerSystem _container = default!;
public override void Initialize()
{
}
- private void OnFoldableOpenAttempt(EntityUid uid, FoldableComponent component, StorageOpenAttemptEvent args)
+ private void OnFoldableOpenAttempt(EntityUid uid, FoldableComponent component, ref StorageOpenAttemptEvent args)
{
if (component.IsFolded)
- args.Cancel();
+ args.Cancelled = true;
}
public bool TryToggleFold(FoldableComponent comp)
_buckle.StrapSetEnabled(component.Owner, !component.IsFolded);
}
- public void OnStoreThisAttempt(EntityUid uid, FoldableComponent comp, StoreMobInItemContainerAttemptEvent args)
+ public void OnStoreThisAttempt(EntityUid uid, FoldableComponent comp, ref StoreMobInItemContainerAttemptEvent args)
{
args.Handled = true;
if (comp.IsFolded)
- args.Cancel();
+ args.Cancelled = true;
}
#region Verb
using Content.Server.Mind;
using Content.Server.Mind.Components;
using Content.Server.Players;
-using Content.Server.Storage.Components;
using Content.Server.Visible;
using Content.Server.Warps;
using Content.Shared.Actions;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.Movement.Events;
+using Content.Shared.Storage.Components;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Server.Player;
}
}
- private void OnEntityStorageInsertAttempt(EntityUid uid, GhostComponent comp, InsertIntoEntityStorageAttemptEvent args)
+ private void OnEntityStorageInsertAttempt(EntityUid uid, GhostComponent comp, ref InsertIntoEntityStorageAttemptEvent args)
{
- args.Cancel();
+ args.Cancelled = true;
}
/// <summary>
+++ /dev/null
-using Robust.Shared.Audio;
-
-namespace Content.Server.Storage.Components
-{
- /// <summary>
- /// Allows locking/unlocking, with access determined by AccessReader
- /// </summary>
- [RegisterComponent]
- public sealed class LockComponent : Component
- {
- [ViewVariables(VVAccess.ReadWrite)] [DataField("locked")] public bool Locked { get; set; } = true;
- [ViewVariables(VVAccess.ReadWrite)] [DataField("lockOnClick")] public bool LockOnClick { get; set; } = false;
- [ViewVariables(VVAccess.ReadWrite)] [DataField("unlockingSound")] public SoundSpecifier UnlockSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/door_lock_off.ogg");
- [ViewVariables(VVAccess.ReadWrite)] [DataField("lockingSound")] public SoundSpecifier LockSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/door_lock_on.ogg");
- }
-}
-[ByRefEvent]
-public struct LockToggleAttemptEvent
-{
- public bool Silent = false;
- public bool Cancelled = false;
- public EntityUid User;
-
- public LockToggleAttemptEvent(EntityUid user, bool silent = false)
- {
- User = user;
- Silent = silent;
- }
-}
-public sealed class LockToggleAttemptArgs : EventArgs { }
+++ /dev/null
-using Content.Server.Storage.Components;
-using Content.Shared.Emag.Systems;
-using Content.Shared.Access.Components;
-using Content.Shared.Access.Systems;
-using Content.Shared.Examine;
-using Content.Shared.Hands.Components;
-using Content.Shared.Interaction;
-using Content.Shared.Popups;
-using Content.Shared.Storage;
-using Content.Shared.Verbs;
-using JetBrains.Annotations;
-using Robust.Shared.Audio;
-using Robust.Shared.Player;
-
-namespace Content.Server.Lock
-{
- /// <summary>
- /// Handles (un)locking and examining of Lock components
- /// </summary>
- [UsedImplicitly]
- public sealed class LockSystem : EntitySystem
- {
- [Dependency] private readonly AccessReaderSystem _accessReader = default!;
- [Dependency] private readonly SharedPopupSystem _sharedPopupSystem = default!;
- [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
- [Dependency] private readonly SharedAudioSystem _audio = default!;
-
- /// <inheritdoc />
- public override void Initialize()
- {
- base.Initialize();
- SubscribeLocalEvent<LockComponent, ComponentStartup>(OnStartup);
- SubscribeLocalEvent<LockComponent, ActivateInWorldEvent>(OnActivated);
- SubscribeLocalEvent<LockComponent, StorageOpenAttemptEvent>(OnStorageOpenAttempt);
- SubscribeLocalEvent<LockComponent, ExaminedEvent>(OnExamined);
- SubscribeLocalEvent<LockComponent, GetVerbsEvent<AlternativeVerb>>(AddToggleLockVerb);
- SubscribeLocalEvent<LockComponent, GotEmaggedEvent>(OnEmagged);
- }
-
- private void OnStartup(EntityUid uid, LockComponent lockComp, ComponentStartup args)
- {
- if (EntityManager.TryGetComponent(lockComp.Owner, out AppearanceComponent? appearance))
- {
- _appearanceSystem.SetData(uid, StorageVisuals.CanLock, true, appearance);
- }
- }
-
- private void OnActivated(EntityUid uid, LockComponent lockComp, ActivateInWorldEvent args)
- {
- if (args.Handled)
- return;
-
- // Only attempt an unlock by default on Activate
- if (lockComp.Locked)
- {
- TryUnlock(uid, args.User, lockComp);
- args.Handled = true;
- }
- else if (lockComp.LockOnClick)
- {
- TryLock(uid, args.User, lockComp);
- args.Handled = true;
- }
- }
-
- private void OnStorageOpenAttempt(EntityUid uid, LockComponent component, StorageOpenAttemptEvent args)
- {
- if (component.Locked)
- {
- if (!args.Silent)
- _sharedPopupSystem.PopupEntity(Loc.GetString("entity-storage-component-locked-message"), uid);
-
- args.Cancel();
- }
- }
-
- private void OnExamined(EntityUid uid, LockComponent lockComp, ExaminedEvent args)
- {
- args.PushText(Loc.GetString(lockComp.Locked
- ? "lock-comp-on-examined-is-locked"
- : "lock-comp-on-examined-is-unlocked",
- ("entityName", EntityManager.GetComponent<MetaDataComponent>(lockComp.Owner).EntityName)));
- }
-
- public bool TryLock(EntityUid uid, EntityUid user, LockComponent? lockComp = null)
- {
- if (!Resolve(uid, ref lockComp))
- return false;
-
- if (!CanToggleLock(uid, user, quiet: false))
- return false;
-
- if (!HasUserAccess(uid, user, quiet: false))
- return false;
-
- _sharedPopupSystem.PopupEntity(Loc.GetString("lock-comp-do-lock-success", ("entityName", EntityManager.GetComponent<MetaDataComponent>(uid).EntityName)), uid, user);
- lockComp.Locked = true;
-
- _audio.PlayPvs(_audio.GetSound(lockComp.LockSound), uid, AudioParams.Default.WithVolume(-5));
-
- if (EntityManager.TryGetComponent(uid, out AppearanceComponent? appearanceComp))
- {
- _appearanceSystem.SetData(uid, StorageVisuals.Locked, true, appearanceComp);
- }
-
- RaiseLocalEvent(lockComp.Owner, new LockToggledEvent(true), true);
-
- return true;
- }
-
- public void Unlock(EntityUid uid, EntityUid? user, LockComponent? lockComp = null)
- {
- if (!Resolve(uid, ref lockComp))
- return;
-
- if (user is { Valid: true })
- {
- _sharedPopupSystem.PopupEntity(Loc.GetString("lock-comp-do-unlock-success", ("entityName", EntityManager.GetComponent<MetaDataComponent>(uid).EntityName)), uid, user.Value);
- }
-
- lockComp.Locked = false;
-
- _audio.PlayPvs(_audio.GetSound(lockComp.UnlockSound), uid, AudioParams.Default.WithVolume(-5));
-
- if (EntityManager.TryGetComponent(lockComp.Owner, out AppearanceComponent? appearanceComp))
- {
- _appearanceSystem.SetData(uid, StorageVisuals.Locked, false, appearanceComp);
- }
-
- RaiseLocalEvent(lockComp.Owner, new LockToggledEvent(false), true);
- }
-
- public bool TryUnlock(EntityUid uid, EntityUid user, LockComponent? lockComp = null)
- {
- if (!Resolve(uid, ref lockComp))
- return false;
-
- if (!CanToggleLock(uid, user, quiet: false))
- return false;
-
- if (!HasUserAccess(uid, user, quiet: false))
- return false;
-
- Unlock(uid, user, lockComp);
- return true;
- }
-
- /// <summary>
- /// Before locking the entity, check whether it's a locker. If is, prevent it from being locked from the inside or while it is open.
- /// </summary>
- public bool CanToggleLock(EntityUid uid, EntityUid user, bool quiet = true)
- {
- if (!HasComp<SharedHandsComponent>(user))
- return false;
-
- var ev = new LockToggleAttemptEvent(user, quiet);
- RaiseLocalEvent(uid, ref ev, true);
- return !ev.Cancelled;
- }
-
- private bool HasUserAccess(EntityUid uid, EntityUid user, AccessReaderComponent? reader = null, bool quiet = true)
- {
- // Not having an AccessComponent means you get free access. woo!
- if (!Resolve(uid, ref reader))
- return true;
-
- if (!_accessReader.IsAllowed(user, reader))
- {
- if (!quiet)
- _sharedPopupSystem.PopupEntity(Loc.GetString("lock-comp-has-user-access-fail"), uid, user);
- return false;
- }
-
- return true;
- }
-
- private void AddToggleLockVerb(EntityUid uid, LockComponent component, GetVerbsEvent<AlternativeVerb> args)
- {
- if (!args.CanAccess || !args.CanInteract || !CanToggleLock(uid, args.User))
- return;
-
- AlternativeVerb verb = new();
- verb.Act = component.Locked ?
- () => TryUnlock(uid, args.User, component) :
- () => TryLock(uid, args.User, component);
- verb.Text = Loc.GetString(component.Locked ? "toggle-lock-verb-unlock" : "toggle-lock-verb-lock");
- verb.IconTexture = component.Locked ? "/Textures/Interface/VerbIcons/unlock.svg.192dpi.png" : "/Textures/Interface/VerbIcons/lock.svg.192dpi.png";
- args.Verbs.Add(verb);
- }
-
- private void OnEmagged(EntityUid uid, LockComponent component, ref GotEmaggedEvent args)
- {
- if (component.Locked)
- {
- _audio.PlayPvs(_audio.GetSound(component.UnlockSound), uid, AudioParams.Default.WithVolume(-5));
-
- if (EntityManager.TryGetComponent(component.Owner, out AppearanceComponent? appearanceComp))
- {
- _appearanceSystem.SetData(uid, StorageVisuals.Locked, false, appearanceComp);
- }
- EntityManager.RemoveComponent<LockComponent>(uid); //Literally destroys the lock as a tell it was emagged
- args.Handled = true;
- }
- }
- }
-}
+++ /dev/null
-namespace Content.Server.Lock
-{
- public sealed class LockToggledEvent : EntityEventArgs
- {
- public readonly bool Locked;
-
- public LockToggledEvent(bool locked)
- {
- Locked = locked;
- }
- }
-}
using Content.Shared.Standing;
using Content.Shared.Storage;
using Content.Shared.IdentityManagement;
+using Content.Shared.Storage.Components;
namespace Content.Server.Morgue;
return;
if (_appearance.TryGetData<bool>(uid, CrematoriumVisuals.Burning, out var isBurning, appearance) && isBurning)
+ {
args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-is-burning", ("owner", uid)));
-
+ }
if (_appearance.TryGetData<bool>(uid, StorageVisuals.HasContents, out var hasContents, appearance) && hasContents)
{
args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-has-contents"));
}
}
- private void OnAttemptOpen(EntityUid uid, ActiveCrematoriumComponent component, StorageOpenAttemptEvent args)
+ private void OnAttemptOpen(EntityUid uid, ActiveCrematoriumComponent component, ref StorageOpenAttemptEvent args)
{
- args.Cancel();
+ args.Cancelled = true;
}
private void AddCremateVerb(EntityUid uid, CrematoriumComponent component, GetVerbsEvent<AlternativeVerb> args)
-using Content.Server.Body.Systems;
using Content.Server.Morgue.Components;
-using Content.Server.Storage.Components;
using Content.Shared.Body.Components;
using Content.Shared.Standing;
+using Content.Shared.Storage.Components;
namespace Content.Server.Morgue;
public sealed class EntityStorageLayingDownOverrideSystem : EntitySystem
{
[Dependency] private readonly StandingStateSystem _standing = default!;
- [Dependency] private readonly BodySystem _body = default!;
public override void Initialize()
{
SubscribeLocalEvent<EntityStorageLayingDownOverrideComponent, StorageBeforeCloseEvent>(OnBeforeClose);
}
- private void OnBeforeClose(EntityUid uid, EntityStorageLayingDownOverrideComponent component,
- StorageBeforeCloseEvent args)
+ private void OnBeforeClose(EntityUid uid, EntityStorageLayingDownOverrideComponent component, ref StorageBeforeCloseEvent args)
{
foreach (var ent in args.Contents)
+ {
if (HasComp<BodyComponent>(ent) && !_standing.IsDown(ent))
args.Contents.Remove(ent);
+ }
}
}
-using Content.Shared.Movement;
using Content.Server.Storage.Components;
using Content.Server.DoAfter;
-using Content.Server.Lock;
-using Robust.Shared.Player;
using Robust.Shared.Containers;
using Content.Server.Popups;
using Content.Shared.Movement.Events;
using Content.Server.Storage.EntitySystems;
+using Content.Shared.Lock;
using Content.Shared.Popups;
namespace Content.Server.Resist;
-using Content.Server.Lock;
-using Content.Server.Storage.Components;
+using Content.Shared.Lock;
using Content.Shared.Security;
using Robust.Server.GameObjects;
ToggleBarrierDeploy(uid, component, lockComponent.Locked);
}
- private void OnLockToggled(EntityUid uid, DeployableBarrierComponent component, LockToggledEvent args)
+ private void OnLockToggled(EntityUid uid, DeployableBarrierComponent component, ref LockToggledEvent args)
{
ToggleBarrierDeploy(uid, component, args.Locked);
}
using Content.Shared.Database;
using Content.Shared.Examine;
using Content.Shared.Interaction;
+using Content.Shared.Lock;
using Content.Shared.Popups;
using Content.Shared.Projectiles;
using Content.Shared.Singularity.Components;
[ViewVariables(VVAccess.ReadWrite)]
public GasMixture Air { get; set; } = new (GasMixVolume);
}
-
-public sealed class InsertIntoEntityStorageAttemptEvent : CancellableEntityEventArgs { }
-public sealed class StoreMobInItemContainerAttemptEvent : CancellableEntityEventArgs
-{
- public bool Handled = false;
-}
-public sealed class StorageOpenAttemptEvent : CancellableEntityEventArgs
-{
- public bool Silent = false;
-
- public StorageOpenAttemptEvent (bool silent = false)
- {
- Silent = silent;
- }
-}
-public sealed class StorageBeforeOpenEvent : EventArgs { }
-public sealed class StorageAfterOpenEvent : EventArgs { }
-public sealed class StorageCloseAttemptEvent : CancellableEntityEventArgs { }
-public sealed class StorageBeforeCloseEvent : EventArgs
-{
- public HashSet<EntityUid> Contents;
-
- /// <summary>
- /// Entities that will get inserted, regardless of any insertion or whitelist checks.
- /// </summary>
- public HashSet<EntityUid> BypassChecks = new();
-
- public StorageBeforeCloseEvent(HashSet<EntityUid> contents)
- {
- Contents = contents;
- }
-}
-public sealed class StorageAfterCloseEvent : EventArgs { }
using System.Threading;
using Content.Server.DoAfter;
using Content.Server.Explosion.EntitySystems;
-using Content.Server.Lock;
using Content.Server.Mind.Components;
using Content.Server.Resist;
using Content.Server.Station.Components;
using Content.Server.Tools.Systems;
using Content.Shared.Access.Components;
using Content.Shared.Coordinates;
+using Content.Shared.Lock;
+using Content.Shared.Storage.Components;
using Robust.Shared.Random;
using Robust.Shared.Timing;
Spawn(effectSourceComponent.BehaviorProperties.BluespaceEffectPrototype, effectTargetUid.ToCoordinates());
}
- private void PreOpen(EntityUid uid, BluespaceLockerComponent component, StorageBeforeOpenEvent args)
+ private void PreOpen(EntityUid uid, BluespaceLockerComponent component, ref StorageBeforeOpenEvent args)
{
EntityStorageComponent? entityStorageComponent = null;
int transportedEntities = 0;
}
}
- private void PostClose(EntityUid uid, BluespaceLockerComponent component, StorageAfterCloseEvent args)
+ private void PostClose(EntityUid uid, BluespaceLockerComponent component, ref StorageAfterCloseEvent args)
{
PostClose(uid, component);
}
using Content.Server.Storage.Components;
using Content.Shared.Audio;
-using Content.Shared.Interaction;
-using Robust.Server.Containers;
using Robust.Shared.Audio;
using Robust.Shared.Player;
using Robust.Shared.Random;
using System.Linq;
+using Content.Shared.Storage.Components;
namespace Content.Server.Storage.EntitySystems;
SubscribeLocalEvent<CursedEntityStorageComponent, StorageAfterCloseEvent>(OnClose);
}
- private void OnClose(EntityUid uid, CursedEntityStorageComponent component, StorageAfterCloseEvent args)
+ private void OnClose(EntityUid uid, CursedEntityStorageComponent component, ref StorageAfterCloseEvent args)
{
if (!TryComp<EntityStorageComponent>(uid, out var storage))
return;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction;
using Content.Shared.Item;
+using Content.Shared.Lock;
using Content.Shared.Placeable;
using Content.Shared.Storage;
+using Content.Shared.Storage.Components;
using Content.Shared.Wall;
using Content.Shared.Whitelist;
using Robust.Server.Containers;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;
-using Robust.Shared.Player;
namespace Content.Server.Storage.EntitySystems;
if (!Resolve(uid, ref component))
return;
- RaiseLocalEvent(uid, new StorageBeforeOpenEvent());
+ var beforeev = new StorageBeforeOpenEvent();
+ RaiseLocalEvent(uid, ref beforeev);
component.Open = true;
EmptyContents(uid, component);
ModifyComponents(uid, component);
- _audio.PlayPvs(component.OpenSound, component.Owner);
+ _audio.PlayPvs(component.OpenSound, uid);
ReleaseGas(uid, component);
- RaiseLocalEvent(uid, new StorageAfterOpenEvent());
+ var afterev = new StorageAfterOpenEvent();
+ RaiseLocalEvent(uid, ref afterev);
}
public void CloseStorage(EntityUid uid, EntityStorageComponent? component = null)
var entities = _lookup.GetEntitiesInRange(targetCoordinates, component.EnteringRange, LookupFlags.Approximate | LookupFlags.Dynamic | LookupFlags.Sundries);
- var ev = new StorageBeforeCloseEvent(entities);
- RaiseLocalEvent(uid, ev);
+ var ev = new StorageBeforeCloseEvent(entities, new());
+ RaiseLocalEvent(uid, ref ev);
var count = 0;
foreach (var entity in ev.Contents)
{
TakeGas(uid, component);
ModifyComponents(uid, component);
- _audio.PlayPvs(component.CloseSound, component.Owner);
+ _audio.PlayPvs(component.CloseSound, uid);
component.LastInternalOpenAttempt = default;
- RaiseLocalEvent(uid, new StorageAfterCloseEvent());
+ var afterev = new StorageAfterCloseEvent();
+ RaiseLocalEvent(uid, ref afterev);
}
public bool Insert(EntityUid toInsert, EntityUid container, EntityStorageComponent? component = null)
}
var ev = new StorageOpenAttemptEvent(silent);
- RaiseLocalEvent(target, ev, true);
+ RaiseLocalEvent(target, ref ev, true);
return !ev.Cancelled;
}
public bool CanClose(EntityUid target, bool silent = false)
{
var ev = new StorageCloseAttemptEvent();
- RaiseLocalEvent(target, ev, silent);
+ RaiseLocalEvent(target, ref ev, silent);
return !ev.Cancelled;
}
// 6. if this is an item, then mobs must only be eaten if some other component prevents
// pick-up interactions while a mob is inside (e.g. foldable)
var attemptEvent = new InsertIntoEntityStorageAttemptEvent();
- RaiseLocalEvent(toInsert, attemptEvent);
+ RaiseLocalEvent(toInsert, ref attemptEvent);
if (attemptEvent.Cancelled)
return false;
else
{
var storeEv = new StoreMobInItemContainerAttemptEvent();
- RaiseLocalEvent(container, storeEv);
+ RaiseLocalEvent(container, ref storeEv);
allowedToEat = storeEv.Handled && !storeEv.Cancelled;
}
}
using Content.Shared.CombatMode;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Implants.Components;
+using Content.Shared.Lock;
using Content.Shared.Movement.Events;
namespace Content.Server.Storage.EntitySystems
--- /dev/null
+using Robust.Shared.Audio;
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Lock;
+
+/// <summary>
+/// Allows locking/unlocking, with access determined by AccessReader
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+[Access(typeof(LockSystem))]
+public sealed class LockComponent : Component
+{
+ /// <summary>
+ /// Whether or not the lock is locked.
+ /// </summary>
+ [DataField("locked"), ViewVariables(VVAccess.ReadWrite)]
+ public bool Locked = true;
+
+ /// <summary>
+ /// Whether or not the lock is toggled by simply clicking.
+ /// </summary>
+ [DataField("lockOnClick"), ViewVariables(VVAccess.ReadWrite)]
+ public bool LockOnClick;
+
+ /// <summary>
+ /// The sound played when unlocked.
+ /// </summary>
+ [DataField("unlockingSound"), ViewVariables(VVAccess.ReadWrite)]
+ public SoundSpecifier UnlockSound = new SoundPathSpecifier("/Audio/Machines/door_lock_off.ogg");
+
+ /// <summary>
+ /// The sound played when locked.
+ /// </summary>
+ [DataField("lockingSound"), ViewVariables(VVAccess.ReadWrite)]
+ public SoundSpecifier LockSound = new SoundPathSpecifier("/Audio/Machines/door_lock_on.ogg");
+}
+
+[Serializable, NetSerializable]
+public sealed class LockComponentState : ComponentState
+{
+ public bool Locked;
+
+ public bool LockOnClick;
+
+ public LockComponentState(bool locked, bool lockOnClick)
+ {
+ Locked = locked;
+ LockOnClick = lockOnClick;
+ }
+}
+
+[ByRefEvent]
+public record struct LockToggleAttemptEvent(EntityUid User, bool Silent = false, bool Cancelled = false);
+
+[ByRefEvent]
+public readonly record struct LockToggledEvent(bool Locked);
--- /dev/null
+using Content.Shared.Emag.Systems;
+using Content.Shared.Access.Components;
+using Content.Shared.Access.Systems;
+using Content.Shared.Examine;
+using Content.Shared.Hands.Components;
+using Content.Shared.IdentityManagement;
+using Content.Shared.Interaction;
+using Content.Shared.Popups;
+using Content.Shared.Storage;
+using Content.Shared.Storage.Components;
+using Content.Shared.Verbs;
+using JetBrains.Annotations;
+using Robust.Shared.Audio;
+using Robust.Shared.GameStates;
+using Robust.Shared.Network;
+using Robust.Shared.Timing;
+
+namespace Content.Shared.Lock;
+
+/// <summary>
+/// Handles (un)locking and examining of Lock components
+/// </summary>
+[UsedImplicitly]
+public sealed class LockSystem : EntitySystem
+{
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly INetManager _net = default!;
+ [Dependency] private readonly AccessReaderSystem _accessReader = default!;
+ [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly SharedPopupSystem _sharedPopupSystem = default!;
+
+ /// <inheritdoc />
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<LockComponent, ComponentGetState>(OnGetState);
+ SubscribeLocalEvent<LockComponent, ComponentHandleState>(OnHandleState);
+ SubscribeLocalEvent<LockComponent, ComponentStartup>(OnStartup);
+ SubscribeLocalEvent<LockComponent, ActivateInWorldEvent>(OnActivated);
+ SubscribeLocalEvent<LockComponent, StorageOpenAttemptEvent>(OnStorageOpenAttempt);
+ SubscribeLocalEvent<LockComponent, ExaminedEvent>(OnExamined);
+ SubscribeLocalEvent<LockComponent, GetVerbsEvent<AlternativeVerb>>(AddToggleLockVerb);
+ SubscribeLocalEvent<LockComponent, GotEmaggedEvent>(OnEmagged);
+ }
+
+ private void OnGetState(EntityUid uid, LockComponent component, ref ComponentGetState args)
+ {
+ args.State = new LockComponentState(component.Locked, component.LockOnClick);
+ }
+
+ private void OnHandleState(EntityUid uid, LockComponent component, ref ComponentHandleState args)
+ {
+ if (args.Current is not LockComponentState state)
+ return;
+ component.Locked = state.Locked;
+ component.LockOnClick = state.LockOnClick;
+ }
+
+ private void OnStartup(EntityUid uid, LockComponent lockComp, ComponentStartup args)
+ {
+ _appearanceSystem.SetData(uid, StorageVisuals.CanLock, true);
+ }
+
+ private void OnActivated(EntityUid uid, LockComponent lockComp, ActivateInWorldEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ // Only attempt an unlock by default on Activate
+ if (lockComp.Locked)
+ {
+ TryUnlock(uid, args.User, lockComp);
+ args.Handled = true;
+ }
+ else if (lockComp.LockOnClick)
+ {
+ TryLock(uid, args.User, lockComp);
+ args.Handled = true;
+ }
+ }
+
+ private void OnStorageOpenAttempt(EntityUid uid, LockComponent component, ref StorageOpenAttemptEvent args)
+ {
+ if (!component.Locked)
+ return;
+ if (!args.Silent)
+ _sharedPopupSystem.PopupEntity(Loc.GetString("entity-storage-component-locked-message"), uid);
+
+ args.Cancelled = true;
+ }
+
+ private void OnExamined(EntityUid uid, LockComponent lockComp, ExaminedEvent args)
+ {
+ args.PushText(Loc.GetString(lockComp.Locked
+ ? "lock-comp-on-examined-is-locked"
+ : "lock-comp-on-examined-is-unlocked",
+ ("entityName", Identity.Name(uid, EntityManager))));
+ }
+
+ /// <summary>
+ /// Attmempts to lock a given entity
+ /// </summary>
+ /// <param name="uid">The entity with the lock</param>
+ /// <param name="user">The person trying to lock it</param>
+ /// <param name="lockComp"></param>
+ /// <returns>If locking was successful</returns>
+ public bool TryLock(EntityUid uid, EntityUid user, LockComponent? lockComp = null)
+ {
+ if (!Resolve(uid, ref lockComp))
+ return false;
+
+ if (!CanToggleLock(uid, user, quiet: false))
+ return false;
+
+ if (!HasUserAccess(uid, user, quiet: false))
+ return false;
+
+ if (_net.IsClient && _timing.IsFirstTimePredicted)
+ {
+ _sharedPopupSystem.PopupEntity(Loc.GetString("lock-comp-do-lock-success",
+ ("entityName", Identity.Name(uid, EntityManager))), uid, user);
+ _audio.PlayPvs(_audio.GetSound(lockComp.LockSound), uid, AudioParams.Default.WithVolume(-5));
+ }
+
+ lockComp.Locked = true;
+ _appearanceSystem.SetData(uid, StorageVisuals.Locked, true);
+ Dirty(lockComp);
+
+ RaiseLocalEvent(uid, new LockToggledEvent(true), true);
+ return true;
+ }
+
+ /// <summary>
+ /// Forces a given entity to be unlocked
+ /// </summary>
+ /// <param name="uid">The entity with the lock</param>
+ /// <param name="user">The person unlocking it. Can be null</param>
+ /// <param name="lockComp"></param>
+ public void Unlock(EntityUid uid, EntityUid? user, LockComponent? lockComp = null)
+ {
+ if (!Resolve(uid, ref lockComp))
+ return;
+
+ if (_net.IsClient && _timing.IsFirstTimePredicted)
+ {
+ if (user is { Valid: true })
+ {
+ _sharedPopupSystem.PopupEntity(Loc.GetString("lock-comp-do-unlock-success",
+ ("entityName", Identity.Name(uid, EntityManager))), uid, user.Value);
+ }
+ _audio.PlayPvs(_audio.GetSound(lockComp.UnlockSound), uid, AudioParams.Default.WithVolume(-5));
+ }
+
+ lockComp.Locked = false;
+ _appearanceSystem.SetData(uid, StorageVisuals.Locked, false);
+ Dirty(lockComp);
+
+ RaiseLocalEvent(uid, new LockToggledEvent(false), true);
+ }
+
+
+ /// <summary>
+ /// Attmempts to unlock a given entity
+ /// </summary>
+ /// <param name="uid">The entity with the lock</param>
+ /// <param name="user">The person trying to unlock it</param>
+ /// <param name="lockComp"></param>
+ /// <returns>If locking was successful</returns>
+ public bool TryUnlock(EntityUid uid, EntityUid user, LockComponent? lockComp = null)
+ {
+ if (!Resolve(uid, ref lockComp))
+ return false;
+
+ if (!CanToggleLock(uid, user, quiet: false))
+ return false;
+
+ if (!HasUserAccess(uid, user, quiet: false))
+ return false;
+
+ Unlock(uid, user, lockComp);
+ return true;
+ }
+
+ /// <summary>
+ /// Raises an event for other components to check whether or not
+ /// the entity can be locked in its current state.
+ /// </summary>
+ public bool CanToggleLock(EntityUid uid, EntityUid user, bool quiet = true)
+ {
+ if (!HasComp<SharedHandsComponent>(user))
+ return false;
+
+ var ev = new LockToggleAttemptEvent(user, quiet);
+ RaiseLocalEvent(uid, ref ev, true);
+ return !ev.Cancelled;
+ }
+
+ private bool HasUserAccess(EntityUid uid, EntityUid user, AccessReaderComponent? reader = null, bool quiet = true)
+ {
+ // Not having an AccessComponent means you get free access. woo!
+ if (!Resolve(uid, ref reader))
+ return true;
+
+ if (_accessReader.IsAllowed(user, reader))
+ return true;
+
+ if (!quiet && _net.IsClient && _timing.IsFirstTimePredicted)
+ _sharedPopupSystem.PopupEntity(Loc.GetString("lock-comp-has-user-access-fail"), uid, user);
+ return false;
+ }
+
+ private void AddToggleLockVerb(EntityUid uid, LockComponent component, GetVerbsEvent<AlternativeVerb> args)
+ {
+ if (!args.CanAccess || !args.CanInteract || !CanToggleLock(uid, args.User))
+ return;
+
+ AlternativeVerb verb = new()
+ {
+ Act = component.Locked ?
+ () => TryUnlock(uid, args.User, component) :
+ () => TryLock(uid, args.User, component),
+ Text = Loc.GetString(component.Locked ? "toggle-lock-verb-unlock" : "toggle-lock-verb-lock"),
+ IconTexture = component.Locked ? "/Textures/Interface/VerbIcons/unlock.svg.192dpi.png" : "/Textures/Interface/VerbIcons/lock.svg.192dpi.png"
+ };
+ args.Verbs.Add(verb);
+ }
+
+ private void OnEmagged(EntityUid uid, LockComponent component, ref GotEmaggedEvent args)
+ {
+ if (!component.Locked)
+ return;
+ if (_net.IsClient && _timing.IsFirstTimePredicted)
+ {
+ _audio.PlayPvs(_audio.GetSound(component.UnlockSound), uid, AudioParams.Default.WithVolume(-5));
+ }
+ _appearanceSystem.SetData(uid, StorageVisuals.Locked, false);
+ RemComp<LockComponent>(uid); //Literally destroys the lock as a tell it was emagged
+ args.Handled = true;
+ }
+}
+
--- /dev/null
+namespace Content.Shared.Storage.Components;
+
+[ByRefEvent]
+public record struct InsertIntoEntityStorageAttemptEvent(bool Cancelled = false);
+
+[ByRefEvent]
+public record struct StoreMobInItemContainerAttemptEvent(bool Handled, bool Cancelled = false);
+
+[ByRefEvent]
+public record struct StorageOpenAttemptEvent(bool Silent, bool Cancelled = false);
+
+[ByRefEvent]
+public readonly record struct StorageBeforeOpenEvent;
+
+[ByRefEvent]
+public readonly record struct StorageAfterOpenEvent;
+
+[ByRefEvent]
+public record struct StorageCloseAttemptEvent(bool Cancelled = false);
+
+[ByRefEvent]
+public readonly record struct StorageBeforeCloseEvent(HashSet<EntityUid> Contents, HashSet<EntityUid> BypassChecks);
+
+[ByRefEvent]
+public readonly record struct StorageAfterCloseEvent;