Decompiled source of PingVisualizer v1.0.0

Mods/PingVisualizer.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using FlatLand;
using HarmonyLib;
using Il2Cpp;
using Il2CppExitGames.Client.Photon;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppLiv.Lck;
using Il2CppPhoton.Pun;
using Il2CppPhoton.Realtime;
using Il2CppRUMBLE.CharacterCreation.Interactable;
using Il2CppRUMBLE.Combat.ShiftStones;
using Il2CppRUMBLE.Input;
using Il2CppRUMBLE.Interactions.InteractionBase;
using Il2CppRUMBLE.Managers;
using Il2CppRUMBLE.Networking;
using Il2CppRUMBLE.Players;
using Il2CppRUMBLE.Players.Scaling;
using Il2CppRUMBLE.Players.Subsystems;
using Il2CppRUMBLE.Utilities;
using Il2CppSystem;
using MelonLoader;
using PingVisualizer;
using RumbleModUI;
using RumbleModdingAPI;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using VoidLand;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Core), "PingVisualizer", "1.0.0", "TacoSlayer36", null)]
[assembly: MelonGame("Buckethead Entertainment", "RUMBLE")]
[assembly: MelonOptionalDependencies(new string[] { "FlatLand", "VoidLand" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("PingVisualizer")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PingVisualizer")]
[assembly: AssemblyTitle("PingVisualizer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace PingVisualizer
{
	public static class BuildInfo
	{
		public const string Name = "PingVisualizer";

		public const string Author = "TacoSlayer36";

		public const string Version = "1.0.0";

		public const string Description = "Visualizes ping with delayed clones";
	}
	public class Core : MelonMod
	{
		public static Core Instance;

		public bool GlobalInit = false;

		public List<Laggard> LaggardList = new List<Laggard>();

		public GameObject ParentGameObject;

		public Material LaggardMaterial;

		private int _hostPing = 150;

		private int _localPing = 70;

		public Mod Mod = new Mod();

		public static bool IsFlatLandInstalled => MelonTypeBase<MelonMod>.RegisteredMelons.Any((MelonMod melon) => ((MelonBase)melon).Info.Name == "FlatLand");

		public static bool IsVoidLandInstalled => MelonTypeBase<MelonMod>.RegisteredMelons.Any((MelonMod melon) => ((MelonBase)melon).Info.Name == "VoidLand");

		private Player host
		{
			get
			{
				Room currentRoom = PhotonNetwork.CurrentRoom;
				return (currentRoom != null) ? currentRoom.players[PhotonNetwork.CurrentRoom.MasterClientId] : null;
			}
		}

		public bool NoHostExists => PhotonNetwork.IsMasterClient || host == null || Scene.GetSceneName() == "Gym";

		private bool opponentHasLaggardsEnabled
		{
			get
			{
				Player obj = Singleton<PlayerManager>.Instance.AllPlayers[1];
				int result;
				if (obj != null)
				{
					PlayerController controller = obj.Controller;
					if (controller != null)
					{
						PhotonView component = ((Component)controller).GetComponent<PhotonView>();
						if (component != null)
						{
							Player owner = component.Owner;
							if (owner != null)
							{
								Object obj2 = owner.CustomProperties[Object.op_Implicit("PingVisualizer.LaggardsEnabled")];
								if (obj2 != null)
								{
									((Il2CppObjectBase)obj2).Unbox<bool>();
									if (0 == 0)
									{
										result = 1;
										goto IL_0063;
									}
								}
							}
						}
					}
				}
				result = 0;
				goto IL_0063;
				IL_0063:
				return (byte)result != 0;
			}
		}

		public int HostPing
		{
			get
			{
				if (ModUISettings.HostTestPing.HasValue)
				{
					return ModUISettings.HostTestPing.Value;
				}
				return _hostPing;
			}
			set
			{
				_hostPing = value;
			}
		}

		public int LocalPing
		{
			get
			{
				if (ModUISettings.LocalTestPing.HasValue)
				{
					return ModUISettings.LocalTestPing.Value;
				}
				return _localPing;
			}
			set
			{
				_localPing = value;
			}
		}

		public override void OnLateInitializeMelon()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			Instance = this;
			UI.instance.UI_Initialized += OnUIInit;
			Calls.onMapInitialized += sceneReady;
			MelonCoroutines.Start(SlowFixedUpdate());
			LaggardMaterial = new Material(Calls.LoadAssetFromStream<Material>((MelonMod)(object)this, "PingVisualizer.assets.pingvisualizer", "Laggard"));
			((Object)LaggardMaterial).hideFlags = (HideFlags)32;
		}

		public override void OnFixedUpdate()
		{
			List<Laggard> list = new List<Laggard>();
			foreach (Laggard laggard in LaggardList)
			{
				if ((Object)(object)laggard == (Object)null)
				{
					list.Add(laggard);
					continue;
				}
				laggard.AddPosition();
				laggard.PlayBackPosition();
			}
			foreach (Laggard item in list)
			{
				LaggardList.Remove(item);
			}
		}

		private void sceneReady()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			if (Scene.GetSceneName() != "Loader")
			{
				ParentGameObject = new GameObject("PingVisualizer");
				if (IsFlatLandInstalled)
				{
					main.dontDisableGameObject.Add("PingVisualizer");
				}
				if (IsVoidLandInstalled)
				{
					main.dontDisableGameObject.Add("PingVisualizer");
				}
				if (!GlobalInit)
				{
					MelonCoroutines.Start(SlowFixedUpdate());
					GlobalInit = true;
				}
			}
		}

		public IEnumerator SlowFixedUpdate()
		{
			while (true)
			{
				yield return (object)new WaitForSeconds(1f);
				if (Scene.GetSceneName() != "Loader")
				{
					FetchPings();
				}
			}
		}

		public void FetchPings()
		{
			try
			{
				LocalPing = PhotonNetwork.GetPing();
			}
			catch
			{
			}
			if (PhotonNetwork.InRoom && Scene.GetSceneName() != "Gym")
			{
				try
				{
					if (NoHostExists)
					{
						HostPing = ModUISettings.AssumedHostPing;
					}
					else
					{
						HostPing = ((Il2CppObjectBase)host.CustomProperties[Object.op_Implicit("ping")]).Unbox<int>();
					}
					return;
				}
				catch
				{
					return;
				}
			}
			HostPing = ModUISettings.AssumedHostPing;
		}

		public IEnumerator CreateAllLaggards(PlayerController player, float waitTime)
		{
			if (PhotonNetwork.InRoom)
			{
				Hashtable ht = new Hashtable();
				ht[Object.op_Implicit("PingVisualizer.LaggardsEnabled")] = Object.op_Implicit(ModUISettings.RoundTripLaggard || ModUISettings.OneWayLaggard);
				PhotonNetwork.LocalPlayer.SetCustomProperties(ht, (Hashtable)null, (WebFlags)null);
			}
			yield return (object)new WaitForSeconds(waitTime);
			if (!Scene.GetSceneName().Contains("Map") || Singleton<PlayerManager>.Instance.AllPlayers.Count <= 1 || opponentHasLaggardsEnabled)
			{
				CreateLaggard(player, roundTrip: false);
				CreateLaggard(player, roundTrip: true);
				SetLaggardsVisibility();
			}
		}

		public IEnumerator ClearAllLaggards()
		{
			yield return (object)new WaitForSeconds(0.1f);
			foreach (Laggard laggard in LaggardList)
			{
				Object.Destroy((Object)(object)((Component)laggard).gameObject);
			}
			LaggardList.Clear();
		}

		public void CreateLaggard(PlayerController player, bool roundTrip)
		{
			GameObject val = Object.Instantiate<GameObject>(((Component)player).gameObject);
			val.transform.SetParent(ParentGameObject.transform);
			((Object)val).name = (roundTrip ? "Round-Trip Laggard" : "One-Way Laggard");
			Laggard laggard = val.AddComponent<Laggard>();
			laggard.RoundTrip = roundTrip;
			laggard.TrackedPlayer = player;
			try
			{
				laggard.Setup();
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error("Failed to create laggard: " + ex.Message);
				Object.Destroy((Object)(object)val);
				return;
			}
			LaggardList.Add(laggard);
		}

		public void SetLaggardsVisibility()
		{
			foreach (Laggard laggard in LaggardList)
			{
				if (laggard.RoundTrip)
				{
					((Component)laggard).gameObject.SetActive(ModUISettings.RoundTripLaggard);
				}
				else
				{
					((Component)laggard).gameObject.SetActive(ModUISettings.OneWayLaggard);
				}
				if (ModUISettings.AssumedHostPing < 0 && NoHostExists)
				{
					((Component)laggard).gameObject.SetActive(false);
				}
			}
		}

		public void OnUIInit()
		{
			//IL_0049: 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_005b: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			Mod.ModName = "PingVisualizer";
			Mod.ModVersion = "1.0.0";
			Mod.SetFolder("PingVisualizer");
			Mod.AddDescription("Description", "", "Visualizes ping with delayed clones", new Tags
			{
				IsSummary = true
			});
			Mod.AddToList("<#F0F>Round-trip laggard", true, 0, "Enable a <#F0F>clone</color> to show your ping delay to the host and back\n(This is the position that can be hit/spawn structures)", new Tags());
			Mod.AddToList("<#FF0>One-way laggard", false, 0, "Enable a <#FF0>clone</color> to show your ping delay to the host\n(This has no affect on gameplay, but is the real-time location that the host is seeing you)", new Tags());
			Mod.AddToList("Assumed Host Ping", 70, "The ping to assume for the host when there is not one\nSet to -1 to auto-disable laggards on host", new Tags());
			Mod.AddToList("Test Pings", "", "Override actual pings with these values for testing\nLeave blank to ignore\n\nFormatted like: \"host, client\"\nEx: \"70, 150\"", new Tags());
			Mod.AddToList("Hide nearby laggards", 1, "The amount to hide laggards that are close to you\n0: None\n1: Hide heads only\n2: Hide entire bodies", new Tags());
			Mod.GetFromFile();
			Mod.ModSaved += OnUISave;
			UI.instance.AddMod(Mod);
		}

		public void OnUISave()
		{
			SetLaggardsVisibility();
		}
	}
	[RegisterTypeInIl2Cpp]
	public class Laggard : MonoBehaviour
	{
		public PlayerController TrackedPlayer;

		public PlayerController PlayerController;

		public Material MaterialInstance;

		public bool RoundTrip = false;

		public List<PlayerPosition> RecordedPositions = new List<PlayerPosition>();

		private PlayerMeasurement lastMeasurement;

		private Transform headBone;

		private float delayTime => RoundTrip ? (Core.Instance.HostPing + Core.Instance.LocalPing) : ((Core.Instance.HostPing + Core.Instance.LocalPing) / 2);

		private int delayUpdates => Math.Clamp((int)(delayTime / 20f), 0, int.MaxValue);

		private int frame => Math.Clamp(RecordedPositions.Count - delayUpdates - 1, 0, RecordedPositions.Count);

		public PlayerPosition PlayerPosition => RecordedPositions[frame];

		public Transform vr => ((Component)this).gameObject.transform.GetChild(1);

		public Transform visuals => ((Component)this).gameObject.transform.GetChild(0);

		public Transform Head => ((Component)vr.GetChild(0).GetChild(0)).transform;

		public Transform LeftHand => ((Component)vr.GetChild(1)).transform;

		public Transform RightHand => ((Component)vr.GetChild(2)).transform;

		public void Setup()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Core.Instance.LaggardMaterial == (Object)null)
			{
				throw new Exception("Ghost material was null");
			}
			MaterialInstance = new Material(Core.Instance.LaggardMaterial);
			headBone = ((Component)this).transform.GetChild(1).GetChild(1).GetChild(0)
				.GetChild(4)
				.GetChild(0)
				.GetChild(0)
				.GetChild(0);
			PlayerController = ((Component)this).GetComponent<PlayerController>();
			((Behaviour)PlayerController).enabled = false;
			foreach (Behaviour component2 in ((Component)this).GetComponents<Behaviour>())
			{
				component2.enabled = false;
			}
			((Behaviour)this).enabled = true;
			foreach (Renderer componentsInChild in ((Component)this).gameObject.GetComponentsInChildren<Renderer>())
			{
				if (((Object)componentsInChild).name != "FadeScreenRenderer")
				{
					componentsInChild.shadowCastingMode = (ShadowCastingMode)0;
					componentsInChild.sharedMaterial = MaterialInstance;
					componentsInChild.material.SetFloat("_Opacity", 0.1f);
					componentsInChild.material.SetColor("_Color", RoundTrip ? Color.magenta : Color.yellow);
				}
			}
			PlayerShiftstoneSystem component = ((Component)this).GetComponent<PlayerShiftstoneSystem>();
			foreach (ShiftstoneSocket item in (Il2CppArrayBase<ShiftstoneSocket>)(object)component.shiftStoneSockets)
			{
				Object.DestroyImmediate((Object)(object)((Component)item.shiftstonePlacementTransform.GetChild(0)).gameObject);
			}
			((Behaviour)component).enabled = false;
			Transform child = ((Component)this).gameObject.transform.GetChild(10);
			((Behaviour)((Component)child.GetChild(1)).GetComponent<LckServiceHelper>()).enabled = false;
			((Component)child.GetChild(3)).gameObject.SetActive(false);
			Object.Destroy((Object)(object)((Component)child.GetChild(2)).gameObject, 0.25f);
			((Component)child.GetChild(0)).gameObject.SetActive(false);
			((Behaviour)((Component)((Component)this).gameObject.transform.GetChild(1)).GetComponent<PlayerAnimator>()).enabled = false;
			((Behaviour)((Component)((Component)this).gameObject.transform.GetChild(1)).GetComponent<PlayerVisuals>()).enabled = false;
			((Behaviour)((Component)((Component)this).gameObject.transform.GetChild(1)).GetComponent<PlayerAudioPresence>()).enabled = false;
			((Behaviour)((Component)((Component)this).gameObject.transform.GetChild(1)).GetComponent<PhotonAnimatorView>()).enabled = false;
			((Behaviour)((Component)((Component)this).gameObject.transform.GetChild(1)).GetComponent<PhotonView>()).enabled = false;
			((PlayerControllerSubsystem)((Component)((Component)this).gameObject.transform.GetChild(1)).GetComponent<PlayerHandPresence>()).Initialize(PlayerController);
			Object.Destroy((Object)(object)((Component)((Component)((Component)this).gameObject.transform.GetChild(1)).GetComponent<PlayerHandPresence>().lefthand.Index.BoneC).GetComponent<SphereCollider>());
			Object.Destroy((Object)(object)((Component)((Component)((Component)this).gameObject.transform.GetChild(1)).GetComponent<PlayerHandPresence>().righthand.Index.BoneC).GetComponent<SphereCollider>());
			((Component)((Component)this).gameObject.transform.GetChild(1).GetChild(0)).gameObject.layer = 0;
			Transform child2 = ((Component)this).transform.GetChild(2).GetChild(0).GetChild(0);
			((Behaviour)((Component)child2).GetComponent<PlayerCamera>()).enabled = false;
			((Behaviour)((Component)child2).GetComponent<UniversalAdditionalCameraData>()).enabled = false;
			((Behaviour)((Component)child2).GetComponent<Volume>()).enabled = false;
			((Behaviour)((Component)child2).GetComponent<NetworkGameObject>()).enabled = false;
			((Behaviour)((Component)child2).GetComponent<LckAudioCapture>()).enabled = false;
			Object.Destroy((Object)(object)((Component)child2).GetComponent<Rigidbody>());
			Object.DestroyImmediate((Object)(object)((Component)child2.GetChild(4)).gameObject);
			Object.DestroyImmediate((Object)(object)((Component)child2.GetChild(3)).gameObject);
			Object.DestroyImmediate((Object)(object)((Component)child2.GetChild(2)).gameObject);
			((Component)child2.GetChild(1)).gameObject.SetActive(false);
			((Behaviour)((Component)((Component)this).transform.GetChild(2).GetChild(1)).GetComponent<InteractionHand>()).enabled = false;
			((Behaviour)((Component)((Component)this).transform.GetChild(2).GetChild(1)).GetComponent<NetworkGameObject>()).enabled = false;
			((Behaviour)((Component)((Component)this).transform.GetChild(2).GetChild(2)).GetComponent<InteractionHand>()).enabled = false;
			((Behaviour)((Component)((Component)this).transform.GetChild(2).GetChild(2)).GetComponent<NetworkGameObject>()).enabled = false;
			((Behaviour)((Component)((Component)this).gameObject.transform.GetChild(2)).GetComponent<NetworkGameObject>()).enabled = false;
			Object.Destroy((Object)(object)((Component)((Component)this).gameObject.transform.GetChild(2)).GetComponent<Rigidbody>());
			Object.DestroyImmediate((Object)(object)((Component)((Component)this).gameObject.transform.GetChild(9)).gameObject);
			Object.DestroyImmediate((Object)(object)((Component)((Component)this).gameObject.transform.GetChild(8)).gameObject);
			Object.DestroyImmediate((Object)(object)((Component)((Component)this).gameObject.transform.GetChild(7)).gameObject);
			Object.DestroyImmediate((Object)(object)((Component)((Component)this).gameObject.transform.GetChild(6)).gameObject);
			Object.DestroyImmediate((Object)(object)((Component)((Component)this).gameObject.transform.GetChild(5)).gameObject);
			Object.DestroyImmediate((Object)(object)((Component)((Component)this).gameObject.transform.GetChild(2).GetChild(1).GetChild(1)).gameObject);
			Object.DestroyImmediate((Object)(object)((Component)((Component)this).gameObject.transform.GetChild(2).GetChild(2).GetChild(1)).gameObject);
			Object.DestroyImmediate((Object)(object)((Component)((Component)this).gameObject.transform.GetChild(0)).gameObject);
		}

		public void AddPosition()
		{
			//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_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0068: 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_0083: 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_009e: 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_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_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: 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_0108: Unknown result type (might be due to invalid IL or missing references)
			PlayerPosition item = new PlayerPosition
			{
				HeadPos = TrackedPlayer.GetPlayerHead().transform.position,
				HeadRot = TrackedPlayer.GetPlayerHead().transform.rotation,
				LeftHandPos = TrackedPlayer.GetLeftHand().transform.position,
				RightHandPos = TrackedPlayer.GetRightHand().transform.position,
				LeftHandRot = TrackedPlayer.GetLeftHand().transform.rotation,
				RightHandRot = TrackedPlayer.GetRightHand().transform.rotation,
				Measurement = TrackedPlayer.assignedPlayer.Data.PlayerMeasurement,
				VisualsPos = ((Component)TrackedPlayer).transform.GetChild(1).position,
				LHandInput = TrackedPlayer.GetHandPresence().GetHandPresenceInputForHand((Hand)1),
				RHandInput = TrackedPlayer.GetHandPresence().GetHandPresenceInputForHand((Hand)2)
			};
			if (RecordedPositions.Count > delayUpdates + 1000)
			{
				RecordedPositions.RemoveAt(0);
			}
			RecordedPositions.Add(item);
		}

		public void PlayBackPosition()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: 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_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			if (RecordedPositions.Count > delayUpdates || RecordedPositions.Count <= frame)
			{
				((Component)Head).transform.position = PlayerPosition.HeadPos;
				((Component)LeftHand).transform.position = PlayerPosition.LeftHandPos;
				((Component)RightHand).transform.position = PlayerPosition.RightHandPos;
				((Component)Head).transform.rotation = PlayerPosition.HeadRot;
				((Component)LeftHand).transform.rotation = PlayerPosition.LeftHandRot;
				((Component)RightHand).transform.rotation = PlayerPosition.RightHandRot;
				((Component)Head).transform.rotation = PlayerPosition.HeadRot;
				if (lastMeasurement.Length != PlayerPosition.Measurement.Length || lastMeasurement.ArmSpan != PlayerPosition.Measurement.ArmSpan)
				{
					((Component)visuals).GetComponent<PlayerScaling>().ScaleController(PlayerPosition.Measurement);
				}
				lastMeasurement = PlayerPosition.Measurement;
				((Component)visuals).transform.position = PlayerPosition.VisualsPos;
				bool flag = Vector3.Distance(((Component)Head).transform.position, Singleton<PlayerManager>.Instance.LocalPlayer.Controller.GetPlayerHead().transform.position) < 0.3f;
				if (ModUISettings.HideNearbyLaggards == 1 && flag)
				{
					((Component)headBone).transform.localScale = Vector3.one * 0.01f;
					return;
				}
				if (ModUISettings.HideNearbyLaggards == 2 && flag)
				{
					((Component)visuals).gameObject.SetActive(false);
					return;
				}
				((Component)headBone).transform.localScale = Vector3.one;
				((Component)visuals).gameObject.SetActive(true);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerController), "Initialize", new Type[] { typeof(Player) })]
	public static class playerSpawnPatch
	{
		private static void Postfix(ref PlayerController __instance, ref Player player)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			if ((int)player.Controller.controllerType == 1)
			{
				MelonCoroutines.Start(Core.Instance.CreateAllLaggards(player.Controller, 2f));
			}
		}
	}
	[HarmonyPatch(typeof(PlayerHandPresence), "UpdateHandPresenceAnimationStates")]
	public class handPresencePatch
	{
		private static void Prefix(PlayerHandPresence __instance, Hand hand, ref HandPresenceInput input)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Invalid comparison between Unknown and I4
			//IL_0059: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			if (((PlayerControllerSubsystem)__instance).parentController.IsLaggard())
			{
				Laggard component = ((Component)((PlayerControllerSubsystem)__instance).parentController).GetComponent<Laggard>();
				if (!((Object)(object)component == (Object)null) && component.RecordedPositions.Count >= 1)
				{
					input = (((int)hand == 1) ? component.PlayerPosition.LHandInput : component.PlayerPosition.RHandInput);
				}
			}
		}
	}
	[HarmonyPatch(typeof(DressingRoom), "PlayCurtainSFX", new Type[] { typeof(bool) })]
	public static class dressingRoomPatch
	{
		private static void Prefix(ref bool open)
		{
			if (!open)
			{
				Core.Instance.ClearAllLaggards();
				MelonCoroutines.Start(Core.Instance.CreateAllLaggards(Singleton<PlayerManager>.Instance.LocalPlayer.Controller, 0.15f));
			}
		}
	}
	public class PlayerPosition
	{
		public Vector3 LeftHandPos;

		public Vector3 RightHandPos;

		public Vector3 HeadPos;

		public Quaternion LeftHandRot;

		public Quaternion RightHandRot;

		public Quaternion HeadRot;

		public HandPresenceInput LHandInput;

		public HandPresenceInput RHandInput;

		public Vector3 VisualsPos;

		public PlayerMeasurement Measurement;
	}
	public static class Extensions
	{
		public static GameObject GetPlayerHead(this PlayerController player)
		{
			return ((Component)((Component)player).transform.GetChild(2).GetChild(0).GetChild(0)).gameObject;
		}

		public static GameObject GetLeftHand(this PlayerController player)
		{
			return ((Component)((Component)player).transform.GetChild(2).GetChild(1)).gameObject;
		}

		public static GameObject GetRightHand(this PlayerController player)
		{
			return ((Component)((Component)player).transform.GetChild(2).GetChild(2)).gameObject;
		}

		public static GameObject GetPlayerFoot(this PlayerController player)
		{
			return ((Component)((Component)player).GetComponentInChildren<PlayerPhysics>().FootCollider).gameObject;
		}

		public static PlayerHandPresence GetHandPresence(this PlayerController player)
		{
			return player.GetSubsystem<PlayerHandPresence>();
		}

		public static bool IsLaggard(this PlayerController player)
		{
			return Core.Instance.LaggardList.Contains(((Component)player).GetComponent<Laggard>());
		}
	}
	public static class ModUISettings
	{
		public static bool RoundTripLaggard => (bool)Core.Instance.Mod.Settings[1].SavedValue;

		public static bool OneWayLaggard => (bool)Core.Instance.Mod.Settings[2].SavedValue;

		public static int AssumedHostPing => (int)Core.Instance.Mod.Settings[3].SavedValue;

		private static string _testPings => (string)Core.Instance.Mod.Settings[4].SavedValue;

		public static int? HostTestPing
		{
			get
			{
				string[] array = _testPings.Split(", ");
				int result = 0;
				if (array.Length >= 1 && int.TryParse(array[0], out result))
				{
					return result;
				}
				return null;
			}
		}

		public static int HideNearbyLaggards => (int)Core.Instance.Mod.Settings[5].SavedValue;

		public static int? LocalTestPing
		{
			get
			{
				string[] array = _testPings.Split(", ");
				int result = 0;
				if (array.Length == 2 && int.TryParse(array[1], out result))
				{
					return result;
				}
				return null;
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}