Decompiled source of PingVisualizer v1.1.1

Mods/PingVisualizer.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using FlatLand;
using HarmonyLib;
using Il2CppExitGames.Client.Photon;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppPhoton.Pun;
using Il2CppPhoton.Realtime;
using Il2CppRUMBLE.CharacterCreation.Interactable;
using Il2CppRUMBLE.Combat.ShiftStones;
using Il2CppRUMBLE.Managers;
using Il2CppRUMBLE.Players;
using Il2CppRUMBLE.Players.Scaling;
using Il2CppRUMBLE.Players.Subsystems;
using Il2CppRUMBLE.Pools;
using Il2CppRUMBLE.Utilities;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using PingVisualizer;
using UIFramework;
using UIFramework.Models;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.VFX;
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.1.1", "TacoSlayer36", null)]
[assembly: MelonGame("Buckethead Entertainment", "RUMBLE")]
[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: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
}
namespace PingVisualizer
{
	public static class BuildInfo
	{
		public const string Name = "PingVisualizer";

		public const string Author = "TacoSlayer36";

		public const string Version = "1.1.1";
	}
	public static class Config
	{
		public enum HideNearbyType
		{
			[Display(Name = "Disabled")]
			Disabled,
			[Display(Name = "Only Heads")]
			OnlyHeads,
			[Display(Name = "Entirely")]
			Entirely
		}

		public static string UserDataPath = Path.Combine("UserData", "PingVisualizer");

		public static string PreferencesFilePath = Path.Combine(UserDataPath, "Config.cfg");

		public static MelonPreferences_Category Cat_Visualizer;

		public static MelonPreferences_Entry<bool> Enabled;

		public static MelonPreferences_Entry<HideNearbyType> HideNearby;

		public static MelonPreferences_Entry<string> OneWayColor;

		public static MelonPreferences_Entry<string> TwoWayColor;

		public static MelonPreferences_Entry<bool> MatchesOnly;

		public static MelonPreferences_Category Cat_Client;

		public static MelonPreferences_Entry<bool> OneWayClient;

		public static MelonPreferences_Entry<bool> TwoWayClient;

		public static MelonPreferences_Category Cat_Host;

		public static MelonPreferences_Entry<bool> OneWayHost;

		public static MelonPreferences_Entry<bool> TwoWayHost;

		public static MelonPreferences_Category Cat_Testing;

		public static MelonPreferences_Entry<int> AssumedHostPing;

		public static MelonPreferences_Entry<int> AssumedClientPing;

		public static MelonPreferences_Entry<int> ForcedHostPing;

		public static MelonPreferences_Entry<int> ForcedClientPing;

		public static float DefaultHostPing => ((float)ForcedHostPing.EditedValue != -1f) ? ForcedHostPing.EditedValue : AssumedHostPing.EditedValue;

		public static float DefaultClientPing => ((float)ForcedClientPing.EditedValue != -1f) ? ForcedClientPing.EditedValue : AssumedClientPing.EditedValue;

