Decompiled source of SimplePoses v1.0.0

Mods/SimplePoses.dll

Decompiled a day ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using BoneLib;
using BoneLib.BoneMenu;
using BoneLib.BoneMenu.UI;
using BoneLib.Notifications;
using Il2CppCysharp.Threading.Tasks;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Data;
using Il2CppSLZ.Marrow.Pool;
using Il2CppSLZ.Marrow.Warehouse;
using Il2CppSystem;
using LabFusion.Entities;
using LabFusion.Marrow.Extenders;
using LabFusion.Network;
using LabFusion.Player;
using LabFusion.RPC;
using LabFusion.SDK.Metadata;
using LabFusion.Scene;
using LabFusion.Utilities;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using PhasePosePlayback;
using PhasesPoses;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(PosesTestMod), "SimplePoses", "0.1.8", "Phase", null)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("SimplePoses")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SimplePoses")]
[assembly: AssemblyTitle("SimplePoses")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PhasesPoses
{
	public sealed class TransformData
	{
		public float[] Position { get; set; } = new float[3];

		public float[] Rotation { get; set; } = new float[4] { 0f, 0f, 0f, 1f };

		public float[] Scale { get; set; } = new float[3] { 1f, 1f, 1f };

		public void Validate()
		{
			Check(Position, 3);
			Check(Rotation, 4);
			Check(Scale, 3);
			double num = Rotation.Sum((float v) => (double)v * (double)v);
			if (num < 0.9 || num > 1.1 || Scale.Any((float v) => v <= 0f))
			{
				throw new InvalidDataException("Invalid rotation or scale.");
			}
		}

		private static void Check(float[] a, int length)
		{
			if (a == null || a.Length != length || a.Any((float v) => !float.IsFinite(v)))
			{
				throw new InvalidDataException("Invalid transform numbers.");
			}
		}
	}
	public sealed class PoseFile
	{
		public int Version { get; set; } = 1;

		public string Id { get; set; } = Guid.NewGuid().ToString("N");

		public string Name { get; set; } = "New pose";

		public string SeatBarcode { get; set; } = "Doctor.BodyMallAndMore.Spawnable.PoseableSeat";

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

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

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

		public int RotationSnap { get; set; } = 15;

		public bool Frozen { get; set; } = true;

		public bool Visible { get; set; } = true;

		public float? FloorHeight { get; set; }

		public int FloorHeightMeasurementVersion { get; set; }

		public TransformData LastWorldSeat { get; set; } = new TransformData();

		public TransformData SeatAnchorLocal { get; set; } = new TransformData();

		public TransformData LeftFootLocal { get; set; } = new TransformData
		{
			Position = new float[3] { -0.1433f, 0.047f, 0.566f }
		};

		public TransformData RightFootLocal { get; set; } = new TransformData
		{
			Position = new float[3] { 0.1432f, 0.047f, 0.566f }
		};

		public TransformData LeftTargetLocal { get; set; } = new TransformData
		{
			Position = new float[3] { 0f, 0f, 0.1083f }
		};

		public TransformData RightTargetLocal { get; set; } = new TransformData
		{
			Position = new float[3] { 0f, 0f, 0.1083f }
		};

		public float[] SpineLimits { get; set; } = new float[4] { 60f, 180f, 60f, 40f };

		public float[] MinimumSeatBounds { get; set; } = new float[3] { 0.1f, 0.05f, 0.1f };

		public float[] MaximumSeatBounds { get; set; } = new float[3] { 0.25f, 0.1f, 0.2f };

		public void Validate()
		{
			if (Version != 1 || !Guid.TryParseExact(Id, "N", out var _) || string.IsNullOrWhiteSpace(Name) || Name.Length > 80)
			{
				throw new InvalidDataException("Unsupported pose format or invalid name/ID.");
			}
			if (SeatBarcode != "Doctor.BodyMallAndMore.Spawnable.PoseableSeat")
			{
				throw new InvalidDataException("Unsupported seat crate.");
			}
			TransformData[] array = new TransformData[6] { LastWorldSeat, SeatAnchorLocal, LeftFootLocal, RightFootLocal, LeftTargetLocal, RightTargetLocal };
			int i;
			for (i = 0; i < array.Length; i++)
			{
				(array[i] ?? throw new InvalidDataException("Missing transform.")).Validate();
			}
			if (!new int[5] { 5, 15, 30, 45, 90 }.Contains(RotationSnap))
			{
				throw new InvalidDataException("Invalid snap interval.");
			}
			if (FloorHeight.HasValue && !float.IsFinite(FloorHeight.Value))
			{
				throw new InvalidDataException("Invalid saved floor height.");
			}
			i = FloorHeightMeasurementVersion;
			if ((i < 0 || i > 1) ? true : false)
			{
				throw new InvalidDataException("Unsupported floor height measurement version.");
			}
			CheckLimits(SpineLimits, 4);
			CheckLimits(MinimumSeatBounds, 3);
			CheckLimits(MaximumSeatBounds, 3);
		}

		private static void CheckLimits(float[] values, int count)
		{
			if (values == null || values.Length != count || values.Any((float v) => !float.IsFinite(v) || v < 0f))
			{
				throw new InvalidDataException("Invalid seat limits.");
			}
		}
	}
	public sealed class PoseStore
	{
		public static readonly JsonSerializerOptions Json = new JsonSerializerOptions
		{
			WriteIndented = true
		};

		public string DirectoryPath { get; }

		public PoseStore(string directory)
		{
			DirectoryPath = directory;
			Directory.CreateDirectory(directory);
		}

		private string PathFor(string id)
		{
			if (!Guid.TryParseExact(id, "N", out var _))
			{
				throw new InvalidDataException("Invalid pose ID.");
			}
			return Path.Combine(DirectoryPath, id + ".json");
		}

		public string Save(PoseFile pose)
		{
			pose.Validate();
			pose.SavedUtc = DateTime.UtcNow.ToString("O");
			string text = PathFor(pose.Id);
			string text2 = text + ".tmp";
			File.WriteAllText(text2, JsonSerializer.Serialize(pose, Json));
			File.Move(text2, text, overwrite: true);
			return text;
		}

		private static string CheckedName(string name)
		{
			name = name?.Trim();
			if (string.IsNullOrEmpty(name) || name.Length > 80 || name.Any(char.IsControl))
			{
				throw new InvalidDataException("Enter a pose name between 1 and 80 characters.");
			}
			return name;
		}

		private List<PoseFile> Named(string name)
		{
			return (from p in List(null)
				where string.Equals(p.Name.Trim(), name, StringComparison.OrdinalIgnoreCase)
				select p).ToList();
		}

		public string SaveNamed(PoseFile draft)
		{
			draft.Validate();
			string text = CheckedName(draft.Name);
			List<PoseFile> list = Named(text);
			if (list.Count > 1)
			{
				throw new InvalidDataException("Multiple saved poses have that name. Rename duplicates in Saved poses first.");
			}
			PoseFile poseFile = Copy(draft);
			poseFile.Id = ((list.Count == 1) ? list[0].Id : Guid.NewGuid().ToString("N"));
			poseFile.Name = ((list.Count == 1) ? list[0].Name : text);
			string result = Save(poseFile);
			draft.Id = poseFile.Id;
			draft.Name = poseFile.Name;
			draft.SavedUtc = poseFile.SavedUtc;
			return result;
		}

		public PoseFile Clone(string id, string name)
		{
			name = CheckedName(name);
			if (Named(name).Count != 0)
			{
				throw new InvalidDataException("Choose a new name for the clone; that name is already saved.");
			}
			PoseFile poseFile = Copy(Load(id));
			poseFile.Id = Guid.NewGuid().ToString("N");
			poseFile.Name = name;
			poseFile.SavedUtc = "";
			Save(poseFile);
			return poseFile;
		}

		public void Rename(string id, string name)
		{
			name = CheckedName(name);
			if (Named(name).Any((PoseFile p) => p.Id != id))
			{
				throw new InvalidDataException("Another pose already has that name. Choose a different name.");
			}
			PoseFile poseFile = Load(id);
			poseFile.Name = name;
			Save(poseFile);
		}

		public PoseFile Load(string id)
		{
			FileInfo fileInfo = new FileInfo(PathFor(id));
			if (fileInfo.Length > 256000)
			{
				throw new InvalidDataException("Pose file is too large.");
			}
			PoseFile poseFile = JsonSerializer.Deserialize<PoseFile>(File.ReadAllText(fileInfo.FullName));
			if (poseFile == null || poseFile.Id != id)
			{
				throw new InvalidDataException("Pose ID does not match its filename.");
			}
			poseFile.Validate();
			return poseFile;
		}

		public List<PoseFile> List(Action<string> warning)
		{
			List<PoseFile> list = new List<PoseFile>();
			foreach (string item in Directory.EnumerateFiles(DirectoryPath, "*.json"))
			{
				try
				{
					list.Add(Load(Path.GetFileNameWithoutExtension(item)));
				}
				catch (Exception ex)
				{
					warning?.Invoke(Path.GetFileName(item) + ": " + ex.Message);
				}
			}
			return list.OrderBy<PoseFile, string>((PoseFile p) => p.Name, StringComparer.OrdinalIgnoreCase).ToList();
		}

		public void Delete(string id)
		{
			File.Delete(PathFor(id));
		}

		public static PoseFile Copy(PoseFile pose)
		{
			return JsonSerializer.Deserialize<PoseFile>(JsonSerializer.Serialize(pose, Json));
		}

		public static bool CanResumeHere(PoseFile p, string map)
		{
			if (!string.IsNullOrWhiteSpace(map))
			{
				return map == p.MapBarcode;
			}
			return false;
		}
	}
	public enum EditorStage
	{
		Idle,
		Loading,
		Place,
		Adjust,
		Spawning,
		Feet,
		RemovingSeat
	}
	public enum PoseEditTarget
	{
		NativeGrips,
		Seat,
		LeftFoot,
		RightFoot
	}
	public static class PoseMath
	{
		public static float PlacementAltitude(float surfaceY, float? floorHeight, float newPoseOffset)
		{
			return surfaceY + (floorHeight ?? newPoseOffset);
		}

		public static void RaySegmentParameters(double dot, double axisOffset, double rayOffset, double length, out double segment, out double ray)
		{
			if (!AxisParameter(dot, axisOffset, rayOffset, out segment))
			{
				segment = axisOffset;
			}
			segment = Math.Clamp(segment, 0.0, length);
			ray = segment * dot - rayOffset;
			if (ray < 0.0)
			{
				ray = 0.0;
				segment = Math.Clamp(axisOffset, 0.0, length);
			}
		}

		public static bool ConfirmPressed(bool blocked, bool held, ref bool armed)
		{
			if (blocked)
			{
				armed = false;
				return false;
			}
			if (!held)
			{
				armed = true;
				return false;
			}
			if (!armed)
			{
				return false;
			}
			armed = false;
			return true;
		}

		public static double Snap(double degrees, int step)
		{
			return Math.Round(degrees / (double)step, MidpointRounding.AwayFromZero) * (double)step;
		}

		public static double Unwrap(double previous, double current)
		{
			double num = (current - previous) % 360.0;
			if (num > 180.0)
			{
				num -= 360.0;
			}
			if (num < -180.0)
			{
				num += 360.0;
			}
			return num;
		}

		public static bool AxisParameter(double dot, double axisOffset, double rayOffset, out double parameter)
		{
			double num = 1.0 - dot * dot;
			parameter = 0.0;
			if (num < 0.0025)
			{
				return false;
			}
			parameter = (axisOffset - dot * rayOffset) / num;
			return double.IsFinite(parameter);
		}

		public static EditorStage Previous(EditorStage stage)
		{
			return stage switch
			{
				EditorStage.Feet => EditorStage.Adjust, 
				EditorStage.Adjust => EditorStage.Place, 
				_ => stage, 
			};
		}
	}
}
namespace PhasePosePlayback
{
	public sealed class PoseEntry
	{
		public string Name { get; set; }

		public string Key { get; set; }

		public string Label { get; set; }

		public string Category { get; set; }

		public bool LongLegs { get; set; }

		public string Barcode { get; set; }

		public float Height { get; set; }

		public float[] Tilt { get; set; }

		public PoseFile Pose { get; set; }
	}
	public sealed class PoseCatalog
	{
		public IReadOnlyList<PoseEntry> Entries { get; }

		public IEnumerable<PoseEntry> MenuEntries => Entries.Where((PoseEntry p) => !p.LongLegs);

		public PoseCatalog(PoseEntry[] entries)
		{
			if (entries == null || entries.Length == 0)
			{
				throw new InvalidDataException("Expected at least one authored pose crate.");
			}
			HashSet<(string, bool)> hashSet = new HashSet<(string, bool)>();
			HashSet<string> hashSet2 = new HashSet<string>();
			int num = 0;
			while (num < entries.Length)
			{
				PoseEntry poseEntry = entries[num];
				if (poseEntry != null && !string.IsNullOrWhiteSpace(poseEntry.Key) && !string.IsNullOrWhiteSpace(poseEntry.Label) && !(poseEntry.Barcode != "Phaseyy.Phasesposes.Spawnable." + poseEntry.Name) && hashSet2.Add(poseEntry.Barcode) && hashSet.Add((poseEntry.Key, poseEntry.LongLegs)) && float.IsFinite(poseEntry.Height))
				{
					float[] tilt = poseEntry.Tilt;
					if (tilt != null && tilt.Length == 4 && !poseEntry.Tilt.Any((float v) => !float.IsFinite(v)) && !(Math.Abs(poseEntry.Tilt.Sum((float x) => (double)x * (double)x) - 1.0) > 0.001) && new string[4] { "Sit/Floor", "Sit/Ledge", "Lay", "Other" }.Contains(poseEntry.Category))
					{
						poseEntry.Pose?.Validate();
						if (poseEntry.Pose == null)
						{
							throw new InvalidDataException("Missing authored pose.");
						}
						num++;
						continue;
					}
				}
				throw new InvalidDataException("Invalid pose catalog entry.");
			}
			foreach (PoseEntry item in entries.Where((PoseEntry p) => p.LongLegs))
			{
				if (!hashSet.Contains((item.Key, false)))
				{
					throw new InvalidDataException("LongLegs pose needs a regular variant.");
				}
			}
			Entries = entries;
		}

		public PoseEntry Resolve(string key, bool tall)
		{
			return Entries.FirstOrDefault((PoseEntry p) => p.Key == key && p.LongLegs == tall) ?? Entries.FirstOrDefault((PoseEntry p) => p.Key == key && !p.LongLegs) ?? throw new InvalidDataException("Pose is not in the catalog: " + key);
		}

		public static PoseCatalog Load()
		{
			using Stream utf8Json = Assembly.GetExecutingAssembly().GetManifestResourceStream("PhasePosePlayback.Catalog.json") ?? throw new InvalidDataException("Pose catalog resource missing.");
			return new PoseCatalog(JsonSerializer.Deserialize<PoseEntry[]>(utf8Json));
		}
	}
	public enum OccupancyChange
	{
		None,
		Entered,
		Left,
		EntryTimedOut
	}
	public sealed class OccupancyTracker
	{
		private readonly double _started;

		private double _missingSince = double.NaN;

		private bool _entered;

		private bool _finished;

		public OccupancyTracker(double started)
		{
			_started = started;
		}

		public OccupancyChange Observe(double now, bool seated)
		{
			if (_finished)
			{
				return OccupancyChange.None;
			}
			if (seated)
			{
				_missingSince = double.NaN;
				if (!_entered)
				{
					_entered = true;
					return OccupancyChange.Entered;
				}
			}
			else if (_entered)
			{
				if (double.IsNaN(_missingSince))
				{
					_missingSince = now;
				}
				if (now - _missingSince >= 0.2)
				{
					_finished = true;
					return OccupancyChange.Left;
				}
			}
			else if (now - _started >= 8.0)
			{
				_finished = true;
				return OccupancyChange.EntryTimedOut;
			}
			return OccupancyChange.None;
		}
	}
	public sealed class PosesTestMod : MelonMod
	{
		private sealed class JoinDownload
		{
			public PlayerID Player;

			public float ReadyAt = float.NaN;

			public float Expires;
		}

		private sealed class TemporaryCylinder
		{
			public GameObject Root;

			public int Id;

			public float DeleteAt;
		}

		private enum Stage
		{
			Idle,
			Preview,
			Spawning,
			Initializing,
			Entering,
			Seated,
			Leaving,
			Removing
		}

		private const string DownloadCylinderBarcode = "Phaseyy.Phasesposes.Spawnable.DownloadCylinder";

		private readonly List<JoinDownload> _joinDownloads = new List<JoinDownload>();

		private readonly List<TemporaryCylinder> _temporaryCylinders = new List<TemporaryCylinder>();

		private float _nextJoinCheck;

		private int _joinGeneration;

		private bool _downloadPending;

		private bool _manualDownload;

		private int _downloadQueued;

		private float _downloadAt;

		private float _downloadDeadline;

		private static readonly Color Accent = new Color(0.3f, 0.9f, 1f);

		private readonly ConcurrentQueue<Action> _actions = new ConcurrentQueue<Action>();

		private PoseCatalog _catalog;

		private MelonPreferences_Category _preferences;

		private MelonPreferences_Entry<bool> _tallPreference;

		private Page _menu;

		private FunctionElement _status;

		private PoseEntry _entry;

		private PoseEntry _pending;

		private PlacementVisuals _visual;

		private SpawnedSeat _seat;

		private OccupancyTracker _occupancy;

		private Stage _stage;

		private bool _tall;

		private bool _bodyYaw = true;

		private bool _validSurface;

		private bool _triggerArmed;

		private bool _cancelSpawn;

		private bool _shownControls;

		private Vector3 _position;

		private Quaternion _rotation = Quaternion.identity;

		private Quaternion _heading = Quaternion.identity;

		private int _generation;

		private int _removalAttempts;

		private float _inputAfter;

		private float _nextTick;

		private float _deadline;

		private float _readyAt;

		private string _lastNotification;

		private float _lastNotificationAt;

		private static Vector3 DownloadOrigin()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			return ((Component)Player.RigManager).transform.position;
		}

		private static Vector3 ManualDownloadOrigin()
		{
			//IL_003a: 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_0063: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			RigManager rigManager = Player.RigManager;
			Vector3 val = (((Object)(object)rigManager.ControllerRig != (Object)null && (Object)(object)((Rig)rigManager.ControllerRig).m_head != (Object)null) ? ((Rig)rigManager.ControllerRig).m_head : ((Component)rigManager).transform).forward;
			val.y = 0f;
			val = ((((Vector3)(ref val)).sqrMagnitude < 0.001f) ? Vector3.forward : ((Vector3)(ref val)).normalized);
			return (((Object)(object)rigManager.physicsRig != (Object)null && (Object)(object)((Rig)rigManager.physicsRig).m_chest != (Object)null) ? ((Component)((Rig)rigManager.physicsRig).m_chest).transform.position : (((Object)(object)rigManager.physicsRig != (Object)null && (Object)(object)((Rig)rigManager.physicsRig).m_pelvis != (Object)null) ? ((Component)((Rig)rigManager.physicsRig).m_pelvis).transform.position : ((Component)rigManager).transform.position)) + val * 2f;
		}

		private static bool IsDownloadCylinderLoaded()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0020: Expected O, but got Unknown
			try
			{
				return (Object)(object)((CrateReferenceT<SpawnableCrate>)new SpawnableCrateReference
				{
					_barcode = new Barcode
					{
						ID = "Phaseyy.Phasesposes.Spawnable.DownloadCylinder"
					}
				}).Crate != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		private bool TrySpawnDownloadCylinder(Vector3 position, Action<GameObject> callback = null)
		{
			//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)
			//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_0039: Expected O, but got Unknown
			//IL_003a: Expected O, but got Unknown
			//IL_003c: 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_0055: Expected O, but got Unknown
			//IL_0057: 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_005f: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkInfo.HasServer || !NetworkSceneManager.IsLevelNetworked)
			{
				return false;
			}
			try
			{
				SpawnableCrateReference crateRef = new SpawnableCrateReference
				{
					_barcode = new Barcode
					{
						ID = "Phaseyy.Phasesposes.Spawnable.DownloadCylinder"
					}
				};
				NetworkAssetSpawner.Spawn(new SpawnRequestInfo
				{
					Spawnable = new Spawnable
					{
						crateRef = crateRef
					},
					Position = position,
					Rotation = Quaternion.identity,
					SpawnEffect = false,
					SpawnCallback = ((callback == null) ? null : ((Action<SpawnCallbackInfo>)delegate(SpawnCallbackInfo info)
					{
						//IL_0006: Unknown result type (might be due to invalid IL or missing references)
						callback(info.Spawned);
					}))
				});
				return true;
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Warning("Download-cylinder request: " + ex.Message);
				return false;
			}
		}

		private void InitializeJoinDownloads()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			MultiplayerHooking.OnPlayerJoined += new PlayerUpdate(NewDownloadPlayer);
		}

		private void DisposeJoinDownloads()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			MultiplayerHooking.OnPlayerJoined -= new PlayerUpdate(NewDownloadPlayer);
		}

		private void NewDownloadPlayer(PlayerID id)
		{
			if (id == null || id.IsMe || !NetworkInfo.HasServer)
			{
				return;
			}
			foreach (JoinDownload joinDownload in _joinDownloads)
			{
				if (joinDownload.Player == id)
				{
					return;
				}
			}
			_joinDownloads.Add(new JoinDownload
			{
				Player = id,
				Expires = Time.unscaledTime + 600f
			});
		}

		private static void QuietDeleteCylinder(GameObject root)
		{
			try
			{
				if (Object.op_Implicit((Object)(object)root) && root.activeInHierarchy)
				{
					Poolee component = root.GetComponent<Poolee>();
					if (component != null)
					{
						component.Despawn();
					}
				}
			}
			catch
			{
			}
		}

		private void CancelJoinDownloads()
		{
			_joinGeneration++;
			_joinDownloads.Clear();
			foreach (TemporaryCylinder temporaryCylinder in _temporaryCylinders)
			{
				if (Object.op_Implicit((Object)(object)temporaryCylinder.Root) && ((Object)temporaryCylinder.Root).GetInstanceID() == temporaryCylinder.Id)
				{
					QuietDeleteCylinder(temporaryCylinder.Root);
				}
			}
			_temporaryCylinders.Clear();
		}

		private void ProcessJoinDownloads()
		{
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			if (_joinDownloads.Count == 0 && _temporaryCylinders.Count == 0)
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime < _nextJoinCheck)
			{
				return;
			}
			_nextJoinCheck = unscaledTime + 0.5f;
			if (!NetworkInfo.HasServer)
			{
				CancelJoinDownloads();
				return;
			}
			for (int num = _temporaryCylinders.Count - 1; num >= 0; num--)
			{
				TemporaryCylinder temporaryCylinder = _temporaryCylinders[num];
				if (!(unscaledTime < temporaryCylinder.DeleteAt))
				{
					if (Object.op_Implicit((Object)(object)temporaryCylinder.Root) && ((Object)temporaryCylinder.Root).GetInstanceID() == temporaryCylinder.Id)
					{
						QuietDeleteCylinder(temporaryCylinder.Root);
					}
					_temporaryCylinders.RemoveAt(num);
				}
			}
			bool flag = NetworkSceneManager.IsLevelNetworked && !FusionSceneManager.IsLoading();
			bool flag2 = false;
			bool flag3 = false;
			NetworkPlayer val = default(NetworkPlayer);
			for (int num2 = _joinDownloads.Count - 1; num2 >= 0; num2--)
			{
				JoinDownload joinDownload = _joinDownloads[num2];
				PlayerID player = joinDownload.Player;
				if (!player.IsValid || unscaledTime > joinDownload.Expires)
				{
					_joinDownloads.RemoveAt(num2);
				}
				else if (!flag || !player.Metadata.IsValid || ((MetadataVariableT<bool>)(object)player.Metadata.Loading).GetValue() || !NetworkPlayerManager.TryGetPlayer(player.SmallID, ref val) || !val.HasRig)
				{
					joinDownload.ReadyAt = float.NaN;
				}
				else if (float.IsNaN(joinDownload.ReadyAt))
				{
					joinDownload.ReadyAt = unscaledTime + 15f;
				}
				else if (!(unscaledTime < joinDownload.ReadyAt) && !((Object)(object)Player.RigManager == (Object)null))
				{
					if (!flag2)
					{
						flag3 = IsDownloadCylinderLoaded();
						flag2 = true;
					}
					if (flag3)
					{
						int generation = _joinGeneration;
						if (TrySpawnDownloadCylinder(ManualDownloadOrigin() + new Vector3(50f, 20f, 50f), delegate(GameObject root)
						{
							Queue(delegate
							{
								if (Object.op_Implicit((Object)(object)root))
								{
									if (generation != _joinGeneration || !NetworkInfo.HasServer)
									{
										QuietDeleteCylinder(root);
									}
									else
									{
										_temporaryCylinders.Add(new TemporaryCylinder
										{
											Root = root,
											Id = ((Object)root).GetInstanceID(),
											DeleteAt = Time.unscaledTime + 10f
										});
									}
								}
							});
						}))
						{
							_joinDownloads.RemoveAt(num2);
						}
					}
				}
			}
		}

		private void InitializeDownloads()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			MultiplayerHooking.OnStartedServer += new ServerEvent(ScheduleDownloads);
			MultiplayerHooking.OnJoinedServer += new ServerEvent(ScheduleDownloads);
			Hooking.OnLevelLoaded += DownloadLevelLoaded;
			InitializeJoinDownloads();
			ScheduleDownloads();
		}

		private void DisposeDownloads()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			MultiplayerHooking.OnStartedServer -= new ServerEvent(ScheduleDownloads);
			MultiplayerHooking.OnJoinedServer -= new ServerEvent(ScheduleDownloads);
			Hooking.OnLevelLoaded -= DownloadLevelLoaded;
			DisposeJoinDownloads();
			CancelDownloads();
		}

		private void DownloadLevelLoaded(LevelInfo _)
		{
			ScheduleDownloads();
		}

		private void ScheduleDownloads()
		{
			if (NetworkInfo.HasServer && !_downloadPending)
			{
				_downloadPending = true;
				_downloadQueued = 0;
				_downloadAt = Time.unscaledTime + 5f;
				_downloadDeadline = _downloadAt + 60f;
			}
		}

		private void RequestDownloads()
		{
			if (!NetworkInfo.HasServer)
			{
				Notify("Join a Fusion lobby before requesting the mod download.");
				return;
			}
			_downloadPending = true;
			_downloadQueued = 0;
			_manualDownload = true;
			_downloadAt = Time.unscaledTime;
			_downloadDeadline = _downloadAt + 60f;
		}

		private void CancelDownloads()
		{
			_downloadPending = false;
			_manualDownload = false;
			_downloadQueued = 0;
			CancelJoinDownloads();
		}

		private void ProcessDownloads()
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			ProcessJoinDownloads();
			if (!_downloadPending || Time.unscaledTime < _downloadAt)
			{
				return;
			}
			if (!NetworkInfo.HasServer)
			{
				CancelDownloads();
				return;
			}
			if (Time.unscaledTime >= _downloadDeadline)
			{
				bool manualDownload = _manualDownload;
				_downloadPending = false;
				_manualDownload = false;
				_downloadQueued = 0;
				((MelonBase)this).LoggerInstance.Warning("Pose-pallet download preload timed out waiting for Fusion, the rig or the DownloadCylinder crate.");
				if (manualDownload)
				{
					Notify("Download cylinders could not be requested. Check that the updated poses pallet is installed.", 4f);
				}
				return;
			}
			_downloadAt = Time.unscaledTime + 1f;
			if (!NetworkSceneManager.IsLevelNetworked || (Object)(object)Player.RigManager == (Object)null || !IsDownloadCylinderLoaded())
			{
				return;
			}
			Vector3 val = (_manualDownload ? ManualDownloadOrigin() : (DownloadOrigin() + new Vector3(2000f, 200f, 2000f)));
			while (_downloadQueued < (_manualDownload ? 1 : 2))
			{
				if (!TrySpawnDownloadCylinder(val + new Vector3((float)_downloadQueued * (_manualDownload ? 1.5f : 3f), 0f, 0f)))
				{
					return;
				}
				_downloadQueued++;
			}
			bool manualDownload2 = _manualDownload;
			_downloadPending = false;
			_manualDownload = false;
			_downloadQueued = 0;
			if (manualDownload2)
			{
				Notify("Download cylinders requested through Fusion.");
			}
		}

		public override void OnLateInitializeMelon()
		{
			//IL_005d: 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_00b3: 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)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Expected O, but got Unknown
			try
			{
				_preferences = MelonPreferences.CreateCategory("PhasesPosesTest", "SimplePoses");
				_tallPreference = _preferences.CreateEntry<bool>("SeatsForTallAvatars", false, "Seats for tall avatars", (string)null, false, false, (ValueValidator)null, (string)null);
				_tall = _tallPreference.Value;
				_catalog = PoseCatalog.Load();
				_menu = Page.Root.CreatePage("SimplePoses", Accent, 0, true);
				_status = _menu.CreateFunction("Idle", Color.gray, (Action)delegate
				{
				});
				_menu.CreateBool("Seats for tall avatars", Accent, _tall, (Action<bool>)delegate(bool value)
				{
					Queue(delegate
					{
						SetTall(value);
					});
				});
				Page val = _menu.CreatePage("Sit", Accent, 0, true);
				Dictionary<string, Page> dictionary = new Dictionary<string, Page>
				{
					{
						"Sit/Floor",
						val.CreatePage("Floor", Accent, 0, true)
					},
					{
						"Sit/Ledge",
						val.CreatePage("Ledge", Accent, 0, true)
					},
					{
						"Lay",
						_menu.CreatePage("Lay", Accent, 0, true)
					},
					{
						"Other",
						_menu.CreatePage("Other", Accent, 0, true)
					}
				};
				foreach (PoseEntry menuEntry in _catalog.MenuEntries)
				{
					string key = menuEntry.Key;
					dictionary[menuEntry.Category].CreateFunction(menuEntry.Label, Accent, (Action)delegate
					{
						Queue(delegate
						{
							Choose(key);
						});
					});
				}
				_menu.CreateFunction("Cancel posing / leave seat (X)", Color.yellow, (Action)delegate
				{
					Queue(delegate
					{
						Stop(keepPending: false);
					});
				});
				_menu.CreateFunction("Make everyone download the mod", Accent, (Action)delegate
				{
					Queue(RequestDownloads);
				});
				_menu.CreateFunction("Controls", Accent, (Action)delegate
				{
					Notify("Point with right hand. Y: body/left-hand yaw. Right trigger: place and sit. X: cancel or leave. Tall switch applies to the next pose or current hologram.", 12f);
				});
				Hooking.OnLevelLoading += LevelLoading;
				MultiplayerHooking.OnDisconnected += new ServerEvent(Disconnected);
				InitializeDownloads();
				((MelonBase)this).LoggerInstance.Msg($"Loaded {_catalog.Entries.Count} prebuilt pose crates. Install the packed Phase's poses Unity pallet. No Doctor seat mod is required by this player.");
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error(ex.ToString());
			}
		}

		private void Queue(Action action)
		{
			_actions.Enqueue(action);
		}

		private void Status(Stage stage)
		{
			_stage = stage;
			if (_status != null)
			{
				((Element)_status).ElementName = ((stage == Stage.Idle) ? "Idle" : ((_entry?.Label ?? "Pose") + ": " + stage));
			}
		}

		private void Notify(string text, float seconds = 2f)
		{
			//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_004b: 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)
			//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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			if (text == _lastNotification && Time.unscaledTime - _lastNotificationAt < 3f)
			{
				return;
			}
			_lastNotification = text;
			_lastNotificationAt = Time.unscaledTime;
			((MelonBase)this).LoggerInstance.Msg(text);
			try
			{
				Notifier.Send(new Notification
				{
					Title = NotificationText.op_Implicit("SimplePoses"),
					Message = NotificationText.op_Implicit(text),
					ShowTitleOnPopup = true,
					PopupLength = seconds,
					Type = (NotificationType)0
				});
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Warning("Notification: " + ex.Message);
			}
		}

		private void Choose(string key)
		{
			if ((Object)(object)Player.RigManager == (Object)null)
			{
				throw new InvalidOperationException("Load into a level first.");
			}
			PoseEntry poseEntry = _catalog.Resolve(key, _tall);
			Stage stage = _stage;
			if ((uint)stage <= 1u)
			{
				StartPreview(poseEntry);
				return;
			}
			_pending = poseEntry;
			Stop(keepPending: true);
		}

		private void SetTall(bool value)
		{
			_tall = value;
			if (_tallPreference.Value != value)
			{
				_tallPreference.Value = value;
				try
				{
					_preferences.SaveToFile(false);
				}
				catch (Exception ex)
				{
					((MelonBase)this).LoggerInstance.Warning("Tall-avatar preference save: " + ex.Message);
					Notify("Could not save the tall-avatar setting to disk.", 4f);
				}
			}
			if (_stage == Stage.Preview && _entry != null)
			{
				StartPreview(_catalog.Resolve(_entry.Key, value));
			}
		}

		private void StartPreview(PoseEntry entry)
		{
			if (_seat != null)
			{
				throw new InvalidOperationException("Wait for the previous seat to be removed.");
			}
			_visual?.Dispose();
			_visual = null;
			_entry = entry;
			_validSurface = false;
			_triggerArmed = false;
			_visual = new PlacementVisuals(entry);
			_inputAfter = Time.unscaledTime + 0.3f;
			Status(Stage.Preview);
			if (!_shownControls)
			{
				_shownControls = true;
				Notify("Point: right hand. Y: body/left-hand yaw. Right trigger: place and sit. X: cancel or leave.", 12f);
			}
		}

		public override void OnUpdate()
		{
			try
			{
				if (_actions.TryDequeue(out var result))
				{
					result();
				}
				ProcessDownloads();
				if (_stage != Stage.Idle)
				{
					bool flag = (Object.op_Implicit((Object)(object)GUIMenu.Instance) && ((Component)GUIMenu.Instance).gameObject.activeInHierarchy) || Time.unscaledTime < _inputAfter;
					BaseController leftController = Player.LeftController;
					if (!flag && (Object)(object)leftController != (Object)null && leftController.GetAButtonDown())
					{
						Stop(keepPending: false);
					}
					else if (_stage == Stage.Preview)
					{
						UpdatePreview(flag);
					}
					else if (!(Time.unscaledTime < _nextTick))
					{
						_nextTick = Time.unscaledTime + 0.1f;
						TickSeat();
					}
				}
			}
			catch (Exception ex)
			{
				Fail(ex);
			}
		}

		private void UpdatePreview(bool blocked)
		{
			//IL_003d: 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_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_0058: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: 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_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Player.RightHand == (Object)null || (Object)(object)Player.LeftHand == (Object)null || (Object)(object)Player.LeftController == (Object)null)
			{
				_triggerArmed = false;
				return;
			}
			Transform transform = ((Component)Player.RightHand).transform;
			Vector3 val = transform.position + transform.up * 0.04f + transform.forward * 0.08f;
			Vector3 forward = transform.forward;
			Ray ray = default(Ray);
			((Ray)(ref ray))..ctor(val, ((Vector3)(ref forward)).normalized);
			if (!blocked && Player.LeftController.GetBButtonDown())
			{
				_bodyYaw = !_bodyYaw;
				Notify(_bodyYaw ? "Orientation: body yaw" : "Orientation: left-hand yaw", 0.65f);
			}
			_validSurface = Surface(ray, out var point);
			object obj;
			if (!_bodyYaw)
			{
				obj = ((Component)Player.LeftHand).transform;
			}
			else
			{
				PhysicsRig physicsRig = Player.PhysicsRig;
				obj = ((physicsRig != null) ? ((Rig)physicsRig).m_pelvis : null);
			}
			Transform val2 = (Transform)obj;
			Vector3 val3 = (Object.op_Implicit((Object)(object)val2) ? val2.forward : ((Component)Player.LeftHand).transform.forward);
			val3.y = 0f;
			if (((Vector3)(ref val3)).sqrMagnitude > 0.001f)
			{
				_heading = Quaternion.LookRotation(((Vector3)(ref val3)).normalized, Vector3.up);
			}
			if (_validSurface)
			{
				_position = new Vector3(point.x, point.y + _entry.Height, point.z);
			}
			_rotation = _heading * PlacementVisuals.Q(_entry.Tilt);
			_visual.Update(_validSurface, _position, _rotation, _heading, ray, point);
			bool held = !blocked && Player.RightHand.GetIndexButton();
			if (PoseMath.ConfirmPressed(blocked, held, ref _triggerArmed))
			{
				if (!_validSurface)
				{
					Notify("Point at a surface within 25 metres.");
				}
				else
				{
					BeginSpawn();
				}
			}
		}

		private static bool Surface(Ray ray, out Vector3 point)
		{
			//IL_0001: 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_0020: 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_0031: 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_0078: 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_00a0: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			point = default(Vector3);
			RigManager rigManager = Player.RigManager;
			Transform val = ((rigManager != null) ? ((Component)rigManager).transform : null);
			Vector3 val2 = ((Ray)(ref ray)).origin;
			float num = 25f;
			RaycastHit val3 = default(RaycastHit);
			for (int i = 0; i < 12; i++)
			{
				if (!(num > 0f))
				{
					break;
				}
				if (!Physics.Raycast(val2, ((Ray)(ref ray)).direction, ref val3, num, -5, (QueryTriggerInteraction)1))
				{
					return false;
				}
				Collider collider = ((RaycastHit)(ref val3)).collider;
				if (!Object.op_Implicit((Object)(object)collider))
				{
					return false;
				}
				if (!Object.op_Implicit((Object)(object)val) || !((Component)collider).transform.IsChildOf(val))
				{
					point = ((RaycastHit)(ref val3)).point;
					return true;
				}
				float num2 = Mathf.Max(0.05f, ((RaycastHit)(ref val3)).distance + 0.02f);
				num -= num2;
				val2 += ((Ray)(ref ray)).direction * num2;
			}
			return false;
		}

		private void BeginSpawn()
		{
			//IL_0056: 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)
			_cancelSpawn = false;
			_pending = null;
			int generation = ++_generation;
			_deadline = Time.unscaledTime + 30f;
			Status(Stage.Spawning);
			SpawnedSeat.Spawn(_entry.Barcode, _position, _rotation, delegate(GameObject root)
			{
				Queue(delegate
				{
					if (generation != _generation)
					{
						if (Object.op_Implicit((Object)(object)root))
						{
							SpawnedSeat.Despawn(root);
						}
					}
					else
					{
						if (!Object.op_Implicit((Object)(object)root))
						{
							throw new InvalidOperationException("Seat spawning failed.");
						}
						try
						{
							_seat = new SpawnedSeat(root);
						}
						catch
						{
							SpawnedSeat.Despawn(root);
							throw;
						}
						if (_cancelSpawn)
						{
							BeginLeaving();
						}
						else
						{
							_readyAt = Time.unscaledTime + 1.3f;
							Status(Stage.Initializing);
						}
					}
				});
			});
			_visual?.Dispose();
			_visual = null;
		}

		private void TickSeat()
		{
			float unscaledTime = Time.unscaledTime;
			if (_stage == Stage.Spawning)
			{
				if (unscaledTime > _deadline)
				{
					_generation++;
					FinishRemoval();
					Notify("Seat spawn timed out. Any late result will be removed; check the pallet installation.", 4f);
				}
				return;
			}
			if (_seat == null || _seat.Removed)
			{
				FinishRemoval();
				return;
			}
			switch (_stage)
			{
			case Stage.Initializing:
				if (unscaledTime > _deadline)
				{
					throw new InvalidOperationException("Seat initialization/Fusion registration timed out.");
				}
				if (!(unscaledTime < _readyAt) && _seat.Ready)
				{
					_seat.Sit();
					_occupancy = new OccupancyTracker(unscaledTime);
					Status(Stage.Entering);
				}
				break;
			case Stage.Entering:
			case Stage.Seated:
				switch (_occupancy.Observe(unscaledTime, (Object)(object)Player.RigManager != (Object)null && (Object)(object)Player.RigManager.activeSeat == (Object)(object)_seat.Seat))
				{
				case OccupancyChange.Entered:
					Status(Stage.Seated);
					break;
				case OccupancyChange.Left:
					BeginLeaving();
					break;
				case OccupancyChange.EntryTimedOut:
					Notify("Native seat entry did not complete; removing the unused seat.", 4f);
					BeginLeaving();
					break;
				}
				break;
			case Stage.Leaving:
				if (!(unscaledTime < _readyAt))
				{
					LeaveSafely();
					RequestRemoval();
				}
				break;
			case Stage.Removing:
				if (unscaledTime > _deadline)
				{
					if (_removalAttempts < 3)
					{
						RequestRemoval();
					}
					else
					{
						AbandonRemoval();
					}
				}
				break;
			}
		}

		private void Stop(bool keepPending)
		{
			if (!keepPending)
			{
				_pending = null;
			}
			_visual?.Dispose();
			_visual = null;
			if (_stage == Stage.Spawning)
			{
				_cancelSpawn = true;
			}
			else if (_seat == null || _seat.Removed)
			{
				FinishRemoval();
			}
			else if (_stage == Stage.Removing)
			{
				_removalAttempts = 0;
				RequestRemoval();
			}
			else
			{
				BeginLeaving();
			}
		}

		private void BeginLeaving()
		{
			LeaveSafely();
			_visual?.Dispose();
			_visual = null;
			_readyAt = Time.unscaledTime + 0.35f;
			_removalAttempts = 0;
			Status(Stage.Leaving);
		}

		private void RequestRemoval()
		{
			_removalAttempts++;
			_deadline = Time.unscaledTime + 3f;
			Status(Stage.Removing);
			try
			{
				_seat.Remove();
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Warning("Removal request: " + ex.Message);
			}
		}

		private void LeaveSafely()
		{
			try
			{
				_seat?.Leave();
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Warning("Seat exit: " + ex.Message);
			}
		}

		private void Fail(Exception ex)
		{
			((MelonBase)this).LoggerInstance.Error(ex.ToString());
			Notify(ex.Message, 4f);
			_pending = null;
			try
			{
				if (_seat != null && !_seat.Removed)
				{
					BeginLeaving();
					return;
				}
				_generation++;
				FinishRemoval();
			}
			catch (Exception ex2)
			{
				((MelonBase)this).LoggerInstance.Error("Seat cleanup: " + ex2);
			}
		}

		private void LevelLoading(LevelInfo _)
		{
			CancelDownloads();
			Reset();
		}

		private void Disconnected()
		{
			CancelDownloads();
			Reset();
		}

		private void Reset()
		{
			_generation++;
			_pending = null;
			_visual?.Dispose();
			_visual = null;
			if (_seat != null)
			{
				try
				{
					_seat.Leave();
					_seat.Remove();
				}
				catch (Exception ex)
				{
					((MelonBase)this).LoggerInstance.Warning("Scene cleanup: " + ex.Message);
				}
				_seat.Dispose();
				_seat = null;
			}
			_occupancy = null;
			_entry = null;
			Status(Stage.Idle);
		}

		public override void OnDeinitializeMelon()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			Hooking.OnLevelLoading -= LevelLoading;
			MultiplayerHooking.OnDisconnected -= new ServerEvent(Disconnected);
			DisposeDownloads();
			Reset();
			if (_menu != null)
			{
				Menu.DestroyPage(_menu);
			}
		}

		private void AbandonRemoval()
		{
			Notify("The seat could not be despawned and may still be in the lobby. You can keep using other poses.", 5f);
			FinishRemoval();
		}

		private void FinishRemoval()
		{
			_seat?.Dispose();
			_seat = null;
			_occupancy = null;
			_entry = null;
			_cancelSpawn = false;
			_visual?.Dispose();
			_visual = null;
			Status(Stage.Idle);
			PoseEntry pending = _pending;
			_pending = null;
			if (pending != null)
			{
				StartPreview(pending);
			}
		}
	}
	internal sealed class PlacementVisuals : IDisposable
	{
		private sealed class Box
		{
			public string Path { get; set; }

			public float[] Position { get; set; }

			public float[] Rotation { get; set; }

			public float[] Scale { get; set; }
		}

		private static Box[] _boxes;

		private bool _visible;

		private readonly GameObject _root;

		private readonly Transform _ghost;

		private readonly LineRenderer _laser;

		private readonly LineRenderer _arrow;

		private readonly List<Material> _materials = new List<Material>();

		private static Box[] PreviewBoxes()
		{
			if (_boxes != null)
			{
				return _boxes;
			}
			using Stream utf8Json = Assembly.GetExecutingAssembly().GetManifestResourceStream("PhasePosePlayback.Preview.json") ?? throw new InvalidDataException("Preview resource missing.");
			Box[]? array = JsonSerializer.Deserialize<Box[]>(utf8Json);
			if (array == null || array.Length != 7)
			{
				throw new InvalidDataException("Invalid preview geometry.");
			}
			_boxes = array;
			return array;
		}

		public PlacementVisuals(PoseEntry entry)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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)
			//IL_0030: Expected O, but got Unknown
			//IL_0066: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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)
			//IL_0200: 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)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			_root = new GameObject("SimplePoses - local preview")
			{
				layer = 0,
				hideFlags = (HideFlags)52
			};
			try
			{
				_ghost = Child(_root.transform, "Hologram").transform;
				_ghost.localScale = V(entry.Pose.LastWorldSeat.Scale);
				Box[] array = PreviewBoxes();
				Material m = Material(new Color(0.12f, 0.9f, 1f, 0.7f));
				Box[] array2 = array;
				foreach (Box box in array2)
				{
					Transform obj = Path(_ghost, box.Path);
					obj.localPosition = V(box.Position);
					obj.localRotation = Q(box.Rotation);
					obj.localScale = V(box.Scale);
					LineRenderer val = Line(obj, m, 0.008f);
					val.useWorldSpace = false;
					int[] array3 = new int[16]
					{
						0, 1, 3, 2, 0, 4, 5, 1, 5, 7,
						3, 7, 6, 2, 6, 4
					};
					val.positionCount = array3.Length;
					for (int j = 0; j < array3.Length; j++)
					{
						int num = array3[j];
						val.SetPosition(j, new Vector3(((num & 1) == 0) ? (-0.5f) : 0.5f, ((num & 2) == 0) ? (-0.5f) : 0.5f, ((num & 4) == 0) ? (-0.5f) : 0.5f));
					}
				}
				Local(Path(_ghost, "Seat"), entry.Pose.SeatAnchorLocal);
				Local(Path(_ghost, "Seat/FootLf"), entry.Pose.LeftFootLocal);
				Local(Path(_ghost, "Seat/FootRt"), entry.Pose.RightFootLocal);
				_laser = Line(Child(_root.transform, "Pointer").transform, Material(Color.white), 0.004f);
				_laser.positionCount = 2;
				_arrow = Line(Child(_root.transform, "Forward").transform, Material(Color.yellow), 0.012f);
				_arrow.positionCount = 5;
				_root.SetActive(false);
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		public void Update(bool valid, Vector3 position, Quaternion rotation, Quaternion heading, Ray ray, Vector3 hit)
		{
			//IL_0026: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_006c: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: 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)
			if (_visible != valid)
			{
				_root.SetActive(valid);
				_visible = valid;
			}
			if (valid)
			{
				_ghost.SetPositionAndRotation(position, rotation);
				_laser.SetPosition(0, ((Ray)(ref ray)).origin);
				_laser.SetPosition(1, hit);
				Vector3 val = position + Vector3.up * 0.6f;
				Vector3 val2 = val + heading * Vector3.forward * 0.5f;
				_arrow.SetPosition(0, val);
				_arrow.SetPosition(1, val2);
				_arrow.SetPosition(2, val2 + heading * new Vector3(-0.1f, 0f, -0.13f));
				_arrow.SetPosition(3, val2);
				_arrow.SetPosition(4, val2 + heading * new Vector3(0.1f, 0f, -0.13f));
			}
		}

		private Material Material(Color color)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0057: 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)
			Shader val = Shader.Find("Unlit/Color");
			if (!Object.op_Implicit((Object)(object)val))
			{
				val = Shader.Find("Sprites/Default");
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("Supported preview shader unavailable.");
			}
			Material val2 = new Material(val);
			_materials.Add(val2);
			if (val2.HasProperty("_Color"))
			{
				val2.SetColor("_Color", color);
			}
			if (val2.HasProperty("_BaseColor"))
			{
				val2.SetColor("_BaseColor", color);
			}
			val2.renderQueue = 3000;
			return val2;
		}

		private static GameObject Child(Transform parent, string name)
		{
			//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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			GameObject val = new GameObject(name)
			{
				layer = 0
			};
			val.transform.SetParent(parent, false);
			return val;
		}

		private static Transform Path(Transform root, string path)
		{
			string[] array = path.Split('/');
			foreach (string text in array)
			{
				Transform val = root.Find(text);
				root = (Object.op_Implicit((Object)(object)val) ? val : Child(root, text).transform);
			}
			return root;
		}

		private static LineRenderer Line(Transform t, Material m, float width)
		{
			LineRenderer obj = ((Component)t).gameObject.AddComponent<LineRenderer>();
			((Renderer)obj).sharedMaterial = m;
			obj.useWorldSpace = true;
			float startWidth = (obj.endWidth = width);
			obj.startWidth = startWidth;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)obj).receiveShadows = false;
			return obj;
		}

		internal static Vector3 V(float[] a)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(a[0], a[1], a[2]);
		}

		internal static Quaternion Q(float[] a)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return new Quaternion(a[0], a[1], a[2], a[3]);
		}

		private static void Local(Transform t, TransformData a)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: 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)
			t.localPosition = V(a.Position);
			t.localRotation = Q(a.Rotation);
			t.localScale = V(a.Scale);
		}

		public void Dispose()
		{
			if (Object.op_Implicit((Object)(object)_root))
			{
				Object.Destroy((Object)(object)_root);
			}
			foreach (Material material in _materials)
			{
				if (Object.op_Implicit((Object)(object)material))
				{
					Object.Destroy((Object)(object)material);
				}
			}
			_materials.Clear();
		}
	}
	internal sealed class SpawnedSeat : IDisposable
	{
		private readonly int _id;

		private readonly Poolee _pool;

		private bool _retired;

		private bool _everActive;

		private Action<GameObject> _onRetired;

		public GameObject Root { get; }

		public Seat Seat { get; }

		public bool Removed
		{
			get
			{
				if (!_retired && Object.op_Implicit((Object)(object)Root) && ((Object)Root).GetInstanceID() == _id)
				{
					if (_everActive)
					{
						return !Root.activeInHierarchy;
					}
					return false;
				}
				return true;
			}
		}

		public bool Ready
		{
			get
			{
				if (Removed || !Root.activeInHierarchy)
				{
					return false;
				}
				_everActive = true;
				if (Object.op_Implicit((Object)(object)Seat) && Object.op_Implicit((Object)(object)Seat.seatRb))
				{
					if (NetworkInfo.HasServer)
					{
						if (NetworkSceneManager.IsLevelNetworked)
						{
							return SeatExtender.Cache.ContainsSource(Seat);
						}
						return false;
					}
					return true;
				}
				return false;
			}
		}

		public SpawnedSeat(GameObject root)
		{
			Root = root;
			_id = ((Object)root).GetInstanceID();
			_everActive = root.activeInHierarchy;
			Seat = root.GetComponentInChildren<Seat>(true);
			_pool = root.GetComponent<Poolee>();
			if (!Object.op_Implicit((Object)(object)Seat) || !Object.op_Implicit((Object)(object)_pool))
			{
				throw new InvalidOperationException("Spawned crate has no native Seat/Poolee.");
			}
			_onRetired = Action<GameObject>.op_Implicit((Action<GameObject>)delegate
			{
				_retired = true;
				Dispose();
			});
			Poolee pool = _pool;
			pool.OnDespawnDelegate += _onRetired;
			Poolee pool2 = _pool;
			pool2.OnRecycleDelegate += _onRetired;
		}

		public void Sit()
		{
			if (!Ready || (Object)(object)Player.RigManager == (Object)null)
			{
				throw new InvalidOperationException("The seat or player rig is not ready.");
			}
			if ((Object)(object)Seat.rigManager != (Object)null && (Object)(object)Seat.rigManager != (Object)(object)Player.RigManager)
			{
				throw new InvalidOperationException("Another player is using this seat.");
			}
			if (Object.op_Implicit((Object)(object)Player.RigManager.activeSeat) && (Object)(object)Player.RigManager.activeSeat != (Object)(object)Seat)
			{
				throw new InvalidOperationException("Leave your current seat before posing.");
			}
			Seat.IngressRig(Player.RigManager);
		}

		public void Leave()
		{
			if (!Removed && (Object)(object)Player.RigManager != (Object)null && ((Object)(object)Player.RigManager.activeSeat == (Object)(object)Seat || (Object)(object)Seat.rigManager == (Object)(object)Player.RigManager))
			{
				Seat.EgressRig(true);
			}
		}

		public void Remove()
		{
			if (!Removed)
			{
				Despawn(Root);
			}
		}

		public void Dispose()
		{
			if (!((Delegate)(object)_onRetired == (Delegate)null))
			{
				if (Object.op_Implicit((Object)(object)_pool))
				{
					Poolee pool = _pool;
					pool.OnDespawnDelegate -= _onRetired;
					Poolee pool2 = _pool;
					pool2.OnRecycleDelegate -= _onRetired;
				}
				_onRetired = null;
			}
		}

		public static void Despawn(GameObject root)
		{
			if (Object.op_Implicit((Object)(object)root) && root.activeInHierarchy)
			{
				Poolee component = root.GetComponent<Poolee>();
				if (!Object.op_Implicit((Object)(object)component))
				{
					throw new InvalidOperationException("No native pool handle for seat cleanup.");
				}
				component.Despawn();
			}
		}

		public static void Spawn(string barcode, Vector3 position, Quaternion rotation, Action<GameObject> callback)
		{
			//IL_000d: 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_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_0025: Expected O, but got Unknown
			//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_004b: Expected O, but got Unknown
			//IL_00be: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_0077: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			SpawnableCrateReference val = new SpawnableCrateReference
			{
				_barcode = new Barcode
				{
					ID = barcode
				}
			};
			if (!((ScannableReference)val).IsValid())
			{
				throw new InvalidOperationException("Install the packed Phase's poses pallet first. Missing crate: " + barcode);
			}
			Spawnable val2 = new Spawnable
			{
				crateRef = val
			};
			if (NetworkInfo.HasServer)
			{
				if (!NetworkSceneManager.IsLevelNetworked)
				{
					throw new InvalidOperationException("Wait for the Fusion map to finish loading.");
				}
				NetworkAssetSpawner.Spawn(new SpawnRequestInfo
				{
					Spawnable = val2,
					Position = position,
					Rotation = rotation,
					SpawnEffect = false,
					SpawnCallback = delegate(SpawnCallbackInfo info)
					{
						//IL_0006: Unknown result type (might be due to invalid IL or missing references)
						callback(info.Spawned);
					}
				});
				return;
			}
			AssetSpawner.Register(val2);
			Awaiter<Poolee> awaiter = AssetSpawner.SpawnAsync(val2, position, rotation, new Nullable<Vector3>(Vector3.zero)
			{
				hasValue = false
			}, (Transform)null, false, new Nullable<int>(0)
			{
				hasValue = false
			}, (Action<GameObject>)null, (Action<GameObject>)null, (Action<GameObject>)null).GetAwaiter();
			awaiter.OnCompleted(Action.op_Implicit((Action)delegate
			{
				GameObject obj = null;
				try
				{
					Poolee result = awaiter.GetResult();
					obj = ((result != null) ? ((Component)result).gameObject : null);
				}
				finally
				{
					callback(obj);
				}
			}));
		}
	}
}