[O] Support SDGA and other game version in one binary

Merge pull request #61

* Merge targets

* Merge branch 'v1-dev' into fork/Menci/merge-targets

* [O] Move Shim to AquaMai.Helpers

---------

Co-authored-by: Clansty <i@gao4.pw>
pull/58/head^2
Menci 2024-10-13 21:35:13 +08:00 committed by Clansty
parent e67b68aa20
commit 81e0232712
No known key found for this signature in database
GPG Key ID: 3A6BE8BAF2EDE134
4 changed files with 94 additions and 66 deletions

View File

@ -8,14 +8,11 @@ EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|Any CPU = Release|Any CPU
SDGA145|Any CPU = SDGA145|Any CPU
Debug|Any CPU = Debug|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{788BC472-59F7-46F6-B760-65C18BA74389}.Release|Any CPU.ActiveCfg = Release|Any CPU
{788BC472-59F7-46F6-B760-65C18BA74389}.Release|Any CPU.Build.0 = Release|Any CPU
{788BC472-59F7-46F6-B760-65C18BA74389}.SDGA145|Any CPU.ActiveCfg = SDGA145|Any CPU
{788BC472-59F7-46F6-B760-65C18BA74389}.SDGA145|Any CPU.Build.0 = SDGA145|Any CPU
{788BC472-59F7-46F6-B760-65C18BA74389}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{788BC472-59F7-46F6-B760-65C18BA74389}.Debug|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection

View File

@ -2,7 +2,6 @@
using System.Linq;
using System.Reflection;
using HarmonyLib;
using MelonLoader;
using Net.Packet;
namespace AquaMai.Fix;
@ -11,65 +10,41 @@ public class RemoveEncryption
{
[HarmonyPrefix]
[HarmonyPatch(typeof(Packet), "Obfuscator", typeof(string))]
private static bool PreObfuscator(string srcStr, ref string __result)
public static bool PreObfuscator(string srcStr, ref string __result)
{
__result = srcStr.Replace("MaimaiExp", "").Replace("MaimaiChn", "");
return false;
}
[HarmonyPatch]
public class Encrypt
public class EncryptDecrypt
{
public static IEnumerable<MethodBase> TargetMethods()
{
# if SDGA145
return [AccessTools.Method("Net.CipherAES:Encrypt", [typeof(byte[])])];
# else
return [AccessTools.TypeByName("Net.CipherAES").GetMethods().FirstOrDefault(it => it.Name == "Encrypt")];
# endif
var methods = AccessTools.TypeByName("Net.CipherAES").GetMethods();
return
[
methods.FirstOrDefault(it => it.Name == "Encrypt" && it.IsPublic),
methods.FirstOrDefault(it => it.Name == "Decrypt" && it.IsPublic)
];
}
# if SDGA145
public static bool Prefix(byte[] data, ref byte[] __result)
public static bool Prefix(object[] __args, ref object __result)
{
__result = data;
if (__args.Length == 1)
{
// public static byte[] Encrypt(byte[] data)
// public static byte[] Decrypt(byte[] encryptData)
__result = __args[0];
}
else if (__args.Length == 2)
{
// public static bool Encrypt(byte[] data, out byte[] encryptData)
// public static bool Decrypt(byte[] encryptData, out byte[] plainData)
__args[1] = __args[0];
__result = true;
}
return false;
}
# else
public static bool Prefix(byte[] data, out byte[] encryptData, ref bool __result)
{
encryptData = data;
__result = true;
return false;
}
# endif
}
[HarmonyPatch]
public class Decrypt
{
public static IEnumerable<MethodBase> TargetMethods()
{
# if SDGA145
return [AccessTools.Method("Net.CipherAES:Decrypt", [typeof(byte[])])];
# else
return [AccessTools.TypeByName("Net.CipherAES").GetMethods().FirstOrDefault(it => it.Name == "Decrypt")];
# endif
}
# if SDGA145
public static bool Prefix(byte[] encryptData, ref byte[] __result)
{
__result = encryptData;
return false;
}
# else
public static bool Prefix(byte[] encryptData, out byte[] plainData, ref bool __result)
{
plainData = encryptData;
__result = true;
return false;
}
# endif
}
}

View File

