Skip to content

Commit

Permalink
Add AutoPatch Harmony attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
MrBlue committed Apr 28, 2024
1 parent 9e6f3d9 commit cd53384
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/Oxide.Core.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<Import Project="..\netfx.props" />
Expand All @@ -17,6 +17,7 @@
<NoWarn>NU1701</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Lib.Harmony" Version="2.3.3" />
<PackageReference Include="Oxide.Common" Version="2.0.21-develop" />
<PackageReference Include="Oxide.References" Version="2.0.*">
<PrivateAssets>contentfiles;analyzers;build</PrivateAssets>
Expand Down
64 changes: 64 additions & 0 deletions src/Plugins/CSPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Reflection;
using Oxide.Pooling;
using HarmonyLib;

namespace Oxide.Core.Plugins
{
Expand All @@ -27,6 +28,17 @@ public HookMethodAttribute(string name)
}
}

/// <summary>
/// Indicates that the specified class should automatically apply it's harmony patches
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class AutoPatchAttribute : Attribute
{
public AutoPatchAttribute()
{
}
}

/// <summary>
/// Represents a plugin implemented in .NET
/// </summary>
Expand All @@ -42,6 +54,22 @@ public abstract class CSPlugin : Plugin
// All hooked methods
protected Dictionary<string, List<HookMethod>> Hooks = new Dictionary<string, List<HookMethod>>();

// Harmony
private Harmony _harmonyInstance;
protected string HarmonyId => $"com.oxidemod.{Name}";
protected Harmony HarmonyInstance
{
get
{
if (_harmonyInstance == null)
{
_harmonyInstance = new Harmony(HarmonyId);
}

return _harmonyInstance;
}
}

// All matched hooked methods
protected HookCache HooksCache = new HookCache();

Expand Down Expand Up @@ -97,6 +125,29 @@ public override void HandleAddedToManager(PluginManager manager)
Subscribe(hookname);
}

// Find all classes with the AutoPatch attribute and apply the patches
foreach (Type nestedType in GetType().GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static))
{
object[] attr = nestedType.GetCustomAttributes(typeof(AutoPatchAttribute), false);
if (attr.Length < 1)
{
continue;
}

List<MethodInfo> harmonyMethods = HarmonyInstance.CreateClassProcessor(nestedType)?.Patch();

if (harmonyMethods == null || harmonyMethods.Count == 0)
{
Interface.Oxide.LogWarning($"[{Title}] AutoPatch attribute found on '{nestedType.Name}' but no HarmonyPatch methods found. Skipping.");
continue;
}

foreach (MethodInfo method in harmonyMethods)
{
Interface.Oxide.LogInfo($"[{Title}] Automatically Harmony patched '{method.Name}' method. ({nestedType.Name})");
}
}

try
{
// Let the plugin know that it is loading
Expand All @@ -112,6 +163,19 @@ public override void HandleAddedToManager(PluginManager manager)
}
}

/// <summary>
/// Called when this plugin has been removed from a manager
/// </summary>
/// <param name="manager"></param>
public override void HandleRemovedFromManager(PluginManager manager)
{
// Unpatch all automatically patched Harmony patches
_harmonyInstance?.UnpatchAll(HarmonyId);

// Let base work
base.HandleRemovedFromManager(manager);
}

protected void AddHookMethod(string name, MethodInfo method)
{
if (!Hooks.TryGetValue(name, out List<HookMethod> hookMethods))
Expand Down

0 comments on commit cd53384

Please sign in to comment.