Decompiled source of SceneSaverBL v2.0.0

Mods/SceneSaverBL.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using BoneLib;
using BoneLib.BoneMenu;
using BoneLib.BoneMenu.UI;
using BoneLib.Notifications;
using HarmonyLib;
using Il2CppCysharp.Threading.Tasks;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppOculus.Platform;
using Il2CppOculus.Platform.Models;
using Il2CppSLZ.Bonelab;
using Il2CppSLZ.MLAgents;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.AI;
using Il2CppSLZ.Marrow.Data;
using Il2CppSLZ.Marrow.Interaction;
using Il2CppSLZ.Marrow.Pool;
using Il2CppSLZ.Marrow.PuppetMasta;
using Il2CppSLZ.Marrow.SceneStreaming;
using Il2CppSLZ.Marrow.Warehouse;
using Il2CppSLZ.VFX;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Threading;
using Jevil;
using Jevil.ModStats;
using Jevil.Patching;
using Jevil.PostProcessing;
using Jevil.Prefs;
using Jevil.Spawning;
using Jevil.Tweening;
using Jevil.Waiting;
using LabFusion.Network;
using LabFusion.RPC;
using MelonLoader;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using SceneSaverBL;
using SceneSaverBL.Exceptions;
using SceneSaverBL.Interfaces;
using SceneSaverBL.Versions;
using SceneSaverBL.Versions.Version4;
using SceneSaverBL.Versions.Version5;
using SceneSaverBL.Versions.Version6;
using SceneSaverRepo.Data;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("SceneSaverBL")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany(null)]
[assembly: AssemblyProduct("SceneSaverBL")]
[assembly: AssemblyCopyright("Created by extraes")]
[assembly: AssemblyTrademark(null)]
[assembly: ComVisible(false)]
[assembly: AssemblyFileVersion("2.0.0")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: MelonInfo(typeof(global::SceneSaverBL.SceneSaverBL), "SceneSaverBL", "2.0.0", "extraes", "https://bonelab.thunderstore.io/package/extraes/SceneSaverBL/")]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: Ungovernable(/*Could not decode attribute arguments.*/)]
[assembly: MelonOptionalDependencies(new string[] { "LabFusion" })]
[assembly: VerifyLoaderVersion(0, 7, 1, true)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.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]
	internal sealed class IsUnmanagedAttribute : Attribute
	{
	}
	[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NativeIntegerAttribute : Attribute
	{
		public readonly bool[] TransformFlags;

		public NativeIntegerAttribute()
		{
			TransformFlags = new bool[1] { true };
		}

		public NativeIntegerAttribute(bool[] P_0)
		{
			TransformFlags = 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 SceneSaverRepo.Data
{
	public class SceneSaverEntryCollection
	{
		public TimeSpan TimeSinceLastUpdate { get; set; }

		public SceneSaverSaveEntry[] Saves { get; set; }
	}
	public class SceneSaverRepoInfo
	{
		public string name { get; set; }

		public Version version { get; set; }

		public string timeZone { get; set; }

		public int totalDownloads { get; set; }

		public int totalDownloadsWeek { get; set; }

		public int totalSaves { get; set; }

		public TimeSpan timeSinceLastUpdate { get; set; }
	}
	public class SceneSaverSaveEntry
	{
		public const string FILENAME = "ssblmeta";

		public static readonly SceneSaverSaveEntry err = new SceneSaverSaveEntry
		{
			name = "error",
			hash = "0000000000000000",
			tag = "0000"
		};

		public string name { get; set; } = "";


		public string hash { get; set; } = "";


		public string tag { get; set; } = "";


		public string owner { get; set; } = "";


		public int version { get; set; }

		public int downloadCount { get; set; }

		public int downloadCountWeek { get; set; }

		public DateTime? expire { get; set; }

		public override bool Equals(object obj)
		{
			if (obj is SceneSaverSaveEntry sceneSaverSaveEntry)
			{
				return sceneSaverSaveEntry == this;
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (((((-1527566069 * -1521134295 + EqualityComparer<string>.Default.GetHashCode(name)) * -1521134295 + EqualityComparer<string>.Default.GetHashCode(hash)) * -1521134295 + EqualityComparer<string>.Default.GetHashCode(tag)) * -1521134295 + version.GetHashCode()) * -1521134295 + downloadCount.GetHashCode()) * -1521134295 + expire.GetHashCode();
		}

		public TimeSpan? TimeUntilExpired()
		{
			if (!expire.HasValue)
			{
				return null;
			}
			return expire - DateTime.Now;
		}

		public static bool operator ==(SceneSaverSaveEntry lhs, SceneSaverSaveEntry rhs)
		{
			return lhs.hash == rhs.hash;
		}

		public static bool operator !=(SceneSaverSaveEntry lhs, SceneSaverSaveEntry rhs)
		{
			return !(lhs == rhs);
		}
	}
}
namespace SceneSaverBL
{
	internal static class Assets
	{
		internal static class Prefabs
		{
			internal static readonly BundledAsset<GameObject> SelectionWire = new BundledAsset<GameObject>("Assets/SceneSaver/SelectionParticlePrefab.prefab", true);

			internal static readonly BundledAsset<GameObject> SelectionWireMusic = new BundledAsset<GameObject>("Assets/SceneSaver/SelectionWireMusic.prefab", true);

			internal static readonly BundledAsset<GameObject> SavingObjectBounds = new BundledAsset<GameObject>("Assets/SceneSaver/SavingBounds.prefab", true);

			internal static readonly BundledAsset<GameObject> SavingPhotographer = new BundledAsset<GameObject>("Assets/SceneSaver/Photographer.prefab", true);

			internal static readonly BundledAsset<GameObject> IdlePhotographer = new BundledAsset<GameObject>("Assets/SceneSaver/PhotographerIdle.prefab", true);

			internal static readonly BundledAsset<GameObject> CameraFlash = new BundledAsset<GameObject>("Assets/SceneSaver/CameraParticles.prefab", true);

			internal static readonly BundledAsset<GameObject> Polaroid = new BundledAsset<GameObject>("Assets/SceneSaver/PreviewPolaroid.prefab", true);

			internal static readonly BundledAsset<GameObject> FullsavePreviewBounds = new BundledAsset<GameObject>("Assets/SceneSaver/FullsaveBounds.prefab", true);

			internal static readonly BundledAsset<GameObject> ControllerTutorial = new BundledAsset<GameObject>("Assets/SceneSaver/Tutorial/ControllerTutorial.prefab", true);

			internal static readonly BundledAsset<GameObject> Laser = new BundledAsset<GameObject>("Assets/SceneSaver/Laser.prefab", true);

			internal static readonly BundledAsset<GameObject> GroundCircle = new BundledAsset<GameObject>("Assets/SceneSaver/GroundCircle.prefab", true);

			internal static readonly BundledAsset<GameObject> DupeTutorial = new BundledAsset<GameObject>("Assets/SceneSaver/Tutorial/DupeTutorial.prefab", true);
		}

		internal static class Materials
		{
			internal static readonly BundledAsset<Material> SavingObjectCompletedMaterial = new BundledAsset<Material>("Assets/SceneSaver/BoundsLinesSAVED.mat", true);
		}

		private static AssetBundle bundle;

		internal static async Task Init()
		{
			string text = "SceneSaverBL.Resources.Resources" + (Utilities.IsPlatformQuest() ? "Quest.bundle" : ".bundle");
			byte[] bundleBytes = null;
			Extensions.UseEmbeddedResource(((MelonBase)SceneSaverBL.instance).MelonAssembly.Assembly, text, (Action<byte[]>)delegate(byte[] bytes)
			{
				bundleBytes = bytes;
			});
			bundle = await AsyncExtensions.ToTask(AssetBundle.LoadFromMemoryAsync(Il2CppStructArray<byte>.op_Implicit(bundleBytes)), (PlayerLoopTiming)8);
			Extensions.Persist((Object)(object)bundle, true);
			await Prefabs.SelectionWire.BindAsync(bundle);
			await Prefabs.SelectionWireMusic.BindAsync(bundle);
			await Prefabs.SavingObjectBounds.BindAsync(bundle);
			await Prefabs.SavingPhotographer.BindAsync(bundle);
			await Prefabs.IdlePhotographer.BindAsync(bundle);
			await Prefabs.CameraFlash.BindAsync(bundle);
			await Prefabs.Polaroid.BindAsync(bundle);
			await Prefabs.FullsavePreviewBounds.BindAsync(bundle);
			await Prefabs.ControllerTutorial.BindAsync(bundle);
			await Prefabs.Laser.BindAsync(bundle);
			await Prefabs.GroundCircle.BindAsync(bundle);
			await Prefabs.DupeTutorial.BindAsync(bundle);
			await Materials.SavingObjectCompletedMaterial.BindAsync(bundle);
		}
	}
	public static class BonemenuStringInput
	{
		public const string ALL_NUMBERS_ALLOWED = "*";

		public const string ALL_LETTERS_ALLOWED = "*";

		public const string DEFAULT_SYMBOL_SELECTION = " !~@#$%^&*()_+-=/<>,.;':\"[]{}?";

		private const string CATEGORY_NAME_BASE = "Input String: ";

		private static readonly string CharsNotForPath = new string(Path.GetInvalidFileNameChars());

		private static readonly string SymbolsForPath = new string(" !~@#$%^&*()_+-=/<>,.;':\"[]{}?".Where((char c) => !CharsNotForPath.Contains(c)).ToArray());

		private static Page basePage;

		private static BoolElement capsLockElement;

		private static Page letters;

		private static Page numbers;

		private static Page symbols;

		private static FunctionElement backspaceElement;

		private static FunctionElement confirmElement;

		private static int lastLetterSelHash;

		private static int lastNumSelHash;

		private static int lastSymbolSelHash;

		private static UniTaskCompletionSource<string>? uniTaskCompletion;

		private static readonly StringBuilder stringCollector = new StringBuilder();

		private static bool capsLockActive;

		internal static void Init()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			basePage = Page.Root.CreatePage("Input String: ", Color.white, 0, true);
			Element val = basePage.Parent.Elements.First((Element e) => e.ElementName == basePage.Name);
			basePage.Parent.Remove(val);
			basePage.RemoveAll();
			capsLockElement = basePage.CreateBool("caps", Color.gray, false, (Action<bool>)SetCapsLock);
			letters = basePage.CreatePage("Letters", Color.white, 0, true);
			numbers = basePage.CreatePage("Numbers", Color.white, 0, true);
			symbols = basePage.CreatePage("Symbols/other", Color.white, 0, true);
			backspaceElement = basePage.CreateFunction("Backspace", Color.red, (Action)Backspace);
			confirmElement = basePage.CreateFunction("Confirm", Color.green, (Action)ConfirmSelection);
		}

		internal static Task<string> GetFileNameInput()
		{
			return GetStringInput("*", "*", SymbolsForPath);
		}

		internal static async Task<string> GetStringInput(string lettersSelection = "*", string numbersSelection = "*", string symbolSelection = " !~@#$%^&*()_+-=/<>,.;':\"[]{}?")
		{
			basePage.RemoveAll();
			await SetSubpanelButtons(lettersSelection, numbersSelection, symbolSelection);
			RefreshBaseCategory();
			uniTaskCompletion = new UniTaskCompletionSource<string>();
			Page currentPage = Menu.CurrentPage;
			Menu.OpenPage(basePage);
			string result = await uniTaskCompletion.Task;
			uniTaskCompletion = null;
			Menu.OpenPage(currentPage);
			return result;
		}

		private static async Task SetSubpanelButtons(string lettersSelection, string numbersSelection, string symbolSelection)
		{
			SetCapsLock(capsLock: false);
			int hashCode = lettersSelection.GetHashCode();
			string text;
			if (hashCode != lastLetterSelHash)
			{
				lastLetterSelHash = hashCode;
				letters.RemoveAll();
				text = ((lettersSelection == "*") ? "abcdefghijklmnopqrstuvwxyz" : lettersSelection);
				for (int i = 0; i < text.Length; i++)
				{
					char c3 = text[i];
					letters.CreateFunction(c3.ToString(), Color.white, (Action)delegate
					{
						InputCharacter(capsLockActive ? char.ToUpper(c3) : c3);
					});
				}
				await UniTask.Yield();
			}
			int hashCode2 = numbersSelection.GetHashCode();
			if (hashCode2 != lastNumSelHash)
			{
				lastNumSelHash = hashCode2;
				numbers.RemoveAll();
				text = ((numbersSelection == "*") ? "0123456789" : numbersSelection);
				for (int i = 0; i < text.Length; i++)
				{
					char c2 = text[i];
					numbers.CreateFunction(c2.ToString(), Color.white, (Action)delegate
					{
						InputCharacter(c2);
					});
				}
				await UniTask.Yield();
			}
			int hashCode3 = symbolSelection.GetHashCode();
			if (hashCode3 == lastSymbolSelHash)
			{
				return;
			}
			lastSymbolSelHash = hashCode3;
			symbols.RemoveAll();
			text = symbolSelection;
			for (int i = 0; i < text.Length; i++)
			{
				char c = text[i];
				string text2 = c switch
				{
					'\n' => "Newline", 
					'\t' => "Tab", 
					' ' => "Space", 
					'_' => "Underscore", 
					'"' => "Double quote/Quotation mark", 
					'\'' => "Single quote/apostraphe", 
					_ => c.ToString(), 
				};
				symbols.CreateFunction(text2, Color.white, (Action)delegate
				{
					InputCharacter(c);
				});
			}
			await UniTask.Yield();
		}

		private static void RefreshBaseCategory()
		{
			if (letters.Elements.Count != 0)
			{
				basePage.Add((Element)(object)capsLockElement);
				basePage.CreatePageLink(letters);
			}
			if (numbers.Elements.Count != 0)
			{
				basePage.CreatePageLink(numbers);
			}
			if (symbols.Elements.Count != 0)
			{
				basePage.CreatePageLink(symbols);
			}
			basePage.Add((Element)(object)backspaceElement);
			basePage.Add((Element)(object)confirmElement);
		}

		private static void InputCharacter(char c)
		{
			stringCollector.Append(c);
			basePage.Name = "Input String: " + stringCollector.ToString();
		}

		private static void SetCapsLock(bool capsLock)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			capsLockActive = capsLock;
			if (capsLock)
			{
				((Element)capsLockElement).ElementColor = Color.white;
				((Element)capsLockElement).ElementName = "CAPS";
			}
			else
			{
				((Element)capsLockElement).ElementColor = Color.gray;
				((Element)capsLockElement).ElementName = "caps";
			}
		}

		private static void Backspace()
		{
			stringCollector.Remove(stringCollector.Length - 1, 1);
			basePage.Name = "Input String: " + stringCollector.ToString();
		}

		private static void ConfirmSelection()
		{
			uniTaskCompletion.TrySetResult(stringCollector.ToString());
		}
	}
	internal static class CameraFella
	{
		private static GameObject cameraFella;

		private static CancellationTokenSource currentOperation;

		public static void PlayScreenshot()
		{
			currentOperation?.Cancel();
			currentOperation = new CancellationTokenSource();
			AsyncUtilities.WrapNoThrow<CancellationToken>((Func<CancellationToken, Task>)SavingStartedImpl, currentOperation.Token);
		}

		public static void MenuOpened()
		{
			currentOperation?.Cancel();
			currentOperation = new CancellationTokenSource();
			AsyncUtilities.WrapNoThrow<CancellationToken>((Func<CancellationToken, Task>)MenuOpenedImpl, currentOperation.Token);
		}

		public static void MenuClosed()
		{
			currentOperation?.Cancel();
			currentOperation = new CancellationTokenSource();
			AsyncUtilities.WrapNoThrow<CancellationToken>((Func<CancellationToken, Task>)MenuClosedImpl, currentOperation.Token);
		}

		public static void UpdatePosition()
		{
			//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_0026: 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_0036: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (SelectionZone.Active && !((Object)(object)cameraFella == (Object)null))
			{
				var (val, val2) = SelectionZone.Instance.GetCameraPosAndDir();
				cameraFella.transform.SetPositionAndRotation(val, Quaternion.LookRotation(-val2));
			}
		}

		private static async Task SavingStartedImpl(CancellationToken token)
		{
			if ((Object)(object)cameraFella == (Object)null)
			{
				await MenuOpenedImpl(token);
			}
			cameraFella.GetComponent<Animation>().Play();
		}

		[MemberNotNull("cameraFella")]
		private static async Task MenuOpenedImpl(CancellationToken token)
		{
			GameObject val = await Assets.Prefabs.SavingPhotographer.GetAsync();
			Object.Destroy((Object)(object)cameraFella);
			if (!token.IsCancellationRequested)
			{
				cameraFella = Object.Instantiate<GameObject>(val);
				cameraFella.SetActive(SelectionZone.Active);
			}
		}

		private static async Task MenuClosedImpl(CancellationToken token)
		{
			GameObject val = await Assets.Prefabs.IdlePhotographer.GetAsync();
			Object.Destroy((Object)(object)cameraFella);
			if (!token.IsCancellationRequested)
			{
				cameraFella = Object.Instantiate<GameObject>(val);
				cameraFella.SetActive(SelectionZone.Active && Prefs.showPreviewLocation);
			}
		}
	}
	internal static class ConfigVars
	{
		internal static int previewSize = (Utilities.IsPlatformQuest() ? 64 : 256);

		internal static int timeSliceMs = 3;

		internal static bool fullsaveOverTime = true;
	}
	[RegisterTypeInIl2Cpp]
	public class ControllerTutorial : MonoBehaviour
	{
		private const string PLAYER_PREFS_KEY = "SSBL_Shown_Tutorial";

		private static bool tutorialCurrentlyActive;

		private double startTime;

		private Transform handL;

		private Transform handR;

		public ControllerTutorial(nint ptr)
			: base((IntPtr)ptr)
		{
		}

		private void Start()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Invalid comparison between Unknown and I4
			tutorialCurrentlyActive = !((Enum)((Object)this).hideFlags).HasFlag((Enum)(object)(HideFlags)32);
			startTime = Time.timeAsDouble;
			CallDelayed.CallAction((Action)Disappearize, 40f, false);
			handL = ((Component)Player.LeftHand).transform;
			handR = ((Component)Player.RightHand).transform;
			AutoAgroBoid component = ((Component)this).GetComponent<AutoAgroBoid>();
			for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)component.betweenAgroWaypoints).Length; i++)
			{
				((Il2CppArrayBase<GameObject>)(object)component.betweenAgroWaypoints)[i].SetActive(false);
			}
			int num;
			int num2;
			if ((int)((ControllerRig)Player.ControllerRig).leftController.Type == 1)
			{
				num = component.bumperUpdateRate;
				num2 = component.bumperUpdateRate * 2;
			}
			else
			{
				num = 0;
				num2 = component.bumperUpdateRate;
			}
			for (int j = num; j < num2; j++)
			{
				((Il2CppArrayBase<GameObject>)(object)component.betweenAgroWaypoints)[j].SetActive(true);
			}
		}

		private void Update()
		{
			//IL_0010: 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_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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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)
			//IL_0064: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//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_007a: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)Player.Head).transform;
			Vector3 val = Vector3.Lerp(handL.position, handR.position, 0.5f);
			Vector3 val2 = transform.forward + new Vector3(0f, 0.25f, 0f);
			Vector3 normalized = ((Vector3)(ref val2)).normalized;
			normalized.y /= 2f;
			Vector3 val3 = transform.position + 1.5f * normalized;
			Vector3 val4 = transform.position - ((Component)this).transform.position;
			val4.y = 0f;
			Quaternion val5 = Quaternion.LookRotation(val4);
			Vector3 val6 = Vector3.Lerp(val3, val, 0.25f);
			Vector3 val7 = Vector3.Lerp(((Component)this).transform.position, val6, Time.deltaTime * 5f);
			((Component)this).transform.SetPositionAndRotation(val7, val5);
		}

		private void OnDestroy()
		{
			tutorialCurrentlyActive = false;
		}

		private void Disappearize()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			TweenTweenExtensions.RunOnFinish<ScaleTween>(TweenTweenExtensions.UseCustomInterpolator<ScaleTween>(TweenExtensions.TweenLocalScale(((Component)this).transform, Vector3.zero, 5f), (Func<float, float>)((float time) => Mathf.Pow(time, 4f))), (Action)delegate
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			});
		}

		public static void ShowIfUnseen()
		{
			if (!PlayerPrefs.HasKey("SSBL_Shown_Tutorial"))
			{
				Show();
			}
		}

		public static void Show()
		{
			PlayerPrefs.TrySetInt("SSBL_Shown_Tutorial", 1);
			AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow((Func<Task>)ShowImpl), (Action<Exception>)SceneSaverBL.ErrIfNotNull);
		}

		private static async Task ShowImpl()
		{
			GameObject val = await Assets.Prefabs.ControllerTutorial.GetAsync();
			if (!tutorialCurrentlyActive)
			{
				GameObject obj = Object.Instantiate<GameObject>(val);
				obj.AddComponent<ControllerTutorial>();
				obj.SetActive(true);
			}
		}
	}
	internal static class DeserializationBroker
	{
		public static async Task<ISaveFile> CreateSaveFromFile(string path)
		{
			_ = 1;
			try
			{
				using FileStream fs = File.OpenRead(path);
				ISaveFile isf = CreateFileVersion(fs, await SaveUtils.CheckFormatIdentifier(fs));
				await isf.SetFilePath(path);
				return isf;
			}
			catch (Exception ex)
			{
				SceneSaverBL.Warn("Failed to read save metadata from disk! " + ex);
				return new FailedSaveFile(ex);
			}
		}

		private static ISaveFile CreateFileVersion(FileStream fs, byte version)
		{
			return version switch
			{
				4 => new SaveFile(), 
				5 => new SaveFile5(), 
				6 => new SaveFile6(), 
				_ => throw new InvalidVersionException(version), 
			};
		}
	}
	[RegisterTypeInIl2Cpp]
	public class DupeTutorial : MonoBehaviour
	{
		private const string PLAYER_PREFS_KEY = "SSBL_Shown_DupeTutorial";

		private static bool tutorialCurrentlyActive;

		private double startTime;

		private Transform handL;

		private Transform handR;

		public DupeTutorial(nint ptr)
			: base((IntPtr)ptr)
		{
		}

		private void Start()
		{
			//IL_0001: 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)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			tutorialCurrentlyActive = !((Enum)((Object)this).hideFlags).HasFlag((Enum)(object)(HideFlags)32);
			((Component)this).transform.position = Player.Head.position + Player.Head.forward * 50f;
			startTime = Time.timeAsDouble;
			CallDelayed.CallAction((Action)delegate
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}, 21f, false);
			handL = ((Component)Player.LeftHand).transform;
			handR = ((Component)Player.RightHand).transform;
		}

		private void Update()
		{
			//IL_000b: 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_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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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_009f: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			Transform head = Player.Head;
			Vector3 val = Vector3.Lerp(handL.position, handR.position, 0.5f);
			Vector3 val2 = head.forward + new Vector3(0f, 0.25f, 0f);
			Vector3 normalized = ((Vector3)(ref val2)).normalized;
			normalized.y /= 2f;
			Vector3 val3 = head.position + 1.5f * normalized;
			Vector3 val4 = head.position - ((Component)this).transform.position;
			val4.y = 0f;
			Quaternion val5 = Quaternion.LookRotation(val4);
			Vector3 val6 = Vector3.Lerp(val3, val, 0.25f);
			Vector3 val7 = Vector3.Lerp(((Component)this).transform.position, val6, Time.deltaTime * 5f);
			((Component)this).transform.SetPositionAndRotation(val7, val5);
		}

		private void OnDestroy()
		{
			tutorialCurrentlyActive = false;
		}

		public static void ShowIfUnseen()
		{
			if (!PlayerPrefs.HasKey("SSBL_Shown_DupeTutorial"))
			{
				Show();
			}
		}

		public static void Show()
		{
			PlayerPrefs.TrySetInt("SSBL_Shown_DupeTutorial", 1);
			AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow((Func<Task>)ShowImpl), (Action<Exception>)SceneSaverBL.ErrIfNotNull);
		}

		private static async Task ShowImpl()
		{
			GameObject val = await Assets.Prefabs.DupeTutorial.GetAsync();
			if (!tutorialCurrentlyActive)
			{
				GameObject obj = Object.Instantiate<GameObject>(val);
				obj.AddComponent<DupeTutorial>();
				obj.SetActive(true);
			}
		}
	}
	internal static class FingerOffset
	{
		private enum BlendModes
		{
			Alpha,
			PreMultiply,
			Additive,
			Multiply
		}

		private const float ANT_SIZE_DEFAULT = 1f;

		private static readonly ShaderProperty<float> antSize = ShaderProperty<float>.op_Implicit("_AntSize");

		private static readonly ShaderProperty<int> blendMode = ShaderProperty<int>.op_Implicit("_Blend");

		private static readonly Vector3[] directions = (Vector3[])(object)new Vector3[8]
		{
			new Vector3(-1f, 0f, -1f),
			new Vector3(-1f, 0f, 0f),
			new Vector3(-1f, 0f, 1f),
			new Vector3(0f, 0f, -1f),
			new Vector3(0f, 0f, 1f),
			new Vector3(1f, 0f, -1f),
			new Vector3(1f, 0f, 0f),
			new Vector3(1f, 0f, 1f)
		};

		private static readonly float[] directionDistances = new float[directions.Length];

		private static readonly Vector3[] scratchDirections = (Vector3[])(object)new Vector3[directions.Length];

		private static readonly float[] scratchDistances = new float[directions.Length];

		private static readonly float[] distanceHitPoints = new float[directions.Length];

		private static readonly byte[] directionComplements = directions.Select((Vector3 dir) => (byte)Array.IndexOf(directions, -dir)).ToArray();

		private static float timerFollowSpeed = 50f;

		private static Transform timer;

		private static Animation timerAnim;

		private static Renderer timerRend;

		private static Il2CppStructArray<Vector3> timerDirScratch = new Il2CppStructArray<Vector3>(1L);

		private static Il2CppStructArray<Color> timerColScratch = new Il2CppStructArray<Color>(1L);

		private static GameObject line;

		private static Transform lineTransform;

		private static Transform indexFinger;

		private static Material dupeMat;

		private static BlendModes? currBlendMode;

		public static Vector2 wsSaveExtents = Vector2.one;

		private static bool forceFadeoutTimer = false;

		private static Transform Timer
		{
			get
			{
				return timer;
			}
			set
			{
				timer = value;
				timerAnim = ((Component)value).GetComponent<Animation>();
				timerRend = ((Component)value.GetChild(0)).GetComponent<Renderer>();
			}
		}

		private static Animation TimerAnim
		{
			get
			{
				if ((Object)(object)timerAnim == (Object)null && (Object)(object)Timer != (Object)null)
				{
					timerAnim = ((Component)Timer).GetComponent<Animation>();
				}
				return timerAnim;
			}
		}

		private static Renderer TimerRend
		{
			get
			{
				if ((Object)(object)timerRend == (Object)null && (Object)(object)Timer != (Object)null)
				{
					timerRend = ((Component)Timer.GetChild(0)).GetComponent<Renderer>();
				}
				return timerRend;
			}
		}

		private static Il2CppStructArray<Vector3> TimerDirScratch
		{
			get
			{
				if (timerDirScratch == null || ((Il2CppObjectBase)timerDirScratch).WasCollected)
				{
					timerDirScratch = new Il2CppStructArray<Vector3>(1L);
				}
				return timerDirScratch;
			}
		}

		private static Il2CppStructArray<Color> TimerColScratch
		{
			get
			{
				if (timerColScratch == null || ((Il2CppObjectBase)timerColScratch).WasCollected)
				{
					timerColScratch = new Il2CppStructArray<Color>(1L);
				}
				return timerColScratch;
			}
		}

		private static GameObject Line
		{
			get
			{
				return line;
			}
			set
			{
				line = value;
				lineTransform = value.transform;
			}
		}

		private static Transform LineTransform
		{
			get
			{
				if ((Object)(object)lineTransform == (Object)null && (Object)(object)Line != (Object)null)
				{
					lineTransform = Line.transform;
				}
				return lineTransform;
			}
		}

		private static Transform IndexFinger
		{
			get
			{
				if ((Object)(object)indexFinger == (Object)null)
				{
					indexFinger = GetIndex();
				}
				return indexFinger;
			}
		}

		private static Material DupeMat
		{
			get
			{
				if ((Object)(object)dupeMat == (Object)null && (Object)(object)Line != (Object)null)
				{
					dupeMat = ((Renderer)((Component)LineTransform.GetChild(0)).GetComponent<MeshRenderer>()).sharedMaterial;
				}
				return dupeMat;
			}
		}

		private static void CalculateDirectionDistances()
		{
			float x = wsSaveExtents.x;
			float y = wsSaveExtents.y;
			float num = Mathf.Sqrt(x * x + y * y);
			directionDistances[0] = num;
			directionDistances[1] = x;
			directionDistances[2] = num;
			directionDistances[3] = y;
			directionDistances[4] = y;
			directionDistances[5] = num;
			directionDistances[6] = x;
			directionDistances[7] = num;
		}

		public static void Init()
		{
			Hooking.OnLevelLoading += delegate
			{
				currBlendMode = null;
			};
		}

		public static void Begin()
		{
			forceFadeoutTimer = false;
			if ((Object)(object)Line != (Object)null)
			{
				Line.SetActive(true);
				return;
			}
			AsyncExtensions.RunOnFinish<GameObject>(Assets.Prefabs.Laser.GetAsync(), (Action<GameObject>)delegate(GameObject go)
			{
				Line = Object.Instantiate<GameObject>(go);
				Line.SetActive(true);
			});
			AsyncExtensions.RunOnFinish<GameObject>(Assets.Prefabs.GroundCircle.GetAsync(), (Action<GameObject>)delegate(GameObject go)
			{
				GameObject obj = Object.Instantiate<GameObject>(go);
				Timer = obj.transform;
				obj.SetActive(false);
				TimerAnim.Play();
				int stateCount = TimerAnim.GetStateCount();
				for (int i = 0; i < stateCount; i++)
				{
					TimerAnim.GetStateAtIndex(i).speed = 0f;
					TimerAnim.GetStateAtIndex(i).time = 0f;
				}
				TimerAnim.Stop();
			});
		}

		public static async Task MenuGetPosition()
		{
			SceneSaverBL.desiredDupePos = null;
			Page currPage = Menu.CurrentPage;
			PopUpMenuView popup = Player.UIRig.popUpMenu;
			UIControllerInput input = popup._lastCursor;
			popup.Deactivate();
			Begin();
			while (!SceneSaverBL.desiredDupePos.HasValue)
			{
				await UniTask.Yield();
			}
			End();
			popup.Activate(((Rig)Player.ControllerRig).m_head, ((Rig)Player.PhysicsRig).m_chest, input, input.isLeft ? Player.LeftController : Player.RightController);
			await UniTask.Yield();
			popup.BypassToPreferences();
			PreferencesPanelView preferencesPanelView = popup.preferencesPanelView;
			int num = ((Il2CppArrayBase<GameObject>)(object)preferencesPanelView.pages).Length - 1;
			for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)preferencesPanelView.pages).Length; i++)
			{
				if (Instances<GUIMenu>.Has(((Il2CppArrayBase<GameObject>)(object)preferencesPanelView.pages)[i]))
				{
					num = i;
					break;
				}
			}
			Player.UIRig.popUpMenu.preferencesPanelView.PAGESELECT(num);
			await UniTask.Yield();
			Menu.OpenPage(currPage);
			await UniTask.Yield();
		}

		public static void End()
		{
			if ((Object)(object)Line != (Object)null)
			{
				Line.SetActive(false);
			}
			if ((Object)(object)Timer != (Object)null)
			{
				forceFadeoutTimer = true;
			}
		}

		public static void Fadeout()
		{
			if (!((Object)(object)TimerAnim == (Object)null))
			{
				int stateCount = TimerAnim.GetStateCount();
				for (int i = 0; i < stateCount; i++)
				{
					TimerAnim.GetStateAtIndex(i).speed = -1f;
				}
			}
		}

		internal static void OnUpdate()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//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_00c5: 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_008a: 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_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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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)
			if ((Object)(object)Line == (Object)null || !Line.active || (Object)(object)Timer == (Object)null)
			{
				return;
			}
			Transform val = IndexFinger;
			Vector3 val2 = val.position - val.parent.parent.position;
			Vector3 normalized = ((Vector3)(ref val2)).normalized;
			RaycastHit val3 = default(RaycastHit);
			float num = (Physics.Raycast(val.position, normalized, ref val3, 50f) ? ((RaycastHit)(ref val3)).distance : 50f);
			for (int i = 0; i < 10; i++)
			{
				if (num > 0.05f)
				{
					break;
				}
				num = (Physics.Raycast(((RaycastHit)(ref val3)).point + normalized * 0.05f, normalized, ref val3, 50f) ? ((RaycastHit)(ref val3)).distance : 50f);
			}
			UpdateLine(val, normalized, num);
			if (num != 0f && num != 50f)
			{
				UpdateTimer(((RaycastHit)(ref val3)).point, ((RaycastHit)(ref val3)).normal, out var completedAt);
				if (completedAt.HasValue)
				{
					SceneSaverBL.desiredDupePos = completedAt.Value;
					Fadeout();
				}
			}
		}

		private static void UpdateLine(Transform startPoint, Vector3 forward, float dist)
		{
			//IL_0021: 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)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			antSize.SetOn(DupeMat, 1f / dist);
			Line.transform.position = startPoint.position;
			Line.transform.forward = forward;
			Line.transform.localScale = new Vector3(1f, 1f, dist);
		}

		private static void UpdateTimer(Vector3 hitPoint, Vector3 normal, out Vector3? completedAt)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Invalid comparison between Unknown and I4
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			completedAt = null;
			bool flag = false;
			bool flag2 = Vector3.Dot(normal, Vector3.up) > 0.8f;
			HandPoseAnimator val = (Prefs.rightHandDupeLine ? Player.RightHand.Animator : Player.LeftHand.Animator);
			bool flag3 = (int)(Prefs.rightHandDupeLine ? Player.RightController : Player.LeftController).Type == 1;
			bool flag4 = val._currentMiddle + val._currentRing + val._currentPinky > 2.7f;
			bool flag5 = val._currentThumb < 0.1f && !forceFadeoutTimer;
			bool flag6 = flag4 && flag5;
			if (flag6 && val._currentIndex < 0.15f && flag3)
			{
				val._currentIndex = 0f;
			}
			int stateCount = TimerAnim.GetStateCount();
			for (int i = 0; i < stateCount; i++)
			{
				AnimationState stateAtIndex = TimerAnim.GetStateAtIndex(i);
				float time = stateAtIndex.time;
				float num = Mathf.Clamp01((flag2 && flag6) ? (time + Time.deltaTime) : (time - Time.deltaTime));
				if (!flag4 || time != num)
				{
					if (time == 0f)
					{
						TimerAnim.Sample();
						((Component)Timer).gameObject.SetActive(true);
						stateAtIndex.speed = 1f;
						TimerAnim.Play();
					}
					stateAtIndex.time = num;
					if (num == 1f && flag4)
					{
						flag = true;
					}
					if (num == 0f)
					{
						((Component)Timer).gameObject.SetActive(false);
						TimerAnim.Stop();
						return;
					}
				}
			}
			if (!Prefs.dontAdjustDupePos)
			{
				AdjustPosFromWall(ref hitPoint, ref normal);
			}
			Vector3 position = Timer.position;
			if (position == default(Vector3))
			{
				Timer.position = hitPoint;
				timer.rotation = Quaternion.LookRotation(Vector3.forward, normal);
				return;
			}
			Vector3 val2 = hitPoint + normal * 0.01f;
			float num2 = (flag2 ? Vector3.Distance(position, val2) : 0f);
			Vector3 val3 = Vector3.Lerp(position, val2, Time.deltaTime * timerFollowSpeed * num2);
			if (flag)
			{
				completedAt = val3;
			}
			Timer.position = val3;
			if (flag2)
			{
				Timer.rotation = Quaternion.LookRotation(Vector3.forward, normal);
			}
			_ = val3 != position;
		}

		private static void AdjustPosFromWall(ref Vector3 hitPoint, ref Vector3 normal)
		{
			//IL_0014: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_0077: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			int num = (Utilities.IsPlatformQuest() ? 4 : 8);
			RaycastHit val4 = default(RaycastHit);
			RaycastHit val5 = default(RaycastHit);
			for (int i = 0; i < num; i++)
			{
				Vector3 val = hitPoint + normal * 0.01f;
				bool flag = false;
				bool flag2 = false;
				(float, int) tuple = (1f, 0);
				for (int j = 0; j < scratchDirections.Length; j++)
				{
					Vector3 val2 = directions[(j + i) % directions.Length];
					Vector3 val3 = Vector3.Cross(normal, val2);
					scratchDirections[j] = val3;
					bool flag3 = Physics.Raycast(val, val3, ref val4, 0.5f);
					distanceHitPoints[j] = (flag3 ? ((RaycastHit)(ref val4)).distance : 0f);
					if (flag3)
					{
						flag = true;
						if (tuple.Item1 > ((RaycastHit)(ref val4)).distance)
						{
							tuple = (((RaycastHit)(ref val4)).distance, j);
						}
					}
				}
				if (!flag)
				{
					break;
				}
				val -= scratchDirections[tuple.Item2] * (0.5f - tuple.Item1);
				if (Physics.Raycast(val, Vector3.down, ref val5, 0.5f))
				{
					if (Vector3.Distance(hitPoint, ((RaycastHit)(ref val5)).point) < 0.001f)
					{
						break;
					}
					hitPoint = ((RaycastHit)(ref val5)).point;
					normal = ((RaycastHit)(ref val5)).normal;
				}
				if (flag2)
				{
					break;
				}
			}
		}

		private static Transform GetIndex()
		{
			ArtRig artOutput = Player.PhysicsRig.artOutput;
			return ((Component)(Prefs.rightHandDupeLine ? artOutput._rightAnimatorHand : artOutput._leftAnimatorHand).index3).transform.GetChild(0);
		}
	}
	internal class IMGUIInputField
	{
		private const string IMGUI_CONTROL_NAME = "imguiInputField";

		private string str;

		private int duration;

		private float startTime;

		private string filter;

		private UniTaskCompletionSource<string> taskCompletionSource;

		private GUIStyle? style;

		public UniTask<string> OnComplete => taskCompletionSource.Task;

		public bool TimeFinished
		{
			get
			{
				if (duration != -1)
				{
					return Time.realtimeSinceStartup >= startTime + (float)duration;
				}
				return false;
			}
		}

		private GUIStyle Style
		{
			get
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Expected O, but got Unknown
				if (style == null || ((Il2CppObjectBase)style).WasCollected)
				{
					style = new GUIStyle(GUI.skin.textField);
				}
				style.fontSize = (int)Screen.dpi / 4;
				if (style.fontSize == 0)
				{
					style.fontSize = 24;
				}
				return style;
			}
		}

		public IMGUIInputField(int duration, string startStr = "", string filter = "")
		{
			startTime = Time.realtimeSinceStartup;
			this.duration = duration;
			str = startStr;
			this.filter = filter;
			taskCompletionSource = new UniTaskCompletionSource<string>();
		}

		public void OnGUI()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Invalid comparison between Unknown and I4
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: 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_0241: Unknown result type (might be due to invalid IL or missing references)
			if (TimeFinished)
			{
				Finish();
				return;
			}
			GUI.SetNextControlName("imguiInputField");
			bool flag = Event.current.isKey && ((int)Event.current.keyCode == 13 || (int)Event.current.keyCode == 271);
			if (GUI.GetNameOfFocusedControl() == "imguiInputField" && flag)
			{
				Finish();
				return;
			}
			float num = (float)Screen.width * 0.2f;
			float num2 = (float)Screen.height * 0.475f;
			float num3 = (float)Screen.width - 2f * num;
			float num4 = (float)Screen.height - 2f * num2;
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(num, num2, num3, num4);
			string text = str;
			str = GUI.TextField(val, str, 64, Style);
			if (!string.IsNullOrEmpty(filter) && text != str)
			{
				StringBuilder stringBuilder = new StringBuilder(str.Length);
				for (int i = 0; i < str.Length; i++)
				{
					char c = str[i];
					if (filter.Contains(c))
					{
						stringBuilder.Append(c);
					}
					else if (filter.Contains(char.ToUpper(c)))
					{
						stringBuilder.Append(char.ToUpper(c));
					}
					else if (filter.Contains(char.ToLower(c)))
					{
						stringBuilder.Append(char.ToLower(c));
					}
				}
				str = stringBuilder.ToString();
			}
			Rect val2 = new Rect(num, num2 - num4 * 0.5f, num3 * 0.25f, num4 * 0.5f);
			GUI.SetNextControlName("");
			GUI.Box(val2, "Input a string");
			if (duration != -1)
			{
				float num5 = startTime + (float)duration - Time.realtimeSinceStartup;
				Rect val3 = val;
				((Rect)(ref val3)).y = ((Rect)(ref val3)).y + (((Rect)(ref val3)).height + ((Rect)(ref val3)).height * 0.125f);
				((Rect)(ref val3)).height = ((Rect)(ref val3)).height * 0.25f;
				((Rect)(ref val3)).width = ((Rect)(ref val3)).width * (num5 / (float)duration);
				GUI.Box(val3, "");
			}
		}

		private void Finish()
		{
			SceneSaverBL.currentInputter = null;
			taskCompletionSource.TrySetResult(str);
		}

		public static UniTask<string> GetStringAsync(int duration = 30, string startStr = "", string filter = "")
		{
			return (SceneSaverBL.currentInputter = new IMGUIInputField(duration, startStr, filter)).OnComplete;
		}
	}
	public static class BuildInfo
	{
		public const string Name = "SceneSaverBL";

		public const string Author = "extraes";

		public const string Company = null;

		public const string Version = "2.0.0";

		public const string DownloadLink = "https://bonelab.thunderstore.io/package/extraes/SceneSaverBL/";
	}
	public class SceneSaverBL : MelonMod
	{
		private static PrefEntries prefEntries;

		internal static bool isFullSave;

		internal static volatile bool currentlySaving;

		internal static string username;

		internal static SceneSaverBL instance;

		internal static ConcurrentQueue<ISaveFile> needInitialize = new ConcurrentQueue<ISaveFile>();

		internal static ConcurrentQueue<Action> runOnMainThread = new ConcurrentQueue<Action>();

		internal static Vector3? desiredDupePos = null;

		private static readonly Stopwatch updateSw = new Stopwatch();

		public static int[] supportedSaveVers;

		internal static IMGUIInputField? currentInputter;

		internal static string saveDir = Path.Combine(MelonEnvironment.UserDataDirectory, "SceneSaver", "Saves");

		internal static string dupesDir = Path.Combine(MelonEnvironment.UserDataDirectory, "SceneSaver", "Dupes");

		private static readonly SemaphoreSlim logSemaphore = new SemaphoreSlim(1, 1);

		public SceneSaverBL()
		{
			instance = this;
		}

		public override void OnEarlyInitializeMelon()
		{
			SaveChecks.EstablishMainThread();
		}

		public override async void OnInitializeMelon()
		{
			if (!JevilBuildInfo.RuntimeVersionGreaterThanOrEqual("3.1.0"))
			{
				Warn($"SceneSaver v{((MelonBase)this).MelonAssembly.Assembly.GetName().Version} was built for JeviLib v{"3.1.0"}!!! Update your dependencies!!!");
				return;
			}
			prefEntries = Preferences.Register(typeof(Prefs), (string)null);
			Page category = prefEntries.BoneMenuPage["About"];
			Page repoPage = prefEntries.BoneMenuPage["Repo"];
			Prefs.PopulateAboutMenu(category);
			Utilities.CreateDirectoryRecursive(SaveUtils.PreviewDir);
			Menu.OnPageOpened += PageSelected;
			BonemenuStringInput.Init();
			SpawnerStates.Init();
			FingerOffset.Init();
			await Assets.Init();
			Hook.OntoMethod<Action>(typeof(PopUpMenuView), "Deactivate", (Action)MenuClosed);
			Instances<ObjectDestructible>.TryAutoCache();
			Instances<Poolee>.TryAutoCache();
			Instances<AIBrain>.TryAutoCache();
			Instances<GUIMenu>.TryAutoCache();
			FetchUsername();
			await RepoConsumer.Init(repoPage);
			await Saves.Init(prefEntries.BoneMenuPage);
		}

		private static void LogBoardGunState(string loggedFrom, BoardGenerator bg)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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)
			DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(97, 7);
			defaultInterpolatedStringHandler.AppendLiteral("Boardgun state as of ");
			defaultInterpolatedStringHandler.AppendFormatted(loggedFrom);
			defaultInterpolatedStringHandler.AppendLiteral(":\n\tupDir = ");
			defaultInterpolatedStringHandler.AppendFormatted<Vector3>(bg.upDir);
			defaultInterpolatedStringHandler.AppendLiteral("\n\tbuttonDown = ");
			defaultInterpolatedStringHandler.AppendFormatted(bg.ButtonDown);
			defaultInterpolatedStringHandler.AppendLiteral("\n\tfirstPoint = ");
			defaultInterpolatedStringHandler.AppendFormatted<Vector3>(bg.firstPoint);
			defaultInterpolatedStringHandler.AppendLiteral("\n\tEndPoint = ");
			defaultInterpolatedStringHandler.AppendFormatted<Vector3>(bg.EndPoint);
			defaultInterpolatedStringHandler.AppendLiteral("\n\tFirstRb = ");
			MarrowBody firstRb = bg.FirstRb;
			defaultInterpolatedStringHandler.AppendFormatted(((firstRb != null) ? Extensions.GetFullPath(((Component)firstRb).transform) : null) ?? "shid");
			defaultInterpolatedStringHandler.AppendLiteral("\n\tEndRb = ");
			MarrowBody endRb = bg.EndRb;
			defaultInterpolatedStringHandler.AppendFormatted(((endRb != null) ? Extensions.GetFullPath(((Component)endRb).transform) : null) ?? "shid");
			Log(defaultInterpolatedStringHandler.ToStringAndClear());
		}

		public override void OnUpdate()
		{
			ISaveFile result;
			while (needInitialize.TryDequeue(out result))
			{
				Log($"Save {result} - Now initializing from main thread Update");
				AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow((Func<Task>)result.Initialize), (Action<Exception>)ErrIfNotNull);
			}
			updateSw.Restart();
			Action result2;
			while (runOnMainThread.TryDequeue(out result2) && updateSw.ElapsedMilliseconds < ConfigVars.timeSliceMs)
			{
				result2();
			}
			CameraFella.UpdatePosition();
		}

		public override void OnLateUpdate()
		{
			FingerOffset.OnUpdate();
		}

		public override void OnGUI()
		{
			if (currentInputter != null)
			{
				currentInputter.OnGUI();
			}
		}

		private static void FetchUsername()
		{
			if (Utilities.IsSteamVersion())
			{
				AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow((Func<Task>)FetchSteamUsernameAsync), (Action<Exception>)ErrIfNotNull);
			}
			else
			{
				AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow((Func<Task>)FetchOculusUsername), (Action<Exception>)ErrIfNotNull);
			}
		}

		private static async Task FetchSteamUsernameAsync()
		{
			while (!JeviLib.DoneMappingNamespacesToAssemblies)
			{
				await UniTask.Yield();
			}
			Type typeFromString = Utilities.GetTypeFromString("Steamworks", "SteamClient");
			if ((object)typeFromString == null)
			{
				Warn("Steamworks not found! Are you using the Oculus/Meta version?");
				username = "Unknown";
			}
			else
			{
				username = (string)typeFromString.GetProperty("Name").GetValue(null);
				PostcheckUsername();
			}
		}

		private static async Task FetchOculusUsername()
		{
			while (!Core.IsPlatformInitialized)
			{
				await Task.Delay(1000);
			}
			await Task.Delay(1000);
			Request<User> loggedInUser;
			for (loggedInUser = Users.GetLoggedInUser(); loggedInUser == null; loggedInUser = Users.GetLoggedInUser())
			{
				await Task.Yield();
			}
			loggedInUser.OnComplete(Callback<User>.op_Implicit((Action<Message<User>>)SetOculusUsername));
		}

		private static void SetOculusUsername(Message<User> msg)
		{
			if (((Message)msg).IsError)
			{
				Error("Error while getting OVR usernameBytes:" + ((Object)((Message)msg).error).ToString());
				return;
			}
			username = msg.Data.DisplayName;
			PostcheckUsername();
		}

		private static void PostcheckUsername()
		{
			Log("Detected usernameBytes as " + username);
			if (username.Length > 32)
			{
				username = username.Substring(0, 29) + "...";
				Log("Username is over 32 char, shortened to: " + username);
			}
		}

		private static void PageSelected(Page category)
		{
			if (category == prefEntries.BoneMenuPage)
			{
				CameraFella.MenuOpened();
			}
		}

		private static void MenuClosed()
		{
			Saves.MenuClosed();
			CameraFella.MenuClosed();
		}

		internal static Poolee? GetPooleeUpwards(Transform? t)
		{
			if ((Object)(object)t == (Object)null)
			{
				return null;
			}
			Poolee val = Poolee.Cache.Get(((Component)t.root).gameObject);
			if ((Object)(object)val == (Object)null)
			{
				return GetPooleeUpwardsRecursive(t);
			}
			return val;
		}

		private static Poolee? GetPooleeUpwardsRecursive(Transform t)
		{
			Poolee val = Poolee.Cache.Get(((Component)t).gameObject);
			if (Object.op_Implicit((Object)(object)val))
			{
				return val;
			}
			Transform parent = t.parent;
			if ((Object)(object)parent != (Object)null)
			{
				return GetPooleeUpwardsRecursive(parent);
			}
			return null;
		}

		internal static AIBrain? GetBrainImmediateDownward(Transform t)
		{
			Transform val = t;
			AIBrain result = default(AIBrain);
			if (Instances<AIBrain>.TryGetFromCache(((Component)t).gameObject, ref result))
			{
				return result;
			}
			for (int i = 0; i < val.childCount; i++)
			{
				t = val.GetChild(i);
				if (Instances<AIBrain>.TryGetFromCache(((Component)t).gameObject, ref result))
				{
					return result;
				}
			}
			return null;
		}

		internal static void Log(string str)
		{
			try
			{
				logSemaphore.Wait();
				((MelonBase)instance).LoggerInstance.Msg(str);
			}
			finally
			{
				logSemaphore.Release();
			}
		}

		internal static void Log(object? obj)
		{
			Log(obj?.ToString() ?? "null");
		}

		internal static void Warn(string str)
		{
			try
			{
				logSemaphore.Wait();
				((MelonBase)instance).LoggerInstance.Warning(str);
			}
			finally
			{
				logSemaphore.Release();
			}
		}

		internal static void Warn(object? obj)
		{
			Warn(obj?.ToString() ?? "null");
		}

		internal static void WarnVariable(object? obj, [CallerArgumentExpression("obj")] string paramName = "<none>")
		{
			Warn(paramName + ": " + obj);
		}

		internal static void Error(string str)
		{
			try
			{
				logSemaphore.Wait();
				((MelonBase)instance).LoggerInstance.Error(str);
			}
			finally
			{
				logSemaphore.Release();
			}
		}

		internal static void Error(object? obj)
		{
			Error(obj?.ToString() ?? "null");
		}

		internal static void ErrIfNotNull(object? obj)
		{
			if (obj != null)
			{
				Error(obj);
			}
		}
	}
	[RegisterTypeInIl2Cpp]
	internal class OffsetProviderLink : MonoBehaviour
	{
		private Transform _firePoint;

		private Transform FirePoint
		{
			get
			{
				if ((Object)(object)_firePoint == (Object)null)
				{
					_firePoint = ((Component)this).transform.Find("FirePoint");
				}
				return _firePoint;
			}
		}

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

		private void Start()
		{
			_ = FirePoint;
		}

		public Vector3 AcquirePosition()
		{
			//IL_0006: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_0035: 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_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_0054: Unknown result type (might be due to invalid IL or missing references)
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(FirePoint.position, FirePoint.forward, ref val, 50f))
			{
				return FirePoint.position + FirePoint.forward * 50f;
			}
			return ((RaycastHit)(ref val)).point;
		}

		public void Clicked()
		{
			//IL_0001: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 value = AcquirePosition();
			SceneSaverBL.Log($"Clicked at {value}");
		}
	}
	[Preferences("SceneSaver", true)]
	internal static class Prefs
	{
		[Pref("Always shows where the preview image will be taken from, as opposed to only when SSBL's BoneMenu is open. (By showing an orange smiley face)")]
		internal static bool showPreviewLocation = false;

		[Pref("When saving, a 'polaroid' of the preview image is spawned. To disable this, set this to true.")]
		internal static bool disablePolaroid = false;

		[Pref]
		internal static bool filterByLevel = true;

		[Pref("Freezes objects while other objects are still loading. This may cause saves to load slower than if it was disabled.")]
		internal static bool freezeWhileLoading = true;

		[Pref("Performs extra checks while saving, to make sure data will be able to be loaded properly (has fallback behavior)")]
		internal static bool saveChecks = true;

		[Pref("Loads WELD constraints that are between the current object and a non-saved object")]
		internal static bool loadStaticWelds = false;

		[Pref("If true, will move wire when only Grip+Trigger are held, otherwise will require Grip+Trigger+StickClick")]
		internal static bool dontUseStickClick = false;

		[Pref("The URL base to be used when fetching from the online save repository. (if you replace this, dont include a slash at the end.)")]
		internal static string ssblRepo = "https://ssbl.extraes.xyz";

		[Pref("Disables stats. SSBL uses stats to inform the developer (extraes) of: How many times the mod was used on Q2/PC, how many saves were saved/loaded")]
		internal static bool disableStats = false;

		[Pref("If true, will use the right hand for the dupe line, otherwise will use the left hand")]
		internal static bool rightHandDupeLine = true;

		[Pref("If true, dupes will be allowed to spawn in walls")]
		internal static bool dontAdjustDupePos = false;

		[Pref("If true, tells Fusion to sync spawned objects.")]
		internal static bool fusionSync = true;

		internal static SelectionZone? activeSelection;

		[MemberNotNull("activeSelection")]
		private static void CreateSelectionWire()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0010: 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)
			GameObject val = new GameObject("SceneSaver Selection Wire");
			Utilities.MoveAndFacePlayer(val);
			val.transform.localRotation = Quaternion.identity;
			activeSelection = val.AddComponent<SelectionZone>();
			((Component)activeSelection).gameObject.SetActive(true);
		}

		public static void PopulateAboutMenu(Page category)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			Type[] array = (from t in ((MelonBase)SceneSaverBL.instance).MelonAssembly.Assembly.GetTypes()
				where t.GetInterfaces().Any((Type t) => t == typeof(ISaveFile)) && t != typeof(FailedSaveFile)
				select t).ToArray();
			int[] array2 = new int[array.Length];
			for (int i = 0; i < array.Length; i++)
			{
				int.TryParse(new string((array[i].Namespace ?? "").SkipWhile((char c) => !char.IsDigit(c)).ToArray()), out var result);
				array2[i] = result;
			}
			SceneSaverBL.supportedSaveVers = array2;
			category.CreateFunction("Version 2.0.0 (Release)", Color.white, SaveUtils.NothingAction);
			category.CreateFunction("Created by extraes", Color.white, SaveUtils.NothingAction);
			category.CreateFunction($"Creates V{array2.Max()} saves", Color.white, SaveUtils.NothingAction);
			category.CreateFunction("Reads V" + string.Join(" , V", array2), Color.white, SaveUtils.NothingAction);
			category.CreateFunction("Donate (opens browser)", new Color(0.9f, 0.75f, 0.75f), (Action)delegate
			{
				Application.OpenURL("https://ko-fi.com/extraes");
			});
		}

		[Pref("", 0.75f, 1f, 0.75f)]
		public static void ShowSaves()
		{
			Saves.ShowBoneMenu();
		}

		[Pref("Saving")]
		public static void ToggleSelectionWire()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)activeSelection == (Object)null)
			{
				CreateSelectionWire();
			}
			else if (!((Component)activeSelection).gameObject.active)
			{
				Utilities.MoveAndFacePlayer(((Component)activeSelection).gameObject);
				((Component)activeSelection).transform.rotation = Quaternion.identity;
				((Component)activeSelection).gameObject.SetActive(true);
			}
			else
			{
				((Component)activeSelection).gameObject.SetActive(false);
				CameraFella.MenuClosed();
			}
		}

		[Pref("Saving")]
		public static void SaveSelection()
		{
			if (!((Object)(object)activeSelection == (Object)null) && ((Component)activeSelection).gameObject.active)
			{
				SceneSaverBL.isFullSave = true;
				SceneSaverBL.currentlySaving = true;
				AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow((Func<Task>)Saves.DoSave), (Action<Exception>)SaveFinished);
			}
		}

		[Pref(/*Could not decode attribute arguments.*/)]
		public static void ShowTutorial()
		{
			ControllerTutorial.Show();
		}

		[Pref("Repo")]
		public static void ThereWasABugYay()
		{
		}

		[Pref("About")]
		public static void SceneSaver()
		{
		}

		private static void SaveFinished(Exception? ex)
		{
			SceneSaverBL.currentlySaving = false;
			if (ex == null)
			{
				return;
			}
			SceneSaverBL.Error($"SAVING FAILED! Cleaning saves directory of unfilled saves.\n\t More details: {ex}");
			foreach (string item in Directory.EnumerateFiles(SceneSaverBL.saveDir, "*.ssbl"))
			{
				if (new FileInfo(item).Length <= 5)
				{
					SceneSaverBL.Warn("Deleting : " + item);
					File.Delete(item);
				}
			}
		}
	}
	internal static class RepoConsumer
	{
		private enum InputMethod
		{
			BONEMENU,
			IMGUI,
			CLIPBOARD
		}

		private const string HEXADEC = "0123456789ABCDEF";

		private const string RECENTS_MENU_NAME_FORMAT = "Recents as of {0}m ago";

		private static readonly string DownloadedSavePath = Path.Combine(SceneSaverBL.saveDir, "Downloaded");

		private static Page downloadedPage;

		private static Page repoPage;

		private static SceneSaverRepoInfo repoInfo;

		private static Page workingPage;

		private static Page genericErrorPage;

		private static Page recentsPage;

		private static Page saveMetadataPage;

		private static Page uploadPage;

		private static readonly List<ISaveFile> saves = new List<ISaveFile>();

		public static async Task Init(Page repoCategory)
		{
			Prefs.ssblRepo = Prefs.ssblRepo.TrimEnd('/');
			repoPage = repoCategory;
			workingPage = repoPage.CreatePage("Working...", Color.gray, 0, true);
			genericErrorPage = repoPage.CreatePage("Error!", Color.Lerp(Color.white, Color.red, 0.5f), 0, true);
			recentsPage = repoPage.CreatePage("Recents as of {0}m ago", Color.white, 0, true);
			saveMetadataPage = repoPage.CreatePage("Save metadata placeholder name", Color.white, 0, true);
			uploadPage = repoPage.CreatePage("Upload a save", Color.white, 0, true);
			downloadedPage = repoPage.CreatePage("Downloaded", Color.white, 0, true);
			Utilities.CreateDirectoryRecursive(DownloadedSavePath);
			repoPage.RemoveAll();
			UnityWebRequest repoInfoReq = UnityWebRequest.Get(Prefs.ssblRepo + "/api/repo/info");
			Awaiter val = AsyncUtilities.ToUniTask((AsyncOperation)(object)repoInfoReq.SendWebRequest(), (PlayerLoopTiming)8).GetAwaiter();
			if (!val.IsCompleted)
			{
				await val;
				object obj = default(object);
				val = (Awaiter)obj;
			}
			val.GetResult();
			if (((Il2CppObjectBase)repoInfoReq).WasCollected)
			{
				CreateMainErroredMenu("Web req GC'd");
				return;
			}
			if (((Il2CppObjectBase)repoInfoReq.downloadHandler).WasCollected)
			{
				CreateMainErroredMenu("DL handler GC'd");
				return;
			}
			Result result = repoInfoReq.result;
			switch (result - 2)
			{
			case 0:
				CreateMainErroredMenu("Net err - " + repoInfoReq.error);
				return;
			case 1:
				CreateMainErroredMenu($"HTTP err ({repoInfoReq.responseCode}) - " + repoInfoReq.error);
				return;
			case 2:
				CreateMainErroredMenu($"Data err (from HTTP{repoInfoReq.responseCode}) - " + repoInfoReq.error);
				return;
			}
			try
			{
				repoInfo = JsonSerializer.Deserialize<SceneSaverRepoInfo>(repoInfoReq.downloadHandler.text);
			}
			catch (Exception ex)
			{
				SceneSaverBL.Log("Raw response from webserver: " + repoInfoReq.downloadHandler.text);
				SceneSaverBL.Error("Exception while deserializing SSBL Repo info: " + ex);
				CreateMainErroredMenu("Parse fail: " + ex.Message);
				return;
			}
			PopulateMenu();
			foreach (string item2 in Directory.EnumerateFiles(DownloadedSavePath, "*.ssbl"))
			{
				ISaveFile item = await Saves.CreateSave(item2);
				saves.Add(item);
			}
		}

		private static void PopulateMenu()
		{
			//IL_004d: 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_009f: 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_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: 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)
			int num = Prefs.ssblRepo.IndexOf("://");
			string text = ((num == -1 || num >= Prefs.ssblRepo.Length - 3) ? Prefs.ssblRepo : Prefs.ssblRepo.Split(new string[1] { "://" }, StringSplitOptions.None)[1]);
			Page obj = repoPage.CreatePage(text, Color.white, 0, true);
			obj.CreateFunction("Running V" + repoInfo.version, Color.white, SaveUtils.NothingAction);
			obj.CreateFunction("Timezone " + repoInfo.timeZone, Color.white, SaveUtils.NothingAction);
			obj.CreateFunction(repoInfo.totalDownloads + " total DLs", Color.white, SaveUtils.NothingAction);
			obj.CreateFunction(repoInfo.totalDownloadsWeek + " DLs this week", Color.white, SaveUtils.NothingAction);
			repoPage.CreateFunction("Recents", Color.white, (Action)delegate
			{
				AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow<int>((Func<int, Task>)ShowRecents, 0), (Action<Exception>)SceneSaverBL.ErrIfNotNull);
			});
			repoPage.CreateFunction("Upload", Color.white, (Action)delegate
			{
				AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow((Func<Task>)ShowUploadMenu), (Action<Exception>)SceneSaverBL.ErrIfNotNull);
			});
			Page val = repoPage.CreatePage("DL from tag", Color.Lerp(Color.green, Color.white, 0.5f), 0, true);
			val.CreateFunction("Input from BoneMenu", Color.white, (Action)delegate
			{
				AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow<InputMethod>((Func<InputMethod, Task>)DownloadFromTag, InputMethod.BONEMENU), (Action<Exception>)SceneSaverBL.ErrIfNotNull);
			});
			val.CreateFunction("Input from Clipboard", Color.white, (Action)delegate
			{
				AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow<InputMethod>((Func<InputMethod, Task>)DownloadFromTag, InputMethod.CLIPBOARD), (Action<Exception>)SceneSaverBL.ErrIfNotNull);
			});
			if (!Utilities.IsPlatformQuest())
			{
				val.CreateFunction("Input from Spectator Screen", Color.white, (Action)delegate
				{
					AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow<InputMethod>((Func<InputMethod, Task>)DownloadFromTag, InputMethod.IMGUI), (Action<Exception>)SceneSaverBL.ErrIfNotNull);
				});
			}
			repoPage.CreateFunction("Downloaded", Color.white, (Action)ShowDownloaded);
		}

		private static void ShowDownloaded()
		{
			downloadedPage.RemoveAll();
			foreach (ISaveFile safe in saves)
			{
				safe.PopulateBoneMenu(downloadedPage);
			}
			Menu.OpenPage(downloadedPage);
		}

		private static async Task ShowRecents(int pageIdx)
		{
			Menu.OpenPage(workingPage);
			DownloadHandler val = await SendRequestForOrShowError(Prefs.ssblRepo + $"/api/repo/recent?skip={pageIdx * 10}&take={10}");
			if (val == null)
			{
				return;
			}
			SceneSaverEntryCollection sceneSaverEntryCollection;
			try
			{
				sceneSaverEntryCollection = JsonConvert.DeserializeObject<SceneSaverEntryCollection>(val.text);
			}
			catch (Exception ex)
			{
				SceneSaverBL.Log("Raw response from webserver: " + val.text);
				SceneSaverBL.Error("Exception while deserializing recent save files: " + ex);
				SetAndSelectError("Parse fail: " + ex.Message);
				return;
			}
			recentsPage.Name = $"Recents as of {Math.Round(sceneSaverEntryCollection.TimeSinceLastUpdate.TotalMinutes)}m ago";
			recentsPage.RemoveAll();
			recentsPage.CreateFunction($"Page {pageIdx + 1}", Color.white, SaveUtils.NothingAction);
			SceneSaverSaveEntry[] array = sceneSaverEntryCollection.Saves;
			foreach (SceneSaverSaveEntry saveMeta in array)
			{
				recentsPage.CreateFunction(saveMeta.name, Color.white, (Action)delegate
				{
					SelectSaveMetadata(saveMeta);
				});
			}
			if (pageIdx > 0)
			{
				recentsPage.CreateFunction("< Previous page", Color.white, (Action)delegate
				{
					AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow<int>((Func<int, Task>)ShowRecents, pageIdx - 1), (Action<Exception>)SceneSaverBL.ErrIfNotNull);
				});
			}
			if (sceneSaverEntryCollection.Saves.Count() == 10)
			{
				recentsPage.CreateFunction("Next page >", Color.white, (Action)delegate
				{
					AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow<int>((Func<int, Task>)ShowRecents, pageIdx + 1), (Action<Exception>)SceneSaverBL.ErrIfNotNull);
				});
			}
			else if (sceneSaverEntryCollection.Saves.Count() == 0)
			{
				recentsPage.CreateFunction("No more pages", Color.white, SaveUtils.NothingAction);
			}
			Menu.OpenPage(recentsPage);
		}

		private static void SelectSaveMetadata(SceneSaverSaveEntry saveMeta)
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: 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_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			SceneSaverSaveEntry saveMeta2 = saveMeta;
			if (saveMeta2.name == "error" && string.IsNullOrEmpty(saveMeta2.owner))
			{
				SetAndSelectError("No such save found");
				return;
			}
			TimeSpan? timeSpan = saveMeta2.TimeUntilExpired();
			saveMetadataPage.RemoveAll();
			saveMetadataPage.Name = saveMeta2.name;
			if (!Utilities.IsPlatformQuest())
			{
				saveMetadataPage.CreateFunction("Copy tag to clipboard", Color.white, (Action)delegate
				{
					GUIUtility.systemCopyBuffer = saveMeta2.tag;
				});
			}
			saveMetadataPage.CreateFunction("Tag: " + saveMeta2.tag, Color.white, SaveUtils.NothingAction);
			saveMetadataPage.CreateFunction("Hash: " + saveMeta2.hash, Color.gray, SaveUtils.NothingAction);
			saveMetadataPage.CreateFunction("Save file version: " + saveMeta2.version, Color.green, SaveUtils.NothingAction);
			saveMetadataPage.CreateFunction("Weekly downloads: " + saveMeta2.downloadCountWeek, Color.gray, SaveUtils.NothingAction);
			saveMetadataPage.CreateFunction("Lifetime downloads: " + saveMeta2.downloadCount, Color.gray, SaveUtils.NothingAction);
			saveMetadataPage.CreateFunction("Uploaded by ID: " + saveMeta2.owner, Color.gray, SaveUtils.NothingAction);
			if (timeSpan.HasValue)
			{
				saveMetadataPage.CreateFunction($"Expires in {(int)timeSpan.Value.TotalDays}d {timeSpan.Value.Hours}h {timeSpan.Value.Minutes}m", Color.green, SaveUtils.NothingAction);
			}
			else
			{
				saveMetadataPage.CreateFunction("Doesn't expire", Color.green, SaveUtils.NothingAction);
			}
			if (SceneSaverBL.supportedSaveVers.Contains(saveMeta2.version))
			{
				saveMetadataPage.CreateFunction("Download", Color.green, (Action)delegate
				{
					AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow<SceneSaverSaveEntry>((Func<SceneSaverSaveEntry, Task>)DownloadSave, saveMeta2), (Action<Exception>)SceneSaverBL.ErrIfNotNull);
				});
			}
			else
			{
				saveMetadataPage.CreateFunction($"Can't read V{saveMeta2.version} saves", Color.red, SaveUtils.NothingAction);
			}
			Menu.OpenPage(saveMetadataPage);
		}

		private static async Task DownloadSave(SceneSaverSaveEntry metadata)
		{
			Menu.OpenPage(workingPage);
			DownloadHandler val = await SendRequestForOrShowError(Prefs.ssblRepo + "/api/saves/download?tag=" + metadata.tag);
			if (val != null)
			{
				File.WriteAllBytes(Path.Combine(DownloadedSavePath, "DL - " + metadata.name), Il2CppArrayBase<byte>.op_Implicit((Il2CppArrayBase<byte>)(object)val.data));
				ShowDownloaded();
			}
		}

		private static void CreateMainErroredMenu(string text, string otherText = "")
		{
			//IL_000a: 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_002f: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			repoPage.CreateFunction("Repo client error", Color.red, SaveUtils.NothingAction);
			repoPage.CreateFunction(text, Color.Lerp(Color.white, Color.red, 0.5f), SaveUtils.NothingAction);
			if (!string.IsNullOrEmpty(otherText))
			{
				repoPage.CreateFunction(otherText, Color.Lerp(Color.white, Color.red, 0.25f), SaveUtils.NothingAction);
			}
			repoPage.CreateFunction("Retry", Color.Lerp(Color.white, Color.green, 0.25f), (Action)delegate
			{
				AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow<Page>((Func<Page, Task>)Init, repoPage), (Action<Exception>)SceneSaverBL.ErrIfNotNull);
			});
		}

		private static async Task DownloadFromTag(InputMethod inputMethod)
		{
			string text;
			switch (inputMethod)
			{
			default:
				return;
			case InputMethod.BONEMENU:
				text = await BonemenuStringInput.GetStringInput("ABCDEF", "*", string.Empty);
				break;
			case InputMethod.IMGUI:
				Menu.OpenPage(workingPage);
				text = await IMGUIInputField.GetStringAsync(60, "", "0123456789ABCDEF");
				break;
			case InputMethod.CLIPBOARD:
				text = GUIUtility.systemCopyBuffer;
				break;
			}
			string text2 = text;
			for (int i = 0; i < text2.Length; i++)
			{
				char c = text2[i];
				if (!"0123456789ABCDEF".Contains(char.ToUpper(c)))
				{
					SetAndSelectError("Tags don't contain: " + c);
					return;
				}
			}
			Menu.OpenPage(workingPage);
			DownloadHandler val = await SendRequestForOrShowError(Prefs.ssblRepo + "/api/saves/info?tag=" + text);
			if (val != null)
			{
				SceneSaverSaveEntry saveMeta;
				try
				{
					saveMeta = JsonSerializer.Deserialize<SceneSaverSaveEntry>(val.text);
				}
				catch (Exception ex)
				{
					SceneSaverBL.Log("Raw response from webserver: " + val.text);
					SceneSaverBL.Error("Exception while deserializing recent save files: " + ex);
					SetAndSelectError("Parse fail: " + ex.Message);
					return;
				}
				SelectSaveMetadata(saveMeta);
			}
		}

		private static async Task ShowUploadMenu()
		{
			Menu.OpenPage(workingPage);
			uploadPage.RemoveAll();
			await AsyncUtilities.ForEachTimeSlice<string>(Directory.EnumerateFiles(SceneSaverBL.saveDir, "*.ssbl"), (Action<string>)delegate(string savePath)
			{
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: 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)
				if (!savePath.StartsWith(DownloadedSavePath))
				{
					Page obj = uploadPage.CreatePage(Path.GetFileNameWithoutExtension(savePath), Color.white, 0, true);
					obj.CreateFunction("Delete", Color.red, (Action)delegate
					{
						File.Delete(savePath);
					});
					Action performUpload = delegate
					{
						AsyncExtensions.RunOnFinish<Exception>(AsyncUtilities.WrapNoThrow<string>((Func<string, Task>)UploadSave, savePath), (Action<Exception>)SceneSaverBL.ErrIfNotNull);
					};
					obj.CreateFunction("Upload", Color.white, (Action)delegate
					{
						Menu.DisplayDialog("Confirmation", "Are you sure you want to upload \"" + Path.GetFileName(savePath) + "\"?", (Texture2D)null, performUpload, (Action)null);
					});
				}
			}, 1f, (PlayerLoopTiming)8);
			Menu.OpenPage(uploadPage);
		}

		public static async Task UploadSave(string savePath)
		{
			if (Utilities.IsPlatformQuest())
			{
				SetAndSelectError("Uploading not possible on Quest. Blame SLZ for IL2CPP!");
				return;
			}
			Menu.OpenPage(workingPage);
			string fileName = Path.GetFileName(savePath);
			byte[] content = File.ReadAllBytes(savePath);
			string responseTxt = "";
			Exception ex2;
			try
			{
				HttpClient httpClient = new HttpClient();
				HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Put, Prefs.ssblRepo + "/api/saves/upload?filename=" + fileName);
				httpRequestMessage.Content = new ByteArrayContent(content);
				Task<HttpResponseMessage> uploadTask = httpClient.SendAsync(httpRequestMessage);
				while (!uploadTask.IsCompleted)
				{
					await UniTask.Yield();
				}
				uploadTask.Result.EnsureSuccessStatusCode();
				Task<string> stringTask = uploadTask.Result.Content.ReadAsStringAsync();
				while (!stringTask.IsCompleted)
				{
					await UniTask.Yield();
				}
				responseTxt = stringTask.Result;
				SceneSaverSaveEntry? sceneSaverSaveEntry = JsonSerializer.Deserialize<SceneSaverSaveEntry>(responseTxt);
				GUIUtility.systemCopyBuffer = sceneSaverSaveEntry.tag;
				SelectSaveMetadata(sceneSaverSaveEntry);
				return;
			}
			catch (AggregateException ex)
			{
				ex2 = ((ex.InnerExceptions.Count != 1) ? ex : ex.InnerExceptions[0]);
			}
			catch (Exception ex3)
			{
				ex2 = ex3;
			}
			if (ex2 is WebException ex4)
			{
				SceneSaverBL.Error("Exception uploading file to repo: " + ex4);
				SetAndSelectError("Upload fail: " + ex4.Message);
				return;
			}
			if (ex2 is DecoderFallbackException ex5)
			{
				SceneSaverBL.Error("Exception while decoding binary stream into text: " + ex5);
				SetAndSelectError("Decode fail: " + ex5.Message);
				return;
			}
			JsonReaderException val = (JsonReaderException)(object)((ex2 is JsonReaderException) ? ex2 : null);
			if (val != null)
			{
				SceneSaverBL.Log("Raw response from webserver: " + responseTxt);
				SceneSaverBL.Error("Exception while deserializing uploaded save metadata: " + (object)val);
				SetAndSelectError("Parse fail: " + ((Exception)(object)val).Message);
			}
			else
			{
				SceneSaverBL.Error("Exception while uploading save file: " + ex2);
				SetAndSelectError("Generic fail: " + ex2.Message);
			}
		}

		private static async Task<DownloadHandler?> SendRequestForOrShowError(string url, string method = "GET")
		{
			UnityWebRequest webReq = UnityWebRequest.Get(url);
			if (method != "GET")
			{
				webReq.method = method;
			}
			Awaiter val = AsyncUtilities.ToUniTask((AsyncOperation)(object)webReq.SendWebRequest(), (PlayerLoopTiming)8).GetAwaiter();
			if (!val.IsCompleted)
			{
				await val;
				object obj = default(object);
				val = (Awaiter)obj;
			}
			val.GetResult();
			if (((Il2CppObjectBase)webReq).WasCollected)
			{
				SetAndSelectError("Web req GC'd");
				return null;
			}
			if (((Il2CppObjectBase)webReq.downloadHandler).WasCollected)
			{
				SetAndSelectError("DL handler GC'd");
				return null;
			}
			Result result = webReq.result;
			switch (result - 2)
			{
			case 0:
				SetAndSelectError("Net err - " + webReq.error);
				return null;
			case 1:
				SetAndSelectError($"HTTP err ({webReq.responseCode}) - " + webReq.error);
				return null;
			case 2:
				SetAndSelectError($"Data err (from HTTP{webReq.responseCode}) - " + webReq.error);
				return null;
			default:
				return webReq.downloadHandler;
			}
		}

		private static void SetAndSelectError(string text)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			((Element)(((object)genericErrorPage.Elements.FirstOrDefault()) ?? ((object)genericErrorPage.CreateFunction("", Color.white, SaveUtils.NothingAction)))).ElementName = text;
			Menu.OpenPage(genericErrorPage);
		}
	}
	internal static class SaveChecks
	{
		private const string POOLED_RIG_MANAGER = "SLZ.BONELAB.Core.DefaultPlayerRig";

		private const string CONSTRAINT_NAME_START = "jPt";

		private const string SAVING_BOUNDS_NAME = "SavingBounds";

		private static readonly Dictionary<string, bool> HierarchyMatchCache = new Dictionary<string, bool>();

		private static int mainThreadId;

		public static bool CanBeSerializedDeserialized(string barcode)
		{
			return barcode != "SLZ.BONELAB.Core.DefaultPlayerRig";
		}

		public static bool IsTransformIgnored(Transform transformName)
		{
			string name = ((Object)transformName).name;
			if (!name.StartsWith("jPt"))
			{
				return name.StartsWith("SavingBounds");
			}
			return true;
		}

		public static bool IsHierarchyConsistent(Poolee poolee)
		{
			//IL_0039: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			string iD = ((Scannable)poolee.SpawnableCrate).Barcode.ID;
			if (HierarchyMatchCache.TryGetValue(iD, out var value))
			{
				return value;
			}
			Hash128 val = HierarchyHash(((MarrowAssetT<GameObject>)(object)((GameObjectCrate)poolee.SpawnableCrate).MainGameObject).Asset.transform);
			Hash128 val2 = HierarchyHash(((Component)poolee).transform);
			bool flag = ((Hash128)(ref val2)).Equals(val);
			HierarchyMatchCache[iD] = flag;
			return flag;
		}

		private static Hash128 HierarchyHash(Transform t, Hash128 continueHash = default(Hash128))
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			for (int i = 0; i < t.childCount; i++)
			{
				Transform child = t.GetChild(i);
				if (IsTransformIgnored(child))
				{
					num++;
				}
				else
				{
					continueHash = HierarchyHash(child, continueHash);
				}
			}
			((Hash128)(ref continueHash)).Append(t.childCount - num);
			return continueHash;
		}

		internal static void ThrowIfDefault(int checkFor, [CallerArgumentExpression("checkFor")] string name = null)
		{
			if (checkFor == 0)
			{
				LogThrow(new UninitializedSerializedDataException("The int variable " + name + " must be assigned a value instead of its default value."));
			}
		}

		internal static void ThrowIfDefault(Vector3 checkFor, [CallerArgumentExpression("checkFor")] string name = null)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (checkFor == default(Vector3))
			{
				LogThrow(new UninitializedSerializedDataException("The Vector3 variable " + name + " must be assigned a value instead of its default value."));
			}
		}

		internal static void ThrowIfDefault<T>(T checkFor, [CallerArgumentExpression("checkFor")] string name = null) where T : IEquatable<T>
		{
			ref T reference = ref checkFor;
			T val = default(T);
			if (val == null)
			{
				val = reference;
				reference = ref val;
			}
			if (reference.Equals(default(T)))
			{
				LogThrow(new UninitializedSerializedDataException("The equatable variable " + name + " must be assigned a value instead of its default value."));
			}
		}

		internal static void ThrowIfDefault(object obj, [CallerArgumentExpression("obj")] string name = null)
		{
			if (obj == null)
			{
				LogThrow(new UninitializedSerializedDataException("The reference variable " + name + " must be assigned a value instead of null."));
			}
		}

		internal static void ThrowIfInvalid(Vector3 vec, [CallerArgumentExpression("vec")] string name = null)
		{
			//IL_0000: 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_0028: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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)
			bool num = float.IsNaN(vec.x) || float.IsNaN(vec.y) || float.IsNaN(vec.z);
			bool flag = float.IsInfinity(vec.x) || float.IsInfinity(vec.y) || float.IsInfinity(vec.z);
			if (num || flag)
			{
				LogThrow(new InvalidDataException("Invalid " + name + " Vector3: " + SaveUtils.ToStr(vec)));
			}
		}

		internal static void EstablishMainThread()
		{
			if (mainThreadId != 0)
			{
				SceneSaverBL.Warn($"Main thread ID is already set to {mainThreadId}! Now setting to {Thread.CurrentThread.ManagedThreadId}");
			}
			mainThreadId = Thread.CurrentThread.ManagedThreadId;
		}

		internal static void ThrowIfOffMainThread([CallerMemberName] string caller = null, [CallerLineNumber] int lineNum = 0)
		{
			if (Thread.CurrentThread.ManagedThreadId != mainThreadId)
			{
				LogThrow(new ThreadStateException($"Execution was knocked off the main thread in {caller}! See line {lineNum}."));
			}
		}

		internal static void ThrowIfLongerThanByte(string strToCheck, Encoding encoder = null)
		{
			if (encoder == null)
			{
				encoder = Encoding.UTF8;
			}
			int byteCount = encoder.GetByteCount(strToCheck);
			if (byteCount > 255)
			{
				LogThrow(new StringTooLongException($"String is too long to be serialized ({byteCount} is greater than max 255 characters). Report this error to the developer (or maybe shorten barcode)! String: " + strToCheck));
			}
		}

		internal static void ThrowIfLongerThanByte(Array arr, string arrayPurpose)
		{
			int length = arr.Length;
			if (length > 255)
			{
				LogThrow(new ArrayTooLongException($"Array is too long to be serialized ({length} is greater than max length 255). Report this error to the developer! The array used for: " + arrayPurpose));
			}
		}

		private static void LogThrow(Exception ex)
		{
			SceneSaverBL.Error(ex);
			throw ex;
		}
	}
	internal static class Saves
	{
		private static Page savesCategory;

		private const string DATE_FORMAT = "s";

		private static FileSystemWatcher saveWatcher;

		private static readonly char[] invalidChars = Path.GetInvalidFileNameChars();

		private static readonly List<ISaveFile> saves = new List<ISaveFile>();

		private static float lastSaveTime;

		private static Page dupeMenu;

		private static Vector3 extraDupeOffset;

		private static Bounds displayBounds;

		private static Bounds calcBounds;

		private static Transform boundsVis;

		private static PositionTween currPosTween;

		private static bool boxKeepAlive;

		private static Vector3 GetTotalOffset()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_003e: 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_002d: 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)
			Vector3 center = ((Bounds)(ref displayBounds)).center;
			center.y = ((Bounds)(ref displayBounds)).min.y;
			return (SceneSaverBL.desiredDupePos.HasValue ? (SceneSaverBL.desiredDupePos.Value - center) : Vector3.zero) + extraDupeOffset;
		}

		internal static async Task Init(Page parentCategory)
		{
			savesCategory = parentCategory.CreatePage("SceneSaver Saves", Color.white, 0, true);
			dupeMenu = savesCategory.CreatePage("Dupe spawning", Color.green, 0, true);
			Element val = parentCategory.Elements.First((Element e) => e.ElementName == savesCategory.Name);
			parentCategory.Remove(val);
			string directoryName = Path.GetDirectoryName(SceneSaverBL.saveDir);
			Path.GetDirectoryName(SceneSaverBL.dupesDir);
			if (!Directory.Exists(directoryName))
			{
				Directory.CreateDirectory(directoryName);
			}
			if (!Directory.Exists(SceneSaverBL.saveDir))
			{
				Directory.CreateDirectory(SceneSaverBL.saveDir);
			}
			saveWatcher = new FileSystemWatcher(SceneSaverBL.saveDir, "*.ssbl");
			saveWatcher.Changed += CheckChangedSave;
			saveWatcher.Created += CheckChangedSave;
			saveWatcher.Deleted += CheckChangedSave;
			saveWatcher.EnableRaisingEvents = true;
			await InitSaves();
		}

		private static async Task InitSa