Decompiled source of Brew From Here v2.0.0

plugins/PotionCraftBrewFromHere.dll

Decompiled 2 weeks 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.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using DarkScreenSystem;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using PotionCraft.Core;
using PotionCraft.ManagersSystem;
using PotionCraft.ManagersSystem.Potion;
using PotionCraft.ManagersSystem.Potion.Entities;
using PotionCraft.ManagersSystem.SaveLoad;
using PotionCraft.NotificationSystem;
using PotionCraft.ObjectBased.InteractiveItem;
using PotionCraft.ObjectBased.RecipeMap.Path;
using PotionCraft.ObjectBased.RecipeMap.RecipeMapItem;
using PotionCraft.ObjectBased.RecipeMap.RecipeMapItem.PathMapItem;
using PotionCraft.ObjectBased.UIElements;
using PotionCraft.ObjectBased.UIElements.Bookmarks;
using PotionCraft.ObjectBased.UIElements.Books;
using PotionCraft.ObjectBased.UIElements.Books.RecipeBook;
using PotionCraft.ObjectBased.UIElements.PotionCraftPanel;
using PotionCraft.SaveFileSystem;
using PotionCraft.SaveLoadSystem;
using PotionCraft.ScriptableObjects;
using PotionCraft.ScriptableObjects.Ingredient;
using PotionCraft.ScriptableObjects.Potion;
using PotionCraft.ScriptableObjects.Salts;
using PotionCraftUsefulRecipeMarks.Scripts;
using PotionCraftUsefulRecipeMarks.Scripts.Json;
using PotionCraftUsefulRecipeMarks.Scripts.Services;
using PotionCraftUsefulRecipeMarks.Scripts.Storage;
using PotionCraftUsefulRecipeMarks.Scripts.Storage.Delta;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PotionCraftBrewFromHere")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Recipe Waypoint Mod for Potion Craft")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+e859b5ed3bf7d2ed7f325b5227e700e362cb6fe5")]
[assembly: AssemblyProduct("PotionCraftBrewFromHere")]
[assembly: AssemblyTitle("PotionCraftBrewFromHere")]
[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 PotionCraftUsefulRecipeMarks
{
	[BepInPlugin("com.fahlgorithm.potioncraftbrewfromhere", "PotionCraftBrewFromHere", "2.0.0.0")]
	[BepInProcess("Potion Craft.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PLUGIN_GUID = "com.fahlgorithm.potioncraftbrewfromhere";

		public const string PLUGIN_VERSION = "2.0.0.0";

		public static ManualLogSource PluginLogger { get; private set; }

		public static void LogInfo(string message)
		{
			PluginLogger.LogInfo((object)message);
		}

		public static void LogError(string message)
		{
			PluginLogger.LogError((object)message);
			Ex.SaveErrorMessage(message);
		}

		private void Awake()
		{
			PluginLogger = ((BaseUnityPlugin)this).Logger;
			PluginLogger.LogInfo((object)"Plugin com.fahlgorithm.potioncraftbrewfromhere is loaded!");
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "com.fahlgorithm.potioncraftbrewfromhere");
			PluginLogger.LogInfo((object)"Plugin com.fahlgorithm.potioncraftbrewfromhere: Patch Succeeded!");
			StaticStorage.BookmarkOrganizerOldVersionInstalled = Chainloader.PluginInfos.Any((KeyValuePair<string, PluginInfo> p) => p.Value.Metadata.GUID.Equals("com.fahlgorithm.potioncraftbookmarkorganizer") && p.Value.Metadata.Version < new Version(1, 0, 5, 3));
			if (StaticStorage.BookmarkOrganizerOldVersionInstalled)
			{
				PluginLogger.LogError((object)"An old version of Bookmark Organizer is installed! This version causes some issues for this mod and should be updated as soon as possible!");
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "PotionCraftBrewFromHere";

		public const string PLUGIN_NAME = "PotionCraftBrewFromHere";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace PotionCraftUsefulRecipeMarks.Scripts
{
	public static class Ex
	{
		public static bool RunSafe(Func<bool> action, Func<bool> errorAction = null, bool logErrorToStorage = false)
		{
			try
			{
				return action();
			}
			catch (Exception ex)
			{
				LogException(ex, logErrorToStorage);
			}
			return errorAction?.Invoke() ?? true;
		}

		public static void RunSafe(Action action, Action errorAction = null, bool logErrorToStorage = false)
		{
			try
			{
				action();
			}
			catch (Exception ex)
			{
				LogException(ex, logErrorToStorage);
				errorAction?.Invoke();
			}
		}

		public static void LogException(Exception ex, bool logErrorToStorage = false)
		{
			string exceptionText = GetExceptionText(ex);
			Plugin.PluginLogger.LogError((object)exceptionText);
			if (logErrorToStorage)
			{
				StaticStorage.ErrorLog.Add(exceptionText);
			}
		}

		public static string GetExceptionText(Exception ex)
		{
			return $"{DateTime.UtcNow}: {ex.GetType()}: {ex.Message}\r\n{ex.StackTrace}\r\n{ex.InnerException?.Message}";
		}

		public static void SaveErrorMessage(string errorMessage)
		{
			StaticStorage.ErrorLog.Add($"{DateTime.UtcNow}: {errorMessage}");
		}
	}
	public static class Extensions
	{
		public static (float x, float y) ToTuple(this Vector3 vector)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return Vector2.op_Implicit(vector).ToTuple();
		}

		public static (float x, float y) ToTuple(this Vector2 vector)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return (vector.x, vector.y);
		}

		public static Vector2 ToVector(this (float x, float y) tuple)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2(tuple.x, tuple.y);
		}

		public static SerializedPotionRecipeData GetRecipeData(this Potion potion)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			return (SerializedPotionRecipeData)potion.GetSerializedRecipeData();
		}
	}
	public static class Saver
	{
		public class SaveState
		{
			public Dictionary<int, RecipeMarkInfo> CurrentPotionRecipeMarkInfos { get; set; }

			public Dictionary<DeltaProperty, BaseDelta> CurrentPotionState { get; set; }

			public RecipeMarkInfo CurrentRecipeMarkInfo { get; set; }

			public Dictionary<int, RecipeMarkInfo> PreviousPotionRecipeMarkInfo { get; set; }

			public Dictionary<DeltaProperty, BaseDelta> SelectedRecipePotionState { get; set; }

			public int SelectedRecipeMarkIndex { get; set; }

			public int SelectedRecipeIndex { get; set; }

			public Dictionary<int, Dictionary<int, RecipeMarkInfo>> RecipeMarkInfos { get; set; }

			public List<string> ErrorLog { get; set; }

			public string Version { get; set; }
		}

		[HarmonyPatch(typeof(SavedState), "ToJson")]
		public class SavedState_ToJson
		{
			private static void Postfix(ref string __result)
			{
				StoreData(ref __result);
			}
		}

		[HarmonyPatch(typeof(SaveLoadManager), "LoadProgressState")]
		public class SaveLoadManager_LoadProgressState
		{
			private static bool Prefix()
			{
				return RetreiveStoredData();
			}
		}

		[HarmonyPatch(typeof(File), "Load")]
		public class File_Load
		{
			private static bool Prefix(File __instance)
			{
				return RetrieveStateJsonString(__instance);
			}
		}

		private class Deserialized<T>
		{
			[JsonProperty("FahlgorithmUsefulRecipeMarks")]
			public T DeserializedObject { get; set; }
		}

		public const string JsonSaveName = "FahlgorithmUsefulRecipeMarks";

		public static string StateJsonString;

		private static SaveState GetSaveState()
		{
			return new SaveState
			{
				CurrentPotionRecipeMarkInfos = StaticStorage.CurrentPotionRecipeMarkInfos,
				CurrentPotionState = StaticStorage.CurrentPotionState,
				CurrentRecipeMarkInfo = StaticStorage.CurrentRecipeMarkInfo,
				PreviousPotionRecipeMarkInfo = StaticStorage.PreviousPotionRecipeMarkInfo,
				SelectedRecipePotionState = StaticStorage.SelectedRecipePotionState,
				SelectedRecipeMarkIndex = StaticStorage.SelectedRecipeMarkIndex,
				SelectedRecipeIndex = StaticStorage.SelectedRecipeIndex,
				RecipeMarkInfos = StaticStorage.RecipeMarkInfos,
				ErrorLog = StaticStorage.ErrorLog,
				Version = "2.0.0.0"
			};
		}

		private static void LoadSaveState(SaveState loadedSaveState)
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Expected O, but got Unknown
			if (loadedSaveState == null)
			{
				LogError("Error: An error occured during deserialization. Could not find load save state!");
				return;
			}
			if (loadedSaveState.CurrentPotionRecipeMarkInfos == null || loadedSaveState.CurrentPotionState == null || loadedSaveState.RecipeMarkInfos == null || loadedSaveState.ErrorLog == null)
			{
				LogError("Error: An error occured during deserialization. A property was null!");
				return;
			}
			StaticStorage.CurrentPotionRecipeMarkInfos = loadedSaveState.CurrentPotionRecipeMarkInfos;
			StaticStorage.CurrentPotionState = loadedSaveState.CurrentPotionState;
			StaticStorage.CurrentRecipeMarkInfo = loadedSaveState.CurrentRecipeMarkInfo;
			StaticStorage.PreviousPotionRecipeMarkInfo = loadedSaveState.PreviousPotionRecipeMarkInfo;
			StaticStorage.SelectedRecipePotionState = loadedSaveState.SelectedRecipePotionState;
			StaticStorage.SelectedRecipeMarkIndex = loadedSaveState.SelectedRecipeMarkIndex;
			StaticStorage.SelectedRecipeIndex = loadedSaveState.SelectedRecipeIndex;
			StaticStorage.RecipeMarkInfos = loadedSaveState.RecipeMarkInfos;
			StaticStorage.ErrorLog = loadedSaveState.ErrorLog;
			StaticStorage.ShouldLoadLastBrewState = StaticStorage.CurrentRecipeMarkInfo != null;
			int currentPageIndex = ((Book)RecipeBook.Instance).currentPageIndex;
			if (!RecipeReconstructionService.MarkHasSavedData(currentPageIndex, StaticStorage.SelectedRecipeMarkIndex))
			{
				RecipeBookUIService.DisableOldRecipeMarks((RecipeBookRightPageContent)((Book)RecipeBook.Instance).curlPageController.frontRightPage.pageContent);
			}
			else
			{
				RecipeBookUIService.UpdateRecipeBookPageForSelectedRecipeMark(currentPageIndex, StaticStorage.SelectedRecipeMarkIndex);
			}
		}

		private static void LogError(string errorMessage)
		{
			Plugin.PluginLogger.LogInfo((object)errorMessage);
		}

		public static void StoreData(ref string result)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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)
			//IL_002e: Expected O, but got Unknown
			string text = null;
			try
			{
				string obj = result;
				SaveState saveState = GetSaveState();
				if (saveState == null)
				{
					LogError("Error: no data found to save!");
				}
				string text2 = JsonConvert.SerializeObject((object)saveState, new JsonSerializerSettings
				{
					ReferenceLoopHandling = (ReferenceLoopHandling)1,
					TypeNameHandling = (TypeNameHandling)4
				});
				string value = ",\"FahlgorithmUsefulRecipeMarks\":" + text2;
				int startIndex = obj.LastIndexOf('}');
				text = obj.Insert(startIndex, value);
			}
			catch (Exception ex)
			{
				LogError($"{ex.GetType()}: {ex.Message}\r\n{ex.StackTrace}\r\n{ex.InnerException?.Message}");
			}
			if (!string.IsNullOrEmpty(text))
			{
				result = text;
			}
		}

		public static bool RetreiveStoredData()
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			try
			{
				SaveLoadService.ClearFileSpecificDataOnFileLoad();
				string stateJsonString = StateJsonString;
				StateJsonString = null;
				if (string.IsNullOrEmpty(stateJsonString))
				{
					LogError("Error: stateJsonString is empty. Cannot load data.");
					return true;
				}
				if (stateJsonString.IndexOf("FahlgorithmUsefulRecipeMarks") == -1)
				{
					LogError("No existing data found during load");
					return true;
				}
				NamespaceMigrationSerializationBinder serializationBinder = new NamespaceMigrationSerializationBinder(new BasicNamespaceMigration
				{
					FromAssembly = "PotionCraftBrewFromHere",
					FromType = "PotionCraftUsefulRecipeMarks.Scripts.Storage.Delta.ModifyDelta`1[[PotionCraft.SaveLoadSystem.ProgressState+SerializedPath, PotionCraft.Scripts]]",
					ToType = typeof(ModifyDelta<SerializedPath>)
				});
				LoadSaveState(JsonConvert.DeserializeObject<Deserialized<SaveState>>(stateJsonString, new JsonSerializerSettings
				{
					ReferenceLoopHandling = (ReferenceLoopHandling)1,
					TypeNameHandling = (TypeNameHandling)4,
					SerializationBinder = (ISerializationBinder)(object)serializationBinder
				}).DeserializedObject);
			}
			catch (Exception ex)
			{
				LogError($"{ex.GetType()}: {ex.Message}\r\n{ex.StackTrace}\r\n{ex.InnerException?.Message}");
			}
			return true;
		}

		public static bool RetrieveStateJsonString(File instance)
		{
			try
			{
				StateJsonString = instance.StateJsonString;
			}
			catch (Exception ex)
			{
				LogError($"{ex.GetType()}: {ex.Message}\r\n{ex.StackTrace}\r\n{ex.InnerException?.Message}");
			}
			return true;
		}
	}
}
namespace PotionCraftUsefulRecipeMarks.Scripts.Storage
{
	public class FixedHintTimeline
	{
		public int FixedHintIndex { get; set; }

