diff --git a/Exiled.Events/EventArgs/Server/RoundStartingEventArgs.cs b/Exiled.Events/EventArgs/Server/RoundStartingEventArgs.cs
new file mode 100644
index 0000000000..9b1d54e457
--- /dev/null
+++ b/Exiled.Events/EventArgs/Server/RoundStartingEventArgs.cs
@@ -0,0 +1,31 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.EventArgs.Server
+{
+ ///
+ /// Contains all information before the start of the round.
+ ///
+ public class RoundStartingEventArgs
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ ///
+ ///
+ public RoundStartingEventArgs(bool isAllowed = true)
+ {
+ IsAllowed = isAllowed;
+ }
+
+ ///
+ /// Gets or sets a value indicating whether the round can start or not.
+ ///
+ public bool IsAllowed { get; set; }
+ }
+}
diff --git a/Exiled.Events/Handlers/Server.cs b/Exiled.Events/Handlers/Server.cs
index 1b3d0481a9..2ee721cdd1 100644
--- a/Exiled.Events/Handlers/Server.cs
+++ b/Exiled.Events/Handlers/Server.cs
@@ -103,6 +103,11 @@ public static class Server
///
public static Event ReloadedPermissions { get; set; } = new();
+ ///
+ /// Invoked before the round starts.
+ ///
+ public static Event RoundStarting { get; set; } = new();
+
///
/// Called before waiting for players.
///
@@ -195,5 +200,11 @@ public static class Server
///
/// The instance.
public static void OnSelectingRespawnTeam(SelectingRespawnTeamEventArgs ev) => SelectingRespawnTeam.InvokeSafely(ev);
+
+ ///
+ /// Called before round started.
+ ///
+ /// The instance.
+ public static void OnRoundStarting(RoundStartingEventArgs ev) => RoundStarting.InvokeSafely(ev);
}
-}
\ No newline at end of file
+}
diff --git a/Exiled.Events/Patches/Events/Server/RoundStarting.cs b/Exiled.Events/Patches/Events/Server/RoundStarting.cs
new file mode 100644
index 0000000000..b064e49b5f
--- /dev/null
+++ b/Exiled.Events/Patches/Events/Server/RoundStarting.cs
@@ -0,0 +1,78 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Events.Server
+{
+ using System.Collections.Generic;
+ using System.Reflection.Emit;
+
+ using API.Features.Pools;
+ using Exiled.Events.Attributes;
+ using Exiled.Events.EventArgs.Server;
+ using Exiled.Events.Handlers;
+
+ using GameCore;
+
+ using HarmonyLib;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patch the .
+ /// Adds the event.
+ ///
+ [EventPatch(typeof(Server), nameof(Server.RoundStarting))]
+ [HarmonyPatch(typeof(RoundStart), nameof(RoundStart.NetworkTimer), MethodType.Setter)]
+ internal static class RoundStarting
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ Label ret = generator.DefineLabel();
+ Label contlabel = generator.DefineLabel();
+
+ newInstructions[newInstructions.Count - 1].labels.Add(ret);
+ LocalBuilder ev = generator.DeclareLocal(typeof(RoundStartingEventArgs));
+
+ newInstructions.InsertRange(
+ 0,
+ new CodeInstruction[]
+ {
+ // Getting a old value
+ new CodeInstruction(OpCodes.Ldarg_1),
+
+ // Getting a new value
+ new CodeInstruction(OpCodes.Ldc_I4, -1),
+
+ // If the value is not equal, jump
+ new CodeInstruction(OpCodes.Bne_Un, contlabel),
+
+ // RoundStartingEventArgs ev = new
+ new CodeInstruction(OpCodes.Newobj, GetDeclaredConstructors(typeof(RoundStartingEventArgs))[0]),
+ new CodeInstruction(OpCodes.Dup),
+ new CodeInstruction(OpCodes.Stloc_S, ev.LocalIndex),
+
+ // Handlers.Server.OnRoundStarting(ev)
+ new CodeInstruction(OpCodes.Call, Method(typeof(Server), nameof(Server.OnRoundStarting))),
+ new CodeInstruction(OpCodes.Ldloc_S, ev.LocalIndex),
+
+ // If isallowed = false
+ new CodeInstruction(OpCodes.Callvirt, PropertyGetter(typeof(RoundStartingEventArgs), nameof(RoundStartingEventArgs.IsAllowed))),
+ new CodeInstruction(OpCodes.Brfalse_S, ret),
+
+ // Empty opcode for jump
+ new CodeInstruction(OpCodes.Nop).WithLabels(contlabel),
+ });
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}