CHUNITHM-Patch-Finder/Program.cs
2024-04-11 13:34:11 +07:00

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");