mirror of
https://gitea.tendokyu.moe/beerpsi/CHUNITHM-Patch-Finder.git
synced 2024-11-23 23:31:03 +01:00
130 lines
3.6 KiB
C#
130 lines
3.6 KiB
C#
// See https://aka.ms/new-console-template for more information
|
|
|
|
using System.Text.Json;
|
|
using System.Text.Json.Nodes;
|
|
using CHUNITHM_Patch_Finder;
|
|
using Reloaded.Memory.Sigscan;
|
|
using Reloaded.Memory.Sigscan.Definitions.Structs;
|
|
using YamlDotNet.Serialization;
|
|
using YamlDotNet.Serialization.NamingConventions;
|
|
|
|
if (args.Length < 1)
|
|
{
|
|
Console.WriteLine($"Usage: {Environment.ProcessPath} <PATH TO EXE>");
|
|
Environment.Exit(22); // EINVAL
|
|
}
|
|
|
|
var deserializer = new DeserializerBuilder()
|
|
.WithNamingConvention(LowerCaseNamingConvention.Instance)
|
|
.Build();
|
|
var patches =
|
|
deserializer.Deserialize<Pattern[]>(
|
|
File.ReadAllText("patterns.yaml"));
|
|
var binary = File.ReadAllBytes(args[0]);
|
|
var scanner = new Scanner(binary);
|
|
var exportedPatches = new JsonArray();
|
|
|
|
// Other patches
|
|
foreach (var patch in patches)
|
|
{
|
|
var signatures = patch.Patches.Select(p => p.Signature ?? patch.Signature).ToList();
|
|
|
|
if (signatures.Any(s => s == null))
|
|
{
|
|
Console.WriteLine($"[ERROR] No signature provided for patch {patch.Name}");
|
|
continue;
|
|
}
|
|
|
|
var matches = signatures
|
|
.Zip(scanner.FindPatternsCached(signatures)!)
|
|
.GroupBy(p => p.First)
|
|
.ToDictionary(g => g.Key, g => g.First().Second);
|
|
|
|
if (matches.Any(p => !p.Value.Found))
|
|
{
|
|
Console.WriteLine($"No offset found for patch {patch.Name}");
|
|
continue;
|
|
}
|
|
|
|
var patchObject = new JsonObject()
|
|
{
|
|
{ "name", patch.Name },
|
|
};
|
|
|
|
if (patch.Tooltip != null)
|
|
patchObject.Add("tooltip", patch.Tooltip);
|
|
else if (patch.Danger != null)
|
|
patchObject.Add("danger", patch.Danger);
|
|
|
|
var patchArray = new JsonArray();
|
|
|
|
foreach (var p in patch.Patches)
|
|
{
|
|
var signature = (p.Signature ?? patch.Signature)!;
|
|
var off = new JsonArray();
|
|
var on = new JsonArray();
|
|
|
|
foreach (var b in p.Off)
|
|
off.Add(b);
|
|
|
|
foreach (var b in p.On)
|
|
on.Add(b);
|
|
|
|
var pObject = new JsonObject()
|
|
{
|
|
{ "offset", matches[signature].Offset + p.Offset },
|
|
{ "off", off },
|
|
{ "on", on },
|
|
};
|
|
|
|
patchArray.Add(pObject);
|
|
}
|
|
|
|
patchObject.Add("patches", patchArray);
|
|
exportedPatches.Add(patchObject);
|
|
}
|
|
|
|
// max track count patch
|
|
if (Path.GetFileName(args[0]) == "chusanApp.exe")
|
|
{
|
|
var offset = scanner
|
|
.FindPatterns([
|
|
"E8 ?? ?? ?? ?? 8D ?? 78 8B F0", // SDHD 2.00-2.20
|
|
"E8 ?? ?? ?? ?? 8B 4C 24 24 8B F0", // SDGS 1.30
|
|
])
|
|
.FirstOrDefault(o => o.Found, new PatternScanResult(-1));
|
|
|
|
if (offset.Found)
|
|
{
|
|
var trackCountRelativeAddress = BitConverter.ToInt32(binary, offset.Offset + 1);
|
|
var trackCountAddress = offset.Offset + 5 + trackCountRelativeAddress;
|
|
|
|
Console.WriteLine($"Found track count function at {trackCountAddress:X}");
|
|
|
|
var patch = new JsonObject
|
|
{
|
|
{ "type", "number" },
|
|
{ "name", "Maximum tracks" },
|
|
{ "offset", trackCountAddress + 1 },
|
|
{ "size", 4 },
|
|
{ "min", 3 },
|
|
{ "max", 12 }
|
|
};
|
|
|
|
exportedPatches.Add(patch);
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Track count function not found");
|
|
}
|
|
}
|
|
|
|
|
|
File.WriteAllText(
|
|
"patches.json",
|
|
JsonSerializer.Serialize(exportedPatches, new JsonSerializerOptions(JsonSerializerOptions.Default)
|
|
{
|
|
WriteIndented = true
|
|
}));
|
|
|
|
Console.WriteLine("Wrote patches to patches.json"); |