move lockcomponent to shared (#13722)

* move lockcomponent to shared

* ajcm review
This commit is contained in:
Nemanja
2023-02-11 20:12:29 -05:00
committed by GitHub
parent 301956ef15
commit c6c319f7e4
23 changed files with 381 additions and 332 deletions

View File

@@ -4,21 +4,19 @@ using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Piping.Components; using Content.Server.Atmos.Piping.Components;
using Content.Server.Atmos.Piping.Unary.Components; using Content.Server.Atmos.Piping.Unary.Components;
using Content.Server.Cargo.Systems; using Content.Server.Cargo.Systems;
using Content.Server.Lock;
using Content.Server.NodeContainer; using Content.Server.NodeContainer;
using Content.Server.NodeContainer.NodeGroups; using Content.Server.NodeContainer.NodeGroups;
using Content.Server.NodeContainer.Nodes; using Content.Server.NodeContainer.Nodes;
using Content.Server.Popups; using Content.Server.Popups;
using Content.Server.Storage.Components;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping.Binary.Components; using Content.Shared.Atmos.Piping.Binary.Components;
using Content.Shared.Database; using Content.Shared.Database;
using Content.Shared.Hands.EntitySystems; using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Lock;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.Player;
namespace Content.Server.Atmos.Piping.Unary.EntitySystems namespace Content.Server.Atmos.Piping.Unary.EntitySystems
{ {
@@ -324,7 +322,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
args.GasMixtures = new Dictionary<string, GasMixture?> { {Name(uid), component.Air} }; 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); _appearanceSystem.SetData(uid, GasCanisterVisuals.Locked, args.Locked);
} }

View File

@@ -1,6 +1,5 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Content.Server.Administration.Logs; using Content.Server.Administration.Logs;
using Content.Server.Storage.Components;
using Content.Shared.Alert; using Content.Shared.Alert;
using Content.Shared.Bed.Sleep; using Content.Shared.Bed.Sleep;
using Content.Shared.Buckle.Components; using Content.Shared.Buckle.Components;
@@ -11,6 +10,7 @@ using Content.Shared.IdentityManagement;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Components;
using Content.Shared.Pulling.Components; using Content.Shared.Pulling.Components;
using Content.Shared.Storage.Components;
using Content.Shared.Stunnable; using Content.Shared.Stunnable;
using Content.Shared.Vehicle.Components; using Content.Shared.Vehicle.Components;
using Content.Shared.Verbs; using Content.Shared.Verbs;
@@ -98,10 +98,10 @@ public sealed partial class BuckleSystem
TryUnbuckle(uid, buckle.Owner, true, buckle); 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) if (comp.Buckled)
args.Cancel(); args.Cancelled = true;
} }
private void OnBuckleCanDrop(EntityUid uid, BuckleComponent component, CanDropEvent args) private void OnBuckleCanDrop(EntityUid uid, BuckleComponent component, CanDropEvent args)

View File

@@ -3,6 +3,7 @@ using Content.Shared.Audio;
using Content.Shared.Cabinet; using Content.Shared.Cabinet;
using Content.Shared.Containers.ItemSlots; using Content.Shared.Containers.ItemSlots;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Lock;
using Content.Shared.Verbs; using Content.Shared.Verbs;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Audio; using Robust.Shared.Audio;

View File

@@ -8,6 +8,7 @@ using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems; using Content.Shared.Movement.Systems;
using Content.Shared.Stealth; using Content.Shared.Stealth;
using Content.Shared.Stealth.Components; using Content.Shared.Stealth.Components;
using Content.Shared.Storage.Components;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.Player; using Robust.Shared.Player;
@@ -44,7 +45,7 @@ public sealed class CardboardBoxSystem : SharedCardboardBoxSystem
_storage.OpenStorage(uid); _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. //Remove the mover after the box is opened and play the effect if it hasn't been played yet.
if (component.Mover != null) if (component.Mover != null)
@@ -64,7 +65,7 @@ public sealed class CardboardBoxSystem : SharedCardboardBoxSystem
_stealth.SetEnabled(uid, false); _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 this box has a stealth/chameleon effect, enable the stealth effect.
if (TryComp(uid, out StealthComponent? stealth)) if (TryComp(uid, out StealthComponent? stealth))