		public static void SetUpUI()
		{
			Cat_Visualizer = MelonPreferences.CreateCategory("PingVisualizer_Visualizer", "Visualizer");
			Cat_Visualizer.SetFilePath(PreferencesFilePath);
			Enabled = Cat_Visualizer.CreateEntry<bool>("PingVisualizer_Enabled", true, "Enabled", "Enable/Disable all visualization", false, false, (ValueValidator)null, (string)null);
			MatchesOnly = Cat_Visualizer.CreateEntry<bool>("PingVisualizer_MatchesOnly", true, "Matches Only", "Only show laggards while in a match", false, false, (ValueValidator)null, (string)null);
			HideNearby = Cat_Visualizer.CreateEntry<HideNearbyType>("PingVisualizer_HideNearby", HideNearbyType.OnlyHeads, "Hide Nearby Laggards", "Hides laggards that are close to you", false, false, (ValueValidator)null, (string)null);
			OneWayColor = Cat_Visualizer.CreateEntry<string>("PingVisualizer_OneWayColor", "#FF00FF", "One-Way Color", "Color for one-way laggards", false, false, (ValueValidator)null, (string)null);
			TwoWayColor = Cat_Visualizer.CreateEntry<string>("PingVisualizer_TwoWayColor", "#FFFF00", "Two-Way Color", "Color for two-way laggards", false, false, (ValueValidator)null, (string)null);
			Cat_Client = MelonPreferences.CreateCategory("PingVisualizer_Client", "Client");
			Cat_Client.SetFilePath(PreferencesFilePath);
			OneWayClient = Cat_Client.CreateEntry<bool>("PingVisualizer_OneWay", false, "One-Way Laggard", "Enable a <#F0F>clone</color> to show your ping delay to the host\n(This has no effect on gameplay, but is the real-time position that the host is seeing you)", false, false, (ValueValidator)null, (string)null);
			TwoWayClient = Cat_Client.CreateEntry<bool>("PingVisualizer_TwoWay", true, "Two-Way Laggard", "Enable a <#FF0>clone</color> to show your ping delay to the host and back\n(This is the position that can be hit/spawn structures)", false, false, (ValueValidator)null, (string)null);
			Cat_Host = MelonPreferences.CreateCategory("PingVisualizer_Host", "Host");
			Cat_Host.SetFilePath(PreferencesFilePath);
			OneWayHost = Cat_Host.CreateEntry<bool>("PingVisualizer_OneWay", false, "One-Way Laggard", "Enable a <#F0F>clone</color> to show your ping delay to the opponent\n(This is the real-time position the client is seeing you in)", false, false, (ValueValidator)null, (string)null);
			TwoWayHost = Cat_Host.CreateEntry<bool>("PingVisualizer_TwoWay", false, "Two-Way Laggard", "Enable a <#FF0>clone</color> to show your ping delay to the opponent and back\n(This is the position the client is seeing you by the time they react on your end)", false, false, (ValueValidator)null, (string)null);
			Cat_Testing = MelonPreferences.CreateCategory("PingVisualizer_Testing", "Testing");
			Cat_Testing.SetFilePath(PreferencesFilePath);
			AssumedClientPing = Cat_Testing.CreateEntry<int>("PingVisualizer_AssumedClientPing", 70, "Assumed Client Ping", "Ping value to give the client when the actual value cannot be found or doesn't exist", false, false, (ValueValidator)null, (string)null);
			AssumedHostPing = Cat_Testing.CreateEntry<int>("PingVisualizer_AssumedHostPing", 70, "Assumed Host Ping", "Ping value to give the host when the actual value cannot be found or doesn't exist", false, false, (ValueValidator)null, (string)null);
			ForcedClientPing = Cat_Testing.CreateEntry<int>("PingVisualizer_ForcedClientPing", -1, "Forced Client Ping", "Override the client ping to this value\n(-1 to disable)", false, false, (ValueValidator)null, (string)null);
			ForcedHostPing = Cat_Testing.CreateEntry<int>("PingVisualizer_ForcedHostPing", -1, "Forced Host Ping", "Override the host ping to this value\n(-1 to disable)", false, false, (ValueValidator)null, (string)null);
			MelonModel val = UI.RegisterMelon((MelonBase)(object)Core.Instance, (MelonPreferences_Category[])(object)new MelonPreferences_Category[4] { Cat_Visualizer, Cat_Client, Cat_Host, Cat_Testing });
		}

		public static void OnMyPrefsSaved(string filePath)
		{
			if (!(filePath != PreferencesFilePath))
			{
				Core.SetLaggards();
			}
		}
	}
	public class Core : MelonMod
	{
		public static Core Instance;

		public static List<PlayerVisualsClone> Laggards = new List<PlayerVisualsClone>();

		public static Material PoseGhostMat;

		public static int BuildIndex = -1;

		public static bool HasGuard;

		public static PooledVisualEffect? LocalGuardVFX;

