From eca2b7f5ee6bc63dc37e5accf999276b97567730 Mon Sep 17 00:00:00 2001 From: goaaats Date: Sun, 19 Jun 2022 20:40:15 +0200 Subject: [PATCH] feat: basic .text scan cache This currently saves cached jsons in the working directory, we might wanna change that --- Dalamud/Dalamud.cs | 14 ++++++++--- Dalamud/Game/SigScanner.cs | 50 +++++++++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs index e9fef946e..96ed99b8b 100644 --- a/Dalamud/Dalamud.cs +++ b/Dalamud/Dalamud.cs @@ -106,7 +106,12 @@ namespace Dalamud Service.Set(); // Initialize the process information. - Service.Set(new SigScanner(true)); + var info = Service.Get(); + var cacheDir = new DirectoryInfo(Path.Combine(info.WorkingDirectory!, "cachedSigs")); + if (!cacheDir.Exists) + cacheDir.Create(); + + Service.Set(new SigScanner(true, new FileInfo(Path.Combine(cacheDir.FullName, $"{info.GameVersion}.json")))); Service.Set(); // Signal the main game thread to continue @@ -117,7 +122,7 @@ namespace Dalamud // Initialize FFXIVClientStructs function resolver using (Timings.Start("CS Resolver Init")) { - FFXIVClientStructs.Resolver.Initialize(); + FFXIVClientStructs.Resolver.InitializeParallel(); Log.Information("[T1] FFXIVClientStructs initialized!"); } @@ -390,7 +395,10 @@ namespace Dalamud Service.GetNullable()?.Dispose(); Service.GetNullable()?.Dispose(); Service.GetNullable()?.Dispose(); - Service.GetNullable()?.Dispose(); + + var sigScanner = Service.Get(); + sigScanner.Save(); + sigScanner.Dispose(); SerilogEventSink.Instance.LogLine -= SerilogOnLogLine; diff --git a/Dalamud/Game/SigScanner.cs b/Dalamud/Game/SigScanner.cs index e35b17cc4..3885a7894 100644 --- a/Dalamud/Game/SigScanner.cs +++ b/Dalamud/Game/SigScanner.cs @@ -2,11 +2,13 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; +using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Dalamud.IoC; using Dalamud.IoC.Internal; +using Newtonsoft.Json; using Serilog; namespace Dalamud.Game @@ -16,17 +18,22 @@ namespace Dalamud.Game /// [PluginInterface] [InterfaceVersion("1.0")] - public sealed class SigScanner : IDisposable + public class SigScanner : IDisposable { + private readonly FileInfo? cacheFile; + private IntPtr moduleCopyPtr; private long moduleCopyOffset; + private Dictionary? textCache; + /// /// Initializes a new instance of the class using the main module of the current process. /// /// Whether or not to copy the module upon initialization for search operations to use, as to not get disturbed by possible hooks. - public SigScanner(bool doCopy = false) - : this(Process.GetCurrentProcess().MainModule!, doCopy) + /// File used to cached signatures. + public SigScanner(bool doCopy = false, FileInfo? cacheFile = null) + : this(Process.GetCurrentProcess().MainModule!, doCopy, cacheFile) { } @@ -35,8 +42,10 @@ namespace Dalamud.Game /// /// The ProcessModule to be used for scanning. /// Whether or not to copy the module upon initialization for search operations to use, as to not get disturbed by possible hooks. - public SigScanner(ProcessModule module, bool doCopy = false) + /// File used to cached signatures. + public SigScanner(ProcessModule module, bool doCopy = false, FileInfo? cacheFile = null) { + this.cacheFile = cacheFile; this.Module = module; this.Is32BitProcess = !Environment.Is64BitProcess; this.IsCopy = doCopy; @@ -49,6 +58,9 @@ namespace Dalamud.Game Log.Verbose($"Module base: 0x{this.TextSectionBase.ToInt64():X}"); Log.Verbose($"Module size: 0x{this.TextSectionSize:X}"); + + if (cacheFile != null) + this.Load(); } /// @@ -294,6 +306,12 @@ namespace Dalamud.Game /// The real offset of the found signature. public IntPtr ScanText(string signature) { + if (this.textCache != null && this.textCache.TryGetValue(signature, out var address)) + { + Log.Information("Found signature {Signature} in cache: {Address}", signature, address); + return address; + } + var mBase = this.IsCopy ? this.moduleCopyPtr : this.TextSectionBase; var scanRet = Scan(mBase, this.TextSectionSize, signature); @@ -306,6 +324,8 @@ namespace Dalamud.Game if (insnByte == 0xE8 || insnByte == 0xE9) return ReadJmpCallSig(scanRet); + this.textCache?.Add(signature, scanRet); + return scanRet; } @@ -337,6 +357,17 @@ namespace Dalamud.Game Marshal.FreeHGlobal(this.moduleCopyPtr); } + /// + /// Save the current state of the cache. + /// + internal void Save() + { + if (this.cacheFile == null) + return; + + File.WriteAllText(this.cacheFile.FullName, JsonConvert.SerializeObject(this.textCache)); + } + /// /// Helper for ScanText to get the correct address for IDA sigs that mark the first JMP or CALL location. /// @@ -479,5 +510,16 @@ namespace Dalamud.Game this.moduleCopyOffset = this.moduleCopyPtr.ToInt64() - this.Module.BaseAddress.ToInt64(); } + + private void Load() + { + if (this.cacheFile is not { Exists: true }) + { + this.textCache = new(); + return; + } + + this.textCache = JsonConvert.DeserializeObject>(File.ReadAllText(this.cacheFile.FullName)) ?? new Dictionary(); + } } }