diff --git a/EXILED/Exiled.API/Enums/LockerType.cs b/EXILED/Exiled.API/Enums/LockerType.cs
index d960514ace..6b21f699c7 100644
--- a/EXILED/Exiled.API/Enums/LockerType.cs
+++ b/EXILED/Exiled.API/Enums/LockerType.cs
@@ -8,7 +8,7 @@
namespace Exiled.API.Enums
{
///
- /// Unique identifier for different types of s.
+ /// Unique identifier for different types of s.
///
public enum LockerType
{
diff --git a/EXILED/Exiled.API/Features/Lockers/Chamber.cs b/EXILED/Exiled.API/Features/Lockers/Chamber.cs
new file mode 100644
index 0000000000..c6bae8c8cb
--- /dev/null
+++ b/EXILED/Exiled.API/Features/Lockers/Chamber.cs
@@ -0,0 +1,173 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+namespace Exiled.API.Features.Lockers
+{
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Linq;
+
+ using Exiled.API.Enums;
+ using Exiled.API.Features.Pickups;
+ using Exiled.API.Interfaces;
+ using MapGeneration.Distributors;
+ using UnityEngine;
+
+ ///
+ /// A wrapper for .
+ ///
+ public class Chamber : IWrapper, IWorldSpace
+ {
+ ///
+ /// with and .
+ ///
+ internal static readonly Dictionary Chambers = new();
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// instance.
+ /// where this chamber is located.
+ public Chamber(LockerChamber chamber, Locker locker)
+ {
+ Base = chamber;
+ Locker = locker;
+
+ Chambers.Add(chamber, this);
+ }
+
+ ///
+ /// Gets a of which contains all the instances.
+ ///
+ public static IReadOnlyCollection List => Chambers.Values;
+
+ ///
+ public LockerChamber Base { get; }
+
+ ///
+ /// Gets the where this chamber is located at.
+ ///
+ public Locker Locker { get; }
+
+ ///
+ public Vector3 Position => Base.transform.position;
+
+ ///
+ public Quaternion Rotation => Base.transform.rotation;
+
+ ///
+ /// Gets or sets all pickups that should be spawned when the door is initially opened.
+ ///
+ public IEnumerable ToBeSpawned
+ {
+ get => Base._toBeSpawned.Select(Pickup.Get);
+ set
+ {
+ Base._toBeSpawned.Clear();
+
+ foreach (Pickup pickup in value)
+ Base._toBeSpawned.Add(pickup.Base);
+ }
+ }
+
+ ///
+ /// Gets or sets all spawn points.
+ ///
+ ///
+ /// Used if is set to .
+ ///
+ public IEnumerable Spawnpoints
+ {
+ get => Base._spawnpoints;
+ set => Base._spawnpoints = value.ToArray();
+ }
+
+ ///
+ /// Gets or sets all the acceptable items which can be spawned in this chamber.
+ ///
+ public IEnumerable AcceptableTypes
+ {
+ get => Base.AcceptableItems;
+ set => Base.AcceptableItems = value.ToArray();
+ }
+
+ ///
+ /// Gets or sets required permissions to open this chamber.
+ ///
+ public KeycardPermissions RequiredPermissions
+ {
+ get => (KeycardPermissions)Base.RequiredPermissions;
+ set => Base.RequiredPermissions = (Interactables.Interobjects.DoorUtils.KeycardPermissions)value;
+ }
+
+ ///
+ /// Gets or sets a value indicating whether multiple spawn points should be used.
+ ///
+ ///
+ /// If , will be used over .
+ ///
+ public bool UseMultipleSpawnpoints
+ {
+ get => Base._useMultipleSpawnpoints;
+ set => Base._useMultipleSpawnpoints = value;
+ }
+
+ ///
+ /// Gets or sets a spawn point for the items in the chamber.
+ ///
+ ///
+ /// Used if is set to .
+ ///
+ public Transform Spawnpoint
+ {
+ get => Base._spawnpoint;
+ set => Base._spawnpoint = value;
+ }
+
+ ///
+ /// Gets or sets a value indicating whether or not items should be spawned as soon as they one chamber is opened.
+ ///
+ public bool InitiallySpawn
+ {
+ get => Base._spawnOnFirstChamberOpening;
+ set => Base._spawnOnFirstChamberOpening = value;
+ }
+
+ ///
+ /// Gets or sets the amount of time before a player can interact with the chamber again.
+ ///
+ public float Cooldown
+ {
+ get => Base._targetCooldown;
+ set => Base._targetCooldown = value;
+ }
+
+ ///
+ /// Gets the of current cooldown.
+ ///
+ /// Used in check.
+ public Stopwatch CurrentCooldown => Base._stopwatch;
+
+ ///
+ /// Gets a value indicating whether the chamber is interactable.
+ ///
+ public bool CanInteract => Base.CanInteract;
+
+ ///
+ /// Spawns a specified item from .
+ ///
+ /// from .
+ /// Amount of items that should be spawned.
+ public void SpawnItem(ItemType type, int amount) => Base.SpawnItem(type, amount);
+
+ ///
+ /// Gets the chamber by its .
+ ///
+ /// .
+ /// .
+ internal static Chamber Get(LockerChamber chamber) => Chambers.TryGetValue(chamber, out Chamber chmb) ? chmb : new(chamber, Locker.Get(x => x.Chambers.Any(x => x.Base == chamber)).FirstOrDefault());
+ }
+}
diff --git a/EXILED/Exiled.API/Features/SupplyLocker.cs b/EXILED/Exiled.API/Features/Lockers/Locker.cs
similarity index 50%
rename from EXILED/Exiled.API/Features/SupplyLocker.cs
rename to EXILED/Exiled.API/Features/Lockers/Locker.cs
index b3bdd538ad..15fb2ccaec 100644
--- a/EXILED/Exiled.API/Features/SupplyLocker.cs
+++ b/EXILED/Exiled.API/Features/Lockers/Locker.cs
@@ -1,79 +1,78 @@
// -----------------------------------------------------------------------
-//
+//
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
//
// -----------------------------------------------------------------------
-namespace Exiled.API.Features
+namespace Exiled.API.Features.Lockers
{
using System;
using System.Collections.Generic;
using System.Linq;
- using System.Reflection;
using Exiled.API.Enums;
using Exiled.API.Extensions;
+ using Exiled.API.Features;
+ using Exiled.API.Features.Pickups;
using Exiled.API.Interfaces;
+
using InventorySystem.Items.Pickups;
using MapGeneration.Distributors;
+
using Mirror;
- using PluginAPI.Core.Items;
using UnityEngine;
+ using BaseLocker = MapGeneration.Distributors.Locker;
#nullable enable
///
- /// The in-game SupplyLocker.
+ /// The in-game Locker.
///
- public class SupplyLocker : IWrapper, IWorldSpace
+ public class Locker : IWrapper, IWorldSpace
{
///
- /// A containing all known s and their corresponding .
+ /// A containing all known s and their corresponding .
///
- internal static readonly Dictionary LockerToSupplyLocker = new(250, new ComponentsEqualityComparer());
+ internal static readonly Dictionary BaseToExiledLockers = new();
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
- /// The encapsulated .
- internal SupplyLocker(Locker locker)
+ /// The encapsulated .
+ public Locker(BaseLocker locker)
{
Base = locker;
- LockerToSupplyLocker.Add(locker, this);
+ BaseToExiledLockers.Add(locker, this);
+
+ Chambers = locker.Chambers.Select(x => new Chamber(x, this)).ToList();
Type = locker.GetLockerType();
}
///
- /// Gets a of which contains all the instances.
+ /// Gets a of which contains all the instances.
///
- public static IReadOnlyCollection List => LockerToSupplyLocker.Values;
+ public static IReadOnlyCollection List => BaseToExiledLockers.Values;
- ///
- /// Gets the instance of the supply locker.
- ///
- public Locker Base { get; }
+ ///
+ public BaseLocker Base { get; }
///
- /// Gets the of the .
+ /// Gets the of the .
///
public LockerType Type { get; }
///
- /// Gets the .
+ /// Gets the .
///
public Transform Transform => Base.transform;
- ///
- /// Gets the position.
- ///
+ ///
public Vector3 Position => Base.transform.position;
- ///
- /// Gets the rotation.
- ///
+ ///
public Quaternion Rotation => Base.transform.rotation;
///
- /// Gets the in which the is located.
+ /// Gets the in which the is located.
///
public Room? Room => Room.Get(Position);
@@ -83,14 +82,18 @@ internal SupplyLocker(Locker locker)
public ZoneType Zone => Room?.Zone ?? ZoneType.Unspecified;
///
- /// Gets the 's in this .
+ /// Gets the all in this locker.
///
- public IEnumerable Chambers => Base.Chambers;
+ public IReadOnlyCollection Chambers { get; }
///
- /// Gets the who has been open.
+ /// Gets or sets an id for manipulating opened chambers.
///
- public IEnumerable OpenedChambers => Chambers.Where(c => c.IsOpen).ToArray();
+ public ushort OpenedChambers
+ {
+ get => Base.OpenedChambers;
+ set => Base.NetworkOpenedChambers = value;
+ }
///
/// Gets a random position from one of the .
@@ -99,51 +102,51 @@ public Vector3 RandomChamberPosition
{
get
{
- LockerChamber randomChamber = Chambers.GetRandomValue();
+ Chamber randomChamber = Chambers.GetRandomValue();
// Determine if the chamber uses multiple spawn points and has at least one available spawn point.
- if (randomChamber._useMultipleSpawnpoints && randomChamber._spawnpoints.Length > 0)
+ if (randomChamber.UseMultipleSpawnpoints && randomChamber.Spawnpoints.Count() > 0)
{
// Return the position of a random spawn point within the chamber.
- return randomChamber._spawnpoints.RandomItem().position;
+ return randomChamber.Spawnpoints.GetRandomValue().position;
}
// Return the position of the main spawn point for the chamber.
- return randomChamber._spawnpoint.position;
+ return randomChamber.Spawnpoint.position;
}
}
///
- /// Gets the belonging to the , if any.
+ /// Gets the belonging to the , if any.
///
- /// The to get.
- /// A or if not found.
- public static SupplyLocker? Get(Locker locker) => locker == null ? null :
- LockerToSupplyLocker.TryGetValue(locker, out SupplyLocker supply) ? supply : new SupplyLocker(locker);
+ /// The to get.
+ /// A or if not found.
+ public static Locker? Get(BaseLocker locker) => locker == null ? null :
+ BaseToExiledLockers.TryGetValue(locker, out Locker supply) ? supply : new Locker(locker);
///
- /// Gets a of given the specified .
+ /// Gets a of given the specified .
///
/// The to search for.
- /// The with the given or if not found.
- public static IEnumerable Get(ZoneType zoneType) => Get(room => room.Zone.HasFlag(zoneType));
+ /// The with the given or if not found.
+ public static IEnumerable Get(ZoneType zoneType) => Get(room => room.Zone.HasFlag(zoneType));
///
- /// Gets a of filtered based on a predicate.
+ /// Gets a of filtered based on a predicate.
///
/// The condition to satify.
- /// A of which contains elements that satify the condition.
- public static IEnumerable Get(Func predicate) => List.Where(predicate);
+ /// A of which contains elements that satify the condition.
+ public static IEnumerable Get(Func predicate) => List.Where(predicate);
///
- /// Gets a random based on the specified filters.
+ /// Gets a random based on the specified filters.
///
/// The to filter by. If unspecified, all zones are considered.
/// The to filter by. If unspecified, all locker types are considered.
- /// A random object, or null if no matching locker is found.
- public static SupplyLocker? Random(ZoneType zone = ZoneType.Unspecified, LockerType lockerType = LockerType.Unknow)
+ /// A random object, or null if no matching locker is found.
+ public static Locker? Random(ZoneType zone = ZoneType.Unspecified, LockerType lockerType = LockerType.Unknow)
{
- IEnumerable filteredLockers = List;
+ IEnumerable filteredLockers = List;
if (lockerType != LockerType.Unknow)
filteredLockers = filteredLockers.Where(l => l.Type == lockerType);
@@ -157,19 +160,19 @@ public Vector3 RandomChamberPosition
///
/// Adds an item to a randomly selected locker chamber.
///
- /// The to be added to the locker chamber.
- public void AddItem(ItemPickup item)
+ /// The to be added to the locker chamber.
+ public void AddItem(Pickup item)
{
// Select a random chamber from the available locker chambers.
- LockerChamber chamber = Chambers.GetRandomValue();
+ Chamber chamber = Chambers.GetRandomValue();
// Determine the parent transform where the item will be placed.
- Transform parentTransform = chamber._useMultipleSpawnpoints && chamber._spawnpoints.Length > 0
- ? chamber._spawnpoints.RandomItem()
- : chamber._spawnpoint;
+ Transform parentTransform = chamber.UseMultipleSpawnpoints && chamber.Spawnpoints.Count() > 0
+ ? chamber.Spawnpoints.GetRandomValue()
+ : chamber.Spawnpoint;
// If the chamber is open, immediately set the item's parent and spawn it.
- if (chamber.IsOpen)
+ if (chamber.Base.IsOpen)
{
item.Transform.SetParent(parentTransform);
item.Spawn();
@@ -177,7 +180,7 @@ public void AddItem(ItemPickup item)
else
{
// If the item is already spawned on the network, unspawn it before proceeding.
- if (NetworkServer.spawned.ContainsKey(item.OriginalObject.netId))
+ if (NetworkServer.spawned.ContainsKey(item.Base.netId))
NetworkServer.UnSpawn(item.GameObject);
// Set the item's parent transform.
@@ -187,7 +190,7 @@ public void AddItem(ItemPickup item)
item.IsLocked = true;
// Notify any pickup distributor triggers.
- (item.OriginalObject as IPickupDistributorTrigger)?.OnDistributed();
+ (item.Base as IPickupDistributorTrigger)?.OnDistributed();
// If the item has a Rigidbody component, make it kinematic and reset its position and rotation.
if (item.Rigidbody != null)
@@ -202,36 +205,25 @@ public void AddItem(ItemPickup item)
// If the chamber is configured to spawn items on the first opening, add the item to the list of items to be spawned.
// Otherwise, spawn the item immediately.
- if (chamber._spawnOnFirstChamberOpening)
- chamber._toBeSpawned.Add(item.OriginalObject);
+ if (chamber.InitiallySpawn)
+ chamber.Base._toBeSpawned.Add(item.Base);
else
- ItemDistributor.SpawnPickup(item.OriginalObject);
+ ItemDistributor.SpawnPickup(item.Base);
}
}
///
- /// Spawns an item of the specified to the locker by creating a new .
+ /// Spawns an item of the specified to the locker by creating a new .
///
/// The type of item to be added.
- public void AddItem(ItemType type) => AddItem(ItemPickup.Create(type, default, default));
+ public void AddItem(ItemType type) => AddItem(Pickup.Create(type));
///
- /// Clears the cached lockers in the dictionary that have become invalid.
- /// This method identifies and removes all entries where either the key (a instance)
- /// or the value (a instance) is null, ensuring that only valid references
- /// are kept in the cache.
+ /// Clears the cached lockers in the dictionary.
///
internal static void ClearCache()
{
- List keysToRemove = LockerToSupplyLocker
- .Where(kv => kv.Key == null || kv.Value == null)
- .Select(kv => kv.Key)
- .ToList();
-
- foreach (Locker key in keysToRemove)
- {
- LockerToSupplyLocker.Remove(key);
- }
+ BaseToExiledLockers.Clear();
}
}
}
diff --git a/EXILED/Exiled.API/Features/Map.cs b/EXILED/Exiled.API/Features/Map.cs
index 05e5007a43..13d55fc987 100644
--- a/EXILED/Exiled.API/Features/Map.cs
+++ b/EXILED/Exiled.API/Features/Map.cs
@@ -16,6 +16,7 @@ namespace Exiled.API.Features
using Enums;
using Exiled.API.Extensions;
using Exiled.API.Features.Hazards;
+ using Exiled.API.Features.Lockers;
using Exiled.API.Features.Pickups;
using Exiled.API.Features.Toys;
using global::Hazards;
@@ -79,9 +80,9 @@ DecontaminationController.Singleton.NetworkDecontaminationOverride is Decontamin
public static ReadOnlyCollection PocketDimensionTeleports { get; } = TeleportsValue.AsReadOnly();
///
- /// Gets all objects.
+ /// Gets all objects.
///
- public static ReadOnlyCollection Lockers { get; } = SupplyLocker.LockerToSupplyLocker.Keys.ToList().AsReadOnly();
+ public static ReadOnlyCollection Lockers { get; } = Features.Lockers.Locker.BaseToExiledLockers.Keys.ToList().AsReadOnly();
///
/// Gets all objects.
@@ -207,10 +208,10 @@ public static void ResetLightsColor()
}
///
- /// Gets a random .
+ /// Gets a random .
///
- /// object.
- public static Locker GetRandomLocker() => Lockers.GetRandomValue();
+ /// object.
+ public static MapGeneration.Distributors.Locker GetRandomLocker() => Lockers.GetRandomValue();
///
/// Gets a random .
diff --git a/EXILED/Exiled.API/Features/Spawn/LockerSpawnPoint.cs b/EXILED/Exiled.API/Features/Spawn/LockerSpawnPoint.cs
index 84579e2272..ecc4341279 100644
--- a/EXILED/Exiled.API/Features/Spawn/LockerSpawnPoint.cs
+++ b/EXILED/Exiled.API/Features/Spawn/LockerSpawnPoint.cs
@@ -10,6 +10,7 @@ namespace Exiled.API.Features.Spawn
using System.Linq;
using Exiled.API.Enums;
+ using Exiled.API.Features.Lockers;
using UnityEngine;
using YamlDotNet.Serialization;
@@ -35,7 +36,7 @@ public class LockerSpawnPoint : SpawnPoint
public Vector3 Offset { get; set; } = Vector3.zero;
///
- /// Gets or sets the type of the .
+ /// Gets or sets the type of the .
///
public LockerType Type { get; set; } = LockerType.Unknow;
@@ -56,7 +57,7 @@ public override Vector3 Position
{
get
{
- SupplyLocker foundLocker = SupplyLocker.Random(Zone, Type) ?? throw new NullReferenceException("No locker found in the specified zone.");
+ Locker foundLocker = Locker.Random(Zone, Type) ?? throw new NullReferenceException("No locker found in the specified zone.");
// If UseChamber is true, use a random chamber's position.
if (UseChamber)
diff --git a/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs b/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs
index 1bbcc5ddb4..30ad47c9f0 100644
--- a/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs
+++ b/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs
@@ -18,7 +18,7 @@ namespace Exiled.Events.Handlers.Internal
using Exiled.API.Enums;
using Exiled.API.Extensions;
-
+ using Exiled.API.Features.Lockers;
using InventorySystem.Items.Firearms.Attachments;
using InventorySystem.Items.Firearms.Attachments.Components;
@@ -47,7 +47,7 @@ public static void OnMapGenerated()
{
Map.ClearCache();
PrefabHelper.LoadPrefabs();
- SupplyLocker.ClearCache();
+ Locker.ClearCache();
// TODO: Fix For (https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/377)
PlayerRoles.RoleAssign.HumanSpawner.Handlers[PlayerRoles.Team.ChaosInsurgency] = new PlayerRoles.RoleAssign.OneRoleHumanSpawner(PlayerRoles.RoleTypeId.ChaosConscript);
diff --git a/EXILED/Exiled.Events/Patches/Generic/LockerList.cs b/EXILED/Exiled.Events/Patches/Generic/LockerList.cs
index a4491f5c39..7dadd8817a 100644
--- a/EXILED/Exiled.Events/Patches/Generic/LockerList.cs
+++ b/EXILED/Exiled.Events/Patches/Generic/LockerList.cs
@@ -12,7 +12,7 @@ namespace Exiled.Events.Patches.Generic
using API.Features;
using API.Features.Pools;
-
+ using Exiled.API.Features.Lockers;
using HarmonyLib;
using MapGeneration.Distributors;
@@ -20,22 +20,22 @@ namespace Exiled.Events.Patches.Generic
using static HarmonyLib.AccessTools;
///
- /// Patches .
+ /// Patches .
///
- [HarmonyPatch(typeof(Locker), nameof(Locker.Start))]
+ [HarmonyPatch(typeof(MapGeneration.Distributors.Locker), nameof(MapGeneration.Distributors.Locker.Start))]
internal class LockerList
{
private static IEnumerable Transpiler(IEnumerable codeInstructions)
{
List newInstructions = ListPool.Pool.Get(codeInstructions);
- // new SupplyLocker(this)
+ // new Locker(this)
newInstructions.InsertRange(
0,
new CodeInstruction[]
{
new(OpCodes.Ldarg_0),
- new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SupplyLocker))[0]),
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(API.Features.Lockers.Locker))[0]),
new(OpCodes.Pop),
});