View File

@@ -1,6 +1,6 @@
using Content.Server.Storage.Components;
using Content.Shared.Construction; using Content.Shared.Construction;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Lock;
using JetBrains.Annotations; using JetBrains.Annotations;
namespace Content.Server.Construction.Conditions namespace Content.Server.Construction.Conditions

View File

@@ -3,6 +3,7 @@ using Content.Server.Buckle.Systems;
using Content.Server.Storage.Components; using Content.Server.Storage.Components;
using Content.Shared.Buckle.Components; using Content.Shared.Buckle.Components;
using Content.Shared.Foldable; using Content.Shared.Foldable;
using Content.Shared.Storage.Components;
using Content.Shared.Verbs; using Content.Shared.Verbs;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.Containers; using Robust.Shared.Containers;
@@ -12,8 +13,8 @@ namespace Content.Server.Foldable
[UsedImplicitly] [UsedImplicitly]
public sealed class FoldableSystem : SharedFoldableSystem public sealed class FoldableSystem : SharedFoldableSystem
{ {
[Dependency] private BuckleSystem _buckle = default!; [Dependency] private readonly BuckleSystem _buckle = default!;
[Dependency] private SharedContainerSystem _container = default!; [Dependency] private readonly SharedContainerSystem _container = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -25,10 +26,10 @@ namespace Content.Server.Foldable
} }
private void OnFoldableOpenAttempt(EntityUid uid, FoldableComponent component, StorageOpenAttemptEvent args) private void OnFoldableOpenAttempt(EntityUid uid, FoldableComponent component, ref StorageOpenAttemptEvent args)
{ {
if (component.IsFolded) if (component.IsFolded)
args.Cancel(); args.Cancelled = true;
} }
public bool TryToggleFold(FoldableComponent comp) public bool TryToggleFold(FoldableComponent comp)
@@ -89,12 +90,12 @@ namespace Content.Server.Foldable
_buckle.StrapSetEnabled(component.Owner, !component.IsFolded); _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; args.Handled = true;
if (comp.IsFolded) if (comp.IsFolded)
args.Cancel(); args.Cancelled = true;
} }
#region Verb #region Verb

View File

@@ -4,7 +4,6 @@ using Content.Server.Ghost.Components;
using Content.Server.Mind; using Content.Server.Mind;
using Content.Server.Mind.Components; using Content.Server.Mind.Components;
using Content.Server.Players; using Content.Server.Players;
using Content.Server.Storage.Components;
using Content.Server.Visible; using Content.Server.Visible;
using Content.Server.Warps; using Content.Server.Warps;
using Content.Shared.Actions; using Content.Shared.Actions;
@@ -15,6 +14,7 @@ using Content.Shared.Ghost;
using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems; using Content.Shared.Mobs.Systems;
using Content.Shared.Movement.Events; using Content.Shared.Movement.Events;
using Content.Shared.Storage.Components;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Server.Player; using Robust.Server.Player;
@@ -270,9 +270,9 @@ namespace Content.Server.Ghost
} }
} }
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> /// <summary>

View File

@@ -1,30 +0,0 @@
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 { }

View File

@@ -1,206 +0,0 @@
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;
}
}
}
}

View File

@@ -1,12 +0,0 @@
namespace Content.Server.Lock
{
public sealed class LockToggledEvent : EntityEventArgs
{
public readonly bool Locked;
public LockToggledEvent(bool locked)
{
Locked = locked;
}
}
}

View File

@@ -14,6 +14,7 @@ using Content.Shared.Examine;
using Content.Shared.Standing; using Content.Shared.Standing;
using Content.Shared.Storage; using Content.Shared.Storage;
using Content.Shared.IdentityManagement; using Content.Shared.IdentityManagement;
using Content.Shared.Storage.Components;
namespace Content.Server.Morgue; namespace Content.Server.Morgue;
@@ -42,8 +43,9 @@ public sealed class CrematoriumSystem : EntitySystem
return; return;
if (_appearance.TryGetData<bool>(uid, CrematoriumVisuals.Burning, out var isBurning, appearance) && isBurning) 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))); 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) 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")); args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-has-contents"));
@@ -54,9 +56,9 @@ public sealed class CrematoriumSystem : EntitySystem
} }
} }
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) private void AddCremateVerb(EntityUid uid, CrematoriumComponent component, GetVerbsEvent<AlternativeVerb> args)

