Decompiled source of STREPLAY v1.1.2

BepInEx/plugins/streplay/streplay.dll

Decompiled 9 hours ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ComputerysModdingUtilities;
using FishNet;
using FishNet.Component.Transforming;
using FishNet.Managing;
using FishNet.Managing.Client;
using FishNet.Managing.Object;
using FishNet.Object;
using Goodgulf.Graphics;
using HarmonyLib;
using ICSharpCode.SharpZipLib;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using StreplayFfmpeg;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.Rendering.PostProcessing;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: StraftatMod(true)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("streplay")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.2.0")]
[assembly: AssemblyInformationalVersion("1.1.2+1b240207a82c4306dc9aedbfc8c08bc923cd65f6")]
[assembly: AssemblyProduct("streplay")]
[assembly: AssemblyTitle("streplay")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.2.0")]
[module: UnverifiableCode]
[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 Streplay
{
	internal static class AudioCapture
	{
		[ThreadStatic]
		internal static int RpcDepth;

		internal static int ReplayPlays;

		internal static readonly List<string> ReplayClips = new List<string>();

		internal static bool OwnPlay;

		public static void Install(Harmony harmony)
		{
			Type typeFromHandle = typeof(AudioSource);
			Patch(harmony, typeFromHandle.GetMethod("PlayOneShot", new Type[2]
			{
				typeof(AudioClip),
				typeof(float)
			}), "PlayOneShotPostfix");
			Patch(harmony, typeFromHandle.GetMethod("Play", Type.EmptyTypes), "PlayPostfix");
			Patch(harmony, typeFromHandle.GetMethod("Play", new Type[1] { typeof(ulong) }), "PlayPostfix");
			Patch(harmony, typeFromHandle.GetMethod("PlayDelayed", new Type[1] { typeof(float) }), "PlayPostfix");
		}

		private static void Patch(Harmony harmony, MethodInfo target, string postfix)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			try
			{
				if (target == null)
				{
					throw new MissingMethodException("AudioSource", postfix);
				}
				harmony.Patch((MethodBase)target, (HarmonyMethod)null, new HarmonyMethod(typeof(AudioCapture).GetMethod(postfix, BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not hook AudioSource for sound capture: " + ex.Message));
			}
		}

		private static void PlayOneShotPostfix(AudioSource __instance, AudioClip clip, float volumeScale)
		{
			Observe(__instance, clip, volumeScale, fromPlay: false);
		}

		private static void PlayPostfix(AudioSource __instance)
		{
			Observe(__instance, ((Object)(object)__instance != (Object)null) ? __instance.clip : null, 1f, fromPlay: true);
		}

		private static void Observe(AudioSource src, AudioClip clip, float volumeScale, bool fromPlay)
		{
			try
			{
				if ((Object)(object)src == (Object)null || (Object)(object)clip == (Object)null)
				{
					return;
				}
				if (ReplayPlayer.Active)
				{
					if (!OwnPlay && ((Behaviour)src).isActiveAndEnabled)
					{
						ReplayPlays++;
						if (ReplayClips.Count < 64)
						{
							ReplayClips.Add(((Object)clip).name);
						}
					}
				}
				else
				{
					Recorder instance = Recorder.Instance;
					if ((Object)(object)instance != (Object)null && instance.IsRecording)
					{
						instance.OnSound(src, clip, volumeScale, fromPlay, RpcDepth > 0);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Sound capture failed: " + ex.Message));
			}
		}
	}
	internal sealed class AudioTap : MonoBehaviour
	{
		private readonly object _lock = new object();

		private List<float> _samples = new List<float>();

		private volatile bool _on;

		private int _channels = 2;

		public int SampleRate { get; private set; }

		public int Channels
		{
			get
			{
				lock (_lock)
				{
					return _channels;
				}
			}
		}

		public int Frames
		{
			get
			{
				lock (_lock)
				{
					return _samples.Count / Math.Max(1, _channels);
				}
			}
		}

		public void Begin()
		{
			SampleRate = AudioSettings.outputSampleRate;
			lock (_lock)
			{
				_samples = new List<float>(SampleRate * 2 * 30);
			}
			_on = true;
		}

		public void Stop()
		{
			_on = false;
		}

		private void OnAudioFilterRead(float[] data, int channels)
		{
			if (_on)
			{
				lock (_lock)
				{
					_channels = channels;
					_samples.AddRange(data);
				}
				if (Plugin.RenderMuteSoundPass.Value)
				{
					Array.Clear(data, 0, data.Length);
				}
			}
		}

		public void WriteWavMapped(string path, int frames, Func<int, double> srcFrame, float gain)
		{
			float[] array;
			int num;
			lock (_lock)
			{
				array = _samples.ToArray();
				num = Math.Max(1, _channels);
			}
			int num2 = array.Length / num;
			using BinaryWriter binaryWriter = new BinaryWriter(File.Create(path));
			WriteHeader(binaryWriter, frames, num);
			for (int i = 0; i < frames; i++)
			{
				double num3 = srcFrame(i);
				int num4 = (int)Math.Floor(num3);
				float num5 = (float)(num3 - (double)num4);
				for (int j = 0; j < num; j++)
				{
					float num6 = ((num4 >= 0 && num4 < num2) ? array[num4 * num + j] : 0f);
					float num7 = ((num4 + 1 >= 0 && num4 + 1 < num2) ? array[(num4 + 1) * num + j] : num6);
					binaryWriter.Write((short)Mathf.Clamp(Mathf.RoundToInt((num6 + (num7 - num6) * num5) * gain * 32767f), -32768, 32767));
				}
			}
		}

		private void WriteHeader(BinaryWriter w, int frames, int ch)
		{
			int num = frames * ch * 2;
			w.Write(new char[4] { 'R', 'I', 'F', 'F' });
			w.Write(36 + num);
			w.Write(new char[8] { 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ' });
			w.Write(16);
			w.Write((short)1);
			w.Write((short)ch);
			w.Write(SampleRate);
			w.Write(SampleRate * ch * 2);
			w.Write((short)(ch * 2));
			w.Write((short)16);
			w.Write(new char[4] { 'd', 'a', 't', 'a' });
			w.Write(num);
		}

		public void WriteWav(string path, int frames)
		{
			float[] array;
			int num;
			lock (_lock)
			{
				array = _samples.ToArray();
				num = Math.Max(1, _channels);
			}
			using BinaryWriter binaryWriter = new BinaryWriter(File.Create(path));
			int num2 = frames * num * 2;
			binaryWriter.Write(new char[4] { 'R', 'I', 'F', 'F' });
			binaryWriter.Write(36 + num2);
			binaryWriter.Write(new char[8] { 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ' });
			binaryWriter.Write(16);
			binaryWriter.Write((short)1);
			binaryWriter.Write((short)num);
			binaryWriter.Write(SampleRate);
			binaryWriter.Write(SampleRate * num * 2);
			binaryWriter.Write((short)(num * 2));
			binaryWriter.Write((short)16);
			binaryWriter.Write(new char[4] { 'd', 'a', 't', 'a' });
			binaryWriter.Write(num2);
			for (int i = 0; i < frames * num; i++)
			{
				binaryWriter.Write((short)((i < array.Length) ? ((short)Mathf.Clamp(Mathf.RoundToInt(array[i] * 32767f), -32768, 32767)) : 0));
			}
		}
	}
	internal sealed class DebugDump : MonoBehaviour
	{
		private void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = Plugin.DumpKey.Value;
			if (!((KeyboardShortcut)(ref value)).IsDown())
			{
				return;
			}
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				Scene activeScene = SceneManager.GetActiveScene();
				stringBuilder.AppendLine($"Scene: {((Scene)(ref activeScene)).name}  replay={ReplayPlayer.Active}  time={DateTime.Now}");
				ClientManager clientManager = InstanceFinder.ClientManager;
				if (!ReplayPlayer.Active && (Object)(object)clientManager != (Object)null && clientManager.Started)
				{
					DumpCanvases(stringBuilder);
					FirstPersonController val = (((Object)(object)Settings.Instance != (Object)null) ? Settings.Instance.localPlayer : null);
					PlayerSetup val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<PlayerSetup>() : null);
					if ((Object)(object)val2 != (Object)null && AccessTools.Field(typeof(PlayerSetup), "cameras")?.GetValue(val2) is Camera[] array)
					{
						for (int i = 0; i < array.Length; i++)
						{
							if ((Object)(object)array[i] != (Object)null)
							{
								stringBuilder.AppendLine($"player camera[{i}] {((Object)array[i]).name} enabled={((Behaviour)array[i]).enabled} fov={array[i].fieldOfView} depth={array[i].depth} " + $"clear={array[i].clearFlags} mask={array[i].cullingMask:X8} near={array[i].nearClipPlane} path={Recorder.ScenePath(((Component)array[i]).transform)}");
							}
						}
					}
					foreach (NetworkObject item in from n in ((ManagedObjects)clientManager.Objects).Spawned.Values
						where (Object)(object)n != (Object)null && (Object)(object)n.ParentNetworkObject == (Object)null
						orderby n.ObjectId
						select n)
					{
						stringBuilder.AppendLine($"=== #{item.ObjectId} {((Object)item).name} prefab={item.SpawnableCollectionId}:{item.PrefabId} scene={Net.SceneId(item)} owner={item.IsOwner}");
						Dump(stringBuilder, ((Component)item).transform, 1);
					}
				}
				else
				{
					activeScene = SceneManager.GetActiveScene();
					GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
					foreach (GameObject val3 in rootGameObjects)
					{
						Dump(stringBuilder, val3.transform, 0);
					}
				}
				string text = Path.Combine(Plugin.ReplayFolder.Value, "dump_" + DateTime.Now.ToString("yyyyMMdd_HHmmss", CultureInfo.InvariantCulture) + ".txt");
				File.WriteAllText(text, stringBuilder.ToString());
				Plugin.Log.LogInfo((object)("Wrote " + text));
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Dump failed: {arg}");
			}
		}

		private static void DumpCanvases(StringBuilder sb)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0099: Unknown result type (might be due to invalid IL or missing references)
			Canvas[] array = Resources.FindObjectsOfTypeAll<Canvas>();
			foreach (Canvas val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Scene scene = ((Component)val).gameObject.scene;
					if (((Scene)(ref scene)).IsValid() && val.isRootCanvas)
					{
						int num = ((Component)val).GetComponentsInChildren<Graphic>(true).Length;
						int num2 = ((Component)val).GetComponentsInChildren<CanvasGroup>(true).Length;
						string arg = Recorder.ScenePath(((Component)val).transform);
						scene = ((Component)val).gameObject.scene;
						sb.AppendLine($"canvas {arg} scene={((Scene)(ref scene)).name} active={((Behaviour)val).isActiveAndEnabled} " + string.Format("mode={0} cam={1} order={2} graphics={3} groups={4}", val.renderMode, ((Object)(object)val.worldCamera != (Object)null) ? ((Object)val.worldCamera).name : "-", val.sortingOrder, num, num2));
					}
				}
			}
			sb.AppendLine();
		}

		private static void Dump(StringBuilder sb, Transform t, int depth)
		{
			if (depth <= 14)
			{
				IEnumerable<string> values = (from c in ((Component)t).GetComponents<Component>()
					where (Object)(object)c != (Object)null && !(c is Transform)
					select c).Select(delegate(Component c)
				{
					Behaviour val = (Behaviour)(object)((c is Behaviour) ? c : null);
					return (val == null || val.enabled) ? ((object)c).GetType().Name : (((object)c).GetType().Name + "(off)");
				});
				sb.Append(' ', depth * 2).Append(((Component)t).gameObject.activeSelf ? "" : "[inactive] ").Append(((Object)t).name)
					.Append(" layer=")
					.Append(((Component)t).gameObject.layer)
					.Append("  ")
					.AppendLine(string.Join(", ", values));
				for (int num = 0; num < t.childCount; num++)
				{
					Dump(sb, t.GetChild(num), depth + 1);
				}
			}
		}
	}
	internal static class Disk
	{
		public const long Floor = 2147483648L;

		public const long Low = 5368709120L;

		internal static long TestFree = -1L;

		public static long Free(string dir)
		{
			if (TestFree >= 0)
			{
				return TestFree;
			}
			try
			{
				string pathRoot = Path.GetPathRoot(Path.GetFullPath(dir));
				return string.IsNullOrEmpty(pathRoot) ? (-1) : new DriveInfo(pathRoot).AvailableFreeSpace;
			}
			catch
			{
				return -1L;
			}
		}

		public static string Drive(string dir)
		{
			try
			{
				return Path.GetPathRoot(Path.GetFullPath(dir)).TrimEnd('\\');
			}
			catch
			{
				return "the drive";
			}
		}

		public static string Gb(long bytes)
		{
			return ((double)bytes / 1073741824.0).ToString((bytes < 10737418240L) ? "0.0" : "0", CultureInfo.InvariantCulture) + " GB";
		}
	}
	[HarmonyPatch]
	internal static class GameSuspend
	{
		[HarmonyPatch(typeof(PauseManager), "Update")]
		[HarmonyPrefix]
		private static bool PauseManagerUpdate()
		{
			return !ReplayPlayer.SuspendGame;
		}

		[HarmonyPatch(typeof(PauseManager), "Menu")]
		[HarmonyPrefix]
		private static bool PauseManagerMenu()
		{
			return !ReplayPlayer.SuspendGame;
		}
	}
	[HarmonyPatch]
	internal static class ReplayNoise
	{
		[HarmonyPatch(typeof(KillCam), "OnDisable")]
		[HarmonyFinalizer]
		private static Exception KillCamOnDisable(Exception __exception)
		{
			if (!ReplayPlayer.Active)
			{
				return __exception;
			}
			return null;
		}

		[HarmonyPatch(typeof(PlayerHealth), "Awake___UserLogic")]
		[HarmonyFinalizer]
		private static Exception PlayerHealthAwake(Exception __exception)
		{
			if (!ReplayPlayer.Active)
			{
				return __exception;
			}
			return null;
		}
	}
	internal static class Highlights
	{
		internal sealed class KillRec
		{
			public float T;

			public float ShotT;

			public string Victim = "";

			public string Weapon = "";

			public string Held = "";

			public bool Headshot;

			public bool Airborne;

			public bool Scoped;

			public bool QuickScope;

			public float Distance;

			public float Speed;

			public int Health;

			public float FlickDeg;

			public float FlickPeak;

			public float Straight = 1f;

			public float FlickGap;

			public int Corrections;

			public int Shots = -1;

			private float _score = -1f;

			[JsonIgnore]
			public bool NoScope
			{
				get
				{
					if (!Scoped)
					{
						return IsScopeGun(Held);
					}
					return false;
				}
			}

			[JsonIgnore]
			public bool CleanFlick
			{
				get
				{
					if (FlickDeg >= 35f && FlickPeak >= 600f && Straight >= 0.85f && Corrections <= 1)
					{
						return FlickGap <= 0.3f;
					}
					return false;
				}
			}

			public float Score()
			{
				if (_score >= 0f)
				{
					return _score;
				}
				float num = WeaponWeight(Weapon);
				float num2 = 1f;
				if (FlickDeg >= 35f && FlickPeak >= 600f)
				{
					float num3 = Mathf.Clamp01((Straight - 0.6f) / 0.35f) * ((Corrections == 0) ? 1f : ((Corrections == 1) ? 0.7f : 0.35f)) * ((FlickGap <= 0.3f) ? 1f : ((FlickGap <= 0.6f) ? 0.5f : 0.2f));
					num2 += num3 * (1.2f + Mathf.Clamp((FlickDeg - 35f) / 60f, 0f, 1.6f) + Mathf.Clamp((FlickPeak - 600f) / 1200f, 0f, 0.8f));
				}
				else if (Corrections >= 3)
				{
					num2 -= 0.3f;
				}
				if (Shots == 1)
				{
					num2 += 0.6f;
				}
				else if (Shots >= 5)
				{
					num2 -= 0.6f;
				}
				if (Headshot)
				{
					num2 += 0.7f;
				}
				num2 += Mathf.Clamp((Distance - 20f) / 30f, 0f, 1f);
				if (QuickScope)
				{
					num2 += 1f;
				}
				if (NoScope)
				{
					num2 += 0.9f;
				}
				if (Health > 0 && Health <= 35)
				{
					num2 += 0.5f;
				}
				if (num >= 1f)
				{
					if (Airborne)
					{
						num2 += 0.4f;
					}
					num2 += Mathf.Clamp((Speed - 10f) / 15f, 0f, 0.6f);
				}
				return _score = num2 * num;
			}
		}

		private static class Tuning
		{
			public const float FlickMinDeg = 35f;

			public const float FlickMinPeak = 600f;
		}

		private sealed class Context
		{
			private readonly ReplayData _d;

			private readonly int _local;

			private readonly float _restFov;

			private readonly UiElementInfo _speedHud;

			private readonly UiElementInfo _healthHud;

			public readonly Dictionary<string, float> LocalZoom = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

			private static readonly Regex SpeedRx = new Regex("speed\\s*:?\\s*([0-9]+(?:[.,][0-9]+)?)", RegexOptions.IgnoreCase);

			private static readonly Regex HealthRx = new Regex("health\\s*:?\\s*([0-9]+)", RegexOptions.IgnoreCase);

			private List<float> _shots;

			public Context(ReplayData d, int local)
			{
				_d = d;
				_local = local;
				_restFov = Median(from x in d.Frames
					select x.CamFov into v
					where v > 1f
					select v);
				foreach (UiElementInfo value2 in d.Ui.Values)
				{
					if (value2.Kind == UiKind.Text && !value2.Dynamic)
					{
						if (_speedHud == null && value2.States.Any((UiState s) => s.Text != null && SpeedRx.IsMatch(s.Text)))
						{
							_speedHud = value2;
						}
						if (_healthHud == null && value2.Path.IndexOf("Enemy", StringComparison.OrdinalIgnoreCase) < 0 && value2.States.Any((UiState s) => s.Text != null && HealthRx.IsMatch(s.Text)))
						{
							_healthHud = value2;
						}
					}
				}
				foreach (Frame frame in d.Frames)
				{
					if (!Scoped(frame))
					{
						continue;
					}
					string text = Held(frame);
					if (text != null)
					{
						float num = frame.CamFov / _restFov;
						if (!LocalZoom.TryGetValue(text, out var value) || num < value)
						{
							LocalZoom[text] = num;
						}
					}
				}
				MergeZoom(LocalZoom);
			}

			private bool Scoped(Frame f)
			{
				if (f.CamFov > 1f && _restFov > 1f)
				{
					return f.CamFov < _restFov * 0.8f;
				}
				return false;
			}

			private ObjState Me(Frame f)
			{
				ObjState[] objects = f.Objects;
				foreach (ObjState objState in objects)
				{
					ObjectInfo objectInfo = _d.Objects[objState.Obj];
					if (objectInfo.Player != null && objectInfo.Player.PlayerId == _local && objState.Active)
					{
						return objState;
					}
				}
				return null;
			}

			private string Held(Frame f)
			{
				ObjState objState = Me(f);
				if (objState == null || objState.HeldRight < 0 || objState.HeldRight >= _d.Objects.Count)
				{
					return null;
				}
				string name = _d.Objects[objState.HeldRight].Name;
				int num = name.IndexOf("(Clone)", StringComparison.Ordinal);
				if (num <= 0)
				{
					return name;
				}
				return name.Substring(0, num).Trim();
			}

			private void MeasureAim(KillRec k)
			{
				//IL_0085: Unknown result type (might be due to invalid IL or missing references)
				//IL_008c: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cb: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
				//IL_017f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0190: 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_01c4: Unknown result type (might be due to invalid IL or missing references)
				List<Frame> frames = _d.Frames;
				int num = FrameAt(frames, k.ShotT);
				int num2 = FrameAt(frames, k.ShotT - 0.8f);
				if (num - num2 < 4)
				{
					return;
				}
				int num3 = num - num2;
				float[] array = new float[num3];
				float[] array2 = new float[num3];
				for (int i = 0; i < num3; i++)
				{
					Frame frame = frames[num2 + i];
					Frame frame2 = frames[num2 + i + 1];
					float num4 = frame2.T - frame.T;
					if (!(num4 <= 0.0001f))
					{
						float num5 = Quaternion.Angle(frame.CamRot, frame2.CamRot);
						if (num5 / num4 > 6000f)
						{
							return;
						}
						array[i] = num5 / num4;
						array2[i] = Mathf.DeltaAngle((frame.CamRot * Vector3.forward).Yaw(), (frame2.CamRot * Vector3.forward).Yaw()) / num4;
					}
				}
				int num6 = 0;
				for (int j = 1; j < num3; j++)
				{
					if (array[j] > array[num6])
					{
						num6 = j;
					}
				}
				float num7 = array[num6];
				int num8 = num6;
				int l = num6;
				while (num8 > 0 && array[num8 - 1] > 0.3f * num7)
				{
					num8--;
				}
				for (; l < num3 - 1 && array[l + 1] > 0.3f * num7; l++)
				{
				}
				float num9 = 0f;
				for (int m = num8; m <= l; m++)
				{
					num9 += Quaternion.Angle(frames[num2 + m].CamRot, frames[num2 + m + 1].CamRot);
				}
				float num10 = Quaternion.Angle(frames[num2 + num8].CamRot, frames[num2 + l + 1].CamRot);
				k.FlickPeak = num7;
				k.FlickDeg = num10;
				k.Straight = ((num9 > 0.001f) ? (num10 / num9) : 1f);
				k.FlickGap = Mathf.Max(0f, k.ShotT - frames[num2 + l + 1].T);
				int num11 = 0;
				for (int n = 0; n < num3; n++)
				{
					if (!(frames[num2 + n].T < k.ShotT - 0.4f))
					{
						int num12 = ((array2[n] > 40f) ? 1 : ((array2[n] < -40f) ? (-1) : 0));
						if (num12 != 0 && num11 != 0 && num12 != num11)
						{
							k.Corrections++;
						}
						if (num12 != 0)
						{
							num11 = num12;
						}
					}
				}
			}

			private float? Hud(UiElementInfo el, Regex rx, float t)
			{
				if (el == null)
				{
					return null;
				}
				int num = FrameAt(_d.Frames, t);
				int num2 = -1;
				for (int i = 0; i < el.Frames.Count && el.Frames[i] <= num; i++)
				{
					num2 = i;
				}
				if (num2 < 0 || el.States[num2].Text == null)
				{
					return null;
				}
				Match match = rx.Match(el.States[num2].Text);
				if (!match.Success || !float.TryParse(match.Groups[1].Value.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
				{
					return null;
				}
				return result;
			}

			private List<float> Shots()
			{
				if (_shots != null)
				{
					return _shots;
				}
				_shots = new List<float>();
				foreach (ReplayEvent @event in _d.Events)
				{
					if (@event.Method.StartsWith("Shoot", StringComparison.Ordinal))
					{
						ObjState objState = Me(_d.Frames[FrameAt(_d.Frames, @event.T)]);
						if (objState != null && (@event.Obj == objState.HeldRight || @event.Obj == objState.HeldLeft))
						{
							_shots.Add(@event.T);
						}
					}
				}
				return _shots;
			}

			public void Measure(KillRec k, int victimId)
			{
				//IL_0218: Unknown result type (might be due to invalid IL or missing references)
				//IL_021f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0224: Unknown result type (might be due to invalid IL or missing references)
				//IL_022e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0233: Unknown result type (might be due to invalid IL or missing references)
				//IL_0398: Unknown result type (might be due to invalid IL or missing references)
				//IL_039d: Unknown result type (might be due to invalid IL or missing references)
				List<Frame> frames = _d.Frames;
				List<float> list = Shots();
				float num = list.Where((float x) => x <= k.T + 0.02f && x >= k.T - 0.6f).DefaultIfEmpty(-1f).Max();
				k.ShotT = ((num >= 0f) ? num : (k.T - 0.03f));
				k.Shots = ((list.Count > 0) ? list.Count((float x) => x <= k.T + 0.02f && x >= k.T - 1.2f) : (-1));
				if (k.Shots == 0)
				{
					k.Shots = -1;
				}
				MeasureAim(k);
				int num2 = FrameAt(frames, k.T);
				Frame frame = frames[num2];
				k.Scoped = Scoped(frame);
				if (k.Scoped)
				{
					bool quickScope = false;
					for (int num3 = FrameAt(frames, k.T - 0.45f); num3 < FrameAt(frames, k.T - 0.08f); num3++)
					{
						if (!Scoped(frames[num3]))
						{
							quickScope = true;
							break;
						}
					}
					k.QuickScope = quickScope;
				}
				k.Held = Held(frame) ?? Held(frames[FrameAt(frames, k.T - 0.1f)]) ?? "";
				ObjState[] objects = frames[FrameAt(frames, k.T - 0.05f)].Objects;
				foreach (ObjState objState in objects)
				{
					ObjectInfo objectInfo = _d.Objects[objState.Obj];
					if (objectInfo.Player != null && objState.Active && objectInfo.Player.PlayerId == victimId)
					{
						k.Distance = Mathf.Max(k.Distance, Vector3.Distance(frame.CamPos, objState.Pos + Vector3.up * 1.2f));
					}
				}
				Frame frame2 = frames[FrameAt(frames, k.T - 0.15f)];
				ObjState objState2 = Me(frame2);
				ObjState objState3 = Me(frame);
				if (objState2 != null && objState3 != null && frame.T - frame2.T > 0.05f)
				{
					float num5 = (objState3.Pos.y - objState2.Pos.y) / (frame.T - frame2.T);
					float num6 = float.MaxValue;
					for (int num7 = FrameAt(frames, k.T - 1.5f); num7 <= num2; num7++)
					{
						ObjState objState4 = Me(frames[num7]);
						if (objState4 != null)
						{
							num6 = Mathf.Min(num6, objState4.Pos.y);
						}
					}
					k.Airborne = Mathf.Abs(num5) > 2.5f || objState3.Pos.y - num6 > 1.5f;
					Vector2 val = new Vector2(objState3.Pos.x - objState2.Pos.x, objState3.Pos.z - objState2.Pos.z);
					float num8 = ((Vector2)(ref val)).magnitude / (frame.T - frame2.T);
					k.Speed = Hud(_speedHud, SpeedRx, k.T) ?? num8;
				}
				k.Health = Mathf.RoundToInt(Hud(_healthHud, HealthRx, k.T - 0.05f).GetValueOrDefault());
			}
		}

		public const int Version = 6;

		public const int FeaturesVersion = 1;

		private static readonly Regex Tag = new Regex("<[^>]*>");

		internal static readonly Regex Who = new Regex("\\{PLAYER_NAME\\}:\\{(\\d+)\\}");

		private static Dictionary<string, float> _weights;

		private static string _weightsFrom;

		private static readonly Dictionary<string, float> Zoom = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		private const float ScopeZoom = 0.35f;

		private static Thread _thread;

		private static volatile int _done;

		private static volatile int _total;

		internal static int Changes;

		public static bool Scanning
		{
			get
			{
				if (_thread != null)
				{
					return _thread.IsAlive;
				}
				return false;
			}
		}

		public static string Progress
		{
			get
			{
				if (!Scanning)
				{
					return null;
				}
				return $"Finding highlights {_done}/{_total}…";
			}
		}

		public static List<ReplayMeta.MetaHighlight> Analyze(ReplayData data, ReplayMeta meta)
		{
			Measure(data, meta);
			return Score(meta);
		}

		private static void Measure(ReplayData data, ReplayMeta meta)
		{
			List<ObjectInfo> players = data.Objects.Where((ObjectInfo o) => o.Player != null).ToList();
			int num = (players.FirstOrDefault((ObjectInfo o) => o.Player.IsLocal)?.Player)?.PlayerId ?? meta.Players.FirstOrDefault((ReplayMeta.MetaPlayer p) => p.IsLocal)?.PlayerId ?? (-1);
			Context context = new Context(data, num);
			List<KillRec> list = new List<KillRec>();
			List<float> list2 = new List<float>();
			if (num >= 0)
			{
				foreach (ReplayEvent @event in data.Events)
				{
					if (@event.Method != "RpcSendChatLineToAllObservers" || @event.Args.Length == 0 || !(@event.Args[0] is string input))
					{
						continue;
					}
					string text = Tag.Replace(input, "").Trim();
					List<int> list3 = (from Match x in Who.Matches(text)
						select int.Parse(x.Groups[1].Value)).ToList();
					if (text.EndsWith(" won the take", StringComparison.Ordinal))
					{
						if (list3.Contains(num))
						{
							list2.Add(@event.T);
						}
						continue;
					}
					int num2 = text.LastIndexOf(" by ", StringComparison.Ordinal);
					if (list3.Count != 2 || num2 < 0 || !text.Contains(" was ") || list3[1] != num || list3[0] == num)
					{
						continue;
					}
					KillRec killRec = new KillRec
					{
						T = @event.T,
						Victim = Name(list3[0]),
						Headshot = text.Contains(" headshot ")
					};
					int num3 = text.IndexOf(" with a", StringComparison.Ordinal);
					if (num3 >= 0)
					{
						int num4 = text.IndexOf(' ', num3 + 6) + 1;
						if (num4 > 0 && num4 < num2)
						{
							killRec.Weapon = text.Substring(num4, num2 - num4).Trim();
						}
					}
					context.Measure(killRec, list3[0]);
					list.Add(killRec);
				}
			}
			meta.KillRecs = list;
			meta.TakeWins = list2;
			meta.WeaponZoom = context.LocalZoom;
			meta.FeaturesVersion = 1;
			string Name(int id)
			{
				string text2 = players.FirstOrDefault((ObjectInfo o) => o.Player.PlayerId == id)?.Player.Name;
				if (text2 == null || text2.Length <= 0)
				{
					string text3 = meta.Players.FirstOrDefault((ReplayMeta.MetaPlayer p) => p.PlayerId == id)?.Name;
					if (text3 == null)
					{
						return $"player {id}";
					}
					return Tag.Replace(text3, "");
				}
				return Tag.Replace(text2, "");
			}
		}

		public static List<ReplayMeta.MetaHighlight> Score(ReplayMeta meta)
		{
			List<KillRec> list = meta.KillRecs ?? new List<KillRec>();
			List<float> source = meta.TakeWins ?? new List<float>();
			List<ReplayMeta.MetaHighlight> list2 = new List<ReplayMeta.MetaHighlight>();
			List<ReplayMeta.MetaMarker> source2 = meta.Markers.Where((ReplayMeta.MetaMarker m) => !m.Auto).ToList();
			HashSet<ReplayMeta.MetaMarker> usedFlags = new HashSet<ReplayMeta.MetaMarker>();
			float value = Plugin.HighlightChain.Value;
			int num = 0;
			while (num < list.Count)
			{
				int num2;
				for (num2 = num + 1; num2 < list.Count && list[num2].T - list[num2 - 1].T <= value; num2++)
				{
				}
				List<KillRec> range = list.GetRange(num, num2 - num);
				num = num2;
				float t0 = range[0].T;
				float t1 = range[range.Count - 1].T;
				float num3 = t1 - t0;
				List<ReplayMeta.MetaMarker> list3 = source2.Where((ReplayMeta.MetaMarker f) => f.T >= t0 - 1.5f && f.T <= t1 + 1.5f).ToList();
				foreach (ReplayMeta.MetaMarker item in list3)
				{
					usedFlags.Add(item);
				}
				bool num4 = source.Any((float w) => w >= t1 && w - t1 < 3f);
				List<float> list4 = (from k in range
					select k.Score() into x
					orderby x descending
					select x).ToList();
				float num5 = list4[0] + 0.3f * list4.Skip(1).Sum();
				if (range.Count > 1)
				{
					num5 += 0.35f * (float)(range.Count - 1) + 0.3f * Mathf.Clamp01((4f - num3) / 4f);
				}
				if (num4)
				{
					num5 += 0.3f;
				}
				if (list3.Count > 0)
				{
					num5 += 3f;
				}
				int num6 = range.Count((KillRec k) => k.Headshot);
				float num7 = range.Max((KillRec k) => k.Distance);
				float num8 = range.Max((KillRec k) => k.Speed);
				range.OrderByDescending((KillRec k) => k.Score()).First();
				List<string> list5 = new List<string>();
				if (range.Count > 1)
				{
					list5.Add($"{range.Count}K" + ((num3 < 2f) ? " fast" : ""));
				}
				KillRec killRec = (from k in range
					where k.CleanFlick
					orderby k.FlickDeg descending
					select k).FirstOrDefault();
				if (killRec != null)
				{
					list5.Add($"flick {killRec.FlickDeg:0}°");
				}
				if (num6 > 0)
				{
					list5.Add((num6 > 1) ? $"{num6} headshots" : "headshot");
				}
				if (range.Any((KillRec k) => k.QuickScope))
				{
					list5.Add("quickscope");
				}
				if (range.Any((KillRec k) => k.NoScope))
				{
					list5.Add("no-scope");
				}
				if (range.All((KillRec k) => k.Shots == 1))
				{
					list5.Add((range.Count > 1) ? "one-taps" : "one-tap");
				}
				else if (range.Any((KillRec k) => k.Shots >= 5))
				{
					list5.Add("spray");
				}
				if (num7 >= 25f)
				{
					list5.Add($"{num7:0} m");
				}
				if (range.Any((KillRec k) => k.Airborne))
				{
					list5.Add("airborne");
				}
				if (num8 >= 12f)
				{
					list5.Add($"fast {num8:0} m/s");
				}
				int num9 = (from k in range
					where k.Health > 0 && k.Health <= 35
					select k.Health).DefaultIfEmpty(0).Min();
				if (num9 > 0)
				{
					list5.Add($"low hp {num9}");
				}
				if (num4)
				{
					list5.Add("take winner");
				}
				if (list3.Count > 0)
				{
					list5.Add("flagged");
				}
				IEnumerable<string> enumerable = (from k in range
					select k.Weapon into w
					where w.Length > 0
					select w).Distinct();
				list2.Add(new ReplayMeta.MetaHighlight
				{
					T0 = t0,
					T1 = t1,
					Kills = range.Count,
					Score = (float)Math.Round(num5, 1),
					KillT = range.Select((KillRec k) => k.T).ToList(),
					Tags = list5,
					Detail = string.Join(", ", range.Select((KillRec k) => k.Victim).Distinct()) + (enumerable.Any() ? (" · " + string.Join(", ", enumerable)) : "")
				});
			}
			foreach (ReplayMeta.MetaMarker item2 in source2.Where((ReplayMeta.MetaMarker f) => !usedFlags.Contains(f)))
			{
				list2.Add(new ReplayMeta.MetaHighlight
				{
					T0 = item2.T,
					T1 = item2.T,
					Kills = 0,
					Score = 3f,
					Tags = new List<string> { "flagged" },
					Detail = item2.Label
				});
			}
			return list2.OrderBy((ReplayMeta.MetaHighlight h) => h.T0).ToList();
		}

		private static float WeaponWeight(string weapon)
		{
			string text = Plugin.HighlightWeaponWeights?.Value ?? "";
			if (_weights == null || _weightsFrom != text)
			{
				Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);
				string[] array = text.Split(',');
				foreach (string text2 in array)
				{
					int num = text2.IndexOf('=');
					if (num > 0 && float.TryParse(text2.Substring(num + 1).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
					{
						dictionary[text2.Substring(0, num).Trim()] = Mathf.Clamp(result, 0f, 5f);
					}
				}
				_weights = dictionary;
				_weightsFrom = text;
			}
			if (string.IsNullOrEmpty(weapon))
			{
				return 1f;
			}
			foreach (KeyValuePair<string, float> weight in _weights)
			{
				if (weapon.IndexOf(weight.Key, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return weight.Value;
				}
			}
			return 1f;
		}

		private static bool IsScopeGun(string weapon)
		{
			lock (Zoom)
			{
				float value;
				return weapon != null && Zoom.TryGetValue(weapon, out value) && value < 0.35f;
			}
		}

		private static void MergeZoom(Dictionary<string, float> zoom)
		{
			if (zoom == null)
			{
				return;
			}
			lock (Zoom)
			{
				foreach (KeyValuePair<string, float> item in zoom)
				{
					if (!Zoom.TryGetValue(item.Key, out var value) || item.Value < value)
					{
						Zoom[item.Key] = item.Value;
					}
				}
			}
		}

		internal static string ZoomSummary()
		{
			lock (Zoom)
			{
				return string.Join(", ", from z in Zoom
					orderby z.Value
					select $"{z.Key} {z.Value:0.00}");
			}
		}

		public static List<(float T, int Victim)> LocalKills(ReplayData data, ReplayMeta meta)
		{
			List<(float, int)> list = new List<(float, int)>();
			int num = data.Objects.FirstOrDefault((ObjectInfo o) => o.Player != null && o.Player.IsLocal)?.Player.PlayerId ?? meta?.Players.FirstOrDefault((ReplayMeta.MetaPlayer p) => p.IsLocal)?.PlayerId ?? (-1);
			if (num < 0)
			{
				return list;
			}
			foreach (ReplayEvent @event in data.Events)
			{
				if (!(@event.Method != "RpcSendChatLineToAllObservers") && @event.Args.Length != 0 && @event.Args[0] is string input)
				{
					string text = Tag.Replace(input, "");
					List<int> list2 = (from Match x in Who.Matches(text)
						select int.Parse(x.Groups[1].Value)).ToList();
					if (list2.Count == 2 && text.Contains(" was ") && text.Contains(" by ") && list2[1] == num && list2[0] != num)
					{
						list.Add((@event.T, list2[0]));
					}
				}
			}
			return list;
		}

		private static float Yaw(this Vector3 f)
		{
			//IL_0000: 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)
			return Mathf.Atan2(f.x, f.z) * 57.29578f;
		}

		private static int FrameAt(List<Frame> frames, float t)
		{
			int num = 0;
			int num2 = frames.Count - 1;
			while (num < num2)
			{
				int num3 = num + num2 + 1 >> 1;
				if (frames[num3].T <= t)
				{
					num = num3;
				}
				else
				{
					num2 = num3 - 1;
				}
			}
			return num;
		}

		private static float Median(IEnumerable<float> values)
		{
			List<float> list = values.OrderBy((float x) => x).ToList();
			if (list.Count != 0)
			{
				return list[list.Count / 2];
			}
			return 0f;
		}

		public static void Scan(List<ReplayMeta> metas)
		{
			if (Scanning)
			{
				return;
			}
			string recording = (((Object)(object)Recorder.Instance != (Object)null) ? Recorder.Instance.CurrentMetaPath : null);
			List<ReplayMeta> todo = metas.Where((ReplayMeta m) => m.HighlightsVersion < 6 && (m.Finished || !string.Equals(m.MetaPath, recording, StringComparison.OrdinalIgnoreCase))).ToList();
			if (todo.Count == 0)
			{
				return;
			}
			foreach (ReplayMeta meta in metas)
			{
				MergeZoom(meta.WeaponZoom);
			}
			_done = 0;
			_total = todo.Count;
			_thread = new Thread((ThreadStart)delegate
			{
				int num = 0;
				Stopwatch stopwatch = Stopwatch.StartNew();
				foreach (ReplayMeta item in todo)
				{
					try
					{
						ReplayMeta work = ReplayMeta.Load(item.MetaPath);
						if (work == null)
						{
							item.HighlightsVersion = 6;
							_done++;
							continue;
						}
						bool flag = work.FeaturesVersion == 1 && work.KillRecs != null;
						if (!flag || !work.Finished)
						{
							ReplayData replayData = ReplayIO.Read(work.ReplayPath);
							if (!flag)
							{
								Measure(replayData, work);
								num++;
							}
							if (!work.Finished)
							{
								work.Duration = replayData.Duration;
								work.Finished = true;
							}
						}
						List<ReplayMeta.MetaHighlight> found = Score(work);
						ReplayMeta.UpdateFile(item.MetaPath, delegate(ReplayMeta f)
						{
							f.Highlights = found;
							f.HighlightsVersion = 6;
							f.KillRecs = work.KillRecs;
							f.TakeWins = work.TakeWins;
							f.WeaponZoom = work.WeaponZoom;
							f.FeaturesVersion = work.FeaturesVersion;
							if (!f.Finished)
							{
								f.Duration = work.Duration;
								f.Finished = true;
							}
						});
						item.Highlights = found;
						item.HighlightsVersion = 6;
						if (!item.Finished)
						{
							item.Duration = work.Duration;
							item.Finished = true;
						}
					}
					catch (ThreadAbortException)
					{
						throw;
					}
					catch (Exception ex2)
					{
						Plugin.Log.LogWarning((object)("Finding highlights in " + item.ReplayFile + " failed: " + ex2.Message));
						item.HighlightsVersion = 6;
					}
					_done++;
					Interlocked.Increment(ref Changes);
				}
				Plugin.Log.LogInfo((object)$"Highlights: scored {_total} recordings in {stopwatch.Elapsed.TotalSeconds:0}s ({num} read from disk, the rest from stored measurements); weapon zoom: {ZoomSummary()}");
			})
			{
				IsBackground = true,
				Name = "Streplay highlights",
				Priority = ThreadPriority.BelowNormal
			};
			_thread.Start();
		}
	}
	internal enum UiKind : byte
	{
		Graphic,
		Text,
		Group
	}
	internal sealed class UiState
	{
		public bool Visible;

		public Color32 Color;

		public int Sprite = -1;

		public float Fill = 1f;

		public string Text;

		public Vector2 Pos;

		public Vector2 Size;

		public Vector3 Scale = Vector3.one;

		public float RotZ;

		public float Alpha = 1f;

		public bool SameAs(UiState o, bool dynamic = false)
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			if (o != null && Visible == o.Visible)
			{
				if (Visible)
				{
					if (Color.r == o.Color.r && Color.g == o.Color.g && Color.b == o.Color.b && Color.a == o.Color.a && Sprite == o.Sprite && Mathf.Abs(Fill - o.Fill) < 0.001f && Text == o.Text)
					{
						Vector2 val = Pos - o.Pos;
						if (((Vector2)(ref val)).sqrMagnitude < (dynamic ? 2.5E-09f : 0.01f))
						{
							val = Size - o.Size;
							if (((Vector2)(ref val)).sqrMagnitude < (dynamic ? 2.5E-09f : 0.01f))
							{
								Vector3 val2 = Scale - o.Scale;
								if (((Vector3)(ref val2)).sqrMagnitude < 1E-06f && Mathf.Abs(RotZ - o.RotZ) < 0.05f)
								{
									return Mathf.Abs(Alpha - o.Alpha) < 0.002f;
								}
							}
						}
					}
					return false;
				}
				return true;
			}
			return false;
		}

		public void Write(BinaryWriter w, UiKind kind)
		{
			w.Write(Visible);
			if (!Visible)
			{
				return;
			}
			if (kind == UiKind.Group)
			{
				w.Write(Alpha);
				return;
			}
			w.Write(Color.r);
			w.Write(Color.g);
			w.Write(Color.b);
			w.Write(Color.a);
			w.Write(Sprite);
			w.Write(Fill);
			if (kind == UiKind.Text)
			{
				w.Write(Text ?? "");
			}
			w.Write(Pos.x);
			w.Write(Pos.y);
			w.Write(Size.x);
			w.Write(Size.y);
			w.Write(Scale.x);
			w.Write(Scale.y);
			w.Write(Scale.z);
			w.Write(RotZ);
		}

		public static UiState Read(BinaryReader r, UiKind kind)
		{
			//IL_0047: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			UiState uiState = new UiState
			{
				Visible = r.ReadBoolean()
			};
			if (!uiState.Visible)
			{
				return uiState;
			}
			if (kind == UiKind.Group)
			{
				uiState.Alpha = r.ReadSingle();
				return uiState;
			}
			uiState.Color = new Color32(r.ReadByte(), r.ReadByte(), r.ReadByte(), r.ReadByte());
			uiState.Sprite = r.ReadInt32();
			uiState.Fill = r.ReadSingle();
			if (kind == UiKind.Text)
			{
				uiState.Text = r.ReadString();
			}
			uiState.Pos = new Vector2(r.ReadSingle(), r.ReadSingle());
			uiState.Size = new Vector2(r.ReadSingle(), r.ReadSingle());
			uiState.Scale = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
			uiState.RotZ = r.ReadSingle();
			return uiState;
		}
	}
	internal sealed class HudCapture
	{
		private sealed class Elem
		{
			public int Id;

			public UiKind Kind;

			public Component C;

			public UiState Last;

			public bool SeenThisFrame;

			public bool Dynamic;
		}

		private sealed class Root
		{
			public Transform T;

			public byte Anchor;

			public Transform AnchorRoot;
		}

		public const byte AnchorDdol = 0;

		public const byte AnchorLocalPlayer = 1;

		private readonly Dictionary<Component, Elem> _elems = new Dictionary<Component, Elem>();

		private readonly List<Elem> _visibleLast = new List<Elem>();

		private readonly Dictionary<Transform, Component[]> _comps = new Dictionary<Transform, Component[]>();

		private readonly Dictionary<string, int> _strings = new Dictionary<string, int>();

		private readonly List<Root> _roots = new List<Root>();

		private readonly HashSet<GameObject> _excluded = new HashSet<GameObject>();

		private readonly List<(Elem e, UiState s)> _changes = new List<(Elem, UiState)>();

		private float _nextRootScan;

		private Transform _localRoot;

		private static readonly string[] ExcludedPauseFields = new string[6] { "mainMenu", "pauseMenu", "optionsMenu", "firstInterface", "secondInterface", "voiceChatText" };

		private readonly MemoryStream _buf = new MemoryStream(4096);

		private BinaryWriter _bw;

		public void Reset()
		{
			_elems.Clear();
			_visibleLast.Clear();
			_comps.Clear();
			_strings.Clear();
			_roots.Clear();
			_nextRootScan = 0f;
			_localRoot = null;
		}

		public void Sample(BinaryWriter output, NetworkObject localPlayer)
		{
			if (_bw == null)
			{
				_bw = new BinaryWriter(_buf);
			}
			_buf.SetLength(0L);
			SampleInto(_bw, localPlayer);
			_bw.Flush();
			if (_buf.Length > 0)
			{
				output.Write(_buf.GetBuffer(), 0, (int)_buf.Length);
			}
		}

		private void SampleInto(BinaryWriter w, NetworkObject localPlayer)
		{
			Transform val = (((Object)(object)localPlayer != (Object)null) ? ((Component)localPlayer).transform : null);
			if (Time.unscaledTime >= _nextRootScan || (Object)(object)val != (Object)(object)_localRoot)
			{
				_nextRootScan = Time.unscaledTime + 1f;
				_localRoot = val;
				ScanRoots(val);
			}
			foreach (Elem item in _visibleLast)
			{
				item.SeenThisFrame = false;
			}
			_changes.Clear();
			foreach (Root root in _roots)
			{
				if ((Object)(object)root.T != (Object)null && ((Component)root.T).gameObject.activeInHierarchy)
				{
					Walk(w, root, root.T);
				}
			}
			for (int num = _visibleLast.Count - 1; num >= 0; num--)
			{
				Elem elem = _visibleLast[num];
				if (!elem.SeenThisFrame)
				{
					UiState uiState = new UiState
					{
						Visible = false
					};
					if (!uiState.SameAs(elem.Last))
					{
						elem.Last = uiState;
						_changes.Add((elem, uiState));
					}
					_visibleLast.RemoveAt(num);
				}
			}
			if (_changes.Count != 0)
			{
				w.Write((byte)8);
				w.Write((ushort)Math.Min(_changes.Count, 65535));
				for (int i = 0; i < _changes.Count && i < 65535; i++)
				{
					w.Write(_changes[i].e.Id);
					_changes[i].s.Write(w, _changes[i].e.Kind);
				}
			}
		}

		private void ScanRoots(Transform localRoot)
		{
			//IL_00a2: 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_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Invalid comparison between Unknown and I4
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Invalid comparison between Unknown and I4
			_roots.Clear();
			_excluded.Clear();
			PauseManager instance = PauseManager.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				string[] excludedPauseFields = ExcludedPauseFields;
				foreach (string text in excludedPauseFields)
				{
					object? obj = AccessTools.Field(typeof(PauseManager), text)?.GetValue(instance);
					GameObject val = (GameObject)((obj is GameObject) ? obj : null);
					if (val != null && (Object)(object)val != (Object)null)
					{
						_excluded.Add(val);
					}
				}
			}
			if ((Object)(object)VoiceChatUI.Instance != (Object)null)
			{
				_excluded.Add(((Component)VoiceChatUI.Instance).gameObject);
			}
			Scene val2 = Net.DdolScene();
			Canvas[] componentsInChildren;
			if (((Scene)(ref val2)).IsValid())
			{
				GameObject[] rootGameObjects = ((Scene)(ref val2)).GetRootGameObjects();
				for (int i = 0; i < rootGameObjects.Length; i++)
				{
					componentsInChildren = rootGameObjects[i].GetComponentsInChildren<Canvas>(true);
					foreach (Canvas val3 in componentsInChildren)
					{
						if (val3.isRootCanvas && (int)val3.renderMode != 2)
						{
							_roots.Add(new Root
							{
								T = ((Component)val3).transform,
								Anchor = 0
							});
						}
					}
				}
			}
			if (!((Object)(object)localRoot != (Object)null))
			{
				return;
			}
			componentsInChildren = ((Component)localRoot).GetComponentsInChildren<Canvas>(true);
			foreach (Canvas val4 in componentsInChildren)
			{
				if (val4.isRootCanvas && (int)val4.renderMode != 2)
				{
					_roots.Add(new Root
					{
						T = ((Component)val4).transform,
						Anchor = 1,
						AnchorRoot = localRoot
					});
				}
			}
		}

		private void Walk(BinaryWriter w, Root root, Transform t)
		{
			//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_0103: 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)
			if (!((Component)t).gameObject.activeSelf || _excluded.Contains(((Component)t).gameObject))
			{
				return;
			}
			if (!_comps.TryGetValue(t, out var value))
			{
				value = (Component[])(object)new Component[3]
				{
					(Component)((Component)t).GetComponent<Canvas>(),
					(Component)((Component)t).GetComponent<CanvasGroup>(),
					(Component)((Component)t).GetComponent<Graphic>()
				};
				_comps[t] = value;
			}
			Component obj = value[0];
			Canvas val = (Canvas)(object)((obj is Canvas) ? obj : null);
			if (val != null && (Object)(object)val != (Object)null && !((Behaviour)val).enabled)
			{
				return;
			}
			Component obj2 = value[1];
			CanvasGroup val2 = (CanvasGroup)(object)((obj2 is CanvasGroup) ? obj2 : null);
			if (val2 != null && (Object)(object)val2 != (Object)null)
			{
				Visit(w, root, (Component)(object)val2, UiKind.Group);
				if (val2.alpha <= 0.001f)
				{
					return;
				}
			}
			Component obj3 = value[2];
			Graphic val3 = (Graphic)(object)((obj3 is Graphic) ? obj3 : null);
			if (val3 != null && (Object)(object)val3 != (Object)null && ((Behaviour)val3).enabled && !(val3 is TMP_SubMeshUI))
			{
				Visit(w, root, (Component)(object)val3, (val3 is TMP_Text || val3 is Text) ? UiKind.Text : UiKind.Graphic);
			}
			Vector3 localScale = t.localScale;
			if (!((Object)(object)t != (Object)(object)root.T) || (!(Mathf.Abs(localScale.x) < 0.0001f) && !(Mathf.Abs(localScale.y) < 0.0001f)))
			{
				for (int i = 0; i < t.childCount; i++)
				{
					Walk(w, root, t.GetChild(i));
				}
			}
		}

		private void Visit(BinaryWriter w, Root root, Component c, UiKind kind)
		{
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			if (!_elems.TryGetValue(c, out var value))
			{
				value = new Elem
				{
					Id = _elems.Count,
					Kind = kind,
					C = c,
					Dynamic = (kind != UiKind.Group && IsSpawned(c.transform, root.T))
				};
				_elems[c] = value;
				w.Write((byte)7);
				w.Write(value.Id);
				w.Write(root.Anchor);
				w.Write((root.Anchor == 1) ? Recorder.RelPath(root.AnchorRoot, c.transform) : Recorder.ScenePath(c.transform));
				w.Write((byte)kind);
				w.Write(value.Dynamic);
				if (value.Dynamic)
				{
					Image val = (Image)(object)((c is Image) ? c : null);
					TMP_Text val2 = (TMP_Text)(object)((c is TMP_Text) ? c : null);
					w.Write((byte)(((Object)(object)val != (Object)null) ? ((uint)(int)val.type) : 0u));
					w.Write((Object)(object)val != (Object)null && val.preserveAspect);
					w.Write(((Object)(object)val2 != (Object)null && (Object)(object)val2.font != (Object)null) ? ((Object)val2.font).name : "");
					w.Write(((Object)(object)val2 != (Object)null) ? val2.fontSize : 0f);
					w.Write(((Object)(object)val2 != (Object)null) ? ((int)val2.alignment) : 0);
					w.Write(((Object)(object)val2 != (Object)null) ? ((int)val2.fontStyle) : 0);
				}
			}
			UiState uiState = Capture(w, c, kind, value.Dynamic);
			if (!value.SeenThisFrame && (value.Last == null || !value.Last.Visible))
			{
				_visibleLast.Add(value);
			}
			value.SeenThisFrame = true;
			if (!uiState.SameAs(value.Last, value.Dynamic))
			{
				value.Last = uiState;
				_changes.Add((value, uiState));
			}
		}

		private static bool IsSpawned(Transform t, Transform root)
		{
			Transform val = t;
			while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
			{
				if (((Object)val).name.EndsWith("(Clone)", StringComparison.Ordinal))
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private UiState Capture(BinaryWriter w, Component c, UiKind kind, bool dynamic)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_002d: 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_0013: 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_0077: Invalid comparison between Unknown and I4
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: 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_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: 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_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: 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_0169: 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)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			UiState uiState = new UiState
			{
				Visible = true
			};
			if (kind == UiKind.Group)
			{
				uiState.Alpha = ((CanvasGroup)c).alpha;
				return uiState;
			}
			Graphic val = (Graphic)c;
			uiState.Color = Color32.op_Implicit(val.color);
			Image val2 = (Image)(object)((val is Image) ? val : null);
			if (val2 != null)
			{
				uiState.Sprite = (((Object)(object)val2.sprite != (Object)null) ? StringId(w, ((Object)val2.sprite).name) : (-1));
				uiState.Fill = (((int)val2.type == 3) ? val2.fillAmount : 1f);
			}
			TMP_Text val3 = (TMP_Text)(object)((val is TMP_Text) ? val : null);
			if (val3 != null)
			{
				uiState.Text = val3.text;
			}
			else
			{
				Text val4 = (Text)(object)((val is Text) ? val : null);
				if (val4 != null)
				{
					uiState.Text = val4.text;
				}
			}
			RectTransform rectTransform = val.rectTransform;
			if (dynamic)
			{
				Rect rect = rectTransform.rect;
				Vector3 val5 = ((Transform)rectTransform).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center));
				Vector3 lossyScale = ((Transform)rectTransform).lossyScale;
				float num = Mathf.Max(1, Screen.width);
				float num2 = Mathf.Max(1, Screen.height);
				uiState.Pos = new Vector2(val5.x / num, val5.y / num2);
				rect = rectTransform.rect;
				float num3 = ((Rect)(ref rect)).width * lossyScale.x / num;
				rect = rectTransform.rect;
				uiState.Size = new Vector2(num3, ((Rect)(ref rect)).height * lossyScale.y / num);
				uiState.Scale = Vector3.one;
				uiState.RotZ = ((Transform)rectTransform).eulerAngles.z;
				return uiState;
			}
			uiState.Pos = rectTransform.anchoredPosition;
			uiState.Size = rectTransform.sizeDelta;
			uiState.Scale = ((Transform)rectTransform).localScale;
			uiState.RotZ = ((Transform)rectTransform).localEulerAngles.z;
			return uiState;
		}

		private int StringId(BinaryWriter w, string s)
		{
			if (_strings.TryGetValue(s, out var value))
			{
				return value;
			}
			value = _strings.Count;
			_strings[s] = value;
			w.Write((byte)9);
			w.Write(value);
			w.Write(s);
			return value;
		}
	}
	internal sealed class HudReplay
	{
		private sealed class Bound
		{
			public int Part = -1;

			public UiElementInfo Info;

			public Component C;

			public Canvas RootCanvas;

			public string FitFor;

			public int LogBirth = -1;

			public Vector2 LogPos;

			public List<Transform> Collapsed;

			public List<UiElementInfo> Groups;
		}

		private sealed class Snap
		{
			public Component C;

			public bool Enabled;

			public float Alpha;

			public Color Color;

			public Sprite Sprite;

			public float Fill;

			public string Text;

			public TMP_SpriteAsset SpriteAsset;

			public Vector2 Pos;

			public Vector2 Size;

			public Vector3 Scale;

			public Quaternion Rot;
		}

		internal static readonly (string key, string label, string[] paths)[] Parts = new(string, string, string[])[9]
		{
			("Crosshair", "Crosshair", new string[1] { "---USER INTERFACE---/Crosshair" }),
			("Hitmarkers", "Hitmarkers", new string[1] { "HitMarker" }),
			("KillFeed", "Kill feed", new string[1] { "/LogsPosition/" }),
			("Ammo", "Ammo", new string[3] { "/GUN_RIGHT", "/GUN_LEFT", "Ammo" }),
			("Health", "Health", new string[2] { "/HealthDisplay/text", "Health" }),
			("Speed", "Speed", new string[1] { "/Speedometer" }),
			("FpsPing", "FPS / ping", new string[2] { "/HealthDisplay/fps", "/HealthDisplay/ping" }),
			("RoundText", "Round text", new string[3] { "--START ROUND", "--END ROUND", "/START ROUND TEXT" }),
			("Chat", "Text chat", new string[1] { "/ChatText/" })
		};

		private const string LogPath = "/LogsPosition/LogPrefab(Clone)";

		private const float LogLineStep = 35f;

		private readonly List<int> _logBirths = new List<int>();

		private readonly List<Bound> _bound = new List<Bound>();

		private readonly List<GameObject> _created = new List<GameObject>();

		private Dictionary<string, TMP_FontAsset> _fonts;

		private readonly List<GameObject> _activated = new List<GameObject>();

		private readonly List<Behaviour> _enabled = new List<Behaviour>();

		private readonly List<Graphic> _suppressed = new List<Graphic>();

		private readonly List<Snap> _snaps = new List<Snap>();

		private readonly List<(CanvasGroup g, float a)> _groupAlpha = new List<(CanvasGroup, float)>();

		private readonly List<(Transform t, Vector3 scale)> _expanded = new List<(Transform, Vector3)>();

		private Dictionary<string, Sprite> _sprites;

		private ReplayData _data;

		private readonly List<Canvas> _roots = new List<Canvas>();

		private readonly List<(Canvas c, RenderMode mode, Camera cam, float plane, CanvasScaler scaler, bool scalerOn, float scale)> _moved = new List<(Canvas, RenderMode, Camera, float, CanvasScaler, bool, float)>();

		private Camera _renderCam;

		private readonly List<Renderer> _hiddenRenderers = new List<Renderer>();

		private static Vector4? _logTextMargin;

		private static bool _materialsLogged;

		private static bool _renderersListed;

		internal static bool ProbeOnRender;

		private float _nextProbe;

		private static readonly Regex SpriteName = new Regex("<sprite\\s+name\\s*=\\s*\"?([^\">]+)\"?", RegexOptions.IgnoreCase);

		private readonly Dictionary<string, TMP_SpriteAsset> _spriteAssetFor = new Dictionary<string, TMP_SpriteAsset>();

		private static bool _askedIconMods;

		private HashSet<Component> _keep;

		private float _nextStrayCheck;

		public bool Shown { get; private set; }

		public bool Available => _bound.Count > 0;

		internal static bool PartDefault(string key)
		{
			return key != "Chat";
		}

		private static int PartOf(string path)
		{
			foreach (int item2 in from i in Enumerable.Range(0, Parts.Length)
				orderby (!(Parts[i].key == "RoundText")) ? ((Parts[i].key == "FpsPing") ? 1 : 2) : 0
				select i)
			{
				string[] item = Parts[item2].paths;
				foreach (string value in item)
				{
					if (path.IndexOf(value, StringComparison.Ordinal) >= 0 && (item2 != 0 || !path.Contains("ScopeCrosshair")))
					{
						return item2;
					}
				}
			}
			return -1;
		}

		private void TakeSnapshots()
		{
			//IL_009b: 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_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			_snaps.Clear();
			foreach (Bound item in _bound)
			{
				if ((Object)(object)item.C == (Object)null || item.Info.Dynamic)
				{
					continue;
				}
				Snap snap = new Snap
				{
					C = item.C
				};
				Component c = item.C;
				CanvasGroup val = (CanvasGroup)(object)((c is CanvasGroup) ? c : null);
				if (val != null)
				{
					snap.Alpha = val.alpha;
				}
				else
				{
					Component c2 = item.C;
					Graphic val2 = (Graphic)(object)((c2 is Graphic) ? c2 : null);
					if (val2 == null)
					{
						continue;
					}
					snap.Enabled = ((Behaviour)val2).enabled;
					snap.Color = val2.color;
					Image val3 = (Image)(object)((val2 is Image) ? val2 : null);
					if (val3 != null)
					{
						snap.Sprite = val3.sprite;
						snap.Fill = val3.fillAmount;
					}
					TMP_Text val4 = (TMP_Text)(object)((val2 is TMP_Text) ? val2 : null);
					if (val4 != null)
					{
						snap.Text = val4.text;
						snap.SpriteAsset = val4.spriteAsset;
					}
					else
					{
						Text val5 = (Text)(object)((val2 is Text) ? val2 : null);
						if (val5 != null)
						{
							snap.Text = val5.text;
						}
					}
					RectTransform rectTransform = val2.rectTransform;
					snap.Pos = rectTransform.anchoredPosition;
					snap.Size = rectTransform.sizeDelta;
					snap.Scale = ((Transform)rectTransform).localScale;
					snap.Rot = ((Transform)rectTransform).localRotation;
				}
				_snaps.Add(snap);
			}
		}

		private void RestoreSnapshots()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: 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_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			foreach (Snap snap in _snaps)
			{
				try
				{
					if ((Object)(object)snap.C == (Object)null)
					{
						continue;
					}
					Component c = snap.C;
					CanvasGroup val = (CanvasGroup)(object)((c is CanvasGroup) ? c : null);
					if (val != null)
					{
						val.alpha = snap.Alpha;
						continue;
					}
					Graphic val2 = (Graphic)snap.C;
					val2.color = snap.Color;
					Image val3 = (Image)(object)((val2 is Image) ? val2 : null);
					if (val3 != null)
					{
						val3.sprite = snap.Sprite;
						val3.fillAmount = snap.Fill;
					}
					TMP_Text val4 = (TMP_Text)(object)((val2 is TMP_Text) ? val2 : null);
					if (val4 != null)
					{
						val4.spriteAsset = snap.SpriteAsset;
						if (val4.text != snap.Text)
						{
							val4.text = snap.Text;
						}
					}
					else
					{
						Text val5 = (Text)(object)((val2 is Text) ? val2 : null);
						if (val5 != null)
						{
							val5.text = snap.Text;
						}
					}
					RectTransform rectTransform = val2.rectTransform;
					rectTransform.anchoredPosition = snap.Pos;
					rectTransform.sizeDelta = snap.Size;
					((Transform)rectTransform).localScale = snap.Scale;
					((Transform)rectTransform).localRotation = snap.Rot;
					((Behaviour)val2).enabled = snap.Enabled;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogDebug((object)("HUD restore: " + ex.Message));
				}
			}
			_snaps.Clear();
		}

		public bool UsesCanvas(Canvas c)
		{
			if (Shown)
			{
				return _roots.Contains(c);
			}
			return false;
		}

		public void Bind(ReplayData data, Transform localPlayer)
		{
			//IL_002c: 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_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			_spriteAssetFor.Clear();
			Hide();
			Unbind();
			_data = data;
			if (data.Ui.Count == 0)
			{
				return;
			}
			Scene val = Net.DdolScene();
			GameObject[] rootGameObjects = ((Scene)(ref val)).GetRootGameObjects();
			int num = 0;
			int num2 = 0;
			List<string> list = new List<string>();
			foreach (UiElementInfo value in data.Ui.Values)
			{
				if (IsTmpSubMesh(value.Path) || value.Path.IndexOf("/VoiceChatIndicator/", StringComparison.Ordinal) >= 0 || value.Path.IndexOf("--PopupWriting--/VoiceText", StringComparison.Ordinal) >= 0 || (value.Kind == UiKind.Group && value.Path.IndexOf("(Clone)", StringComparison.Ordinal) >= 0))
				{
					continue;
				}
				if (value.Dynamic)
				{
					(Component, Canvas) tuple = Create(value, localPlayer, rootGameObjects);
					if ((Object)(object)tuple.Item1 != (Object)null)
					{
						List<Bound> bound = _bound;
						Bound obj = new Bound
						{
							Info = value
						};
						(obj.C, obj.RootCanvas) = tuple;
						bound.Add(obj);
						num2++;
					}
					else
					{
						num++;
					}
					continue;
				}
				Transform val2 = Resolve(value.Anchor, value.Path, localPlayer, rootGameObjects);
				Component val3 = null;
				if ((Object)(object)val2 != (Object)null)
				{
					val3 = (Component)((value.Kind == UiKind.Group) ? ((object)((Component)val2).GetComponent<CanvasGroup>()) : ((object)((Component)val2).GetComponent<Graphic>()));
				}
				if ((Object)(object)val3 == (Object)null)
				{
					num++;
					if (list.Count < 60)
					{
						list.Add(value.Path);
					}
				}
				else
				{
					_bound.Add(new Bound
					{
						Info = value,
						C = val3
					});
				}
			}
			foreach (Bound item in _bound)
			{
				item.Part = PartOf(item.Info.Path);
			}
			LinkGroups(data);
			_logBirths.Clear();
			if (data.Header.Version < 7)
			{
				foreach (Bound item2 in _bound)
				{
					if (!item2.Info.Dynamic || item2.Info.Path.IndexOf("/LogsPosition/LogPrefab(Clone)", StringComparison.Ordinal) < 0)
					{
						continue;
					}
					int num3 = item2.Info.States.FindIndex((UiState st) => st.Visible);
					if (num3 >= 0)
					{
						item2.LogBirth = item2.Info.Frames[num3];
						item2.LogPos = item2.Info.States[num3].Pos;
						if (item2.Info.Kind == UiKind.Graphic && item2.Info.Path.EndsWith("/LogsPosition/LogPrefab(Clone)/Panel (1)", StringComparison.Ordinal))
						{
							_logBirths.Add(item2.LogBirth);
						}
					}
				}
				_logBirths.Sort();
			}
			Plugin.Log.LogDebug((object)($"HUD: {_bound.Count} elements bound ({num2} rebuilt)" + ((num > 0) ? $", {num} not found" : "") + ((_logBirths.Count > 0) ? $", {_logBirths.Count} kill feed lines restacked" : "")));
			if (list.Count > 0)
			{
				Plugin.Log.LogDebug((object)("HUD not found: " + string.Join(" | ", list.Distinct())));
			}
		}

		private static Transform Resolve(byte anchor, string path, Transform localPlayer, GameObject[] ddolRoots)
		{
			if (anchor == 1)
			{
				if (!((Object)(object)localPlayer != (Object)null))
				{
					return null;
				}
				if (!string.IsNullOrEmpty(path))
				{
					return localPlayer.Find(path);
				}
				return localPlayer;
			}
			int num = path.IndexOf('/');
			string text = ((num < 0) ? path : path.Substring(0, num));
			foreach (GameObject val in ddolRoots)
			{
				if (!(((Object)val).name != text))
				{
					Transform val2 = ((num < 0) ? val.transform : val.transform.Find(path.Substring(num + 1)));
					if ((Object)(object)val2 != (Object)null)
					{
						return val2;
					}
				}
			}
			return null;
		}

		private static Vector4 LogTextMargin()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			if (_logTextMargin.HasValue)
			{
				return _logTextMargin.Value;
			}
			GameObject val = (((Object)(object)MatchLogsOffline.Instance != (Object)null) ? MatchLogsOffline.Instance.chatLinePrefab : null);
			if ((Object)(object)val == (Object)null && (Object)(object)MatchLogs.Instance != (Object)null)
			{
				val = MatchLogs.Instance.chatLinePrefab;
			}
			if ((Object)(object)val == (Object)null)
			{
				val = (from l in Resources.FindObjectsOfTypeAll<MatchChatLine>()
					select ((Component)l).gameObject).FirstOrDefault((Func<GameObject, bool>)delegate(GameObject go)
				{
					//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)
					Scene scene = go.scene;
					return !((Scene)(ref scene)).IsValid();
				});
			}
			TMP_Text val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInChildren<TMP_Text>(true) : null);
			if ((Object)(object)val2 == (Object)null)
			{
				return Vector4.zero;
			}
			_logTextMargin = val2.margin;
			Plugin.Log.LogDebug((object)$"Kill feed text margin {val2.margin}");
			return val2.margin;
		}

		private (Component c, Canvas canvas) Create(UiElementInfo el, Transform localPlayer, GameObject[] ddolRoots)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//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_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			string text = el.Path;
			Transform val = null;
			while ((Object)(object)val == (Object)null && text.Length > 0)
			{
				int num = text.LastIndexOf('/');
				text = ((num < 0) ? "" : text.Substring(0, num));
				if (text.Length > 0 || el.Anchor == 1)
				{
					val = Resolve(el.Anchor, text, localPlayer, ddolRoots);
				}
			}
			Canvas val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInParent<Canvas>(true) : null);
			if ((Object)(object)val2 == (Object)null)
			{
				return (c: null, canvas: null);
			}
			val2 = val2.rootCanvas;
			GameObject val3 = new GameObject("Streplay " + el.Path.Substring(el.Path.LastIndexOf('/') + 1), new Type[1] { typeof(RectTransform) });
			val3.transform.SetParent(((Component)val2).transform, false);
			val3.transform.SetAsLastSibling();
			RectTransform val4 = (RectTransform)val3.transform;
			Vector2 val5 = default(Vector2);
			((Vector2)(ref val5))..ctor(0.5f, 0.5f);
			val4.pivot = val5;
			Vector2 anchorMin = (val4.anchorMax = val5);
			val4.anchorMin = anchorMin;
			_created.Add(val3);
			Graphic val9;
			if (el.Kind == UiKind.Text)
			{
				TextMeshProUGUI val7 = val3.AddComponent<TextMeshProUGUI>();
				TMP_FontAsset val8 = FindFont(el.Font);
				if ((Object)(object)val8 != (Object)null)
				{
					((TMP_Text)val7).font = val8;
				}
				((TMP_Text)val7).fontSize = el.FontSize;
				((TMP_Text)val7).alignment = (TextAlignmentOptions)el.Alignment;
				((TMP_Text)val7).fontStyle = (FontStyles)el.FontStyle;
				if (el.Path.IndexOf("/LogsPosition/LogPrefab(Clone)", StringComparison.Ordinal) >= 0)
				{
					((TMP_Text)val7).margin = LogTextMargin();
				}
				val9 = (Graphic)(object)val7;
			}
			else
			{
				Image obj = val3.AddComponent<Image>();
				obj.type = (Type)el.ImageType;
				obj.preserveAspect = el.PreserveAspect;
				val9 = (Graphic)(object)obj;
			}
			val9.raycastTarget = false;
			((Behaviour)val9).enabled = false;
			return (c: (Component)(object)val9, canvas: val2);
		}

		private void Unbind()
		{
			foreach (GameObject item in _created)
			{
				if ((Object)(object)item != (Object)null)
				{
					Object.Destroy((Object)(object)item);
				}
			}
			_created.Clear();
			_bound.Clear();
		}

		public void Dispose()
		{
			Hide();
			Unbind();
		}

		public void Show()
		{
			if (Shown || _bound.Count == 0)
			{
				return;
			}
			Shown = true;
			TakeSnapshots();
			HashSet<Component> hashSet = (_keep = new HashSet<Component>(from b in _bound
				where (Object)(object)b.C != (Object)null
				select b.C));
			HashSet<Canvas> hashSet2 = new HashSet<Canvas>();
			foreach (Bound item2 in _bound)
			{
				if ((Object)(object)item2.C == (Object)null)
				{
					continue;
				}
				Transform val = item2.C.transform;
				while ((Object)(object)val != (Object)null)
				{
					if (!((Component)val).gameObject.activeSelf)
					{
						((Component)val).gameObject.SetActive(true);
						_activated.Add(((Component)val).gameObject);
					}
					Canvas component = ((Component)val).GetComponent<Canvas>();
					if ((Object)(object)component != (Object)null)
					{
						if (!((Behaviour)component).enabled)
						{
							((Behaviour)component).enabled = true;
							_enabled.Add((Behaviour)(object)component);
						}
						if (component.isRootCanvas)
						{
							hashSet2.Add(component);
							break;
						}
					}
					val = val.parent;
				}
			}
			_roots.Clear();
			_roots.AddRange(hashSet2);
			FindCollapsedParents(hashSet);
			if ((Object)(object)_renderCam != (Object)null)
			{
				MoveToCamera();
			}
			foreach (Canvas item3 in hashSet2)
			{
				Graphic[] componentsInChildren = ((Component)item3).GetComponentsInChildren<Graphic>(true);
				foreach (Graphic val2 in componentsInChildren)
				{
					if (((Behaviour)val2).enabled && !hashSet.Contains((Component)(object)val2) && !(val2 is TMP_SubMeshUI))
					{
						((Behaviour)val2).enabled = false;
						_suppressed.Add(val2);
					}
				}
				CanvasGroup[] componentsInChildren2 = ((Component)item3).GetComponentsInChildren<CanvasGroup>(true);
				foreach (CanvasGroup val3 in componentsInChildren2)
				{
					if (!hashSet.Contains((Component)(object)val3))
					{
						_groupAlpha.Add((val3, val3.alpha));
					}
				}
			}
			foreach (var item4 in _groupAlpha)
			{
				CanvasGroup item = item4.g;
				if ((Object)(object)item != (Object)null)
				{
					item.alpha = 1f;
				}
			}
		}

		public void Hide()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			if (!Shown)
			{
				return;
			}
			Shown = false;
			_keep = null;
			RestoreFromCamera();
			_roots.Clear();
			foreach (var (val, localScale) in _expanded)
			{
				if ((Object)(object)val != (Object)null)
				{
					val.localScale = localScale;
				}
			}
			_expanded.Clear();
			foreach (var (val2, alpha) in _groupAlpha)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					val2.alpha = alpha;
				}
			}
			_groupAlpha.Clear();
			foreach (Graphic item in _suppressed)
			{
				if ((Object)(object)item != (Object)null)
				{
					((Behaviour)item).enabled = true;
				}
			}
			_suppressed.Clear();
			RestoreSnapshots();
			foreach (Behaviour item2 in _enabled)
			{
				if ((Object)(object)item2 != (Object)null)
				{
					item2.enabled = false;
				}
			}
			_enabled.Clear();
			for (int num = _activated.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)_activated[num] != (Object)null)
				{
					_activated[num].SetActive(false);
				}
			}
			_activated.Clear();
		}

		private void FindCollapsedParents(HashSet<Component> keep)
		{
			//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_008a: 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)
			foreach (Bound item in _bound)
			{
				item.Collapsed = null;
				if ((Object)(object)item.C == (Object)null || item.Info.Dynamic)
				{
					continue;
				}
				Transform parent = item.C.transform.parent;
				while ((Object)(object)parent != (Object)null)
				{
					Canvas component = ((Component)parent).GetComponent<Canvas>();
					if (component != null && component.isRootCanvas)
					{
						break;
					}
					Graphic component2 = ((Component)parent).GetComponent<Graphic>();
					if (component2 == null || !keep.Contains((Component)(object)component2))
					{
						Vector3 localScale = parent.localScale;
						if (Mathf.Abs(localScale.x) < 0.05f || Mathf.Abs(localScale.y) < 0.05f)
						{
							Bound bound = item;
							(bound.Collapsed ?? (bound.Collapsed = new List<Transform>())).Add(parent);
						}
					}
					parent = parent.parent;
				}
			}
			List<Bound> list = _bound.Where((Bound b) => b.Collapsed != null).ToList();
			if (list.Count > 0)
			{
				Plugin.Log.LogDebug((object)($"HUD: {list.Count} recorded elements sit in collapsed containers (" + string.Join(", ", from t in list.SelectMany((Bound b) => b.Collapsed).Distinct().Take(4)
					select $"{((Object)t).name} scale {t.localScale.x:0.###}") + ")" + ((_data.Header.Version < 7) ? ", kept hidden" : "")));
			}
		}

		public void SetRenderCamera(Camera cam)
		{
			if (!((Object)(object)cam == (Object)(object)_renderCam))
			{
				RestoreFromCamera();
				_renderCam = cam;
				if ((Object)(object)cam != (Object)null && Shown)
				{
					MoveToCamera();
				}
			}
		}

		internal void ProbeCentre(string when)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			HashSet<Component> hashSet = new HashSet<Component>(from b in _bound
				where (Object)(object)b.C != (Object)null
				select b.C);
			foreach (Canvas root in _roots)
			{
				if ((Object)(object)root == (Object)null)
				{
					continue;
				}
				Camera val = (((int)root.renderMode == 0) ? null : root.worldCamera);
				Vector2 val2 = (((Object)(object)val != (Object)null && (Object)(object)val.targetTexture != (Object)null) ? (new Vector2((float)((Texture)val.targetTexture).width, (float)((Texture)val.targetTexture).height) / 2f) : (new Vector2((float)Screen.width, (float)Screen.height) / 2f));
				Graphic[] componentsInChildren = ((Component)root).GetComponentsInChildren<Graphic>(false);
				foreach (Graphic val3 in componentsInChildren)
				{
					if (((Behaviour)val3).enabled && !val3.canvasRenderer.cull && !(val3.canvasRenderer.GetInheritedAlpha() <= 0.001f) && !(val3.color.a <= 0.001f) && RectTransformUtility.RectangleContainsScreenPoint(val3.rectTransform, val2, val))
					{
						Texture mainTexture = val3.mainTexture;
						Canvas canvas = val3.canvas;
						ManualLogSource log = Plugin.Log;
						string[] array = new string[5];
						object[] obj = new object[6]
						{
							when,
							Recorder.ScenePath(((Component)val3).transform),
							((object)val3).GetType().Name,
							hashSet.Contains((Component)(object)val3),
							null,
							null
						};
						Rect rect = val3.rectTransform.rect;
						obj[4] = ((Rect)(ref rect)).size;
						obj[5] = ((Component)val3).transform.lossyScale.x;
						array[0] = string.Format("[probe {0}] {1} {2} recorded={3} rect={4} lossy={5:0.####} ", obj);
						array[1] = "tex=";
						array[2] = (((Object)(object)mainTexture != (Object)null) ? (((Object)mainTexture).name + " " + mainTexture.width + "x" + mainTexture.height) : "-");
						array[3] = " canvas=";
						array[4] = (((Object)(object)canvas != (Object)null) ? (((Object)canvas).name + " " + ((object)canvas.renderMode/*cast due to .constrained prefix*/).ToString() + " order " + canvas.sortingOrder) : "-");
						log.LogDebug((object)string.Concat(array));
					}
				}
			}
		}

		private void MoveToCamera()
		{
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			if (ProbeOnRender)
			{
				ProbeCentre("render");
			}
			if (!_materialsLogged)
			{
				_materialsLogged = true;
				foreach (Bound item in _bound)
				{
					Component c = item.C;
					Graphic val = (Graphic)(object)((c is Graphic) ? c : null);
					if (val == null || (Object)(object)val == (Object)null)
					{
						continue;
					}
					Material materialForRendering = val.materialForRendering;
					if (((Object)(object)materialForRendering != (Object)null && (Object)(object)materialForRendering != (Object)(object)Graphic.defaultGraphicMaterial) || item.Info.Path.IndexOf("rosshair", StringComparison.Ordinal) >= 0)
					{
						Image val2 = (Image)(object)((val is Image) ? val : null);
						ManualLogSource log = Plugin.Log;
						string[] obj = new string[10]
						{
							"[hud] ",
							item.Info.Path,
							": material=",
							((Object)(object)materialForRendering != (Object)null) ? ((Object)materialForRendering).name : "null",
							" shader=",
							((Object)(object)materialForRendering != (Object)null && (Object)(object)materialForRendering.shader != (Object)null) ? ((Object)materialForRendering.shader).name : "null",
							" sprite=",
							null,
							null,
							null
						};
						object obj2;
						if (!((Object)(object)val2 != (Object)null) || !((Object)(object)val2.sprite != (Object)null))
						{
							obj2 = "-";
						}
						else
						{
							object[] obj3 = new object[4]
							{
								((Object)val2.sprite).name,
								null,
								null,
								null
							};
							Texture2D texture = val2.sprite.texture;
							obj3[1] = ((texture != null) ? ((Object)texture).name : null);
							obj3[2] = val2.sprite.textureRect;
							obj3[3] = val2.sprite.packed;
							obj2 = string.Format("{0} tex={1} rect={2} packed={3}", obj3);
						}
						obj[7] = (string)obj2;
						obj[8] = " ";
						string arg = (((Object)(object)val2 != (Object)null) ? ((object)val2.type/*cast due to .constrained prefix*/).ToString() : "-");
						Rect rect = val.rectTransform.rect;
						obj[9] = $"type={arg} size={((Rect)(ref rect)).size}";
						log.LogDebug((object)string.Concat(obj));
					}
				}
			}
			RenderTexture targetTexture = _renderCam.targetTexture;
			float w = (((Object)(object)targetTexture != (Object)null) ? ((Texture)targetTexture).width : _renderCam.pixelWidth);
			float h = (((Object)(object)targetTexture != (Object)null) ? ((Texture)targetTexture).height : _renderCam.pixelHeight);
			foreach (Canvas root in _roots)
			{
				if ((Object)(object)root == (Object)null || (int)root.renderMode != 0)
				{
					continue;
				}
				CanvasScaler component = ((Component)root).GetComponent<CanvasScaler>();
				_moved.Add((root, root.renderMode, root.worldCamera, root.planeDistance, component, (Object)(object)component != (Object)null && ((Behaviour)component).enabled, root.scaleFactor));
				float scaleFactor = ScaleFor(root, component, w, h);
				if ((Object)(object)component != (Object)null)
				{
					((Behaviour)component).enabled = false;
				}
				root.renderMode = (RenderMode)1;
				root.worldCamera = _renderCam;
				root.planeDistance = 5000f;
				root.scaleFactor = scaleFactor;
				Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(false);
				foreach (Renderer val3 in componentsInChildren)
				{
					if (val3.enabled)
					{
						val3.enabled = false;
						_hiddenRenderers.Add(val3);
					}
				}
			}
			if (!_renderersListed)
			{
				_renderersListed = true;
				List<Renderer> list = _moved.SelectMany(((Canvas c, RenderMode mode, Camera cam, float plane, CanvasScaler scaler, bool scalerOn, float scale) m) => ((Component)m.c).GetComponentsInChildren<Renderer>(true)).ToList();
				Plugin.Log.LogDebug((object)($"[render] 3D renderers in the HUD canvases ({list.Count}): " + string.Join(", ", from r in list.Take(12)
					select $"{Recorder.ScenePath(((Component)r).transform)} {((object)r).GetType().Name} on={r.enabled && ((Component)r).gameObject.activeInHierarchy}")));
			}
			if (_hiddenRenderers.Count > 0)
			{
				Plugin.Log.LogDebug((object)($"[render] hid {_hiddenRenderers.Count} 3D renderers inside the HUD canvases: " + string.Join(", ", from r in _hiddenRenderers.Take(6)
					select ((Object)r).name + " (" + ((object)r).GetType().Name + ")")));
			}
		}

		private void RestoreFromCamera()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			foreach (var (val, renderMode, worldCamera, planeDistance, val2, enabled, scaleFactor) in _moved)
			{
				if (!((Object)(object)val == (Object)null))
				{
					val.renderMode = renderMode;
					val.worldCamera = worldCamera;
					val.planeDistance = planeDistance;
					val.scaleFactor = scaleFactor;
					if ((Object)(object)val2 != (Object)null)
					{
						((Behaviour)val2).enabled = enabled;
					}
				}
			}
			_moved.Clear();
			foreach (Renderer hiddenRenderer in _hiddenRenderers)
			{
				if ((Object)(object)hiddenRenderer != (Object)null)
				{
					hiddenRenderer.enabled = true;
				}
			}
			_hiddenRenderers.Clear();
		}

		private static float ScaleFor(Canvas c, CanvasScaler s, float w, float h)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Invalid comparison between Unknown and I4
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Invalid comparison between Unknown and I4
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)s == (Object)null || !((Behaviour)s).enabled)
			{
				return c.scaleFactor * h / (float)Mathf.Max(1, Screen.height);
			}
			if ((int)s.uiScaleMode == 1)
			{
				Vector2 referenceResolution = s.referenceResolution;
				ScreenMatchMode screenMatchMode = s.screenMatchMode;
				if ((int)screenMatchMode != 1)
				{
					if ((int)screenMatchMode == 2)
					{
						return Mathf.Max(w / referenceResolution.x, h / referenceResolution.y);
					}
					float num = Mathf.Log(w / referenceResolution.x, 2f);
					float num2 = Mathf.Log(h / referenceResolution.y, 2f);
					return Mathf.Pow(2f, Mathf.Lerp(num, num2, s.matchWidthOrHeight));
				}
				return Mathf.Min(w / referenceResolution.x, h / referenceResolution.y);
			}
			return c.scaleFactor * h / (float)Mathf.Max(1, Screen.height);
		}

		public void Apply(int frame)
		{
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Expected O, but got Unknown
			//IL_025b: 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_0380: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0410: 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_0174: 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_017d: 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_0478: Unknown result type (might be due to invalid IL or missing references)
			//IL_047e: Invalid comparison between Unknown and I4
			//IL_066b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0679: Unknown result type (might be due to invalid IL or missing references)
			//IL_0687: Unknown result type (might be due to invalid IL or missing references)
			//IL_0693: Unknown result type (might be due to invalid IL or missing references)
			//IL_0698: Unknown result type (might be due to invalid IL or missing references)
			//IL_069c: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_0598: Unknown result type (might be due to invalid IL or missing references)
			//IL_059d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0585: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05be: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0602: Unknown result type (might be due to invalid IL or missing references)
			//IL_0610: Unknown result type (might be due to invalid IL or missing references)
			//IL_061c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0628: Unknown result type (might be due to invalid IL or missing references)
			//IL_0645: Unknown result type (might be due to invalid IL or missing references)
			if (!Shown)
			{
				return;
			}
			if (ProbeOnRender && (Object)(object)_renderCam != (Object)null && Time.realtimeSinceStartup > _nextProbe)
			{
				_nextProbe = Time.realtimeSinceStartup + 1f;
				foreach (Bound item in _bound)
				{
					Component c = item.C;
					Image val = (Image)(object)((c is Image) ? c : null);
					if (val != null && !((Object)(object)val == (Object)null) && item.Info.Path.IndexOf("/Crosshair", StringComparison.Ordinal) >= 0)
					{
						Sprite sprite = val.sprite;
						ManualLogSource log = Plugin.Log;
						object arg = frame;
						object arg2;
						if (!((Object)(object)sprite != (Object)null))
						{
							arg2 = "null";
						}
						else
						{
							object[] obj = new object[4]
							{
								((Object)sprite).name,
								((Object)sprite).GetInstanceID(),
								sprite.rect,
								null
							};
							Texture2D texture = sprite.texture;
							obj[3] = ((texture != null) ? ((Object)texture).name : null);
							arg2 = string.Format("{0}#{1} rect={2} tex={3}", obj);
						}
						string text = $"[xhair] frame {arg} sprite={arg2} ";
						string text2 = string.Format("override={0} type={1} ", ((Object)(object)val.overrideSprite != (Object)null) ? (((Object)val.overrideSprite).name + "#" + ((Object)val.overrideSprite).GetInstanceID()) : "-", val.type);
						object[] array = new object[4];
						Rect rect = ((Graphic)val).rectTransform.rect;
						array[0] = ((Rect)(ref rect)).size;
						array[1] = ((Transform)((Graphic)val).rectTransform).localScale;
						Material materialForRendering = ((Graphic)val).materialForRendering;
						array[2] = ((materialForRendering != null) ? ((Object)materialForRendering).name : null);
						Canvas canvas = ((Graphic)val).canvas;
						array[3] = ((canvas != null) ? new RenderMode?(canvas.renderMode) : ((RenderMode?)null));
						log.LogDebug((object)(text + text2 + string.Format("size={0} scale={1} mat={2} canvas={3}", array)));
					}
				}
			}
			SuppressStrays(now: false);
			foreach (Bound item2 in _bound)
			{
				UiState uiState = StateAt(item2.Info, frame);
				if ((Object)(object)item2.C == (Object)null)
				{
					continue;
				}
				if (item2.Info.Kind == UiKind.Group)
				{
					((CanvasGroup)item2.C).alpha = ((uiState != null && uiState.Visible) ? uiState.Alpha : 0f);
					continue;
				}
				Graphic val2 = (Graphic)item2.C;
				bool flag = uiState != null && uiState.Visible && (item2.Part < 0 || Plugin.HudShow[item2.Part].Value);
				if (flag && item2.Collapsed != null)
				{
					if (_data.Header.Version < 7)
					{
						flag = false;
					}
					else
					{
						foreach (Transform item3 in item2.Collapsed)
						{
							if ((Object)(object)item3 != (Object)null && item3.localScale != Vector3.one)
							{
								_expanded.Add((item3, item3.localScale));
								item3.localScale = Vector3.one;
							}
						}
					}
				}
				if (((Behaviour)val2).enabled != flag)
				{
					((Behaviour)val2).enabled = flag;
				}
				if (!flag)
				{
					continue;
				}
				Color val3 = Color32.op_Implicit(uiState.Color);
				if (item2.Groups != null)
				{
					foreach (UiElementInfo group in item2.Groups)
					{
						UiState uiState2 = StateAt(group, frame);
						val3.a *= ((uiState2 != null && uiState2.Visible) ? uiState2.Alpha : 0f);
					}
					if (val3.a <= 0.002f)
					{
						((Behaviour)val2).enabled = false;
						continue;
					}
				}
				val2.color = val3;
				Image val4 = (Image)(object)((val2 is Image) ? val2 : null);
				if (val4 != null)
				{
					if (uiState.Sprite >= 0 && _data.UiStrings.TryGetValue(uiState.Sprite, out var value))
					{
						Sprite val5 = FindSprite(value);
						if ((Object)(object)val5 != (Object)null && (Object)(object)val4.sprite != (Object)(object)val5)
						{
							val4.sprite = val5;
						}
					}
					if ((int)val4.type == 3)
					{
						val4.fillAmount = uiState.Fill;
					}
				}
				if (uiState.Text != null)
				{
					TMP_Text val6 = (TMP_Text)(object)((val2 is TMP_Text) ? val2 : null);
					if (val6 != null)
					{
						if (val6.text != uiState.Text)
						{
							if (uiState.Text.IndexOf("<sprite", StringComparison.OrdinalIgnoreCase) >= 0)
							{
								TMP_SpriteAsset val7 = SpriteAssetFor(uiState.Text);
								if ((Object)(object)val7 != (Object)null && (Object)(object)val6.spriteAsset != (Object)(object)val7)
								{
									val6.spriteAsset = val7;
								}
							}
							val6.text = uiState.Text;
						}
					}
					else
					{
						Text val8 = (Text)(object)((val2 is Text) ? val2 : null);
						if (val8 != null && val8.text != uiState.Text)
						{
							val8.text = uiState.Text;
						}
					}
				}
				RectTransform rectTransform = val2.rectTransform;
				if (item2.Info.Dynamic)
				{
					Rect val9 = (Rect)(((Object)(object)item2.RootCanvas != (Object)null) ? ((RectTransform)((Component)item2.RootCanvas).transform).rect : new Rect(0f, 0f, (float)Screen.width, (float)Screen.height));
					Vector2 val10 = ((item2.LogBirth >= 0) ? item2.LogPos : uiState.Pos);
					rectT