Decompiled source of PresetSaver v0.2.0

AskaPresetSaver.dll

Decompiled 13 hours ago
using System;
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 AskaPresetSaver.Core;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using SSSGame;
using SSSGame.UI;
using SandSailorStudio.Inventory;
using SandSailorStudio.Storage;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("AskaPresetSaver")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.0")]
[assembly: AssemblyInformationalVersion("0.2.0+91ff6e46d0d62bf196bf09f71f08f796e81a0034")]
[assembly: AssemblyProduct("Aska Preset Saver")]
[assembly: AssemblyTitle("AskaPresetSaver")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 AskaPresetSaver
{
	public sealed class CaptureBehaviour : MonoBehaviour
	{
		public CaptureBehaviour(IntPtr ptr)
			: base(ptr)
		{
		}

		private void Update()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			if (!PreferencesManagerPatches.CaptureRequested)
			{
				return;
			}
			PreferencesManagerPatches.CaptureRequested = false;
			if (!PresetSaverConfig.Capture.Value)
			{
				return;
			}
			if ((Object)Object.FindObjectOfType<PlayerCharacter>() == (Object)null)
			{
				Plugin.Log.LogInfo((object)"capture requested but not in-world yet; skipping this save.");
				return;
			}
			PreferencesManager val = Object.FindObjectOfType<PreferencesManager>();
			if ((Object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"capture requested but no PreferencesManager found; skipping.");
				return;
			}
			if (!val.IsLocalStorageClient)
			{
				Plugin.Log.LogInfo((object)"capture skipped — not the local storage client (co-op non-host).");
				return;
			}
			PresetLibraryDto val2 = PreferencesBridge.Capture(val);
			PresetLibraryDto val3 = PresetLibrary.MergeCaptured(PresetStore.Load(), val2);
			PresetStore.Save(val3);
			int num = 0;
			foreach (TasksPresetDto task in val2.Tasks)
			{
				num += task.Rows.Count;
			}
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(124, 5, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("captured ");
				((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(val2.Schedules.Count);
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" schedule preset(s) and ");
				((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(val2.Tasks.Count);
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" task preset(s) (");
				((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(num);
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" row(s) total); ");
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("library now holds ");
				((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(val3.Schedules.Count);
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" schedule preset(s) and ");
				((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(val3.Tasks.Count);
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" task preset(s).");
			}
			log.LogInfo(val4);
		}
	}
	[BepInPlugin("smithio.aska.presetsaver", "Aska Preset Saver", "0.2.0")]
	public class Plugin : BasePlugin
	{
		public const string PluginGuid = "smithio.aska.presetsaver";

		public const string PluginName = "Aska Preset Saver";

		public const string PluginVersion = "0.2.0";

		internal static ManualLogSource Log;

		public override void Load()
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			Log = ((BasePlugin)this).Log;
			PresetSaverConfig.Init(((BasePlugin)this).Config);
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val;
			if (!PresetSaverConfig.Enabled.Value)
			{
				ManualLogSource log = Log;
				val = new BepInExInfoLogInterpolatedStringHandler(22, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Aska Preset Saver");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" v");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("0.2.0");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" disabled by config.");
				}
				log.LogInfo(val);
				return;
			}
			ClassInjector.RegisterTypeInIl2Cpp<RestoreBehaviour>();
			ClassInjector.RegisterTypeInIl2Cpp<CaptureBehaviour>();
			new Harmony("smithio.aska.presetsaver").PatchAll(typeof(PreferencesManagerPatches));
			((BasePlugin)this).AddComponent<CaptureBehaviour>();
			((BasePlugin)this).AddComponent<RestoreBehaviour>();
			ManualLogSource log2 = Log;
			val = new BepInExInfoLogInterpolatedStringHandler(31, 4, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Aska Preset Saver");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" v");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("0.2.0");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded ");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("(Capture=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(PresetSaverConfig.Capture.Value);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", Restore=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(PresetSaverConfig.Restore.Value);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(").");
			}
			log2.LogInfo(val);
		}
	}
	internal static class PreferencesBridge
	{
		internal static PresetLibraryDto Capture(PreferencesManager pm)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			//IL_03e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ef: Expected O, but got Unknown
			//IL_044a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0451: Expected O, but got Unknown
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Expected O, but got Unknown
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Expected O, but got Unknown
			PresetLibraryDto val = new PresetLibraryDto();
			if ((Object)(object)pm == (Object)null)
			{
				return val;
			}
			bool flag = default(bool);
			try
			{
				List<VillagerSchedulePreset> villagerSchedulePresets = pm.VillagerSchedulePresets;
				if (villagerSchedulePresets != null)
				{
					Enumerator<VillagerSchedulePreset> enumerator = villagerSchedulePresets.GetEnumerator();
					while (enumerator.MoveNext())
					{
						VillagerSchedulePreset current = enumerator.Current;
						Il2CppStructArray<int> schedule = current.Schedule;
						if (schedule != null)
						{
							int[] array = new int[((Il2CppArrayBase<int>)(object)schedule).Length];
							for (int i = 0; i < ((Il2CppArrayBase<int>)(object)schedule).Length; i++)
							{
								array[i] = ((Il2CppArrayBase<int>)(object)schedule)[i];
							}
							val.Schedules.Add(new SchedulePresetDto
							{
								Name = current.presetName,
								Schedule = array
							});
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(27, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("capture: schedules failed: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val2);
			}
			try
			{
				List<TasksPreset> tasksConfigurationPresets = pm.TasksConfigurationPresets;
				if (tasksConfigurationPresets != null)
				{
					Enumerator<TasksPreset> enumerator2 = tasksConfigurationPresets.GetEnumerator();
					while (enumerator2.MoveNext())
					{
						TasksPreset current2 = enumerator2.Current;
						try
						{
							ItemInfo requiredTemplate = current2.requiredTemplate;
							if ((Object)(object)requiredTemplate == (Object)null)
							{
								continue;
							}
							TasksPresetDto val3 = new TasksPresetDto
							{
								Name = current2.presetName,
								TemplateId = requiredTemplate.id
							};
							if (pm._tasksPresetsData == null || !pm._tasksPresetsData.ContainsKey(current2.presetName))
							{
								Plugin.Log.LogWarning((object)("capture: task preset '" + current2.presetName + "' has no entry in _tasksPresetsData; captured with 0 rows."));
								val.Tasks.Add(val3);
								continue;
							}
							DataObject val4 = pm._tasksPresetsData[current2.presetName];
							object obj2;
							if (val4 != null)
							{
								DataElement obj = FindChild(val4, "tdArray");
								obj2 = ((obj != null) ? ((Il2CppObjectBase)obj).TryCast<DataArray>() : null);
							}
							else
							{
								obj2 = null;
							}
							DataArray val5 = (DataArray)obj2;
							if (val5 == null)
							{
								Plugin.Log.LogWarning((object)("capture: task preset '" + current2.presetName + "' has no readable 'tdArray' (missing, or not a DataArray); captured with 0 rows."));
								val.Tasks.Add(val3);
								continue;
							}
							int count = val5.Count;
							for (int j = 0; j < val5.Count; j++)
							{
								DataElement obj3 = val5[j];
								DataObject val6 = ((obj3 != null) ? ((Il2CppObjectBase)obj3).TryCast<DataObject>() : null);
								if (val6 != null)
								{
									DataElement obj4 = FindChild(val6, "itmInfo");
									DataElementInt val7 = ((obj4 != null) ? ((Il2CppObjectBase)obj4).TryCast<DataElementInt>() : null);
									DataElement obj5 = FindChild(val6, "taskPrio");
									DataElementInt val8 = ((obj5 != null) ? ((Il2CppObjectBase)obj5).TryCast<DataElementInt>() : null);
									DataElement obj6 = FindChild(val6, "qttyR");
									DataElementFloat val9 = ((obj6 != null) ? ((Il2CppObjectBase)obj6).TryCast<DataElementFloat>() : null);
									if (val7 != null && val8 != null && val9 != null)
									{
										val3.Rows.Add(new TaskRowDto
										{
											ItemId = val7.value,
											Priority = val8.value,
											QuantityRatio = val9.value
										});
									}
								}
							}
							if (count > 0 && val3.Rows.Count == 0)
							{
								Plugin.Log.LogWarning((object)($"capture: task preset '{current2.presetName}' has {count} row(s) " + "in 'tdArray' but none parsed (unexpected row shape); captured with 0 rows."));
							}
							else if (val3.Rows.Count < count)
							{
								ManualLogSource log2 = Plugin.Log;
								BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(95, 3, ref flag);
								if (flag)
								{
									((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("capture: task preset '");
									((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(current2.presetName);
									((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("': parsed ");
									((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(val3.Rows.Count);
									((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
									((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("of ");
									((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(count);
									((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" row(s); the rest had an unreadable shape and were skipped.");
								}
								log2.LogWarning(val2);
							}
							val.Tasks.Add(val3);
						}
						catch (Exception ex2)
						{
							ManualLogSource log3 = Plugin.Log;
							BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(33, 2, ref flag);
							if (flag)
							{
								((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("capture: tasks preset '");
								((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(current2.presetName);
								((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' failed: ");
								((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex2.Message);
							}
							log3.LogWarning(val2);
						}
					}
				}
			}
			catch (Exception ex3)
			{
				ManualLogSource log4 = Plugin.Log;
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(23, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("capture: tasks failed: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex3.Message);
				}
				log4.LogWarning(val2);
			}
			return val;
		}

		private static DataElement FindChild(DataObject obj, string key)
		{
			Dictionary<string, DataElement> val = ((obj != null) ? obj._elements : null);
			if (val == null)
			{
				return null;
			}
			Enumerator<string, DataElement> enumerator = val.GetEnumerator();
			while (enumerator.MoveNext())
			{
				KeyValuePair<string, DataElement> current = enumerator.Current;
				if (current.Key == key)
				{
					return current.Value;
				}
			}
			return null;
		}

		internal static int InjectSchedules(PreferencesManager pm, PresetLibraryDto missing)
		{
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			int num = 0;
			bool flag = default(bool);
			foreach (SchedulePresetDto schedule in missing.Schedules)
			{
				try
				{
					string text = PresetNames.Normalize(schedule.Name);
					if (text.Length != 0 && schedule.Schedule != null && schedule.Schedule.Length != 0)
					{
						if ((Object)(object)pm.networkLogic != (Object)null && pm.networkLogic._GetNextAvailableSchedulePresetSlot() < 0)
						{
							Plugin.Log.LogWarning((object)("restore: schedule preset capacity full; '" + text + "' and any remaining presets were not injected."));
							break;
						}
						Il2CppStructArray<int> val = new Il2CppStructArray<int>((long)schedule.Schedule.Length);
						for (int i = 0; i < schedule.Schedule.Length; i++)
						{
							((Il2CppArrayBase<int>)(object)val)[i] = schedule.Schedule[i];
						}
						pm.SaveSchedulePreset(text, val);
						num++;
						ManualLogSource log = Plugin.Log;
						BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(28, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("restored schedule preset '");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'.");
						}
						log.LogInfo(val2);
					}
				}
				catch (Exception ex)
				{
					ManualLogSource log2 = Plugin.Log;
					BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(29, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("restore: schedule '");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(schedule.Name);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' failed: ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message);
					}
					log2.LogWarning(val3);
				}
			}
			return num;
		}

		internal static int InjectTasks(PreferencesManager pm, PresetLibraryDto missing)
		{
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Expected O, but got Unknown
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Expected O, but got Unknown
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			int num = 0;
			if ((Object)(object)pm.networkLogic == (Object)null)
			{
				return num;
			}
			string text2 = default(string);
			bool flag = default(bool);
			foreach (TasksPresetDto task in missing.Tasks)
			{
				try
				{
					string text = PresetNames.Normalize(task.Name);
					if (text.Length == 0)
					{
						continue;
					}
					if (pm.networkLogic._GetNextAvailableTaskPresetSlot() < 0)
					{
						Plugin.Log.LogWarning((object)("restore: task preset capacity full; '" + text + "' and any remaining task presets were not injected."));
						break;
					}
					if (!pm.networkLogic.AddTaskPresetFromDeserialization(text, task.TemplateId, ref text2))
					{
						ManualLogSource log = Plugin.Log;
						BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(69, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("restore: task preset '");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' rejected by AddTaskPresetFromDeserialization.");
						}
						log.LogWarning(val);
						continue;
					}
					DataObject val2 = new DataObject();
					DataArray val3 = new DataArray();
					if (task.Rows != null)
					{
						foreach (TaskRowDto row in task.Rows)
						{
							DataObject val4 = new DataObject();
							val4.AddElement("itmInfo", DataElement.op_Implicit(row.ItemId));
							val4.AddElement("taskPrio", DataElement.op_Implicit(row.Priority));
							val4.AddElement("qttyR", DataElement.op_Implicit(row.QuantityRatio));
							val3.AddElement((DataElement)(object)val4);
						}
					}
					val2.AddElement("tdArray", (DataElement)(object)val3);
					if (pm._tasksPresetsData == null)
					{
						ManualLogSource log2 = Plugin.Log;
						BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(85, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("restore: task preset '");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' added but _tasksPresetsData is unavailable; rows not written.");
						}
						log2.LogWarning(val);
						continue;
					}
					pm._tasksPresetsData[text2] = val2;
					num++;
					ManualLogSource log3 = Plugin.Log;
					BepInExInfoLogInterpolatedStringHandler val5 = new BepInExInfoLogInterpolatedStringHandler(34, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("restored task preset '");
						((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<string>(text2);
						((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("' (");
						((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<int>(task.Rows?.Count ?? 0);
						((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(" row(s)).");
					}
					log3.LogInfo(val5);
				}
				catch (Exception ex)
				{
					ManualLogSource log4 = Plugin.Log;
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(32, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("restore: task preset '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(task.Name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' failed: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					log4.LogWarning(val);
				}
			}
			return num;
		}

		internal static ISet<int> KnownItemIds()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			try
			{
				ItemDatabaseManager val = Object.FindObjectOfType<ItemDatabaseManager>();
				if ((Object)val == (Object)null)
				{
					return null;
				}
				ItemInfoDatabase database = val.Database;
				if ((Object)database == (Object)null)
				{
					return null;
				}
				Dictionary<int, ItemInfo> itemsMap = database._itemsMap;
				if (itemsMap == null)
				{
					return null;
				}
				HashSet<int> hashSet = new HashSet<int>();
				Enumerator<int, ItemInfo> enumerator = itemsMap.GetEnumerator();
				while (enumerator.MoveNext())
				{
					KeyValuePair<int, ItemInfo> current = enumerator.Current;
					hashSet.Add(current.Key);
				}
				return hashSet;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(21, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("KnownItemIds failed: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val2);
				return null;
			}
		}
	}
	internal static class PreferencesManagerPatches
	{
		internal static volatile bool CaptureRequested;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PreferencesManager), "Serialize")]
		private static void SerializePostfix()
		{
			if (PresetSaverConfig.Capture.Value)
			{
				CaptureRequested = true;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PreferencesManager), "Deserialize")]
		private static void DeserializePostfix()
		{
			if (PresetSaverConfig.Restore.Value && RestoreBehaviour.Arm())
			{
				Plugin.Log.LogInfo((object)"restore armed.");
			}
		}
	}
	internal static class PresetSaverConfig
	{
		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> Capture;

		internal static ConfigEntry<bool> Restore;

		internal static void Init(ConfigFile config)
		{
			Enabled = config.Bind<bool>("PresetSaver", "Enabled", true, "Master switch. When false the mod does nothing at all.");
			Capture = config.Bind<bool>("PresetSaver", "Capture", true, "Save presets from your game into the global library when the game saves.");
			Restore = config.Bind<bool>("PresetSaver", "Restore", true, "Re-create presets from the global library when a save is loaded. Presets already present in the save are never touched.");
		}
	}
	internal static class PresetStore
	{
		internal static string Path => System.IO.Path.Combine(Paths.ConfigPath, "PresetSaver", "presets.json");

		internal static PresetLibraryDto Load()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			try
			{
				if (!File.Exists(Path))
				{
					return new PresetLibraryDto();
				}
				return PresetLibrary.FromJson(File.ReadAllText(Path));
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(46, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("preset library load failed (");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("); starting empty.");
				}
				log.LogWarning(val);
				return new PresetLibraryDto();
			}
		}

		internal static void Save(PresetLibraryDto library)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			try
			{
				Directory.CreateDirectory(System.IO.Path.GetDirectoryName(Path));
				string text = Path + ".tmp";
				File.WriteAllText(text, PresetLibrary.ToJson(library));
				File.Copy(text, Path, overwrite: true);
				File.Delete(text);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(29, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("preset library write failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val);
			}
		}
	}
	public sealed class RestoreBehaviour : MonoBehaviour
	{
		private static volatile bool _armed;

		private const int MaxItemIdsUnavailableFrames = 300;

		private static int _itemIdsUnavailableFrames;

		public RestoreBehaviour(IntPtr ptr)
			: base(ptr)
		{
		}

		internal static bool Arm()
		{
			if (_armed)
			{
				return false;
			}
			_armed = true;
			return true;
		}

		private void Update()
		{
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Expected O, but got Unknown
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Expected O, but got Unknown
			if (!_armed || (Object)Object.FindObjectOfType<PlayerCharacter>() == (Object)null)
			{
				return;
			}
			PreferencesManager val = Object.FindObjectOfType<PreferencesManager>();
			if ((Object)val == (Object)null)
			{
				return;
			}
			if (!val.IsLocalStorageClient)
			{
				Plugin.Log.LogInfo((object)"restore skipped: not the local storage client (joined another host's game).");
				_armed = false;
			}
			else
			{
				if ((Object)(object)val.networkLogic == (Object)null)
				{
					return;
				}
				if (PresetSaverConfig.Restore.Value)
				{
					ISet<int> set = PreferencesBridge.KnownItemIds();
					bool flag = false;
					if (set == null)
					{
						_itemIdsUnavailableFrames++;
						if (_itemIdsUnavailableFrames < 300)
						{
							return;
						}
						flag = true;
						_itemIdsUnavailableFrames = 0;
					}
					else
					{
						_itemIdsUnavailableFrames = 0;
					}
					_armed = false;
					bool flag2 = default(bool);
					try
					{
						PresetLibraryDto val2 = PresetStore.Load();
						PresetLibraryDto val3;
						if (flag)
						{
							Plugin.Log.LogWarning((object)($"restore: item database unavailable after {300} " + "frame(s) of polling; SKIPPING template/item id validation and injecting task presets UNVALIDATED."));
							val3 = val2;
						}
						else
						{
							Action<string> action = delegate(string msg)
							{
								//IL_000a: Unknown result type (might be due to invalid IL or missing references)
								//IL_0010: Expected O, but got Unknown
								ManualLogSource log3 = Plugin.Log;
								bool flag3 = default(bool);
								BepInExWarningLogInterpolatedStringHandler val7 = new BepInExWarningLogInterpolatedStringHandler(17, 1, ref flag3);
								if (flag3)
								{
									((BepInExLogInterpolatedStringHandler)val7).AppendLiteral("restore: dropped ");
									((BepInExLogInterpolatedStringHandler)val7).AppendFormatted<string>(msg);
								}
								log3.LogWarning(val7);
							};
							val3 = PresetValidation.DropUnresolvable(val2, set, (ISet<int>)new HashSet<int>(), action);
						}
						PresetLibraryDto val4 = PreferencesBridge.Capture(val);
						PresetLibraryDto missing = PresetLibrary.MissingFrom(val3, val4);
						int num = PreferencesBridge.InjectSchedules(val, missing);
						int num2 = PreferencesBridge.InjectTasks(val, missing);
						ManualLogSource log = Plugin.Log;
						BepInExInfoLogInterpolatedStringHandler val5 = new BepInExInfoLogInterpolatedStringHandler(117, 4, ref flag2);
						if (flag2)
						{
							((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("restore complete: ");
							((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<int>(num);
							((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(" schedule preset(s) and ");
							((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<int>(num2);
							((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(" task preset(s) injected, ");
							((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<int>(val4.Schedules.Count);
							((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(" schedule(s) and ");
							((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<int>(val4.Tasks.Count);
							((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(" task preset(s) already present.");
						}
						log.LogInfo(val5);
						return;
					}
					catch (Exception ex)
					{
						ManualLogSource log2 = Plugin.Log;
						BepInExWarningLogInterpolatedStringHandler val6 = new BepInExWarningLogInterpolatedStringHandler(16, 1, ref flag2);
						if (flag2)
						{
							((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("restore failed: ");
							((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<string>(ex.Message);
						}
						log2.LogWarning(val6);
						return;
					}
				}
				_armed = false;
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "AskaPresetSaver";

		public const string PLUGIN_NAME = "Aska Preset Saver";

		public const string PLUGIN_VERSION = "0.2.0";
	}
}

AskaPresetSaver.Core.dll

Decompiled 13 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("AskaPresetSaver.Core")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+91ff6e46d0d62bf196bf09f71f08f796e81a0034")]
[assembly: AssemblyProduct("AskaPresetSaver.Core")]
[assembly: AssemblyTitle("AskaPresetSaver.Core")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 AskaPresetSaver.Core
{
	public sealed class PresetLibraryDto
	{
		public int SchemaVersion { get; set; } = 1;

		public List<SchedulePresetDto> Schedules { get; set; } = new List<SchedulePresetDto>();

		public List<TasksPresetDto> Tasks { get; set; } = new List<TasksPresetDto>();

		public List<EquipColorPresetDto> EquipmentColors { get; set; } = new List<EquipColorPresetDto>();
	}
	public sealed class SchedulePresetDto
	{
		public string Name { get; set; } = "";

		public int[] Schedule { get; set; } = Array.Empty<int>();
	}
	public sealed class TasksPresetDto
	{
		public string Name { get; set; } = "";

		public int TemplateId { get; set; }

		public List<TaskRowDto> Rows { get; set; } = new List<TaskRowDto>();
	}
	public sealed class TaskRowDto
	{
		public int ItemId { get; set; }

		public int Priority { get; set; }

		public float QuantityRatio { get; set; }
	}
	public sealed class EquipColorPresetDto
	{
		public string Name { get; set; } = "";

		public int[] DyeIds { get; set; } = Array.Empty<int>();
	}
	public static class PresetLibrary
	{
		private static readonly JsonSerializerOptions Options = new JsonSerializerOptions
		{
			WriteIndented = true
		};

		public static PresetLibraryDto FromJson(string? json)
		{
			if (string.IsNullOrWhiteSpace(json))
			{
				return new PresetLibraryDto();
			}
			try
			{
				PresetLibraryDto? obj = JsonSerializer.Deserialize<PresetLibraryDto>(json, Options) ?? new PresetLibraryDto();
				PresetLibraryDto presetLibraryDto = obj;
				if (presetLibraryDto.Schedules == null)
				{
					List<SchedulePresetDto> list = (presetLibraryDto.Schedules = new List<SchedulePresetDto>());
				}
				presetLibraryDto = obj;
				if (presetLibraryDto.Tasks == null)
				{
					List<TasksPresetDto> list3 = (presetLibraryDto.Tasks = new List<TasksPresetDto>());
				}
				presetLibraryDto = obj;
				if (presetLibraryDto.EquipmentColors == null)
				{
					List<EquipColorPresetDto> list5 = (presetLibraryDto.EquipmentColors = new List<EquipColorPresetDto>());
				}
				return obj;
			}
			catch (JsonException)
			{
				return new PresetLibraryDto();
			}
		}

		public static string ToJson(PresetLibraryDto library)
		{
			return JsonSerializer.Serialize(library, Options);
		}

		public static PresetLibraryDto MergeCaptured(PresetLibraryDto existing, PresetLibraryDto captured)
		{
			PresetLibraryDto presetLibraryDto = new PresetLibraryDto();
			presetLibraryDto.SchemaVersion = existing.SchemaVersion;
			presetLibraryDto.Schedules.AddRange(existing.Schedules);
			AddNew(presetLibraryDto.Schedules, captured.Schedules, (SchedulePresetDto s) => s.Name);
			presetLibraryDto.Tasks.AddRange(existing.Tasks);
			AddNew(presetLibraryDto.Tasks, captured.Tasks, (TasksPresetDto t) => t.Name);
			presetLibraryDto.EquipmentColors.AddRange(existing.EquipmentColors);
			AddNew(presetLibraryDto.EquipmentColors, captured.EquipmentColors, (EquipColorPresetDto c) => c.Name);
			return presetLibraryDto;
		}

		public static PresetLibraryDto MissingFrom(PresetLibraryDto library, PresetLibraryDto inSave)
		{
			PresetLibraryDto obj = new PresetLibraryDto
			{
				SchemaVersion = library.SchemaVersion
			};
			AddNew(obj.Schedules, library.Schedules.Where((SchedulePresetDto l) => !inSave.Schedules.Any((SchedulePresetDto s) => PresetNames.SameAs(s.Name, l.Name))), (SchedulePresetDto s) => s.Name);
			AddNew(obj.Tasks, library.Tasks.Where((TasksPresetDto l) => !inSave.Tasks.Any((TasksPresetDto s) => PresetNames.SameAs(s.Name, l.Name))), (TasksPresetDto t) => t.Name);
			AddNew(obj.EquipmentColors, library.EquipmentColors.Where((EquipColorPresetDto l) => !inSave.EquipmentColors.Any((EquipColorPresetDto s) => PresetNames.SameAs(s.Name, l.Name))), (EquipColorPresetDto c) => c.Name);
			return obj;
		}

		private static void AddNew<T>(List<T> target, IEnumerable<T> candidates, Func<T, string> name)
		{
			foreach (T candidate in candidates)
			{
				if (!target.Any((T t) => PresetNames.SameAs(name(t), name(candidate))))
				{
					target.Add(candidate);
				}
			}
		}
	}
	public static class PresetNames
	{
		public const int MaxLength = 16;

		public static string Normalize(string? name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return "";
			}
			string text = name.Trim();
			if (text.Length > 16)
			{
				return text.Substring(0, 16);
			}
			return text;
		}

		public static bool SameAs(string? a, string? b)
		{
			return string.Equals(Normalize(a), Normalize(b), StringComparison.OrdinalIgnoreCase);
		}
	}
	public static class PresetValidation
	{
		public static PresetLibraryDto DropUnresolvable(PresetLibraryDto library, ISet<int> knownItemIds, ISet<int> knownDyeIds, Action<string>? onDropped = null)
		{
			PresetLibraryDto presetLibraryDto = new PresetLibraryDto
			{
				SchemaVersion = library.SchemaVersion
			};
			List<SchedulePresetDto> schedules = presetLibraryDto.Schedules;
			IEnumerable<SchedulePresetDto> schedules2 = library.Schedules;
			schedules.AddRange(schedules2 ?? Enumerable.Empty<SchedulePresetDto>());
			IEnumerable<TasksPresetDto> tasks = library.Tasks;
			foreach (TasksPresetDto task in tasks ?? Enumerable.Empty<TasksPresetDto>())
			{
				if (!knownItemIds.Contains(task.TemplateId))
				{
					onDropped?.Invoke($"tasks preset '{task.Name}': unknown template id {task.TemplateId}");
					continue;
				}
				TasksPresetDto tasksPresetDto = new TasksPresetDto
				{
					Name = task.Name,
					TemplateId = task.TemplateId
				};
				tasksPresetDto.Rows.AddRange(KeepKnown(task.Rows, (TaskRowDto row) => row.ItemId, knownItemIds, (TaskRowDto row) => $"tasks preset '{task.Name}': unknown item id {row.ItemId}", onDropped));
				presetLibraryDto.Tasks.Add(tasksPresetDto);
			}
			IEnumerable<EquipColorPresetDto> equipmentColors = library.EquipmentColors;
			foreach (EquipColorPresetDto color in equipmentColors ?? Enumerable.Empty<EquipColorPresetDto>())
			{
				List<int> list = KeepKnown(color.DyeIds, (int dye) => dye, knownDyeIds, (int dye) => $"color preset '{color.Name}': unknown dye id {dye}", onDropped);
				presetLibraryDto.EquipmentColors.Add(new EquipColorPresetDto
				{
					Name = color.Name,
					DyeIds = list.ToArray()
				});
			}
			return presetLibraryDto;
		}

		private static List<T> KeepKnown<T>(IEnumerable<T>? items, Func<T, int> idOf, ISet<int> knownIds, Func<T, string> dropMessage, Action<string>? onDropped)
		{
			List<T> list = new List<T>();
			foreach (T item in items ?? Enumerable.Empty<T>())
			{
				if (knownIds.Contains(idOf(item)))
				{
					list.Add(item);
				}
				else
				{
					onDropped?.Invoke(dropMessage(item));
				}
			}
			return list;
		}
	}
}