Decompiled source of SmartItemSaving v1.2.4

SmartItemSaving.dll

Decompiled 3 months 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.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using IL;
using IL.GameNetcodeStuff;
using Microsoft.CodeAnalysis;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using On;
using On.GameNetcodeStuff;
using SmartItemSaving.Fixes;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SmartItemSaving")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("A mod for Lethal Company")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+462be6473b002a343c431db4f5928d445fdb6193")]
[assembly: AssemblyProduct("SmartItemSaving")]
[assembly: AssemblyTitle("SmartItemSaving")]
[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 SmartItemSaving
{
	public static class Compatibility
	{
		public static bool HasSaveItemRotations()
		{
			PluginInfo pluginInfo;
			return HasSaveItemRotations(out pluginInfo);
		}

		public static bool HasSaveItemRotations(out PluginInfo pluginInfo)
		{
			return Chainloader.PluginInfos.TryGetValue("moe.sylvi.SaveItemRotations", out pluginInfo);
		}

		public static bool HasLethalLevelLoader()
		{
			PluginInfo pluginInfo;
			return HasLethalLevelLoader(out pluginInfo);
		}

		public static bool HasLethalLevelLoader(out PluginInfo pluginInfo)
		{
			return Chainloader.PluginInfos.TryGetValue("imabatby.lethallevelloader", out pluginInfo);
		}
	}
	public class Config
	{
		public static ConfigEntry<bool> FixItemIds { get; private set; }

		public static ConfigEntry<bool> RemoveIfNotFound { get; private set; }

		public static ConfigEntry<bool> SaveItemRotation { get; private set; }

		public static ConfigEntry<bool> FixItemFalling { get; private set; }

		public static ConfigEntry<bool> BetterSyncItems { get; private set; }

		public static ConfigEntry<bool> BackupOnLoad { get; private set; }

		public static ConfigEntry<bool> ForceHandleFixItemIds { get; private set; }

		public static ConfigEntry<bool> ForceHandleSaveItemRotation { get; private set; }

		public Config(ConfigFile cfg)
		{
			FixItemIds = cfg.Bind<bool>("FixItemIds", "Enabled", true, "Attempts to fix changed item ids on load by comparing the saved item names.");
			RemoveIfNotFound = cfg.Bind<bool>("FixItemIds", "RemoveIfNotFound", true, "Removes items with missing names instead of replacing them with an item of the same ID.");
			SaveItemRotation = cfg.Bind<bool>("Misc", "SaveItemRotation", true, "Saves and loads the rotation of items on the ship.");
			FixItemFalling = cfg.Bind<bool>("Misc", "FixItemFalling", true, "Fixes items falling through furniture on load.");
			BetterSyncItems = cfg.Bind<bool>("Misc", "BetterSyncItems", true, "[CLIENT AND HOST] Correctly synchronizes item positions and rotations upon joining (important for Fix Item Falling and Save Item Rotation).");
			BackupOnLoad = cfg.Bind<bool>("Misc", "BackupOnLoad", true, "Whether save files should be backed up on load incase the mod causes any destructive behaviour. NOTE: Only one backup is made!");
			ForceHandleFixItemIds = cfg.Bind<bool>("Compatibility", "ForceHandleFixItemIds", false, "Forces this mod to handle item ID fixing even if the mod LethalLevelLoader is active, which uses a generally more comprehensive ID fixing system.");
			ForceHandleSaveItemRotation = cfg.Bind<bool>("Compatibility", "ForceHandleSaveItemRotation", false, "Forces this mod to handle item rotation loading even if the mod SaveItemRotations is active.");
		}
	}
	public class Patches
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Manipulator <0>__GameNetworkManager_SaveGameValues;

			public static Manipulator <1>__GameNetworkManager_SaveItemsInShip;

			public static hook_SetTimeAndPlanetToSavedSettings <2>__StartOfRound_SetTimeAndPlanetToSavedSettings;

			public static Manipulator <3>__StartOfRound_LoadUnlockables;

			public static Manipulator <4>__StartOfRound_LoadShipGrabbableItems;

			public static hook_Start <5>__GrabbableObject_Start;

			public static hook_Update <6>__GrabbableObject_Update;

			public static hook_ConnectClientToPlayerObject <7>__PlayerControllerB_ConnectClientToPlayerObject;

			public static Manipulator <8>__PlayerControllerB_ThrowObjectClientRpc;

			public static Action<GameNetworkManager> <9>__SaveInitialValues;

			public static Action<GameNetworkManager, List<int>> <10>__SaveFixUnlockIds;

			public static Action<GameNetworkManager> <11>__DeleteItemKeys;

			public static Action <12>__PreSave;

			public static Action<GrabbableObject[], int> <13>__Save;

			public static Func<Vector3, GrabbableObject[], int, Vector3> <14>__Save;
		}

		public static void Initialize()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Expected O, but got Unknown
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Expected O, but got Unknown
			object obj = <>O.<0>__GameNetworkManager_SaveGameValues;
			if (obj == null)
			{
				Manipulator val = GameNetworkManager_SaveGameValues;
				<>O.<0>__GameNetworkManager_SaveGameValues = val;
				obj = (object)val;
			}
			GameNetworkManager.SaveGameValues += (Manipulator)obj;
			object obj2 = <>O.<1>__GameNetworkManager_SaveItemsInShip;
			if (obj2 == null)
			{
				Manipulator val2 = GameNetworkManager_SaveItemsInShip;
				<>O.<1>__GameNetworkManager_SaveItemsInShip = val2;
				obj2 = (object)val2;
			}
			GameNetworkManager.SaveItemsInShip += (Manipulator)obj2;
			object obj3 = <>O.<2>__StartOfRound_SetTimeAndPlanetToSavedSettings;
			if (obj3 == null)
			{
				hook_SetTimeAndPlanetToSavedSettings val3 = StartOfRound_SetTimeAndPlanetToSavedSettings;
				<>O.<2>__StartOfRound_SetTimeAndPlanetToSavedSettings = val3;
				obj3 = (object)val3;
			}
			StartOfRound.SetTimeAndPlanetToSavedSettings += (hook_SetTimeAndPlanetToSavedSettings)obj3;
			object obj4 = <>O.<3>__StartOfRound_LoadUnlockables;
			if (obj4 == null)
			{
				Manipulator val4 = StartOfRound_LoadUnlockables;
				<>O.<3>__StartOfRound_LoadUnlockables = val4;
				obj4 = (object)val4;
			}
			StartOfRound.LoadUnlockables += (Manipulator)obj4;
			object obj5 = <>O.<4>__StartOfRound_LoadShipGrabbableItems;
			if (obj5 == null)
			{
				Manipulator val5 = StartOfRound_LoadShipGrabbableItems;
				<>O.<4>__StartOfRound_LoadShipGrabbableItems = val5;
				obj5 = (object)val5;
			}
			StartOfRound.LoadShipGrabbableItems += (Manipulator)obj5;
			object obj6 = <>O.<5>__GrabbableObject_Start;
			if (obj6 == null)
			{
				hook_Start val6 = GrabbableObject_Start;
				<>O.<5>__GrabbableObject_Start = val6;
				obj6 = (object)val6;
			}
			GrabbableObject.Start += (hook_Start)obj6;
			object obj7 = <>O.<6>__GrabbableObject_Update;
			if (obj7 == null)
			{
				hook_Update val7 = GrabbableObject_Update;
				<>O.<6>__GrabbableObject_Update = val7;
				obj7 = (object)val7;
			}
			GrabbableObject.Update += (hook_Update)obj7;
			object obj8 = <>O.<7>__PlayerControllerB_ConnectClientToPlayerObject;
			if (obj8 == null)
			{
				hook_ConnectClientToPlayerObject val8 = PlayerControllerB_ConnectClientToPlayerObject;
				<>O.<7>__PlayerControllerB_ConnectClientToPlayerObject = val8;
				obj8 = (object)val8;
			}
			PlayerControllerB.ConnectClientToPlayerObject += (hook_ConnectClientToPlayerObject)obj8;
			object obj9 = <>O.<8>__PlayerControllerB_ThrowObjectClientRpc;
			if (obj9 == null)
			{
				Manipulator val9 = PlayerControllerB_ThrowObjectClientRpc;
				<>O.<8>__PlayerControllerB_ThrowObjectClientRpc = val9;
				obj9 = (object)val9;
			}
			PlayerControllerB.ThrowObjectClientRpc += (Manipulator)obj9;
		}

		private static void GameNetworkManager_SaveGameValues(ILContext il)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_00b7: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
			ILCursor val = new ILCursor(il);
			int unlockListLoc = -1;
			if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[2]
			{
				(Instruction instr1) => ILPatternMatchingExt.MatchLdstr(instr1, "UnlockedShipObjects"),
				(Instruction instr2) => ILPatternMatchingExt.MatchLdloc(instr2, ref unlockListLoc)
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveGameValues @ Save unlocked ship objects list");
				return;
			}
			Instruction next = val.Next;
			if (!val.TryGotoPrev((MoveType)2, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchStloc(instr, unlockListLoc)
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveGameValues @ After initialize unlocks list");
				return;
			}
			val.MoveAfterLabels();
			val.Emit(OpCodes.Ldarg_0);
			val.EmitDelegate<Action<GameNetworkManager>>((Action<GameNetworkManager>)General.SaveInitialValues);
			val.Goto(next, (MoveType)1, false);
			val.Emit(OpCodes.Ldarg_0);
			val.Emit(OpCodes.Ldloc, unlockListLoc);
			val.EmitDelegate<Action<GameNetworkManager, List<int>>>((Action<GameNetworkManager, List<int>>)FixUnlockIds.SaveFixUnlockIds);
		}

		private static void GameNetworkManager_SaveItemsInShip(ILContext il)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_032c: Unknown result type (might be due to invalid IL or missing references)
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
			ILCursor val = new ILCursor(il);
			if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchCallOrCallvirt<Object>(instr, "FindObjectsByType")
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveItemsInShip @ Find grabbable objects");
				return;
			}
			int grabbableObjectsLoc = -1;
			if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchStloc(instr, ref grabbableObjectsLoc)
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveItemsInShip @ Get grabbable objects local");
				return;
			}
			if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchCallOrCallvirt<ES3>(instr, "DeleteKey")
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveItemsInShip @ Delete empty keys");
				return;
			}
			val.Emit(OpCodes.Ldarg_0);
			val.EmitDelegate<Action<GameNetworkManager>>((Action<GameNetworkManager>)General.DeleteItemKeys);
			int[] array = new int[4];
			for (int i = 0; i < array.Length; i++)
			{
				int loc = -1;
				if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
				{
					(Instruction instr) => ILPatternMatchingExt.MatchStloc(instr, ref loc)
				}))
				{
					Plugin.Logger.LogError((object)$"Failed IL hook for GameNetworkManager.SaveItemsInShip @ Get list {i} local");
					return;
				}
				array[i] = loc;
			}
			int num = array[0];
			int posLoc = array[1];
			int num2 = array[2];
			int num3 = array[3];
			int iLoc = -1;
			ILLabel val2 = default(ILLabel);
			if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[3]
			{
				(Instruction instr1) => ILPatternMatchingExt.MatchLdcI4(instr1, 0),
				(Instruction instr2) => ILPatternMatchingExt.MatchStloc(instr2, ref iLoc),
				(Instruction instr3) => ILPatternMatchingExt.MatchBr(instr3, ref val2)
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveItemsInShip @ Get loop 'i' local");
				return;
			}
			val.EmitDelegate<Action>((Action)FixItemRotation.PreSave);
			if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchLdloc(instr, posLoc)
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveItemsInShip @ Before add item position");
				return;
			}
			val.Emit(OpCodes.Ldloc, grabbableObjectsLoc);
			val.Emit(OpCodes.Ldloc, iLoc);
			val.EmitDelegate<Action<GrabbableObject[], int>>((Action<GrabbableObject[], int>)FixItemRotation.Save);
			if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchCallOrCallvirt<Transform>(instr, "get_position")
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveItemsInShip @ Get item position");
				return;
			}
			val.Emit(OpCodes.Ldloc, grabbableObjectsLoc);
			val.Emit(OpCodes.Ldloc, iLoc);
			val.EmitDelegate<Func<Vector3, GrabbableObject[], int, Vector3>>((Func<Vector3, GrabbableObject[], int, Vector3>)FixItemFalling.Save);
			if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchCallOrCallvirt<ES3>(instr, "Save")
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveItemsInShip @ First save call");
				return;
			}
			val.Emit(OpCodes.Ldarg_0);
			val.Emit(OpCodes.Ldloc, num);
			val.EmitDelegate<Action<GameNetworkManager, List<int>>>((Action<GameNetworkManager, List<int>>)delegate(GameNetworkManager self, List<int> ids)
			{
				FixItemRotation.PostSave(self);
				FixItemIds.Save(self, ids);
			});
		}

		private static void StartOfRound_SetTimeAndPlanetToSavedSettings(orig_SetTimeAndPlanetToSavedSettings orig, StartOfRound self)
		{
			General.LoadCreateBackup();
			orig.Invoke(self);
			General.LoadInitialValues(self);
		}

		private static void StartOfRound_LoadUnlockables(ILContext il)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			ILCursor val = new ILCursor(il);
			if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchCallOrCallvirt<ES3>(instr, "Load")
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadUnlockables @ Load unlocks list");
				return;
			}
			val.Emit(OpCodes.Ldarg_0);
			val.EmitDelegate<Func<int[], StartOfRound, int[]>>((Func<int[], StartOfRound, int[]>)delegate(int[] unlocks, StartOfRound self)
			{
				try
				{
					FixUnlockIds.LoadFixUnlockIds(self, ref unlocks);
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogError((object)"Load | Unlocks | Error occured during load");
					Plugin.Logger.LogError((object)ex);
				}
				return unlocks;
			});
		}

		private static void StartOfRound_LoadShipGrabbableItems(ILContext il)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			ILCursor val = new ILCursor(il);
			int idsLoc = -1;
			if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchLdstr(instr, "shipGrabbableItemIDs")
			}) || !val.TryGotoNext((MoveType)1, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchStloc(instr, ref idsLoc)
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadShipGrabbableItems @ Get item IDs local");
				return;
			}
			ILLabel val3 = default(ILLabel);
			if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[2]
			{
				(Instruction instr1) => ILPatternMatchingExt.MatchBrfalse(instr1, ref val3),
				(Instruction instr2) => ILPatternMatchingExt.MatchLdstr(instr2, "shipScrapValues")
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadShipGrabbableItems @ Load values");
				return;
			}
			int valuesLoc = -1;
			if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchStloc(instr, ref valuesLoc)
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadShipGrabbableItems @ Get item values local");
				return;
			}
			int dataLoc = 1;
			if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[2]
			{
				(Instruction instr1) => ILPatternMatchingExt.MatchCallOrCallvirt<ES3>(instr1, "Load"),
				(Instruction instr2) => ILPatternMatchingExt.MatchStloc(instr2, ref dataLoc)
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadShipGrabbableItems @ Get item data local");
				return;
			}
			val.MoveAfterLabels();
			val.Emit(OpCodes.Ldarg_0);
			val.Emit(OpCodes.Ldloc, idsLoc);
			val.Emit(OpCodes.Ldloc, valuesLoc);
			val.Emit(OpCodes.Ldloc, dataLoc);
			val.EmitDelegate<Func<StartOfRound, int[], int[], int[], (int[], int[])>>((Func<StartOfRound, int[], int[], int[], (int[], int[])>)delegate(StartOfRound self, int[] ids, int[] values, int[] data)
			{
				try
				{
					FixItemFalling.PreLoad();
					FixItemRotation.PreLoad(ids);
					FixItemIds.Load(self, ids, ref values, ref data);
				}
				catch (Exception ex2)
				{
					Plugin.Logger.LogError((object)"Load | Items | Error occured during pre-load");
					Plugin.Logger.LogError((object)ex2);
				}
				return (values, data);
			});
			val.Emit(OpCodes.Dup);
			val.EmitDelegate<Func<(int[], int[]), int[]>>((Func<(int[], int[]), int[]>)(((int[], int[]) tuple) => tuple.Item1));
			val.Emit(OpCodes.Stloc, valuesLoc);
			val.EmitDelegate<Func<(int[], int[]), int[]>>((Func<(int[], int[]), int[]>)(((int[], int[]) tuple) => tuple.Item2));
			val.Emit(OpCodes.Stloc, dataLoc);
			int iLoc = -1;
			ILLabel val2 = default(ILLabel);
			if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[3]
			{
				(Instruction instr1) => ILPatternMatchingExt.MatchLdcI4(instr1, 0),
				(Instruction instr2) => ILPatternMatchingExt.MatchStloc(instr2, ref iLoc),
				(Instruction instr3) => ILPatternMatchingExt.MatchBr(instr3, ref val2)
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadShipGrabbableItems @ Get loop 'i' local");
				return;
			}
			if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchCallOrCallvirt<GameObject>(instr, "GetComponent")
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadShipGrabbableItems @ Grabbable object instantiation");
				return;
			}
			int grabbableObjectLoc = -1;
			if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchStloc(instr, ref grabbableObjectLoc)
			}))
			{
				Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadShipGrabbableItems @ Get grabbable object local");
				return;
			}
			val.Emit(OpCodes.Ldloc, iLoc);
			val.Emit(OpCodes.Ldloc, grabbableObjectLoc);
			val.EmitDelegate<Action<int, GrabbableObject>>((Action<int, GrabbableObject>)delegate(int i, GrabbableObject grabbableObject)
			{
				try
				{
					FixItemFalling.Load(grabbableObject);
					FixItemRotation.Load(i, grabbableObject);
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogError((object)"Load | Items | Error occured during load");
					Plugin.Logger.LogError((object)ex);
				}
			});
		}

		private static void GrabbableObject_Update(orig_Update orig, GrabbableObject self)
		{
			orig.Invoke(self);
			FixItemRotation.Apply(self);
		}

		private static void GrabbableObject_Start(orig_Start orig, GrabbableObject self)
		{
			orig.Invoke(self);
			FixItemFalling.Apply(self);
		}

		private static void PlayerControllerB_ConnectClientToPlayerObject(orig_ConnectClientToPlayerObject orig, PlayerControllerB self)
		{
			orig.Invoke(self);
			BetterSyncItems.InitializeNetworkingAndSync();
		}

		private static void PlayerControllerB_ThrowObjectClientRpc(ILContext il)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			ILCursor val = new ILCursor(il);
			if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchLdcI4(instr, -1)
			}))
			{
				Plugin.Logger.LogWarning((object)"Failed IL hook for PlayerControllerB.ThrowObjectClientRpc @ Pass -1 (Not a big deal)");
				return;
			}
			val.Emit(OpCodes.Ldarg, 5);
			val.EmitDelegate<Func<int, int, int>>((Func<int, int, int>)((int orig, int floorYRot) => (!Config.BetterSyncItems.Value) ? orig : floorYRot));
		}
	}
	[BepInPlugin("SylviBlossom.SmartItemSaving", "SmartItemSaving", "1.2.4")]
	public class Plugin : BaseUnityPlugin
	{
		public const int FormatVersion = 2;

		public static Plugin Instance { get; private set; }

		public static Config Config { get; private set; }

		public static ManualLogSource Logger { get; private set; }

		private void Awake()
		{
			Instance = this;
			Config = new Config(((BaseUnityPlugin)this).Config);
			Logger = ((BaseUnityPlugin)this).Logger;
			Patches.Initialize();
			Logger.LogInfo((object)"Plugin SmartItemSaving is loaded!");
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "SylviBlossom.SmartItemSaving";

		public const string PLUGIN_NAME = "SmartItemSaving";

		public const string PLUGIN_VERSION = "1.2.4";
	}
	public static class SaveKeys
	{
		public const string FormatVersion = "SylviBlossom.SmartItemSaving_formatVersion";

		public const string ParityStepsTaken = "SylviBlossom.SmartItemSaving_parityStepsTaken";

		public const string ItemNames = "SylviBlossom.SmartItemSaving_itemNames";

		public const string ItemHasValue = "SylviBlossom.SmartItemSaving_itemHasValue";

		public const string ItemHasData = "SylviBlossom.SmartItemSaving_itemHasData";

		public const string ItemRotations = "SylviBlossom.SmartItemSaving_itemRotations";

		public const string UnlockNames = "SylviBlossom.SmartItemSaving_unlockNames";
	}
}
namespace SmartItemSaving.Fixes
{
	public static class BetterSyncItems
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Func<GrabbableObject, bool> <0>__IsValidObject;

