Decompiled source of RemoveAllCosmetics v1.0.0

Zichen-RemoveAllCosmetics-1.0.0.dll

Decompiled 11 hours ago
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<string> affectedFeatures = new List<string>();

			private readonly List<string> details = new List<string>();

			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<int>)", 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<string> 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<int> Tokens;

			public List<int> Unlocks;

			public List<int> History;

			public List<int> Equipped;

			public List<List<int>> CosmeticPresets;

			public List<List<int>> ColorPresets;

			public int[] Colors;

			public List<CosmeticAsset> Assets;
		}

		[Serializable]
		private sealed class ExtBackup
		{
			public List<int> cosmeticUnlocks = new List<int>();

			public List<int> cosmeticEquipped = new List<int>();

			public List<int> colorsEquipped = new List<int>();
		}

		[CompilerGenerated]
		private sealed class <NukeCosmetics>d__52 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Plugin <>4__this;

			private MetaManager <meta>5__2;

			private bool <saveReady>5__3;

			private float <deadline>5__4;

			private int <i>5__5;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <NukeCosmetics>d__52(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<meta>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;
					<meta>5__2 = null;
					<saveReady>5__3 = false;
					<deadline>5__4 = Time.unscaledTime + 60f;
					goto IL_009c;
				case 1:
					<>1__state = -1;
					goto IL_009c;
				case 2:
					{
						<>1__state = -1;
						<i>5__5++;
						break;
					}
					IL_009c:
					if (Time.unscaledTime < <deadline>5__4)
					{
						<meta>5__2 = GetMetaManagerInstance();
						if (!(((Object)(object)<meta>5__2 != (Object)null && TryGetFieldValue<bool>(MetaSaveReadyField, <meta>5__2, out <saveReady>5__3)) & <saveReady>5__3))
						{
							<>2__current = null;
							<>1__state = 1;
							return true;
						}
					}
					if ((Object)(object)<meta>5__2 == (Object)null || !<saveReady>5__3)
					{
						plugin.ShowRemovalFailure("等待游戏装饰存档就绪超时,本次未执行清理。");
						return false;
					}
					<i>5__5 = 0;
					break;
				}
				if (<i>5__5 < 10)
				{
					<>2__current = null;
					<>1__state = 2;
					return true;
				}
				<meta>5__2 = GetMetaManagerInstance();
				if ((Object)(object)<meta>5__2 == (Object)null)
				{
					plugin.ShowRemovalFailure("MetaManager 在清理前失效,本次未执行清理。");
					return false;
				}
				if (!TryGetEncryptionPassword(out var encryptionPassword))
				{
					plugin.ShowRemovalFailure("无法读取游戏存档加密密码,本次未修改装饰存档。");
					return false;
				}
				if (!TryReadCosmeticSaveData(<meta>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<int> finalEquipped = data.Equipped ?? new List<int>();
				int[] finalColors = data.Colors ?? CreateEmptyColorsArray();
				int presetSlotCount = GetPresetSlotCount(<meta>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(<meta>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 <WaitAndShowPopup>d__82 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <WaitAndShowPopup>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<int>)
		}, (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<CosmeticType> HeadTypes = new HashSet<CosmeticType>
		{
			(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<CosmeticType> BodyTypes = new HashSet<CosmeticType>
		{
			(CosmeticType)7,
			(CosmeticType)8,
			(CosmeticType)16,
			(CosmeticType)20,
			(CosmeticType)21,
			(CosmeticType)23
		};

		private static readonly HashSet<CosmeticType> ArmsTypes = new HashSet<CosmeticType>
		{
			(CosmeticType)1,
			(CosmeticType)2,
			(CosmeticType)9,
			(CosmeticType)10,
			(CosmeticType)26,
			(CosmeticType)27
		};

		private static readonly HashSet<CosmeticType> LegsFeetTypes = new HashSet<CosmeticType>
		{
			(CosmeticType)3,
			(CosmeticType)4,
			(CosmeticType)11,
			(CosmeticType)12,
			(CosmeticType)19,
			(CosmeticType)22,
			(CosmeticType)28,
			(CosmeticType)29
		};

		private static readonly HashSet<CosmeticType> GrabberTypes = new HashSet<CosmeticType> { (CosmeticType)13 };

		private static readonly HashSet<CosmeticType> 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<CosmeticAsset> cosmeticAssets = GetCosmeticAssets(GetMetaManagerInstance());
				if (cosmeticAssets == null || cosmeticAssets.Count == 0)
				{
					return;
				}
				List<int> list = new List<int>(_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(<NukeCosmetics>d__52))]
		private IEnumerator NukeCosmetics()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <NukeCosmetics>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<CosmeticAsset> cosmeticAssets = GetCosmeticAssets(meta);
			if (cosmeticAssets == null)
			{
				error = "无法读取游戏装饰资源列表,本次未执行清理。";
				return false;
			}
			if (!TryGetFieldValue<string>(MetaSavePathField, meta, out var value) || string.IsNullOrWhiteSpace(value))
			{
				error = "无法读取装饰存档路径,本次未修改存档。";
				return false;
			}
			TryGetFieldValue<List<int>>(MetaCosmeticTokensField, meta, out var value2);
			List<int> value3;
			bool num = TryGetFieldValue<List<int>>(MetaCosmeticUnlocksField, meta, out value3);
			List<int> value4;
			bool flag = TryGetFieldValue<List<int>>(MetaCosmeticHistoryField, meta, out value4);
			List<int> value5;
			bool flag2 = TryGetFieldValue<List<int>>(MetaCosmeticEquippedField, meta, out value5);
			List<List<int>> value6;
			bool flag3 = TryGetFieldValue<List<List<int>>>(MetaCosmeticPresetsField, meta, out value6);
			List<List<int>> value7;
			bool flag4 = TryGetFieldValue<List<List<int>>>(MetaColorPresetsField, meta, out value7);
			int[] value8;
			bool flag5 = TryGetFieldValue<int[]>(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<int> 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<int> list = saveData.Tokens ?? TryLoadTokensFromSave(val);
				if (list != null)
				{
					ES3.Save<List<int>>("cosmeticTokens", list, val);
				}
				ES3.Save<List<int>>("cosmeticUnlocks", saveData.Unlocks ?? new List<int>(), val);
				ES3.Save<List<int>>("cosmeticHistory", saveData.History ?? new List<int>(), val);
				ES3.Save<List<int>>("cosmeticEquipped", finalEquipped ?? new List<int>(), val);
				ES3.Save<List<List<int>>>("cosmeticPresets", saveData.CosmeticPresets ?? CreateEmptyIntPresetSlots(presetSlotCount), val);
				ES3.Save<List<List<int>>>("colorPresets", saveData.ColorPresets ?? CreateEmptyIntPresetSlots(presetSlotCount), val);
				ES3.Save<int[]>("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<List<string>>("cosmeticUnlocks", new List<string>(), val);
				ES3.Save<List<string>>("cosmeticHistory", new List<string>(), val);
				ES3.Save<List<string>>("cosmeticEquipped", new List<string>(), val);
				ES3.Save<List<List<string>>>("cosmeticPresets", CreateEmptyStringPresetSlots(presetSlotCount), val);
				ES3.Save<List<List<int>>>("colorPresets", CreateEmptyIntPresetSlots(presetSlotCount), val);
				ES3.Save<int[]>("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<int> 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<ExtBackup>(text) ?? new ExtBackup();
						extBackup.cosmeticUnlocks = new List<int>();
						extBackup.cosmeticEquipped = ((finalEquipped != null) ? new List<int>(finalEquipped) : new List<int>());
						extBackup.colorsEquipped = ((finalColors != null) ? finalColors.ToList() : new List<int>());
						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<PlayerCosmetics>();
			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<int> TryLoadTokensFromSave(ES3Settings settings)
		{
			try
			{
				return ES3.KeyExists("cosmeticTokens", settings) ? ES3.Load<List<int>>("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<int> indexes, List<CosmeticAsset> assets, HashSet<CosmeticType> 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<List<int>> presets, List<CosmeticAsset> assets, HashSet<CosmeticType> typesToRemove)
		{
			if (presets == null)
			{
				return 0;
			}
			int num = 0;
			foreach (List<int> preset in presets)
			{
				num += RemoveMatchingCosmeticIndexes(preset, assets, typesToRemove);
			}
			return num;
		}

		private static bool ShouldRemoveCosmeticIndex(int index, List<CosmeticAsset> assets, HashSet<CosmeticType> 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<CosmeticType> 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<List<int>> colorPresets, HashSet<CosmeticType> 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<int> 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<int>(MetaPresetSlotsField, meta, out var value) && value > 0)
			{
				return value;
			}
			return 28;
		}

		private static List<List<int>> CreateEmptyIntPresetSlots(int count)
		{
			List<List<int>> list = new List<List<int>>();
			for (int i = 0; i < count; i++)
			{
				list.Add(new List<int>());
			}
			return list;
		}

		private static List<List<string>> CreateEmptyStringPresetSlots(int count)
		{
			List<List<string>> list = new List<List<string>>();
			for (int i = 0; i < count; i++)
			{
				list.Add(new List<string>());
			}
			return list;
		}

		private static int[] CreateEmptyColorsArray()
		{
			return new int[Enum.GetValues(typeof(CosmeticType)).Length];
		}

		private static HashSet<CosmeticType> BuildAllRemovalSet()
		{
			HashSet<CosmeticType> hashSet = new HashSet<CosmeticType>();
			hashSet.UnionWith(HeadTypes);
			hashSet.UnionWith(BodyTypes);
			hashSet.UnionWith(ArmsTypes);
			hashSet.UnionWith(LegsFeetTypes);
			hashSet.UnionWith(GrabberTypes);
			return hashSet;
		}

		private static bool TryGetFieldValue<T>(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<CosmeticAsset> GetCosmeticAssets(MetaManager meta)
		{
			if (!TryGetFieldValue<List<CosmeticAsset>>(MetaCosmeticAssetsField, meta, out var value))
			{
				return null;
			}
			return value;
		}

		private static MetaManager GetMetaManagerInstance()
		{
			if (!TryGetStaticFieldValue<MetaManager>(MetaManagerInstanceField, out var value))
			{
				return null;
			}
			return value;
		}

		private static StatsManager GetStatsManagerInstance()
		{
			if (!TryGetStaticFieldValue<StatsManager>(StatsManagerInstanceField, out var value))
			{
				return null;
			}
			return value;
		}

		private static MenuManager GetMenuManagerInstance()
		{
			if (!TryGetStaticFieldValue<MenuManager>(MenuManagerInstanceField, out var value))
			{
				return null;
			}
			return value;
		}

		private static bool TryGetStaticFieldValue<T>(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<CosmeticType>(CosmeticAssetTypeField, asset, out type);
		}

		private static bool TryGetEncryptionPassword(out string encryptionPassword)
		{
			encryptionPassword = null;
			try
			{
				StatsManager statsManagerInstance = GetStatsManagerInstance();
				if ((Object)(object)statsManagerInstance != (Object)null && TryGetFieldValue<string>(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<MenuPage>(MenuManagerCurrentMenuPageField, menuManager, out var value) || (Object)(object)value == (Object)null)
			{
				return true;
			}
			if (!TryGetFieldValue<bool>(MenuManagerPagePopUpScheduledField, menuManager, out var value2) || value2)
			{
				return true;
			}
			if (!TryGetFieldValue<MenuPageIndex>(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(<WaitAndShowPopup>d__82))]
		private static IEnumerator WaitAndShowPopup()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <WaitAndShowPopup>d__82(0);
		}
	}
}