Skip to content
This repository was archived by the owner on May 9, 2023. It is now read-only.

Persistent hook #196

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 87 additions & 1 deletion src/Hooks/HookCreator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using HarmonyLib;
using System.Linq;
using System.Xml.Serialization;
using HarmonyLib;
using UnityExplorer.CSConsole;
using UnityExplorer.Runtime;
using UnityExplorer.UI.Panels;
Expand Down Expand Up @@ -225,12 +227,96 @@ internal static void EditorInputSave()
CurrentEditedHook.Patch();

CurrentEditedHook.PatchSourceCode = input;
SaveHooks(CurrentEditedHook);
CurrentEditedHook = null;
HookManagerPanel.Instance.SetPage(HookManagerPanel.Pages.ClassMethodSelector);
}

HookList.HooksScrollPool.Refresh(true, false);
}
// Persistent hooks
public struct HookData
{
public string Description;
public string SourceCode;
public string ReflectedType;
}

public static void SaveHooks(HookInstance hook)
{
HookData data = new HookData();
data.Description = hook.TargetMethod.FullDescription();
data.ReflectedType = hook.TargetMethod.ReflectedType.ToString();
data.SourceCode = hook.PatchSourceCode;
string filename = data.Description.GetHashCode().ToString("X8") + ".txt";
string folderpath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "UnityExplorerHarmonyHooks");
Directory.CreateDirectory(folderpath);
string fpath = Path.Combine(folderpath, filename);
XmlSerializer xs = new XmlSerializer(typeof(HookData));
TextWriter tw = new StreamWriter(fpath);
xs.Serialize(tw, data);
tw.Close();
ExplorerCore.Log("Save hook: " + data.Description + " to: " + filename);
}

public void LoadSavedHooks()
{
string folderpath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "UnityExplorerHarmonyHooks");
Directory.CreateDirectory(folderpath);
ExplorerCore.Log("Hooks path: " + folderpath);
XmlSerializer xs = new XmlSerializer(typeof(HookData));
xs.UnknownNode += new XmlNodeEventHandler(xs_UnknownNode);
xs.UnknownAttribute += new XmlAttributeEventHandler(xs_UnknownAttribute);
DirectoryInfo di = new DirectoryInfo(folderpath);
FileInfo[] fs = di.GetFiles("*.txt");
foreach (FileInfo fi in fs)
{
ExplorerCore.Log("Load: " + fi.Name);
try
{
FileStream fileStream = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read);
HookData hookData;
hookData = (HookData)xs.Deserialize(fileStream);
ExplorerCore.Log("+> Hook: " + hookData.Description);
Type type = ReflectionUtility.GetTypeByName(hookData.ReflectedType);
IEnumerable<MethodInfo> ms = type.GetMethods().Where(
mi => mi.FullDescription() == hookData.Description
);

MethodInfo method = ms.First();
HookManagerPanel.Instance.SetPage(HookManagerPanel.Pages.ClassMethodSelector);

if (HookList.hookedSignatures.Contains(hookData.Description))
{
ExplorerCore.LogWarning($"Method is already hooked!");
return;
}

HookInstance hook = new(method, hookData.SourceCode);
HookList.hookedSignatures.Add(hookData.Description);
HookList.currentHooks.Add(hookData.Description, hook);

AddHooksScrollPool.Refresh(true, false);
HookList.HooksScrollPool.Refresh(true, false);
}
catch (Exception ex)
{
ExplorerCore.LogError("Exception when load: " + fi.Name + " ---------\n" + ex.Message);
}
}
}


private void xs_UnknownNode(object sender, XmlNodeEventArgs e)
{
ExplorerCore.LogWarning("Unknown Node in hooks:" + e.Name + "\t" + e.Text);
}

private void xs_UnknownAttribute(object sender, XmlAttributeEventArgs e)
{
System.Xml.XmlAttribute attr = e.Attr;
ExplorerCore.LogWarning("Unknown attribute in hooks:" + attr.Name + "='" + attr.Value + "'");
}

// UI Construction

Expand Down
13 changes: 13 additions & 0 deletions src/Hooks/HookInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ public HookInstance(MethodInfo targetMethod)
if (CompileAndGenerateProcessor(PatchSourceCode))
Patch();
}

public HookInstance(MethodInfo targetMethod, string code)
{
this.TargetMethod = targetMethod;
this.signature = TargetMethod.FullDescription();

PatchSourceCode = code;

if (CompileAndGenerateProcessor(PatchSourceCode))
{
Patch();
}
}

// Evaluator.source_file
private static readonly FieldInfo fi_sourceFile = AccessTools.Field(typeof(Evaluator), "source_file");
Expand Down
2 changes: 2 additions & 0 deletions src/UI/Panels/HookManagerPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ protected override void ConstructPanelContent()

genericArgsHandler.ConstructUI(ContentRoot);
genericArgsHandler.UIRoot.SetActive(false);

hookCreator.LoadSavedHooks();
}
}
}