			public static HandleNamedMessageDelegate <1>__OnRequestSync;

			public static HandleNamedMessageDelegate <2>__OnReceiveSync;
		}

		internal static void RequestSync()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkManager.Singleton.IsClient)
			{
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1);
			try
			{
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("SylviBlossom.SmartItemSaving_OnRequestItemSync", 0uL, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref val)).Dispose();
			}
		}

		internal static void OnRequestSync(ulong clientId, FastBufferReader _)
		{
			if (NetworkManager.Singleton.IsHost)
			{
				SendSyncTo(clientId);
			}
		}

		internal static void SendSyncTo(ulong clientId)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: 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_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkManager.Singleton.IsHost)
			{
				return;
			}
			GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>().Where(IsValidObject).ToArray();
			int num = Math.Min(array.Length, 999);
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(8 + 32 * num, (Allocator)2, 65536);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				for (int i = 0; i < num; i++)
				{
					NetworkObjectReference val2 = NetworkObjectReference.op_Implicit(((NetworkBehaviour)array[i]).NetworkObject);
					((FastBufferWriter)(ref val)).WriteValueSafe<NetworkObjectReference>(ref val2, default(ForNetworkSerializable));
					Vector3 position = ((Component)array[i]).transform.position;
					((FastBufferWriter)(ref val)).WriteValueSafe(ref position);
					position = ((Component)array[i]).transform.eulerAngles;
					((FastBufferWriter)(ref val)).WriteValueSafe(ref position);
				}
				Plugin.Logger.LogInfo((object)$"Item rotation sync: Sending packet\n- Buffer size: {((FastBufferWriter)(ref val)).Capacity}\n- Bytes written: {((FastBufferWriter)(ref val)).Length}\n- Objects synced: {num}");
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("SylviBlossom.SmartItemSaving_OnReceiveItemSync", clientId, val, (NetworkDelivery)4);
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error occured syncing item rotations with client: {clientId}\n{arg}");
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref val)).Dispose();
			}
		}

		internal static void OnReceiveSync(ulong _, FastBufferReader reader)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((FastBufferReader)(ref reader)).TryBeginRead(4))
				{
					Plugin.Logger.LogError((object)"Item rotation sync error: Could not begin reading buffer");
					return;
				}
				int num = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
				if (!((FastBufferReader)(ref reader)).TryBeginRead(32 * num))
				{
					Plugin.Logger.LogError((object)"Item rotation sync error: Invalid buffer size");
					return;
				}
				NetworkObjectReference val = default(NetworkObjectReference);
				Vector3 position = default(Vector3);
				Vector3 eulerAngles = default(Vector3);
				NetworkObject val2 = default(NetworkObject);
				for (int i = 0; i < num; i++)
				{
					((FastBufferReader)(ref reader)).ReadValueSafe<NetworkObjectReference>(ref val, default(ForNetworkSerializable));
					((FastBufferReader)(ref reader)).ReadValueSafe(ref position);
					((FastBufferReader)(ref reader)).ReadValueSafe(ref eulerAngles);
					if (!((NetworkObjectReference)(ref val)).TryGet(ref val2, (NetworkManager)null))
					{
						Plugin.Logger.LogWarning((object)$"Item rotation sync: Unknown object reference {((NetworkObjectReference)(ref val)).NetworkObjectId}");
						continue;
					}
					GrabbableObject component = ((Component)val2).gameObject.GetComponent<GrabbableObject>();
					if ((Object)(object)component != (Object)null && IsValidObject(component))
					{
						ApplyPositionTo(component, position);
						ApplyRotationTo(component, eulerAngles);
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error occured receiving item rotation sync!\n{arg}");
			}
		}

		public static void InitializeNetworkingAndSync()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			if (!Config.BetterSyncItems.Value)
			{
				return;
			}
			if (NetworkManager.Singleton.IsHost)
			{
				CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager;
				object obj = <>O.<1>__OnRequestSync;
				if (obj == null)
				{
					HandleNamedMessageDelegate val = OnRequestSync;
					<>O.<1>__OnRequestSync = val;
					obj = (object)val;
				}
				customMessagingManager.RegisterNamedMessageHandler("SylviBlossom.SmartItemSaving_OnRequestItemSync", (HandleNamedMessageDelegate)obj);
				return;
			}
			CustomMessagingManager customMessagingManager2 = NetworkManager.Singleton.CustomMessagingManager;
			object obj2 = <>O.<2>__OnReceiveSync;
			if (obj2 == null)
			{
				HandleNamedMessageDelegate val2 = OnReceiveSync;
				<>O.<2>__OnReceiveSync = val2;
				obj2 = (object)val2;
			}
			customMessagingManager2.RegisterNamedMessageHandler("SylviBlossom.SmartItemSaving_OnReceiveItemSync", (HandleNamedMessageDelegate)obj2);
			RequestSync();
		}

		private static bool IsValidObject(GrabbableObject grabbableObject)
		{
			return !grabbableObject.isHeld && (Object)(object)grabbableObject.parentObject == (Object)null && grabbableObject.reachedFloorTarget;
		}

		private static void ApplyPositionTo(GrabbableObject grabbableObject, Vector3 position)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			grabbableObject.fallTime = 1f;
			grabbableObject.hasHitGround = true;
			((Component)grabbableObject).transform.position = position;
			grabbableObject.targetFloorPosition = ((Component)grabbableObject).transform.localPosition;
		}

		private static void ApplyRotationTo(GrabbableObject grabbableObject, Vector3 eulerAngles)
		{
			//IL_0014: 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)
			//IL_002a: 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)
			grabbableObject.floorYRot = -1;
			((Component)grabbableObject).transform.rotation = Quaternion.Euler(((Component)grabbableObject).transform.eulerAngles.x, eulerAngles.y, ((Component)grabbableObject).transform.eulerAngles.z);
		}
	}
	public static class FixItemFalling
	{
		public static HashSet<GrabbableObject> NeedsFixItemFalling = new HashSet<GrabbableObject>();

		public static Vector3 Save(Vector3 position, GrabbableObject[] grabbableObjects, int i)
		{
			//IL_0024: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_0081: 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)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			GrabbableObject val = grabbableObjects[i];
			if (val.isHeld || (Object)(object)val.parentObject != (Object)null)
			{
				return val.GetItemFloorPosition(default(Vector3));
			}
			if (!val.reachedFloorTarget)
			{
				Vector3 val2 = val.targetFloorPosition;
				if ((Object)(object)((Component)val).transform.parent != (Object)null)
				{
					val2 = ((Component)val).transform.parent.TransformPoint(val2);
				}
				return val2;
			}
			return position;
		}

		public static void PreLoad()
		{
			NeedsFixItemFalling = new HashSet<GrabbableObject>();
		}

		public static void Load(GrabbableObject grabbableObject)
		{
			if (Config.FixItemFalling.Value)
			{
				NeedsFixItemFalling.Add(grabbableObject);
			}
		}

		public static void Apply(GrabbableObject grabbableObject)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)StartOfRound.Instance).IsServer && NeedsFixItemFalling.Contains(grabbableObject) && grabbableObject.itemProperties.itemSpawnsOnGround)
			{
				grabbableObject.fallTime = 1f;
				grabbableObject.hasHitGround = true;
				grabbableObject.targetFloorPosition = ((Component)grabbableObject).transform.localPosition;
			}
		}
	}
	public static class FixItemIds
	{
		public static void Save(GameNetworkManager gameNetworkManager, List<int> ids)
		{
			string[] array = new string[ids.Count];
			bool[] array2 = new bool[ids.Count];
			bool[] array3 = new bool[ids.Count];
			for (int i = 0; i < ids.Count; i++)
			{
				int num = ids[i];
				List<Item> itemsList = StartOfRound.Instance.allItemsList.itemsList;
				if (itemsList.Count < num || string.IsNullOrEmpty(itemsList[num].itemName))
				{
					Plugin.Logger.LogWarning((object)$"Save | Items | No item name found for item id {num}");
					array[i] = "";
					array2[i] = false;
					array3[i] = false;
					continue;
				}
				Item val = itemsList[num];
				string name = val.itemName;
				List<Item> list = itemsList.Where((Item x) => x.itemName.Equals(name, StringComparison.InvariantCultureIgnoreCase)).ToList();
				int num2 = list.IndexOf(itemsList[num]);
				if (list.Count > 1 && num2 >= 0)
				{
					name += $"##ID{num2}";
				}
				array[i] = name;
				array2[i] = val.isScrap;
				array3[i] = val.saveItemVariable;
			}
			ES3.Save<string[]>("SylviBlossom.SmartItemSaving_itemNames", array, gameNetworkManager.currentSaveFileName);
			ES3.Save<bool[]>("SylviBlossom.SmartItemSaving_itemHasValue", array2, gameNetworkManager.currentSaveFileName);
			ES3.Save<bool[]>("SylviBlossom.SmartItemSaving_itemHasData", array3, gameNetworkManager.currentSaveFileName);
			Plugin.Logger.LogInfo((object)$"Save | Items | Successfully saved {array.Length} items");
		}

		public static void Load(StartOfRound startOfRound, int[] ids, ref int[] values, ref int[] data)
		{
			string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
			if (!General.LoadedParityCheck)
			{
				return;
			}
			if (!ES3.KeyExists("SylviBlossom.SmartItemSaving_itemNames", currentSaveFileName))
			{
				Plugin.Logger.LogWarning((object)"Load | Items | No item name save data found, skipping item id fixing");
				return;
			}
			string[] array = ES3.Load<string[]>("SylviBlossom.SmartItemSaving_itemNames", currentSaveFileName, new string[0]);
			bool[] array2 = ES3.Load<bool[]>("SylviBlossom.SmartItemSaving_itemHasValue", currentSaveFileName, new bool[ids.Length]);
			bool[] array3 = ES3.Load<bool[]>("SylviBlossom.SmartItemSaving_itemHasData", currentSaveFileName, new bool[ids.Length]);
			if (!Config.FixItemIds.Value)
			{
				Plugin.Logger.LogInfo((object)"Load | Items | FixItemIds is disabled, skipping item id fixing");
				return;
			}
			if (Compatibility.HasLethalLevelLoader(out var pluginInfo) && !Config.ForceHandleFixItemIds.Value)
			{
				Plugin.Logger.LogInfo((object)$"Load | Items | Found mod {pluginInfo.Metadata.Name} v{pluginInfo.Metadata.Version}, skipping item id fixing");
				return;
			}
			if (array.Length != ids.Length)
			{
				Plugin.Logger.LogError((object)$"Load | Items | Item count mismatch (Expected {array.Length}, got {ids.Length}), likely outdated save, skipping item id fixing");
				return;
			}
			int num = 0;
			if (values != null)
			{
				for (int i = 0; i < values.Length; i++)
				{
					num += values[i];
				}
			}
			for (int j = 0; j < ids.Length; j++)
			{
				int num2 = ids[j];
				string text = array[j];
				if (string.IsNullOrEmpty(text))
				{
					Plugin.Logger.LogWarning((object)$"Load | Items | Found empty item name for item id {num2}, loading normally");
					continue;
				}
				string text2 = "";
				if (startOfRound.allItemsList.itemsList.Count > num2 && !string.IsNullOrEmpty(startOfRound.allItemsList.itemsList[num2].itemName))
				{
					text2 = "as \"" + startOfRound.allItemsList.itemsList[num2].itemName + "\"";
				}
				int result = 0;
				bool flag = false;
				int num3 = text.IndexOf("##ID");
				if (num3 != -1)
				{
					if (!int.TryParse(text.Substring(num3 + 4), out result))
					{
						Plugin.Logger.LogError((object)("Load | Items | Failed to parse item name " + text));
					}
					text = text.Substring(0, num3);
					flag = true;
				}
				List<int> list = new List<int>();
				for (int k = 0; k < startOfRound.allItemsList.itemsList.Count; k++)
				{
					Item val = startOfRound.allItemsList.itemsList[k];
					if (val.itemName.Equals(text, StringComparison.InvariantCultureIgnoreCase))
					{
						list.Add(k);
					}
				}
				if (list.Count == 0)
				{
					if (Config.RemoveIfNotFound.Value)
					{
						Plugin.Logger.LogWarning((object)("Load | Items | No item id found for item \"" + text + "\", removing item"));
						ids[j] = int.MaxValue;
					}
					else
					{
						Plugin.Logger.LogWarning((object)$"Load | Items | No item id found for item \"{text}\", loading normally with id {num2} {text2}");
					}
					continue;
				}
				if (list.Count <= result)
				{
					Plugin.Logger.LogWarning((object)$"Load | Items | Saved {num2} as \"{text}\" #{result + 1}, but only found {list.Count} name duplicates, loading as #{list.Count}");
					result = list.Count - 1;
				}
				if (list.Count > 1 && !flag)
				{
					string text3 = string.Join(",", list);
					if (list.Contains(num2))
					{
						Plugin.Logger.LogWarning((object)$"Load | Items | Multiple ids ({text3}) found for item \"{text}\", loading normally with id {num2} {text2}");
						continue;
					}
					Plugin.Logger.LogWarning((object)$"Load | Items | Multiple ids ({text3}) found for item \"{text}\", arbitrarily loading {list[0]}");
				}
				if (num2 != list[result])
				{
					if (num2 < startOfRound.allItemsList.itemsList.Count && num2 >= 0)
					{
						Plugin.Logger.LogInfo((object)$"Load | Items | Fixed item mismatch ({num2}, \"{startOfRound.allItemsList.itemsList[num2].itemName}\" -> {list[result]}, \"{text}\")");
					}
					else
					{
						Plugin.Logger.LogInfo((object)$"Load | Items | Fixed item mismatch ({num2}, unknown -> {list[result]}, \"{text}\")");
					}
					ids[j] = list[result];
				}
			}
			List<int> list2 = new List<int>();
			List<int> list3 = new List<int>();
			int num4 = 0;
			int num5 = 0;
			int num6 = 0;
			for (int l = 0; l < ids.Length; l++)
			{
				if (ids[l] < startOfRound.allItemsList.itemsList.Count)
				{
					Item val2 = startOfRound.allItemsList.itemsList[ids[l]];
					if (val2.isScrap)
					{
						if (array2[l])
						{
							list2.Add(values[num4]);
							num6 += values[num4];
						}
						else
						{
							int num7 = (int)((float)Random.Range(val2.minValue, val2.maxValue - 1) * RoundManager.Instance.scrapValueMultiplier);
							list2.Add(num7);
							num6 += num7;
							Plugin.Logger.LogWarning((object)$"Load | Items | Assigning random value of {num7} to \"{val2.itemName}\"");
						}
					}
					if (val2.saveItemVariable)
					{
						if (array3[l])
						{
							list3.Add(data[num5]);
						}
						else
						{
							list3.Add(0);
							Plugin.Logger.LogWarning((object)("Load | Items | Loaded item \"" + val2.itemName + "\" without its associated save data"));
						}
					}
				}
				if (array2[l])
				{
					num4++;
				}
				if (array3[l])
				{
					num5++;
				}
			}
			string text4 = (num6 - num).ToString();
			if (num6 > num)
			{
				text4 = "+" + text4;
			}
			Plugin.Logger.LogInfo((object)$"Load | Items | Loaded {array.Length} items with a total value of {num6} ({text4})");
			values = list2.ToArray();
			data = list3.ToArray();
		}
	}
	public static class FixItemRotation
	{
		public static Vector3[] LoadedItemRotations;

		public static Dictionary<GrabbableObject, Vector3> NeedsItemRotation = new Dictionary<GrabbableObject, Vector3>();

		public static List<Vector3> SavedItemRotations;

		public static void PreSave()
		{
			SavedItemRotations = new List<Vector3>();
		}

		public static void Save(GrabbableObject[] grabbableObjects, int i)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			GrabbableObject val = grabbableObjects[i];
			SavedItemRotations.Add(((Component)val).transform.eulerAngles);
		}

		public static void PostSave(GameNetworkManager gameNetworkManager)
		{
			if (SavedItemRotations != null)
			{
				ES3.Save<Vector3[]>("SylviBlossom.SmartItemSaving_itemRotations", SavedItemRotations.ToArray(), gameNetworkManager.currentSaveFileName);
			}
		}

		public static void PreLoad(int[] ids)
		{
			LoadedItemRotations = null;
			NeedsItemRotation = new Dictionary<GrabbableObject, Vector3>();
			string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
			if (!General.LoadedParityCheck)
			{
				return;
			}
			if (!Config.SaveItemRotation.Value)
			{
				Plugin.Logger.LogInfo((object)"Load | Items | SaveItemRotation is disabled, skipping load item rotation");
				return;
			}
			if (Compatibility.HasSaveItemRotations(out var pluginInfo) && !Config.ForceHandleSaveItemRotation.Value)
			{
				Plugin.Logger.LogInfo((object)$"Load | Items | Found mod {pluginInfo.Metadata.Name} v{pluginInfo.Metadata.Version}, skipping load item rotation");
				return;
			}
			if (!ES3.KeyExists("SylviBlossom.SmartItemSaving_itemRotations", currentSaveFileName))
			{
				Plugin.Logger.LogWarning((object)"Load | Items | No item rotation save data found, skipping load item rotation");
				return;
			}
			LoadedItemRotations = ES3.Load<Vector3[]>("SylviBlossom.SmartItemSaving_itemRotations", currentSaveFileName);
			if (LoadedItemRotations.Length != ids.Length)
			{
				Plugin.Logger.LogError((object)$"Load | Items | Item count mismatch (Expected {LoadedItemRotations.Length}, got {ids.Length}), likely outdated save, skipping load item rotation");
				LoadedItemRotations = null;
			}
		}

		public static void Load(int i, GrabbableObject grabbableObject)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if (LoadedItemRotations != null)
			{
				if (i >= LoadedItemRotations.Length)
				{
					Plugin.Logger.LogError((object)"Load | Items | Item index outside bounds of saved rotations, this shouldn't happen");
					return;
				}
				NeedsItemRotation.Add(grabbableObject, LoadedItemRotations[i]);
				ApplyRotationTo(grabbableObject, LoadedItemRotations[i]);
			}
		}

		public static void Apply(GrabbableObject grabbableObject)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)grabbableObject).IsServer && NeedsItemRotation.TryGetValue(grabbableObject, out var value))
			{
				ApplyRotationTo(grabbableObject, value);
				NeedsItemRotation.Remove(grabbableObject);
			}
		}

		private static void ApplyRotationTo(GrabbableObject grabbableObject, Vector3 eulerAngles)
		{
			//IL_0014: 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)
			//IL_002a: 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)
			grabbableObject.floorYRot = -1;
			((Component)grabbableObject).transform.rotation = Quaternion.Euler(((Component)grabbableObject).transform.eulerAngles.x, eulerAngles.y, ((Component)grabbableObject).transform.eulerAngles.z);
		}
	}
	public static class FixUnlockIds
	{
		public static void SaveFixUnlockIds(GameNetworkManager gameNetworkManager, List<int> unlocks)
		{
			string[] array = new string[unlocks.Count];
			for (int i = 0; i < unlocks.Count; i++)
			{
				array[i] = StartOfRound.Instance.unlockablesList.unlockables[unlocks[i]].unlockableName;
			}
			ES3.Save<string[]>("SylviBlossom.SmartItemSaving_unlockNames", array, gameNetworkManager.currentSaveFileName);
			Plugin.Logger.LogInfo((object)$"Save | Unlockables | Successfully saved {array.Length} unlocks");
		}

		public static void LoadFixUnlockIds(StartOfRound startOfRound, ref int[] unlocks)
		{
			string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
			if (!General.LoadedParityCheck)
			{
				return;
			}
			if (!Config.FixItemIds.Value)
			{
				Plugin.Logger.LogInfo((object)"Load | Unlockables | FixItemIds is disabled, skipping unlockable id fixing");
				return;
			}
			if (!ES3.KeyExists("SylviBlossom.SmartItemSaving_unlockNames", currentSaveFileName))
			{
				Plugin.Logger.LogWarning((object)"Load | Unlockables | No unlock name save data found, skipping unlockable id fixing");
				return;
			}
			string[] array = ES3.Load<string[]>("SylviBlossom.SmartItemSaving_unlockNames", currentSaveFileName, new string[0]);
			if (array.Length != unlocks.Length)
			{
				Plugin.Logger.LogError((object)$"Load | Unlockables | Unlocks count mismatch (Expected {array.Length}, got {unlocks.Length}), likely outdated save, skipping unlockable id fixing");
				return;
			}
			List<int> list = new List<int>();
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i];
				int num = unlocks[i];
				if (string.IsNullOrEmpty(text))
				{
					Plugin.Logger.LogWarning((object)$"Load | Unlockables | Found empty unlock name for unlock id {num}, loading normally");
					list.Add(num);
					continue;
				}
				string text2 = "";
				if (startOfRound.unlockablesList.unlockables.Count > num && !string.IsNullOrEmpty(startOfRound.unlockablesList.unlockables[num].unlockableName))
				{
					text2 = "as \"" + startOfRound.unlockablesList.unlockables[num].unlockableName + "\"";
				}
				List<int> list2 = new List<int>();
				for (int j = 0; j < startOfRound.unlockablesList.unlockables.Count; j++)
				{
					UnlockableItem val = startOfRound.unlockablesList.unlockables[j];
					if (val.unlockableName.Equals(text, StringComparison.InvariantCultureIgnoreCase))
					{
						list2.Add(j);
					}
				}
				if (list2.Count == 0)
				{
					if (Config.RemoveIfNotFound.Value)
					{
						Plugin.Logger.LogWarning((object)("Load | Unlockables | No unlock id found for unlock \"" + text + "\", removing item"));
						continue;
					}
					Plugin.Logger.LogWarning((object)$"Load | Unlockables | No unlock id found for unlock \"{text}\", loading normally with id {num} {text2}");
					list.Add(num);
					continue;
				}
				if (list2.Count > 1)
				{
					string text3 = string.Join(",", list2);
					if (list2.Contains(num))
					{
						Plugin.Logger.LogWarning((object)$"Load | Unlockables | Multiple ids ({text3}) found for unlock \"{text}\", loading normally with id {num} {text2}");
						list.Add(num);
						continue;
					}
					Plugin.Logger.LogWarning((object)$"Load | Unlockables | Multiple ids ({text3}) found for unlock \"{text}\", arbitrarily loading {list2[0]}");
				}
				if (num != list2[0])
				{
					if (num < startOfRound.unlockablesList.unlockables.Count && num >= 0)
					{
						Plugin.Logger.LogInfo((object)$"Load | Unlockables | Fixed unlock mismatch ({num}, \"{startOfRound.unlockablesList.unlockables[num].unlockableName}\" -> {list2[0]}, \"{text}\")");
					}
					else
					{
						Plugin.Logger.LogInfo((object)$"Load | Unlockables | Fixed unlock mismatch ({num}, unknown -> {list2[0]}, \"{text}\")");
					}
					list.Add(list2[0]);
				}
				else
				{
					list.Add(num);
				}
			}
			unlocks = list.ToArray();
			Plugin.Logger.LogInfo((object)$"Load | Unlockables | Loaded {list.Count} unlocks");
		}
	}
	public static class General
	{
		public static int LoadedFormatVersion;

		public static bool LoadedParityCheck;

		public static void SaveInitialValues(GameNetworkManager gameNetworkManager)
		{
			ES3.Save<int>("SylviBlossom.SmartItemSaving_formatVersion", 2, gameNetworkManager.currentSaveFileName);
			ES3.Save<int>("SylviBlossom.SmartItemSaving_parityStepsTaken", StartOfRound.Instance.gameStats.allStepsTaken, gameNetworkManager.currentSaveFileName);
		}

		public static void LoadInitialValues(StartOfRound startOfRound)
		{
			string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
			if (!ES3.KeyExists("SylviBlossom.SmartItemSaving_formatVersion", currentSaveFileName))
			{
				LoadedFormatVersion = 0;
				LoadedParityCheck = false;
				Plugin.Logger.LogWarning((object)"Load | General | No SmartItemSaving save data found, skipping all");
				return;
			}
			LoadedFormatVersion = ES3.Load<int>("SylviBlossom.SmartItemSaving_formatVersion", currentSaveFileName, 2);
			int num = ES3.Load<int>("SylviBlossom.SmartItemSaving_parityStepsTaken", currentSaveFileName, startOfRound.gameStats.allStepsTaken);
			if (num != startOfRound.gameStats.allStepsTaken)
			{
				LoadedParityCheck = false;
				Plugin.Logger.LogWarning((object)$"Load | General | Steps Taken mismatch (Expected {num}, got {startOfRound.gameStats.allStepsTaken}), likely outdated save, skipping all");
			}
			else
			{
				LoadedParityCheck = true;
			}
		}

		public static void LoadCreateBackup()
		{
			string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
			if (Config.BackupOnLoad.Value && ES3.FileExists(currentSaveFileName))
			{
				Plugin.Logger.LogInfo((object)"Load | General | Creating save backup");
				ES3.CreateBackup(currentSaveFileName);
			}
		}

		public static void DeleteItemKeys(GameNetworkManager gameNetworkManager)
		{
			ES3.DeleteKey("SylviBlossom.SmartItemSaving_itemNames", gameNetworkManager.currentSaveFileName);
			ES3.DeleteKey("SylviBlossom.SmartItemSaving_itemHasValue", gameNetworkManager.currentSaveFileName);
			ES3.DeleteKey("SylviBlossom.SmartItemSaving_itemHasData", gameNetworkManager.currentSaveFileName);
			ES3.DeleteKey("SylviBlossom.SmartItemSaving_itemRotations", gameNetworkManager.currentSaveFileName);
		}
	}
}