using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; 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-RemoveAllCosmetics-1.0.0")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+78877d59e6688a3c44dc2491e364ee0e0878e78d")] [assembly: AssemblyProduct("Zichen-RemoveAllCosmetics-1.0.0")] [assembly: AssemblyTitle("Zichen-RemoveAllCosmetics-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_RemoveAllCosmetics { [BepInPlugin("zichen.removeallcosmetics", "RemoveAllCosmetics", "1.0.0")] public class Plugin : BaseUnityPlugin { private sealed class CompatibilityReport { private readonly List affectedFeatures = new List(); private readonly List details = new List(); public bool AutomaticRemovalAvailable = true; public bool VisualFilterAvailable = true; public bool VisualRefreshAvailable = true; public bool ResultPopupAvailable = true; public bool HasIssues => affectedFeatures.Count > 0; public static CompatibilityReport CreateHealthy() { return new CompatibilityReport(); } public static CompatibilityReport Build() { CompatibilityReport compatibilityReport = new CompatibilityReport(); if ((1u & (RequireField(MetaManagerInstanceField, "MetaManager.instance", compatibilityReport, "启动自动清理") ? 1u : 0u) & (RequireField(MetaSaveReadyField, "MetaManager.saveReady", compatibilityReport, "启动自动清理") ? 1u : 0u) & (RequireField(MetaSavePathField, "MetaManager.savePath", compatibilityReport, "装饰存档写回") ? 1u : 0u) & (RequireField(MetaCosmeticTokensField, "MetaManager.cosmeticTokens", compatibilityReport, "装饰硬币保留") ? 1u : 0u) & (RequireField(MetaCosmeticUnlocksField, "MetaManager.cosmeticUnlocks", compatibilityReport, "解锁装饰清理") ? 1u : 0u) & (RequireField(MetaCosmeticHistoryField, "MetaManager.cosmeticHistory", compatibilityReport, "历史装饰清理") ? 1u : 0u) & (RequireField(MetaCosmeticEquippedField, "MetaManager.cosmeticEquipped", compatibilityReport, "已装备装饰清理") ? 1u : 0u) & (RequireField(MetaCosmeticPresetsField, "MetaManager.cosmeticPresets", compatibilityReport, "装饰预设清理") ? 1u : 0u) & (RequireField(MetaColorPresetsField, "MetaManager.colorPresets", compatibilityReport, "装饰颜色预设清理") ? 1u : 0u) & (RequireField(MetaColorsEquippedField, "MetaManager.colorsEquipped", compatibilityReport, "装饰颜色重置") ? 1u : 0u) & (RequireField(MetaCosmeticAssetsField, "MetaManager.cosmeticAssets", compatibilityReport, "装饰资源索引匹配") ? 1u : 0u) & (RequireField(CosmeticAssetTypeField, "CosmeticAsset.type", compatibilityReport, "装饰类型识别") ? 1u : 0u) & (RequireField(StatsManagerInstanceField, "StatsManager.instance", compatibilityReport, "装饰存档加密写回") ? 1u : 0u) & (RequireField(StatsManagerPasswordField, "StatsManager.totallyNormalString", compatibilityReport, "装饰存档加密写回") ? 1u : 0u)) == 0) { compatibilityReport.AutomaticRemovalAvailable = false; } if (!RequireField(MetaPresetSlotsField, "MetaManager.presetSlots", compatibilityReport, "装饰预设槽数量读取")) { compatibilityReport.details.Add("MetaManager.presetSlots missing; fallback preset slot count 28 will be used."); } if ((1u & (RequireMethod(PlayerCosmeticsSetupCosmeticsLogicMethod, "PlayerCosmetics.SetupCosmeticsLogic(int[], bool)", compatibilityReport, "视觉层装饰过滤") ? 1u : 0u) & (RequireField(MetaCosmeticAssetsField, "MetaManager.cosmeticAssets", compatibilityReport, "视觉层装饰过滤") ? 1u : 0u) & (RequireField(CosmeticAssetTypeField, "CosmeticAsset.type", compatibilityReport, "视觉层装饰过滤") ? 1u : 0u)) == 0) { compatibilityReport.VisualFilterAvailable = false; } if ((1u & (RequireMethod(MetaCosmeticPreviewSetMethod, "MetaManager.CosmeticPreviewSet(bool)", compatibilityReport, "清理后视觉刷新") ? 1u : 0u) & (RequireMethod(MetaCosmeticPlayerUpdateLocalMethod, "MetaManager.CosmeticPlayerUpdateLocal(bool, bool)", compatibilityReport, "清理后视觉刷新") ? 1u : 0u) & (RequireMethod(PlayerCosmeticsSetupCosmeticsMethod, "PlayerCosmetics.SetupCosmetics(bool, bool, List)", compatibilityReport, "清理后视觉刷新") ? 1u : 0u) & (RequireMethod(PlayerCosmeticsSetupColorsMethod, "PlayerCosmetics.SetupColors(bool, int[])", compatibilityReport, "清理后视觉刷新") ? 1u : 0u)) == 0) { compatibilityReport.VisualRefreshAvailable = false; } if ((1u & (RequireField(MenuManagerInstanceField, "MenuManager.instance", compatibilityReport, "启动结果弹窗") ? 1u : 0u) & (RequireField(MenuManagerCurrentMenuPageField, "MenuManager.currentMenuPage", compatibilityReport, "启动结果弹窗") ? 1u : 0u) & (RequireField(MenuManagerPagePopUpScheduledField, "MenuManager.pagePopUpScheduled", compatibilityReport, "启动结果弹窗") ? 1u : 0u) & (RequireField(MenuManagerCurrentMenuPageIndexField, "MenuManager.currentMenuPageIndex", compatibilityReport, "启动结果弹窗") ? 1u : 0u) & (RequireMethod(MenuManagerPagePopUpMethod, "MenuManager.PagePopUp(string, Color, string, string, bool)", compatibilityReport, "启动结果弹窗") ? 1u : 0u)) == 0) { compatibilityReport.ResultPopupAvailable = false; } return compatibilityReport; } public void AddPatchFailure(string featureName, string patchName, string reason) { AddAffectedFeature(featureName); details.Add("Patch failed: " + patchName + " -> " + reason); } public string BuildLogMessage() { if (!HasIssues) { return "Compatibility self-check passed."; } return "Compatibility self-check found possible game API changes. Affected features: " + string.Join(";", affectedFeatures.Distinct().ToArray()); } public string BuildPopupMessage() { if (!HasIssues) { return null; } string text = "检测到游戏接口可能已变化,RemoveAllCosmetics 已进入兼容模式。\n以下功能可能不可用:"; foreach (string item in affectedFeatures.Distinct().Take(6)) { text = text + "\n- " + item; } text += "\n\n为避免损坏存档,缺少关键接口时不会执行清理。"; return text + "\n如需使用这些功能,请等待作者适配最新版本。"; } public string BuildPopupAppendix() { if (!HasIssues) { return null; } string text = "兼容提示:检测到部分游戏接口可能已变化。"; foreach (string item in affectedFeatures.Distinct().Take(4)) { text = text + "\n- " + item; } return text + "\n如清理结果异常,请等待作者适配最新版本。"; } public IEnumerable GetDetailMessages() { return details.Distinct().ToArray(); } private static bool RequireField(FieldInfo field, string apiName, CompatibilityReport report, string affectedFeature) { if (field != null) { return true; } report.AddAffectedFeature(affectedFeature); report.details.Add("Missing field: " + apiName); return false; } private static bool RequireMethod(MethodInfo method, string apiName, CompatibilityReport report, string affectedFeature) { if (method != null) { return true; } report.AddAffectedFeature(affectedFeature); report.details.Add("Missing method: " + apiName); return false; } private void AddAffectedFeature(string feature) { if (!affectedFeatures.Contains(feature)) { affectedFeatures.Add(feature); } } } private sealed class CosmeticSaveData { public string SavePath; public List Tokens; public List Unlocks; public List History; public List Equipped; public List> CosmeticPresets; public List> ColorPresets; public int[] Colors; public List Assets; } [Serializable] private sealed class ExtBackup { public List cosmeticUnlocks = new List(); public List cosmeticEquipped = new List(); public List colorsEquipped = new List(); } [CompilerGenerated] private sealed class d__52 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Plugin <>4__this; private MetaManager 5__2; private bool 5__3; private float 5__4; private int 5__5; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__52(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; Plugin plugin = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; 5__2 = null; 5__3 = false; 5__4 = Time.unscaledTime + 60f; goto IL_009c; case 1: <>1__state = -1; goto IL_009c; case 2: { <>1__state = -1; 5__5++; break; } IL_009c: if (Time.unscaledTime < 5__4) { 5__2 = GetMetaManagerInstance(); if (!(((Object)(object)5__2 != (Object)null && TryGetFieldValue(MetaSaveReadyField, 5__2, out 5__3)) & 5__3)) { <>2__current = null; <>1__state = 1; return true; } } if ((Object)(object)5__2 == (Object)null || !5__3) { plugin.ShowRemovalFailure("等待游戏装饰存档就绪超时,本次未执行清理。"); return false; } 5__5 = 0; break; } if (5__5 < 10) { <>2__current = null; <>1__state = 2; return true; } 5__2 = GetMetaManagerInstance(); if ((Object)(object)5__2 == (Object)null) { plugin.ShowRemovalFailure("MetaManager 在清理前失效,本次未执行清理。"); return false; } if (!TryGetEncryptionPassword(out var encryptionPassword)) { plugin.ShowRemovalFailure("无法读取游戏存档加密密码,本次未修改装饰存档。"); return false; } if (!TryReadCosmeticSaveData(5__2, out var data, out var error)) { plugin.ShowRemovalFailure(error); return false; } ((BaseUnityPlugin)plugin).Logger.LogInfo((object)"=== RemoveAllCosmetics START ==="); int num2 = RemoveMatchingCosmeticIndexes(data.Unlocks, data.Assets, AllRemovalTypes); int num3 = RemoveMatchingCosmeticIndexes(data.History, data.Assets, AllRemovalTypes); int num4 = RemoveMatchingCosmeticIndexesFromPresets(data.CosmeticPresets, data.Assets, AllRemovalTypes); ResetColorsForTypes(data.Colors, AllRemovalTypes); ResetColorPresetsForTypes(data.ColorPresets, AllRemovalTypes); int num5 = RemoveMatchingCosmeticIndexes(data.Equipped, data.Assets, AllRemovalTypes); List finalEquipped = data.Equipped ?? new List(); int[] finalColors = data.Colors ?? CreateEmptyColorsArray(); int presetSlotCount = GetPresetSlotCount(5__2); bool flag = plugin.WriteVanillaMetaSave(data, finalEquipped, finalColors, presetSlotCount, encryptionPassword); bool flag2 = plugin.WriteModdedMetaSave(data.SavePath, finalColors, presetSlotCount, encryptionPassword); plugin.SyncUnlockAllCosmeticsBackup(finalEquipped, finalColors); plugin.RefreshCosmeticVisuals(5__2); ((BaseUnityPlugin)plugin).Logger.LogInfo((object)("=== RemoveAllCosmetics DONE === " + $"equipped={num5}, unlocks={num2}, history={num3}, presetItems={num4}, " + $"tokensKept={data.Tokens?.Count ?? 0}, vanillaSaved={flag}, moddedSaved={flag2}")); string text = (flag ? "已移除全部装饰并保存\n" : "已尝试移除全部装饰,但写入存档失败\n"); text += "本模组每次启动游戏都会移除全部装饰。\n"; text += "如不需要此功能,请卸载本模组。\n"; text += "已保留装饰硬币。\n"; text += $"已装备移除:{num5}件 解锁:{num2} 历史:{num3} 预设:{num4}项"; if (!flag) { text += "\n请查看 BepInEx 日志,确认存档是否被其他程序占用或游戏接口是否已变化。"; } string text2 = _compatibilityReport.BuildPopupAppendix(); if (!string.IsNullOrWhiteSpace(text2)) { text = text + "\n\n" + text2; } Color color = ((_compatibilityReport.HasIssues || !flag) ? Color.yellow : Color.green); TryShowPopup("移除全部装饰", color, text); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__82 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__82(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; goto IL_013a; case 1: { <>1__state = -1; MenuManager menuManagerInstance = GetMenuManagerInstance(); if ((Object)(object)menuManagerInstance != (Object)null && !IsPopupSlotBusy(menuManagerInstance)) { try { Plugin instance = _instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogInfo((object)"Showing popup after menu is ready."); } if (!TryInvoke(MenuManagerPagePopUpMethod, menuManagerInstance, _pendingPopupTitle, _pendingPopupColor, _pendingPopupBody, "OK", false)) { _popupWaiting = false; return false; } _popupShown = true; _popupWaiting = false; } catch (Exception ex) { _popupShown = false; _popupWaiting = false; Plugin instance2 = _instance; if (instance2 != null) { ((BaseUnityPlugin)instance2).Logger.LogWarning((object)("Failed to show popup: " + ex.Message)); } } return false; } goto IL_0123; } case 2: { <>1__state = -1; goto IL_013a; } IL_013a: if (!_popupShown) { MenuManager menuManagerInstance = GetMenuManagerInstance(); if ((Object)(object)menuManagerInstance != (Object)null && !IsPopupSlotBusy(menuManagerInstance)) { <>2__current = null; <>1__state = 1; return true; } goto IL_0123; } _popupWaiting = false; return false; IL_0123: <>2__current = null; <>1__state = 2; return true; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public const string PluginGuid = "zichen.removeallcosmetics"; public const string PluginName = "RemoveAllCosmetics"; public const string PluginVersion = "1.0.0"; private const int MetaReadyTimeoutSeconds = 60; private const int PostReadyDelayFrames = 10; private static Plugin _instance; private static Harmony _harmony; private static CompatibilityReport _compatibilityReport = CompatibilityReport.CreateHealthy(); private static bool _popupShown; private static bool _popupWaiting; private static string _pendingPopupTitle; private static Color _pendingPopupColor; private static string _pendingPopupBody; private static readonly FieldInfo MetaManagerInstanceField = AccessTools.Field(typeof(MetaManager), "instance"); private static readonly FieldInfo MetaSaveReadyField = AccessTools.Field(typeof(MetaManager), "saveReady"); private static readonly FieldInfo MetaSavePathField = AccessTools.Field(typeof(MetaManager), "savePath"); private static readonly FieldInfo MetaCosmeticTokensField = AccessTools.Field(typeof(MetaManager), "cosmeticTokens"); 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 MetaCosmeticAssetsField = AccessTools.Field(typeof(MetaManager), "cosmeticAssets"); private static readonly FieldInfo MetaPresetSlotsField = AccessTools.Field(typeof(MetaManager), "presetSlots"); private static readonly FieldInfo CosmeticAssetTypeField = AccessTools.Field(typeof(CosmeticAsset), "type"); private static readonly FieldInfo StatsManagerInstanceField = AccessTools.Field(typeof(StatsManager), "instance"); private static readonly FieldInfo StatsManagerPasswordField = AccessTools.Field(typeof(StatsManager), "totallyNormalString"); private static readonly FieldInfo MenuManagerInstanceField = AccessTools.Field(typeof(MenuManager), "instance"); private static readonly FieldInfo MenuManagerPagePopUpScheduledField = AccessTools.Field(typeof(MenuManager), "pagePopUpScheduled"); private static readonly FieldInfo MenuManagerCurrentMenuPageIndexField = AccessTools.Field(typeof(MenuManager), "currentMenuPageIndex"); private static readonly FieldInfo MenuManagerCurrentMenuPageField = AccessTools.Field(typeof(MenuManager), "currentMenuPage"); private static readonly MethodInfo PlayerCosmeticsSetupCosmeticsLogicMethod = AccessTools.Method(typeof(PlayerCosmetics), "SetupCosmeticsLogic", new Type[2] { typeof(int[]), typeof(bool) }, (Type[])null); private static readonly MethodInfo PlayerCosmeticsSetupCosmeticsMethod = AccessTools.Method(typeof(PlayerCosmetics), "SetupCosmetics", new Type[3] { typeof(bool), typeof(bool), typeof(List) }, (Type[])null); private static readonly MethodInfo PlayerCosmeticsSetupColorsMethod = AccessTools.Method(typeof(PlayerCosmetics), "SetupColors", new Type[2] { typeof(bool), typeof(int[]) }, (Type[])null); private static readonly MethodInfo MetaCosmeticPreviewSetMethod = AccessTools.Method(typeof(MetaManager), "CosmeticPreviewSet", new Type[1] { typeof(bool) }, (Type[])null); private static readonly MethodInfo MetaCosmeticPlayerUpdateLocalMethod = AccessTools.Method(typeof(MetaManager), "CosmeticPlayerUpdateLocal", new Type[2] { typeof(bool), typeof(bool) }, (Type[])null); private static readonly MethodInfo MenuManagerPagePopUpMethod = AccessTools.Method(typeof(MenuManager), "PagePopUp", new Type[5] { typeof(string), typeof(Color), typeof(string), typeof(string), typeof(bool) }, (Type[])null); private static readonly MethodInfo SetupCosmeticsLogicPrefixMethod = AccessTools.Method(typeof(Plugin), "SetupCosmeticsLogic_Prefix", (Type[])null, (Type[])null); private static readonly HashSet HeadTypes = new HashSet { (CosmeticType)0, (CosmeticType)5, (CosmeticType)6, (CosmeticType)14, (CosmeticType)15, (CosmeticType)17, (CosmeticType)18, (CosmeticType)24, (CosmeticType)25, (CosmeticType)30, (CosmeticType)31, (CosmeticType)32 }; private static readonly HashSet BodyTypes = new HashSet { (CosmeticType)7, (CosmeticType)8, (CosmeticType)16, (CosmeticType)20, (CosmeticType)21, (CosmeticType)23 }; private static readonly HashSet ArmsTypes = new HashSet { (CosmeticType)1, (CosmeticType)2, (CosmeticType)9, (CosmeticType)10, (CosmeticType)26, (CosmeticType)27 }; private static readonly HashSet LegsFeetTypes = new HashSet { (CosmeticType)3, (CosmeticType)4, (CosmeticType)11, (CosmeticType)12, (CosmeticType)19, (CosmeticType)22, (CosmeticType)28, (CosmeticType)29 }; private static readonly HashSet GrabberTypes = new HashSet { (CosmeticType)13 }; private static readonly HashSet AllRemovalTypes = BuildAllRemovalSet(); private void Awake() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown _instance = this; DetachFromManager(); _compatibilityReport = CompatibilityReport.Build(); _harmony = new Harmony("zichen.removeallcosmetics.patch"); PatchHarmonySafely(); LogCompatibilityReport(); StartAutomaticRemoval(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"RemoveAllCosmetics v1.0.0 loaded."); } private void OnDestroy() { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Harmony unpatch failed: " + ex.Message)); } _harmony = null; if (_instance == this) { _instance = null; } } private void DetachFromManager() { ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } private void PatchHarmonySafely() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown if (!_compatibilityReport.VisualFilterAvailable) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Skipped visual cosmetic filter patch because compatibility self-check failed."); return; } try { _harmony.Patch((MethodBase)PlayerCosmeticsSetupCosmeticsLogicMethod, new HarmonyMethod(SetupCosmeticsLogicPrefixMethod), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch (Exception ex) { _compatibilityReport.AddPatchFailure("视觉层装饰过滤", "PlayerCosmetics.SetupCosmeticsLogic", ex.Message); _compatibilityReport.VisualFilterAvailable = false; ((BaseUnityPlugin)this).Logger.LogWarning((object)("Skipped visual cosmetic filter patch: " + ex.Message)); } } private void LogCompatibilityReport() { if (!_compatibilityReport.HasIssues) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Compatibility self-check passed."); return; } ((BaseUnityPlugin)this).Logger.LogWarning((object)_compatibilityReport.BuildLogMessage()); foreach (string detailMessage in _compatibilityReport.GetDetailMessages()) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Compatibility detail: " + detailMessage)); } } private static void SetupCosmeticsLogic_Prefix(ref int[] _cosmeticEquipped) { if (!_compatibilityReport.VisualFilterAvailable) { return; } try { if (_cosmeticEquipped == null || _cosmeticEquipped.Length == 0) { return; } List cosmeticAssets = GetCosmeticAssets(GetMetaManagerInstance()); if (cosmeticAssets == null || cosmeticAssets.Count == 0) { return; } List list = new List(_cosmeticEquipped.Length); int[] array = _cosmeticEquipped; foreach (int num in array) { if (!ShouldRemoveCosmeticIndex(num, cosmeticAssets, AllRemovalTypes)) { list.Add(num); } } if (list.Count != _cosmeticEquipped.Length) { Plugin instance = _instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogInfo((object)$"[SetupCosmeticsLogic] filtered {_cosmeticEquipped.Length} -> {list.Count}"); } _cosmeticEquipped = list.ToArray(); } } catch (Exception ex) { Plugin instance2 = _instance; if (instance2 != null) { ((BaseUnityPlugin)instance2).Logger.LogWarning((object)("[SetupCosmeticsLogic] visual filter failed: " + ex.Message)); } } } private void StartAutomaticRemoval() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) _popupShown = false; _popupWaiting = false; if (!_compatibilityReport.AutomaticRemovalAvailable) { string body = _compatibilityReport.BuildPopupMessage(); ((BaseUnityPlugin)this).Logger.LogWarning((object)"Automatic cosmetic removal is disabled by compatibility self-check."); TryShowPopup("RemoveAllCosmetics 兼容提示", Color.yellow, body); } else { ((MonoBehaviour)this).StartCoroutine(NukeCosmetics()); } } [IteratorStateMachine(typeof(d__52))] private IEnumerator NukeCosmetics() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__52(0) { <>4__this = this }; } private static bool TryReadCosmeticSaveData(MetaManager meta, out CosmeticSaveData data, out string error) { data = null; error = null; if ((Object)(object)meta == (Object)null) { error = "MetaManager 不可用,本次未执行清理。"; return false; } List cosmeticAssets = GetCosmeticAssets(meta); if (cosmeticAssets == null) { error = "无法读取游戏装饰资源列表,本次未执行清理。"; return false; } if (!TryGetFieldValue(MetaSavePathField, meta, out var value) || string.IsNullOrWhiteSpace(value)) { error = "无法读取装饰存档路径,本次未修改存档。"; return false; } TryGetFieldValue>(MetaCosmeticTokensField, meta, out var value2); List value3; bool num = TryGetFieldValue>(MetaCosmeticUnlocksField, meta, out value3); List value4; bool flag = TryGetFieldValue>(MetaCosmeticHistoryField, meta, out value4); List value5; bool flag2 = TryGetFieldValue>(MetaCosmeticEquippedField, meta, out value5); List> value6; bool flag3 = TryGetFieldValue>>(MetaCosmeticPresetsField, meta, out value6); List> value7; bool flag4 = TryGetFieldValue>>(MetaColorPresetsField, meta, out value7); int[] value8; bool flag5 = TryGetFieldValue(MetaColorsEquippedField, meta, out value8); if (!num || !flag || !flag2 || !flag3 || !flag4 || !flag5) { error = "游戏装饰存档结构可能已变化,本次未修改存档。"; return false; } data = new CosmeticSaveData { SavePath = value, Tokens = value2, Unlocks = value3, History = value4, Equipped = value5, CosmeticPresets = value6, ColorPresets = value7, Colors = value8, Assets = cosmeticAssets }; return true; } private bool WriteVanillaMetaSave(CosmeticSaveData saveData, List finalEquipped, int[] finalColors, int presetSlotCount, string encryptionPassword) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_0017: Unknown result type (might be due to invalid IL or missing references) try { ES3Settings val = new ES3Settings(new Enum[1] { (Enum)(object)(Location)4 }); val.encryptionType = (EncryptionType)1; val.encryptionPassword = encryptionPassword; val.path = saveData.SavePath + ".es3"; List list = saveData.Tokens ?? TryLoadTokensFromSave(val); if (list != null) { ES3.Save>("cosmeticTokens", list, val); } ES3.Save>("cosmeticUnlocks", saveData.Unlocks ?? new List(), val); ES3.Save>("cosmeticHistory", saveData.History ?? new List(), val); ES3.Save>("cosmeticEquipped", finalEquipped ?? new List(), val); ES3.Save>>("cosmeticPresets", saveData.CosmeticPresets ?? CreateEmptyIntPresetSlots(presetSlotCount), val); ES3.Save>>("colorPresets", saveData.ColorPresets ?? CreateEmptyIntPresetSlots(presetSlotCount), val); ES3.Save("colorsEquipped", finalColors ?? CreateEmptyColorsArray(), val); ES3.StoreCachedFile(val); ((BaseUnityPlugin)this).Logger.LogInfo((object)($"ES3 write {val.path}: tokensKept={list?.Count ?? 0}, " + $"unlocks={saveData.Unlocks?.Count ?? 0}, history={saveData.History?.Count ?? 0}, equipped={finalEquipped?.Count ?? 0}")); return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("ES3 write MetaSave failed: " + ex)); return false; } } private bool WriteModdedMetaSave(string savePath, int[] finalColors, int presetSlotCount, string encryptionPassword) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown try { ES3Settings val = new ES3Settings(savePath + "Modded.es3", (EncryptionType)1, encryptionPassword, (ES3Settings)null); if (!ES3.FileExists(val)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"MetaSaveModded.es3 not found, skipping."); return false; } ES3.Save>("cosmeticUnlocks", new List(), val); ES3.Save>("cosmeticHistory", new List(), val); ES3.Save>("cosmeticEquipped", new List(), val); ES3.Save>>("cosmeticPresets", CreateEmptyStringPresetSlots(presetSlotCount), val); ES3.Save>>("colorPresets", CreateEmptyIntPresetSlots(presetSlotCount), val); ES3.Save("colorsEquipped", finalColors ?? CreateEmptyColorsArray(), val); ((BaseUnityPlugin)this).Logger.LogInfo((object)"ES3 write MetaSaveModded.es3: cosmetic data cleared."); return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("ES3 write MetaSaveModded failed: " + ex.Message)); return false; } } private void SyncUnlockAllCosmeticsBackup(List finalEquipped, int[] finalColors) { try { string path = Path.Combine(Paths.ConfigPath, "UnlockAllCosmetics_save.json"); if (File.Exists(path)) { string text = File.ReadAllText(path); if (!string.IsNullOrWhiteSpace(text)) { ExtBackup extBackup = JsonUtility.FromJson(text) ?? new ExtBackup(); extBackup.cosmeticUnlocks = new List(); extBackup.cosmeticEquipped = ((finalEquipped != null) ? new List(finalEquipped) : new List()); extBackup.colorsEquipped = ((finalColors != null) ? finalColors.ToList() : new List()); File.WriteAllText(path, JsonUtility.ToJson((object)extBackup)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"UnlockAllCosmetics_save.json synced."); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Sync UnlockAllCosmetics backup failed: " + ex.Message)); } } private void RefreshCosmeticVisuals(MetaManager meta) { if (!_compatibilityReport.VisualRefreshAvailable) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Skipped cosmetic visual refresh because compatibility self-check failed."); return; } TryInvoke(MetaCosmeticPreviewSetMethod, meta, false); TryInvoke(MetaCosmeticPlayerUpdateLocalMethod, meta, true, true); PlayerCosmetics[] array = Object.FindObjectsOfType(); foreach (PlayerCosmetics val in array) { if (!((Object)(object)val == (Object)null)) { TryInvoke(PlayerCosmeticsSetupCosmeticsMethod, val, false, true, null); TryInvoke(PlayerCosmeticsSetupColorsMethod, val, false, null); } } } private static List TryLoadTokensFromSave(ES3Settings settings) { try { return ES3.KeyExists("cosmeticTokens", settings) ? ES3.Load>("cosmeticTokens", settings) : null; } catch { return null; } } private void ShowRemovalFailure(string reason) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) ((BaseUnityPlugin)this).Logger.LogWarning((object)reason); string text = reason + "\n"; text += "本模组每次启动游戏都会尝试移除全部装饰。\n"; text += "但当前游戏接口可能已变化,为避免损坏存档,本次没有执行清理。\n"; text += "如不需要此功能,请卸载本模组。"; string text2 = _compatibilityReport.BuildPopupAppendix(); if (!string.IsNullOrWhiteSpace(text2)) { text = text + "\n\n" + text2; } TryShowPopup("RemoveAllCosmetics 兼容提示", Color.yellow, text); } private static int RemoveMatchingCosmeticIndexes(List indexes, List assets, HashSet typesToRemove) { if (indexes == null || assets == null || typesToRemove == null || typesToRemove.Count == 0) { return 0; } int num = 0; for (int num2 = indexes.Count - 1; num2 >= 0; num2--) { if (ShouldRemoveCosmeticIndex(indexes[num2], assets, typesToRemove)) { indexes.RemoveAt(num2); num++; } } return num; } private static int RemoveMatchingCosmeticIndexesFromPresets(List> presets, List assets, HashSet typesToRemove) { if (presets == null) { return 0; } int num = 0; foreach (List preset in presets) { num += RemoveMatchingCosmeticIndexes(preset, assets, typesToRemove); } return num; } private static bool ShouldRemoveCosmeticIndex(int index, List assets, HashSet typesToRemove) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (index < 0 || assets == null || index >= assets.Count) { return false; } if (TryGetCosmeticType(assets[index], out var type)) { return typesToRemove.Contains(type); } return false; } private static void ResetColorsForTypes(int[] colors, HashSet typesToRemove) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected I4, but got Unknown if (colors == null || typesToRemove == null) { return; } foreach (CosmeticType item in typesToRemove) { int num = (int)item; if (num >= 0 && num < colors.Length) { colors[num] = 0; } } } private static void ResetColorPresetsForTypes(List> colorPresets, HashSet typesToRemove) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected I4, but got Unknown if (colorPresets == null || typesToRemove == null) { return; } foreach (List colorPreset in colorPresets) { if (colorPreset == null) { continue; } foreach (CosmeticType item in typesToRemove) { int num = (int)item; if (num >= 0 && num < colorPreset.Count) { colorPreset[num] = 0; } } } } private static int GetPresetSlotCount(MetaManager meta) { if (TryGetFieldValue(MetaPresetSlotsField, meta, out var value) && value > 0) { return value; } return 28; } private static List> CreateEmptyIntPresetSlots(int count) { List> list = new List>(); for (int i = 0; i < count; i++) { list.Add(new List()); } return list; } private static List> CreateEmptyStringPresetSlots(int count) { List> list = new List>(); for (int i = 0; i < count; i++) { list.Add(new List()); } return list; } private static int[] CreateEmptyColorsArray() { return new int[Enum.GetValues(typeof(CosmeticType)).Length]; } private static HashSet BuildAllRemovalSet() { HashSet hashSet = new HashSet(); hashSet.UnionWith(HeadTypes); hashSet.UnionWith(BodyTypes); hashSet.UnionWith(ArmsTypes); hashSet.UnionWith(LegsFeetTypes); hashSet.UnionWith(GrabberTypes); return hashSet; } private static bool TryGetFieldValue(FieldInfo field, object instance, out T value) { value = default(T); if (field == null || instance == null) { return false; } try { object value2 = field.GetValue(instance); if (value2 is T) { T val = (T)value2; value = val; return true; } } catch { return false; } return false; } private static List GetCosmeticAssets(MetaManager meta) { if (!TryGetFieldValue>(MetaCosmeticAssetsField, meta, out var value)) { return null; } return value; } private static MetaManager GetMetaManagerInstance() { if (!TryGetStaticFieldValue(MetaManagerInstanceField, out var value)) { return null; } return value; } private static StatsManager GetStatsManagerInstance() { if (!TryGetStaticFieldValue(StatsManagerInstanceField, out var value)) { return null; } return value; } private static MenuManager GetMenuManagerInstance() { if (!TryGetStaticFieldValue(MenuManagerInstanceField, out var value)) { return null; } return value; } private static bool TryGetStaticFieldValue(FieldInfo field, out T value) { value = default(T); if (field == null) { return false; } try { object value2 = field.GetValue(null); if (value2 is T) { T val = (T)value2; value = val; return true; } } catch { return false; } return false; } private static bool TryGetCosmeticType(CosmeticAsset asset, out CosmeticType type) { type = (CosmeticType)0; return TryGetFieldValue(CosmeticAssetTypeField, asset, out type); } private static bool TryGetEncryptionPassword(out string encryptionPassword) { encryptionPassword = null; try { StatsManager statsManagerInstance = GetStatsManagerInstance(); if ((Object)(object)statsManagerInstance != (Object)null && TryGetFieldValue(StatsManagerPasswordField, statsManagerInstance, out var value) && !string.IsNullOrWhiteSpace(value)) { encryptionPassword = value; return true; } } catch { return false; } return false; } private static bool TryInvoke(MethodInfo method, object instance, params object[] args) { if (method == null || instance == null) { return false; } try { method.Invoke(instance, args); return true; } catch (Exception ex) { Plugin instance2 = _instance; if (instance2 != null) { ((BaseUnityPlugin)instance2).Logger.LogWarning((object)("Invoke failed: " + method.Name + " -> " + ex.Message)); } return false; } } private static bool IsPopupSlotBusy(MenuManager menuManager) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Invalid comparison between Unknown and I4 //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Invalid comparison between Unknown and I4 if (!_compatibilityReport.ResultPopupAvailable || (Object)(object)menuManager == (Object)null) { return true; } if (!TryGetFieldValue(MenuManagerCurrentMenuPageField, menuManager, out var value) || (Object)(object)value == (Object)null) { return true; } if (!TryGetFieldValue(MenuManagerPagePopUpScheduledField, menuManager, out var value2) || value2) { return true; } if (!TryGetFieldValue(MenuManagerCurrentMenuPageIndexField, menuManager, out var value3)) { return true; } if ((int)value3 != 9) { return (int)value3 == 7; } return true; } private static void TryShowPopup(string title, Color color, string body) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (_popupShown) { return; } if (!_compatibilityReport.ResultPopupAvailable) { Plugin instance = _instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("Popup skipped because MenuManager popup API is unavailable. Message: " + body)); } } else { StartPopupWait(title, color, body); } } private static void StartPopupWait(string title, Color color, string body) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (!_popupWaiting && !((Object)(object)_instance == (Object)null)) { _popupWaiting = true; _pendingPopupTitle = title; _pendingPopupColor = color; _pendingPopupBody = body; ((MonoBehaviour)_instance).StartCoroutine(WaitAndShowPopup()); } } [IteratorStateMachine(typeof(d__82))] private static IEnumerator WaitAndShowPopup() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__82(0); } } }