		public string IngredientName { get; set; }

		public float GrindPercent { get; set; }

		public int AddedRecipeIndex { get; set; } = int.MaxValue;


		public SortedDictionary<int, List<ModifyDelta>> Timeline { get; set; } = new SortedDictionary<int, List<ModifyDelta>>();


		public void AddInformationFromDeltas(List<SerializedRecipeMark> recipeMarks, int recipeMarkIndex, List<ModifyDelta> deltas)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			SerializedRecipeMark val = recipeMarks[recipeMarkIndex];
			if ((int)val.type == 1)
			{
				IngredientName = val.stringValue;
				GrindPercent = val.floatValue;
			}
			Timeline[recipeMarkIndex] = deltas.Where((ModifyDelta d) => d.Property == DeltaProperty.FixedHint_Length).ToList();
			if (recipeMarkIndex < AddedRecipeIndex)
			{
				AddedRecipeIndex = recipeMarkIndex;
			}
		}
	}
	public class RecipeMarkInfo
	{
		public int Index { get; set; }

		public List<BaseDelta> Deltas { get; set; } = new List<BaseDelta>();

	}
	public class ReconstructionTimeline
	{
		public Dictionary<int, FixedHintTimeline> FixedHintTimelines = new Dictionary<int, FixedHintTimeline>();

		public SortedDictionary<int, List<BaseDelta>> PathRotationTimeline = new SortedDictionary<int, List<BaseDelta>>();

		public void AddBasePropertyInformationFromDeltas(List<SerializedRecipeMark> recipeMarks, int recipeMarkIndex, List<BaseDelta> deltas)
		{
			List<BaseDelta> list = deltas.Where((BaseDelta d) => d.Property == DeltaProperty.Rotation).ToList();
			if (list.Any())
			{
				PathRotationTimeline[recipeMarkIndex] = list;
			}
		}

		public List<(int index, bool fromEnd, float length)> GetPathDeletionEvents(List<SerializedRecipeMark> allRecipeMarks, int fixedHintIndex)
		{
			List<(int, bool, float)> deletionEvents = new List<(int, bool, float)>();
			if (!FixedHintTimelines.TryGetValue(fixedHintIndex, out var value))
			{
				return deletionEvents;
			}
			int addedIndex = value.AddedRecipeIndex;
			int nextAddedIndex = (from p in FixedHintTimelines
				where p.Key > fixedHintIndex
				orderby p.Key
				select p.Value).FirstOrDefault()?.AddedRecipeIndex ?? int.MaxValue;
			FixedHintTimelines.Values.ToList().ForEach(delegate(FixedHintTimeline FixedHintTimeline)
			{
				float currentLength = -1f;
				FixedHintTimeline.Timeline.Where((KeyValuePair<int, List<ModifyDelta>> prt) => prt.Key < nextAddedIndex).ToList().ForEach(delegate(KeyValuePair<int, List<ModifyDelta>> prt)
				{
					//IL_006e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0074: Invalid comparison between Unknown and I4
					ModifyDelta<float> modifyDelta = prt.Value.FirstOrDefault((ModifyDelta d) => d.Property == DeltaProperty.FixedHint_Length) as ModifyDelta<float>;
					if (!(modifyDelta == null))
					{
						if (currentLength < 0f)
						{
							currentLength = modifyDelta.NewValue;
						}
						else
						{
							SerializedRecipeMark val = allRecipeMarks[prt.Key];
							bool item = (int)val.type == 5 && val.stringValue == "Void Salt";
							float num = currentLength - modifyDelta.NewValue;
							if (num < 0f)
							{
								throw new Exception("Looks like someone added a new salt. This mod simply cannot handle paths which increase in length.");
							}
							if (!(num < 0.0001f))
							{
								if (prt.Key >= addedIndex)
								{
									deletionEvents.Add((prt.Key, item, num));
								}
								currentLength = modifyDelta.NewValue;
							}
						}
					}
				});
			});
			return deletionEvents;
		}

		public List<(int index, Quaternion rotation)> GetRotationEventsForFixedHint(int fixedHintIndex)
		{
			List<(int, Quaternion)> rotationEvents = new List<(int, Quaternion)>();
			if (!FixedHintTimelines.TryGetValue(fixedHintIndex, out var value))
			{
				return rotationEvents;
			}
			int addedIndex = value.AddedRecipeIndex;
			int nextAddedIndex = (from p in FixedHintTimelines
				where p.Key > fixedHintIndex
				orderby p.Key
				select p.Value).FirstOrDefault()?.AddedRecipeIndex ?? int.MaxValue;
			PathRotationTimeline.Where((KeyValuePair<int, List<BaseDelta>> prt) => prt.Key >= addedIndex && prt.Key < nextAddedIndex).ToList().ForEach(delegate(KeyValuePair<int, List<BaseDelta>> prt)
			{
				AddRotationEvent(prt.Key, prt.Value, rotationEvents);
			});
			return rotationEvents;
		}

		private void AddRotationEvent(int index, List<BaseDelta> deltas, List<(int, Quaternion)> rotationEvents)
		{
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			ModifyDelta<float> modifyDelta = deltas.FirstOrDefault((BaseDelta d) => d.Property == DeltaProperty.Rotation) as ModifyDelta<float>;
			if (modifyDelta == null)
			{
				return;
			}
			float num = (from p in PathRotationTimeline
				where p.Key < index
				orderby p.Key descending
				select p.Value.FirstOrDefault((BaseDelta d) => d.Property == DeltaProperty.Rotation) as ModifyDelta<float> into p
				where p != null
				select p).FirstOrDefault()?.NewValue ?? 0f;
			float newValue = modifyDelta.NewValue;
			if (newValue != num)
			{
				rotationEvents.Add((index, Quaternion.Euler(0f, 0f, newValue - num)));
			}
		}
	}
	public static class StaticStorage
	{
		public static List<string> ErrorLog = new List<string>();

		public static bool AddedListeners;

		public static Dictionary<int, RecipeMarkInfo> CurrentPotionRecipeMarkInfos = new Dictionary<int, RecipeMarkInfo>();

		public static Dictionary<DeltaProperty, BaseDelta> CurrentPotionState = new Dictionary<DeltaProperty, BaseDelta>();

		public static RecipeMarkInfo CurrentRecipeMarkInfo;

		public static Dictionary<int, RecipeMarkInfo> PreviousPotionRecipeMarkInfo;

		public static Dictionary<DeltaProperty, BaseDelta> SelectedRecipePotionState;

		public static int SelectedRecipeMarkIndex;

		public static int SelectedRecipeIndex;

		public static Dictionary<int, Dictionary<int, RecipeMarkInfo>> RecipeMarkInfos = new Dictionary<int, Dictionary<int, RecipeMarkInfo>>();

		public static bool ShouldLoadLastBrewState;

		public static bool BookmarkOrganizerOldVersionInstalled;

		public static List<IRecipeBookPageContent> RecipeIndexes;
	}
	public class UsefulRecipeMarksManager : MonoBehaviour
	{
		public Dictionary<int, RecipeMarkInfo> CurrentPotionRecipeMarkInfos => StaticStorage.CurrentPotionRecipeMarkInfos;

		public Dictionary<DeltaProperty, BaseDelta> CurrentPotionState => StaticStorage.CurrentPotionState;

		public RecipeMarkInfo CurrentRecipeMarkInfo => StaticStorage.CurrentRecipeMarkInfo;

		public Dictionary<int, Dictionary<int, RecipeMarkInfo>> RecipeMarkInfos => StaticStorage.RecipeMarkInfos;

		public Dictionary<int, RecipeMarkInfo> PreviousPotionRecipeMarkInfo => StaticStorage.PreviousPotionRecipeMarkInfo;

		public Dictionary<DeltaProperty, BaseDelta> SelectedRecipePotionState => StaticStorage.SelectedRecipePotionState;

		public int SelectedRecipeMarkIndex => StaticStorage.SelectedRecipeMarkIndex;

		public int SelectedRecipeIndex => StaticStorage.SelectedRecipeIndex;

		public List<IRecipeBookPageContent> RecipeIndexes => StaticStorage.RecipeIndexes;
	}
}
namespace PotionCraftUsefulRecipeMarks.Scripts.Storage.Delta
{
	public abstract class BaseDelta
	{
		public DeltaProperty Property { get; set; }

		public static bool operator ==(BaseDelta obj1, BaseDelta obj2)
		{
			if ((object)obj1 == null || (object)obj2 == null)
			{
				if ((object)obj1 == null)
				{
					return (object)obj2 == null;
				}
				return false;
			}
			return obj1.Equals(obj2);
		}

		public static bool operator !=(BaseDelta obj1, BaseDelta obj2)
		{
			if ((object)obj1 == null || (object)obj2 == null)
			{
				if ((object)obj1 == null)
				{
					return (object)obj2 != null;
				}
				return true;
			}
			return !obj1.Equals(obj2);
		}

		public override bool Equals(object obj)
		{
			if (obj is BaseDelta baseDelta)
			{
				return baseDelta.Property == Property;
			}
			return false;
		}

		public override int GetHashCode()
		{
			return HashCode.Combine(Property);
		}
	}
	public enum DeltaProperty
	{
		IndicatorPosition = 0,
		PathPosition = 1,
		IndicatorTargetPosition = 2,
		FollowButtonTargetPosition = 3,
		Rotation = 10,
		PathHints = 20,
		PathDeletedSegments = 30,
		PathAddedFixedHints = 35,
		PathFixedHintsCount = 36,
		FixedHints = 50,
		FixedHint_Length = 53,
		FixedHint_ConnectionPoint = 54,
		UsedComponents = 60,
		UsedComponent_Ammount = 61,
		Effects = 70,
		Health = 80,
		OldSerializedPath = 1000,
		IsOldFixedHint = 1010
	}
	public class ListAddDelta : BaseDelta
	{
		public int Index { get; set; }

		public List<ModifyDelta> Deltas { get; set; } = new List<ModifyDelta>();


		public override bool Equals(object obj)
		{
			if (!base.Equals(obj))
			{
				return false;
			}
			if (!(obj is ListAddDelta listAddDelta))
			{
				return false;
			}
			if (Index == listAddDelta.Index)
			{
				return Deltas.SequenceEqual(listAddDelta.Deltas);
			}
			return false;
		}

		public override int GetHashCode()
		{
			int hashCode = base.GetHashCode();
			Deltas.ForEach(delegate(ModifyDelta delta)
			{
				hashCode = HashCode.Combine(hashCode, delta.GetHashCode());
			});
			return hashCode;
		}
	}
	public class ListDelta : BaseDelta
	{
		public List<ListAddDelta> AddDeltas { get; set; } = new List<ListAddDelta>();


		public override bool Equals(object obj)
		{
			if (!base.Equals(obj))
			{
				return false;
			}
			if (!(obj is ListDelta listDelta))
			{
				return false;
			}
			return AddDeltas.SequenceEqual(listDelta.AddDeltas);
		}

		public override int GetHashCode()
		{
			int hashCode = HashCode.Combine(base.GetHashCode(), AddDeltas.Count);
			AddDeltas.ForEach(delegate(ListAddDelta delta)
			{
				hashCode = HashCode.Combine(hashCode, delta.GetHashCode());
			});
			return hashCode;
		}
	}
	public class ListModifyDelta<T> : ModifyDelta<T>
	{
		public int Index { get; set; }
	}
	public abstract class ModifyDelta : BaseDelta
	{
	}
	public class ModifyDelta<T> : ModifyDelta
	{
		public T NewValue { get; set; }

		public override bool Equals(object obj)
		{
			if (!base.Equals(obj))
			{
				return false;
			}
			if (!(obj is ModifyDelta<T> modifyDelta))
			{
				return false;
			}
			if (NewValue == null || modifyDelta.NewValue == null)
			{
				if (NewValue == null)
				{
					return modifyDelta.NewValue == null;
				}
				return false;
			}
			T newValue = modifyDelta.NewValue;
			if (!((object)newValue is string b))
			{
				if (newValue is float)
				{
					object obj2 = newValue;
					float num = (float)((obj2 is float) ? obj2 : null);
					return (double)Mathf.Abs((NewValue as float?).Value - num) < 1E-05;
				}
				if ((object)newValue is List<string> list)
				{
					return (NewValue as List<string>)?.SequenceEqual(list) ?? (list == null);
				}
				return EqualityComparer<T>.Default.Equals(NewValue, modifyDelta.NewValue);
			}
			return string.Equals(NewValue as string, b);
		}

