Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CosmeticPresetExtender v4.0.0
CosmeticPresetExtender.dll
Decompiled 14 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("REPOJP")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("zabuMod")] [assembly: AssemblyTitle("zabuMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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 REPOJP.CosmeticPresetExtender { [BepInPlugin("REPOJP.CosmeticPresetExtender", "CosmeticPresetExtender", "4.0.0")] public class CosmeticPresetExtenderPlugin : BaseUnityPlugin { [Serializable] private class ExtendedPresetStore { public int version = 2; public int columns = 7; public int vanillaSlots = 28; public int currentRows = 10; public int currentSlots = 70; public string updatedAtUtc = ""; public List<ExtendedPresetEntry> presets = new List<ExtendedPresetEntry>(); public List<LegacyPresetEntry> cosmeticPresets = new List<LegacyPresetEntry>(); public List<LegacyPresetEntry> colorPresets = new List<LegacyPresetEntry>(); } [Serializable] private class ExtendedPresetEntry { public int index; public List<int> cosmetics = new List<int>(); public List<int> colors = new List<int>(); public string updatedAtUtc = ""; public string hash = ""; public ExtendedPresetEntry() { } public ExtendedPresetEntry(int index, List<int> cosmetics, List<int> colors, string updatedAtUtc, string hash) { this.index = index; this.cosmetics = CopyValues(cosmetics); this.colors = CopyValues(colors); this.updatedAtUtc = updatedAtUtc; this.hash = (string.IsNullOrEmpty(hash) ? BuildPresetHash(cosmetics, colors) : hash); } } [Serializable] private class LegacyPresetEntry { public int index; public List<int> values = new List<int>(); public LegacyPresetEntry() { } public LegacyPresetEntry(int index, List<int> values) { this.index = index; this.values = CopyValues(values); } } private class SaveState { public string reason; public int targetSlots; public List<List<int>> restoreCosmeticPresets; public List<List<int>> restoreColorPresets; } [HarmonyPatch(typeof(MetaManager), "Awake")] private static class MetaManagerAwakePatch { private static void Prefix(MetaManager __instance) { if (!IsEnabled()) { return; } try { SetPresetSlotsField(__instance, GetTargetSlots()); } catch (Exception ex) { WriteFailureLog("MetaManager.Awake Prefix", ex); } } private static void Postfix(MetaManager __instance) { EnsurePresetRuntimeSlots(__instance, mergeExtendedStore: false, "MetaManager.Awake Postfix"); } } [HarmonyPatch(typeof(MetaManager), "Load")] private static class MetaManagerLoadPatch { private static void Prefix(MetaManager __instance) { EnsurePresetRuntimeSlots(__instance, mergeExtendedStore: false, "MetaManager.Load Prefix"); } private static void Postfix(MetaManager __instance) { EnsurePresetRuntimeSlots(__instance, mergeExtendedStore: true, "MetaManager.Load Postfix"); } } [HarmonyPatch(typeof(MetaManager), "Save")] private static class MetaManagerSavePatch { private static void Prefix(MetaManager __instance, ref SaveState __state) { if (!IsEnabled() || (Object)(object)__instance == (Object)null) { return; } try { EnsurePresetRuntimeSlots(__instance, mergeExtendedStore: false, "MetaManager.Save Prefix"); __state = BuildSaveState(__instance, insideMetaReset ? "MetaManager.Save inside Reset" : "MetaManager.Save"); if (__state == null) { return; } if (!insideMetaReset || !ProtectExtendedSlotsOnReset()) { SaveExtendedStoreFromRuntime(__instance, __state.restoreCosmeticPresets, __state.restoreColorPresets, GetTargetSlots(), createHistory: false, __state.reason); } if (insideMetaReset && ProtectExtendedSlotsOnReset()) { ExtendedPresetStore extendedPresetStore = LoadExtendedStore(allowBackupRecovery: true); NormalizeStore(extendedPresetStore); Dictionary<int, ExtendedPresetEntry> dictionary = ToEntryMap(extendedPresetStore.presets); for (int i = 28; i < __state.targetSlots; i++) { __state.restoreCosmeticPresets[i] = new List<int>(); __state.restoreColorPresets[i] = new List<int>(); if (dictionary.ContainsKey(i)) { __state.restoreCosmeticPresets[i] = CopyValues(dictionary[i].cosmetics); __state.restoreColorPresets[i] = CopyValues(dictionary[i].colors); } } } PrepareVanillaOnlySave(__instance, __state); } catch (Exception ex) { WriteFailureLog("MetaManager.Save Prefix", ex); } } private static Exception Finalizer(MetaManager __instance, SaveState __state, Exception __exception) { try { if (IsEnabled() && __state != null) { RestoreRuntimeAfterVanillaSave(__instance, __state); } } catch (Exception ex) { WriteFailureLog("MetaManager.Save Finalizer", ex); } return __exception; } } [HarmonyPatch(typeof(MetaManager), "Reset")] private static class MetaManagerResetPatch { private static void Prefix(MetaManager __instance) { if (!IsEnabled()) { return; } try { EnsurePresetRuntimeSlots(__instance, mergeExtendedStore: false, "MetaManager.Reset Prefix"); SaveExtendedPresetsNow(createHistory: true, "before_meta_reset"); insideMetaReset = true; } catch (Exception ex) { insideMetaReset = true; WriteFailureLog("MetaManager.Reset Prefix", ex); } } private static void Postfix(MetaManager __instance) { try { if (IsEnabled()) { insideMetaReset = false; if (!ProtectExtendedSlotsOnReset()) { ClearExtendedStore(createHistory: true, "meta_reset_clear_extended"); } EnsurePresetRuntimeSlots(__instance, ProtectExtendedSlotsOnReset(), "MetaManager.Reset Postfix"); } } catch (Exception ex) { WriteFailureLog("MetaManager.Reset Postfix", ex); } finally { insideMetaReset = false; } } private static Exception Finalizer(Exception __exception) { insideMetaReset = false; return __exception; } } [HarmonyPatch(typeof(MetaManager), "CosmeticPresetSet")] private static class MetaManagerCosmeticPresetSetPatch { private static void Prefix(MetaManager __instance, int _index) { if (_index >= 0) { EnsurePresetRuntimeSlotsForIndex(__instance, _index, "MetaManager.CosmeticPresetSet Prefix"); } } private static void Postfix(MetaManager __instance, int _index) { if (!IsEnabled() || (Object)(object)__instance == (Object)null || _index < 28) { return; } try { List<List<int>> presetList = GetPresetList(__instance, cosmeticPresetsField); List<List<int>> presetList2 = GetPresetList(__instance, colorPresetsField); SaveExtendedStoreFromRuntime(__instance, presetList, presetList2, GetTargetSlots(), createHistory: false, "CosmeticPresetSet " + _index); } catch (Exception ex) { WriteFailureLog("MetaManager.CosmeticPresetSet Postfix", ex); } } } [HarmonyPatch(typeof(MenuPageCosmetics), "RefreshScrollContent")] private static class MenuPageCosmeticsRefreshScrollContentPatch { private static void Prefix() { if ((Object)(object)MetaManager.instance != (Object)null) { EnsurePresetRuntimeSlots(MetaManager.instance, mergeExtendedStore: true, "MenuPageCosmetics.RefreshScrollContent Prefix"); } } private static void Postfix(MenuPageCosmetics __instance) { RefreshPresetGridLayout(__instance); } } [HarmonyPatch(typeof(MenuElementCosmeticPreset), "Start")] private static class MenuElementCosmeticPresetStartPatch { private static void Prefix(MenuElementCosmeticPreset __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)MetaManager.instance == (Object)null)) { EnsurePresetRuntimeSlotsForIndex(MetaManager.instance, __instance.presetIndex, "MenuElementCosmeticPreset.Start Prefix"); } } } [HarmonyPatch(typeof(MenuElementCosmeticPreset), "TogglePreset")] private static class MenuElementCosmeticPresetTogglePresetPatch { private static void Prefix(MenuElementCosmeticPreset __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)MetaManager.instance == (Object)null)) { EnsurePresetRuntimeSlotsForIndex(MetaManager.instance, __instance.presetIndex, "MenuElementCosmeticPreset.TogglePreset Prefix"); } } } [HarmonyPatch(typeof(MenuElementCosmeticPreset), "DeletePreset")] private static class MenuElementCosmeticPresetDeletePresetPatch { private static void Prefix(MenuElementCosmeticPreset __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)MetaManager.instance == (Object)null)) { EnsurePresetRuntimeSlotsForIndex(MetaManager.instance, __instance.presetIndex, "MenuElementCosmeticPreset.DeletePreset Prefix"); } } } [HarmonyPatch(typeof(DebugCommandHandler), "Start")] private static class DebugCommandHandlerStartPatch { private static void Postfix(DebugCommandHandler __instance) { RegisterCommands(__instance); } } public const string PluginGuid = "REPOJP.CosmeticPresetExtender"; public const string PluginName = "CosmeticPresetExtender"; public const string PluginVersion = "4.0.0"; private const int VanillaColumns = 7; private const int VanillaRows = 4; private const int VanillaSlots = 28; private const int MinRows = 4; private const int MaxRows = 100; private const int DefaultRows = 10; private const float PresetCellWidth = 60f; private const float PresetCellHeight = 140f; private static CosmeticPresetExtenderPlugin instance; private static ManualLogSource logSource; private static Harmony harmony; private static ConfigEntry<bool> configEnabled; private static ConfigEntry<int> configPresetRows; private static ConfigEntry<bool> configProtectExtendedSlotsOnReset; private static ConfigEntry<int> configBackupHistoryCount; private static ConfigEntry<bool> configDetailedLog; private static readonly FieldInfo presetSlotsField = AccessTools.Field(typeof(MetaManager), "presetSlots"); private static readonly FieldInfo cosmeticPresetsField = AccessTools.Field(typeof(MetaManager), "cosmeticPresets"); private static readonly FieldInfo colorPresetsField = AccessTools.Field(typeof(MetaManager), "colorPresets"); private static readonly FieldInfo colorsEquippedField = AccessTools.Field(typeof(MetaManager), "colorsEquipped"); private static readonly FieldInfo cosmeticAssetsField = AccessTools.Field(typeof(MetaManager), "cosmeticAssets"); private static readonly FieldInfo colorsField = AccessTools.Field(typeof(MetaManager), "colors"); private static bool insideMetaReset; private static bool commandRegistered; private static string StoreDirectory => Path.Combine(Paths.ConfigPath, "REPOJP.CosmeticPresetExtender"); private static string StoreFilePath => Path.Combine(StoreDirectory, "ExtendedPresets.json"); private static string StoreBackupFilePath => Path.Combine(StoreDirectory, "ExtendedPresets.json.bak"); private static string HistoryDirectory => Path.Combine(StoreDirectory, "history"); private void Awake() { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Expected O, but got Unknown try { instance = this; logSource = ((BaseUnityPlugin)this).Logger; ((Component)this).transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); configEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enables this mod.このMODを有効化します"); configPresetRows = ((BaseUnityPlugin)this).Config.Bind<int>("General", "PresetRows", 10, new ConfigDescription("Cosmetic preset rows. 7 columns are fixed.コスメプリセットの行数。7列固定", (AcceptableValueBase)(object)new AcceptableValueRange<int>(4, 100), Array.Empty<object>())); configProtectExtendedSlotsOnReset = ((BaseUnityPlugin)this).Config.Bind<bool>("Save Safety", "ProtectExtendedSlotsOnReset", true, "Keeps slot 29 and later when vanilla meta progress is reset.バニラのメタ進行リセット時も29枠目以降を保持します"); configBackupHistoryCount = ((BaseUnityPlugin)this).Config.Bind<int>("Save Safety", "BackupHistoryCount", 10, new ConfigDescription("Maximum history backup files.履歴バックアップファイルの最大保持数", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); configDetailedLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DetailedLog", false, "Outputs detailed debug logs.詳細ログを出力します"); harmony = new Harmony("REPOJP.CosmeticPresetExtender"); harmony.PatchAll(typeof(CosmeticPresetExtenderPlugin).Assembly); WriteLog("Loaded. Rows=" + GetTargetRows() + " Slots=" + GetTargetSlots() + " VanillaSaveSlots=" + 28); } catch (Exception ex) { if (logSource != null) { logSource.LogError((object)("Failure: Awake\n" + ex)); } } } private void OnDestroy() { try { if (harmony != null) { harmony.UnpatchSelf(); harmony = null; } } catch (Exception ex) { if (logSource != null) { logSource.LogError((object)("Failure: OnDestroy\n" + ex)); } } } private static bool IsEnabled() { return configEnabled == null || configEnabled.Value; } private static int GetTargetRows() { int num = 10; if (configPresetRows != null) { num = configPresetRows.Value; } return Mathf.Clamp(num, 4, 100); } private static int GetTargetSlots() { return GetTargetRows() * 7; } private static int GetHistoryLimit() { int num = 10; if (configBackupHistoryCount != null) { num = configBackupHistoryCount.Value; } return Mathf.Clamp(num, 0, 100); } private static bool ProtectExtendedSlotsOnReset() { return configProtectExtendedSlotsOnReset == null || configProtectExtendedSlotsOnReset.Value; } private static void WriteLog(string message) { if (logSource != null) { logSource.LogInfo((object)message); } } private static void WriteDetailLog(string message) { if (configDetailedLog != null && configDetailedLog.Value && logSource != null) { logSource.LogInfo((object)message); } } private static void WriteFailureLog(string message, Exception ex) { if (logSource != null) { logSource.LogError((object)("Failure: " + message + "\n" + ex)); } } private static void SetPresetSlotsField(MetaManager manager, int slots) { if (!((Object)(object)manager == (Object)null) && !(presetSlotsField == null)) { presetSlotsField.SetValue(manager, slots); } } private static List<List<int>> GetPresetList(MetaManager manager, FieldInfo field) { if ((Object)(object)manager == (Object)null || field == null) { return null; } return field.GetValue(manager) as List<List<int>>; } private static void SetPresetList(MetaManager manager, FieldInfo field, List<List<int>> value) { if (!((Object)(object)manager == (Object)null) && !(field == null)) { field.SetValue(manager, value); } } private static int[] GetColorsEquipped(MetaManager manager) { if ((Object)(object)manager == (Object)null || colorsEquippedField == null) { return null; } return colorsEquippedField.GetValue(manager) as int[]; } private static int GetCosmeticAssetCount(MetaManager manager) { if ((Object)(object)manager == (Object)null || cosmeticAssetsField == null) { return 0; } object value = cosmeticAssetsField.GetValue(manager); if (!(value is ICollection collection)) { return 0; } return collection.Count; } private static int GetColorCount(MetaManager manager) { if ((Object)(object)manager == (Object)null || colorsField == null) { return 0; } object value = colorsField.GetValue(manager); if (!(value is ICollection collection)) { return 0; } return collection.Count; } private static void EnsurePresetRuntimeSlots(MetaManager manager, bool mergeExtendedStore, string reason) { if (!IsEnabled() || (Object)(object)manager == (Object)null) { return; } try { int targetSlots = GetTargetSlots(); SetPresetSlotsField(manager, targetSlots); List<List<int>> list = GetPresetList(manager, cosmeticPresetsField); List<List<int>> list2 = GetPresetList(manager, colorPresetsField); if (list == null) { list = new List<List<int>>(); SetPresetList(manager, cosmeticPresetsField, list); } if (list2 == null) { list2 = new List<List<int>>(); SetPresetList(manager, colorPresetsField, list2); } ExpandList(list, targetSlots); ExpandList(list2, targetSlots); NormalizeLists(manager, list, list2); if (mergeExtendedStore) { MergeExtendedStoreIntoRuntime(manager, list, list2, forceOverwrite: false); NormalizeLists(manager, list, list2); } WriteDetailLog("EnsurePresetRuntimeSlots: " + reason + " Rows=" + GetTargetRows() + " Slots=" + targetSlots); } catch (Exception ex) { WriteFailureLog("EnsurePresetRuntimeSlots / " + reason, ex); } } private static void EnsurePresetRuntimeSlotsForIndex(MetaManager manager, int index, string reason) { if (!IsEnabled() || (Object)(object)manager == (Object)null || index < 0) { return; } try { int num = Mathf.Max(GetTargetSlots(), index + 1); SetPresetSlotsField(manager, num); List<List<int>> list = GetPresetList(manager, cosmeticPresetsField); List<List<int>> list2 = GetPresetList(manager, colorPresetsField); if (list == null) { list = new List<List<int>>(); SetPresetList(manager, cosmeticPresetsField, list); } if (list2 == null) { list2 = new List<List<int>>(); SetPresetList(manager, colorPresetsField, list2); } ExpandList(list, num); ExpandList(list2, num); NormalizeLists(manager, list, list2); WriteDetailLog("EnsurePresetRuntimeSlotsForIndex: " + reason + " Index=" + index); } catch (Exception ex) { WriteFailureLog("EnsurePresetRuntimeSlotsForIndex / " + reason, ex); } } private static void ExpandList(List<List<int>> list, int targetCount) { if (list == null) { return; } while (list.Count < targetCount) { list.Add(new List<int>()); } for (int i = 0; i < list.Count; i++) { if (list[i] == null) { list[i] = new List<int>(); } } } private static List<List<int>> ClonePresetList(List<List<int>> source, int targetCount) { List<List<int>> list = new List<List<int>>(); for (int i = 0; i < targetCount; i++) { if (source != null && i < source.Count && source[i] != null) { list.Add(new List<int>(source[i])); } else { list.Add(new List<int>()); } } return list; } private static List<List<int>> CloneFirstSlots(List<List<int>> source, int count) { List<List<int>> list = new List<List<int>>(); for (int i = 0; i < count; i++) { if (source != null && i < source.Count && source[i] != null) { list.Add(new List<int>(source[i])); } else { list.Add(new List<int>()); } } return list; } private static List<int> CopyValues(List<int> source) { if (source == null) { return new List<int>(); } return new List<int>(source); } private static bool HasPresetData(List<int> cosmetics, List<int> colors) { bool flag = cosmetics != null && cosmetics.Count > 0; bool flag2 = colors != null && colors.Count > 0; return flag || flag2; } private static void NormalizeLists(MetaManager manager, List<List<int>> cosmeticPresets, List<List<int>> colorPresets) { if ((Object)(object)manager == (Object)null || cosmeticPresets == null || colorPresets == null) { return; } int targetCount = Mathf.Max(GetTargetSlots(), Mathf.Max(cosmeticPresets.Count, colorPresets.Count)); ExpandList(cosmeticPresets, targetCount); ExpandList(colorPresets, targetCount); int cosmeticAssetCount = GetCosmeticAssetCount(manager); int colorCount = GetColorCount(manager); int[] colorsEquipped = GetColorsEquipped(manager); int num = ((colorsEquipped != null) ? colorsEquipped.Length : 0); for (int i = 0; i < cosmeticPresets.Count; i++) { List<int> list = cosmeticPresets[i]; if (list == null) { cosmeticPresets[i] = new List<int>(); continue; } for (int num2 = list.Count - 1; num2 >= 0; num2--) { int num3 = list[num2]; if (num3 < 0 || (cosmeticAssetCount > 0 && num3 >= cosmeticAssetCount)) { list.RemoveAt(num2); } } } for (int j = 0; j < colorPresets.Count; j++) { List<int> list2 = colorPresets[j]; if (list2 == null) { colorPresets[j] = new List<int>(); list2 = colorPresets[j]; } bool flag = HasPresetData((j < cosmeticPresets.Count) ? cosmeticPresets[j] : null, list2); if (num > 0 && flag) { while (list2.Count < num) { list2.Add(0); } while (list2.Count > num) { list2.RemoveAt(list2.Count - 1); } } for (int k = 0; k < list2.Count; k++) { if (list2[k] < 0) { list2[k] = 0; } if (colorCount > 0 && list2[k] >= colorCount) { list2[k] = 0; } } } } private static void MergeExtendedStoreIntoRuntime(MetaManager manager, List<List<int>> cosmeticPresets, List<List<int>> colorPresets, bool forceOverwrite) { if (!IsEnabled() || (Object)(object)manager == (Object)null || cosmeticPresets == null || colorPresets == null) { return; } try { ExtendedPresetStore extendedPresetStore = LoadExtendedStore(allowBackupRecovery: true); NormalizeStore(extendedPresetStore); int targetSlots = GetTargetSlots(); ExpandList(cosmeticPresets, targetSlots); ExpandList(colorPresets, targetSlots); Dictionary<int, ExtendedPresetEntry> dictionary = ToEntryMap(extendedPresetStore.presets); for (int i = 28; i < targetSlots; i++) { if (!dictionary.ContainsKey(i)) { continue; } ExtendedPresetEntry extendedPresetEntry = dictionary[i]; if (!HasPresetData(cosmeticPresets[i], colorPresets[i]) || forceOverwrite) { string text = BuildPresetHash(cosmeticPresets[i], colorPresets[i]); cosmeticPresets[i] = CopyValues(extendedPresetEntry.cosmetics); colorPresets[i] = CopyValues(extendedPresetEntry.colors); string text2 = BuildPresetHash(cosmeticPresets[i], colorPresets[i]); if (text != text2) { DeletePresetIcon(i); } } } WriteDetailLog("Extended preset store merged. Entries=" + extendedPresetStore.presets.Count); } catch (Exception ex) { WriteFailureLog("MergeExtendedStoreIntoRuntime", ex); } } private static void SaveExtendedStoreFromRuntime(MetaManager manager, List<List<int>> fullCosmeticPresets, List<List<int>> fullColorPresets, int visibleSlots, bool createHistory, string reason) { if (!IsEnabled() || (Object)(object)manager == (Object)null) { return; } try { ExtendedPresetStore extendedPresetStore = LoadExtendedStore(allowBackupRecovery: true); NormalizeStore(extendedPresetStore); Dictionary<int, ExtendedPresetEntry> dictionary = ToEntryMap(extendedPresetStore.presets); int num = Mathf.Max(28, visibleSlots); for (int i = 28; i < num; i++) { List<int> list = ((fullCosmeticPresets != null && i < fullCosmeticPresets.Count && fullCosmeticPresets[i] != null) ? fullCosmeticPresets[i] : new List<int>()); List<int> list2 = ((fullColorPresets != null && i < fullColorPresets.Count && fullColorPresets[i] != null) ? fullColorPresets[i] : new List<int>()); string text = BuildPresetHash(list, list2); if (dictionary.TryGetValue(i, out var value) && value != null && value.hash == text) { value.cosmetics = CopyValues(list); value.colors = CopyValues(list2); } else { dictionary[i] = new ExtendedPresetEntry(i, list, list2, DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"), text); DeletePresetIcon(i); } } extendedPresetStore.version = 2; extendedPresetStore.columns = 7; extendedPresetStore.vanillaSlots = 28; extendedPresetStore.currentRows = GetTargetRows(); extendedPresetStore.currentSlots = GetTargetSlots(); extendedPresetStore.updatedAtUtc = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"); extendedPresetStore.presets = ToSortedEntryList(dictionary); extendedPresetStore.cosmeticPresets = new List<LegacyPresetEntry>(); extendedPresetStore.colorPresets = new List<LegacyPresetEntry>(); WriteExtendedStore(extendedPresetStore, createHistory, reason); WriteDetailLog("Extended preset store saved. Reason=" + reason + " Entries=" + extendedPresetStore.presets.Count); } catch (Exception ex) { WriteFailureLog("SaveExtendedStoreFromRuntime / " + reason, ex); } } private static void ClearExtendedStore(bool createHistory, string reason) { try { ExtendedPresetStore store = LoadExtendedStore(allowBackupRecovery: true); NormalizeStore(store); if (createHistory) { WriteHistoryBackup(store, reason); } ExtendedPresetStore extendedPresetStore = new ExtendedPresetStore(); extendedPresetStore.version = 2; extendedPresetStore.columns = 7; extendedPresetStore.vanillaSlots = 28; extendedPresetStore.currentRows = GetTargetRows(); extendedPresetStore.currentSlots = GetTargetSlots(); extendedPresetStore.updatedAtUtc = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"); WriteExtendedStore(extendedPresetStore, createHistory: false, reason); } catch (Exception ex) { WriteFailureLog("ClearExtendedStore / " + reason, ex); } } private static ExtendedPresetStore LoadExtendedStore(bool allowBackupRecovery) { try { if (TryReadStoreFile(StoreFilePath, out var data)) { NormalizeStore(data); return data; } if (allowBackupRecovery && TryReadStoreFile(StoreBackupFilePath, out data)) { NormalizeStore(data); RecoverPrimaryStoreFromBackup(data); return data; } } catch (Exception ex) { WriteFailureLog("LoadExtendedStore", ex); } return new ExtendedPresetStore(); } private static bool TryReadStoreFile(string path, out ExtendedPresetStore data) { data = null; try { if (string.IsNullOrEmpty(path) || !File.Exists(path)) { return false; } string text = File.ReadAllText(path, Encoding.UTF8); if (string.IsNullOrWhiteSpace(text)) { return false; } ExtendedPresetStore extendedPresetStore = JsonUtility.FromJson<ExtendedPresetStore>(text); if (extendedPresetStore == null) { return false; } if (extendedPresetStore.presets == null && extendedPresetStore.cosmeticPresets == null && extendedPresetStore.colorPresets == null) { return false; } data = extendedPresetStore; NormalizeStore(data); return true; } catch (Exception ex) { WriteFailureLog("TryReadStoreFile: " + path, ex); return false; } } private static void RecoverPrimaryStoreFromBackup(ExtendedPresetStore backupData) { try { Directory.CreateDirectory(StoreDirectory); if (File.Exists(StoreFilePath)) { string destFileName = StoreFilePath + ".corrupt_" + DateTime.Now.ToString("yyyyMMdd_HHmmss"); File.Move(StoreFilePath, destFileName); } WriteExtendedStore(backupData, createHistory: false, "recover_from_bak"); WriteLog("ExtendedPresets.json was recovered from .bak."); } catch (Exception ex) { WriteFailureLog("RecoverPrimaryStoreFromBackup", ex); } } private static void WriteExtendedStore(ExtendedPresetStore store, bool createHistory, string reason) { try { Directory.CreateDirectory(StoreDirectory); NormalizeStore(store); if (createHistory) { WriteHistoryBackup(store, reason); } string contents = JsonUtility.ToJson((object)store, true); string text = StoreFilePath + ".tmp"; File.WriteAllText(text, contents, Encoding.UTF8); if (File.Exists(StoreFilePath)) { File.Copy(StoreFilePath, StoreBackupFilePath, overwrite: true); File.Delete(StoreFilePath); } File.Move(text, StoreFilePath); CleanupHistoryBackups(); } catch (Exception ex) { WriteFailureLog("WriteExtendedStore / " + reason, ex); } } private static void WriteHistoryBackup(ExtendedPresetStore store, string reason) { try { int historyLimit = GetHistoryLimit(); if (historyLimit > 0) { Directory.CreateDirectory(HistoryDirectory); NormalizeStore(store); string text = SanitizeFileName(reason); string path = Path.Combine(HistoryDirectory, "ExtendedPresets_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + "_" + text + ".json"); string contents = JsonUtility.ToJson((object)store, true); File.WriteAllText(path, contents, Encoding.UTF8); CleanupHistoryBackups(); } } catch (Exception ex) { WriteFailureLog("WriteHistoryBackup / " + reason, ex); } } private static void CleanupHistoryBackups() { try { int historyLimit = GetHistoryLimit(); if (historyLimit <= 0 || !Directory.Exists(HistoryDirectory)) { return; } FileInfo[] files = new DirectoryInfo(HistoryDirectory).GetFiles("ExtendedPresets_*.json"); Array.Sort(files, (FileInfo a, FileInfo b) => b.CreationTimeUtc.CompareTo(a.CreationTimeUtc)); for (int i = historyLimit; i < files.Length; i++) { try { files[i].Delete(); } catch { } } } catch (Exception ex) { WriteFailureLog("CleanupHistoryBackups", ex); } } private static string SanitizeFileName(string value) { if (string.IsNullOrEmpty(value)) { return "manual"; } char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); string text = value; for (int i = 0; i < invalidFileNameChars.Length; i++) { text = text.Replace(invalidFileNameChars[i], '_'); } return text.Replace(' ', '_'); } private static void NormalizeStore(ExtendedPresetStore store) { if (store == null) { return; } if (store.presets == null) { store.presets = new List<ExtendedPresetEntry>(); } if (store.cosmeticPresets == null) { store.cosmeticPresets = new List<LegacyPresetEntry>(); } if (store.colorPresets == null) { store.colorPresets = new List<LegacyPresetEntry>(); } if (store.presets.Count == 0 && (store.cosmeticPresets.Count > 0 || store.colorPresets.Count > 0)) { Dictionary<int, LegacyPresetEntry> dictionary = ToLegacyEntryMap(store.cosmeticPresets); Dictionary<int, LegacyPresetEntry> dictionary2 = ToLegacyEntryMap(store.colorPresets); Dictionary<int, ExtendedPresetEntry> dictionary3 = new Dictionary<int, ExtendedPresetEntry>(); foreach (int key in dictionary.Keys) { List<int> cosmetics = ((dictionary[key] != null) ? dictionary[key].values : new List<int>()); List<int> colors = ((dictionary2.ContainsKey(key) && dictionary2[key] != null) ? dictionary2[key].values : new List<int>()); dictionary3[key] = new ExtendedPresetEntry(key, cosmetics, colors, DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"), BuildPresetHash(cosmetics, colors)); } foreach (int key2 in dictionary2.Keys) { if (!dictionary3.ContainsKey(key2)) { List<int> colors2 = ((dictionary2[key2] != null) ? dictionary2[key2].values : new List<int>()); dictionary3[key2] = new ExtendedPresetEntry(key2, new List<int>(), colors2, DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"), BuildPresetHash(new List<int>(), colors2)); } } store.presets = ToSortedEntryList(dictionary3); } Dictionary<int, ExtendedPresetEntry> map = ToEntryMap(store.presets); store.presets = ToSortedEntryList(map); } private static Dictionary<int, LegacyPresetEntry> ToLegacyEntryMap(List<LegacyPresetEntry> entries) { Dictionary<int, LegacyPresetEntry> dictionary = new Dictionary<int, LegacyPresetEntry>(); if (entries == null) { return dictionary; } foreach (LegacyPresetEntry entry in entries) { if (entry != null && entry.index >= 28) { dictionary[entry.index] = new LegacyPresetEntry(entry.index, entry.values); } } return dictionary; } private static Dictionary<int, ExtendedPresetEntry> ToEntryMap(List<ExtendedPresetEntry> entries) { Dictionary<int, ExtendedPresetEntry> dictionary = new Dictionary<int, ExtendedPresetEntry>(); if (entries == null) { return dictionary; } foreach (ExtendedPresetEntry entry in entries) { if (entry != null && entry.index >= 28) { dictionary[entry.index] = new ExtendedPresetEntry(entry.index, entry.cosmetics, entry.colors, entry.updatedAtUtc, entry.hash); } } return dictionary; } private static List<ExtendedPresetEntry> ToSortedEntryList(Dictionary<int, ExtendedPresetEntry> map) { List<ExtendedPresetEntry> list = new List<ExtendedPresetEntry>(); if (map == null) { return list; } List<int> list2 = new List<int>(map.Keys); list2.Sort(); foreach (int item in list2) { ExtendedPresetEntry extendedPresetEntry = map[item]; if (extendedPresetEntry != null && item >= 28) { if (string.IsNullOrEmpty(extendedPresetEntry.hash)) { extendedPresetEntry.hash = BuildPresetHash(extendedPresetEntry.cosmetics, extendedPresetEntry.colors); } if (string.IsNullOrEmpty(extendedPresetEntry.updatedAtUtc)) { extendedPresetEntry.updatedAtUtc = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"); } list.Add(new ExtendedPresetEntry(item, extendedPresetEntry.cosmetics, extendedPresetEntry.colors, extendedPresetEntry.updatedAtUtc, extendedPresetEntry.hash)); } } return list; } private static string BuildPresetHash(List<int> cosmetics, List<int> colors) { StringBuilder stringBuilder = new StringBuilder(); if (cosmetics != null) { for (int i = 0; i < cosmetics.Count; i++) { if (i > 0) { stringBuilder.Append(','); } stringBuilder.Append(cosmetics[i].ToString()); } } stringBuilder.Append('|'); if (colors != null) { for (int j = 0; j < colors.Count; j++) { if (j > 0) { stringBuilder.Append(','); } stringBuilder.Append(colors[j].ToString()); } } return stringBuilder.ToString(); } private static void DeletePresetIcon(int presetIndex) { try { if (presetIndex < 0 || (Object)(object)MetaManager.instance == (Object)null) { return; } FieldInfo fieldInfo = AccessTools.Field(typeof(MetaManager), "presetCacheFolder"); string text = "CosmeticsPresets"; if (fieldInfo != null) { object value = fieldInfo.GetValue(MetaManager.instance); if (value is string && !string.IsNullOrEmpty((string)value)) { text = (string)value; } } string path = Path.Combine(Application.persistentDataPath, "Cache", "Icons", text, presetIndex.ToString().ToLowerInvariant() + ".png"); if (File.Exists(path)) { File.Delete(path); } } catch (Exception ex) { WriteFailureLog("DeletePresetIcon", ex); } } private static void RefreshPresetGridLayout(MenuPageCosmetics menuPageCosmetics) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) if (!IsEnabled() || (Object)(object)menuPageCosmetics == (Object)null) { return; } try { if ((int)menuPageCosmetics.selectedTab != 1 || (Object)(object)menuPageCosmetics.sectionRootTransform == (Object)null) { return; } int targetSlots = GetTargetSlots(); int num = Mathf.Max(4, Mathf.CeilToInt((float)targetSlots / 7f)); MenuElementCosmeticSection[] componentsInChildren = ((Component)menuPageCosmetics.sectionRootTransform).GetComponentsInChildren<MenuElementCosmeticSection>(true); MenuElementCosmeticSection[] array = componentsInChildren; foreach (MenuElementCosmeticSection val in array) { if ((Object)(object)val == (Object)null || (Object)(object)val.cosmeticListTransform == (Object)null) { continue; } MenuElementCosmeticPreset componentInChildren = ((Component)val.cosmeticListTransform).GetComponentInChildren<MenuElementCosmeticPreset>(true); if ((Object)(object)componentInChildren == (Object)null) { continue; } GridLayoutGroup component = ((Component)val.cosmeticListTransform).GetComponent<GridLayoutGroup>(); if (!((Object)(object)component == (Object)null)) { component.constraint = (Constraint)1; component.constraintCount = 7; component.cellSize = new Vector2(60f, 140f); float num2 = component.cellSize.y * (float)num + component.spacing.y * (float)Mathf.Max(0, num - 1) + (float)((LayoutGroup)component).padding.top + (float)((LayoutGroup)component).padding.bottom; RectTransform component2 = ((Component)val.cosmeticListTransform).GetComponent<RectTransform>(); if ((Object)(object)component2 != (Object)null) { component2.sizeDelta = new Vector2(component2.sizeDelta.x, num2); LayoutRebuilder.ForceRebuildLayoutImmediate(component2); } RectTransform component3 = ((Component)val).GetComponent<RectTransform>(); if ((Object)(object)component3 != (Object)null) { component3.sizeDelta = new Vector2(component3.sizeDelta.x, num2); LayoutRebuilder.ForceRebuildLayoutImmediate(component3); } } } } catch (Exception ex) { WriteFailureLog("RefreshPresetGridLayout", ex); } } private static SaveState BuildSaveState(MetaManager manager, string reason) { if ((Object)(object)manager == (Object)null) { return null; } int targetSlots = GetTargetSlots(); List<List<int>> presetList = GetPresetList(manager, cosmeticPresetsField); List<List<int>> presetList2 = GetPresetList(manager, colorPresetsField); ExpandList(presetList, targetSlots); ExpandList(presetList2, targetSlots); NormalizeLists(manager, presetList, presetList2); SaveState saveState = new SaveState(); saveState.reason = reason; saveState.targetSlots = targetSlots; saveState.restoreCosmeticPresets = ClonePresetList(presetList, targetSlots); saveState.restoreColorPresets = ClonePresetList(presetList2, targetSlots); return saveState; } private static void PrepareVanillaOnlySave(MetaManager manager, SaveState state) { if (!((Object)(object)manager == (Object)null) && state != null) { List<List<int>> value = CloneFirstSlots(state.restoreCosmeticPresets, 28); List<List<int>> value2 = CloneFirstSlots(state.restoreColorPresets, 28); SetPresetList(manager, cosmeticPresetsField, value); SetPresetList(manager, colorPresetsField, value2); SetPresetSlotsField(manager, 28); } } private static void RestoreRuntimeAfterVanillaSave(MetaManager manager, SaveState state) { if (!((Object)(object)manager == (Object)null) && state != null) { SetPresetList(manager, cosmeticPresetsField, ClonePresetList(state.restoreCosmeticPresets, state.targetSlots)); SetPresetList(manager, colorPresetsField, ClonePresetList(state.restoreColorPresets, state.targetSlots)); SetPresetSlotsField(manager, state.targetSlots); EnsurePresetRuntimeSlots(manager, mergeExtendedStore: false, "RestoreRuntimeAfterVanillaSave / " + state.reason); } } private static void RestoreExtendedPresetsFromStoreNow(bool forceOverwrite, string reason) { try { if (!((Object)(object)MetaManager.instance == (Object)null)) { EnsurePresetRuntimeSlots(MetaManager.instance, mergeExtendedStore: false, reason + " / before_restore"); List<List<int>> presetList = GetPresetList(MetaManager.instance, cosmeticPresetsField); List<List<int>> presetList2 = GetPresetList(MetaManager.instance, colorPresetsField); MergeExtendedStoreIntoRuntime(MetaManager.instance, presetList, presetList2, forceOverwrite); NormalizeLists(MetaManager.instance, presetList, presetList2); WriteLog("Extended presets restored. Reason=" + reason); } } catch (Exception ex) { WriteFailureLog("RestoreExtendedPresetsFromStoreNow / " + reason, ex); } } private static void SaveExtendedPresetsNow(bool createHistory, string reason) { try { if (!((Object)(object)MetaManager.instance == (Object)null)) { EnsurePresetRuntimeSlots(MetaManager.instance, mergeExtendedStore: false, reason + " / before_backup"); List<List<int>> presetList = GetPresetList(MetaManager.instance, cosmeticPresetsField); List<List<int>> presetList2 = GetPresetList(MetaManager.instance, colorPresetsField); SaveExtendedStoreFromRuntime(MetaManager.instance, presetList, presetList2, GetTargetSlots(), createHistory, reason); WriteLog("Extended presets saved. Reason=" + reason); } } catch (Exception ex) { WriteFailureLog("SaveExtendedPresetsNow / " + reason, ex); } } private static void RegisterCommands(DebugCommandHandler handler) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown if (!IsEnabled() || (Object)(object)handler == (Object)null || commandRegistered) { return; } try { handler.Register(new ChatCommand("cpeinfo", "Shows CosmeticPresetExtender save information", (Action<bool, string[]>)delegate { ExtendedPresetStore extendedPresetStore = LoadExtendedStore(allowBackupRecovery: true); NormalizeStore(extendedPresetStore); WriteLog("Rows=" + GetTargetRows() + " Slots=" + GetTargetSlots() + " VanillaSaveSlots=" + 28 + " ExtendedEntries=" + extendedPresetStore.presets.Count + " UpdatedAtUtc=" + extendedPresetStore.updatedAtUtc); }, (Func<bool, string, string[], List<string>>)null, (Func<bool>)null, false)); handler.Register(new ChatCommand("cpebackup", "Saves extended cosmetic presets now", (Action<bool, string[]>)delegate { SaveExtendedPresetsNow(createHistory: true, "chat_cpebackup"); }, (Func<bool, string, string[], List<string>>)null, (Func<bool>)null, false)); handler.Register(new ChatCommand("cperestore", "Restores extended cosmetic presets now", (Action<bool, string[]>)delegate { RestoreExtendedPresetsFromStoreNow(forceOverwrite: true, "chat_cperestore"); }, (Func<bool, string, string[], List<string>>)null, (Func<bool>)null, false)); commandRegistered = true; WriteLog("Chat commands registered: /cpeinfo /cpebackup /cperestore"); } catch (Exception ex) { WriteFailureLog("RegisterCommands", ex); } } } }