33using System . Collections . Generic ;
44using System . Reflection ;
55using Oxide . Pooling ;
6+ using HarmonyLib ;
67
78namespace Oxide . Core . Plugins
89{
@@ -27,6 +28,17 @@ public HookMethodAttribute(string name)
2728 }
2829 }
2930
31+ /// <summary>
32+ /// Indicates that the specified class should automatically apply it's harmony patches
33+ /// </summary>
34+ [ AttributeUsage ( AttributeTargets . Class ) ]
35+ public class AutoPatchAttribute : Attribute
36+ {
37+ public AutoPatchAttribute ( )
38+ {
39+ }
40+ }
41+
3042 /// <summary>
3143 /// Represents a plugin implemented in .NET
3244 /// </summary>
@@ -42,6 +54,22 @@ public abstract class CSPlugin : Plugin
4254 // All hooked methods
4355 protected Dictionary < string , List < HookMethod > > Hooks = new Dictionary < string , List < HookMethod > > ( ) ;
4456
57+ // Harmony
58+ private Harmony _harmonyInstance ;
59+ protected string HarmonyId => $ "com.oxidemod.{ Name } ";
60+ protected Harmony HarmonyInstance
61+ {
62+ get
63+ {
64+ if ( _harmonyInstance == null )
65+ {
66+ _harmonyInstance = new Harmony ( HarmonyId ) ;
67+ }
68+
69+ return _harmonyInstance ;
70+ }
71+ }
72+
4573 // All matched hooked methods
4674 protected HookCache HooksCache = new HookCache ( ) ;
4775
@@ -97,6 +125,29 @@ public override void HandleAddedToManager(PluginManager manager)
97125 Subscribe ( hookname ) ;
98126 }
99127
128+ // Find all classes with the AutoPatch attribute and apply the patches
129+ foreach ( Type nestedType in GetType ( ) . GetNestedTypes ( BindingFlags . DeclaredOnly | BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Static ) )
130+ {
131+ object [ ] attr = nestedType . GetCustomAttributes ( typeof ( AutoPatchAttribute ) , false ) ;
132+ if ( attr . Length < 1 )
133+ {
134+ continue ;
135+ }
136+
137+ List < MethodInfo > harmonyMethods = HarmonyInstance . CreateClassProcessor ( nestedType ) ? . Patch ( ) ;
138+
139+ if ( harmonyMethods == null || harmonyMethods . Count == 0 )
140+ {
141+ Interface . Oxide . LogWarning ( $ "[{ Title } ] AutoPatch attribute found on '{ nestedType . Name } ' but no HarmonyPatch methods found. Skipping.") ;
142+ continue ;
143+ }
144+
145+ foreach ( MethodInfo method in harmonyMethods )
146+ {
147+ Interface . Oxide . LogInfo ( $ "[{ Title } ] Automatically Harmony patched '{ method . Name } ' method. ({ nestedType . Name } )") ;
148+ }
149+ }
150+
100151 try
101152 {
102153 // Let the plugin know that it is loading
@@ -112,6 +163,19 @@ public override void HandleAddedToManager(PluginManager manager)
112163 }
113164 }
114165
166+ /// <summary>
167+ /// Called when this plugin has been removed from a manager
168+ /// </summary>
169+ /// <param name="manager"></param>
170+ public override void HandleRemovedFromManager ( PluginManager manager )
171+ {
172+ // Unpatch all automatically patched Harmony patches
173+ _harmonyInstance ? . UnpatchAll ( HarmonyId ) ;
174+
175+ // Let base work
176+ base . HandleRemovedFromManager ( manager ) ;
177+ }
178+
115179 protected void AddHookMethod ( string name , MethodInfo method )
116180 {
117181 if ( ! Hooks . TryGetValue ( name , out List < HookMethod > hookMethods ) )
0 commit comments