using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("Zichen-FixCosmetics-1.0.0")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Zichen-FixCosmetics-1.0.0")] [assembly: AssemblyTitle("Zichen-FixCosmetics-1.0.0")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Zichen_FixCosmetics { [BepInPlugin("zichen.fixcosmetics", "FixCosmetics", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { [CompilerGenerated] private sealed class d__38 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private CodeInstruction <>2__current; private int <>l__initialThreadId; private IEnumerable instructions; public IEnumerable <>3__instructions; private MethodInfo 5__2; private MethodInfo 5__3; private IEnumerator <>7__wrap3; CodeInstruction IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__38(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } 5__2 = null; 5__3 = null; <>7__wrap3 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = AccessTools.Method(AccessTools.TypeByName("REPOLib.Patches.MetaManagerPatch"), "LoadModded", (Type[])null, (Type[])null); 5__3 = AccessTools.Method(typeof(Plugin), "LoadModdedCosmeticsCompat", (Type[])null, (Type[])null); <>7__wrap3 = instructions.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } if (<>7__wrap3.MoveNext()) { CodeInstruction current = <>7__wrap3.Current; if (5__2 != null && 5__3 != null && current.opcode == OpCodes.Call && object.Equals(current.operand, 5__2)) { current.operand = 5__3; } <>2__current = current; <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap3 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap3 != null) { <>7__wrap3.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__38 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__38(0); } d__.instructions = <>3__instructions; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } public const string PluginGuid = "zichen.fixcosmetics"; public const string PluginName = "FixCosmetics"; public const string PluginVersion = "1.0.0"; private const string RepoLibGuid = "REPOLib"; private const string RepoLibMaxAffectedVersion = "4.0.1"; private const string InfoSection = "只读信息"; private const string GlobalSection = "A.全局设置"; private const string RepoLibFixSection = "B.REPOLib v4.0.1 修复"; private static readonly FieldInfo MetaSavePathField = AccessTools.Field(typeof(MetaManager), "savePath"); private static readonly FieldInfo MetaCosmeticUnlocksField = AccessTools.Field(typeof(MetaManager), "cosmeticUnlocks"); private static readonly FieldInfo MetaCosmeticHistoryField = AccessTools.Field(typeof(MetaManager), "cosmeticHistory"); private static readonly FieldInfo MetaCosmeticEquippedField = AccessTools.Field(typeof(MetaManager), "cosmeticEquipped"); private static readonly FieldInfo MetaCosmeticPresetsField = AccessTools.Field(typeof(MetaManager), "cosmeticPresets"); private static readonly FieldInfo MetaColorPresetsField = AccessTools.Field(typeof(MetaManager), "colorPresets"); private static readonly FieldInfo MetaColorsEquippedField = AccessTools.Field(typeof(MetaManager), "colorsEquipped"); private static readonly FieldInfo MetaSaveReadyField = AccessTools.Field(typeof(MetaManager), "saveReady"); private static readonly FieldInfo StatsEncryptionPasswordField = AccessTools.Field(typeof(StatsManager), "totallyNormalString"); private static readonly FieldInfo CosmeticAssetIdField = AccessTools.Field(typeof(CosmeticAsset), "assetId"); private static FieldInfo repoLibMissingCosmeticUnlocksField; private static FieldInfo repoLibMissingCosmeticHistoryField; private static FieldInfo repoLibMissingCosmeticEquippedField; private static FieldInfo repoLibMissingCosmeticPresetsField; private static ConfigEntry modEnabled; private static ConfigEntry fixRepoLibCosmetics; private Harmony harmony; private string repoLibFixResult; public static bool IsStaticModEnabled() { if (modEnabled != null) { return modEnabled.Value; } return false; } private void Awake() { DetachFromManager(); ResetConfigIfVersionChanged(); BindConfig(); ApplyHarmonyPatches(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"FixCosmetics v1.0.0 loaded."); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } private void BindConfig() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Expected O, but got Unknown //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Expected O, but got Unknown ((BaseUnityPlugin)this).Config.Bind("只读信息", "模组名称", "自定义化妆品修复", new ConfigDescription("", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 1000, ReadOnly = true } })); ((BaseUnityPlugin)this).Config.Bind("只读信息", "模组版本号", "1.0.0", new ConfigDescription("", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 990, ReadOnly = true } })); ((BaseUnityPlugin)this).Config.Bind("只读信息", "REPO交流QQ群", "824639225", new ConfigDescription("", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 980, ReadOnly = true } })); modEnabled = ((BaseUnityPlugin)this).Config.Bind("A.全局设置", "模组启用", true, new ConfigDescription("关闭后整个模组全部功能彻底失效。", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 900 } })); fixRepoLibCosmetics = ((BaseUnityPlugin)this).Config.Bind("B.REPOLib v4.0.1 修复", "修复自定义化妆品", true, new ConfigDescription("修复 REPOLib 4.0.1 及以下版本在 R.E.P.O. v0.4.2 下调用旧 MetaManager.Save() 签名导致自定义化妆品打不开的问题。高于 4.0.1 的 REPOLib 版本不启用此补丁。开关修改后需重启游戏。", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 900 } })); } private void ApplyHarmonyPatches() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown if (IsStaticModEnabled()) { harmony = new Harmony("zichen.fixcosmetics"); try { TryPatchRepoLibCosmetics(); } catch (Exception ex) { repoLibFixResult = "REPOLib cosmetics fix failed: " + ex; ((BaseUnityPlugin)this).Logger.LogError((object)repoLibFixResult); } ((BaseUnityPlugin)this).Logger.LogInfo((object)repoLibFixResult); } } private void TryPatchRepoLibCosmetics() { //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Expected O, but got Unknown //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Expected O, but got Unknown //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Expected O, but got Unknown if (!fixRepoLibCosmetics.Value) { repoLibFixResult = "REPOLib cosmetics fix skipped: config disabled."; return; } if (!CheckPluginVersionAtOrBelow("REPOLib", "4.0.1", out var detectedVersion)) { repoLibFixResult = (string.IsNullOrWhiteSpace(detectedVersion) ? "REPOLib cosmetics fix skipped: REPOLib not detected." : ("REPOLib cosmetics fix skipped: version above affected range. Max affected 4.0.1, detected " + detectedVersion + ".")); return; } Type type = AccessTools.TypeByName("REPOLib.Patches.MetaManagerPatch"); Type type2 = AccessTools.TypeByName("REPOLib.Modules.Cosmetics"); if (type == null || type2 == null) { repoLibFixResult = "REPOLib cosmetics fix failed: target type not found."; return; } MethodInfo methodInfo = AccessTools.Method(typeof(MetaManager), "Load", new Type[1] { typeof(bool) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(type, "LoadPatch", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(Plugin), "MetaManagerLoadPostfix", (Type[])null, (Type[])null); MethodInfo methodInfo4 = AccessTools.Method(type2, "RegisterCosmetics", (Type[])null, (Type[])null); MethodInfo methodInfo5 = AccessTools.GetDeclaredMethods(type2).FirstOrDefault((MethodInfo method) => method.Name == "RegisterCosmetic" && method.GetParameters().Length == 1 && method.GetParameters()[0].ParameterType == typeof(CosmeticAsset)); MethodInfo methodInfo6 = AccessTools.Method(typeof(Plugin), "ReplaceRepoLibLoadModdedCalls", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null || methodInfo3 == null || methodInfo4 == null || methodInfo5 == null || methodInfo6 == null || !CacheRepoLibMissingFields(type)) { repoLibFixResult = "REPOLib cosmetics fix failed: target method not found."; return; } try { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo6), (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo6), (HarmonyMethod)null, (HarmonyMethod)null); harmony.Unpatch((MethodBase)methodInfo, methodInfo2); } catch { SafeUnpatch(methodInfo, methodInfo3); SafeUnpatch(methodInfo4, methodInfo6); SafeUnpatch(methodInfo5, methodInfo6); throw; } repoLibFixResult = "REPOLib cosmetics fix applied: old Load postfix replaced, LoadModded calls redirected."; } private void SafeUnpatch(MethodInfo original, MethodInfo patch) { try { harmony.Unpatch((MethodBase)original, patch); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to roll back partial patch: " + ex.Message)); } } private static bool CacheRepoLibMissingFields(Type metaManagerPatchType) { repoLibMissingCosmeticUnlocksField = AccessTools.Field(metaManagerPatchType, "missingCosmeticUnlocks"); repoLibMissingCosmeticHistoryField = AccessTools.Field(metaManagerPatchType, "missingCosmeticHistory"); repoLibMissingCosmeticEquippedField = AccessTools.Field(metaManagerPatchType, "missingCosmeticEquipped"); repoLibMissingCosmeticPresetsField = AccessTools.Field(metaManagerPatchType, "missingCosmeticPresets"); if (repoLibMissingCosmeticUnlocksField != null && repoLibMissingCosmeticHistoryField != null && repoLibMissingCosmeticEquippedField != null) { return repoLibMissingCosmeticPresetsField != null; } return false; } private static bool CheckPluginVersionAtOrBelow(string guid, string maxAffectedVersion, out string detectedVersion) { detectedVersion = null; if (!Chainloader.PluginInfos.TryGetValue(guid, out var value) || value == null) { return false; } detectedVersion = value.Metadata.Version?.ToString(); return CompareVersionNumbers(detectedVersion, maxAffectedVersion) <= 0; } private static int CompareVersionNumbers(string left, string right) { int[] array = ParseVersionNumbers(left); int[] array2 = ParseVersionNumbers(right); if (array == null || array2 == null) { return 1; } for (int i = 0; i < array.Length; i++) { int num = array[i].CompareTo(array2[i]); if (num != 0) { return num; } } return 0; } private static int[] ParseVersionNumbers(string version) { if (string.IsNullOrWhiteSpace(version)) { return null; } Match match = Regex.Match(version, "^\\s*(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:\\.(\\d+))?"); if (!match.Success) { return null; } int[] array = new int[4]; for (int i = 0; i < array.Length; i++) { string value = match.Groups[i + 1].Value; array[i] = (int.TryParse(value, out var result) ? result : 0); } return array; } private static void MetaManagerLoadPostfix(MetaManager __instance) { if (!IsStaticModEnabled() || (Object)(object)__instance == (Object)null) { return; } SetFieldValue(MetaSaveReadyField, __instance, false); try { LoadModdedCosmeticsCompat(); } finally { SetFieldValue(MetaSaveReadyField, __instance, true); } } [IteratorStateMachine(typeof(d__38))] private static IEnumerable ReplaceRepoLibLoadModdedCalls(IEnumerable instructions) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__38(-2) { <>3__instructions = instructions }; } private static void LoadModdedCosmeticsCompat() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown MetaManager instance = MetaManager.instance; if ((Object)(object)instance == (Object)null) { return; } string text = (GetFieldValue(MetaSavePathField, instance) ?? "MetaSave") + "Modded.es3"; try { ES3Settings val = new ES3Settings(text, (EncryptionType)1, GetStatsEncryptionPassword(), (ES3Settings)null); if (!ES3.FileExists(val)) { instance.Save(false); return; } if (ES3.KeyExists("cosmeticUnlocks", val)) { List list = ES3.Load>("cosmeticUnlocks", val); List intList = GetIntList(MetaCosmeticUnlocksField, instance); List second = ResolveCosmeticIds(list); SetFieldValue(MetaCosmeticUnlocksField, instance, intList.Concat(second).Distinct().ToList()); SetRepoLibMissingList(repoLibMissingCosmeticUnlocksField, list.Where((string x) => !IsValidCosmeticAssetId(x)).ToList()); } if (ES3.KeyExists("cosmeticHistory", val)) { List list2 = ES3.Load>("cosmeticHistory", val); List intList2 = GetIntList(MetaCosmeticHistoryField, instance); List second2 = ResolveCosmeticIds(list2); SetFieldValue(MetaCosmeticHistoryField, instance, intList2.Concat(second2).Distinct().ToList()); SetRepoLibMissingList(repoLibMissingCosmeticHistoryField, list2.Where((string x) => !IsValidCosmeticAssetId(x)).ToList()); } if (ES3.KeyExists("cosmeticEquipped", val)) { List list3 = ES3.Load>("cosmeticEquipped", val); SetFieldValue(MetaCosmeticEquippedField, instance, ResolveCosmeticIds(list3)); SetRepoLibMissingList(repoLibMissingCosmeticEquippedField, list3.Where((string x) => !IsValidCosmeticAssetId(x)).ToList()); } if (ES3.KeyExists("cosmeticPresets", val)) { LoadCosmeticPresets(val, instance); } if (ES3.KeyExists("colorPresets", val)) { List> source = ES3.Load>>("colorPresets", val); List> intListList = GetIntListList(MetaColorPresetsField, instance); CopyPresetLists(source, intListList); } if (ES3.KeyExists("colorsEquipped", val)) { int[] array = ES3.Load("colorsEquipped", val); int[] fieldValue = GetFieldValue(MetaColorsEquippedField, instance); if (array != null && fieldValue != null) { Array.Copy(array, fieldValue, Math.Min(array.Length, fieldValue.Length)); } } } catch (Exception ex) { Debug.LogError((object)("[FixCosmetics] Failed to load modded cosmetics save: " + ex.Message)); ES3.DeleteFile(text); instance.Save(false); } } private static void LoadCosmeticPresets(ES3Settings settings, MetaManager metaManager) { List> list = ES3.Load>>("cosmeticPresets", settings); List> intListList = GetIntListList(MetaCosmeticPresetsField, metaManager); List> list2 = EnsureMissingPresetListSize(intListList.Count); if (list == null || intListList == null) { return; } int num = Math.Min(intListList.Count, list.Count); for (int i = 0; i < num; i++) { List list3 = list[i] ?? new List(); intListList[i] = ResolveCosmeticIds(list3); list2[i] = list3.Where((string x) => !IsValidCosmeticAssetId(x)).ToList(); } SetRepoLibMissingPresetList(list2); } private static List ResolveCosmeticIds(IEnumerable assetIds) { if ((Object)(object)MetaManager.instance == (Object)null || assetIds == null) { return new List(); } return (from index in assetIds.Select(FindCosmeticIndexByAssetId) where index >= 0 select index).ToList(); } private static int FindCosmeticIndexByAssetId(string assetId) { if (string.IsNullOrWhiteSpace(assetId) || (Object)(object)MetaManager.instance == (Object)null || MetaManager.instance.cosmeticAssets == null) { return -1; } return MetaManager.instance.cosmeticAssets.FindIndex((CosmeticAsset asset) => (Object)(object)asset != (Object)null && string.Equals(GetCosmeticAssetId(asset), assetId, StringComparison.Ordinal)); } private static bool IsValidCosmeticAssetId(string assetId) { return FindCosmeticIndexByAssetId(assetId) >= 0; } private static string GetStatsEncryptionPassword() { return GetFieldValue(StatsEncryptionPasswordField, StatsManager.instance) ?? "Why would you want to cheat?... :o It's no fun. :') :'D"; } private static string GetCosmeticAssetId(CosmeticAsset asset) { return GetFieldValue(CosmeticAssetIdField, asset); } private static List GetIntList(FieldInfo field, MetaManager metaManager) { return GetFieldValue>(field, metaManager) ?? new List(); } private static List> GetIntListList(FieldInfo field, MetaManager metaManager) { return GetFieldValue>>(field, metaManager) ?? new List>(); } private static T GetFieldValue(FieldInfo field, object instance) { if (field == null || instance == null) { return default(T); } object value = field.GetValue(instance); if (value is T) { return (T)value; } return default(T); } private static void SetFieldValue(FieldInfo field, object instance, object value) { if (field != null && instance != null) { field.SetValue(instance, value); } } private static void CopyPresetLists(List> source, List> target) { if (source != null && target != null) { int num = Math.Min(source.Count, target.Count); for (int i = 0; i < num; i++) { target[i] = ((source[i] != null) ? source[i].ToList() : new List()); } } } private static void SetRepoLibMissingList(FieldInfo field, List values) { field?.SetValue(null, values ?? new List()); } private static List> EnsureMissingPresetListSize(int size) { FieldInfo fieldInfo = repoLibMissingCosmeticPresetsField; List> list = (fieldInfo?.GetValue(null) as List>) ?? new List>(); while (list.Count < size) { list.Add(new List()); } for (int i = 0; i < list.Count; i++) { list[i] = list[i] ?? new List(); } fieldInfo?.SetValue(null, list); return list; } private static void SetRepoLibMissingPresetList(List> values) { repoLibMissingCosmeticPresetsField?.SetValue(null, values ?? new List>()); } private void ResetConfigIfVersionChanged() { try { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; string text = ReadConfigPluginVersion(configFilePath); if (!string.IsNullOrWhiteSpace(text) && !(text == "1.0.0")) { ((BaseUnityPlugin)this).Config.Clear(); if (File.Exists(configFilePath)) { File.Delete(configFilePath); } ((BaseUnityPlugin)this).Config.Reload(); ((BaseUnityPlugin)this).Logger.LogWarning((object)"Config version changed. Old config was reset to defaults."); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to reset config by version: " + ex.Message)); } } private static string ReadConfigPluginVersion(string configPath) { if (!File.Exists(configPath)) { return null; } Match match = Regex.Match(File.ReadAllText(configPath), "(?m)^模组版本号\\s*=\\s*(.+?)\\s*$"); if (!match.Success) { return null; } return match.Groups[1].Value.Trim(); } private void DetachFromManager() { ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } } internal sealed class ConfigurationManagerAttributes { public bool? ShowRangeAsPercent; public Action CustomDrawer; public bool? Browsable; public string Category; public object DefaultValue; public bool? HideDefaultButton; public bool? HideSettingName; public string Description; public string DispName; public int? Order; public bool? ReadOnly; public bool? IsAdvanced; } }