mirror of
https://github.com/k1tbyte/Wand-Enhancer.git
synced 2026-08-29 19:01:16 +00:00
6716da5c80
Anchor each patch on a stable string (API endpoint, IPC channel, method name) and walk the delimiter structure via JsCursor to the edit site, reading minified identifiers out of the located region. Move injected JavaScript into WandEnhancer/Patches/*.js as embedded resources. Declare patches as PatchEntry rows in EnhancerConfig with CandidateFileNames, SearchHints and optional CapabilityHints. Recognise keyword-preceded regex literals in JsCursor so `return/re/.test(x)` no longer desynchronises the scan. Require the remote setValue anchor to match exactly once; Wand ships sibling call sites for other sources. Require both backup halves in IsPatched so a partial backup no longer blocks patch and restore at the same time. Chain inner exceptions when unpack or pack fails. Rename Common to ProcessTerminator and Utils.Extensions to WeModInstalls.
83 lines
2.7 KiB
C#
83 lines
2.7 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using WandEnhancer.Core.Js;
|
|
using WandEnhancer.Models;
|
|
using WandEnhancer.View.MainWindow;
|
|
|
|
namespace WandEnhancer.Core
|
|
{
|
|
internal sealed class JavaScriptPatchApplier
|
|
{
|
|
private readonly Action<string, ELogType> _logger;
|
|
|
|
public JavaScriptPatchApplier(Action<string, ELogType> logger)
|
|
{
|
|
_logger = logger;
|
|
}
|
|
|
|
public string Apply(string fileName, string source, EnhancerConfig.PatchEntry patch, EPatchType patchType, out bool patchApplied)
|
|
{
|
|
patchApplied = false;
|
|
if (patch.Applied || !CanSearchFile(fileName, patch))
|
|
{
|
|
return source;
|
|
}
|
|
|
|
patch.CapabilityDetected |= ContainsAny(source, patch.CapabilityHints);
|
|
if (!ContainsAny(source, patch.SearchHints))
|
|
{
|
|
return source;
|
|
}
|
|
|
|
string label = FormatLabel(patchType, patch);
|
|
JsEdit[] edits;
|
|
try
|
|
{
|
|
edits = patch.Locate(new JsCursor(source));
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
throw new Exception($"[ENHANCER] [{label}] {e.Message}. The version may not be supported.", e);
|
|
}
|
|
|
|
if (edits == null || edits.Length == 0)
|
|
{
|
|
return source;
|
|
}
|
|
|
|
_logger($"[ENHANCER] [{label}] Found target in: {Path.GetFileName(fileName)}", ELogType.Info);
|
|
foreach (var edit in edits.OrderByDescending(edit => edit.Start))
|
|
{
|
|
source = edit.ApplyTo(source);
|
|
}
|
|
|
|
_logger($"[ENHANCER] [{label}] Patch applied", ELogType.Success);
|
|
patch.Applied = true;
|
|
patchApplied = true;
|
|
return source;
|
|
}
|
|
|
|
public static string FormatLabel(EPatchType patchType, EnhancerConfig.PatchEntry patch)
|
|
{
|
|
return string.IsNullOrEmpty(patch.Name) ? patchType.ToString() : $"{patchType} -> {patch.Name}";
|
|
}
|
|
|
|
public static bool CanSearchFile(string filePath, EnhancerConfig.PatchEntry patch)
|
|
{
|
|
if (patch.CandidateFileNames == null || patch.CandidateFileNames.Length == 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
string fileName = Path.GetFileName(filePath);
|
|
return patch.CandidateFileNames.Any(candidate => fileName.Equals(candidate, StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
|
|
private static bool ContainsAny(string source, string[] hints)
|
|
{
|
|
return hints != null && hints.Any(hint => source.IndexOf(hint, StringComparison.Ordinal) >= 0);
|
|
}
|
|
}
|
|
}
|