		public override void OnLateInitializeMelon()
		{
			Instance = this;
			Config.SetUpUI();
			((MelonEventBase<LemonAction<string>>)(object)MelonPreferences.OnPreferencesSaved).Subscribe((LemonAction<string>)Config.OnMyPrefsSaved, 0, false);
			AssetBundle val = AssetBundle.LoadFromMemory(Il2CppStructArray<byte>.op_Implicit(HelperFunctions.LoadEmbeddedResource("PingVisualizer.assets.pingvisualizer")));
			PoseGhostMat = val.LoadAsset<Material>("Laggard");
			PoseGhostMat.SetFloat("_Inflate", 0.003f);
			((Object)PoseGhostMat).hideFlags = (HideFlags)61;
			if (MelonBase.RegisteredMelons.Any((MelonBase m) => m.Info.Name == "FlatLand"))
			{
				FlatLandSupport.SetUp();
			}
			if (MelonBase.RegisteredMelons.Any((MelonBase m) => m.Info.Name == "VoidLand"))
			{
				VoidLandSupport.SetUp();
			}
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			BuildIndex = buildIndex;
		}

		public override void OnSceneWasUnloaded(int buildIndex, string sceneName)
		{
			if (playerInitializePatch.WaitForPlayerRoutine != null)
			{
				MelonCoroutines.Stop(playerInitializePatch.WaitForPlayerRoutine);
			}
		}

		public override void OnFixedUpdate()
		{
			List<Laggard> list = new List<Laggard>();
			foreach (Laggard laggard in Laggards)
			{
				if ((Object)(object)laggard.ParentController == (Object)null)
				{
					Object.DestroyImmediate((Object)(object)laggard.Visuals);
					list.Add(laggard);
				}
			}
			foreach (Laggard item in list)
			{
				Laggards.Remove(item);
			}
		}

		public static void SetLaggards()
		{
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			List<Laggard> list = new List<Laggard>();
			foreach (Laggard laggard in Laggards)
			{
				if ((Object)(object)laggard == (Object)null || (Object)(object)((Component)laggard).gameObject == (Object)null)
				{
					list.Add(laggard);
					continue;
				}
				if (!Config.Enabled.EditedValue || (Config.MatchesOnly.EditedValue && BuildIndex < 3))
				{
					((Component)laggard).gameObject.SetActive(false);
					continue;
				}
				if (laggard.Type == Laggard.LaggardType.OneWay && !laggard.ParentController.IsHost())
				{
					((Component)laggard).gameObject.SetActive(Config.OneWayClient.EditedValue);
				}
				if (laggard.Type == Laggard.LaggardType.TwoWay && !laggard.ParentController.IsHost())
				{
					((Component)laggard).gameObject.SetActive(Config.TwoWayClient.EditedValue);
				}
				if (laggard.Type == Laggard.LaggardType.OneWay && laggard.ParentController.IsHost())
				{
					((Component)laggard).gameObject.SetActive(Config.OneWayHost.EditedValue);
				}
				if (laggard.Type == Laggard.LaggardType.TwoWay && laggard.ParentController.IsHost())
				{
					((Component)laggard).gameObject.SetActive(Config.TwoWayHost.EditedValue);
				}
				if (laggard.Type == Laggard.LaggardType.OneWay)
				{
					((Renderer)laggard.SMR).material.color = HelperFunctions.ParseColor(Config.OneWayColor.EditedValue);
				}
				if (laggard.Type == Laggard.LaggardType.TwoWay)
				{
					((Renderer)laggard.SMR).material.color = HelperFunctions.ParseColor(Config.TwoWayColor.EditedValue);
				}
			}
			foreach (Laggard item in list)
			{
				Laggards.Remove(item);
			}
		}

		public static float GetPlayerPing(PlayerController controller)
		{
			if (controller.IsHost() && Config.ForcedHostPing.EditedValue > 0)
			{
				return Config.ForcedHostPing.EditedValue;
			}
			if (!controller.IsHost() && Config.ForcedClientPing.EditedValue > 0)
			{
				return Config.ForcedClientPing.EditedValue;
			}
			if ((Object)(object)controller == (Object)null)
			{
				return 0f;
			}
			object obj;
			if (controller == null)
			{
				obj = null;
			}
			else
			{
				PlayerNetworking playerNetworking = controller.PlayerNetworking;
				if (playerNetworking == null)
				{
					obj = null;
				}
				else
				{
					PhotonView rootPhotonView = playerNetworking.RootPhotonView;
					obj = ((rootPhotonView != null) ? rootPhotonView.Owner : null);
				}
			}
			Player val = (Player)obj;
			Hashtable val2 = ((val != null) ? val.CustomProperties : null);
			if (val2 != null && ((Dictionary<Object, Object>)(object)val2).ContainsKey(Object.op_Implicit("ping")))
			{
				return ((Il2CppObjectBase)val2[Object.op_Implicit("ping")]).Unbox<int>();
			}
			if (val != null)
			{
				return controller.IsHost() ? Config.DefaultHostPing : Config.DefaultClientPing;
			}
			if (!PhotonNetwork.InRoom)
			{
				return Config.DefaultHostPing;
			}
			return 0f;
		}

