diff --git a/EXILED/Exiled.Events/EventArgs/Player/RoomChangedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/RoomChangedEventArgs.cs
index 57f17a3eda..c640b78217 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/RoomChangedEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/RoomChangedEventArgs.cs
@@ -8,6 +8,7 @@ namespace Exiled.Events.EventArgs.Player
{
using Exiled.API.Features;
using Exiled.Events.EventArgs.Interfaces;
+
using MapGeneration;
///
@@ -19,7 +20,7 @@ public class RoomChangedEventArgs : IPlayerEvent
/// Initializes a new instance of the class.
///
/// The player whose room has changed.
- /// The room identifier before the change (Can be null on round start).
+ /// The room identifier before the change.
/// The room identifier after the change.
public RoomChangedEventArgs(ReferenceHub player, RoomIdentifier oldRoom, RoomIdentifier newRoom)
{
diff --git a/EXILED/Exiled.Events/EventArgs/Player/ZoneChangedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ZoneChangedEventArgs.cs
new file mode 100644
index 0000000000..3e6d998ed9
--- /dev/null
+++ b/EXILED/Exiled.Events/EventArgs/Player/ZoneChangedEventArgs.cs
@@ -0,0 +1,59 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) ExMod Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.EventArgs.Player
+{
+ using Exiled.API.Enums;
+ using Exiled.API.Features;
+ using Exiled.Events.EventArgs.Interfaces;
+
+ ///
+ /// Contains the information when a player changes zones.
+ ///
+ public class ZoneChangedEventArgs : IPlayerEvent
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The player whose zone has changed.
+ /// The previous room the player was in.
+ /// The new room the player entered.
+ /// The previous zone the player was in.
+ /// The new zone the player entered.
+ public ZoneChangedEventArgs(Player player, Room oldRoom, Room newRoom, ZoneType oldZone, ZoneType newZone)
+ {
+ Player = player;
+ OldRoom = oldRoom;
+ NewRoom = newRoom;
+ OldZone = oldZone;
+ NewZone = newZone;
+ }
+
+ ///
+ public Player Player { get; }
+
+ ///
+ /// Gets the previous zone the player was in.
+ ///
+ public ZoneType OldZone { get; }
+
+ ///
+ /// Gets the new zone the player entered.
+ ///
+ public ZoneType NewZone { get; }
+
+ ///
+ /// Gets the previous room the player was in.
+ ///
+ public Room OldRoom { get; }
+
+ ///
+ /// Gets the new room the player entered.
+ ///
+ public Room NewRoom { get; }
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/Features/Event.cs b/EXILED/Exiled.Events/Features/Event.cs
index bbbc638401..7db233c910 100644
--- a/EXILED/Exiled.Events/Features/Event.cs
+++ b/EXILED/Exiled.Events/Features/Event.cs
@@ -45,8 +45,6 @@ private record AsyncRegistration(CustomAsyncEventHandler handler, int priority);
private readonly List innerAsyncEvent = new();
- private bool patched;
-
///
/// Initializes a new instance of the class.
///
@@ -60,6 +58,11 @@ public Event()
///
public static IReadOnlyList List => EventsValue;
+ ///
+ /// Gets a value indicating whether the Harmony patch for this event has been applied.
+ ///
+ public bool Patched { get; private set; } = !Events.Instance.Config.UseDynamicPatching;
+
///
/// Subscribes a to the inner event, and checks patches if dynamic patching is enabled.
///
@@ -124,10 +127,10 @@ public void Subscribe(CustomEventHandler handler, int priority)
{
Log.Assert(Events.Instance is not null, $"{nameof(Events.Instance)} is null, please ensure you have exiled_events enabled!");
- if (Events.Instance.Config.UseDynamicPatching && !patched)
+ if (Events.Instance.Config.UseDynamicPatching && !Patched)
{
Events.Instance.Patcher.Patch(this);
- patched = true;
+ Patched = true;
}
if (handler == null)
@@ -163,10 +166,10 @@ public void Subscribe(CustomAsyncEventHandler handler, int priority)
{
Log.Assert(Events.Instance is not null, $"{nameof(Events.Instance)} is null, please ensure you have exiled_events enabled!");
- if (Events.Instance.Config.UseDynamicPatching && !patched)
+ if (Events.Instance.Config.UseDynamicPatching && !Patched)
{
Events.Instance.Patcher.Patch(this);
- patched = true;
+ Patched = true;
}
if (handler == null)
diff --git a/EXILED/Exiled.Events/Features/Event{T}.cs b/EXILED/Exiled.Events/Features/Event{T}.cs
index 2d6252b91e..847adc883d 100644
--- a/EXILED/Exiled.Events/Features/Event{T}.cs
+++ b/EXILED/Exiled.Events/Features/Event{T}.cs
@@ -50,8 +50,6 @@ private record AsyncRegistration(CustomAsyncEventHandler handler, int priorit
private readonly List innerAsyncEvent = new();
- private bool patched;
-
///
/// Initializes a new instance of the class.
///
@@ -65,6 +63,11 @@ public Event()
///
public static IReadOnlyDictionary> Dictionary => TypeToEvent;
+ ///
+ /// Gets a value indicating whether the Harmony patch for this event has been applied.
+ ///
+ public bool Patched { get; private set; } = !Events.Instance.Config.UseDynamicPatching;
+
///
/// Subscribes a target to the inner event and checks if patching is possible, if dynamic patching is enabled.
///
@@ -129,10 +132,10 @@ public void Subscribe(CustomEventHandler handler, int priority)
{
Log.Assert(Events.Instance is not null, $"{nameof(Events.Instance)} is null, please ensure you have exiled_events enabled!");
- if (Events.Instance.Config.UseDynamicPatching && !patched)
+ if (Events.Instance.Config.UseDynamicPatching && !Patched)
{
Events.Instance.Patcher.Patch(this);
- patched = true;
+ Patched = true;
}
if (handler == null)
@@ -168,10 +171,10 @@ public void Subscribe(CustomAsyncEventHandler handler, int priority)
{
Log.Assert(Events.Instance is not null, $"{nameof(Events.Instance)} is null, please ensure you have exiled_events enabled!");
- if (Events.Instance.Config.UseDynamicPatching && !patched)
+ if (Events.Instance.Config.UseDynamicPatching && !Patched)
{
Events.Instance.Patcher.Patch(this);
- patched = true;
+ Patched = true;
}
if (handler == null)
diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs
index 998b54f813..49dc14f00f 100644
--- a/EXILED/Exiled.Events/Handlers/Player.cs
+++ b/EXILED/Exiled.Events/Handlers/Player.cs
@@ -9,6 +9,9 @@ namespace Exiled.Events.Handlers
{
using System;
+ using Exiled.API.Enums;
+ using Exiled.API.Features;
+
#pragma warning disable IDE0079
#pragma warning disable IDE0060
#pragma warning disable SA1623 // Property summary documentation should match accessors
@@ -16,6 +19,7 @@ namespace Exiled.Events.Handlers
using Exiled.Events.EventArgs.Player;
using Exiled.Events.Features;
+
using LabApi.Events.Arguments.PlayerEvents;
///
@@ -505,6 +509,11 @@ public class Player
///
public static Event RoomChanged { get; set; } = new();
+ ///
+ /// Invoked when a changes zones.
+ ///
+ public static Event ZoneChanged { get; set; } = new();
+
///
/// Invoked before a toggles the NoClip mode.
///
@@ -835,7 +844,25 @@ public class Player
/// Called when a changes rooms.
///
/// The instance.
- public static void OnRoomChanged(RoomChangedEventArgs ev) => RoomChanged.InvokeSafely(ev);
+ public static void OnRoomChanged(RoomChangedEventArgs ev)
+ {
+ RoomChanged.InvokeSafely(ev);
+
+ if (!ZoneChanged.Patched)
+ return;
+
+ ZoneType oldZone = ev.OldRoom?.Zone ?? ZoneType.Unspecified;
+ ZoneType newZone = ev.NewRoom?.Zone ?? ZoneType.Unspecified;
+
+ if (oldZone != newZone)
+ OnZoneChanged(new ZoneChangedEventArgs(ev.Player, ev.OldRoom, ev.NewRoom, oldZone, newZone));
+ }
+
+ ///
+ /// Called when a changes zones.
+ ///
+ /// The instance.
+ public static void OnZoneChanged(ZoneChangedEventArgs ev) => ZoneChanged.InvokeSafely(ev);
///
/// Called before a escapes.
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/ChangedRoom.cs b/EXILED/Exiled.Events/Patches/Events/Player/ChangedRoom.cs
index 376587b14e..071e1c5fe1 100644
--- a/EXILED/Exiled.Events/Patches/Events/Player/ChangedRoom.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Player/ChangedRoom.cs
@@ -25,6 +25,7 @@ namespace Exiled.Events.Patches.Events.Player
/// Patches to add the event.
///
[EventPatch(typeof(Player), nameof(Player.RoomChanged))]
+ [EventPatch(typeof(Player), nameof(Player.ZoneChanged))]
[HarmonyPatch(typeof(CurrentRoomPlayerCache), nameof(CurrentRoomPlayerCache.ValidateCache))]
internal class ChangedRoom
{
@@ -40,7 +41,7 @@ private static IEnumerable Transpiler(IEnumerable