mirror of
https://github.com/MewoLab/AquaDX.git
synced 2026-02-16 05:37:28 +08:00
[RF] AquaMai configuration refactor (#82)
更新了配置文件格式,原有的配置文件将被自动无缝迁移,详情请见新的配置文件中的注释(例外:`SlideJudgeTweak` 不再默认启用) 旧配置文件将被重命名备份,如果更新到此版本遇到 Bug 请联系我们 Updated configuration file schema. The old config file will be migrated automatically and seamlessly. See the comments in the new configuration file for details. (Except for `SlideJudgeTweak` is no longer enabled by default) Your old configuration file will be renamed as a backup. If you encounter any bug with this version, please contact us.
This commit is contained in:
72
AquaMai/AquaMai.Core/Helpers/EnableConditionHelper.cs
Normal file
72
AquaMai/AquaMai.Core/Helpers/EnableConditionHelper.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using AquaMai.Core.Attributes;
|
||||
using AquaMai.Core.Resources;
|
||||
using HarmonyLib;
|
||||
using MelonLoader;
|
||||
|
||||
namespace AquaMai.Core.Helpers;
|
||||
|
||||
public class EnableConditionHelper
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch("HarmonyLib.PatchTools", "GetPatchMethod")]
|
||||
public static void PostGetPatchMethod(ref MethodInfo __result)
|
||||
{
|
||||
if (__result != null)
|
||||
{
|
||||
if (ShouldSkipMethodOrClass(__result.GetCustomAttribute, __result.ReflectedType, __result.Name))
|
||||
{
|
||||
__result = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch("HarmonyLib.PatchTools", "GetPatchMethods")]
|
||||
public static void PostGetPatchMethods(ref IList __result)
|
||||
{
|
||||
for (int i = 0; i < __result.Count; i++)
|
||||
{
|
||||
var harmonyMethod = Traverse.Create(__result[i]).Field("info").GetValue() as HarmonyMethod;
|
||||
var method = harmonyMethod.method;
|
||||
if (ShouldSkipMethodOrClass(method.GetCustomAttribute, method.ReflectedType, method.Name))
|
||||
{
|
||||
__result.RemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ShouldSkipClass(Type type)
|
||||
{
|
||||
return ShouldSkipMethodOrClass(type.GetCustomAttribute, type);
|
||||
}
|
||||
|
||||
private static bool ShouldSkipMethodOrClass(Func<Type, object> getCustomAttribute, Type type, string methodName = "")
|
||||
{
|
||||
var displayName = type.FullName + (string.IsNullOrEmpty(methodName) ? "" : $".{methodName}");
|
||||
var enableIf = (EnableIfAttribute)getCustomAttribute(typeof(EnableIfAttribute));
|
||||
if (enableIf != null && !enableIf.ShouldEnable(type))
|
||||
{
|
||||
# if DEBUG
|
||||
MelonLogger.Msg($"Skipping {displayName} due to EnableIf condition");
|
||||
# endif
|
||||
return true;
|
||||
}
|
||||
var enableGameVersion = (EnableGameVersionAttribute)getCustomAttribute(typeof(EnableGameVersionAttribute));
|
||||
if (enableGameVersion != null && !enableGameVersion.ShouldEnable(GameInfo.GameVersion))
|
||||
{
|
||||
# if DEBUG
|
||||
MelonLogger.Msg($"Skipping {displayName} due to EnableGameVersion condition");
|
||||
# endif
|
||||
if (!enableGameVersion.NoWarn)
|
||||
{
|
||||
MelonLogger.Warning(string.Format(Locale.SkipIncompatiblePatch, type));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
15
AquaMai/AquaMai.Core/Helpers/FileSystem.cs
Normal file
15
AquaMai/AquaMai.Core/Helpers/FileSystem.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace AquaMai.Core.Helpers;
|
||||
|
||||
public static class FileSystem
|
||||
{
|
||||
public static string ResolvePath(string path)
|
||||
{
|
||||
var varExpanded = Environment.ExpandEnvironmentVariables(path);
|
||||
return Path.IsPathRooted(varExpanded)
|
||||
? varExpanded
|
||||
: Path.Combine(Environment.CurrentDirectory, varExpanded);
|
||||
}
|
||||
}
|
||||
21
AquaMai/AquaMai.Core/Helpers/GameInfo.cs
Normal file
21
AquaMai/AquaMai.Core/Helpers/GameInfo.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Reflection;
|
||||
using MAI2System;
|
||||
|
||||
namespace AquaMai.Core.Helpers;
|
||||
|
||||
public class GameInfo
|
||||
{
|
||||
public static uint GameVersion { get; } = GetGameVersion();
|
||||
|
||||
private static uint GetGameVersion()
|
||||
{
|
||||
return (uint)typeof(ConstParameter).GetField("NowGameVersion", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy).GetValue(null);
|
||||
}
|
||||
|
||||
public static string GameId { get; } = GetGameId();
|
||||
|
||||
private static string GetGameId()
|
||||
{
|
||||
return typeof(ConstParameter).GetField("GameIDStr", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy).GetValue(null) as string;
|
||||
}
|
||||
}
|
||||
57
AquaMai/AquaMai.Core/Helpers/GuiSizes.cs
Normal file
57
AquaMai/AquaMai.Core/Helpers/GuiSizes.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AquaMai.Core.Helpers;
|
||||
|
||||
public static class GuiSizes
|
||||
{
|
||||
public static bool SinglePlayer { get; set; } = false;
|
||||
public static float PlayerWidth => Screen.height / 1920f * 1080;
|
||||
public static float PlayerCenter => SinglePlayer ? Screen.width / 2f : Screen.width / 2f - PlayerWidth / 2;
|
||||
public static int FontSize => (int)(PlayerWidth * .015f);
|
||||
public static float LabelHeight => FontSize * 1.5f;
|
||||
public static float Margin => PlayerWidth * .005f;
|
||||
|
||||
private static Color backgroundColor = new(147 / 256f, 160 / 256f, 173 / 256f, .8f);
|
||||
|
||||
public static void SetupStyles()
|
||||
{
|
||||
var buttonStyle = GUI.skin.button;
|
||||
buttonStyle.normal.textColor = Color.white;
|
||||
buttonStyle.normal.background = Texture2D.whiteTexture;
|
||||
buttonStyle.hover.background = Texture2D.whiteTexture;
|
||||
buttonStyle.active.background = Texture2D.whiteTexture;
|
||||
buttonStyle.border = new RectOffset(0, 0, 0, 0);
|
||||
buttonStyle.margin = new RectOffset(0, 0, 0, 0);
|
||||
buttonStyle.padding = new RectOffset(10, 10, 10, 10);
|
||||
buttonStyle.overflow = new RectOffset(0, 0, 0, 0);
|
||||
|
||||
var boxStyle = GUI.skin.box;
|
||||
boxStyle.border = new RectOffset(0, 0, 0, 0);
|
||||
boxStyle.normal.background = Texture2D.whiteTexture;
|
||||
|
||||
GUI.backgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
[HarmonyPatch]
|
||||
public class BoxBackground
|
||||
{
|
||||
public static IEnumerable<MethodBase> TargetMethods()
|
||||
{
|
||||
return typeof(GUI).GetMethods().Where(x => x.Name == "Box");
|
||||
}
|
||||
|
||||
public static void Prefix()
|
||||
{
|
||||
GUI.backgroundColor = new Color(62 / 256f, 62 / 256f, 66 / 256f, .6f);
|
||||
}
|
||||
|
||||
public static void Postfix()
|
||||
{
|
||||
GUI.backgroundColor = backgroundColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
146
AquaMai/AquaMai.Core/Helpers/KeyListener.cs
Normal file
146
AquaMai/AquaMai.Core/Helpers/KeyListener.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using AquaMai.Config.Types;
|
||||
using HarmonyLib;
|
||||
using Main;
|
||||
using Manager;
|
||||
using MelonLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AquaMai.Core.Helpers;
|
||||
|
||||
public static class KeyListener
|
||||
{
|
||||
private static readonly Dictionary<KeyCodeOrName, int> _keyPressFrames = [];
|
||||
private static readonly Dictionary<KeyCodeOrName, int> _keyPressFramesPrev = [];
|
||||
|
||||
static KeyListener()
|
||||
{
|
||||
foreach (KeyCodeOrName key in Enum.GetValues(typeof(KeyCodeOrName)))
|
||||
{
|
||||
_keyPressFrames[key] = 0;
|
||||
_keyPressFramesPrev[key] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(GameMainObject), "Update")]
|
||||
public static void CheckLongPush()
|
||||
{
|
||||
foreach (KeyCodeOrName key in Enum.GetValues(typeof(KeyCodeOrName)))
|
||||
{
|
||||
_keyPressFramesPrev[key] = _keyPressFrames[key];
|
||||
if (GetKeyPush(key))
|
||||
{
|
||||
# if DEBUG
|
||||
MelonLogger.Msg($"CheckLongPush {key} is push {_keyPressFrames[key]}");
|
||||
# endif
|
||||
_keyPressFrames[key]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
_keyPressFrames[key] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GetKeyPush(KeyCodeOrName key) =>
|
||||
key switch
|
||||
{
|
||||
KeyCodeOrName.None => false,
|
||||
< KeyCodeOrName.Select1P => Input.GetKey(key.GetKeyCode()),
|
||||
KeyCodeOrName.Test => InputManager.GetSystemInputPush(InputManager.SystemButtonSetting.ButtonTest),
|
||||
KeyCodeOrName.Service => InputManager.GetSystemInputPush(InputManager.SystemButtonSetting.ButtonService),
|
||||
KeyCodeOrName.Select1P => InputManager.GetButtonPush(0, InputManager.ButtonSetting.Select),
|
||||
KeyCodeOrName.Select2P => InputManager.GetButtonPush(1, InputManager.ButtonSetting.Select),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(key), key, "我也不知道这是什么键")
|
||||
};
|
||||
|
||||
public static bool GetKeyDown(KeyCodeOrName key)
|
||||
{
|
||||
// return key switch
|
||||
// {
|
||||
// KeyCodeOrName.None => false,
|
||||
// < KeyCodeOrName.Select1P => Input.GetKeyDown(key.GetKeyCode()),
|
||||
// KeyCodeOrName.Test => InputManager.GetSystemInputDown(InputManager.SystemButtonSetting.ButtonTest),
|
||||
// KeyCodeOrName.Service => InputManager.GetSystemInputDown(InputManager.SystemButtonSetting.ButtonService),
|
||||
// KeyCodeOrName.Select1P => InputManager.GetButtonDown(0, InputManager.ButtonSetting.Select),
|
||||
// KeyCodeOrName.Select2P => InputManager.GetButtonDown(1, InputManager.ButtonSetting.Select),
|
||||
// _ => throw new ArgumentOutOfRangeException(nameof(key), key, "我也不知道这是什么键")
|
||||
// };
|
||||
|
||||
// 不用这个,我们检测按键是否弹起以及弹起之前按下的时间是否小于 30,这样可以防止要长按时按下的时候就触发
|
||||
return _keyPressFrames[key] == 0 && 0 < _keyPressFramesPrev[key] && _keyPressFramesPrev[key] < 30;
|
||||
}
|
||||
|
||||
public static bool GetKeyDownOrLongPress(KeyCodeOrName key, bool isLongPress)
|
||||
{
|
||||
bool ret;
|
||||
if (isLongPress)
|
||||
{
|
||||
ret = _keyPressFrames[key] == 60;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = GetKeyDown(key);
|
||||
}
|
||||
|
||||
# if DEBUG
|
||||
if (ret)
|
||||
{
|
||||
MelonLogger.Msg($"Key {key} is pressed, long press: {isLongPress}");
|
||||
MelonLogger.Msg(new StackTrace());
|
||||
}
|
||||
# endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static KeyCode GetKeyCode(this KeyCodeOrName keyCodeOrName) =>
|
||||
keyCodeOrName switch
|
||||
{
|
||||
KeyCodeOrName.Alpha0 => KeyCode.Alpha0,
|
||||
KeyCodeOrName.Alpha1 => KeyCode.Alpha1,
|
||||
KeyCodeOrName.Alpha2 => KeyCode.Alpha2,
|
||||
KeyCodeOrName.Alpha3 => KeyCode.Alpha3,
|
||||
KeyCodeOrName.Alpha4 => KeyCode.Alpha4,
|
||||
KeyCodeOrName.Alpha5 => KeyCode.Alpha5,
|
||||
KeyCodeOrName.Alpha6 => KeyCode.Alpha6,
|
||||
KeyCodeOrName.Alpha7 => KeyCode.Alpha7,
|
||||
KeyCodeOrName.Alpha8 => KeyCode.Alpha8,
|
||||
KeyCodeOrName.Alpha9 => KeyCode.Alpha9,
|
||||
KeyCodeOrName.Keypad0 => KeyCode.Keypad0,
|
||||
KeyCodeOrName.Keypad1 => KeyCode.Keypad1,
|
||||
KeyCodeOrName.Keypad2 => KeyCode.Keypad2,
|
||||
KeyCodeOrName.Keypad3 => KeyCode.Keypad3,
|
||||
KeyCodeOrName.Keypad4 => KeyCode.Keypad4,
|
||||
KeyCodeOrName.Keypad5 => KeyCode.Keypad5,
|
||||
KeyCodeOrName.Keypad6 => KeyCode.Keypad6,
|
||||
KeyCodeOrName.Keypad7 => KeyCode.Keypad7,
|
||||
KeyCodeOrName.Keypad8 => KeyCode.Keypad8,
|
||||
KeyCodeOrName.Keypad9 => KeyCode.Keypad9,
|
||||
KeyCodeOrName.F1 => KeyCode.F1,
|
||||
KeyCodeOrName.F2 => KeyCode.F2,
|
||||
KeyCodeOrName.F3 => KeyCode.F3,
|
||||
KeyCodeOrName.F4 => KeyCode.F4,
|
||||
KeyCodeOrName.F5 => KeyCode.F5,
|
||||
KeyCodeOrName.F6 => KeyCode.F6,
|
||||
KeyCodeOrName.F7 => KeyCode.F7,
|
||||
KeyCodeOrName.F8 => KeyCode.F8,
|
||||
KeyCodeOrName.F9 => KeyCode.F9,
|
||||
KeyCodeOrName.F10 => KeyCode.F10,
|
||||
KeyCodeOrName.F11 => KeyCode.F11,
|
||||
KeyCodeOrName.F12 => KeyCode.F12,
|
||||
KeyCodeOrName.Insert => KeyCode.Insert,
|
||||
KeyCodeOrName.Delete => KeyCode.Delete,
|
||||
KeyCodeOrName.Home => KeyCode.Home,
|
||||
KeyCodeOrName.End => KeyCode.End,
|
||||
KeyCodeOrName.PageUp => KeyCode.PageUp,
|
||||
KeyCodeOrName.PageDown => KeyCode.PageDown,
|
||||
KeyCodeOrName.UpArrow => KeyCode.UpArrow,
|
||||
KeyCodeOrName.DownArrow => KeyCode.DownArrow,
|
||||
KeyCodeOrName.LeftArrow => KeyCode.LeftArrow,
|
||||
KeyCodeOrName.RightArrow => KeyCode.RightArrow,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(keyCodeOrName), keyCodeOrName, "游戏功能键需要单独处理")
|
||||
};
|
||||
}
|
||||
39
AquaMai/AquaMai.Core/Helpers/MessageHelper.cs
Normal file
39
AquaMai/AquaMai.Core/Helpers/MessageHelper.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using DB;
|
||||
using HarmonyLib;
|
||||
using Manager;
|
||||
using MelonLoader;
|
||||
using Process;
|
||||
|
||||
namespace AquaMai.Core.Helpers;
|
||||
|
||||
public class MessageHelper
|
||||
{
|
||||
private static IGenericManager _genericManager = null;
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(ProcessManager), "SetMessageManager")]
|
||||
private static void OnSetMessageManager(IGenericManager genericManager)
|
||||
{
|
||||
_genericManager = genericManager;
|
||||
}
|
||||
|
||||
public static void ShowMessage(string message, WindowSizeID size = WindowSizeID.Middle, string title = null)
|
||||
{
|
||||
if (_genericManager is null)
|
||||
{
|
||||
MelonLogger.Error($"[MessageHelper] Unable to show message: `{message}` GenericManager is null");
|
||||
return;
|
||||
}
|
||||
|
||||
_genericManager.Enqueue(0, WindowMessageID.CollectionAttentionEmptyFavorite, new WindowParam()
|
||||
{
|
||||
hideTitle = title is null,
|
||||
replaceTitle = true,
|
||||
title = title,
|
||||
replaceText = true,
|
||||
text = message,
|
||||
changeSize = true,
|
||||
sizeID = size,
|
||||
});
|
||||
}
|
||||
}
|
||||
31
AquaMai/AquaMai.Core/Helpers/MusicDirHelper.cs
Normal file
31
AquaMai/AquaMai.Core/Helpers/MusicDirHelper.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using HarmonyLib;
|
||||
|
||||
namespace AquaMai.Core.Helpers;
|
||||
|
||||
public class MusicDirHelper
|
||||
{
|
||||
private static Dictionary<int, string> _map = new();
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(Manager.MaiStudio.Serialize.MusicData), "AddPath")]
|
||||
private static void AddPath(Manager.MaiStudio.Serialize.MusicData __instance, string parentPath)
|
||||
{
|
||||
_map[__instance.GetID()] = parentPath;
|
||||
}
|
||||
|
||||
public static string LookupPath(int id)
|
||||
{
|
||||
return _map.GetValueOrDefault(id);
|
||||
}
|
||||
|
||||
public static string LookupPath(Manager.MaiStudio.Serialize.MusicData musicData)
|
||||
{
|
||||
return LookupPath(musicData.GetID());
|
||||
}
|
||||
|
||||
public static string LookupPath(Manager.MaiStudio.MusicData musicData)
|
||||
{
|
||||
return LookupPath(musicData.GetID());
|
||||
}
|
||||
}
|
||||
25
AquaMai/AquaMai.Core/Helpers/SharedInstances.cs
Normal file
25
AquaMai/AquaMai.Core/Helpers/SharedInstances.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using HarmonyLib;
|
||||
using Main;
|
||||
using Process;
|
||||
|
||||
namespace AquaMai.Core.Helpers;
|
||||
|
||||
public class SharedInstances
|
||||
{
|
||||
public static ProcessDataContainer ProcessDataContainer { get; private set; }
|
||||
public static GameMainObject GameMainObject { get; private set; }
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(ProcessDataContainer), MethodType.Constructor)]
|
||||
public static void OnCreateProcessDataContainer(ProcessDataContainer __instance)
|
||||
{
|
||||
ProcessDataContainer = __instance;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(GameMainObject), "Awake")]
|
||||
public static void OnCreateGameMainObject(GameMainObject __instance)
|
||||
{
|
||||
GameMainObject = __instance;
|
||||
}
|
||||
}
|
||||
90
AquaMai/AquaMai.Core/Helpers/Shim.cs
Normal file
90
AquaMai/AquaMai.Core/Helpers/Shim.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using MAI2.Util;
|
||||
using Manager;
|
||||
using Manager.UserDatas;
|
||||
using Net.Packet;
|
||||
using Net.Packet.Mai2;
|
||||
|
||||
namespace AquaMai.Core.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");
|
||||
}
|
||||
})();
|
||||
|
||||
public static IEnumerable<UserScore>[] GetUserScoreList(UserData userData)
|
||||
{
|
||||
var tUserData = Traverse.Create(userData);
|
||||
|
||||
var tScoreList = tUserData.Property("ScoreList");
|
||||
if (tScoreList.PropertyExists())
|
||||
{
|
||||
return tScoreList.GetValue<List<UserScore>[]>();
|
||||
}
|
||||
|
||||
var tScoreDic = tUserData.Property("ScoreDic");
|
||||
if (tScoreDic.PropertyExists())
|
||||
{
|
||||
var scoreDic = tScoreDic.GetValue<Dictionary<int, UserScore>[]>();
|
||||
return scoreDic.Select(dic => dic.Values).ToArray();
|
||||
}
|
||||
|
||||
throw new MissingFieldException("No matching UserData.ScoreList/ScoreDic found");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user