@ -0,0 +1,67 @@
using System;
using System.Reflection;
using HarmonyLib;
using MAI2.Util;
using Manager;
using Net.Packet;
using Net.Packet.Mai2;
namespace AquaMai.Helpers;
public static class Shim
{
public delegate string GetAccessTokenMethod(int index);
public static readonly GetAccessTokenMethod GetAccessToken = new Func<GetAccessTokenMethod>(() => {
var tOperationManager = Traverse.Create(Singleton<OperationManager>.Instance);
var tGetAccessToken = tOperationManager.Method("GetAccessToken", [typeof(int)]);
if (!tGetAccessToken.MethodExists())
{
return (index) => throw new MissingMethodException("No matching OperationManager.GetAccessToken() method found");
}
return (index) => tGetAccessToken.GetValue<string>(index);
})();
public delegate PacketUploadUserPlaylog PacketUploadUserPlaylogCreator(int index, UserData src, int trackNo, Action<int> onDone, Action<PacketStatus> onError = null);
public static readonly PacketUploadUserPlaylogCreator CreatePacketUploadUserPlaylog = new Func<PacketUploadUserPlaylogCreator>(() => {
var type = typeof(PacketUploadUserPlaylog);
if (type.GetConstructor([typeof(int), typeof(UserData), typeof(int), typeof(Action<int>), typeof(Action<PacketStatus>)]) is ConstructorInfo ctor1) {
return (index, src, trackNo, onDone, onError) => {
var args = new object[] {index, src, trackNo, "", onDone, onError};
return (PacketUploadUserPlaylog)ctor1.Invoke(args);
};
}
else if (type.GetConstructor([typeof(int), typeof(UserData), typeof(int), typeof(string), typeof(Action<int>), typeof(Action<PacketStatus>)]) is ConstructorInfo ctor2) {
return (index, src, trackNo, onDone, onError) => {
var accessToken = GetAccessToken(index);
var args = new object[] {index, src, trackNo, accessToken, onDone, onError};
return (PacketUploadUserPlaylog)ctor2.Invoke(args);
};
}
else
{
throw new MissingMethodException("No matching PacketUploadUserPlaylog constructor found");
}
})();
public delegate PacketUpsertUserAll PacketUpsertUserAllCreator(int index, UserData src, Action<int> onDone, Action<PacketStatus> onError = null);
public static readonly PacketUpsertUserAllCreator CreatePacketUpsertUserAll = new Func<PacketUpsertUserAllCreator>(() => {
var type = typeof(PacketUpsertUserAll);
if (type.GetConstructor([typeof(int), typeof(UserData), typeof(Action<int>), typeof(Action<PacketStatus>)]) is ConstructorInfo ctor1) {
return (index, src, onDone, onError) => {
var args = new object[] {index, src, "", onDone, onError};
return (PacketUpsertUserAll)ctor1.Invoke(args);
};
}
else if (type.GetConstructor([typeof(int), typeof(UserData), typeof(string), typeof(Action<int>), typeof(Action<PacketStatus>)]) is ConstructorInfo ctor2) {
return (index, src, onDone, onError) => {
var accessToken = GetAccessToken(index);
var args = new object[] {index, src, accessToken, onDone, onError};
return (PacketUpsertUserAll)ctor2.Invoke(args);
};
}
else
{
throw new MissingMethodException("No matching PacketUpsertUserAll constructor found");
}
})();
}

View File

@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using AquaMai.Helpers;
using AquaMai.Resources;
using AquaMai.Utils;
using CriAtomDebugDetail;
using DB;
using HarmonyLib;
using MAI2.Util;
@ -63,12 +65,7 @@ public class ImmediateSave
}
SaveDataFix(userData);
# if SDGA145
PacketHelper.StartPacket(new PacketUploadUserPlaylog(i, userData, (int)GameManager.MusicTrackNumber - 1,
# else
var accessToken = Singleton<OperationManager>.Instance.GetAccessToken(i);
PacketHelper.StartPacket(new PacketUploadUserPlaylog(i, userData, (int)GameManager.MusicTrackNumber - 1, accessToken,
# endif
PacketHelper.StartPacket(Shim.CreatePacketUploadUserPlaylog(i, userData, (int)GameManager.MusicTrackNumber - 1,
delegate
{
MelonLogger.Msg("Playlog saved");
@ -82,11 +79,7 @@ public class ImmediateSave
MessageHelper.ShowMessage("Playlog save error");
CheckSaveDone();
}));
# if SDGA145
PacketHelper.StartPacket(new PacketUpsertUserAll(i, userData, delegate(int code)
# else
PacketHelper.StartPacket(new PacketUpsertUserAll(i, userData, accessToken, delegate(int code)
# endif
PacketHelper.StartPacket(Shim.CreatePacketUpsertUserAll(i, userData, delegate(int code)
{
if (code == 1)
{
@ -222,11 +215,7 @@ public class ImmediateSave
userData.Detail.LastPlayMode = 2;
}
# if SDGA145
userData.Detail.LastGameId = "SDGA";
# else
userData.Detail.LastGameId = "SDEZ";
# endif
userData.Detail.LastGameId = ConstParameter.GameIDStr;
userData.Detail.LastRomVersion = Singleton<SystemConfig>.Instance.config.romVersionInfo.versionNo.versionString;
userData.Detail.LastDataVersion = Singleton<SystemConfig>.Instance.config.dataVersionInfo.versionNo.versionString;
}