From 3a19c311ec17623eed0fe22d8858e2e076a8b0f0 Mon Sep 17 00:00:00 2001
From: Eve <85962933+obvEve@users.noreply.github.com>
Date: Wed, 16 Sep 2026 11:31:13 +0200
Subject: [PATCH 1/7] Le harmony update
---
SecretAPI.Examples/Patches/ExampleAmmoPatch.cs | 8 +++-----
SecretAPI.Examples/SecretAPI.Examples.csproj | 2 +-
SecretAPI/SecretAPI.csproj | 12 +++++++-----
3 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/SecretAPI.Examples/Patches/ExampleAmmoPatch.cs b/SecretAPI.Examples/Patches/ExampleAmmoPatch.cs
index 46467c6..e119515 100644
--- a/SecretAPI.Examples/Patches/ExampleAmmoPatch.cs
+++ b/SecretAPI.Examples/Patches/ExampleAmmoPatch.cs
@@ -20,15 +20,13 @@ private static void Prefix()
// gets called after the original method is called
// We grab the method params of ammoType and player, the names must be correct
- // ref __result will become a reference to the return value
-#pragma warning disable SA1313
- private static void Postfix(ItemType ammoType, ReferenceHub player, ref ushort __result)
-#pragma warning restore SA1313
+ // ref result will become a reference to the return value
+ private static void Postfix(ItemType ammoType, ReferenceHub player, [HarmonyArgument("__result")] ref ushort result)
{
// make sure we don't modify the max ammo if its not the correct ammo type or the player hasn't been fake synced
if (ammoType != ExampleFakeSyncButton.AmmoFakeSync || !ExampleFakeSyncButton.FakeSyncs.TryGetValue(player, out ushort sync))
return;
- __result = sync;
+ result = sync;
}
}
\ No newline at end of file
diff --git a/SecretAPI.Examples/SecretAPI.Examples.csproj b/SecretAPI.Examples/SecretAPI.Examples.csproj
index 7dbfccb..09de51d 100644
--- a/SecretAPI.Examples/SecretAPI.Examples.csproj
+++ b/SecretAPI.Examples/SecretAPI.Examples.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/SecretAPI/SecretAPI.csproj b/SecretAPI/SecretAPI.csproj
index db3c6ac..c31687d 100644
--- a/SecretAPI/SecretAPI.csproj
+++ b/SecretAPI/SecretAPI.csproj
@@ -4,6 +4,8 @@
net48
latest
true
+ true
+ false
@@ -23,10 +25,7 @@
-
-
+
@@ -40,11 +39,14 @@
-
+
+
+
+
From c6faf191f6d559e50cda7ddacd9d9b14d08dfaf9 Mon Sep 17 00:00:00 2001
From: Eve <85962933+obvEve@users.noreply.github.com>
Date: Wed, 16 Sep 2026 13:43:05 +0200
Subject: [PATCH 2/7] Lib.Harmony.Thin
---
SecretAPI.Examples/SecretAPI.Examples.csproj | 2 +-
SecretAPI/SecretAPI.csproj | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/SecretAPI.Examples/SecretAPI.Examples.csproj b/SecretAPI.Examples/SecretAPI.Examples.csproj
index 09de51d..5248071 100644
--- a/SecretAPI.Examples/SecretAPI.Examples.csproj
+++ b/SecretAPI.Examples/SecretAPI.Examples.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/SecretAPI/SecretAPI.csproj b/SecretAPI/SecretAPI.csproj
index c31687d..b06bcdb 100644
--- a/SecretAPI/SecretAPI.csproj
+++ b/SecretAPI/SecretAPI.csproj
@@ -25,7 +25,7 @@
-
+
From 5ce0662269a0fcecc6ee992e4ebc2d8bf8f409f8 Mon Sep 17 00:00:00 2001
From: Eve <85962933+obvEve@users.noreply.github.com>
Date: Wed, 16 Sep 2026 14:29:26 +0200
Subject: [PATCH 3/7] Obsolete
---
SecretAPI/Attributes/HarmonyPatchCategory.cs | 4 ++--
SecretAPI/Extensions/HarmonyExtensions.cs | 16 ++++++++++------
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/SecretAPI/Attributes/HarmonyPatchCategory.cs b/SecretAPI/Attributes/HarmonyPatchCategory.cs
index 4257803..9de4637 100644
--- a/SecretAPI/Attributes/HarmonyPatchCategory.cs
+++ b/SecretAPI/Attributes/HarmonyPatchCategory.cs
@@ -1,4 +1,4 @@
-namespace SecretAPI.Attributes;
+/*namespace SecretAPI.Attributes;
using System;
using SecretAPI.Extensions;
@@ -22,4 +22,4 @@ public HarmonyPatchCategory(string category)
/// Gets the patch category.
///
public string Category { get; }
-}
\ No newline at end of file
+}*/
\ No newline at end of file
diff --git a/SecretAPI/Extensions/HarmonyExtensions.cs b/SecretAPI/Extensions/HarmonyExtensions.cs
index 1eee37b..d44831f 100644
--- a/SecretAPI/Extensions/HarmonyExtensions.cs
+++ b/SecretAPI/Extensions/HarmonyExtensions.cs
@@ -21,32 +21,36 @@ public static class HarmonyExtensions
///
/// The category to patch.
/// The assembly to find patches in.
+ [Obsolete("Use Harmony::PatchCategory(Assembly, string)")]
public void PatchCategory(string category, Assembly? assembly = null)
{
assembly ??= Assembly.GetCallingAssembly();
+ harmony.PatchCategory(assembly, category);
- assembly.GetTypes().Where(type =>
+ /*assembly.GetTypes().Where(type =>
{
IEnumerable categories = type.GetCustomAttributes();
- return categories.Any(c => c.Category == category);
+ return categories.Any(c => c.info.category == category);
})
- .Do(type => SafePatch(harmony, type));
+ .Do(type => SafePatch(harmony, type));*/
}
///
/// Patches all patches that don't have a .
///
/// The assembly to look for patches.
+ [Obsolete("Use Harmony::PatchAllUncategorized(Assembly)")]
public void PatchAllNoCategory(Assembly? assembly = null)
{
assembly ??= Assembly.GetCallingAssembly();
+ harmony.PatchAllUncategorized(assembly);
- assembly.GetTypes().Where(type =>
+ /*assembly.GetTypes().Where(type =>
{
IEnumerable categories = type.GetCustomAttributes();
return !categories.Any();
})
- .Do(type => SafePatch(harmony, type));
+ .Do(type => SafePatch(harmony, type));*/
}
///
@@ -61,7 +65,7 @@ public void SafePatch(Type type)
}
catch (Exception ex)
{
- Logger.Error($"[HarmonyExtensions] failed to safely patch {harmony.Id} ({type.FullName}): {ex}");
+ Logger.Error($"[HarmonyExtensions] Failed to safely patch {harmony.Id} ({type.FullName}): {ex}");
}
}
}
From 754015ce3048ab32d29a45e9218537f1126a2a9d Mon Sep 17 00:00:00 2001
From: Eve <85962933+obvEve@users.noreply.github.com>
Date: Wed, 16 Sep 2026 16:00:08 +0200
Subject: [PATCH 4/7] Remove publicize
---
SecretAPI.Examples/ExampleEntry.cs | 9 +++++++--
SecretAPI.Examples/SecretAPI.Examples.csproj | 5 +----
SecretAPI/Extensions/CodeMatcherExtensions.cs | 11 ++++-------
SecretAPI/Features/UserSettings/CustomSetting.cs | 3 +--
SecretAPI/SecretAPI.csproj | 2 +-
5 files changed, 14 insertions(+), 16 deletions(-)
diff --git a/SecretAPI.Examples/ExampleEntry.cs b/SecretAPI.Examples/ExampleEntry.cs
index 1839237..5fd53a0 100644
--- a/SecretAPI.Examples/ExampleEntry.cs
+++ b/SecretAPI.Examples/ExampleEntry.cs
@@ -1,10 +1,10 @@
namespace SecretAPI.Examples;
using System;
+using System.Reflection;
using HarmonyLib;
using LabApi.Loader.Features.Plugins;
using SecretAPI.Examples.Settings;
-using SecretAPI.Extensions;
using SecretAPI.Features.UserSettings;
///
@@ -29,11 +29,16 @@ public class ExampleEntry : Plugin
///
public override Version RequiredApiVersion { get; } = new(LabApi.Features.LabApiProperties.CompiledVersion);
+ ///
+ /// Gets the of SecretAPI.Examples.
+ ///
+ internal Assembly Assembly { get; } = typeof(ExampleEntry).Assembly;
+
///
public override void Enable()
{
CustomSetting.Register(new ExampleKeybindSetting(), new ExampleDropdownSetting(), new ExampleButtonSetting(), new ExampleFakeSyncButton());
- harmony.PatchCategory(nameof(ExampleFakeSyncButton));
+ harmony.PatchCategory(Assembly, nameof(ExampleFakeSyncButton));
}
///
diff --git a/SecretAPI.Examples/SecretAPI.Examples.csproj b/SecretAPI.Examples/SecretAPI.Examples.csproj
index 5248071..cce57e4 100644
--- a/SecretAPI.Examples/SecretAPI.Examples.csproj
+++ b/SecretAPI.Examples/SecretAPI.Examples.csproj
@@ -7,10 +7,7 @@
-
-
+
diff --git a/SecretAPI/Extensions/CodeMatcherExtensions.cs b/SecretAPI/Extensions/CodeMatcherExtensions.cs
index 6bfd06a..a2b849e 100644
--- a/SecretAPI/Extensions/CodeMatcherExtensions.cs
+++ b/SecretAPI/Extensions/CodeMatcherExtensions.cs
@@ -25,11 +25,8 @@ public static class CodeMatcherExtensions
/// The of the local to declare.
/// The declared.
/// The current .
- public CodeMatcher DeclareLocal(Type localType, out LocalBuilder localBuilder)
- {
- localBuilder = matcher.generator.DeclareLocal(localType);
- return matcher;
- }
+ [Obsolete("Use CodeMatcher::DeclareLocal(Type, out LocalBuilder)")]
+ public CodeMatcher DeclareLocal(Type localType, out LocalBuilder localBuilder) => matcher.DeclareLocal(localType, out localBuilder);
///
/// Declares a local to be used of a certain .
@@ -39,7 +36,7 @@ public CodeMatcher DeclareLocal(Type localType, out LocalBuilder localBuilder)
/// The current .
public CodeMatcher DeclareLocal(Type localType, out int localIndex)
{
- DeclareLocal(matcher, localType, out LocalBuilder builder);
+ matcher.DeclareLocal(localType, out LocalBuilder builder);
localIndex = builder.LocalIndex;
return matcher;
}
@@ -63,7 +60,7 @@ public CodeMatcher GetFirstLabel(out Label label)
/// The current .
public CodeMatcher GetFirstLabelAt(int position, out Label label)
{
- label = matcher.codes[position].labels.FirstOrDefault();
+ label = matcher.Instructions()[position].labels.FirstOrDefault();
return matcher;
}
}
diff --git a/SecretAPI/Features/UserSettings/CustomSetting.cs b/SecretAPI/Features/UserSettings/CustomSetting.cs
index 5715e44..2b5fc03 100644
--- a/SecretAPI/Features/UserSettings/CustomSetting.cs
+++ b/SecretAPI/Features/UserSettings/CustomSetting.cs
@@ -12,7 +12,6 @@
using LabApi.Features.Wrappers;
using Mirror;
using NorthwoodLib.Pools;
-using SecretAPI.Extensions;
///
/// Wraps .
@@ -23,7 +22,7 @@ public abstract class CustomSetting : ISetting
static CustomSetting()
{
- SecretApi.Harmony.PatchCategory(nameof(CustomSetting), SecretApi.Assembly);
+ SecretApi.Harmony.PatchCategory(SecretApi.Assembly, nameof(CustomSetting));
ServerSpecificSettingsSync.SendOnJoinFilter = null;
ServerSpecificSettingsSync.DefinedSettings ??= []; // fix null ref
diff --git a/SecretAPI/SecretAPI.csproj b/SecretAPI/SecretAPI.csproj
index b06bcdb..1689e92 100644
--- a/SecretAPI/SecretAPI.csproj
+++ b/SecretAPI/SecretAPI.csproj
@@ -25,7 +25,7 @@
-
+
From 28eda5a3f5225fb4373e196dfc84ccb66c072706 Mon Sep 17 00:00:00 2001
From: Eve <85962933+obvEve@users.noreply.github.com>
Date: Wed, 16 Sep 2026 16:19:01 +0200
Subject: [PATCH 5/7] Use: HarmonyArgument
---
.../Features/Settings/SettingsOriginalDefinitionFix.cs | 8 +++-----
.../Patches/Features/Settings/SettingsSyncValidateFix.cs | 8 +++-----
2 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/SecretAPI/Patches/Features/Settings/SettingsOriginalDefinitionFix.cs b/SecretAPI/Patches/Features/Settings/SettingsOriginalDefinitionFix.cs
index c3f0a7f..77cb9aa 100644
--- a/SecretAPI/Patches/Features/Settings/SettingsOriginalDefinitionFix.cs
+++ b/SecretAPI/Patches/Features/Settings/SettingsOriginalDefinitionFix.cs
@@ -12,14 +12,12 @@
[HarmonyPatch(typeof(ServerSpecificSettingBase), nameof(ServerSpecificSettingBase.OriginalDefinition), MethodType.Getter)]
internal static class SettingsOriginalDefinitionFix
{
-#pragma warning disable SA1313 // Parameter '__result' should begin with lower-case letter
- private static void Postfix(ServerSpecificSettingBase __instance, ref ServerSpecificSettingBase __result)
-#pragma warning restore SA1313
+ private static void Postfix([HarmonyArgument("__instance")] ServerSpecificSettingBase instance, [HarmonyArgument("__result")] ref ServerSpecificSettingBase result)
{
// Prevent handling non SecretAPI settings.
- if (__result != null)
+ if (result != null)
return;
- __result = CustomSetting.Get(__instance.GetType(), __instance.SettingId)?.Base ?? null!;
+ result = CustomSetting.Get(instance.GetType(), instance.SettingId)?.Base ?? null!;
}
}
\ No newline at end of file
diff --git a/SecretAPI/Patches/Features/Settings/SettingsSyncValidateFix.cs b/SecretAPI/Patches/Features/Settings/SettingsSyncValidateFix.cs
index 31cb578..51d29b7 100644
--- a/SecretAPI/Patches/Features/Settings/SettingsSyncValidateFix.cs
+++ b/SecretAPI/Patches/Features/Settings/SettingsSyncValidateFix.cs
@@ -12,14 +12,12 @@
[HarmonyPatch(typeof(ServerSpecificSettingsSync), nameof(ServerSpecificSettingsSync.ServerPrevalidateClientResponse))]
internal static class SettingsSyncValidateFix
{
-#pragma warning disable SA1313 // Parameter '__result' should begin with lower-case letter
- private static void Postfix(SSSClientResponse msg, ref bool __result)
-#pragma warning restore SA1313
+ private static void Postfix(SSSClientResponse msg, [HarmonyArgument("__result")] ref bool result)
{
// prevent overriding already validated settings
- if (__result)
+ if (result)
return;
- __result = CustomSetting.Get(msg.SettingType, msg.Id) != null;
+ result = CustomSetting.Get(msg.SettingType, msg.Id) != null;
}
}
\ No newline at end of file
From 9c6e0a7cb21930d1a9d1d6418d9c9f03eb3859c6 Mon Sep 17 00:00:00 2001
From: Eve <85962933+obvEve@users.noreply.github.com>
Date: Thu, 17 Sep 2026 11:51:08 +0200
Subject: [PATCH 6/7] Remove breaking change
---
SecretAPI.Examples/ExampleEntry.cs | 9 ++++++++-
SecretAPI/Attributes/HarmonyPatchCategory.cs | 8 +++++---
SecretAPI/SecretApi.cs | 9 ++++++++-
3 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/SecretAPI.Examples/ExampleEntry.cs b/SecretAPI.Examples/ExampleEntry.cs
index 5fd53a0..58f82bc 100644
--- a/SecretAPI.Examples/ExampleEntry.cs
+++ b/SecretAPI.Examples/ExampleEntry.cs
@@ -1,4 +1,11 @@
-namespace SecretAPI.Examples;
+/*
+ Temp until 4.0
+*/
+#pragma warning disable SA1200
+global using HarmonyPatchCategoryAttribute = HarmonyLib.HarmonyPatchCategory;
+#pragma warning restore SA1200
+
+namespace SecretAPI.Examples;
using System;
using System.Reflection;
diff --git a/SecretAPI/Attributes/HarmonyPatchCategory.cs b/SecretAPI/Attributes/HarmonyPatchCategory.cs
index 9de4637..00026d9 100644
--- a/SecretAPI/Attributes/HarmonyPatchCategory.cs
+++ b/SecretAPI/Attributes/HarmonyPatchCategory.cs
@@ -1,4 +1,4 @@
-/*namespace SecretAPI.Attributes;
+namespace SecretAPI.Attributes;
using System;
using SecretAPI.Extensions;
@@ -7,13 +7,15 @@
/// Category handling for .
///
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
-public class HarmonyPatchCategory : Attribute
+[Obsolete("Please use HarmonyLib.HarmonyPatchCategoryAttribute - This will be removed in 4.0")]
+public class HarmonyPatchCategory : HarmonyLib.HarmonyPatchCategory
{
///
/// Initializes a new instance of the class.
///
/// The category of the patch.
public HarmonyPatchCategory(string category)
+ : base(category)
{
Category = category;
}
@@ -22,4 +24,4 @@ public HarmonyPatchCategory(string category)
/// Gets the patch category.
///
public string Category { get; }
-}*/
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/SecretAPI/SecretApi.cs b/SecretAPI/SecretApi.cs
index 2268034..d1b14a6 100644
--- a/SecretAPI/SecretApi.cs
+++ b/SecretAPI/SecretApi.cs
@@ -1,4 +1,11 @@
-namespace SecretAPI;
+/*
+ Temp until 4.0
+*/
+#pragma warning disable SA1200
+global using HarmonyPatchCategoryAttribute = HarmonyLib.HarmonyPatchCategory;
+#pragma warning restore SA1200
+
+namespace SecretAPI;
using System;
using System.IO;
From a50eb468dc7cdf87741e6cabaafbf3299114ca4e Mon Sep 17 00:00:00 2001
From: Eve <85962933+obvEve@users.noreply.github.com>
Date: Thu, 24 Sep 2026 18:12:10 +0200
Subject: [PATCH 7/7] 3.5.0-beta1 bump
---
.github/README.md | 26 +++++++++++++++++++-------
Directory.Build.props | 2 +-
2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/.github/README.md b/.github/README.md
index d353b21..1f11f0e 100644
--- a/.github/README.md
+++ b/.github/README.md
@@ -1,14 +1,26 @@
# SecretAPI 
* SecretAPI is a plugin that extends [LabAPI](https://github.com/northwood-studios/LabAPI) by providing extra features to help devs.
+# Dependencies
+- SecretAPI relies on Harmony to implement features
+ - You can find the latest version [here](https://github.com/pardeike/Harmony/releases/latest)
+ - You should download Harmony-Fat and put the **0harmony.dll** (found in /net48) into your dependencies folder!
+
# Features
-- CollectionExtensions: Extensions to provide utility for collections like lists and arrays.
-- RoomExtensions: Extensions to help with room specific tasks, like checking if a room is safe to teleport to.
-- HarmonyExtensions: Extensions to provide more utility to Harmony patching, like adding some updated Harmony features which can't be utilised, i.e. patching by category.
-- CustomPlayerEffect: Create custom status effects using the base-game system.
-- IRegister: Handle auto registering certain plugin features inheriting this interface and then running `IRegister.RegisterAll(Assembly)` in your plugin's initialise method.
-- CallOnLoadAttribute: Allows calling static initialize methods on enable via ``CallOnLoadAttribute.Load(Assembly)``
-- CustomSetting: Server Specific Settings without the management hassle, control everything for 1 setting in 1 class, including permissions. A better setting system overall.
+- **CustomPlayerEffect**: Create custom status effects using the base-game system.
+ - BlastResistance: Grants 0.5% resistance to explosion damage
+ - Depleted: Disables stamina and its regen
+ - Energized: Disables stamina usage
+- **IRegister**: Handle auto registering certain plugin features inheriting this interface and then running `IRegister.RegisterAll(Assembly)` in your plugin's initialize method.
+- **CallOnLoadAttribute**: Allows calling static initialize methods on enable via ``CallOnLoadAttribute.Load(Assembly)``
+- **CustomSetting**: Server Specific Settings without the management hassle, control everything for 1 setting in 1 class, including permissions. A better setting system overall.
+- **PrefabStore** and **PrefabManager**: Designed to help access prefabs in a clean way
+- Extensions:
+ - CodeMatcherExtensions: Extensions related to ``HarmonyLib.CodeMatcher``.
+ - CollectionExtensions: Extensions to provide utility for collections like lists and arrays.
+ - MirrorExtensions: Extensions providing help with fake-syncing ``SyncVar``, ``SyncList`` and ``Rpc``
+ - ReflectionExtensions: Extensions related to C# Reflection
+ - RoomExtensions: Extensions to help with room specific tasks, like checking if a room is safe to teleport to.
# Examples
You can find examples inside the `SecretAPI.Examples` folder above, this contains some example settings, patches using categories and some more.
diff --git a/Directory.Build.props b/Directory.Build.props
index 24401c1..52706c7 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,7 +1,7 @@
enable
- 3.4.0
+ 3.5.0-beta1