		public static float GetHostPing()
		{
			if (!PhotonNetwork.InRoom)
			{
				return GetPlayerPing(Singleton<PlayerManager>.Instance.LocalPlayer.Controller);
			}
			Player masterClient = PhotonNetwork.MasterClient;
			if (masterClient != null)
			{
				_ = masterClient.ActorNumber;
				if (true)
				{
					Player playerByActorNo = Singleton<PlayerManager>.Instance.GetPlayerByActorNo(PhotonNetwork.MasterClient.ActorNumber);
					return GetPlayerPing((playerByActorNo != null) ? playerByActorNo.Controller : null);
				}
			}
			return 0f;
		}
	}
	[HarmonyPatch(typeof(PlayerController), "Initialize")]
	public static class playerInitializePatch
	{
		public static object WaitForPlayerRoutine;

		private static void Postfix(ref PlayerController __instance)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			PlayerController val = __instance;
			if ((int)val.controllerType == 1)
			{
				WaitForPlayerRoutine = MelonCoroutines.Start(HelperFunctions.WaitForPlayerLoad(val, processNewPlayer));
			}
			static void processNewPlayer(PlayerController player)
			{
				Core.Laggards.Add(Laggard.CreateLaggard(player, Laggard.LaggardType.OneWay));
				Core.Laggards.Add(Laggard.CreateLaggard(player, Laggard.LaggardType.TwoWay));
				Core.SetLaggards();
			}
		}
	}
	public static class FlatLandSupport
	{
		public static void SetUp()
		{
			main.AddNameToDontDisable("PingVisualizer");
		}
	}
	internal static class HelperFunctions
	{
		public static Color ParseColor(string input)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Color result = default(Color);
			if (ColorUtility.TryParseHtmlString(input, ref result))
			{
				return result;
			}
			return Color.white;
		}

		public static List<Transform> FindChildrenRecursive(Transform parent)
		{
			List<Transform> list = new List<Transform>();
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform child = parent.GetChild(i);
				list.Add(child);
				list.AddRange(FindChildrenRecursive(child));
			}
			return list;
		}

		public static void DisableAllComponents(GameObject gameObject, List<Behaviour> except = null)
		{
			foreach (Behaviour component in gameObject.GetComponents<Behaviour>())
			{
				component.enabled = except?.Contains(component) ?? false;
			}
		}

		public static void CopyAllTransforms(List<Transform> from, List<Transform> to)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < from.Count; i++)
			{
				if (to.Count >= i || from.Count >= 1)
				{
					to[i].position = from[i].position;
					to[i].rotation = from[i].rotation;
					to[i].localScale = from[i].localScale;
				}
			}
		}

		public static string SanitizeString(string Input)
		{
			string pattern = "<[^>]*>";
			return Regex.Replace(Input, pattern, string.Empty);
		}

		public static Vector3 GetRelativeVelocity(Vector3 velocityA, Collision collision)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			Rigidbody rigidbody = collision.rigidbody;
			Vector3 val = (((Object)(object)rigidbody != (Object)null) ? rigidbody.velocity : Vector3.zero);
			return velocityA - val;
		}

		public static byte[] LoadEmbeddedResource(string resourcePath)
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			using Stream stream = executingAssembly.GetManifestResourceStream(resourcePath);
			if (stream == null)
			{
				throw new FileNotFoundException("Embedded resource '" + resourcePath + "' not found.");
			}
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			return memoryStream.ToArray();
		}

		public static IEnumerator WaitForPlayerLoad(PlayerController player, Action<PlayerController> callback)
		{
			int i = 0;
			int startingBuildIndex = -1;
			while (true)
			{
				i++;
				if (i == 100)
				{
					startingBuildIndex = Core.BuildIndex;
				}
				if (i > 100 && startingBuildIndex != Core.BuildIndex)
				{
					yield break;
				}
				if ((Object)(object)((player != null) ? player.PlayerVisuals : null) != (Object)null && player.IsInitialized && (int)player.PlayerSessionStateSystem.CurrentVRState == 0)
				{
					break;
				}
				yield return (object)new WaitForFixedUpdate();
			}
			callback(player);
		}
	}
	public static class Extensions
	{
		public static Transform GetChest(this PlayerController player)
		{
			return ((Component)player).GetComponentInChildren<RigDefinition>().ChestDefinition.Transform;
		}

		public static Transform GetHead(this PlayerController player)
		{
			return player.PlayerVR.headset.Transform;
		}

		public static Vector3 GetStandingPosition(this PlayerController player)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			return ((Component)player.PlayerPhysics.footCollider).transform.position;
		}

		public static Camera GetCamera(this PlayerController player)
		{
			object result;
			if (player == null)
			{
				result = null;
			}
			else
			{
				PlayerCamera playerCamera = player.PlayerCamera;
				result = ((playerCamera != null) ? playerCamera.Camera : null);
			}
			return (Camera)result;
		}

		public static List<BoneDefinition> GetBones(this PlayerController player)
		{
			return ((IEnumerable<BoneDefinition>)((Component)player).GetComponentInChildren<RigDefinition>().BoneDefinitions).ToList();
		}

		public static bool IsHost(this PlayerController player)
		{
			int result;
			if (PhotonNetwork.InRoom)
			{
				bool? obj;
				if (player == null)
				{
					obj = null;
				}
				else
				{
					PlayerNetworking playerNetworking = player.PlayerNetworking;
					if (playerNetworking == null)
					{
						obj = null;
					}
					else
					{
						PhotonView rootPhotonView = playerNetworking.RootPhotonView;
						if (rootPhotonView == null)
						{
							obj = null;
						}
						else
						{
							Player owner = rootPhotonView.Owner;
							obj = ((owner != null) ? new bool?(owner.IsMasterClient) : ((bool?)null));
						}
					}
				}
				result = ((obj ?? true) ? 1 : 0);
			}
			else
			{
				result = 1;
			}
			return (byte)result != 0;
		}
	}
	[RegisterTypeInIl2Cpp]
	public class Laggard : PlayerVisualsClone
	{
		public enum LaggardType
		{
			OneWay,
			TwoWay
		}

		public class LaggardState
		{
			public float TimeStamp = 0f;

			public List<TransformState> BoneStates = new List<TransformState>();

			public Vector3 VisualsPos;

			public Quaternion VisualsRot;

			public bool IsGuarding;

			public Vector3? GuardPos;

			public float? GuardYaw;

			public LaggardState()
			{
				TimeStamp = Time.time;
			}
		}

		public class TransformState
		{
			public Vector3 Pos = Vector3.zero;

			public Quaternion Rot = Quaternion.identity;

			public Vector3 Scale = Vector3.one;

			public static TransformState FromTransform(Transform transform)
			{
				//IL_0008: 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_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				return new TransformState
				{
					Pos = transform.localPosition,
					Rot = transform.localRotation,
					Scale = transform.localScale
				};
			}

			public static List<TransformState> FromTransforms(List<Transform> transforms)
			{
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				List<TransformState> list = new List<TransformState>();
				foreach (Transform transform in transforms)
				{
					if (!((Object)(object)transform == (Object)null))
					{
						list.Add(new TransformState
						{
							Pos = ((Component)transform).transform.localPosition,
							Rot = ((Component)transform).transform.localRotation,
							Scale = ((Component)transform).transform.localScale
						});
					}
				}
				return list;
			}

			public static void CopyStateTo(Transform transform, TransformState state)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)transform == (Object)null))
				{
					transform.localPosition = state.Pos;
					transform.localRotation = state.Rot;
					transform.localScale = state.Scale;
				}
			}

			public static void CopyStatesTo(List<Transform> transforms, List<TransformState> states)
			{
				for (int i = 0; i < transforms.Count && i < transforms.Count && i < states.Count; i++)
				{
					CopyStateTo(transforms[i], states[i]);
				}
			}
		}

		public const string OneWayLaggardName = "OneWayLaggard";

		public const string TwoWayLaggardName = "TwoWayLaggard";

		public const string LaggardParentName = "PingVisualizer";

		public static GameObject LaggardParent;

		public LaggardType Type = LaggardType.OneWay;

		public List<LaggardState> LaggardStates = new List<LaggardState>();

		private VisualEffect guardVFX = null;

		private bool hadGuardLastFrame = false;

		public float HostPing => Core.GetHostPing();

		public float OwnerPing => Core.GetPlayerPing(ParentController);

		public float Offset
		{
			get
			{
				if (Type == LaggardType.OneWay)
				{
					return (OwnerPing + HostPing) / 2000f;
				}
				if (Type == LaggardType.TwoWay)
				{
					return (OwnerPing + HostPing) / 1000f;
				}
				return 0f;
			}
		}

		public void StoreState()
		{
			//IL_005b: 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_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_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			LaggardState laggardState = new LaggardState
			{
				BoneStates = TransformState.FromTransforms((from b in ParentController.GetBones()
					select b.Transform).ToList()),
				VisualsPos = ((Component)ParentController.PlayerVisuals).gameObject.transform.position,
				VisualsRot = ((Component)ParentController.PlayerVisuals).gameObject.transform.rotation
			};
			Il2CppStructArray<int> currentShiftStoneConfiguration = ((Component)ParentController).GetComponent<PlayerShiftstoneSystem>().GetCurrentShiftStoneConfiguration();
			Core.HasGuard = ((Il2CppArrayBase<int>)(object)currentShiftStoneConfiguration)[0] == 3 || ((Il2CppArrayBase<int>)(object)currentShiftStoneConfiguration)[1] == 3;
			if (!Core.HasGuard)
			{
				Core.LocalGuardVFX = null;
			}
			else if ((Object)(object)Core.LocalGuardVFX == (Object)null)
			{
				Transform obj = ((Component)ParentController).transform.Find("Guardstone_VFX");
				Core.LocalGuardVFX = ((obj != null) ? ((Component)obj).GetComponent<PooledVisualEffect>() : null);
			}
			if (!hadGuardLastFrame && Core.HasGuard && (Object)(object)Core.LocalGuardVFX != (Object)null && (Object)(object)guardVFX == (Object)null)
			{
				GameObject val = Object.Instantiate<GameObject>(((Component)Core.LocalGuardVFX).gameObject);
				val.SetActive(true);
				((Component)val.transform.GetChild(0)).gameObject.SetActive(false);
				val.transform.SetParent(Visuals.transform, false);
				guardVFX = val.GetComponent<VisualEffect>();
			}
			hadGuardLastFrame = Core.HasGuard;
			laggardState.VisualsPos = ((Component)ParentController).transform.GetChild(1).position;
			PooledVisualEffect? localGuardVFX = Core.LocalGuardVFX;
			int isGuarding;
			if (localGuardVFX != null)
			{
				_ = localGuardVFX.isPlaying;
				if (true)
				{
					isGuarding = (Core.LocalGuardVFX.isPlaying ? 1 : 0);
					goto IL_01e7;
				}
			}
			isGuarding = 0;
			goto IL_01e7;
			IL_01e7:
			laggardState.IsGuarding = (byte)isGuarding != 0;
			PooledVisualEffect? localGuardVFX2 = Core.LocalGuardVFX;
			laggardState.GuardPos = ((localGuardVFX2 != null) ? new Vector3?(((Component)localGuardVFX2).transform.position) : ((Vector3?)null));
			PooledVisualEffect? localGuardVFX3 = Core.LocalGuardVFX;
			laggardState.GuardYaw = ((localGuardVFX3 != null) ? new float?(((Component)localGuardVFX3).transform.eulerAngles.y) : ((float?)null));
			LaggardStates.Add(laggardState);
			List<LaggardState> list = LaggardStates.Where((LaggardState s) => s.TimeStamp < Time.time - Offset).ToList();
			foreach (LaggardState item in list)
			{
				LaggardStates.Remove(item);
			}
		}

		public void PlayBackState()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: 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)
			if (LaggardStates.Count == 0)
			{
				return;
			}
			LaggardState laggardState = LaggardStates[0];
			if (laggardState == null)
			{
				return;
			}
			TransformState.CopyStatesTo(BoneTransforms, laggardState.BoneStates);
			Visuals.transform.position = laggardState.VisualsPos;
			Visuals.transform.rotation = laggardState.VisualsRot;
			if (laggardState.GuardPos.HasValue && laggardState.GuardYaw.HasValue && (Object)(object)guardVFX != (Object)null)
			{
				((Component)guardVFX).transform.position = laggardState.GuardPos.Value + Vector3.down * 0.4f;
				((Component)guardVFX).transform.rotation = Quaternion.Euler(0f, laggardState.GuardYaw.Value, 0f);
				if (laggardState.IsGuarding)
				{
					VisualEffect obj = guardVFX;
					if (obj != null)
					{
						obj.Play();
					}
				}
				else
				{
					VisualEffect obj2 = guardVFX;
					if (obj2 != null)
					{
						obj2.Stop();
					}
				}
			}
			double num = Vector3.Distance(((Component)Head).transform.position, ((Component)Singleton<PlayerManager>.Instance.LocalPlayer.Controller.GetHead()).transform.position);
			float num2 = (float)Math.Round(Math.Clamp(num - 0.2, 0.0, 1.0), 3);
			if (Config.HideNearby.EditedValue == Config.HideNearbyType.OnlyHeads)
			{
				((Renderer)SMR).material.SetFloat("_HeadOpacity", num2);
			}
			else
			{
				((Renderer)SMR).material.SetFloat("_HeadOpacity", 1f);
			}
			if (Config.HideNearby.EditedValue == Config.HideNearbyType.Entirely)
			{
				((Renderer)SMR).material.SetFloat("_BodyOpacity", num2);
			}
			else
			{
				((Renderer)SMR).material.SetFloat("_BodyOpacity", 1f);
			}
			VisualEffect obj3 = guardVFX;
			if (obj3 != null)
			{
				GameObject gameObject = ((Component)obj3).gameObject;
				if (gameObject != null)
				{
					gameObject.SetActive(num2 > 0.4f || Config.HideNearby.EditedValue != Config.HideNearbyType.Entirely);
				}
			}
		}

		private void Update()
		{
			StoreState();
			PlayBackState();
		}

		private void OnDestroy()
		{
			Core.Laggards.Remove(this);
		}

		public void SetUp()
		{
			SetUp(null);
			((Object)this).name = ((Type == LaggardType.OneWay) ? "OneWayLaggard" : "TwoWayLaggard");
		}

		public static Laggard CreateLaggard(PlayerController player, LaggardType type)
		{
			//IL_0049: 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)
			Laggard laggard = Object.Instantiate<GameObject>(((Component)player.PlayerVisuals).gameObject).AddComponent<Laggard>();
			laggard.ParentController = player;
			laggard.Type = type;
			laggard.SetUp();
			switch (type)
			{
			case LaggardType.OneWay:
				((Renderer)laggard.SMR).material.color = HelperFunctions.ParseColor(Config.OneWayColor.EditedValue);
				break;
			case LaggardType.TwoWay:
				((Renderer)laggard.SMR).material.color = HelperFunctions.ParseColor(Config.TwoWayColor.EditedValue);
				break;
			}
			createParentObjectIfNeeded();
			((Component)laggard).transform.SetParent(LaggardParent.transform);
			return laggard;
		}

		private static void createParentObjectIfNeeded()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			if (!((Object)(object)LaggardParent != (Object)null))
			{
				LaggardParent = new GameObject("PingVisualizer");
			}
		}
	}
	[RegisterTypeInIl2Cpp]
	public class PlayerVisualsClone : MonoBehaviour
	{
		public PlayerController ParentController;

		public GameObject Visuals;

		public List<Transform> BoneTransforms = new List<Transform>();

		public Transform Head;

		public SkinnedMeshRenderer SMR;

		public static void Clone(PlayerController player)
		{
			GameObject val = Object.Instantiate<GameObject>(((Component)player.PlayerVisuals).gameObject);
			val.AddComponent<PlayerVisualsClone>().SetUp();
		}

		public void SetUp(GameObject setupObject = null)
		{
			if ((Object)(object)setupObject == (Object)null)
			{
				setupObject = ((Component)this).gameObject;
			}
			Visuals = setupObject;
			Transform child = Visuals.transform.GetChild(1).GetChild(0).GetChild(4)
				.GetChild(0);
			object obj;
			if (child == null)
			{
				obj = null;
			}
			else
			{
				Transform child2 = child.GetChild(1);
				if (child2 == null)
				{
					obj = null;
				}
				else
				{
					GameObject gameObject = ((Component)child2).gameObject;
					if (gameObject == null)
					{
						obj = null;
					}
					else
					{
						ShiftStone componentInChildren = gameObject.GetComponentInChildren<ShiftStone>(true);
						obj = ((componentInChildren != null) ? ((Component)componentInChildren).gameObject : null);
					}
				}
			}
			Object.Destroy((Object)obj);
			object obj2;
			if (child == null)
			{
				obj2 = null;
			}
			else
			{
				Transform child3 = child.GetChild(2);
				if (child3 == null)
				{
					obj2 = null;
				}
				else
				{
					GameObject gameObject2 = ((Component)child3).gameObject;
					if (gameObject2 == null)
					{
						obj2 = null;
					}
					else
					{
						ShiftStone componentInChildren2 = gameObject2.GetComponentInChildren<ShiftStone>(true);
						obj2 = ((componentInChildren2 != null) ? ((Component)componentInChildren2).gameObject : null);
					}
				}
			}
			Object.Destroy((Object)obj2);
			foreach (Renderer componentsInChild in Visuals.GetComponentsInChildren<Renderer>())
			{
				if (((Object)componentsInChild).name == "FadeScreenRenderer")
				{
					Object.Destroy((Object)(object)((Component)componentsInChild).gameObject);
					continue;
				}
				componentsInChild.shadowCastingMode = (ShadowCastingMode)0;
				componentsInChild.sharedMaterial = Core.PoseGhostMat;
				((Component)componentsInChild).gameObject.layer = 0;
			}
			for (int num = child.childCount - 1; num > 0; num--)
			{
				Transform child4 = child.GetChild(num);
				if (((Object)child4).name.Contains("VFX"))
				{
					((Component)child4).gameObject.SetActive(false);
				}
			}
			foreach (Collider componentsInChild2 in Visuals.GetComponentsInChildren<Collider>())
			{
				componentsInChild2.enabled = false;
			}
			HelperFunctions.DisableAllComponents(Visuals, new List<Behaviour>
			{
				(Behaviour)(object)this,
				(Behaviour)(object)Visuals.GetComponent<RigDefinition>()
			});
			Transform child5 = Visuals.transform.GetChild(2);
			Object.Destroy((Object)(object)((child5 != null) ? ((Component)child5).gameObject : null));
			RigDefinition component = Visuals.GetComponent<RigDefinition>();
			BoneTransforms.AddRange(((IEnumerable<BoneDefinition>)component.BoneDefinitions).Select((BoneDefinition b) => b.Transform).ToArray());
			Head = component.HeadDefinition.Transform;
			SMR = Visuals.GetComponentInChildren<SkinnedMeshRenderer>();
		}

		public void ReapplyVisuals()
		{
			if (!((Object)(object)Visuals == (Object)null))
			{
				SkinnedMeshRenderer componentInChildren = Visuals.GetComponentInChildren<SkinnedMeshRenderer>();
				SkinnedMeshRenderer componentInChildren2 = ((Component)((Component)ParentController).transform.GetChild(1)).GetComponentInChildren<SkinnedMeshRenderer>();
				componentInChildren.sharedMesh = componentInChildren2.sharedMesh;
			}
		}
	}
	[HarmonyPatch(typeof(DressingRoom), "DelayedApplyData", new Type[] { typeof(GeneratedPlayerVisuals) })]
	public static class dressingRoomPatch
	{
		private static void Postfix()
		{
			foreach (Laggard laggard in Core.Laggards)
			{
				if ((Object)(object)laggard.ParentController == (Object)(object)Singleton<PlayerManager>.Instance.LocalPlayer.Controller)
				{
					laggard.ReapplyVisuals();
				}
			}
		}
	}
	public static class VoidLandSupport
	{
		public static void SetUp()
		{
			main.AddNameToDontDisable("PingVisualizer");
		}
	}
}