You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
CrowdControl/Assets/3rd/Plugins/Smart-Inspector/Patches/Provider/PatchBase.cs

134 lines
3.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Reflection;
using HarmonyLib;
using UnityEditor;
using UnityEngine;
namespace AV.Inspector
{
internal abstract class PatchBase
{
protected static Assembly EditorAssembly { get; } = typeof(Editor).Assembly;
static InspectorPrefs prefs = InspectorPrefs.Loaded;
string prefKey => GetType().FullName;
[Serializable]
internal struct State
{
public bool forceSkip;
}
internal State state
{
get => prefs.patchesTable.Get(prefKey, @default: new State { forceSkip = false });
set => prefs.patchesTable.Set(prefKey, value);
}
public enum Apply
{
OnLoad,
OnGUI
}
protected class Patch
{
public MethodBase original;
public string prefix;
public string postfix;
public string transpiler;
public string finalizer;
public Apply apply;
internal bool applied;
internal MethodInfo harmonyPatch;
public Patch(MethodBase original,
string prefix = null, string postfix = null,
string transpiler = null, string finalizer = null,
Apply apply = Apply.OnLoad)
{
this.original = original;
this.prefix = prefix;
this.postfix = postfix;
this.transpiler = transpiler;
this.finalizer = finalizer;
this.apply = apply;
}
}
internal Harmony harmony;
readonly List<Patch> patches = new List<Patch>();
// ReSharper disable once EmptyConstructor
// ReSharper disable once PublicConstructorInAbstractClass
// default constructor required for activator
public PatchBase() {}
protected abstract IEnumerable<Patch> GetPatches();
public void ApplyPatches(Apply applyType)
{
if (harmony == null)
return;
if (state.forceSkip)
return;
var type = GetType();
foreach (var patch in GetPatches())
{
if (patch.applied)
continue;
if (patch.apply != applyType)
continue;
var original = patch.original;
if (original == null)
{
Debug.LogError($"Null MethodBase for {GetType().Name}, {harmony.Id} patching!");
continue;
}
var prefix = AccessTools.Method(type, patch.prefix);
var postfix = AccessTools.Method(type, patch.postfix);
var transpiler = AccessTools.Method(type, patch.transpiler);
var finalizer = AccessTools.Method(type, patch.finalizer);
var harmonyPatch = harmony.Patch(original,
prefix != null ? new HarmonyMethod(prefix) : null,
postfix != null ? new HarmonyMethod(postfix) : null,
transpiler != null ? new HarmonyMethod(transpiler) : null,
finalizer != null ? new HarmonyMethod(finalizer) : null
);
patch.harmonyPatch = harmonyPatch;
patch.applied = true;
patches.Add(patch);
}
}
public void UnpatchAll()
{
if (harmony == null)
return;
foreach (var patch in patches)
{
if (!patch.applied)
continue;
patch.applied = false;
var original = patch.original;
var info = Harmony.GetPatchInfo(original);
info.Prefixes.Do(patchInfo => harmony.Unpatch(original, patchInfo.PatchMethod));
info.Postfixes.Do(patchInfo => harmony.Unpatch(original, patchInfo.PatchMethod));
info.Transpilers.Do(patchInfo => harmony.Unpatch(original, patchInfo.PatchMethod));
info.Finalizers.Do(patchInfo => harmony.Unpatch(original, patchInfo.PatchMethod));
}
patches.Clear();
}
}
}