diff --git a/EXILED/Exiled.Events/EventArgs/Player/ReceivingVoiceMessageEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ReceivingVoiceMessageEventArgs.cs
new file mode 100644
index 0000000000..4b491f739a
--- /dev/null
+++ b/EXILED/Exiled.Events/EventArgs/Player/ReceivingVoiceMessageEventArgs.cs
@@ -0,0 +1,60 @@
+// -----------------------------------------------------------------------
+//
+// 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 PlayerRoles.Voice;
+ using VoiceChat.Networking;
+
+ ///
+ /// Contains all information before a player receives a voice message.
+ ///
+ public class ReceivingVoiceMessageEventArgs : IPlayerEvent, IDeniableEvent
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The player receiving the voice message.
+ /// The player sending the voice message.
+ /// The senders voice module.
+ /// The voice message being sent.
+ public ReceivingVoiceMessageEventArgs(Player receiver, Player sender, VoiceModuleBase voiceModule, VoiceMessage voiceMessage)
+ {
+ Sender = sender;
+ Player = receiver;
+ VoiceMessage = voiceMessage;
+ VoiceModule = voiceModule;
+ }
+
+ ///
+ /// Gets the player receiving the voice message.
+ ///
+ public Player Player { get; }
+
+ ///
+ /// Gets the player sending the voice message.
+ ///
+ public Player Sender { get; }
+
+ ///
+ /// Gets or sets the 's .
+ ///
+ public VoiceMessage VoiceMessage { get; set; }
+
+ ///
+ /// Gets the 's .
+ ///
+ public VoiceModuleBase VoiceModule { get; }
+
+ ///
+ /// Gets or sets a value indicating whether the player can receive the voice message.
+ ///
+ public bool IsAllowed { get; set; } = true;
+ }
+}
diff --git a/EXILED/Exiled.Events/EventArgs/Player/TransmittingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/TransmittingEventArgs.cs
index 96e1ffde45..6cfbf1106a 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/TransmittingEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/TransmittingEventArgs.cs
@@ -12,6 +12,8 @@ namespace Exiled.Events.EventArgs.Player
using PlayerRoles.Voice;
+ using VoiceChat.Networking;
+
///
/// Contains all information regarding the player using the radio.
///
@@ -23,17 +25,17 @@ public class TransmittingEventArgs : IPlayerEvent, IDeniableEvent
///
///
///
+ ///
+ ///
+ ///
///
///
///
- ///
- ///
- ///
- public TransmittingEventArgs(Player player, VoiceModuleBase voiceModule, bool isAllowed = true)
+ public TransmittingEventArgs(Player player, VoiceMessage voiceMessage, VoiceModuleBase voiceModule)
{
Player = player;
+ VoiceMessage = voiceMessage;
VoiceModule = voiceModule;
- IsAllowed = isAllowed;
}
///
@@ -41,6 +43,11 @@ public TransmittingEventArgs(Player player, VoiceModuleBase voiceModule, bool is
///
public Player Player { get; }
+ ///
+ /// Gets or sets the 's .
+ ///
+ public VoiceMessage VoiceMessage { get; set; }
+
///
/// Gets the 's .
///
@@ -49,6 +56,6 @@ public TransmittingEventArgs(Player player, VoiceModuleBase voiceModule, bool is
///
/// Gets or sets a value indicating whether the player can transmit.
///
- public bool IsAllowed { get; set; }
+ public bool IsAllowed { get; set; } = true;
}
}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/EventArgs/Player/VoiceChattingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/VoiceChattingEventArgs.cs
index c67e7bb72f..5a488c3d2e 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/VoiceChattingEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/VoiceChattingEventArgs.cs
@@ -25,21 +25,17 @@ public class VoiceChattingEventArgs : IPlayerEvent, IDeniableEvent
///
///
///
- ///
- ///
- ///
///
///
///
- ///
- ///
+ ///
+ ///
///
- public VoiceChattingEventArgs(Player player, VoiceMessage voiceMessage, VoiceModuleBase voiceModule, bool isAllowed = true)
+ public VoiceChattingEventArgs(Player player, VoiceModuleBase voiceModule, VoiceMessage voiceMessage)
{
Player = player;
VoiceMessage = voiceMessage;
VoiceModule = voiceModule;
- IsAllowed = isAllowed;
}
///
@@ -60,6 +56,6 @@ public VoiceChattingEventArgs(Player player, VoiceMessage voiceMessage, VoiceMod
///
/// Gets or sets a value indicating whether the player can voicechat.
///
- public bool IsAllowed { get; set; }
+ public bool IsAllowed { get; set; } = true;
}
}
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..90cdb6ba98 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)
@@ -296,4 +299,4 @@ internal void InvokeAsync(T arg)
}
}
}
-}
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs
index 998b54f813..54fd199634 100644
--- a/EXILED/Exiled.Events/Handlers/Player.cs
+++ b/EXILED/Exiled.Events/Handlers/Player.cs
@@ -470,6 +470,11 @@ public class Player
///
public static Event VoiceChatting { get; set; } = new();
+ ///
+ /// Invoked before a receives a voice message.
+ ///
+ public static Event ReceivingVoiceMessage { get; set; } = new();
+
///
/// Invoked before a makes noise.
///
@@ -897,6 +902,9 @@ public class Player
/// The instance.
public static void OnReloadingWeapon(PlayerReloadingWeaponEventArgs ev)
{
+ if (!ReloadingWeapon.Patched)
+ return;
+
ReloadingWeaponEventArgs exiledEv = new(ev.FirearmItem.Base, ev.IsAllowed);
ReloadingWeapon.InvokeSafely(exiledEv);
ev.IsAllowed = exiledEv.IsAllowed;
@@ -1010,6 +1018,9 @@ public static void OnReloadingWeapon(PlayerReloadingWeaponEventArgs ev)
/// The instance.
public static void OnUnloadingWeapon(PlayerUnloadingWeaponEventArgs ev)
{
+ if (!UnloadingWeapon.Patched)
+ return;
+
UnloadingWeaponEventArgs exiledEv = new(ev.FirearmItem.Base, ev.IsAllowed);
UnloadingWeapon.InvokeSafely(exiledEv);
ev.IsAllowed = exiledEv.IsAllowed;
@@ -1045,6 +1056,12 @@ public static void OnUnloadingWeapon(PlayerUnloadingWeaponEventArgs ev)
/// The instance.
public static void OnVoiceChatting(VoiceChattingEventArgs ev) => VoiceChatting.InvokeSafely(ev);
+ ///
+ /// Invoked before a receives a voice message.
+ ///
+ /// The instance.
+ public static void OnReceivingVoiceMessage(ReceivingVoiceMessageEventArgs ev) => ReceivingVoiceMessage.InvokeSafely(ev);
+
///
/// Called before a makes noise.
///
diff --git a/EXILED/Exiled.Events/Handlers/Scp127.cs b/EXILED/Exiled.Events/Handlers/Scp127.cs
index b3f86534d3..bfdb1bcada 100644
--- a/EXILED/Exiled.Events/Handlers/Scp127.cs
+++ b/EXILED/Exiled.Events/Handlers/Scp127.cs
@@ -43,6 +43,9 @@ public static class Scp127
/// The instance.
public static void OnTalking(Scp127TalkingEventArgs ev)
{
+ if (!Talking.Patched)
+ return;
+
TalkingEventArgs eventArgs = new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.VoiceLine, ev.Priority, ev.IsAllowed);
Talking.InvokeSafely(eventArgs);
@@ -64,6 +67,9 @@ public static void OnTalked(Scp127TalkedEventArgs ev)
/// The instance.
public static void OnGainingExperience(Scp127GainingExperienceEventArgs ev)
{
+ if (!GainingExperience.Patched)
+ return;
+
GainingExperienceEventArgs eventArgs = new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.ExperienceGain, ev.IsAllowed);
GainingExperience.InvokeSafely(eventArgs);
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/ReceivingVoiceMessage.cs b/EXILED/Exiled.Events/Patches/Events/Player/ReceivingVoiceMessage.cs
new file mode 100644
index 0000000000..fcefcbbd0d
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Events/Player/ReceivingVoiceMessage.cs
@@ -0,0 +1,100 @@
+// -----------------------------------------------------------------------
+//
+// 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;
+ using System.Reflection.Emit;
+
+ using API.Features.Pools;
+
+ using Exiled.Events.Attributes;
+ using Exiled.Events.EventArgs.Player;
+
+ using HarmonyLib;
+
+ using Mirror;
+
+ using PlayerRoles.Voice;
+
+ using VoiceChat.Networking;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches .
+ /// Adds the event.
+ ///
+ [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.ReceivingVoiceMessage))]
+ [HarmonyPatch(typeof(VoiceTransceiver), nameof(VoiceTransceiver.ServerReceiveMessage))]
+
+ internal static class ReceivingVoiceMessage
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ Label skipHub = generator.DefineLabel();
+ Label skipLabel = generator.DefineLabel();
+
+ LocalBuilder ev = generator.DeclareLocal(typeof(ReceivingVoiceMessageEventArgs));
+
+ int offset = -2;
+ int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Newobj && (ConstructorInfo)i.operand == GetDeclaredConstructors(typeof(LabApi.Events.Arguments.PlayerEvents.PlayerReceivingVoiceMessageEventArgs))[0]) + offset;
+
+ newInstructions[index].labels.Add(skipLabel);
+
+ newInstructions.InsertRange(index, new CodeInstruction[]
+ {
+ // Player.Get(hub);
+ new(OpCodes.Ldloc_S, 4),
+ new(OpCodes.Call, Method(typeof(API.Features.Player), nameof(API.Features.Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // Player.Get(msg.Speaker);
+ new(OpCodes.Ldarg_1),
+ new(OpCodes.Ldfld, Field(typeof(VoiceMessage), nameof(VoiceMessage.Speaker))),
+ new(OpCodes.Call, Method(typeof(API.Features.Player), nameof(API.Features.Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // voiceModule
+ new(OpCodes.Ldloc_0),
+ new(OpCodes.Callvirt, PropertyGetter(typeof(IVoiceRole), nameof(IVoiceRole.VoiceModule))),
+
+ // msg
+ new(OpCodes.Ldarg_1),
+
+ // ReceivingVoiceMessageEventArgs ev = new(Player receiver, Player sender, VoiceModuleBase, VoiceMessage);
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(ReceivingVoiceMessageEventArgs))[0]),
+ new(OpCodes.Dup),
+ new(OpCodes.Dup),
+ new(OpCodes.Stloc_S, ev.LocalIndex),
+
+ // Handlers.Player.OnVoiceChatting(ev);
+ new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnReceivingVoiceMessage))),
+
+ // if (!ev.IsAllowed)
+ // continue;
+ new(OpCodes.Callvirt, PropertyGetter(typeof(ReceivingVoiceMessageEventArgs), nameof(ReceivingVoiceMessageEventArgs.IsAllowed))),
+ new(OpCodes.Brfalse_S, skipHub),
+
+ // msg = ev.VoiceMessage;
+ new(OpCodes.Ldloc_S, ev.LocalIndex),
+ new(OpCodes.Callvirt, PropertyGetter(typeof(ReceivingVoiceMessageEventArgs), nameof(ReceivingVoiceMessageEventArgs.VoiceMessage))),
+ new(OpCodes.Starg_S, 1),
+ });
+
+ offset = 1;
+ index = newInstructions.FindIndex(i => i.opcode == OpCodes.Callvirt && i.operand is MethodInfo mi && mi.Name == nameof(NetworkConnection.Send) && mi.IsGenericMethod) + offset;
+
+ newInstructions[index].labels.Add(skipHub);
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/VoiceChatting.cs b/EXILED/Exiled.Events/Patches/Events/Player/VoiceChatting.cs
index a6d49a70f9..17ba25773c 100644
--- a/EXILED/Exiled.Events/Patches/Events/Player/VoiceChatting.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Player/VoiceChatting.cs
@@ -4,14 +4,14 @@
// Licensed under the CC BY-SA 3.0 license.
//
// -----------------------------------------------------------------------
-
namespace Exiled.Events.Patches.Events.Player
{
using System.Collections.Generic;
+ using System.Reflection;
using System.Reflection.Emit;
using API.Features.Pools;
- using API.Features.Roles;
+
using Exiled.Events.Attributes;
using Exiled.Events.EventArgs.Player;
@@ -41,58 +41,41 @@ private static IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions);
Label retLabel = generator.DefineLabel();
- Label isMutedLabel = generator.DefineLabel();
Label skipLabel = generator.DefineLabel();
- List