		public override int GetHashCode()
		{
			int hashCode = base.GetHashCode();
			T newValue = NewValue;
			return HashCode.Combine(hashCode, (newValue != null) ? newValue.GetHashCode() : 0);
		}
	}
}
namespace PotionCraftUsefulRecipeMarks.Scripts.Services
{
	public static class DeltaRecordingService
	{
		public const string VoidSaltName = "Void Salt";

		private static RecipeBookRecipeMarkType? LastRecipeMarkType;

		private static string LastRecipeMarkStringValue;

		private static Dictionary<DeltaProperty, BaseDelta> TemporaryCurrentPotionState;

		private static Vector2 indicatorPosition;

		private static Vector2 pathPosition;

		private static Vector2 indicatorTargetPosition;

		private static Vector2 followButtonTargetPosition;

		private static float rotation;

		private static float health;

		private static bool didDeleteFixedHintViaVoidSalt;

		public static void RecordRecipeMarkInfo()
		{
			PotionManager potion = Managers.Potion;
			bool? obj;
			if (potion == null)
			{
				obj = null;
			}
			else
			{
				PotionCraftPanel potionCraftPanel = potion.potionCraftPanel;
				obj = ((potionCraftPanel != null) ? new bool?(!potionCraftPanel.IsPotionBrewingStarted()) : null);
			}
			bool? flag = obj;
			if (!flag.GetValueOrDefault())
			{
				RecordRecipeMarkInfo(Managers.Potion.recipeMarks.GetMarksList().LastOrDefault());
			}
		}

		public static void SetupInitialInfoForRecipe(RecipeBookRightPageContent rightPageContent)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			int currentPageIndex = ((Book)RecipeBook.Instance).currentPageIndex;
			SetupInitialInfoForRecipe(Extensions.GetRecipeData((Potion)rightPageContent.GetRecipeBookPageContent()), currentPageIndex);
		}

		public static void SetupInitialInfoForRecipe(SerializedPotionRecipeData potionFromPanel, int recipeIndex)
		{
			if (!StaticStorage.RecipeMarkInfos.TryGetValue(recipeIndex, out var value))
			{
				RecipeBook.Instance.currentRecipeIndexes[(RecipeBookPageContentType)1] = recipeIndex;
				SetupInitialInfo();
				StaticStorage.CurrentPotionRecipeMarkInfos[0].Deltas.Add(new ModifyDelta<SerializedPath>
				{
					Property = DeltaProperty.OldSerializedPath,
					NewValue = potionFromPanel.serializedPath
				});
				List<ListAddDelta> addDeltas = ((ListDelta)StaticStorage.CurrentPotionState[DeltaProperty.FixedHints]).AddDeltas;
				List<ListAddDelta> addDeltas2 = ((ListDelta)StaticStorage.CurrentPotionRecipeMarkInfos[0].Deltas.First((BaseDelta d) => d.Property == DeltaProperty.FixedHints)).AddDeltas;
				addDeltas.Concat(addDeltas2).ToList().ForEach(delegate(ListAddDelta fixedHintDelta)
				{
					fixedHintDelta.Deltas.Add(new ModifyDelta<bool>
					{
						Property = DeltaProperty.IsOldFixedHint,
						NewValue = true
					});
				});
			}
			else
			{
				int selectedRecipeMarkIndex = StaticStorage.SelectedRecipeMarkIndex;
				StaticStorage.CurrentPotionRecipeMarkInfos = ((value.Count > selectedRecipeMarkIndex) ? value.Take(selectedRecipeMarkIndex + 1).ToDictionary((KeyValuePair<int, RecipeMarkInfo> kvp) => kvp.Key, (KeyValuePair<int, RecipeMarkInfo> kvp) => kvp.Value) : value);
				List<SerializedRecipeMark> marksList = Managers.Potion.recipeMarks.GetMarksList();
				while (marksList.Count > selectedRecipeMarkIndex + 1)
				{
					marksList.RemoveAt(marksList.Count - 1);
				}
				if (StaticStorage.SelectedRecipePotionState != null)
				{
					StaticStorage.CurrentPotionState = StaticStorage.SelectedRecipePotionState;
				}
			}
		}

		public static void CommitRecipeMarkInfoForSavedRecipe()
		{
			int num = RecipeBook.Instance.savedRecipes.IndexOf(null);
			if (num != -1)
			{
				if (Managers.Potion.potionCraftPanel.previousPotionRecipe != null)
				{
					StaticStorage.RecipeMarkInfos[num] = StaticStorage.PreviousPotionRecipeMarkInfo;
					StaticStorage.PreviousPotionRecipeMarkInfo = null;
				}
				else
				{
					RecordRecipeMarkInfo(null);
					StaticStorage.RecipeMarkInfos[num] = StaticStorage.CurrentPotionRecipeMarkInfos;
				}
			}
		}

		public static void ResetPotion()
		{
			Plugin.PluginLogger.LogMessage((object)$"ResetPotion - {StaticStorage.ShouldLoadLastBrewState} - {StaticStorage.CurrentPotionRecipeMarkInfos != null} - {StaticStorage.CurrentPotionState != null}");
			if (StaticStorage.ShouldLoadLastBrewState)
			{
				StaticStorage.ShouldLoadLastBrewState = false;
				if (StaticStorage.CurrentPotionRecipeMarkInfos != null && StaticStorage.CurrentPotionState != null)
				{
					return;
				}
			}
			Plugin.PluginLogger.LogMessage((object)"ResetPotion - 1");
			if (Managers.Potion.potionCraftPanel.potionChangedAfterSavingRecipe)
			{
				RecordRecipeMarkInfo(null);
				StaticStorage.PreviousPotionRecipeMarkInfo = StaticStorage.CurrentPotionRecipeMarkInfos;
			}
			SetupInitialInfo();
		}

		public static void ClearPreviousSavedPotionRecipeMarkInfo(bool potionUpdated)
		{
			Ex.RunSafe(delegate
			{
				if (potionUpdated)
				{
					StaticStorage.PreviousPotionRecipeMarkInfo = null;
				}
			});
		}

		public static void SetupInitialInfo()
		{
			Plugin.PluginLogger.LogMessage((object)"SetupInitialInfo");
			StaticStorage.CurrentPotionState = new Dictionary<DeltaProperty, BaseDelta>();
			RecordPositionInfo();
			SetupCurrentPotionState(useTemporaryStateDict: false);
			StaticStorage.CurrentPotionRecipeMarkInfos = new Dictionary<int, RecipeMarkInfo> { [0] = new RecipeMarkInfo
			{
				Index = 0,
				Deltas = StaticStorage.CurrentPotionState.Values.ToList()
			} };
			StaticStorage.CurrentRecipeMarkInfo = null;
		}

