From eed998b2d78155725e5937b86e8ecdd4fdf21718 Mon Sep 17 00:00:00 2001 From: MS-crew <100300664+MS-crew@users.noreply.github.com> Date: Mon, 2 Jun 2025 20:14:31 +0300 Subject: [PATCH 1/5] Update Player.cs --- EXILED/Exiled.Events/Handlers/Player.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs index e35df7b044..b0855dd9ad 100644 --- a/EXILED/Exiled.Events/Handlers/Player.cs +++ b/EXILED/Exiled.Events/Handlers/Player.cs @@ -489,6 +489,16 @@ public class Player /// public static Event ChangingSpectatedPlayer { get; set; } = new(); + /// + /// Invoked when a changes rooms. + /// + 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. /// From 08021113e2497109a58474071bcafe32a6922464 Mon Sep 17 00:00:00 2001 From: MS-crew <100300664+MS-crew@users.noreply.github.com> Date: Mon, 2 Jun 2025 20:15:13 +0300 Subject: [PATCH 2/5] Create RoomChangedEventArgs.cs --- .../EventArgs/Player/RoomChangedEventArgs.cs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 EXILED/Exiled.Events/EventArgs/Player/RoomChangedEventArgs.cs diff --git a/EXILED/Exiled.Events/EventArgs/Player/RoomChangedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/RoomChangedEventArgs.cs new file mode 100644 index 0000000000..57f17a3eda --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Player/RoomChangedEventArgs.cs @@ -0,0 +1,44 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- +namespace Exiled.Events.EventArgs.Player +{ + using Exiled.API.Features; + using Exiled.Events.EventArgs.Interfaces; + using MapGeneration; + + /// + /// Contains the information when a player changes rooms. + /// + 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 after the change. + public RoomChangedEventArgs(ReferenceHub player, RoomIdentifier oldRoom, RoomIdentifier newRoom) + { + Player = Player.Get(player); + OldRoom = Room.Get(oldRoom); + NewRoom = Room.Get(newRoom); + } + + /// + public Player Player { get; } + + /// + /// Gets the previous room the player was in. + /// + public Room OldRoom { get; } + + /// + /// Gets the new room the player entered. + /// + public Room NewRoom { get; } + } +} From ec0d36bad089ccf9f28ba2f02c768534d1f7c27b Mon Sep 17 00:00:00 2001 From: MS-crew <100300664+MS-crew@users.noreply.github.com> Date: Mon, 2 Jun 2025 20:15:32 +0300 Subject: [PATCH 3/5] Create ZoneChangedEventArgs.cs --- .../EventArgs/Player/ZoneChangedEventArgs.cs | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 EXILED/Exiled.Events/EventArgs/Player/ZoneChangedEventArgs.cs diff --git a/EXILED/Exiled.Events/EventArgs/Player/ZoneChangedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ZoneChangedEventArgs.cs new file mode 100644 index 0000000000..7d8c0c714d --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Player/ZoneChangedEventArgs.cs @@ -0,0 +1,58 @@ +// ----------------------------------------------------------------------- +// +// 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; + using MapGeneration; + + /// + /// 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. + public ZoneChangedEventArgs(ReferenceHub player, RoomIdentifier oldRoom, RoomIdentifier newRoom) + { + Player = Player.Get(player); + OldRoom = Room.Get(oldRoom); + NewRoom = Room.Get(newRoom); + OldZone = OldRoom.Zone; + NewZone = NewRoom.Zone; + } + + /// + 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; } + } +} From 203b8f9410ee4300fafae47b2517945fe8762bc5 Mon Sep 17 00:00:00 2001 From: MS-crew <100300664+MS-crew@users.noreply.github.com> Date: Mon, 2 Jun 2025 20:16:32 +0300 Subject: [PATCH 4/5] Create ChangedRoomZone.cs --- .../Patches/Events/Player/ChangedRoomZone.cs | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 EXILED/Exiled.Events/Patches/Events/Player/ChangedRoomZone.cs diff --git a/EXILED/Exiled.Events/Patches/Events/Player/ChangedRoomZone.cs b/EXILED/Exiled.Events/Patches/Events/Player/ChangedRoomZone.cs new file mode 100644 index 0000000000..545f52cef7 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Player/ChangedRoomZone.cs @@ -0,0 +1,117 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Player +{ + using System.Collections.Generic; + using System.Reflection.Emit; + + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Player; + using Exiled.Events.Handlers; + using HarmonyLib; + using MapGeneration; + using UnityEngine; + + using static HarmonyLib.AccessTools; + + /// + /// Patches to add the and events. + /// + [EventPatch(typeof(Player), nameof(Player.RoomChanged))] + [EventPatch(typeof(Player), nameof(Player.ZoneChanged))] + [HarmonyPatch(typeof(CurrentRoomPlayerCache), nameof(CurrentRoomPlayerCache.ValidateCache))] + internal class ChangedRoomZone + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label returnLabel = generator.DefineLabel(); + + LocalBuilder oldRoom = generator.DeclareLocal(typeof(RoomIdentifier)); + LocalBuilder newRoom = generator.DeclareLocal(typeof(RoomIdentifier)); + + int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Ldloca_S); + + newInstructions.InsertRange(index, new CodeInstruction[] + { + // oldRoom = this._lastDetected + new(OpCodes.Ldarg_0), + new(OpCodes.Ldfld, Field(typeof(CurrentRoomPlayerCache), nameof(CurrentRoomPlayerCache._lastDetected))), + new(OpCodes.Stloc_S, oldRoom), + }); + + int lastIndex = newInstructions.Count - 1; + + newInstructions[lastIndex].WithLabels(returnLabel); + + newInstructions.InsertRange(lastIndex, new CodeInstruction[] + { + // newRoom = this._lastDetected + new(OpCodes.Ldarg_0), + new(OpCodes.Ldfld, Field(typeof(CurrentRoomPlayerCache), nameof(CurrentRoomPlayerCache._lastDetected))), + new(OpCodes.Dup), + new(OpCodes.Stloc_S, newRoom), + + new(OpCodes.Ldloc_S, oldRoom), + + // if (oldRoom == newRoom) return; + new(OpCodes.Call, Method(typeof(object), nameof(object.Equals), new[] { typeof(object), typeof(object) })), + new(OpCodes.Brtrue_S, returnLabel), + + // ReferenceHub hub = this._roleManager.gameObject.GetComponent(); + new(OpCodes.Ldarg_0), + new(OpCodes.Ldfld, Field(typeof(CurrentRoomPlayerCache), nameof(CurrentRoomPlayerCache._roleManager))), + new(OpCodes.Call, Method(typeof(Component), nameof(Component.GetComponent)).MakeGenericMethod(typeof(ReferenceHub))), + + // oldRoom + new(OpCodes.Ldloc_S, oldRoom), + + // newRoom + new(OpCodes.Ldloc_S, newRoom), + + // Handlers.Player.OnRoomChanged(new RoomChangedEventArgs(hub, oldRoom, newRoom)); + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(RoomChangedEventArgs))[0]), + new(OpCodes.Call, Method(typeof(Player), nameof(Player.OnRoomChanged))), + + // oldRoom.Zone + new(OpCodes.Ldloc_S, oldRoom), + new(OpCodes.Ldfld, Field(typeof(RoomIdentifier), nameof(RoomIdentifier.Zone))), + + // newRoom.Zone + new(OpCodes.Ldloc_S, newRoom), + new(OpCodes.Ldfld, Field(typeof(RoomIdentifier), nameof(RoomIdentifier.Zone))), + + // if (oldRoom.Zone == newRoom.Zone) return; + new(OpCodes.Ceq), + new(OpCodes.Brtrue_S, returnLabel), + + // ReferenceHub hub = this._roleManager.gameObject.GetComponent(); + new(OpCodes.Ldarg_0), + new(OpCodes.Ldfld, Field(typeof(CurrentRoomPlayerCache), nameof(CurrentRoomPlayerCache._roleManager))), + new(OpCodes.Call, Method(typeof(Component), nameof(Component.GetComponent)).MakeGenericMethod(typeof(ReferenceHub))), + + // oldRoom + new(OpCodes.Ldloc_S, oldRoom), + + // newRoom + new(OpCodes.Ldloc_S, newRoom), + + // Handlers.Player.OnZoneChanged(new ZoneChangedEventArgs(hub, oldRoom, newRoom)); + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(ZoneChangedEventArgs))[0]), + new(OpCodes.Call, Method(typeof(Player), nameof(Player.OnZoneChanged))), + }); + + for (int i = 0; i < newInstructions.Count; i++) + yield return newInstructions[i]; + + ListPool.Pool.Return(newInstructions); + } + } +} From 66d41c22369631cbe8ffb340dbe232f454c7773a Mon Sep 17 00:00:00 2001 From: MS-crew <100300664+MS-crew@users.noreply.github.com> Date: Mon, 2 Jun 2025 20:20:36 +0300 Subject: [PATCH 5/5] Update Player.cs --- EXILED/Exiled.Events/Handlers/Player.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs index b0855dd9ad..b0657a2d62 100644 --- a/EXILED/Exiled.Events/Handlers/Player.cs +++ b/EXILED/Exiled.Events/Handlers/Player.cs @@ -809,6 +809,18 @@ public class Player /// The instance. public static void OnRemovedHandcuffs(RemovedHandcuffsEventArgs ev) => RemovedHandcuffs.InvokeSafely(ev); + /// + /// Called when a changes rooms. + /// + /// The instance. + public static void OnRoomChanged(RoomChangedEventArgs ev) => RoomChanged.InvokeSafely(ev); + + /// + /// Called when a changes zones. + /// + /// The instance. + public static void OnZoneChanged(ZoneChangedEventArgs ev) => ZoneChanged.InvokeSafely(ev); + /// /// Called before a escapes. ///