From 04647d93c481cb7142ccf129a473309fd0a9631f Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Thu, 25 Dec 2025 21:46:19 +0100
Subject: [PATCH 1/9] fix: FixEffectOrder
---
.../Patches/Fixes/FixEffectOrder.cs | 52 +++++++++++++++++++
1 file changed, 52 insertions(+)
create mode 100644 EXILED/Exiled.Events/Patches/Fixes/FixEffectOrder.cs
diff --git a/EXILED/Exiled.Events/Patches/Fixes/FixEffectOrder.cs b/EXILED/Exiled.Events/Patches/Fixes/FixEffectOrder.cs
new file mode 100644
index 000000000..e3917aa1a
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Fixes/FixEffectOrder.cs
@@ -0,0 +1,52 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) ExMod Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Fixes
+{
+ using System.Collections.Generic;
+ using System.Reflection.Emit;
+
+ using API.Features.Pools;
+ using CustomPlayerEffects;
+ using Exiled.API.Features;
+ using HarmonyLib;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches delegate.
+ /// Fix than NW do not updated the EffectDuration before Intensity https://github.com/northwood-studios/LabAPI/issues/248.
+ ///
+ [HarmonyPatch(typeof(StatusEffectBase), nameof(StatusEffectBase.ServerSetState))]
+ internal class FixEffectOrder
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ // Find the setter call index
+ int intensityCallIndex = newInstructions.FindIndex(ci => ci.Calls(PropertySetter(typeof(StatusEffectBase), nameof(StatusEffectBase.Intensity))));
+
+ // Extract: ldarg.0, ldarg.1, call set_Intensity
+ List intensityBlock = newInstructions.GetRange(intensityCallIndex - 2, 3);
+
+ // Remove it from original location
+ newInstructions.RemoveRange(intensityCallIndex - 2, 3);
+
+ // Find ServerChangeDuration call
+ int serverChangeIndex = newInstructions.FindIndex(ci => ci.Calls(Method(typeof(StatusEffectBase), nameof(StatusEffectBase.ServerChangeDuration))));
+
+ // Insert AFTER ServerChangeDuration
+ newInstructions.InsertRange(serverChangeIndex + 1, intensityBlock);
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
From 4eb54a584f383ba4ece082ee700c307f37f89166 Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Sat, 27 Dec 2025 15:31:53 +0100
Subject: [PATCH 2/9] more fix
---
EXILED/Exiled.API/Features/Player.cs | 6 +--
.../Exiled.API/Features/Roles/Scp049Role.cs | 3 +-
.../Patches/Fixes/FixEffectOrder.cs | 51 ++++++++++++++++++-
3 files changed, 52 insertions(+), 8 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index 3a7c05c20..8e4f9e165 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -3564,8 +3564,7 @@ public void ChangeEffectIntensity(byte intensity, float duration = 0)
{
if (ReferenceHub.playerEffectsController.TryGetEffect(out T statusEffect))
{
- statusEffect.Intensity = intensity;
- statusEffect.ServerChangeDuration(duration, true);
+ statusEffect.ServerSetState(intensity, duration, false);
}
}
@@ -3579,8 +3578,7 @@ public void ChangeEffectIntensity(EffectType type, byte intensity, float duratio
{
if (TryGetEffect(type, out StatusEffectBase statusEffect))
{
- statusEffect.Intensity = intensity;
- statusEffect.ServerChangeDuration(duration, false);
+ statusEffect.ServerSetState(intensity, duration, false);
}
}
diff --git a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs
index 1c015e2ff..6283226eb 100644
--- a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs
+++ b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs
@@ -271,8 +271,7 @@ public void Attack(Player player)
else
{
cardiacArrest.SetAttacker(AttackAbility.Owner);
- cardiacArrest.Intensity = 1;
- cardiacArrest.ServerChangeDuration(AttackAbility._statusEffectDuration, false);
+ cardiacArrest.ServerSetState(1, AttackAbility._statusEffectDuration, false);
}
SenseAbility.OnServerHit(AttackAbility._target);
diff --git a/EXILED/Exiled.Events/Patches/Fixes/FixEffectOrder.cs b/EXILED/Exiled.Events/Patches/Fixes/FixEffectOrder.cs
index e3917aa1a..91e850366 100644
--- a/EXILED/Exiled.Events/Patches/Fixes/FixEffectOrder.cs
+++ b/EXILED/Exiled.Events/Patches/Fixes/FixEffectOrder.cs
@@ -8,17 +8,22 @@
namespace Exiled.Events.Patches.Fixes
{
using System.Collections.Generic;
+ using System.Reflection;
using System.Reflection.Emit;
using API.Features.Pools;
using CustomPlayerEffects;
using Exiled.API.Features;
using HarmonyLib;
+ using InventorySystem.Items.Usables.Scp330;
+ using PlayerRoles.PlayableScps.Scp049;
using static HarmonyLib.AccessTools;
+#pragma warning disable SA1402 // File may only contain a single type
+
///
- /// Patches delegate.
+ /// Patches .
/// Fix than NW do not updated the EffectDuration before Intensity https://github.com/northwood-studios/LabAPI/issues/248.
///
[HarmonyPatch(typeof(StatusEffectBase), nameof(StatusEffectBase.ServerSetState))]
@@ -49,4 +54,46 @@ private static IEnumerable Transpiler(IEnumerable.Pool.Return(newInstructions);
}
}
-}
+
+ ///
+ /// Patches Method that should use .
+ /// Fix than NW do not updated the EffectDuration before Intensity https://github.com/northwood-studios/LabAPI/issues/248.
+ ///
+ [HarmonyPatch]
+ internal class FixEffectOrder2
+ {
+ private static IEnumerable TargetMethods()
+ {
+ yield return Method(typeof(CandyYellow), nameof(CandyYellow.ServerApplyEffects));
+ yield return Method(typeof(Scp049AttackAbility), nameof(Scp049AttackAbility.ServerProcessCmd));
+ yield return Method(typeof(SugarCrave), nameof(SugarCrave.Disabled));
+ }
+
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ int intensityCallIndex = newInstructions.FindIndex(ci => ci.Calls(PropertySetter(typeof(StatusEffectBase), nameof(StatusEffectBase.Intensity))));
+
+ int offset = 6;
+ if (newInstructions[intensityCallIndex - offset].opcode == OpCodes.Dup)
+ {
+ // specific to Yellow candy that get it's Instance from a OpCodes.Dup
+ newInstructions.RemoveAt(intensityCallIndex);
+ newInstructions.RemoveAt(intensityCallIndex - offset);
+ }
+ else
+ {
+ newInstructions.RemoveRange(intensityCallIndex, 2);
+ }
+
+ int serverChangeIndex = newInstructions.FindIndex(ci => ci.Calls(Method(typeof(StatusEffectBase), nameof(StatusEffectBase.ServerChangeDuration))));
+
+ newInstructions[serverChangeIndex] = new CodeInstruction(OpCodes.Callvirt, Method(typeof(StatusEffectBase), nameof(StatusEffectBase.ServerSetState)));
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
\ No newline at end of file
From 5165f58324d96d17957b148ebb1c0bfc991caefd Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Sat, 27 Dec 2025 16:10:17 +0100
Subject: [PATCH 3/9] ReceivingEffectEventArgs::Intensity
---
.../EventArgs/Player/ReceivingEffectEventArgs.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs
index 168a0f578..fe4574f28 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs
@@ -34,7 +34,7 @@ public ReceivingEffectEventArgs(Player player, StatusEffectBase effect, byte int
Effect = effect;
this.intensity = intensity;
CurrentIntensity = currentIntensity;
- Duration = duration;
+ Duration = intensity is 0 ? 0 : duration;
}
///
@@ -63,7 +63,7 @@ public byte Intensity
{
intensity = value;
- if (intensity == 0)
+ if (value == 0 && intensity != 0)
IsAllowed = false;
}
}
From 4e023680d21d33d3612456a4bc4e7a7a6cea8181 Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Sat, 27 Dec 2025 16:10:53 +0100
Subject: [PATCH 4/9] change Duration to TimeLeft the real Duration of the
Effect
---
.../Patches/Events/Player/ReceivingStatusEffect.cs | 12 ++++++------
EXILED/Exiled.Events/Patches/Fixes/FixEffectOrder.cs | 11 ++++++++---
2 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/ReceivingStatusEffect.cs b/EXILED/Exiled.Events/Patches/Events/Player/ReceivingStatusEffect.cs
index 9d22a80b6..707743a24 100644
--- a/EXILED/Exiled.Events/Patches/Events/Player/ReceivingStatusEffect.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Player/ReceivingStatusEffect.cs
@@ -23,9 +23,9 @@ namespace Exiled.Events.Patches.Events.Player
///
/// Patches the method.
- /// Adds the event.
+ /// Adds the event and fix NW Duration not being correctly set to 0 when effect is Reset.
///
- [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.ReceivingEffect))]
+ // [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.ReceivingEffect))]
[HarmonyPatch(typeof(StatusEffectBase), nameof(StatusEffectBase.ForceIntensity))]
internal static class ReceivingStatusEffect
{
@@ -74,9 +74,9 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions);
// Find the setter call index
- int intensityCallIndex = newInstructions.FindIndex(ci => ci.Calls(PropertySetter(typeof(StatusEffectBase), nameof(StatusEffectBase.Intensity))));
+ int offset = -2;
+ int intensityCallIndex = newInstructions.FindIndex(ci => ci.Calls(PropertySetter(typeof(StatusEffectBase), nameof(StatusEffectBase.Intensity)))) + offset;
// Extract: ldarg.0, ldarg.1, call set_Intensity
- List intensityBlock = newInstructions.GetRange(intensityCallIndex - 2, 3);
+ List intensityBlock = newInstructions.GetRange(intensityCallIndex, 3);
// Remove it from original location
- newInstructions.RemoveRange(intensityCallIndex - 2, 3);
+ newInstructions.RemoveRange(intensityCallIndex, 3);
+ newInstructions[intensityCallIndex].WithLabels(intensityBlock[0].ExtractLabels());
// Find ServerChangeDuration call
int serverChangeIndex = newInstructions.FindIndex(ci => ci.Calls(Method(typeof(StatusEffectBase), nameof(StatusEffectBase.ServerChangeDuration))));
@@ -49,7 +51,10 @@ private static IEnumerable Transpiler(IEnumerable.Pool.Return(newInstructions);
}
From 0b393e6af364af24102eac9485e2c56a69579cd4 Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Sat, 27 Dec 2025 16:34:14 +0100
Subject: [PATCH 5/9] Remove Debug line
---
EXILED/Exiled.Events/Patches/Fixes/FixEffectOrder.cs | 3 ---
1 file changed, 3 deletions(-)
diff --git a/EXILED/Exiled.Events/Patches/Fixes/FixEffectOrder.cs b/EXILED/Exiled.Events/Patches/Fixes/FixEffectOrder.cs
index 9a596e82a..6ea4a5ac0 100644
--- a/EXILED/Exiled.Events/Patches/Fixes/FixEffectOrder.cs
+++ b/EXILED/Exiled.Events/Patches/Fixes/FixEffectOrder.cs
@@ -51,10 +51,7 @@ private static IEnumerable Transpiler(IEnumerable.Pool.Return(newInstructions);
}
From e201aea1e2cb2b7e4f230dc3c0d313ca7032d5e2 Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Sat, 27 Dec 2025 16:44:26 +0100
Subject: [PATCH 6/9] fix: use TimeLeft for Duration
---
EXILED/Exiled.API/Features/Effect.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/EXILED/Exiled.API/Features/Effect.cs b/EXILED/Exiled.API/Features/Effect.cs
index f90196691..426b68dcd 100644
--- a/EXILED/Exiled.API/Features/Effect.cs
+++ b/EXILED/Exiled.API/Features/Effect.cs
@@ -35,7 +35,7 @@ public Effect(StatusEffectBase statusEffectBase)
if (!statusEffectBase.TryGetEffectType(out EffectType effect))
Log.Error($"EffectType not found please report to Exiled BugReport : {statusEffectBase}");
Type = effect;
- Duration = statusEffectBase.Duration;
+ Duration = statusEffectBase.TimeLeft;
Intensity = statusEffectBase.Intensity;
IsEnabled = statusEffectBase.IsEnabled;
}
From 53be605e1eeef6dad178c20556db1a54e9fe1837 Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Sat, 27 Dec 2025 16:44:48 +0100
Subject: [PATCH 7/9] better method for it
---
EXILED/Exiled.API/Features/Player.cs | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index 8e4f9e165..6874edb59 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -3433,10 +3433,7 @@ public void SyncEffect(Effect effect)
{
if (effect.IsEnabled)
{
- EnableEffect(effect.Type, effect.Duration, effect.AddDurationIfActive);
-
- if (effect.Intensity > 0)
- ChangeEffectIntensity(effect.Type, effect.Intensity, effect.Duration);
+ EnableEffect(effect.Type, effect.Intensity, effect.Duration, effect.AddDurationIfActive);
}
}
From 6e4eb8a3d475a3b8dbf0aa05c806f9def48f8ed9 Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Sat, 27 Dec 2025 17:26:08 +0100
Subject: [PATCH 8/9] Trying this option
---
.../EventArgs/Player/ReceivingEffectEventArgs.cs | 16 ++--------------
1 file changed, 2 insertions(+), 14 deletions(-)
diff --git a/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs
index fe4574f28..ba8e4fa37 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs
@@ -18,8 +18,6 @@ namespace Exiled.Events.EventArgs.Player
///
public class ReceivingEffectEventArgs : IPlayerEvent, IDeniableEvent
{
- private byte intensity;
-
///
/// Initializes a new instance of the class.
///
@@ -32,7 +30,7 @@ public ReceivingEffectEventArgs(Player player, StatusEffectBase effect, byte int
{
Player = player;
Effect = effect;
- this.intensity = intensity;
+ Intensity = intensity;
CurrentIntensity = currentIntensity;
Duration = intensity is 0 ? 0 : duration;
}
@@ -56,17 +54,7 @@ public ReceivingEffectEventArgs(Player player, StatusEffectBase effect, byte int
/// Gets or sets the value of the new intensity of the effect. Setting this to 0 is the same as setting IsAllowed to
/// .
///
- public byte Intensity
- {
- get => intensity;
- set
- {
- intensity = value;
-
- if (value == 0 && intensity != 0)
- IsAllowed = false;
- }
- }
+ public byte Intensity { get; set; }
///
/// Gets the value of the intensity of this effect on the player.
From 18d1ec577a6c3f324128afadb87adc5bc9a3f8e4 Mon Sep 17 00:00:00 2001
From: Yamato <66829532+louis1706@users.noreply.github.com>
Date: Sat, 27 Dec 2025 17:59:26 +0100
Subject: [PATCH 9/9] doc: updated
---
.../Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs
index ba8e4fa37..038a3e16c 100644
--- a/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs
+++ b/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs
@@ -51,8 +51,7 @@ public ReceivingEffectEventArgs(Player player, StatusEffectBase effect, byte int
public float Duration { get; set; } = 0;
///
- /// Gets or sets the value of the new intensity of the effect. Setting this to 0 is the same as setting IsAllowed to
- /// .
+ /// Gets or sets the value of the new intensity of the effect.
///
public byte Intensity { get; set; }