		public static void RecordRecipeMarkInfo(SerializedRecipeMark recipeMark)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Expected I4, but got Unknown
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and I4
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Invalid comparison between Unknown and I4
			if (recipeMark != null && (int)recipeMark.type == 0)
			{
				return;
			}
			if (StaticStorage.CurrentRecipeMarkInfo != null && (LastRecipeMarkType != recipeMark?.type || (recipeMark != null && (int)recipeMark.type == 1) || (recipeMark != null && (int)recipeMark.type == 5 && recipeMark?.stringValue != LastRecipeMarkStringValue)))
			{
				CommitPositionInfo();
				if (didDeleteFixedHintViaVoidSalt)
				{
					didDeleteFixedHintViaVoidSalt = false;
					StaticStorage.CurrentRecipeMarkInfo.Deltas.Add(GetBaseProperty(DeltaProperty.PathAddedFixedHints));
				}
				StaticStorage.CurrentPotionRecipeMarkInfos[StaticStorage.CurrentRecipeMarkInfo.Index] = StaticStorage.CurrentRecipeMarkInfo;
				if (TemporaryCurrentPotionState != null)
				{
					StaticStorage.CurrentPotionState = TemporaryCurrentPotionState;
				}
			}
			if (recipeMark == null)
			{
				return;
			}
			LastRecipeMarkType = recipeMark.type;
			LastRecipeMarkStringValue = recipeMark.stringValue;
			int index = Managers.Potion.recipeMarks.GetMarksList().IndexOf(recipeMark);
			StaticStorage.CurrentRecipeMarkInfo = new RecipeMarkInfo
			{
				Index = index
			};
			RecipeBookRecipeMarkType type = recipeMark.type;
			switch (type - 1)
			{
			case 1:
				RecordPositionInfo();
				RecordMoveAlongPathInfo();
				break;
			case 2:
				RecordPositionInfo();
				break;
			case 3:
				RecordEffectInfo();
				break;
			case 4:
				RecordPositionInfo();
				RecordUsedComponentInfo(recipeMark.stringValue);
				if (recipeMark.stringValue == "Void Salt")
				{
					HandleDeletedFixedHintFromVoidSalt();
					RecordEndPathHintInfo();
				}
				else
				{
					RecordConnectionPointInfo();
				}
				break;
			case 0:
				RecordNewIngredientInfo(recipeMark.stringValue);
				break;
			}
			SetupCurrentPotionState(useTemporaryStateDict: true);
		}

		private static void SetupCurrentPotionState(bool useTemporaryStateDict)
		{
			StaticStorage.CurrentPotionState.TryGetValue(DeltaProperty.PathAddedFixedHints, out var value);
			if (useTemporaryStateDict)
			{
				TemporaryCurrentPotionState = new Dictionary<DeltaProperty, BaseDelta>();
			}
			else
			{
				StaticStorage.CurrentPotionState = new Dictionary<DeltaProperty, BaseDelta>();
			}
			Dictionary<DeltaProperty, BaseDelta> currentPotionState = (useTemporaryStateDict ? TemporaryCurrentPotionState : StaticStorage.CurrentPotionState);
			if (value != null)
			{
				currentPotionState[DeltaProperty.PathAddedFixedHints] = value;
			}
			else
			{
				currentPotionState[DeltaProperty.PathAddedFixedHints] = GetBaseProperty(DeltaProperty.PathAddedFixedHints);
			}
			currentPotionState[DeltaProperty.UsedComponents] = GetUsedComponentsProperty();
			currentPotionState[DeltaProperty.FixedHints] = GetFixedHintsProperty();
			List<DeltaProperty> list = new List<DeltaProperty>();
			list.Add(DeltaProperty.IndicatorPosition);
			list.Add(DeltaProperty.PathPosition);
			list.Add(DeltaProperty.IndicatorTargetPosition);
			list.Add(DeltaProperty.FollowButtonTargetPosition);
			list.Add(DeltaProperty.Rotation);
			list.Add(DeltaProperty.Health);
			list.Add(DeltaProperty.Effects);
			list.Add(DeltaProperty.PathDeletedSegments);
			list.Add(DeltaProperty.PathFixedHintsCount);
			list.ForEach(delegate(DeltaProperty p)
			{
				currentPotionState[p] = GetBaseProperty(p);
			});
		}

		private static void RecordPositionInfo()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			indicatorPosition = ((ModifyDelta<(float, float)>)GetBaseProperty(DeltaProperty.IndicatorPosition)).NewValue.ToVector();
			pathPosition = ((ModifyDelta<(float, float)>)GetBaseProperty(DeltaProperty.PathPosition)).NewValue.ToVector();
			indicatorTargetPosition = ((ModifyDelta<(float, float)>)GetBaseProperty(DeltaProperty.IndicatorTargetPosition)).NewValue.ToVector();
			followButtonTargetPosition = ((ModifyDelta<(float, float)>)GetBaseProperty(DeltaProperty.FollowButtonTargetPosition)).NewValue.ToVector();
			rotation = ((ModifyDelta<float>)GetBaseProperty(DeltaProperty.Rotation)).NewValue;
			health = ((ModifyDelta<float>)GetBaseProperty(DeltaProperty.Health)).NewValue;
		}

		private static void CommitPositionInfo()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			CommitProperty(DeltaProperty.IndicatorPosition, indicatorPosition.ToTuple());
			CommitProperty(DeltaProperty.PathPosition, pathPosition.ToTuple());
			CommitProperty(DeltaProperty.IndicatorTargetPosition, indicatorTargetPosition.ToTuple());
			CommitProperty(DeltaProperty.FollowButtonTargetPosition, followButtonTargetPosition.ToTuple());
			CommitProperty(DeltaProperty.Rotation, rotation);
			CommitProperty(DeltaProperty.Health, health);
		}

		private static void CommitProperty<T>(DeltaProperty property, T value)
		{
			ModifyDelta<T> modifyDelta = new ModifyDelta<T>
			{
				Property = property,
				NewValue = value
			};
			if (StaticStorage.CurrentPotionState[property] != modifyDelta)
			{
				StaticStorage.CurrentRecipeMarkInfo.Deltas.Add(modifyDelta);
			}
		}

		private static void RecordMoveAlongPathInfo()
		{
			RecordProperty(DeltaProperty.PathDeletedSegments);
			ListDelta listDelta = (ListDelta)StaticStorage.CurrentPotionState[DeltaProperty.FixedHints];
			int fixedPathHintsCount = GetFixedPathHintsCount();
			if (fixedPathHintsCount < listDelta.AddDeltas.Count)
			{
				StaticStorage.CurrentRecipeMarkInfo.Deltas.Add(GetBaseProperty(DeltaProperty.PathFixedHintsCount));
			}
			int num = listDelta.AddDeltas.Count - fixedPathHintsCount;
			FixedHint val = ((IEnumerable<FixedHint>)Managers.RecipeMap.path.fixedPathHints).FirstOrDefault((Func<FixedHint, bool>)((FixedHint fph) => fph.GetPathLength() > 0.001f));
			if (!((Object)(object)val == (Object)null))
			{
				int index = Managers.RecipeMap.path.fixedPathHints.IndexOf(val);
				RecordListObjectInfo<FixedHint>(DeltaProperty.FixedHints, val, index, num);
				RecordConnectionPointInfo(num);
			}
		}

		private static void RecordConnectionPointInfo(int indexOffset = 0)
		{
			for (int i = 1; i < Managers.RecipeMap.path.fixedPathHints.Count; i++)
			{
				FixedHint sourceAdded = Managers.RecipeMap.path.fixedPathHints[i];
				RecordListObjectInfo<FixedHint>(DeltaProperty.FixedHints, sourceAdded, i, i + indexOffset, new List<DeltaProperty> { DeltaProperty.FixedHint_ConnectionPoint });
			}
		}

		private static void RecordEffectInfo()
		{
			RecordProperty(DeltaProperty.Effects);
		}

		private static void RecordNewIngredientInfo(string ingredientName)
		{
			((ModifyDelta<int>)StaticStorage.CurrentPotionState[DeltaProperty.PathAddedFixedHints]).NewValue++;
			RecordNewListAddInfo(DeltaProperty.FixedHints, Managers.RecipeMap.path.fixedPathHints);
			StaticStorage.CurrentRecipeMarkInfo.Deltas.Add(GetBaseProperty(DeltaProperty.PathAddedFixedHints));
			StaticStorage.CurrentRecipeMarkInfo.Deltas.Add(GetBaseProperty(DeltaProperty.PathFixedHintsCount));
			RecordUsedComponentInfo(ingredientName);
		}

		private static void RecordEndPathHintInfo()
		{
			RecordNewListAddInfo(DeltaProperty.FixedHints, Managers.RecipeMap.path.fixedPathHints, Managers.RecipeMap.path.fixedPathHints.Count - 1);
		}

		private static void HandleDeletedFixedHintFromVoidSalt()
		{
			ListDelta listDelta = (ListDelta)StaticStorage.CurrentPotionState[DeltaProperty.FixedHints];
			int fixedPathHintsCount = GetFixedPathHintsCount();
			if (fixedPathHintsCount == listDelta.AddDeltas.Count - 1)
			{
				didDeleteFixedHintViaVoidSalt = true;
				listDelta.AddDeltas = listDelta.AddDeltas.Take(fixedPathHintsCount).ToList();
				((ModifyDelta<int>)StaticStorage.CurrentPotionState[DeltaProperty.PathAddedFixedHints]).NewValue--;
			}
		}

		private static void RecordUsedComponentInfo(string usedComponentName)
		{
			List<AlchemySubstanceComponent> summaryComponents = Managers.Potion.PotionUsedComponents.GetSummaryComponents();
			AlchemySubstanceComponent val = ((IEnumerable<AlchemySubstanceComponent>)summaryComponents).FirstOrDefault((Func<AlchemySubstanceComponent, bool>)((AlchemySubstanceComponent c) => ((Object)c.Component).name == usedComponentName));
			if (val == null)
			{
				throw new ArgumentException("Cannot record new used component info for " + usedComponentName + ". Used component not found in usedComponents list");
			}
			RecordListObjectInfo<AlchemySubstanceComponent>(DeltaProperty.UsedComponents, val, summaryComponents.IndexOf(val));
		}

		private static void RecordNewListAddInfo<T>(DeltaProperty property, List<T> sourceList, int indexOverride = -1)
		{
			T val = sourceList.LastOrDefault();
			if (val == null)
			{
				throw new InvalidOperationException($"RecordNewListAddInfo should only be called when a new item is added. No {property} found!");
			}
			RecordListObjectInfo(property, val, (indexOverride == -1) ? (sourceList.Count - 1) : indexOverride);
		}

		private static void RecordListObjectInfo<T>(DeltaProperty property, T sourceAdded, int index, int addDeltaIndex = -1, List<DeltaProperty> propertiesToRecord = null)
		{
			ListDelta listDelta = StaticStorage.CurrentPotionState[property] as ListDelta;
			ListAddDelta baseAddDelta = GetBaseAddDelta(sourceAdded, index, propertiesToRecord);
			if (addDeltaIndex == -1)
			{
				addDeltaIndex = index;
			}
			ListAddDelta lastAddedDelta = ((listDelta.AddDeltas.Count > addDeltaIndex) ? listDelta.AddDeltas[addDeltaIndex] : null);
			if (lastAddedDelta != null && lastAddedDelta == baseAddDelta)
			{
				return;
			}
			if (lastAddedDelta == null)
			{
				StaticStorage.CurrentRecipeMarkInfo.Deltas.Add(baseAddDelta);
				return;
			}
			IEnumerable<ModifyDelta> source = baseAddDelta.Deltas.Where(delegate(ModifyDelta newProperty)
			{
				ModifyDelta modifyDelta = lastAddedDelta.Deltas.FirstOrDefault((ModifyDelta d) => d.Property == newProperty.Property);
				return modifyDelta == null || newProperty != modifyDelta;
			});
			ListAddDelta item = new ListAddDelta
			{
				Property = baseAddDelta.Property,
				Index = baseAddDelta.Index,
				Deltas = source.ToList()
			};
			StaticStorage.CurrentRecipeMarkInfo.Deltas.Add(item);
		}

		private static void RecordProperty(DeltaProperty property)
		{
			ModifyDelta baseProperty = GetBaseProperty(property);
			if (StaticStorage.CurrentPotionState[property] != baseProperty)
			{
				StaticStorage.CurrentRecipeMarkInfo.Deltas.Add(baseProperty);
			}
		}

		private static ListDelta GetUsedComponentsProperty()
		{
			return new ListDelta
			{
				Property = DeltaProperty.UsedComponents,
				AddDeltas = (from d in Managers.Potion.PotionUsedComponents.GetSummaryComponents().Select((AlchemySubstanceComponent u, int i) => GetBaseAddDelta(u, i))
					where d != null
					select d).ToList()
			};
		}

		private static ListDelta GetFixedHintsProperty()
		{
			return new ListDelta
			{
				Property = DeltaProperty.FixedHints,
				AddDeltas = (from d in Managers.RecipeMap.path.fixedPathHints.Select((FixedHint h, int i) => GetBaseAddDelta(h, i))
					where d != null
					select d).ToList()
			};
		}

		private static ListAddDelta GetBaseAddDelta(object obj, int index, List<DeltaProperty> propertiesToRecord = null)
		{
			if (obj == null)
			{
				return null;
			}
			DeltaProperty deltaProperty;
			if (!(obj is AlchemySubstanceComponent))
			{
				if (!(obj is FixedHint))
				{
					throw new ArgumentException($"Object of type: {obj.GetType()} is not a valid list add object!");
				}
				deltaProperty = DeltaProperty.FixedHints;
			}
			else
			{
				deltaProperty = DeltaProperty.UsedComponents;
			}
			DeltaProperty deltaProperty2 = deltaProperty;
			if (deltaProperty2 == DeltaProperty.FixedHints)
			{
				int num = ((ModifyDelta<int>)StaticStorage.CurrentPotionState[DeltaProperty.PathAddedFixedHints]).NewValue - Managers.RecipeMap.path.fixedPathHints.Count;
				index += num;
			}
			return new ListAddDelta
			{
				Index = index,
				Property = deltaProperty2,
				Deltas = ((propertiesToRecord == null) ? GetAllBaseProperties(obj) : propertiesToRecord.Select((DeltaProperty p) => GetListObjectProperty(p, obj)).ToList())
			};
		}

		private static List<ModifyDelta> GetAllBaseProperties(object obj)
		{
			if (obj == null)
			{
				return new List<ModifyDelta>();
			}
			List<DeltaProperty> source;
			if (!(obj is AlchemySubstanceComponent))
			{
				if (!(obj is FixedHint))
				{
					throw new ArgumentException($"Object of type: {obj.GetType()} is not a valid list add object!");
				}
				source = new List<DeltaProperty>
				{
					DeltaProperty.FixedHint_Length,
					DeltaProperty.FixedHint_ConnectionPoint
				};
			}
			else
			{
				source = new List<DeltaProperty> { DeltaProperty.UsedComponent_Ammount };
			}
			return source.Select((DeltaProperty p) => GetListObjectProperty(p, obj)).ToList();
		}

		private static ModifyDelta GetListObjectProperty(DeltaProperty property, object obj)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			return property switch
			{
				DeltaProperty.UsedComponent_Ammount => new ModifyDelta<int>
				{
					Property = DeltaProperty.UsedComponent_Ammount,
					NewValue = ((AlchemySubstanceComponent)obj).Amount
				}, 
				DeltaProperty.FixedHint_ConnectionPoint => new ModifyDelta<(float, float)>
				{
					Property = DeltaProperty.FixedHint_ConnectionPoint,
					NewValue = GetConnectionPointForFixedHint((FixedHint)obj).ToTuple()
				}, 
				DeltaProperty.FixedHint_Length => new ModifyDelta<float>
				{
					Property = DeltaProperty.FixedHint_Length,
					NewValue = GetFixedHintPathLength((FixedHint)obj)
				}, 
				_ => throw new ArgumentException($"Property: {property} is not a list object property!"), 
			};
		}

		private static Vector2 GetConnectionPointForFixedHint(FixedHint obj)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			int num = Managers.RecipeMap.path.fixedPathHints.IndexOf(obj);
			switch (num)
			{
			case -1:
				return Vector2.zero;
			case 0:
			{
				ModifyDelta<(float, float)> modifyDelta = GetFixedHintDeltaForFixedHint(obj)?.Deltas?.FirstOrDefault((ModifyDelta d) => d.Property == DeltaProperty.FixedHint_ConnectionPoint) as ModifyDelta<(float, float)>;
				if (modifyDelta != null)
				{
					return modifyDelta.NewValue.ToVector();
				}
				return Vector2.op_Implicit(Managers.RecipeMap.path.fixedPathHints.First().evenlySpacedPointsFixedGraphics.points.First());
			}
			default:
			{
				Vector3[] points = Managers.RecipeMap.path.fixedPathHints[num - 1].evenlySpacedPointsFixedGraphics.points;
				if (!points.Any())
				{
					return Vector2.op_Implicit(Managers.RecipeMap.path.fixedPathHints.First().evenlySpacedPointsFixedGraphics.points.First());
				}
				return Vector2.op_Implicit(points.Last());
			}
			}
		}

		private static float GetPreviouslyRecordedLengthForFixedHint(FixedHint obj)
		{
			if (StaticStorage.CurrentPotionState.ContainsKey(DeltaProperty.PathAddedFixedHints) && StaticStorage.CurrentPotionState.ContainsKey(DeltaProperty.FixedHints))
			{
				ModifyDelta<float> modifyDelta = GetFixedHintDeltaForFixedHint(obj)?.Deltas?.FirstOrDefault((ModifyDelta d) => d.Property == DeltaProperty.FixedHint_Length) as ModifyDelta<float>;
				if (modifyDelta != null)
				{
					return modifyDelta.NewValue;
				}
			}
			return GetFixedHintPathLength(obj);
		}

		private static ListAddDelta GetFixedHintDeltaForFixedHint(FixedHint obj)
		{
			if (!StaticStorage.CurrentPotionState.ContainsKey(DeltaProperty.PathAddedFixedHints) || !StaticStorage.CurrentPotionState.ContainsKey(DeltaProperty.FixedHints))
			{
				return null;
			}
			int index = Managers.RecipeMap.path.fixedPathHints.IndexOf(obj);
			int num = ((ModifyDelta<int>)StaticStorage.CurrentPotionState[DeltaProperty.PathAddedFixedHints]).NewValue - GetFixedPathHintsCount();
			index += num;
			return ((ListDelta)StaticStorage.CurrentPotionState[DeltaProperty.FixedHints]).AddDeltas.FirstOrDefault((ListAddDelta d) => d.Index == index);
		}

		private static float GetFixedHintPathLength(FixedHint hint)
		{
			PathMapItem path = Managers.RecipeMap.path;
			return hint.GetPathLength() - path.segmentLengthToDeleteFromEndGraphics;
		}

		private static ModifyDelta GetBaseProperty(DeltaProperty property)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			BaseDelta value;
			return property switch
			{
				DeltaProperty.IndicatorPosition => new ModifyDelta<(float, float)>
				{
					Property = DeltaProperty.IndicatorPosition,
					NewValue = ((RecipeMapItem)Managers.RecipeMap.indicator).thisTransform.localPosition.ToTuple()
				}, 
				DeltaProperty.PathPosition => new ModifyDelta<(float, float)>
				{
					Property = DeltaProperty.PathPosition,
					NewValue = ((Component)Managers.RecipeMap.path).transform.localPosition.ToTuple()
				}, 
				DeltaProperty.IndicatorTargetPosition => new ModifyDelta<(float, float)>
				{
					Property = DeltaProperty.IndicatorTargetPosition,
					NewValue = Extensions.ToTuple((Vector2)Traverse.Create((object)Managers.RecipeMap.indicator).Field("targetPosition").GetValue())
				}, 
				DeltaProperty.FollowButtonTargetPosition => new ModifyDelta<(float, float)>
				{
					Property = DeltaProperty.FollowButtonTargetPosition,
					NewValue = Managers.RecipeMap.recipeMapObject.followButtonTargetObject.localPosition.ToTuple()
				}, 
				DeltaProperty.Rotation => new ModifyDelta<float>
				{
					Property = DeltaProperty.Rotation,
					NewValue = Managers.RecipeMap.indicatorRotation.Value
				}, 
				DeltaProperty.Health => new ModifyDelta<float>
				{
					Property = DeltaProperty.Health,
					NewValue = (float)Traverse.Create((object)Managers.RecipeMap.indicator).Field("visualHealth").GetValue()
				}, 
				DeltaProperty.Effects => new ModifyDelta<List<string>>
				{
					Property = DeltaProperty.Effects,
					NewValue = (from e in Managers.Potion.collectedPotionEffects
						where (ComparableScriptableObject<PotionEffect>)(object)e != (ComparableScriptableObject<PotionEffect>)null
						select ((Object)e).name).ToList()
				}, 
				DeltaProperty.PathDeletedSegments => new ModifyDelta<float>
				{
					Property = DeltaProperty.PathDeletedSegments,
					NewValue = Managers.RecipeMap.path.deletedGraphicsSegments
				}, 
				DeltaProperty.PathAddedFixedHints => new ModifyDelta<int>
				{
					Property = DeltaProperty.PathAddedFixedHints,
					NewValue = (StaticStorage.CurrentPotionState.TryGetValue(DeltaProperty.PathAddedFixedHints, out value) ? ((ModifyDelta<int>)value).NewValue : GetFixedPathHintsCount())
				}, 
				DeltaProperty.PathFixedHintsCount => new ModifyDelta<int>
				{
					Property = DeltaProperty.PathFixedHintsCount,
					NewValue = GetFixedPathHintsCount()
				}, 
				_ => throw new ArgumentException($"Property: {property} is not a base property!"), 
			};
		}

		private static int GetFixedPathHintsCount()
		{
			return Managers.RecipeMap.path.fixedPathHints.Where((FixedHint fph) => fph.GetPathLength() > 0.001f).Count();
		}

		public static void DeleteMarkInfoForRecipe(Potion recipe)
		{
			int key = RecipeBook.Instance.savedRecipes.IndexOf((IRecipeBookPageContent)(object)recipe);
			if (StaticStorage.RecipeMarkInfos.ContainsKey(key))
			{
				StaticStorage.RecipeMarkInfos.Remove(key);
			}
		}

		private static void DebugPrintDeltas(Dictionary<int, RecipeMarkInfo> recipeMarkInfo)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			Plugin.PluginLogger.LogMessage((object)JsonConvert.SerializeObject((object)recipeMarkInfo, new JsonSerializerSettings
			{
				ReferenceLoopHandling = (ReferenceLoopHandling)1
			}));
		}

		private static void DebugPrintDeltas()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			Plugin.PluginLogger.LogMessage((object)JsonConvert.SerializeObject((object)StaticStorage.CurrentRecipeMarkInfo, new JsonSerializerSettings
			{
				ReferenceLoopHandling = (ReferenceLoopHandling)1
			}));
		}
	}
	public class RecipeBookUIService
	{
		private static Color? MarkDefaultColor;

		private static Color? TextDefaultColor;

		public static void UpdateRecipeBookPageForSelectedRecipeMark(Button __instance)
		{
			RecipeBookRecipeMark val = (RecipeBookRecipeMark)(object)((__instance is RecipeBookRecipeMark) ? __instance : null);
			if (val == null)
			{
				return;
			}
			int currentPageIndex = ((Book)RecipeBook.Instance).currentPageIndex;
			int currentMarkIndex = val.currentMarkIndex;
			if (IsAlchemyMachineRecipe(RecipeBook.Instance.savedRecipes[currentPageIndex]) || currentMarkIndex == 0)
			{
				return;
			}
			int markIndexOverride = -1;
			if (!RecipeReconstructionService.MarkHasSavedData(currentPageIndex, currentMarkIndex))
			{
				if (!RecipeReconstructionService.MarkHasSavedData(currentPageIndex, currentMarkIndex + 1))
				{
					Notification.ShowText("This recipe mark is missing critical information", "You can only continue brewing from new recipe marks", (TextType)0);
					return;
				}
				markIndexOverride = 0;
			}
			UpdateRecipeBookPageForSelectedRecipeMark(currentPageIndex, currentMarkIndex, markIndexOverride);
		}

		public static void UpdateRecipeBookPageForSelectedRecipeMark(int recipeIndex, int markIndex, int markIndexOverride = -1)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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
			Potion potionForRecipeMark = RecipeReconstructionService.GetPotionForRecipeMark(recipeIndex, (markIndexOverride == -1) ? markIndex : markIndexOverride);
			if (!((Object)(object)potionForRecipeMark == (Object)null))
			{
				StaticStorage.SelectedRecipeMarkIndex = markIndex;
				StaticStorage.SelectedRecipeIndex = recipeIndex;
				Page frontLeftPage = ((Book)RecipeBook.Instance).curlPageController.frontLeftPage;
				Page frontRightPage = ((Book)RecipeBook.Instance).curlPageController.frontRightPage;
				frontLeftPage.UpdatePageContent((PageContentState)1, (IBookPageContent)(object)potionForRecipeMark, frontRightPage);
				frontRightPage.UpdatePageContent((PageContentState)1, (IBookPageContent)(object)potionForRecipeMark, frontLeftPage);
				bool num = potionForRecipeMark.GetRecipeData().recipeMarks.Count - 1 != markIndex;
				RecipeBookRightPageContent val = (RecipeBookRightPageContent)frontRightPage.pageContent;
				RecipeBookBrewRecipeButton val2 = (RecipeBookBrewRecipeButton)Traverse.Create((object)Traverse.Create((object)val).Field<RecipeBookRightPageBottomButtonsController>("bottomButtonsController").Value).Field("brewRecipeSoloButton").GetValue();
				val2.UpdateVisual();
				if (num)
				{
					DisableRecipeWaypointsUIElements(val);
				}
				if (num)
				{
					((Button)val2).Locked = true;
				}
			}
		}

		public static void EnableDisableMark(RecipeBookRecipeMark mark)
		{
			int currentPageIndex = ((Book)RecipeBook.Instance).currentPageIndex;
			if (StaticStorage.SelectedRecipeMarkIndex > 0 && StaticStorage.SelectedRecipeIndex == currentPageIndex && StaticStorage.RecipeMarkInfos.ContainsKey(currentPageIndex))
			{
				EnableDisableMark(mark, mark.currentMarkIndex <= StaticStorage.SelectedRecipeMarkIndex);
				return;
			}
			bool num = StaticStorage.RecipeMarkInfos.ContainsKey(currentPageIndex);
			int currentMarkIndex = mark.currentMarkIndex;
			bool enabled = !num || (currentMarkIndex != 0 && (RecipeReconstructionService.MarkHasSavedData(currentPageIndex, currentMarkIndex) || RecipeReconstructionService.MarkHasSavedData(currentPageIndex, currentMarkIndex + 1)));
			EnableDisableMark(mark, enabled);
		}

		private static void EnableDisableMark(RecipeBookRecipeMark mark, bool enabled)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			((Component)mark).GetComponentsInChildren<SpriteRenderer>().ToList().ForEach(delegate(SpriteRenderer r)
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				if (!MarkDefaultColor.HasValue)
				{
					MarkDefaultColor = r.color;
				}
				Color value2 = MarkDefaultColor.Value;
				r.color = (enabled ? value2 : GetDisabledColor(value2));
			});
			TextMeshPro componentInChildren = ((Component)mark).GetComponentInChildren<TextMeshPro>();
			if (!((Object)(object)componentInChildren == (Object)null))
			{
				if (!TextDefaultColor.HasValue)
				{
					TextDefaultColor = ((Graphic)componentInChildren).color;
				}
				Color value = TextDefaultColor.Value;
				((Graphic)componentInChildren).color = (enabled ? value : GetDisabledColor(value));
			}
		}

		private static Color GetDisabledColor(Color baseColor)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			return new Color(baseColor.r, baseColor.g, baseColor.b, 0.5f);
		}

		public static void UpdateRecipeMarksForStateChanged(bool shown)
		{
			Ex.RunSafe(delegate
			{
				if (shown)
				{
					int currentPageIndex = ((Book)RecipeBook.Instance).currentPageIndex;
					if (StaticStorage.SelectedRecipeMarkIndex > 0 && StaticStorage.SelectedRecipeIndex == currentPageIndex && StaticStorage.RecipeMarkInfos.ContainsKey(currentPageIndex))
					{
						UpdateRecipeBookPageForSelectedRecipeMark(currentPageIndex, StaticStorage.SelectedRecipeMarkIndex);
					}
					else
					{
						DisableOldRecipeMarks((Book)(object)RecipeBook.Instance);
					}
				}
			});
		}

		public static void UpdateRecipeMarksForPageChange(int _, int _0)
		{
			Ex.RunSafe(delegate
			{
				DisableOldRecipeMarks((Book)(object)RecipeBook.Instance);
			});
		}

		public static void DisableOldRecipeMarks(Book book)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			RecipeBook val = (RecipeBook)(object)((book is RecipeBook) ? book : null);
			if (val != null)
			{
				RecipeBookUIService.DisableOldRecipeMarks((RecipeBookRightPageContent)((Book)val).curlPageController.frontRightPage.pageContent);
			}
		}

		public static void DisableOldRecipeMarks(RecipeBookRightPageContent rightPageContent)
		{
			IRecipeBookPageContent obj = ((rightPageContent != null) ? rightPageContent.GetRecipeBookPageContent() : null);
			SerializedPotionRecipeData val = ((Potion)(object)((obj is Potion) ? obj : null))?.GetRecipeData();
			if (!((Object)(object)RecipeBook.Instance == (Object)null) && val != null)
			{
				int currentPageIndex = ((Book)RecipeBook.Instance).currentPageIndex;
				StaticStorage.SelectedRecipeMarkIndex = val.recipeMarks.Count - 1;
				StaticStorage.SelectedRecipeIndex = currentPageIndex;
				RecipeBookRightPageRecipePanelController value = Traverse.Create((object)rightPageContent).Field<RecipeBookRightPageRecipePanelController>("recipePanelController").Value;
				Traverse.Create((object)value).Method("ClearRecipe", Array.Empty<object>()).GetValue();
				Traverse.Create((object)value).Method("UpdatePotionRecipe", Array.Empty<object>()).GetValue();
			}
		}

		private static void DisableRecipeWaypointsUIElements(RecipeBookRightPageContent rightPageContent)
		{
			Transform obj = ((Component)rightPageContent).transform.Find("WaypointToggleButton");
			if (obj != null)
			{
				GameObject gameObject = ((Component)obj).gameObject;
				if (gameObject != null)
				{
					gameObject.SetActive(false);
				}
			}
		}

		public static bool IsAlchemyMachineRecipe(IRecipeBookPageContent recipe)
		{
			return !(recipe is Potion);
		}

		public static void BookmarksRearranged(BookmarkController _, List<int> intList)
		{
			Ex.RunSafe(delegate
			{
				List<KeyValuePair<int, Dictionary<int, RecipeMarkInfo>>> source = StaticStorage.RecipeMarkInfos.ToList();
				List<KeyValuePair<int, Dictionary<int, RecipeMarkInfo>>> list = new List<KeyValuePair<int, Dictionary<int, RecipeMarkInfo>>>();
				List<IRecipeBookPageContent> list2 = new List<IRecipeBookPageContent>();
				for (int i = 0; i < intList.Count; i++)
				{
					int oldIndex = intList[i];
					KeyValuePair<int, Dictionary<int, RecipeMarkInfo>> keyValuePair = source.FirstOrDefault((KeyValuePair<int, Dictionary<int, RecipeMarkInfo>> rmi) => rmi.Key == oldIndex);
					if (!keyValuePair.Equals(default(KeyValuePair<int, Dictionary<int, RecipeMarkInfo>>)))
					{
						list.Add(new KeyValuePair<int, Dictionary<int, RecipeMarkInfo>>(i, keyValuePair.Value));
					}
					if (StaticStorage.BookmarkOrganizerOldVersionInstalled)
					{
						list2.Add(StaticStorage.RecipeIndexes[oldIndex]);
					}
				}
				StaticStorage.RecipeMarkInfos = list.ToDictionary((KeyValuePair<int, Dictionary<int, RecipeMarkInfo>> kvp) => kvp.Key, (KeyValuePair<int, Dictionary<int, RecipeMarkInfo>> kvp) => kvp.Value);
				StaticStorage.RecipeIndexes = list2;
			});
		}

		public static void RemoveRecipeMarkForDeletedRecipe(IRecipeBookPageContent recipe)
		{
			if (recipe is Potion)
			{
				int key = RecipeBook.Instance.savedRecipes.IndexOf(recipe);
				if (StaticStorage.RecipeMarkInfos.ContainsKey(key))
				{
					StaticStorage.RecipeMarkInfos.Remove(key);
				}
			}
		}

		public static void DoOldBookmarkOrganizerFailsfe()
		{
			if (!StaticStorage.BookmarkOrganizerOldVersionInstalled)
			{
				return;
			}
			List<IRecipeBookPageContent> savedRecipes = RecipeBook.Instance.savedRecipes;
			List<int> list = new List<int>();
			bool flag = false;
			for (int i = 0; i < savedRecipes.Count; i++)
			{
				if (StaticStorage.RecipeIndexes[i] == savedRecipes[i])
				{
					list.Add(i);
					continue;
				}
				flag = true;
				list.Add(StaticStorage.RecipeIndexes.IndexOf(savedRecipes[i]));
			}
			if (flag)
			{
				BookmarksRearranged(null, list);
			}
		}
	}
	public static class RecipeReconstructionService
	{
		public static bool MarkHasSavedData(int recipeIndex, int recipeMarkIndex)
		{
			if (!StaticStorage.RecipeMarkInfos.TryGetValue(recipeIndex, out var value))
			{
				return false;
			}
			return value.ContainsKey(recipeMarkIndex);
		}

		public static Potion GetPotionForRecipeMark(int recipeIndex, int recipeMarkIndex)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Expected O, but got Unknown
			//IL_04b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d2: Expected O, but got Unknown
			//IL_04d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0528: Unknown result type (might be due to invalid IL or missing references)
			//IL_052d: Unknown result type (might be due to invalid IL or missing references)
			//IL_097f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0981: Unknown result type (might be due to invalid IL or missing references)
			//IL_0983: Unknown result type (might be due to invalid IL or missing references)
			//IL_0988: Unknown result type (might be due to invalid IL or missing references)
			//IL_09fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_09fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0731: Unknown result type (might be due to invalid IL or missing references)
			//IL_0736: Unknown result type (might be due to invalid IL or missing references)
			//IL_073b: Unknown result type (might be due to invalid IL or missing references)
			//IL_075b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0760: Unknown result type (might be due to invalid IL or missing references)
			//IL_0925: Unknown result type (might be due to invalid IL or missing references)
			//IL_092a: Unknown result type (might be due to invalid IL or missing references)
			//IL_092c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0931: Unknown result type (might be due to invalid IL or missing references)
			//IL_0933: Unknown result type (might be due to invalid IL or missing references)
			if (!StaticStorage.RecipeMarkInfos.ContainsKey(recipeIndex))
			{
				return null;
			}
			Potion recipeToClone = (Potion)RecipeBook.Instance.savedRecipes[recipeIndex];
			if (recipeToClone.GetRecipeData().recipeMarks.Count - 1 == recipeMarkIndex)
			{
				return recipeToClone;
			}
			Dictionary<int, RecipeMarkInfo> dictionary = StaticStorage.RecipeMarkInfos[recipeIndex];
			Dictionary<DeltaProperty, BaseDelta> potionState = new Dictionary<DeltaProperty, BaseDelta>();
			ReconstructionTimeline reconstructionTimeline = new ReconstructionTimeline();
			int lowestIngredientIndex = -1;
			List<int> ignoreFixedHintIndexes = new List<int>();
			int? previousAddedIngredients = null;
			int oldRecipeIndex = 0;
			int k;
			for (k = recipeMarkIndex; k >= 0; k--)
			{
				if (!dictionary.TryGetValue(k, out var curRecipeMarkDeltas))
				{
					if (oldRecipeIndex == 0)
					{
						oldRecipeIndex = k;
					}
					continue;
				}
				if (k == 0)
				{
					k = oldRecipeIndex;
				}
				curRecipeMarkDeltas.Deltas.ForEach(delegate(BaseDelta delta)
				{
					if (!potionState.ContainsKey(delta.Property))
					{
						Dictionary<DeltaProperty, BaseDelta> dictionary2 = potionState;
						DeltaProperty property = delta.Property;
						BaseDelta value6 = ((delta is ListDelta) ? delta : ((!(delta is ListAddDelta)) ? delta : new ListDelta
						{
							Property = delta.Property
						}));
						dictionary2[property] = value6;
						if (delta is ListAddDelta addDelta2)
						{
							processListAddDelta(addDelta2, (ListDelta)potionState[delta.Property]);
						}
					}
					else if (!(delta is ListDelta listDelta2))
					{
						if (delta is ListAddDelta addDelta3)
						{
							processListAddDelta(addDelta3, (ListDelta)potionState[delta.Property]);
						}
					}
					else
					{
						ListDelta existingListDelta2 = (ListDelta)potionState[delta.Property];
						listDelta2.AddDeltas.ForEach(delegate(ListAddDelta addDelta)
						{
							processListAddDelta(addDelta, existingListDelta2);
						});
					}
				});
				reconstructionTimeline.AddBasePropertyInformationFromDeltas(recipeToClone.GetRecipeData().recipeMarks, k, curRecipeMarkDeltas.Deltas);
				if (k == oldRecipeIndex)
				{
					k = 0;
				}
				void processListAddDelta(ListAddDelta addDelta, ListDelta existingListDelta)
				{
					int curIndex = addDelta.Index;
					if (addDelta.Property == DeltaProperty.FixedHints)
					{
						if (ignoreFixedHintIndexes.Contains(curIndex))
						{
							return;
						}
						if (!potionState.TryGetValue(DeltaProperty.PathAddedFixedHints, out var value3))
						{
							value3 = curRecipeMarkDeltas.Deltas.FirstOrDefault((BaseDelta d) => d.Property == DeltaProperty.PathAddedFixedHints) as ModifyDelta<int>;
						}
						if (value3 != null)
						{
							int newValue2 = ((ModifyDelta<int>)value3).NewValue;
							ModifyDelta<int> modifyDelta4 = curRecipeMarkDeltas.Deltas.FirstOrDefault((BaseDelta d) => d.Property == DeltaProperty.PathAddedFixedHints) as ModifyDelta<int>;
							if (modifyDelta4 != null)
							{
								if (k == oldRecipeIndex)
								{
									modifyDelta4.NewValue = ((ListDelta)curRecipeMarkDeltas.Deltas.FirstOrDefault((BaseDelta d) => d.Property == DeltaProperty.FixedHints))?.AddDeltas?.Count ?? modifyDelta4.NewValue;
								}
								if (previousAddedIngredients.HasValue && modifyDelta4.NewValue > previousAddedIngredients)
								{
									ignoreFixedHintIndexes.Add(curIndex);
									return;
								}
								previousAddedIngredients = modifyDelta4.NewValue;
							}
							int num6 = newValue2 - 1;
							if (curIndex > num6)
							{
								return;
							}
							if (potionState.TryGetValue(DeltaProperty.PathFixedHintsCount, out var value4))
							{
								lowestIngredientIndex = num6 - ((ModifyDelta<int>)value4).NewValue + 1;
								if (curIndex < lowestIngredientIndex)
								{
									return;
								}
							}
						}
						addFixedHintDeltaToTimeline(addDelta);
					}
					ListAddDelta existingIndexDelta = existingListDelta.AddDeltas.FirstOrDefault((ListAddDelta d) => d.Index == curIndex);
					if (existingIndexDelta == null)
					{
						existingListDelta.AddDeltas.Add(addDelta);
					}
					else
					{
						addDelta.Deltas.ForEach(delegate(ModifyDelta modifyDelta)
						{
							if (!(existingIndexDelta.Deltas.FirstOrDefault((ModifyDelta d) => d.Property == modifyDelta.Property) != null))
							{
								existingIndexDelta.Deltas.Add(modifyDelta);
							}
						});
					}
				}
			}
			ListDelta obj = (ListDelta)potionState[DeltaProperty.FixedHints];
			int newValue = ((ModifyDelta<int>)potionState[DeltaProperty.PathFixedHintsCount]).NewValue;
			obj.AddDeltas = obj.AddDeltas.OrderBy((ListAddDelta d) => d.Index).Take(newValue).ToList();
			obj.AddDeltas.RemoveAll((ListAddDelta d) => d.Index < lowestIngredientIndex);
			reconstructionTimeline.FixedHintTimelines.Where((KeyValuePair<int, FixedHintTimeline> fht) => fht.Key < lowestIngredientIndex).ToList().ForEach(delegate(KeyValuePair<int, FixedHintTimeline> fht)
			{
				reconstructionTimeline.FixedHintTimelines.Remove(fht.Key);
			});
			StaticStorage.SelectedRecipePotionState = potionState;
			Potion newRecipe = (Potion)recipeToClone.Clone();
			SerializedPotionRecipeData newRecipeRecipeData = newRecipe.GetRecipeData();
			ListDelta listDelta = (ListDelta)potionState[DeltaProperty.UsedComponents];
			listDelta.AddDeltas.Sort(SortAddDeltasByIndexDesc);
			int j;
			for (j = newRecipe.usedComponents.GetSummaryComponentsCount() - 1; j > 0; j--)
			{
				ListAddDelta listAddDelta = listDelta.AddDeltas.FirstOrDefault((ListAddDelta d) => d.Index == j);
				if (listAddDelta == null)
				{
					newRecipe.usedComponents.GetSummaryComponents().RemoveAt(j);
					continue;
				}
				ModifyDelta<int> modifyDelta2 = (ModifyDelta<int>)listAddDelta.Deltas.First((ModifyDelta d) => d.Property == DeltaProperty.UsedComponent_Ammount);
				Traverse.Create((object)newRecipe.usedComponents.GetSummaryComponents()[j]).Property("Amount", (object[])null).SetValue((object)modifyDelta2.NewValue);
			}
			newRecipeRecipeData.usedComponents.components.Clear();
			newRecipe.usedComponents.GetSummaryComponents().ForEach(delegate(AlchemySubstanceComponent component)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				//IL_0051: Expected O, but got Unknown
				List<SerializedAlchemySubstanceComponent> components = newRecipeRecipeData.usedComponents.components;
				SerializedAlchemySubstanceComponent val4 = new SerializedAlchemySubstanceComponent
				{
					name = ((Object)component.Component).name,
					amount = component.Amount
				};
				AlchemySubstanceComponentType type = component.Type;
				val4.type = ((object)(AlchemySubstanceComponentType)(ref type)).ToString();
				components.Add(val4);
			});
			ListDelta deltaFixedHints = (ListDelta)potionState[DeltaProperty.FixedHints];
			deltaFixedHints.AddDeltas.Sort(SortAddDeltasByIndex);
			List<FixedHint> fixedPathHints = Managers.RecipeMap.path.fixedPathHints;
			float deletedGraphicsSegments = Managers.RecipeMap.path.deletedGraphicsSegments;
			Vector3 localPosition = ((Component)Managers.RecipeMap.path).transform.localPosition;
			List<int> list = new List<int>();
			List<FixedHint> list2 = new List<FixedHint>();
			GameObject val = new GameObject("dummyObject");
			Vector3 val2 = Vector3.zero;
			Vector3 val3 = Vector3.zero;
			Managers.RecipeMap.path.fixedPathHints = list2;
			Managers.RecipeMap.path.deletedGraphicsSegments = 0f;
			((RecipeMapItem)Managers.RecipeMap.path).SetPositionOnMap(Vector2.op_Implicit(((Component)Managers.RecipeMap.currentMap.referencesContainer.potionBaseMapItem).transform.localPosition));
			if (potionState.ContainsKey(DeltaProperty.OldSerializedPath))
			{
				ModifyDelta<SerializedPath> modifyDelta3 = (ModifyDelta<SerializedPath>)potionState[DeltaProperty.OldSerializedPath];
				list.AddRange((from fh in deltaFixedHints.AddDeltas
					where fh.Deltas.Any((ModifyDelta d) => d.Property == DeltaProperty.IsOldFixedHint)
					select fh.Index).ToList());
				List<SerializedPathPoints> list3 = modifyDelta3.NewValue.fixedPathPoints.ToList();
				for (int num = list3.Count - 1; num >= 0; num--)
				{
					if (!list.Contains(num))
					{
						modifyDelta3.NewValue.fixedPathPoints.RemoveAt(num);
					}
				}
				Managers.RecipeMap.path.ShowLoadedFixedPathHints(modifyDelta3.NewValue);
				modifyDelta3.NewValue.fixedPathPoints = list3;
			}
			bool flag = true;
			foreach (ListAddDelta addDelta4 in deltaFixedHints.AddDeltas)
			{
				int index = addDelta4.Index;
				reconstructionTimeline.FixedHintTimelines.TryGetValue(index, out var value);
				if (!list.Contains(addDelta4.Index))
				{
					string ingredientName = value.IngredientName;
					float grindPercent = value.GrindPercent;
					Ingredient byName = Ingredient.GetByName(ingredientName, false, true);
					if ((Object)(object)byName == (Object)null)
					{
						Plugin.LogError($"Error reconstructing path at index {index}. Ingredient ({ingredientName}) is null!");
						return null;
					}
					Managers.RecipeMap.path.potionComponentHintPainter.ShowIngredientHint(false, 0f, (Object)(object)val, (InventoryItem)(object)byName, grindPercent);
					Managers.RecipeMap.path.AddCurrentPathToFixedPath(byName);
				}
				if (flag)
				{
					val2 = Vector2.op_Implicit(((ModifyDelta<(float, float)>)addDelta4.Deltas.First((ModifyDelta d) => d.Property == DeltaProperty.FixedHint_ConnectionPoint)).NewValue.ToVector());
					val3 = Managers.RecipeMap.path.fixedPathHints.First().evenlySpacedPointsFixedGraphics.points.First();
				}
				if (value == null)
				{
					continue;
				}
				List<(int, bool, float)> pathDeletionEvents = reconstructionTimeline.GetPathDeletionEvents(recipeToClone.GetRecipeData().recipeMarks, index);
				int num2 = (pathDeletionEvents.Any() ? pathDeletionEvents.Max<(int, bool, float)>(((int index, bool fromEnd, float length) d) => d.index) : (-1));
				List<(int, Quaternion)> rotationEventsForFixedHint = reconstructionTimeline.GetRotationEventsForFixedHint(index);
				int num3 = (rotationEventsForFixedHint.Any() ? rotationEventsForFixedHint.Max<(int, Quaternion)>(((int index, Quaternion rotation) d) => d.index) : (-1));
				int num4 = Mathf.Max(num2, num3);
				int i;
				for (i = 0; i <= num4; i++)
				{
					bool num5 = pathDeletionEvents.Any<(int, bool, float)>(((int index, bool fromEnd, float length) e) => e.index == i);
					bool flag2 = rotationEventsForFixedHint.Any<(int, Quaternion)>(((int index, Quaternion rotation) e) => e.index == i);
					if (num5)
					{
						(int, bool, float) tuple = pathDeletionEvents.First<(int, bool, float)>(((int index, bool fromEnd, float length) e) => e.index == i);
						float item = tuple.Item3;
						bool item2 = tuple.Item2;
						if (item > 0.0001f)
						{
							if (item2)
							{
								item = MathF.Round(item - 0.099f, 1, MidpointRounding.AwayFromZero);
								if (item > 0f)
								{
									Managers.RecipeMap.path.DeleteSegmentFromEnd(item);
								}
							}
							else
							{
								Traverse.Create((object)Managers.RecipeMap.path).Method("DeleteFromFixedPath", new object[2]
								{
									item,
									Managers.RecipeMap.path.fixedPathHints.First()
								}).GetValue();
							}
						}
					}
					if (flag2)
					{
						(int, Quaternion) tuple2 = rotationEventsForFixedHint.First<(int, Quaternion)>(((int index, Quaternion rotation) e) => e.index == i);
						RotatePath(localPosition: -Managers.RecipeMap.path.fixedPathHints[0].evenlySpacedPointsFixedGraphics.points[0], rotation: tuple2.Item2);
					}
				}
				flag = false;
			}
			Vector3 offset = val2 - val3;
			SerializedPath pathFromCurrentPotion = SerializedPath.GetPathFromCurrentPotion();
			newRecipeRecipeData.serializedPath = pathFromCurrentPotion;
			Object.Destroy((Object)(object)val);
			list2.ForEach(delegate(FixedHint fh)
			{
				fh.DestroyPath();
			});
			Managers.RecipeMap.path.fixedPathHints = fixedPathHints;
			Managers.RecipeMap.path.deletedGraphicsSegments = deletedGraphicsSegments;
			((RecipeMapItem)Managers.RecipeMap.path).SetPositionOnMap(Vector2.op_Implicit(localPosition));
			potionState.ToList().ForEach(delegate(KeyValuePair<DeltaProperty, BaseDelta> propertyDelta)
			{
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_0085: Unknown result type (might be due to invalid IL or missing references)
				//IL_0091: Unknown result type (might be due to invalid IL or missing references)
				//IL_0092: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
				//IL_0105: Unknown result type (might be due to invalid IL or missing references)
				//IL_010a: Unknown result type (might be due to invalid IL or missing references)
				//IL_011c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0121: Unknown result type (might be due to invalid IL or missing references)
				//IL_0126: Unknown result type (might be due to invalid IL or missing references)
				//IL_0135: Unknown result type (might be due to invalid IL or missing references)
				//IL_0147: Unknown result type (might be due to invalid IL or missing references)
				//IL_014c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0151: Unknown result type (might be due to invalid IL or missing references)
				//IL_0160: Unknown result type (might be due to invalid IL or missing references)
				//IL_0161: Unknown result type (might be due to invalid IL or missing references)
				//IL_0166: Unknown result type (might be due to invalid IL or missing references)
				//IL_0172: Expected O, but got Unknown
				//IL_0172: Unknown result type (might be due to invalid IL or missing references)
				//IL_0173: Unknown result type (might be due to invalid IL or missing references)
				//IL_0178: Unknown result type (might be due to invalid IL or missing references)
				//IL_0184: Expected O, but got Unknown
				//IL_0189: Expected O, but got Unknown
				//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
				//IL_00af: Unknown result type (might be due to invalid IL or missing references)
				BaseDelta value5 = propertyDelta.Value;
				switch (propertyDelta.Key)
				{
				case DeltaProperty.IndicatorPosition:
					newRecipeRecipeData.serializedPath.indicatorPosition = ((ModifyDelta<(float, float)>)value5).NewValue.ToVector();
					break;
				case DeltaProperty.PathPosition:
				{
					Vector2 pathPosition = ((ModifyDelta<(float, float)>)value5).NewValue.ToVector();
					newRecipeRecipeData.serializedPath.pathPosition = pathPosition;
					if (deltaFixedHints.AddDeltas.Any())
					{
						if (offset != Vector3.zero)
						{
							newRecipeRecipeData.serializedPath.fixedPathPoints.ForEach(delegate(SerializedPathPoints point)
							{
								point.graphicsPoints = point.graphicsPoints.Select((Vector3 p) => p + offset).ToList();
								point.physicsPoints = point.physicsPoints.Select((Vector3 p) => p + offset).ToList();
								point.dotsPoints = point.dotsPoints.Select((Vector3 p) => p + offset).ToList();
							});
						}
					}
					else
					{
						newRecipeRecipeData.serializedPath.fixedPathPoints.Add(new SerializedPathPoints
						{
							graphicsPoints = new List<Vector3> { Vector2.op_Implicit(-newRecipeRecipeData.serializedPath.pathPosition) },
							physicsPoints = new List<Vector3> { Vector2.op_Implicit(-newRecipeRecipeData.serializedPath.pathPosition) },
							pathEndParameters = new PathEndParameters
							{
								spriteIndex = 2
							},
							pathStartParameters = new PathEndParameters
							{
								spriteIndex = 2
							}
						});
					}
					break;
				}
				case DeltaProperty.IndicatorTargetPosition:
					newRecipeRecipeData.serializedPath.indicatorTargetPosition = ((ModifyDelta<(float, float)>)value5).NewValue.ToVector();
					break;
				case DeltaProperty.FollowButtonTargetPosition:
					newRecipeRecipeData.serializedPath.followButtonTargetObjectPosition = ((ModifyDelta<(float, float)>)value5).NewValue.ToVector();
					break;
				case DeltaProperty.Rotation:
					newRecipeRecipeData.serializedPath.indicatorRotationValue = ((ModifyDelta<float>)value5).NewValue;
					break;
				case DeltaProperty.Health:
				{
					float newValue4 = ((ModifyDelta<float>)value5).NewValue;
					if (newValue4 > 0.01f)
					{
						newRecipeRecipeData.serializedPath.health = newValue4;
					}
					break;
				}
				case DeltaProperty.Effects:
				{
					List<string> newValue3 = ((ModifyDelta<List<string>>)value5).NewValue;
					newRecipe.Effects = newValue3.Select((string e) => PotionEffect.GetByName(e, false, true, (List<PotionEffect>)null)).ToArray();
					newRecipeRecipeData.collectedPotionEffects = newValue3.ToList();
					break;
				}
				case DeltaProperty.PathDeletedSegments:
					newRecipeRecipeData.serializedPath.deletedGraphicsSegments = ((ModifyDelta<float>)value5).NewValue;
					break;
				}
			});
			return newRecipe;
			void addFixedHintDeltaToTimeline(ListAddDelta addDelta)
			{
				if (!reconstructionTimeline.FixedHintTimelines.TryGetValue(addDelta.Index, out var value2))
				{
					value2 = new FixedHintTimeline
					{
						FixedHintIndex = addDelta.Index
					};
					reconstructionTimeline.FixedHintTimelines[addDelta.Index] = value2;
				}
				value2.AddInformationFromDeltas(recipeToClone.GetRecipeData().recipeMarks, k, addDelta.Deltas);
			}
		}

		private static void RotatePath(Quaternion rotation, Vector3 localPosition)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (rotation != Quaternion.identity)
			{
				Matrix4x4 rotationMatrix = Matrix4x4.Translate(-localPosition) * Matrix4x4.Rotate(rotation) * Matrix4x4.Translate(localPosition);
				MethodInfo rotateByMethod = typeof(FixedHint).GetMethod("RotateBy", BindingFlags.Instance | BindingFlags.NonPublic);
				Managers.RecipeMap.path.fixedPathHints.ForEach(delegate(FixedHint f)
				{
					//IL_0010: Unknown result type (might be due to invalid IL or missing references)
					rotateByMethod.Invoke(f, new object[1] { rotationMatrix });
				});
			}
		}

		private static void DebugLogObject(object obj)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			Plugin.PluginLogger.LogMessage((object)JsonConvert.SerializeObject(obj, new JsonSerializerSettings
			{
				ReferenceLoopHandling = (ReferenceLoopHandling)1
			}));
		}

		public static int SortAddDeltasByIndex(ListAddDelta ad1, ListAddDelta ad2)
		{
			if (ad1.Index <= ad2.Index)
			{
				if (ad1.Index != ad2.Index)
				{
					return -1;
				}
				return 0;
			}
			return 1;
		}

		public static int SortAddDeltasByIndexDesc(ListAddDelta ad1, ListAddDelta ad2)
		{
			return -SortAddDeltasByIndex(ad1, ad2);
		}
	}
	public static class SaveLoadService
	{
		public static void SetupListeners()
		{
			if (!StaticStorage.AddedListeners)
			{
				StaticStorage.AddedListeners = true;
				((Component)Managers.Potion).gameObject.AddComponent<UsefulRecipeMarksManager>();
				((UnityEvent<BookmarkController, List<int>>)(object)((Book)RecipeBook.Instance).bookmarkControllersGroupController.onBookmarksRearranged).AddListener((UnityAction<BookmarkController, List<int>>)RecipeBookUIService.BookmarksRearranged);
				((UnityEvent<int, int>)(object)((Book)RecipeBook.Instance).onPageChanged).AddListener((UnityAction<int, int>)RecipeBookUIService.UpdateRecipeMarksForPageChange);
				((UnityEvent<bool>)(object)((DarkScreenContent)RecipeBook.Instance).onActiveStateChanged).AddListener((UnityAction<bool>)RecipeBookUIService.UpdateRecipeMarksForStateChanged);
				((UnityEvent<bool>)(object)Managers.Potion.potionCraftPanel.onPotionUpdated).AddListener((UnityAction<bool>)DeltaRecordingService.ClearPreviousSavedPotionRecipeMarkInfo);
			}
		}

		public static void ClearFileSpecificDataOnFileLoad()
		{
			SetupListeners();
			StaticStorage.CurrentPotionRecipeMarkInfos.Clear();
			StaticStorage.CurrentPotionState.Clear();
			StaticStorage.CurrentRecipeMarkInfo = null;
			StaticStorage.PreviousPotionRecipeMarkInfo = null;
			StaticStorage.SelectedRecipePotionState?.Clear();
			StaticStorage.SelectedRecipeMarkIndex = 0;
			StaticStorage.SelectedRecipeIndex = 0;
			StaticStorage.RecipeMarkInfos.Clear();
		}

		public static void UpdateFailsafeListOnLoad()
		{
			if (StaticStorage.BookmarkOrganizerOldVersionInstalled)
			{
				List<IRecipeBookPageContent> savedRecipes = RecipeBook.Instance.savedRecipes;
				List<IRecipeBookPageContent> list = new List<IRecipeBookPageContent>(savedRecipes.Count);
				list.AddRange(savedRecipes);
				StaticStorage.RecipeIndexes = list;
			}
		}
	}
}
namespace PotionCraftUsefulRecipeMarks.Scripts.Patches
{
	public class OldBookmarkOrganizerFailsafePatch
	{
		[HarmonyPatch(typeof(Bookmark), "UpdateMovingState")]
		public class Bookmark_UpdateMovingState
		{
			[HarmonyAfter(new string[] { "com.fahlgorithm.potioncraftbookmarkorganizer" })]
			private static void Postfix(MovingState value)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				Ex.RunSafe(delegate
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					BookmarkMovingStateChanged(value);
				});
			}
		}

		[HarmonyPatch(typeof(Bookmark), "UpdateMoving")]
		public class Bookmark_UpdateMoving
		{
			private static void Postfix(Bookmark __instance)
			{
				Ex.RunSafe(delegate
				{
					DetermineIfShouldSwapOnRelease(__instance);
				});
			}
		}

		[HarmonyPatch(typeof(RecipeBook), "OnLoad")]
		public class RecipeBook_OnLoad
		{
			private static void Postfix()
			{
				Ex.RunSafe(delegate
				{
					SaveLoadService.UpdateFailsafeListOnLoad();
				});
			}
		}

		private const float SwapAboveY = 1.2f;

		private const float DontSwapBelowX = -0.6f;

		private static bool ShouldSwapOnRelease;

		private static void BookmarkMovingStateChanged(MovingState value)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (StaticStorage.BookmarkOrganizerOldVersionInstalled)
			{
				if ((int)value != 0)
				{
					_ = 1;
				}
				else if (ShouldSwapOnRelease)
				{
					ShouldSwapOnRelease = false;
					RecipeBookUIService.DoOldBookmarkOrganizerFailsfe();
				}
			}
		}

		private static void DetermineIfShouldSwapOnRelease(Bookmark instance)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			if (!StaticStorage.BookmarkOrganizerOldVersionInstalled || (int)instance.CurrentMovingState == 0)
			{
				return;
			}
			BookmarkController bookmarkController = ((Book)RecipeBook.Instance).bookmarkControllersGroupController.controllers[0].bookmarkController;
			if (bookmarkController.rails.Count < 8)
			{
				return;
			}
			BookmarkRail val = bookmarkController.rails[7];
			if ((Object)(object)instance.rail != (Object)(object)val)
			{
				if (ShouldSwapOnRelease)
				{
					ShouldSwapOnRelease = false;
				}
			}
			else if (!ShouldSwapOnRelease)
			{
				Vector2 currentMouseWorldPosition = Managers.Input.controlsProvider.CurrentMouseWorldPosition;
				float num = ((Component)val).transform.position.y + 1.2f;
				float num2 = ((Component)val).transform.position.x - -0.6f;
				ShouldSwapOnRelease = currentMouseWorldPosition.y > num && currentMouseWorldPosition.x > num2;
			}
		}
	}
}
namespace PotionCraftUsefulRecipeMarks.Scripts.Patches.RecipeBookUI
{
	[HarmonyPatch(typeof(Potion), "Clone")]
	public class CopyImportantInfoToPotionInstancePotionPatch
	{
		private static void Postfix(IRecipeBookPageContent __result, Potion __instance)
		{
			Ex.RunSafe(delegate
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Expected O, but got Unknown
				CopyImportantInfoToPotionInstance((Potion)__result, __instance);
			});
		}