View File

@@ -1,15 +1,13 @@
using Content.Server.Body.Systems;
using Content.Server.Morgue.Components; using Content.Server.Morgue.Components;
using Content.Server.Storage.Components;
using Content.Shared.Body.Components; using Content.Shared.Body.Components;
using Content.Shared.Standing; using Content.Shared.Standing;
using Content.Shared.Storage.Components;
namespace Content.Server.Morgue; namespace Content.Server.Morgue;
public sealed class EntityStorageLayingDownOverrideSystem : EntitySystem public sealed class EntityStorageLayingDownOverrideSystem : EntitySystem
{ {
[Dependency] private readonly StandingStateSystem _standing = default!; [Dependency] private readonly StandingStateSystem _standing = default!;
[Dependency] private readonly BodySystem _body = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -18,11 +16,12 @@ public sealed class EntityStorageLayingDownOverrideSystem : EntitySystem
SubscribeLocalEvent<EntityStorageLayingDownOverrideComponent, StorageBeforeCloseEvent>(OnBeforeClose); SubscribeLocalEvent<EntityStorageLayingDownOverrideComponent, StorageBeforeCloseEvent>(OnBeforeClose);
} }
private void OnBeforeClose(EntityUid uid, EntityStorageLayingDownOverrideComponent component, private void OnBeforeClose(EntityUid uid, EntityStorageLayingDownOverrideComponent component, ref StorageBeforeCloseEvent args)
StorageBeforeCloseEvent args)
{ {
foreach (var ent in args.Contents) foreach (var ent in args.Contents)
{
if (HasComp<BodyComponent>(ent) && !_standing.IsDown(ent)) if (HasComp<BodyComponent>(ent) && !_standing.IsDown(ent))
args.Contents.Remove(ent); args.Contents.Remove(ent);
}
} }
} }

View File

@@ -1,12 +1,10 @@
using Content.Shared.Movement;
using Content.Server.Storage.Components; using Content.Server.Storage.Components;
using Content.Server.DoAfter; using Content.Server.DoAfter;
using Content.Server.Lock;
using Robust.Shared.Player;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Content.Server.Popups; using Content.Server.Popups;
using Content.Shared.Movement.Events; using Content.Shared.Movement.Events;
using Content.Server.Storage.EntitySystems; using Content.Server.Storage.EntitySystems;
using Content.Shared.Lock;
using Content.Shared.Popups; using Content.Shared.Popups;
namespace Content.Server.Resist; namespace Content.Server.Resist;

View File

@@ -1,5 +1,4 @@
using Content.Server.Lock; using Content.Shared.Lock;
using Content.Server.Storage.Components;
using Content.Shared.Security; using Content.Shared.Security;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
@@ -24,7 +23,7 @@ namespace Content.Server.Security.Systems
ToggleBarrierDeploy(uid, component, lockComponent.Locked); 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); ToggleBarrierDeploy(uid, component, args.Locked);
} }

View File

@@ -9,6 +9,7 @@ using Content.Server.Weapons.Ranged.Systems;
using Content.Shared.Database; using Content.Shared.Database;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Lock;
using Content.Shared.Popups; using Content.Shared.Popups;
using Content.Shared.Projectiles; using Content.Shared.Projectiles;
using Content.Shared.Singularity.Components; using Content.Shared.Singularity.Components;

View File

@@ -99,36 +99,3 @@ public sealed class EntityStorageComponent : Component, IGasMixtureHolder
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public GasMixture Air { get; set; } = new (GasMixVolume); 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 { }

View File

