From 825b045f7288adf9b303c960463b6b4d8d4cb50d Mon Sep 17 00:00:00 2001
From: GoldenPig1205 <78902671+GoldenPig1205@users.noreply.github.com>
Date: Sun, 15 Jun 2025 15:26:23 +0900
Subject: [PATCH 1/6] Add Exiled.API.Features.Workstation
---
EXILED/Exiled.API/Features/Workstation.cs | 158 ++++++++++++++++++
.../Patches/Generic/WorkstationListAdd.cs | 39 +++++
2 files changed, 197 insertions(+)
create mode 100644 EXILED/Exiled.API/Features/Workstation.cs
create mode 100644 EXILED/Exiled.Events/Patches/Generic/WorkstationListAdd.cs
diff --git a/EXILED/Exiled.API/Features/Workstation.cs b/EXILED/Exiled.API/Features/Workstation.cs
new file mode 100644
index 0000000000..e8ee24c64c
--- /dev/null
+++ b/EXILED/Exiled.API/Features/Workstation.cs
@@ -0,0 +1,158 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) ExMod Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.API.Features
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Linq;
+
+ using Exiled.API.Enums;
+ using Exiled.API.Interfaces;
+ using Interactables.Interobjects.DoorUtils;
+ using Interactables.Interobjects;
+ using InventorySystem.Items.Firearms.Attachments;
+ using LabApi.Features.Wrappers;
+ using UnityEngine;
+
+ ///
+ /// A wrapper class for .
+ ///
+ public class Workstation : IWrapper, IWorldSpace
+ {
+ ///
+ /// A dictionary mapping to .
+ ///
+ internal static readonly Dictionary WorkstationControllerToWorkstation = new(new ComponentsEqualityComparer());
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to wrap.
+ internal Workstation(WorkstationController workstationController)
+ {
+ WorkstationControllerToWorkstation.Add(workstationController, this);
+ Base = workstationController;
+ }
+
+ ///
+ /// Gets a read-only collection of all instances.
+ ///
+ public static IReadOnlyCollection List => WorkstationControllerToWorkstation.Values;
+
+ ///
+ /// Gets the underlying instance.
+ ///
+ public WorkstationController Base { get; }
+
+ ///
+ /// Gets the of the workstation.
+ ///
+ public GameObject GameObject => Base.gameObject;
+
+ ///
+ /// Gets the of the workstation.
+ ///
+ public Transform Transform => Base.transform;
+
+ ///
+ /// Gets the the workstation is located in.
+ ///
+ public Room Room => Room.Get(Transform.position);
+
+ ///
+ /// Gets the of the workstation's room.
+ ///
+ public ZoneType Zone => Room.Zone;
+
+ ///
+ /// Gets or sets the position of the workstation.
+ ///
+ public Vector3 Position
+ {
+ get => Base.transform.position;
+ set => Base.transform.position = value;
+ }
+
+ ///
+ /// Gets or sets the rotation of the workstation.
+ ///
+ public Quaternion Rotation
+ {
+ get => Base.transform.rotation;
+ set => Base.transform.rotation = value;
+ }
+
+ ///
+ /// Gets or sets the status of the workstation.
+ ///
+ public WorkstationController.WorkstationStatus Status
+ {
+ get => (WorkstationController.WorkstationStatus)Base.Status;
+ set => Base.NetworkStatus = (byte)value;
+ }
+
+ ///
+ /// Gets the used by the workstation.
+ ///
+ public Stopwatch Stopwatch => Base.ServerStopwatch;
+
+ ///
+ /// Gets or sets the player known to be using the workstation.
+ ///
+ public Player KnownUser
+ {
+ get => Player.Get(Base.KnownUser);
+ set => Base.KnownUser = value.ReferenceHub;
+ }
+
+ ///
+ /// Gets all instances that match the specified predicate.
+ ///
+ /// The predicate to filter workstations.
+ /// An of matching workstations.
+ public static IEnumerable Get(Func predicate) => List.Where(predicate);
+
+ ///
+ /// Tries to get all instances that match the specified predicate.
+ ///
+ /// The predicate to filter workstations.
+ /// The matching workstations, if any.
+ /// true if any workstations were found; otherwise, false.
+ public static bool TryGet(Func predicate, out IEnumerable workstations)
+ {
+ workstations = Get(predicate);
+ return workstations.Any();
+ }
+
+ ///
+ /// Determines whether the specified player is in range of the workstation.
+ ///
+ /// The player to check.
+ /// true if the player is in range; otherwise, false.
+ public bool IsInRange(Player player)
+ {
+ return Base.IsInRange(player.ReferenceHub);
+ }
+
+ ///
+ /// Interacts with the workstation as the specified player.
+ ///
+ /// The player to interact as.
+ public void Interact(Player player)
+ {
+ Base.ServerInteract(player.ReferenceHub, Base.ActivateCollider.ColliderId);
+ }
+
+ ///
+ /// Returns the Room in a human-readable format.
+ ///
+ /// A string containing Workstation-related data.
+ public override string ToString() => $"{GameObject.name} ({Zone}) [{Room}]";
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/Patches/Generic/WorkstationListAdd.cs b/EXILED/Exiled.Events/Patches/Generic/WorkstationListAdd.cs
new file mode 100644
index 0000000000..36bb0029e1
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Generic/WorkstationListAdd.cs
@@ -0,0 +1,39 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) ExMod Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Generic
+{
+#pragma warning disable SA1313
+#pragma warning disable SA1402
+
+ using HarmonyLib;
+ using InventorySystem.Items.Firearms.Attachments;
+
+ ///
+ /// Patch for adding to list.
+ ///
+ [HarmonyPatch(typeof(WorkstationController), nameof(WorkstationController.Start))]
+ internal class WorkstationListAdd
+ {
+ private static void Postfix(WorkstationController __instance)
+ {
+ _ = new API.Features.Workstation(__instance);
+ }
+ }
+
+ ///
+ /// Patch for removing to list.
+ ///
+ [HarmonyPatch(typeof(WorkstationController), nameof(WorkstationController.OnDestroy))]
+ internal class WorkstationListRemove
+ {
+ private static void Postfix(WorkstationController __instance)
+ {
+ API.Features.Workstation.WorkstationControllerToWorkstation.Remove(__instance);
+ }
+ }
+}
\ No newline at end of file
From 6cd8ff03a117f300515feafd9850902c274d5ace Mon Sep 17 00:00:00 2001
From: GoldenPig1205 <78902671+GoldenPig1205@users.noreply.github.com>
Date: Sun, 15 Jun 2025 15:32:44 +0900
Subject: [PATCH 2/6] fix
---
EXILED/Exiled.API/Features/Workstation.cs | 3 ---
1 file changed, 3 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Workstation.cs b/EXILED/Exiled.API/Features/Workstation.cs
index e8ee24c64c..af27eb0a4a 100644
--- a/EXILED/Exiled.API/Features/Workstation.cs
+++ b/EXILED/Exiled.API/Features/Workstation.cs
@@ -14,10 +14,7 @@ namespace Exiled.API.Features
using Exiled.API.Enums;
using Exiled.API.Interfaces;
- using Interactables.Interobjects.DoorUtils;
- using Interactables.Interobjects;
using InventorySystem.Items.Firearms.Attachments;
- using LabApi.Features.Wrappers;
using UnityEngine;
///
From e4b77a86c9b6e64b51d4ad503e886beb63e41710 Mon Sep 17 00:00:00 2001
From: GoldenPig1205 <78902671+GoldenPig1205@users.noreply.github.com>
Date: Thu, 19 Jun 2025 17:50:35 +0900
Subject: [PATCH 3/6] Approve the feedback
---
EXILED/Exiled.API/Features/Workstation.cs | 31 +++++++++++++----------
1 file changed, 18 insertions(+), 13 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Workstation.cs b/EXILED/Exiled.API/Features/Workstation.cs
index af27eb0a4a..792c0def08 100644
--- a/EXILED/Exiled.API/Features/Workstation.cs
+++ b/EXILED/Exiled.API/Features/Workstation.cs
@@ -15,6 +15,7 @@ namespace Exiled.API.Features
using Exiled.API.Enums;
using Exiled.API.Interfaces;
using InventorySystem.Items.Firearms.Attachments;
+ using Mirror;
using UnityEngine;
///
@@ -72,8 +73,13 @@ internal Workstation(WorkstationController workstationController)
///
public Vector3 Position
{
- get => Base.transform.position;
- set => Base.transform.position = value;
+ get => GameObject.transform.position;
+ set
+ {
+ NetworkServer.UnSpawn(GameObject);
+ GameObject.transform.position = value;
+ NetworkServer.Spawn(GameObject);
+ }
}
///
@@ -81,8 +87,13 @@ public Vector3 Position
///
public Quaternion Rotation
{
- get => Base.transform.rotation;
- set => Base.transform.rotation = value;
+ get => GameObject.transform.rotation;
+ set
+ {
+ NetworkServer.UnSpawn(GameObject);
+ GameObject.transform.rotation = value;
+ NetworkServer.Spawn(GameObject);
+ }
}
///
@@ -124,7 +135,7 @@ public Player KnownUser
public static bool TryGet(Func predicate, out IEnumerable workstations)
{
workstations = Get(predicate);
- return workstations.Any();
+ return Get(predicate).Any();
}
///
@@ -132,19 +143,13 @@ public static bool TryGet(Func predicate, out IEnumerable
/// The player to check.
/// true if the player is in range; otherwise, false.
- public bool IsInRange(Player player)
- {
- return Base.IsInRange(player.ReferenceHub);
- }
+ public bool IsInRange(Player player) => Base.IsInRange(player.ReferenceHub);
///
/// Interacts with the workstation as the specified player.
///
/// The player to interact as.
- public void Interact(Player player)
- {
- Base.ServerInteract(player.ReferenceHub, Base.ActivateCollider.ColliderId);
- }
+ public void Interact(Player player) => Base.ServerInteract(player.ReferenceHub, Base.ActivateCollider.ColliderId);
///
/// Returns the Room in a human-readable format.
From 7d147b49b91ca3806b8a69bc428da6b9fad02f1e Mon Sep 17 00:00:00 2001
From: GoldenPig1205 <78902671+GoldenPig1205@users.noreply.github.com>
Date: Thu, 19 Jun 2025 17:55:10 +0900
Subject: [PATCH 4/6] omg
---
EXILED/Exiled.API/Features/Workstation.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/EXILED/Exiled.API/Features/Workstation.cs b/EXILED/Exiled.API/Features/Workstation.cs
index 792c0def08..61ee3b2d57 100644
--- a/EXILED/Exiled.API/Features/Workstation.cs
+++ b/EXILED/Exiled.API/Features/Workstation.cs
@@ -135,7 +135,7 @@ public Player KnownUser
public static bool TryGet(Func predicate, out IEnumerable workstations)
{
workstations = Get(predicate);
- return Get(predicate).Any();
+ return workstations.Any();
}
///
From 70d00628e37af77e3a3e28ed4662b0aa66d57c2b Mon Sep 17 00:00:00 2001
From: Yamato
Date: Sat, 5 Jul 2025 18:49:53 +0200
Subject: [PATCH 5/6] fix: Workstation ctor could be called twice
---
EXILED/Exiled.API/Features/Workstation.cs | 7 +++++++
EXILED/Exiled.Events/Patches/Generic/WorkstationListAdd.cs | 2 +-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/EXILED/Exiled.API/Features/Workstation.cs b/EXILED/Exiled.API/Features/Workstation.cs
index 61ee3b2d57..1062027ef8 100644
--- a/EXILED/Exiled.API/Features/Workstation.cs
+++ b/EXILED/Exiled.API/Features/Workstation.cs
@@ -119,6 +119,13 @@ public Player KnownUser
set => Base.KnownUser = value.ReferenceHub;
}
+ ///
+ /// Gets a given a instance.
+ ///
+ /// The instance.
+ /// The instance.
+ public static Workstation Get(WorkstationController workstationController) => WorkstationControllerToWorkstation.TryGetValue(workstationController, out Workstation workstation) ? workstation : new(workstationController);
+
///
/// Gets all instances that match the specified predicate.
///
diff --git a/EXILED/Exiled.Events/Patches/Generic/WorkstationListAdd.cs b/EXILED/Exiled.Events/Patches/Generic/WorkstationListAdd.cs
index 36bb0029e1..544ef5086e 100644
--- a/EXILED/Exiled.Events/Patches/Generic/WorkstationListAdd.cs
+++ b/EXILED/Exiled.Events/Patches/Generic/WorkstationListAdd.cs
@@ -21,7 +21,7 @@ internal class WorkstationListAdd
{
private static void Postfix(WorkstationController __instance)
{
- _ = new API.Features.Workstation(__instance);
+ API.Features.Workstation.Get(__instance);
}
}
From 4d56789caf00dba2aaf4763a3f68aeba635b244a Mon Sep 17 00:00:00 2001
From: Yamato
Date: Sat, 5 Jul 2025 18:51:22 +0200
Subject: [PATCH 6/6] use Transform
---
EXILED/Exiled.API/Features/Workstation.cs | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Workstation.cs b/EXILED/Exiled.API/Features/Workstation.cs
index 1062027ef8..7e7978a7ff 100644
--- a/EXILED/Exiled.API/Features/Workstation.cs
+++ b/EXILED/Exiled.API/Features/Workstation.cs
@@ -61,7 +61,7 @@ internal Workstation(WorkstationController workstationController)
///
/// Gets the the workstation is located in.
///
- public Room Room => Room.Get(Transform.position);
+ public Room Room => Room.Get(Position);
///
/// Gets the of the workstation's room.
@@ -73,11 +73,11 @@ internal Workstation(WorkstationController workstationController)
///
public Vector3 Position
{
- get => GameObject.transform.position;
+ get => Transform.position;
set
{
NetworkServer.UnSpawn(GameObject);
- GameObject.transform.position = value;
+ Transform.position = value;
NetworkServer.Spawn(GameObject);
}
}
@@ -87,11 +87,11 @@ public Vector3 Position
///
public Quaternion Rotation
{
- get => GameObject.transform.rotation;
+ get => Transform.rotation;
set
{
NetworkServer.UnSpawn(GameObject);
- GameObject.transform.rotation = value;
+ Transform.rotation = value;
NetworkServer.Spawn(GameObject);
}
}