		private static void CopyImportantInfoToPotionInstance(Potion copyTo, Potion copyFrom)
		{
			CopyImportantInfoToPotionInstance(copyTo, copyFrom, copyFrom.GetRecipeData());
		}

		private static void CopyImportantInfoToPotionInstance(Potion copyTo, Potion copyFromPotion, SerializedPotionRecipeData copyFrom)
		{
			SerializedPotionRecipeData recipeData = copyTo.GetRecipeData();
			List<SerializedRecipeMark> recipeMarks = recipeData.recipeMarks;
			recipeMarks.Clear();
			copyFrom.recipeMarks.ForEach(delegate(SerializedRecipeMark m)
			{
				recipeMarks.Add(m.Clone());
			});
			recipeData.collectedPotionEffects.Clear();
			PotionEffect[] array = ((copyFromPotion != null) ? copyFromPotion.Effects : null) ?? Managers.Potion.collectedPotionEffects;
			foreach (PotionEffect val in array)
			{
				if ((ComparableScriptableObject<PotionEffect>)(object)val == (ComparableScriptableObject<PotionEffect>)null)
				{
					break;
				}
				recipeData.collectedPotionEffects.Add(((Object)val).name);
			}
			recipeData.serializedPath = copyFrom.serializedPath;
			SimpleAlchemySubstanceComponents usedComponents = copyTo.usedComponents;
			bool? obj;
			if (usedComponents == null)
			{
				obj = null;
			}
			else
			{
				List<AlchemySubstanceComponent> summaryComponents = usedComponents.GetSummaryComponents();
				obj = ((summaryComponents != null) ? new bool?(!summaryComponents.Any()) : null);
			}
			bool? flag = obj;
			if (flag.GetValueOrDefault())
			{
				copyTo.usedComponents.Clear();
				(from component in Managers.Potion.PotionUsedComponents.GetSummaryComponents()
					select component.Clone()).ToList().ForEach(delegate(AlchemySubstanceComponent uc)
				{
					copyTo.usedComponents.Add(uc, -1);
				});
			}
			if (!copyFrom.usedComponents.components.Any())
			{
				copyTo.usedComponents.GetSummaryComponents().ForEach(delegate(AlchemySubstanceComponent component)
				{
					//IL_0010: Unknown result type (might be due to invalid IL or missing references)
					//IL_0015: Unknown result type (might be due to invalid IL or missing references)
					//IL_0026: Unknown result type (might be due to invalid IL or missing references)
					//IL_0032: Unknown result type (might be due to invalid IL or missing references)
					//IL_0034: Unknown result type (might be due to invalid IL or missing references)
					//IL_0039: Unknown result type (might be due to invalid IL or missing references)
					//IL_0051: Expected O, but got Unknown
					List<SerializedAlchemySubstanceComponent> components = copyFrom.usedComponents.components;
					SerializedAlchemySubstanceComponent val2 = new SerializedAlchemySubstanceComponent
					{
						name = ((Object)component.Component).name,
						amount = component.Amount
					};
					AlchemySubstanceComponentType type = component.Type;
					val2.type = ((object)(AlchemySubstanceComponentType)(ref type)).ToString();
					components.Add(val2);
				});
			}
			recipeData.usedComponents = copyFrom.usedComponents;
			recipeData.skinSettings = copyFrom.skinSettings;
		}
	}
	public class DeleteMarkInfoOnRecipeDeletePatch
	{
		[HarmonyPatch(typeof(RecipeBook), "EraseRecipe")]
		public class RecipeBook_EraseRecipe
		{
			private static bool Prefix(IRecipeBookPageContent recipe)
			{
				return Ex.RunSafe(() => DeleteMarkInfoOnRecipeDelete(recipe));
			}
		}

		private static bool DeleteMarkInfoOnRecipeDelete(IRecipeBookPageContent recipe)
		{
			Potion val = (Potion)(object)((recipe is Potion) ? recipe : null);
			if (val == null)
			{
				return true;
			}
			DeltaRecordingService.DeleteMarkInfoForRecipe(val);
			return true;
		}
	}
	public class FixIconExceptionPatch
	{
		[HarmonyPatch(typeof(Icon), "GetByName")]
		public class Icon_GetByName
		{
			private static bool Prefix(ref Icon __result, string iconName)
			{
				return FixPotionIconException(ref __result, iconName);
			}
		}

		private static bool FixPotionIconException(ref Icon result, string iconName)
		{
			Icon tempResult = null;
			bool result2 = Ex.RunSafe(delegate
			{
				if (string.IsNullOrEmpty(iconName))
				{
					tempResult = Icon.allIcons.FirstOrDefault();
					return false;
				}
				return true;
			});
			result = tempResult;
			return result2;
		}
	}
	public class RemoveRecipeMarkForDeletedRecipePatch
	{
		[HarmonyPatch(typeof(RecipeBook), "EraseRecipe")]
		public class RemoveRecipeMarkForDeletedRecipe
		{
			private static void Prefix(IRecipeBookPageContent recipe)
			{
				Ex.RunSafe(delegate
				{
					RecipeBookUIService.RemoveRecipeMarkForDeletedRecipe(recipe);
				});
			}
		}
	}
	public class UpdateRecipeBookPageForSelectedRecipeMarkPatch
	{
		[HarmonyPatch(typeof(Button), "OnClick")]
		public class Button_OnClick
		{
			private static void Postfix(Button __instance)
			{
				Ex.RunSafe(delegate
				{
					RecipeBookUIService.UpdateRecipeBookPageForSelectedRecipeMark(__instance);
				});
			}
		}

		[HarmonyPatch(typeof(RecipeBookRecipeMark), "AssignMark")]
		public class RecipeBookRecipeMark_AssignMark
		{
			private static void Postfix(RecipeBookRecipeMark __instance)
			{
				Ex.RunSafe(delegate
				{
					RecipeBookUIService.EnableDisableMark(__instance);
				});
			}
		}
	}
}
namespace PotionCraftUsefulRecipeMarks.Scripts.Patches.BrewTracking
{
	public class CommitRecipeMarkInfoForSavedRecipePatch
	{
		[HarmonyPatch(typeof(SavePotionRecipeButton), "OnButtonReleasedPointerInside")]
		public class SaveRecipeButton_OnButtonReleasedPointerInside
		{
			private static void Prefix()
			{
				Ex.RunSafe((Action)DeltaRecordingService.CommitRecipeMarkInfoForSavedRecipe, (Action)null, logErrorToStorage: false);
			}
		}
	}
	public class RecordRecipeMarksPatch
	{
		[HarmonyPatch(typeof(RecipeMarksSubManager), "AddLadleMark")]
		public class RecipeMarksSubManager_AddLadleMark
		{
			private static void Postfix()
			{
				Ex.RunSafe(delegate
				{
					DeltaRecordingService.RecordRecipeMarkInfo();
				});
			}
		}