@@ -2,7 +2,6 @@
using System.Threading; using System.Threading;
using Content.Server.DoAfter; using Content.Server.DoAfter;
using Content.Server.Explosion.EntitySystems; using Content.Server.Explosion.EntitySystems;
using Content.Server.Lock;
using Content.Server.Mind.Components; using Content.Server.Mind.Components;
using Content.Server.Resist; using Content.Server.Resist;
using Content.Server.Station.Components; using Content.Server.Station.Components;
@@ -10,6 +9,8 @@ using Content.Server.Storage.Components;
using Content.Server.Tools.Systems; using Content.Server.Tools.Systems;
using Content.Shared.Access.Components; using Content.Shared.Access.Components;
using Content.Shared.Coordinates; using Content.Shared.Coordinates;
using Content.Shared.Lock;
using Content.Shared.Storage.Components;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Timing; using Robust.Shared.Timing;
@@ -58,7 +59,7 @@ public sealed class BluespaceLockerSystem : EntitySystem
Spawn(effectSourceComponent.BehaviorProperties.BluespaceEffectPrototype, effectTargetUid.ToCoordinates()); 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; EntityStorageComponent? entityStorageComponent = null;
int transportedEntities = 0; int transportedEntities = 0;
@@ -259,7 +260,7 @@ public sealed class BluespaceLockerSystem : EntitySystem
} }
} }
private void PostClose(EntityUid uid, BluespaceLockerComponent component, StorageAfterCloseEvent args) private void PostClose(EntityUid uid, BluespaceLockerComponent component, ref StorageAfterCloseEvent args)
{ {
PostClose(uid, component); PostClose(uid, component);
} }

View File

@@ -1,11 +1,10 @@
using Content.Server.Storage.Components; using Content.Server.Storage.Components;
using Content.Shared.Audio; using Content.Shared.Audio;
using Content.Shared.Interaction;
using Robust.Server.Containers;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Random; using Robust.Shared.Random;
using System.Linq; using System.Linq;
using Content.Shared.Storage.Components;
namespace Content.Server.Storage.EntitySystems; namespace Content.Server.Storage.EntitySystems;
@@ -21,7 +20,7 @@ public sealed class CursedEntityStorageSystem : EntitySystem
SubscribeLocalEvent<CursedEntityStorageComponent, StorageAfterCloseEvent>(OnClose); 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)) if (!TryComp<EntityStorageComponent>(uid, out var storage))
return; return;

View File

