Decompiled source of SaveItemRotations v1.0.0

moe.sylvi.SaveItemRotations.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.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using IL;
using IL.GameNetcodeStuff;
using LethalNetworkAPI;
using Microsoft.CodeAnalysis;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using On;
using On.GameNetcodeStuff;
using Unity.Netcode;
using UnityEngine;
using moe.sylvi.SaveItemRotations.Features;
using moe.sylvi.SaveItemRotations.NetcodePatcher;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("ClientNetworkTransform")]
[assembly: IgnoresAccessChecksTo("DissonanceVoip")]
[assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")]
[assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")]
[assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")]
[assembly: IgnoresAccessChecksTo("Unity.Burst")]
[assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")]
[assembly: IgnoresAccessChecksTo("Unity.Collections")]
[assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")]
[assembly: IgnoresAccessChecksTo("Unity.Jobs")]
[assembly: IgnoresAccessChecksTo("Unity.Mathematics")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")]
[assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")]
[assembly: IgnoresAccessChecksTo("Unity.Services.QoS")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Relay")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("Unity.Timeline")]
[assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: AssemblyCompany("moe.sylvi.SaveItemRotations")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+db532e148358b75214ef624b9188e57c19c63e50")]
[assembly: AssemblyProduct("SaveItemRotations")]
[assembly: AssemblyTitle("moe.sylvi.SaveItemRotations")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
internal class <Module>
{
	static <Module>()
	{
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 moe.sylvi.SaveItemRotations
{
	public class Config
	{
		public static Config Instance { get; internal set; }

		public ConfigEntry<bool> SyncOnLoad { get; internal set; }

		public Config(ConfigFile cfg)
		{
			Instance = this;
			SyncOnLoad = cfg.Bind<bool>("General", "SyncOnLoad", true, "Whether to sync item rotations to clients when they join the game. Should only be disabled if it causes issues.");
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("moe.sylvi.SaveItemRotations", "SaveItemRotations", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const int FormatVersion = 1;

		public static Plugin Instance { get; private set; }

		internal static ManualLogSource Logger { get; private set; }

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			new Config(((BaseUnityPlugin)this).Config);
			Common.Patches.Initialize();
			FixItemDrop.Patches.Initialize();
			SaveRotations.Patches.Initialize();
			SyncRotations.Patches.Initialize();
			NetcodePatcher();
			Logger.LogInfo((object)"moe.sylvi.SaveItemRotations v1.0.0 has loaded!");
		}

		private void NetcodePatcher()
		{
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			Type[] array = types;
			foreach (Type type in array)
			{
				MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
				MethodInfo[] array2 = methods;
				foreach (MethodInfo methodInfo in array2)
				{
					object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false);
					if (customAttributes.Length != 0)
					{
						methodInfo.Invoke(null, null);
					}
				}
			}
		}
	}
	public static class SaveKeys
	{
		public const string FormatVersion = "moe.sylvi.SaveItemRotations_formatVersion";

		public const string ParityStepsTaken = "moe.sylvi.SaveItemRotations_parityStepsTaken";

		public const string ItemRotations = "moe.sylvi.SaveItemRotations_itemRotations";
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "moe.sylvi.SaveItemRotations";

		public const string PLUGIN_NAME = "SaveItemRotations";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace moe.sylvi.SaveItemRotations.Features
{
	public static class Common
	{
		public static class Patches
		{
			[CompilerGenerated]
			private static class <>O
			{
				public static hook_SaveItemsInShip <0>__GameNetworkManager_SaveItemsInShip;

				public static hook_SetTimeAndPlanetToSavedSettings <1>__StartOfRound_SetTimeAndPlanetToSavedSettings;
			}

			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
				object obj = <>O.<0>__GameNetworkManager_SaveItemsInShip;
				if (obj == null)
				{
					hook_SaveItemsInShip val = GameNetworkManager_SaveItemsInShip;
					<>O.<0>__GameNetworkManager_SaveItemsInShip = val;
					obj = (object)val;
				}
				GameNetworkManager.SaveItemsInShip += (hook_SaveItemsInShip)obj;
				object obj2 = <>O.<1>__StartOfRound_SetTimeAndPlanetToSavedSettings;
				if (obj2 == null)
				{
					hook_SetTimeAndPlanetToSavedSettings val2 = StartOfRound_SetTimeAndPlanetToSavedSettings;
					<>O.<1>__StartOfRound_SetTimeAndPlanetToSavedSettings = val2;
					obj2 = (object)val2;
				}
				StartOfRound.SetTimeAndPlanetToSavedSettings += (hook_SetTimeAndPlanetToSavedSettings)obj2;
			}

			private static void GameNetworkManager_SaveItemsInShip(orig_SaveItemsInShip orig, GameNetworkManager self)
			{
				if (!StartOfRound.Instance.isChallengeFile)
				{
					SaveInitialValues(self);
				}
				orig.Invoke(self);
			}

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

		public static int LoadedFormatVersion;

		public static bool LoadedParityCheck;

		public static void SaveInitialValues(GameNetworkManager gameNetworkManager)
		{
			ES3.Save<int>("moe.sylvi.SaveItemRotations_formatVersion", 1, gameNetworkManager.currentSaveFileName);
			ES3.Save<int>("moe.sylvi.SaveItemRotations_parityStepsTaken", StartOfRound.Instance.gameStats.allStepsTaken, gameNetworkManager.currentSaveFileName);
		}

		public static void LoadInitialValues(StartOfRound startOfRound)
		{
			string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
			if (!ES3.KeyExists("moe.sylvi.SaveItemRotations_formatVersion", currentSaveFileName))
			{
				LoadedFormatVersion = 0;
				LoadedParityCheck = false;
				Plugin.Logger.LogWarning((object)"Load | No SaveItemRotations save data found, skipping all");
				return;
			}
			LoadedFormatVersion = ES3.Load<int>("moe.sylvi.SaveItemRotations_formatVersion", currentSaveFileName, 1);
			int num = ES3.Load<int>("moe.sylvi.SaveItemRotations_parityStepsTaken", currentSaveFileName, startOfRound.gameStats.allStepsTaken);
			if (num != startOfRound.gameStats.allStepsTaken)
			{
				LoadedParityCheck = false;
				Plugin.Logger.LogWarning((object)$"Load | Steps Taken mismatch (Expected {num}, got {startOfRound.gameStats.allStepsTaken}), likely outdated save, skipping all");
			}
			else
			{
				LoadedParityCheck = true;
			}
		}
	}
	public static class FixItemDrop
	{
		public static class Patches
		{
			[CompilerGenerated]
			private static class <>O
			{
				public static Manipulator <0>__PlayerControllerB_ThrowObjectClientRpc;

				public static Func<int, int, int> <1>__Apply;
			}

			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
				object obj = <>O.<0>__PlayerControllerB_ThrowObjectClientRpc;
				if (obj == null)
				{
					Manipulator val = PlayerControllerB_ThrowObjectClientRpc;
					<>O.<0>__PlayerControllerB_ThrowObjectClientRpc = val;
					obj = (object)val;
				}
				PlayerControllerB.ThrowObjectClientRpc += (Manipulator)obj;
			}

			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_0042: 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)
				}))
				{
					val.Emit(OpCodes.Ldarg, 5);
					val.EmitDelegate<Func<int, int, int>>((Func<int, int, int>)Apply);
				}
			}
		}

		public static int Apply(int orig, int actualRotation)
		{
			return actualRotation;
		}
	}
	public static class SaveRotations
	{
		public static class Patches
		{
			[CompilerGenerated]
			private static class <>O
			{
				public static Manipulator <0>__GameNetworkManager_SaveItemsInShip;

				public static Manipulator <1>__StartOfRound_LoadShipGrabbableItems;

				public static hook_Update <2>__GrabbableObject_Update;

				public static Action <3>__PreSave;

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

				public static Action<GameNetworkManager> <5>__PostSave;

				public static Action<int[]> <6>__PreLoad;

				public static Action<int, GrabbableObject> <7>__Load;
			}

			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
				object obj = <>O.<0>__GameNetworkManager_SaveItemsInShip;
				if (obj == null)
				{
					Manipulator val = GameNetworkManager_SaveItemsInShip;
					<>O.<0>__GameNetworkManager_SaveItemsInShip = val;
					obj = (object)val;
				}
				GameNetworkManager.SaveItemsInShip += (Manipulator)obj;
				object obj2 = <>O.<1>__StartOfRound_LoadShipGrabbableItems;
				if (obj2 == null)
				{
					Manipulator val2 = StartOfRound_LoadShipGrabbableItems;
					<>O.<1>__StartOfRound_LoadShipGrabbableItems = val2;
					obj2 = (object)val2;
				}
				StartOfRound.LoadShipGrabbableItems += (Manipulator)obj2;
				object obj3 = <>O.<2>__GrabbableObject_Update;
				if (obj3 == null)
				{
					hook_Update val3 = GrabbableObject_Update;
					<>O.<2>__GrabbableObject_Update = val3;
					obj3 = (object)val3;
				}
				GrabbableObject.Update += (hook_Update)obj3;
			}

			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_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_02e9: 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;
				}
				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;
				}
				Instruction next = val.Next;
				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;
				}
				Instruction next2 = val.Next;
				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;
				}
				Instruction next3 = val.Next;
				val.Goto(next, (MoveType)0, false);
				val.EmitDelegate<Action>((Action)PreSave);
				val.Goto(next2, (MoveType)0, false);
				val.Emit(OpCodes.Ldloc, grabbableObjectsLoc);
				val.Emit(OpCodes.Ldloc, iLoc);
				val.EmitDelegate<Action<GrabbableObject[], int>>((Action<GrabbableObject[], int>)Save);
				val.Goto(next3, (MoveType)0, false);
				val.Emit(OpCodes.Ldarg_0);
				val.EmitDelegate<Action<GameNetworkManager>>((Action<GameNetworkManager>)PostSave);
			}

			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_01b3: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
				//IL_0203: 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)2, 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;
				}
				Instruction next = val.Next;
				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;
				}
				Instruction next2 = val.Next;
				val.Goto(next, (MoveType)0, false);
				val.Emit(OpCodes.Ldloc, idsLoc);
				val.EmitDelegate<Action<int[]>>((Action<int[]>)PreLoad);
				val.Goto(next2, (MoveType)0, false);
				val.Emit(OpCodes.Ldloc, iLoc);
				val.Emit(OpCodes.Ldloc, grabbableObjectLoc);
				val.EmitDelegate<Action<int, GrabbableObject>>((Action<int, GrabbableObject>)Load);
			}

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

		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_0016: 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[]>("moe.sylvi.SaveItemRotations_itemRotations", SavedItemRotations.ToArray(), gameNetworkManager.currentSaveFileName);
			}
		}

		public static void PreLoad(int[] ids)
		{
			LoadedItemRotations = null;
			NeedsItemRotation = new Dictionary<GrabbableObject, Vector3>();
			string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
			if (!Common.LoadedParityCheck)
			{
				return;
			}
			if (!ES3.KeyExists("moe.sylvi.SaveItemRotations_itemRotations", currentSaveFileName))
			{
				Plugin.Logger.LogWarning((object)"Load | No item rotation save data found, skipping load item rotation");
				return;
			}
			LoadedItemRotations = ES3.Load<Vector3[]>("moe.sylvi.SaveItemRotations_itemRotations", currentSaveFileName);
			if (LoadedItemRotations.Length != ids.Length)
			{
				Plugin.Logger.LogError((object)$"Load | 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 | 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 SyncRotations
	{
		public class ItemData
		{
			public NetworkObjectReference NetworkObject;

			public Vector3 EulerAngles;
		}

		public static class Patches
		{
			[CompilerGenerated]
			private static class <>O
			{
				public static hook_ConnectClientToPlayerObject <0>__PlayerControllerB_ConnectClientToPlayerObject;
			}

			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
				object obj = <>O.<0>__PlayerControllerB_ConnectClientToPlayerObject;
				if (obj == null)
				{
					hook_ConnectClientToPlayerObject val = PlayerControllerB_ConnectClientToPlayerObject;
					<>O.<0>__PlayerControllerB_ConnectClientToPlayerObject = val;
					obj = (object)val;
				}
				PlayerControllerB.ConnectClientToPlayerObject += (hook_ConnectClientToPlayerObject)obj;
			}

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

		public static LNetworkEvent RequestSyncEvent = LNetworkEvent.Connect("RequestItemSync", (Action<ulong>)OnRequestSync, (Action)null, (Action<ulong>)null);

		public static LNetworkMessage<List<ItemData>> SyncItemMessage = LNetworkMessage<List<ItemData>>.Connect("SyncItemData", (Action<List<ItemData>, ulong>)null, (Action<List<ItemData>>)OnReceiveSync, (Action<List<ItemData>, ulong>)null);

		private static void OnReceiveSync(List<ItemData> dataList)
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			if (!Config.Instance.SyncOnLoad.Value)
			{
				Plugin.Logger.LogInfo((object)"Sync | Got item sync from server but SyncOnLoad is disabled, ignoring");
				return;
			}
			Plugin.Logger.LogInfo((object)$"Sync | Got item sync from server with {dataList.Count} object(s)");
			NetworkObject val = default(NetworkObject);
			foreach (ItemData data in dataList)
			{
				if (!((NetworkObjectReference)(ref data.NetworkObject)).TryGet(ref val, (NetworkManager)null))
				{
					Plugin.Logger.LogWarning((object)$"Sync | Unknown object reference {((NetworkObjectReference)(ref data.NetworkObject)).NetworkObjectId}");
					Plugin.Logger.LogWarning((object)$"Sync |   - Supplied rotation: {data.EulerAngles}");
					continue;
				}
				GrabbableObject component = ((Component)val).gameObject.GetComponent<GrabbableObject>();
				if ((Object)(object)component != (Object)null && IsValidObject(component))
				{
					ApplyRotationTo(component, data.EulerAngles);
				}
				else
				{
					Plugin.Logger.LogWarning((object)$"Sync | Attempted to sync invalid item {((NetworkObjectReference)(ref data.NetworkObject)).NetworkObjectId}");
				}
			}
		}

		private static void OnRequestSync(ulong clientId)
		{
			if (!Config.Instance.SyncOnLoad.Value)
			{
				Plugin.Logger.LogInfo((object)$"Sync | Got item sync request from client {clientId} but SyncOnLoad is disabled, ignoring");
				return;
			}
			Plugin.Logger.LogInfo((object)$"Sync | Got item sync request from client {clientId}");
			IEnumerable<ItemData> source = from grabbableObject in Object.FindObjectsOfType<GrabbableObject>().Where(IsValidObject)
				select new ItemData
				{
					NetworkObject = NetworkObjectReference.op_Implicit(((NetworkBehaviour)grabbableObject).NetworkObject),
					EulerAngles = ((Component)grabbableObject).transform.eulerAngles
				};
			SyncItemMessage.SendClient(source.ToList(), clientId);
		}

		public static void InitializeNetworkingAndSync()
		{
			if (!NetworkManager.Singleton.IsHost)
			{
				if (!Config.Instance.SyncOnLoad.Value)
				{
					Plugin.Logger.LogInfo((object)"Sync | SyncOnLoad is disabled, skipping item sync");
					return;
				}
				Plugin.Logger.LogInfo((object)"Sync | Requesting item sync");
				RequestSyncEvent.InvokeServer();
			}
		}

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

		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);
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}
namespace moe.sylvi.SaveItemRotations.NetcodePatcher
{
	[AttributeUsage(AttributeTargets.Module)]
	internal class NetcodePatchedAssemblyAttribute : Attribute
	{
	}
}