		[HarmonyPatch(typeof(NonTeleportationFixedHint), "RunAlongPath")]
		public class FixedHint_RunAlongPath
		{
			private static void Postfix()
			{
				Ex.RunSafe(delegate
				{
					DeltaRecordingService.RecordRecipeMarkInfo();
				});
			}
		}

		[HarmonyPatch(typeof(TeleportationFixedHint), "SetIndicatorPosition")]
		public class TeleportationFixedHint_SetIndicatorPosition
		{
			private static void Postfix()
			{
				Ex.RunSafe(delegate
				{
					DeltaRecordingService.RecordRecipeMarkInfo();
				});
			}
		}

		[HarmonyPatch(typeof(PotionManager), "ApplyEffectToPotion")]
		public class PotionManager_ApplyEffectToPotion
		{
			private static void Postfix()
			{
				Ex.RunSafe(delegate
				{
					DeltaRecordingService.RecordRecipeMarkInfo();
				});
			}
		}

		[HarmonyPatch(typeof(PotionManager), "AddPotionUsedComponent")]
		public class RecipeMarksSubManager_AddIngredientMark
		{
			private static void Postfix(ScriptableObject componentObject)
			{
				Ex.RunSafe(delegate
				{
					RecordIngredientMark(componentObject);
				});
			}
		}

		[HarmonyPatch(typeof(RecipeMarksSubManager), "AddSaltMark")]
		public class RecipeMarksSubManager_AddSaltMark
		{
			private static void Postfix()
			{
				Ex.RunSafe(delegate
				{
					DeltaRecordingService.RecordRecipeMarkInfo();
				});
			}
		}

		private static void RecordIngredientMark(ScriptableObject componentObject)
		{
			if (!(componentObject is PotionBase) && !(componentObject is Salt))
			{
				DeltaRecordingService.RecordRecipeMarkInfo();
			}
		}
	}
	public class ResetTrackingForPotionResetPatch
	{
		[HarmonyPatch(typeof(PotionManager