@@ -10,8 +10,10 @@ using Content.Shared.Destructible;
using Content.Shared.Hands.Components; using Content.Shared.Hands.Components;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Item; using Content.Shared.Item;
using Content.Shared.Lock;
using Content.Shared.Placeable; using Content.Shared.Placeable;
using Content.Shared.Storage; using Content.Shared.Storage;
using Content.Shared.Storage.Components;
using Content.Shared.Wall; using Content.Shared.Wall;
using Content.Shared.Whitelist; using Content.Shared.Whitelist;
using Robust.Server.Containers; using Robust.Server.Containers;
@@ -20,7 +22,6 @@ using Robust.Shared.Map;
using Robust.Shared.Physics; using Robust.Shared.Physics;
using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems; using Robust.Shared.Physics.Systems;
using Robust.Shared.Player;
namespace Content.Server.Storage.EntitySystems; namespace Content.Server.Storage.EntitySystems;
@@ -167,13 +168,15 @@ public sealed class EntityStorageSystem : EntitySystem
if (!Resolve(uid, ref component)) if (!Resolve(uid, ref component))
return; return;
RaiseLocalEvent(uid, new StorageBeforeOpenEvent()); var beforeev = new StorageBeforeOpenEvent();
RaiseLocalEvent(uid, ref beforeev);
component.Open = true; component.Open = true;
EmptyContents(uid, component); EmptyContents(uid, component);
ModifyComponents(uid, component); ModifyComponents(uid, component);
_audio.PlayPvs(component.OpenSound, component.Owner); _audio.PlayPvs(component.OpenSound, uid);
ReleaseGas(uid, component); ReleaseGas(uid, component);
RaiseLocalEvent(uid, new StorageAfterOpenEvent()); var afterev = new StorageAfterOpenEvent();
RaiseLocalEvent(uid, ref afterev);
} }
public void CloseStorage(EntityUid uid, EntityStorageComponent? component = null) public void CloseStorage(EntityUid uid, EntityStorageComponent? component = null)
@@ -186,8 +189,8 @@ public sealed class EntityStorageSystem : EntitySystem
var entities = _lookup.GetEntitiesInRange(targetCoordinates, component.EnteringRange, LookupFlags.Approximate | LookupFlags.Dynamic | LookupFlags.Sundries); var entities = _lookup.GetEntitiesInRange(targetCoordinates, component.EnteringRange, LookupFlags.Approximate | LookupFlags.Dynamic | LookupFlags.Sundries);
var ev = new StorageBeforeCloseEvent(entities); var ev = new StorageBeforeCloseEvent(entities, new());
RaiseLocalEvent(uid, ev); RaiseLocalEvent(uid, ref ev);
var count = 0; var count = 0;
foreach (var entity in ev.Contents) foreach (var entity in ev.Contents)
{ {
@@ -207,9 +210,10 @@ public sealed class EntityStorageSystem : EntitySystem
TakeGas(uid, component); TakeGas(uid, component);
ModifyComponents(uid, component); ModifyComponents(uid, component);
_audio.PlayPvs(component.CloseSound, component.Owner); _audio.PlayPvs(component.CloseSound, uid);
component.LastInternalOpenAttempt = default; 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) public bool Insert(EntityUid toInsert, EntityUid container, EntityStorageComponent? component = null)
@@ -302,7 +306,7 @@ public sealed class EntityStorageSystem : EntitySystem
} }
var ev = new StorageOpenAttemptEvent(silent); var ev = new StorageOpenAttemptEvent(silent);
RaiseLocalEvent(target, ev, true); RaiseLocalEvent(target, ref ev, true);
return !ev.Cancelled; return !ev.Cancelled;
} }
@@ -310,7 +314,7 @@ public sealed class EntityStorageSystem : EntitySystem
public bool CanClose(EntityUid target, bool silent = false) public bool CanClose(EntityUid target, bool silent = false)
{ {
var ev = new StorageCloseAttemptEvent(); var ev = new StorageCloseAttemptEvent();
RaiseLocalEvent(target, ev, silent); RaiseLocalEvent(target, ref ev, silent);
return !ev.Cancelled; return !ev.Cancelled;
} }
@@ -347,7 +351,7 @@ public sealed class EntityStorageSystem : EntitySystem
// 6. if this is an item, then mobs must only be eaten if some other component prevents // 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) // pick-up interactions while a mob is inside (e.g. foldable)
var attemptEvent = new InsertIntoEntityStorageAttemptEvent(); var attemptEvent = new InsertIntoEntityStorageAttemptEvent();
RaiseLocalEvent(toInsert, attemptEvent); RaiseLocalEvent(toInsert, ref attemptEvent);
if (attemptEvent.Cancelled) if (attemptEvent.Cancelled)
return false; return false;
@@ -367,7 +371,7 @@ public sealed class EntityStorageSystem : EntitySystem
else else
{ {
var storeEv = new StoreMobInItemContainerAttemptEvent(); var storeEv = new StoreMobInItemContainerAttemptEvent();
RaiseLocalEvent(container, storeEv); RaiseLocalEvent(container, ref storeEv);
allowedToEat = storeEv.Handled && !storeEv.Cancelled; allowedToEat = storeEv.Handled && !storeEv.Cancelled;
} }
} }

View File

@@ -31,6 +31,7 @@ using Content.Shared.ActionBlocker;
using Content.Shared.CombatMode; using Content.Shared.CombatMode;
using Content.Shared.Containers.ItemSlots; using Content.Shared.Containers.ItemSlots;
using Content.Shared.Implants.Components; using Content.Shared.Implants.Components;
using Content.Shared.Lock;
using Content.Shared.Movement.Events; using Content.Shared.Movement.Events;
namespace Content.Server.Storage.EntitySystems namespace Content.Server.Storage.EntitySystems

View File

@@ -0,0 +1,57 @@
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);

View File

@@ -0,0 +1,243 @@
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;
}
}

View File

@@ -0,0 +1,25 @@
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;