Skip to content

Commit b94f444

Browse files
authored
feat: New Player Changed Room events (#557)
* Create RoomChangedEventArgs.cs * Create ZoneChangedEventArgs.cs * Added Room / Zone Changed handlers * Create ChangedRoomZone.cs * Repeated referencehub references simplified * Simplify * Deleted ZoneChangedEventArgs.cs * Deleted ZoneChanged event handler * Deleted ChangedZone event codes * Update and rename ChangedRoomZone.cs to ChangedRoom.cs * More Comment * More Fast method * Micro Optimization
1 parent 4cf27fe commit b94f444

3 files changed

Lines changed: 146 additions & 0 deletions

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// -----------------------------------------------------------------------
2+
// <copyright file="RoomChangedEventArgs.cs" company="ExMod Team">
3+
// Copyright (c) ExMod Team. All rights reserved.
4+
// Licensed under the CC BY-SA 3.0 license.
5+
// </copyright>
6+
// -----------------------------------------------------------------------
7+
namespace Exiled.Events.EventArgs.Player
8+
{
9+
using Exiled.API.Features;
10+
using Exiled.Events.EventArgs.Interfaces;
11+
using MapGeneration;
12+
13+
/// <summary>
14+
/// Contains the information when a player changes rooms.
15+
/// </summary>
16+
public class RoomChangedEventArgs : IPlayerEvent
17+
{
18+
/// <summary>
19+
/// Initializes a new instance of the <see cref="RoomChangedEventArgs"/> class.
20+
/// </summary>
21+
/// <param name="player">The player whose room has changed.</param>
22+
/// <param name="oldRoom">The room identifier before the change (Can be null on round start).</param>
23+
/// <param name="newRoom">The room identifier after the change.</param>
24+
public RoomChangedEventArgs(ReferenceHub player, RoomIdentifier oldRoom, RoomIdentifier newRoom)
25+
{
26+
Player = Player.Get(player);
27+
OldRoom = Room.Get(oldRoom);
28+
NewRoom = Room.Get(newRoom);
29+
}
30+
31+
/// <inheritdoc/>
32+
public Player Player { get; }
33+
34+
/// <summary>
35+
/// Gets the previous room the player was in.
36+
/// </summary>
37+
public Room OldRoom { get; }
38+
39+
/// <summary>
40+
/// Gets the new room the player entered.
41+
/// </summary>
42+
public Room NewRoom { get; }
43+
}
44+
}

EXILED/Exiled.Events/Handlers/Player.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,11 @@ public class Player
494494
/// </summary>
495495
public static Event<ChangingSpectatedPlayerEventArgs> ChangingSpectatedPlayer { get; set; } = new();
496496

497+
/// <summary>
498+
/// Invoked when a <see cref="API.Features.Player"/> changes rooms.
499+
/// </summary>
500+
public static Event<RoomChangedEventArgs> RoomChanged { get; set; } = new();
501+
497502
/// <summary>
498503
/// Invoked before a <see cref="API.Features.Player"/> toggles the NoClip mode.
499504
/// </summary>
@@ -810,6 +815,12 @@ public class Player
810815
/// <param name="ev">The <see cref="RemovedHandcuffsEventArgs"/> instance.</param>
811816
public static void OnRemovedHandcuffs(RemovedHandcuffsEventArgs ev) => RemovedHandcuffs.InvokeSafely(ev);
812817

818+
/// <summary>
819+
/// Called when a <see cref="API.Features.Player"/> changes rooms.
820+
/// </summary>
821+
/// <param name="ev">The <see cref="RoomChangedEventArgs"/> instance.</param>
822+
public static void OnRoomChanged(RoomChangedEventArgs ev) => RoomChanged.InvokeSafely(ev);
823+
813824
/// <summary>
814825
/// Called before a <see cref="API.Features.Player"/> escapes.
815826
/// </summary>
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// -----------------------------------------------------------------------
2+
// <copyright file="ChangedRoom.cs" company="ExMod Team">
3+
// Copyright (c) ExMod Team. All rights reserved.
4+
// Licensed under the CC BY-SA 3.0 license.
5+
// </copyright>
6+
// -----------------------------------------------------------------------
7+
8+
namespace Exiled.Events.Patches.Events.Player
9+
{
10+
using System.Collections.Generic;
11+
using System.Reflection.Emit;
12+
13+
using Exiled.API.Features.Pools;
14+
using Exiled.Events.Attributes;
15+
using Exiled.Events.EventArgs.Player;
16+
using Exiled.Events.Handlers;
17+
using HarmonyLib;
18+
using MapGeneration;
19+
using UnityEngine;
20+
21+
using static HarmonyLib.AccessTools;
22+
23+
/// <summary>
24+
/// Patches <see cref="CurrentRoomPlayerCache.ValidateCache"/> to add the <see cref="Player.RoomChanged"/> event.
25+
/// </summary>
26+
[EventPatch(typeof(Player), nameof(Player.RoomChanged))]
27+
[HarmonyPatch(typeof(CurrentRoomPlayerCache), nameof(CurrentRoomPlayerCache.ValidateCache))]
28+
internal class ChangedRoom
29+
{
30+
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
31+
{
32+
List<CodeInstruction> newInstructions = ListPool<CodeInstruction>.Pool.Get(instructions);
33+
34+
Label returnLabel = generator.DefineLabel();
35+
36+
LocalBuilder oldRoom = generator.DeclareLocal(typeof(RoomIdentifier));
37+
LocalBuilder newRoom = generator.DeclareLocal(typeof(RoomIdentifier));
38+
39+
int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Ldloca_S);
40+
41+
newInstructions.InsertRange(index, new CodeInstruction[]
42+
{
43+
// RoomIdentifier oldRoom = this._lastDetected
44+
new(OpCodes.Ldarg_0),
45+
new(OpCodes.Ldfld, Field(typeof(CurrentRoomPlayerCache), nameof(CurrentRoomPlayerCache._lastDetected))),
46+
new(OpCodes.Stloc_S, oldRoom),
47+
});
48+
49+
int lastIndex = newInstructions.Count - 1;
50+
51+
newInstructions[lastIndex].WithLabels(returnLabel);
52+
53+
newInstructions.InsertRange(lastIndex, new CodeInstruction[]
54+
{
55+
// newRoom = lastDetected
56+
new(OpCodes.Ldloc_1),
57+
new(OpCodes.Dup),
58+
new(OpCodes.Stloc_S, newRoom),
59+
60+
// oldRoom
61+
new(OpCodes.Ldloc_S, oldRoom),
62+
63+
// if (oldRoom == newRoom) return;
64+
new(OpCodes.Call, Method(typeof(object), nameof(object.ReferenceEquals), new[] { typeof(object), typeof(object) })),
65+
new(OpCodes.Brtrue_S, returnLabel),
66+
67+
// this._roleManager.gameObject.GetComponent<ReferenceHub>();
68+
new(OpCodes.Ldarg_0),
69+
new(OpCodes.Ldfld, Field(typeof(CurrentRoomPlayerCache), nameof(CurrentRoomPlayerCache._roleManager))),
70+
new(OpCodes.Call, Method(typeof(Component), nameof(Component.GetComponent)).MakeGenericMethod(typeof(ReferenceHub))),
71+
72+
// oldRoom
73+
new(OpCodes.Ldloc_S, oldRoom),
74+
75+
// newRoom
76+
new(OpCodes.Ldloc_S, newRoom),
77+
78+
// RoomChangedEventArgs ev = new RoomChangedEventArgs(hub, oldRoom, newRoom);
79+
new(OpCodes.Newobj, GetDeclaredConstructors(typeof(RoomChangedEventArgs))[0]),
80+
81+
// Handlers.Player.OnRoomChanged(ev);
82+
new(OpCodes.Call, Method(typeof(Player), nameof(Player.OnRoomChanged))),
83+
});
84+
85+
for (int i = 0; i < newInstructions.Count; i++)
86+
yield return newInstructions[i];
87+
88+
ListPool<CodeInstruction>.Pool.Return(newInstructions);
89+
}
90+
}
91+
}

0 commit comments

Comments
 (0)