Decompiled source of PaintingCompany v1.0.0

MechaChameleon.dll

Decompiled 4 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.IO.Compression;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalConfig;
using LethalConfig.ConfigItems;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("ClientNetworkTransform")]
[assembly: IgnoresAccessChecksTo("com.olegknyazev.softmask")]
[assembly: IgnoresAccessChecksTo("DissonanceVoip")]
[assembly: IgnoresAccessChecksTo("DunGen")]
[assembly: IgnoresAccessChecksTo("DunGen.Integration.ASPP")]
[assembly: IgnoresAccessChecksTo("DunGen.Integration.UnityNav")]
[assembly: IgnoresAccessChecksTo("EasyTextEffects")]
[assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")]
[assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")]
[assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")]
[assembly: IgnoresAccessChecksTo("Unity.Burst")]
[assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")]
[assembly: IgnoresAccessChecksTo("Unity.Collections")]
[assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")]
[assembly: IgnoresAccessChecksTo("Unity.Jobs")]
[assembly: IgnoresAccessChecksTo("Unity.Mathematics")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")]
[assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Components")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")]
[assembly: IgnoresAccessChecksTo("Unity.Services.QoS")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Relay")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("Unity.Timeline")]
[assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.XR.CoreUtils")]
[assembly: IgnoresAccessChecksTo("Unity.XR.Management")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.ConformanceAutomation")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.MetaQuestSupport")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.MockRuntime")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.OculusQuestSupport")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.RuntimeDebugger")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.SpatialTracking")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: IgnoresAccessChecksTo("UnityEngine.XR.LegacyInputHelpers")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MechaChameleon")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+67f3cc4d0c9e867227f7474adb201e11df783e76")]
[assembly: AssemblyProduct("MechaChameleon")]
[assembly: AssemblyTitle("MechaChameleon")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.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 MechaChameleon
{
	public static class AudioSystem
	{
		private static AudioSource uiSource;

		private static AudioSource GetSource()
		{
			if ((Object)(object)uiSource == (Object)null && (Object)(object)ChameleonManager.Instance != (Object)null)
			{
				uiSource = ((Component)ChameleonManager.Instance).gameObject.AddComponent<AudioSource>();
				uiSource.spatialBlend = 0f;
				uiSource.playOnAwake = false;
				uiSource.bypassEffects = true;
				uiSource.bypassListenerEffects = true;
			}
			return uiSource;
		}

		public static void PlayOpen()
		{
			Terminal val = Object.FindObjectOfType<Terminal>();
			AudioClip clip = (((Object)(object)val != (Object)null && (Object)(object)val.enterTerminalSFX != (Object)null) ? val.enterTerminalSFX : (((Object)(object)HUDManager.Instance != (Object)null) ? HUDManager.Instance.scanSFX : null));
			Play(clip, 0.75f);
		}

		public static void PlayClose()
		{
			Terminal val = Object.FindObjectOfType<Terminal>();
			AudioClip clip = (((Object)(object)val != (Object)null && (Object)(object)val.leaveTerminalSFX != (Object)null) ? val.leaveTerminalSFX : (((Object)(object)HUDManager.Instance != (Object)null) ? HUDManager.Instance.scanSFX : null));
			Play(clip, 0.65f);
		}

		public static void PlayClick()
		{
			Terminal val = Object.FindObjectOfType<Terminal>();
			AudioClip clip = null;
			if ((Object)(object)val != (Object)null && val.keyboardClips != null && val.keyboardClips.Length != 0)
			{
				clip = val.keyboardClips[Random.Range(0, val.keyboardClips.Length)];
			}
			else if ((Object)(object)HUDManager.Instance != (Object)null && HUDManager.Instance.dialogueBleeps != null && HUDManager.Instance.dialogueBleeps.Length != 0)
			{
				clip = HUDManager.Instance.dialogueBleeps[0];
			}
			Play(clip, 0.5f);
		}

		public static void PlaySample()
		{
			AudioClip clip = (((Object)(object)HUDManager.Instance != (Object)null) ? HUDManager.Instance.scanSFX : null);
			Play(clip, 0.6f);
		}

		public static void PlaySuit()
		{
			AudioClip val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.changeSuitSFX : null);
			if ((Object)(object)val == (Object)null && (Object)(object)HUDManager.Instance != (Object)null)
			{
				val = HUDManager.Instance.addToScrapTotalSFX;
			}
			Play(val, 0.7f);
		}

		public static void PlayError()
		{
			AudioClip val = null;
			if ((Object)(object)HUDManager.Instance != (Object)null)
			{
				if (HUDManager.Instance.warningSFX != null && HUDManager.Instance.warningSFX.Length != 0)
				{
					val = HUDManager.Instance.warningSFX[Random.Range(0, HUDManager.Instance.warningSFX.Length)];
				}
				else if ((Object)(object)HUDManager.Instance.levelDecreaseSFX != (Object)null)
				{
					val = HUDManager.Instance.levelDecreaseSFX;
				}
				else if (HUDManager.Instance.tipsSFX != null && HUDManager.Instance.tipsSFX.Length != 0)
				{
					val = HUDManager.Instance.tipsSFX[0];
				}
			}
			if ((Object)(object)val == (Object)null && (Object)(object)StartOfRound.Instance != (Object)null)
			{
				val = StartOfRound.Instance.HUDSystemAlertSFX;
			}
			if ((Object)(object)val == (Object)null)
			{
				Terminal val2 = Object.FindObjectOfType<Terminal>();
				if ((Object)(object)val2 != (Object)null && val2.syncedAudios != null && val2.syncedAudios.Length > 1)
				{
					val = val2.syncedAudios[1];
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				Play(val, 0.75f);
			}
			else
			{
				PlayClick();
			}
		}

		private static void Play(AudioClip clip, float volume = 1f)
		{
			if ((Object)(object)clip == (Object)null)
			{
				return;
			}
			try
			{
				AudioSource source = GetSource();
				if ((Object)(object)source != (Object)null)
				{
					source.PlayOneShot(clip, volume);
				}
				else if ((Object)(object)HUDManager.Instance != (Object)null && (Object)(object)HUDManager.Instance.UIAudio != (Object)null)
				{
					HUDManager.Instance.UIAudio.PlayOneShot(clip, volume);
				}
			}
			catch
			{
			}
		}
	}
	public static class CameraMath
	{
		public static Rect DisplayRect(Camera cam)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_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_00ce: Unknown result type (might be due to invalid IL or missing references)
			Rect val = (Rect)(((Object)(object)cam != (Object)null) ? cam.rect : new Rect(0f, 0f, 1f, 1f));
			if (((Rect)(ref val)).x <= 0.001f && ((Rect)(ref val)).y <= 0.001f && ((Rect)(ref val)).width >= 0.999f && ((Rect)(ref val)).height >= 0.999f)
			{
				return new Rect(0f, 0f, (float)Screen.width, (float)Screen.height);
			}
			return new Rect(((Rect)(ref val)).x * (float)Screen.width, ((Rect)(ref val)).y * (float)Screen.height, ((Rect)(ref val)).width * (float)Screen.width, ((Rect)(ref val)).height * (float)Screen.height);
		}

		public static Matrix4x4 ViewMatrix(Camera cam)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)cam).transform;
			Matrix4x4 val = Matrix4x4.TRS(transform.position, transform.rotation, new Vector3(1f, 1f, -1f));
			return ((Matrix4x4)(ref val)).inverse;
		}

		public static Ray BuildRay(Camera cam, Vector2 screenPos)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: 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_00de: 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_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_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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_0124: Unknown result type (might be due to invalid IL or missing references)
			Rect val = DisplayRect(cam);
			float num = ((((Rect)(ref val)).width > 0f) ? ((screenPos.x - ((Rect)(ref val)).x) / ((Rect)(ref val)).width * 2f - 1f) : 0f);
			float num2 = ((((Rect)(ref val)).height > 0f) ? ((screenPos.y - ((Rect)(ref val)).y) / ((Rect)(ref val)).height * 2f - 1f) : 0f);
			Transform transform = ((Component)cam).transform;
			Matrix4x4 projectionMatrix = cam.projectionMatrix;
			Vector4 val2 = ((Matrix4x4)(ref projectionMatrix)).inverse * new Vector4(num, num2, -1f, 1f);
			if (Mathf.Abs(val2.w) > 1E-06f)
			{
				val2 /= val2.w;
			}
			Vector3 val3 = transform.TransformDirection(new Vector3(val2.x, val2.y, 0f - val2.z));
			if (((Vector3)(ref val3)).sqrMagnitude < 1E-12f)
			{
				val3 = transform.forward;
			}
			return new Ray(transform.position, ((Vector3)(ref val3)).normalized);
		}

		public static bool ProjectToGui(Camera cam, Matrix4x4 viewProjection, Vector3 world, out Vector2 gui)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			gui = default(Vector2);
			if ((Object)(object)cam == (Object)null)
			{
				return false;
			}
			Vector4 val = viewProjection * new Vector4(world.x, world.y, world.z, 1f);
			if (val.w <= 1E-05f)
			{
				return false;
			}
			Rect val2 = DisplayRect(cam);
			float num = ((Rect)(ref val2)).x + (val.x / val.w * 0.5f + 0.5f) * ((Rect)(ref val2)).width;
			float num2 = ((Rect)(ref val2)).y + (val.y / val.w * 0.5f + 0.5f) * ((Rect)(ref val2)).height;
			gui = new Vector2(num, (float)Screen.height - num2);
			return true;
		}
	}
	[DefaultExecutionOrder(30000)]
	public class ChameleonManager : MonoBehaviour
	{
		private PlayerControllerB player;

		private Camera cam;

		private PaintTarget target;

		private PaintUI ui;

		private static readonly float[] ZoomSteps = new float[11]
		{
			0.3f, 0.45f, 0.65f, 0.9f, 1.25f, 1.7f, 2.3f, 3.1f, 4.2f, 5.5f,
			7f
		};

		private Vector3 pivot;

		private Vector3 panOffset;

		private float yaw;

		private float pitch;

		private int zoomIndex = 5;

		private float savedAnimatorSpeed = 1f;

		private bool animatorFrozen;

		private PaintHit hoverHit;

		private bool hoverValid;

		private Vector3 camLocalPos;

		private Quaternion camLocalRot;

		private float camNear;

		private float camFov;

		private int frameCounter;

		private bool shouldPickScreen;

		private float lastScreenRead;

		private Vector2 pickScreenPos;

		private bool pickingWithSpace;

		private Keyboard textDevice;

		private const float PortraitFov = 34f;

		internal const float PortraitAspect = 0.75f;

		public static ChameleonManager Instance { get; private set; }

		public bool Active { get; private set; }

		public static bool HasMoreCompany
		{
			get
			{
				try
				{
					if (Chainloader.PluginInfos.ContainsKey("notnotnotswipez-MoreCompany") || Chainloader.PluginInfos.ContainsKey("MoreCompany"))
					{
						return true;
					}
					return Type.GetType("MoreCompany.MainClass, MoreCompany") != null;
				}
				catch
				{
					return false;
				}
			}
		}

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

		private void Awake()
		{
			Instance = this;
			ui = new PaintUI();
		}

		private void OnDestroy()
		{
			UnsubscribeText();
			if (Active)
			{
				Exit();
			}
			target?.Dispose();
			ui?.Dispose();
			ChameleonNet.Shutdown();
		}

		private static PlayerControllerB GetLocalPlayer()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			PlayerControllerB localPlayerController = instance.localPlayerController;
			if ((Object)(object)localPlayerController == (Object)null || !localPlayerController.isPlayerControlled)
			{
				return null;
			}
			return localPlayerController;
		}

		private void Update()
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			ChameleonNet.Tick();
			Keyboard current = Keyboard.current;
			PlayerControllerB localPlayer = GetLocalPlayer();
			if ((Object)(object)localPlayer == (Object)null)
			{
				if (Active)
				{
					Exit();
				}
				return;
			}
			if (target != null && (Object)(object)target.Player != (Object)(object)localPlayer)
			{
				if (Active)
				{
					Exit();
				}
				target.Dispose();
				target = null;
			}
			bool flag = Active && ui.CapturingText;
			if (current != null && !flag && ((ButtonControl)current[Plugin.ToggleKey.Value]).wasPressedThisFrame)
			{
				if (Active)
				{
					Exit();
				}
				else
				{
					Enter(localPlayer);
				}
			}
			else if (!Active)
			{
				frameCounter++;
				if (target == null && localPlayer.isPlayerControlled && ((Object)(object)localPlayer.thisPlayerModel != (Object)null || ((Component)localPlayer).gameObject.activeInHierarchy))
				{
					target = new PaintTarget(localPlayer);
					if (target.EnsureSetup())
					{
						PublishPaint();
					}
				}
				if (frameCounter % 15 == 0)
				{
					GameObject val = GameObject.Find("ThridPersonCam");
					if ((Object)(object)val != (Object)null && val.activeInHierarchy)
					{
						LODGroup componentInChildren = ((Component)localPlayer).GetComponentInChildren<LODGroup>(true);
						if ((Object)(object)componentInChildren != (Object)null && componentInChildren.enabled && ((Component)componentInChildren).gameObject.activeInHierarchy)
						{
							componentInChildren.ForceLOD(0);
						}
					}
				}
				if (target != null && frameCounter % 30 == 0)
				{
					target.ReapplyIfNeeded();
				}
			}
			else if (current != null && !flag && ((ButtonControl)current.escapeKey).wasPressedThisFrame)
			{
				Exit();
			}
			else
			{
				if (flag)
				{
					HandleTypingInput(current);
				}
				else
				{
					UnsubscribeText();
				}
				target.PreAnimationTick();
			}
		}

		private void RunEditor()
		{
			//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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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)
			Keyboard current = Keyboard.current;
			Mouse current2 = Mouse.current;
			if (current2 != null)
			{
				Vector2 val = ((InputControl<Vector2>)(object)((Pointer)current2).position).ReadValue();
				Vector2 mouse = default(Vector2);
				((Vector2)(ref mouse))..ctor(val.x, (float)Screen.height - val.y);
				bool flag = ui.HandleInput(mouse, current2.leftButton.wasPressedThisFrame, current2.leftButton.isPressed, current2.leftButton.wasReleasedThisFrame);
				hoverValid = !flag && target.RaycastSurface(BuildRay(val), out hoverHit);
				HandleCameraInput(current2, current, flag);
				HandlePaintInput(current2, current, val, flag);
				ui.SetCursor(cam, hoverValid, hoverHit.Point, hoverHit.Normal, ui.BrushRadius * 0.01f);
				target.FlushTextures();
			}
		}

		private void LateUpdate()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Invalid comparison between Unknown and I4
			if (Active && !((Object)(object)cam == (Object)null) && target != null)
			{
				if ((Object)(object)player != (Object)null)
				{
					player.disableLookInput = true;
					player.disableMoveInput = true;
					player.disableInteract = true;
					player.moveInputVector = Vector2.zero;
					player.isJumping = false;
				}
				ApplyCameraPose();
				target.AssertTPose();
				RunEditor();
				target?.TickVisibility(cam);
				if ((int)Cursor.lockState > 0)
				{
					Cursor.lockState = (CursorLockMode)0;
				}
				if (!Cursor.visible)
				{
					Cursor.visible = true;
				}
			}
		}

		private void HandleTypingInput(Keyboard kb)
		{
			if (kb != null)
			{
				SubscribeText(kb);
				if (((ButtonControl)kb.escapeKey).wasPressedThisFrame)
				{
					ui.TypeCancel();
				}
				else if (((ButtonControl)kb.enterKey).wasPressedThisFrame || ((ButtonControl)kb.numpadEnterKey).wasPressedThisFrame)
				{
					ui.TypeCommit();
				}
				else if (((ButtonControl)kb.backspaceKey).wasPressedThisFrame)
				{
					ui.TypeBackspace();
				}
			}
		}

		private void SubscribeText(Keyboard kb)
		{
			if (textDevice != kb)
			{
				UnsubscribeText();
				textDevice = kb;
				kb.onTextInput += OnTextInput;
			}
		}

		private void UnsubscribeText()
		{
			if (textDevice != null)
			{
				try
				{
					textDevice.onTextInput -= OnTextInput;
				}
				catch
				{
				}
				textDevice = null;
			}
		}

		private void OnTextInput(char c)
		{
			ui.TypeChar(c);
		}

		private Ray BuildRay(Vector2 screenPos)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return CameraMath.BuildRay(cam, screenPos);
		}

		private int GetEnvironmentMask()
		{
			if ((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.collidersAndRoomMaskAndDefault != 0)
			{
				return StartOfRound.Instance.collidersAndRoomMaskAndDefault;
			}
			return LayerMask.GetMask(new string[7] { "Room", "Colliders", "Default", "Terrain", "PlaceableShipObject", "Props", "Railing" });
		}

		private void ApplyCameraPose()
		{
			//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_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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_0138: 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_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: 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_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fa: 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_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: 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_0118: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cam == (Object)null || target == null)
			{
				return;
			}
			Vector3 anchor = target.GetAnchor();
			int environmentMask = GetEnvironmentMask();
			Vector3 val = anchor + panOffset;
			Vector3 val2 = val - anchor;
			float magnitude = ((Vector3)(ref val2)).magnitude;
			pivot = val;
			if (magnitude > 0.01f)
			{
				Vector3 val3 = val2 / magnitude;
				RaycastHit val4 = default(RaycastHit);
				if (Physics.SphereCast(anchor, 0.12f, val3, ref val4, magnitude, environmentMask, (QueryTriggerInteraction)1) && (Object)(object)((RaycastHit)(ref val4)).collider != (Object)null && !((RaycastHit)(ref val4)).collider.isTrigger && ((Object)(object)player == (Object)null || !((Component)((RaycastHit)(ref val4)).collider).transform.IsChildOf(((Component)player).transform)))
				{
					float num = Mathf.Max(0f, ((RaycastHit)(ref val4)).distance - 0.06f);
					pivot = anchor + val3 * num;
				}
			}
			Quaternion val5 = Quaternion.Euler(pitch, yaw, 0f);
			Vector3 val6 = val5 * Vector3.back;
			float num2 = ZoomSteps[zoomIndex];
			float num3 = num2;
			float num4 = 0.1f;
			Ray val7 = default(Ray);
			((Ray)(ref val7))..ctor(pivot, val6);
			RaycastHit[] array = Physics.SphereCastAll(val7, num4, num2, environmentMask, (QueryTriggerInteraction)1);
			float num5 = num2;
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val8 = array[i];
				if (!((Object)(object)((RaycastHit)(ref val8)).collider == (Object)null) && !((RaycastHit)(ref val8)).collider.isTrigger && (!((Object)(object)player != (Object)null) || !((Component)((RaycastHit)(ref val8)).collider).transform.IsChildOf(((Component)player).transform)) && ((RaycastHit)(ref val8)).distance < num5)
				{
					num5 = ((RaycastHit)(ref val8)).distance;
				}
			}
			RaycastHit val9 = default(RaycastHit);
			if (Physics.Raycast(val7, ref val9, num2, environmentMask, (QueryTriggerInteraction)1) && (Object)(object)((RaycastHit)(ref val9)).collider != (Object)null && !((RaycastHit)(ref val9)).collider.isTrigger && ((Object)(object)player == (Object)null || !((Component)((RaycastHit)(ref val9)).collider).transform.IsChildOf(((Component)player).transform)))
			{
				float num6 = Mathf.Max(0.12f, ((RaycastHit)(ref val9)).distance - 0.06f);
				if (num6 < num5)
				{
					num5 = num6;
				}
			}
			if (num5 < num2)
			{
				num3 = Mathf.Max(0.18f, num5);
			}
			((Component)cam).transform.SetPositionAndRotation(pivot + val6 * num3, val5);
		}

		private void Enter(PlayerControllerB p)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: 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)
			try
			{
				player = p;
				cam = p.gameplayCamera;
				if ((Object)(object)cam == (Object)null)
				{
					return;
				}
				if (target == null)
				{
					target = new PaintTarget(p);
				}
				if (target.EnsureSetup())
				{
					camLocalPos = ((Component)cam).transform.localPosition;
					camLocalRot = ((Component)cam).transform.localRotation;
					camNear = cam.nearClipPlane;
					camFov = cam.fieldOfView;
					cam.nearClipPlane = Mathf.Min(camNear, 0.03f);
					panOffset = Vector3.zero;
					pivot = target.GetAnchor();
					yaw = ((Component)p).transform.eulerAngles.y + 180f;
					pitch = 6f;
					zoomIndex = 5;
					target.SetPerCameraVisibility(Plugin.RecordingCompat.Value);
					target.SetThirdPerson(on: true, cam);
					target.SetShadows(ui.ShadowsOn);
					ui.HasMoreCompany = HasMoreCompany;
					ui.CosmeticsOn = CosmeticsVisible;
					target.SetCosmeticsVisible(CosmeticsVisible);
					LockGameInput(locked: true);
					Active = true;
					ApplyCameraPose();
					AudioSystem.PlayOpen();
					if (Plugin.FreezePose.Value)
					{
						((MonoBehaviour)this).StartCoroutine(FreezePoseSoon());
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Failed to open the paint editor: {arg}");
				Exit();
			}
		}

		public void Exit()
		{
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			if (!Active)
			{
				return;
			}
			Active = false;
			try
			{
				AudioSystem.PlayClose();
				target?.EndStroke();
				target?.SetTPose(on: false);
				target?.SetFlatView(on: false);
				ui.TPoseOn = false;
				ui.FlatViewOn = false;
				ui.SetPresetsOpen(open: false);
				UnsubscribeText();
				target?.SetThirdPerson(on: false, cam);
				if (Plugin.AutoSave.Value)
				{
					target?.Save();
				}
				PublishPaint();
				if ((Object)(object)cam != (Object)null)
				{
					((Component)cam).transform.localPosition = camLocalPos;
					((Component)cam).transform.localRotation = camLocalRot;
					cam.nearClipPlane = camNear;
					cam.fieldOfView = camFov;
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Error while closing the paint editor: {arg}");
			}
			finally
			{
				LockGameInput(locked: false);
				ThawPose();
			}
		}

		private void PublishPaint()
		{
			try
			{
				if (target != null && target.TryGetSnapshot(out var albedoPixels, out var maskPixels, out var textureSize))
				{
					ChameleonNet.PublishLocal(albedoPixels, maskPixels, textureSize);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Publishing paint to the lobby failed: {arg}");
			}
		}

		private IEnumerator FreezePoseSoon()
		{
			yield return (object)new WaitForSeconds(0.35f);
			if (Active && !((Object)(object)player == (Object)null) && !((Object)(object)player.playerBodyAnimator == (Object)null))
			{
				savedAnimatorSpeed = player.playerBodyAnimator.speed;
				player.playerBodyAnimator.speed = 0f;
				animatorFrozen = true;
			}
		}

		private void ThawPose()
		{
			if (animatorFrozen)
			{
				animatorFrozen = false;
				if ((Object)(object)player != (Object)null && (Object)(object)player.playerBodyAnimator != (Object)null)
				{
					player.playerBodyAnimator.speed = ((savedAnimatorSpeed <= 0f) ? 1f : savedAnimatorSpeed);
				}
			}
		}

		private void LockGameInput(bool locked)
		{
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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)
			try
			{
				IngamePlayerSettings instance = IngamePlayerSettings.Instance;
				if ((Object)(object)instance != (Object)null && (Object)(object)instance.playerInput != (Object)null && (Object)(object)instance.playerInput.actions != (Object)null)
				{
					if (locked)
					{
						instance.playerInput.actions.Disable();
					}
					else
					{
						instance.playerInput.actions.Enable();
					}
				}
			}
			catch
			{
			}
			if ((Object)(object)player != (Object)null)
			{
				try
				{
					player.disableLookInput = locked;
					player.disableMoveInput = locked;
					player.disableInteract = locked;
					if (player.playerActions != null)
					{
						MovementActions movement;
						if (locked)
						{
							player.playerActions.Disable();
							movement = player.playerActions.Movement;
							((MovementActions)(ref movement)).Disable();
						}
						else
						{
							player.playerActions.Enable();
							movement = player.playerActions.Movement;
							((MovementActions)(ref movement)).Enable();
						}
					}
				}
				catch
				{
				}
			}
			if (!locked)
			{
				Cursor.lockState = (CursorLockMode)1;
				Cursor.visible = false;
			}
			else
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
		}

		private void HandleCameraInput(Mouse mouse, Keyboard kb, bool uiCaptured)
		{
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			if (((InputControl<float>)(object)((Vector2Control)mouse.scroll).y).ReadValue() != 0f)
			{
				float num = ((InputControl<float>)(object)((Vector2Control)mouse.scroll).y).ReadValue();
				if (kb != null && (((ButtonControl)kb.leftAltKey).isPressed || ((ButtonControl)kb.rightAltKey).isPressed))
				{
					float num2 = ((((ButtonControl)kb.leftShiftKey).isPressed || ((ButtonControl)kb.rightShiftKey).isPressed) ? 0.2f : 1f);
					ui.BrushRadius = Mathf.Clamp(ui.BrushRadius + ((num > 0f) ? num2 : (0f - num2)), 0.2f, 50f);
				}
				else if (!ui.TryScrollPresets(num) && !uiCaptured)
				{
					int num3 = zoomIndex;
					if (num > 0f && zoomIndex > 0)
					{
						zoomIndex--;
					}
					if (num < 0f && zoomIndex < ZoomSteps.Length - 1)
					{
						zoomIndex++;
					}
				}
			}
			if (mouse.middleButton.isPressed)
			{
				Vector2 val = ((InputControl<Vector2>)(object)((Pointer)mouse).delta).ReadValue();
				if (kb != null && (((ButtonControl)kb.leftShiftKey).isPressed || ((ButtonControl)kb.rightShiftKey).isPressed))
				{
					float num4 = Plugin.PanSensitivity.Value * ZoomSteps[zoomIndex];
					panOffset += ((Component)cam).transform.right * ((0f - val.x) * num4) + ((Component)cam).transform.up * ((0f - val.y) * num4);
					panOffset = Vector3.ClampMagnitude(panOffset, 3.5f);
				}
				else
				{
					float value = Plugin.OrbitSensitivity.Value;
					float num5 = (Plugin.InvertOrbitY.Value ? (-1f) : 1f);
					yaw = Mathf.Repeat(yaw + val.x * value, 360f);
					pitch = Mathf.Clamp(pitch - val.y * value * num5, -80f, 85f);
				}
			}
		}

		private void HandlePaintInput(Mouse mouse, Keyboard kb, Vector2 screenPos, bool uiCaptured)
		{
			//IL_0023: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			if (kb != null && !ui.CapturingText)
			{
				if (((ButtonControl)kb[Plugin.PickKey.Value]).isPressed && !uiCaptured)
				{
					pickingWithSpace = true;
					shouldPickScreen = true;
					pickScreenPos = screenPos;
				}
				else if (pickingWithSpace)
				{
					pickingWithSpace = false;
					ui.Remember(ui.Tint, ui.Metallic, ui.Smoothness);
					AudioSystem.PlaySample();
				}
				bool flag = ((ButtonControl)kb.leftCtrlKey).isPressed || ((ButtonControl)kb.rightCtrlKey).isPressed;
				if (flag && ((ButtonControl)kb.zKey).wasPressedThisFrame)
				{
					RequestUndo();
				}
				if (flag && ((ButtonControl)kb.rKey).wasPressedThisFrame)
				{
					RequestReset();
				}
				Key value = Plugin.TPoseKey.Value;
				if (!flag && (int)value != 0 && ((ButtonControl)kb[value]).wasPressedThisFrame)
				{
					SetTPose(!ui.TPoseOn);
					AudioSystem.PlayClick();
				}
				Key value2 = Plugin.FlatViewKey.Value;
				if (!flag && (int)value2 != 0 && ((ButtonControl)kb[value2]).wasPressedThisFrame)
				{
					SetFlatView(!ui.FlatViewOn);
					AudioSystem.PlayClick();
				}
				Key value3 = Plugin.PresetsKey.Value;
				if (!flag && (int)value3 != 0 && ((ButtonControl)kb[value3]).wasPressedThisFrame)
				{
					ui.TogglePresets();
					AudioSystem.PlayClick();
				}
			}
			if (uiCaptured || mouse.middleButton.isPressed)
			{
				target.EndStroke();
				return;
			}
			bool isPressed = mouse.rightButton.isPressed;
			bool isPressed2 = mouse.leftButton.isPressed;
			if (mouse.leftButton.wasPressedThisFrame || mouse.rightButton.wasReleasedThisFrame)
			{
				target.BeginStroke();
				ui.Remember(ui.Tint, ui.Metallic, ui.Smoothness);
				ui.ClearWearing();
			}
			if (isPressed2 || isPressed)
			{
				if (hoverValid)
				{
					target.StrokeTo(hoverHit, ui.Brush, isPressed && !isPressed2);
				}
				else
				{
					target.BreakStroke();
				}
			}
			if ((mouse.leftButton.wasReleasedThisFrame || mouse.rightButton.wasReleasedThisFrame) && !mouse.leftButton.isPressed && !mouse.rightButton.isPressed)
			{
				target.EndStroke();
			}
		}

		private void ExecuteScreenPick(Vector2 screenPos)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: 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_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Log.LogInfo((object)$"[Eyedropper] Pick triggered at screenPos=({screenPos.x:0}, {screenPos.y:0}) [Screen: {Screen.width}x{Screen.height}]");
			if (hoverValid)
			{
				target.SampleAt(hoverHit.UV, out var color, out var metallic, out var smoothness);
				Plugin.Log.LogInfo((object)$"[Eyedropper] Sampled own player paint at UV=({hoverHit.UV.x:0.000}, {hoverHit.UV.y:0.000}) -> Color={ToHex(color)} (RGB: {color.r:0.00},{color.g:0.00},{color.b:0.00}), Met={metallic:0.00}, Smooth={smoothness:0.00}");
				ui.AdoptSample(color, metallic, smoothness, "own paint");
				return;
			}
			Ray ray = BuildRay(screenPos);
			Plugin.Log.LogInfo((object)$"[Eyedropper] Firing MaterialProbe ray from origin=({((Ray)(ref ray)).origin.x:0.00},{((Ray)(ref ray)).origin.y:0.00},{((Ray)(ref ray)).origin.z:0.00}) dir=({((Ray)(ref ray)).direction.x:0.00},{((Ray)(ref ray)).direction.y:0.00},{((Ray)(ref ray)).direction.z:0.00})");
			if (MaterialProbe.Sample(ray, ((Object)(object)player != (Object)null) ? ((Component)player).transform : null, out var color2, out var metallic2, out var smoothness2, out var what))
			{
				Plugin.Log.LogInfo((object)$"[Eyedropper] MaterialProbe adopted: {what} -> Color={ToHex(color2)} (RGB: {color2.r:0.00},{color2.g:0.00},{color2.b:0.00}), Met={metallic2:0.00}, Smooth={smoothness2:0.00}");
				ui.AdoptSample(color2, metallic2, smoothness2, what);
			}
			else
			{
				Plugin.Log.LogInfo((object)"[Eyedropper] MaterialProbe did not find readable mesh UV. Starting ReadScreenPixel coroutine...");
				if (!(Time.unscaledTime - lastScreenRead < 0.06f))
				{
					lastScreenRead = Time.unscaledTime;
					((MonoBehaviour)this).StartCoroutine(ReadScreenPixel(screenPos));
				}
			}
		}

		private IEnumerator ReadScreenPixel(Vector2 screenPos)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			yield return (object)new WaitForEndOfFrame();
			Texture2D tex = null;
			RenderTexture prev = RenderTexture.active;
			RenderTexture tempRt = null;
			try
			{
				int px = Mathf.Clamp(Mathf.RoundToInt(screenPos.x), 0, Screen.width - 1);
				int py = Mathf.Clamp(Mathf.RoundToInt(screenPos.y), 0, Screen.height - 1);
				tex = new Texture2D(1, 1, (TextureFormat)4, false, false);
				_ = Color.black;
				Color col;
				if ((Object)(object)cam != (Object)null && (Object)(object)cam.targetTexture != (Object)null)
				{
					tempRt = RenderTexture.GetTemporary(1, 1, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
					((Texture)tempRt).filterMode = (FilterMode)0;
					float normX = Mathf.Clamp01(screenPos.x / (float)Screen.width);
					float normY = Mathf.Clamp01(screenPos.y / (float)Screen.height);
					Vector2 scale = new Vector2(1f / (float)Mathf.Max(1, ((Texture)cam.targetTexture).width), 1f / (float)Mathf.Max(1, ((Texture)cam.targetTexture).height));
					Vector2 offset = new Vector2(normX - scale.x * 0.5f, normY - scale.y * 0.5f);
					Graphics.Blit((Texture)(object)cam.targetTexture, tempRt, scale, offset);
					RenderTexture.active = tempRt;
					tex.ReadPixels(new Rect(0f, 0f, 1f, 1f), 0, 0);
					tex.Apply();
					col = tex.GetPixel(0, 0);
				}
				else
				{
					RenderTexture.active = null;
					tex.ReadPixels(new Rect((float)px, (float)py, 1f, 1f), 0, 0);
					tex.Apply();
					col = tex.GetPixel(0, 0);
				}
				col.a = 1f;
				Plugin.Log.LogInfo((object)$"[Eyedropper ReadScreenPixel] Sampled screen at ({px}, {py}) -> Color={ToHex(col)} (Raw RGBA: {col.r:0.000}, {col.g:0.000}, {col.b:0.000}, {col.a:0.000}), LinearSpace={QualitySettings.activeColorSpace}");
				ui.AdoptSample(col, ui.Metallic, ui.Smoothness, "screen");
			}
			catch (Exception ex)
			{
				Exception e = ex;
				Plugin.Log.LogWarning((object)("[Eyedropper ReadScreenPixel FAILED]: " + e.Message + "\n" + e.StackTrace));
			}
			finally
			{
				RenderTexture.active = prev;
				if ((Object)(object)tempRt != (Object)null)
				{
					RenderTexture.ReleaseTemporary(tempRt);
				}
				if ((Object)(object)tex != (Object)null)
				{
					Object.Destroy((Object)(object)tex);
				}
			}
		}

		private static string ToHex(Color c)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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)
			return "#" + ColorUtility.ToHtmlStringRGB(new Color(Mathf.Clamp01(c.r), Mathf.Clamp01(c.g), Mathf.Clamp01(c.b)));
		}

		private void OnGUI()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (Active)
			{
				if (shouldPickScreen)
				{
					shouldPickScreen = false;
					ExecuteScreenPick(pickScreenPos);
				}
				ui.Draw(this, target);
			}
		}

		internal void RequestFill()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (target != null)
			{
				ui.Remember(ui.Tint, ui.Metallic, ui.Smoothness);
				ui.ClearWearing();
				target.FillAll(ui.Brush);
				AudioSystem.PlaySuit();
			}
		}

		internal void RequestUndo()
		{
			target?.Undo();
			AudioSystem.PlayClick();
		}

		internal void RequestReset()
		{
			target?.ResetPaint();
			ui.ClearWearing();
			AudioSystem.PlaySuit();
		}

		internal void RequestSave()
		{
			target?.Save();
			AudioSystem.PlaySuit();
		}

		internal void RequestLoad()
		{
			target?.Load();
			AudioSystem.PlaySuit();
		}

		internal void RequestClose()
		{
			Exit();
		}

		internal void RequestSavePreset(string name)
		{
			if (Active && target != null && target.IsReady)
			{
				((MonoBehaviour)this).StartCoroutine(SavePresetRoutine(name));
			}
		}

		private IEnumerator SavePresetRoutine(string name)
		{
			yield return (object)new WaitForEndOfFrame();
			Texture2D shot = CaptureModelShot(384);
			if (target == null || !target.TryGetSnapshot(out var albedo, out var mask, out var texSize))
			{
				if ((Object)(object)shot != (Object)null)
				{
					Object.Destroy((Object)(object)shot);
				}
				ui.Announce("Nothing to save yet");
				yield break;
			}
			SuitPreset saved = SuitPresets.Save(name, albedo, mask, texSize, shot);
			if (saved != null)
			{
				ui.OnPresetSaved(saved);
				ui.Announce("Saved '" + saved.Name + "'");
				AudioSystem.PlaySuit();
				yield break;
			}
			if ((Object)(object)shot != (Object)null)
			{
				Object.Destroy((Object)(object)shot);
			}
			ui.Announce("Saving the preset failed - see the log");
		}

		internal void RequestApplyPreset(SuitPreset preset)
		{
			if (target != null && preset != null)
			{
				if (!SuitPresets.TryRead(preset, out var albedo, out var mask, out var size))
				{
					ui.Announce("'" + preset.Name + "' could not be read");
					AudioSystem.PlayClick();
				}
				else if (target.ApplyLayers(albedo, mask, size))
				{
					ui.Announce("Wearing '" + preset.Name + "'" + ((mask == null) ? " (colour only)" : ""));
					AudioSystem.PlaySuit();
				}
				else
				{
					ui.Announce("'" + preset.Name + "' would not apply");
				}
			}
		}

		private Texture2D CaptureModelShot(int height)
		{
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: 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_0114: Expected O, but got Unknown
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cam == (Object)null || target == null)
			{
				return null;
			}
			if (!target.TryGetPosedBounds(out var bounds))
			{
				return null;
			}
			int num = Mathf.RoundToInt((float)height * 0.75f);
			RenderTexture val = null;
			RenderTexture active = RenderTexture.active;
			RenderTexture targetTexture = cam.targetTexture;
			Vector3 position = ((Component)cam).transform.position;
			Quaternion rotation = ((Component)cam).transform.rotation;
			float fieldOfView = cam.fieldOfView;
			bool flatView = target.FlatView;
			Texture2D val2 = null;
			try
			{
				target.SetFlatView(on: true);
				PoseForPortrait(bounds);
				cam.aspect = 0.75f;
				val = RenderTexture.GetTemporary(num, height, 24, (RenderTextureFormat)0);
				cam.targetTexture = val;
				cam.Render();
				RenderTexture.active = val;
				val2 = new Texture2D(num, height, (TextureFormat)4, false)
				{
					hideFlags = (HideFlags)61
				};
				val2.ReadPixels(new Rect(0f, 0f, (float)num, (float)height), 0, 0);
				val2.Apply(false);
				if (!CutOutBody(val2))
				{
					Object.Destroy((Object)(object)val2);
					val2 = null;
					Plugin.Log.LogInfo((object)"[Presets] Preview came back empty; falling back to the paint's palette.");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Presets] Preview render failed (" + ex.Message + "); falling back to the paint's palette."));
				if ((Object)(object)val2 != (Object)null)
				{
					Object.Destroy((Object)(object)val2);
					val2 = null;
				}
			}
			finally
			{
				cam.targetTexture = targetTexture;
				RenderTexture.active = active;
				if ((Object)(object)val != (Object)null)
				{
					RenderTexture.ReleaseTemporary(val);
				}
				cam.fieldOfView = fieldOfView;
				cam.ResetAspect();
				((Component)cam).transform.SetPositionAndRotation(position, rotation);
				if (!flatView)
				{
					target.SetFlatView(on: false);
				}
			}
			return val2;
		}

		private void PoseForPortrait(Bounds body)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (((Object)(object)player != (Object)null) ? ((Component)player).transform.forward : Vector3.forward);
			val.y = 0f;
			val = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val)).normalized : Vector3.forward);
			cam.fieldOfView = 34f;
			float num = Mathf.Tan(0.29670596f);
			float num2 = num * 0.75f;
			float num3 = Mathf.Max(((Bounds)(ref body)).extents.x, ((Bounds)(ref body)).extents.z);
			float num4 = Mathf.Max(((Bounds)(ref body)).extents.y / num, num3 / num2) * 1.14f;
			Vector3 val2 = ((Bounds)(ref body)).center + val * num4;
			((Component)cam).transform.SetPositionAndRotation(val2, Quaternion.LookRotation(-val, Vector3.up));
		}

		private bool CutOutBody(Texture2D shot)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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_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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: 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_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_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: 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_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_0538: Unknown result type (might be due to invalid IL or missing references)
			//IL_053d: Unknown result type (might be due to invalid IL or missing references)
			//IL_053f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0549: Unknown result type (might be due to invalid IL or missing references)
			//IL_0557: Unknown result type (might be due to invalid IL or missing references)
			//IL_064a: Unknown result type (might be due to invalid IL or missing references)
			//IL_064f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0684: Unknown result type (might be due to invalid IL or missing references)
			//IL_069f: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_06df: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e1: Unknown result type (might be due to invalid IL or missing references)
			if (!target.TryGetPosedGeometry(out var worldVertices, out var triangles))
			{
				return false;
			}
			int width = ((Texture)shot).width;
			int height = ((Texture)shot).height;
			int num = width * 3;
			int num2 = height * 3;
			Matrix4x4 val = cam.projectionMatrix * CameraMath.ViewMatrix(cam);
			Vector3[] array = (Vector3[])(object)new Vector3[worldVertices.Length];
			for (int i = 0; i + 2 < triangles.Length; i += 3)
			{
				int num3 = triangles[i];
				int num4 = triangles[i + 1];
				int num5 = triangles[i + 2];
				Vector3 val2 = Vector3.Cross(worldVertices[num4] - worldVertices[num3], worldVertices[num5] - worldVertices[num3]);
				ref Vector3 reference = ref array[num3];
				reference += val2;
				ref Vector3 reference2 = ref array[num4];
				reference2 += val2;
				ref Vector3 reference3 = ref array[num5];
				reference3 += val2;
			}
			for (int j = 0; j < array.Length; j++)
			{
				array[j] = ((Vector3)(ref array[j])).normalized;
			}
			Vector3[] array2 = (Vector3[])(object)new Vector3[worldVertices.Length];
			for (int k = 0; k < worldVertices.Length; k++)
			{
				Vector4 val3 = val * new Vector4(worldVertices[k].x, worldVertices[k].y, worldVertices[k].z, 1f);
				if (val3.w <= 1E-05f)
				{
					array2[k] = new Vector3(0f, 0f, -1f);
					continue;
				}
				float num6 = 1f / val3.w;
				array2[k] = new Vector3((val3.x * num6 * 0.5f + 0.5f) * (float)num, (val3.y * num6 * 0.5f + 0.5f) * (float)num2, val3.w);
			}
			float[] array3 = new float[num * num2];
			float[] array4 = new float[num * num2];
			for (int l = 0; l < array3.Length; l++)
			{
				array3[l] = float.MaxValue;
			}
			Quaternion rotation = ((Component)cam).transform.rotation;
			Vector3 val4 = new Vector3(-0.45f, 0.62f, -1f);
			Vector3 key = rotation * ((Vector3)(ref val4)).normalized;
			Vector3 forward = ((Component)cam).transform.forward;
			long num7 = 0L;
			for (int m = 0; m + 2 < triangles.Length; m += 3)
			{
				int num8 = triangles[m];
				int num9 = triangles[m + 1];
				int num10 = triangles[m + 2];
				Vector3 val5 = array2[num8];
				Vector3 val6 = array2[num9];
				Vector3 val7 = array2[num10];
				if (!(val5.z < 0f) && !(val6.z < 0f) && !(val7.z < 0f))
				{
					num7 += ShadeTriangle(array3, array4, num, num2, val5, val6, val7, array[num8], array[num9], array[num10], key, forward);
				}
			}
			if (num7 < (long)num * (long)num2 / 900)
			{
				Plugin.Log.LogWarning((object)$"[Presets] Silhouette covered almost nothing ({num7} subpixels of {(long)num * (long)num2}).");
				return false;
			}
			double num11 = 0.0;
			long num12 = 0L;
			for (int n = 0; n < array4.Length; n++)
			{
				if (array3[n] != float.MaxValue)
				{
					num11 += (double)array4[n];
					num12++;
				}
			}
			float num13 = ((num12 > 0 && num11 > 1E-06) ? ((float)((double)num12 / num11)) : 1f);
			Color32[] pixels = shot.GetPixels32();
			byte[] array5 = new byte[width * height];
			float[] array6 = new float[width * height];
			int[] array7 = new int[256];
			long num14 = 0L;
			int num15 = 255;
			int num16 = 0;
			for (int num17 = 0; num17 < height; num17++)
			{
				for (int num18 = 0; num18 < width; num18++)
				{
					int num19 = 0;
					float num20 = 0f;
					for (int num21 = 0; num21 < 3; num21++)
					{
						int num22 = (num17 * 3 + num21) * num + num18 * 3;
						for (int num23 = 0; num23 < 3; num23++)
						{
							if (array3[num22 + num23] != float.MaxValue)
							{
								num19++;
								num20 += array4[num22 + num23];
							}
						}
					}
					int num24 = num17 * width + num18;
					array5[num24] = (byte)(num19 * 255 / 9);
					array6[num24] = ((num19 > 0) ? (num20 / (float)num19 * num13) : 1f);
					Color32 val8 = pixels[num24];
					int num25 = val8.r * 77 + val8.g * 150 + val8.b * 29 >> 8;
					if (num25 < num15)
					{
						num15 = num25;
					}
					if (num25 > num16)
					{
						num16 = num25;
					}
					if (num19 == 9)
					{
						array7[num25]++;
						num14++;
					}
				}
			}
			if (num14 == 0L || num16 - num15 < 4)
			{
				Plugin.Log.LogWarning((object)$"[Presets] Render came back blank (body px {num14}, frame range {num15}-{num16}).");
				return false;
			}
			byte[] array8 = BuildLevels(array7, num14);
			if (array8 == null)
			{
				return false;
			}
			for (int num26 = 0; num26 < pixels.Length; num26++)
			{
				Color32 val9 = pixels[num26];
				byte b = array5[num26];
				if (b == 0)
				{
					val9.r = 0;
					val9.g = 0;
					val9.b = 0;
				}
				else
				{
					val9.r = Shaded(array8[val9.r], array6[num26]);
					val9.g = Shaded(array8[val9.g], array6[num26]);
					val9.b = Shaded(array8[val9.b], array6[num26]);
				}
				val9.a = b;
				pixels[num26] = val9;
			}
			shot.SetPixels32(pixels);
			shot.Apply(false);
			return true;
		}

		private byte[] BuildLevels(int[] histogram, long inside)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			double num = 0.0;
			for (int i = 0; i < 256; i++)
			{
				if (histogram[i] > 0)
				{
					num += (double)((float)histogram[i] * Mathf.Pow((float)i / 255f, 2.2f));
				}
			}
			num /= (double)inside;
			if (!target.TryGetSnapshot(out var albedoPixels, out var _, out var _) || albedoPixels == null)
			{
				return null;
			}
			double num2 = 0.0;
			long num3 = 0L;
			int num4 = Mathf.Max(1, albedoPixels.Length / 60000);
			for (int j = 0; j < albedoPixels.Length; j += num4)
			{
				Color32 val = albedoPixels[j];
				float num5 = ((float)(int)val.r * 0.299f + (float)(int)val.g * 0.587f + (float)(int)val.b * 0.114f) / 255f;
				num2 += (double)Mathf.Pow(num5, 2.2f);
				num3++;
			}
			if (num3 == 0)
			{
				return null;
			}
			num2 /= (double)num3;
			float num6 = ((num > 1E-06) ? ((float)(num2 / num)) : 1f);
			num6 = Mathf.Clamp(num6, 0.05f, 64f);
			float num7 = (float)num * num6;
			if (num7 < 0.012f && num > 1E-06)
			{
				num6 = 0.012f / (float)num;
			}
			byte[] array = new byte[256];
			for (int k = 0; k < 256; k++)
			{
				float num8 = Mathf.Pow((float)k / 255f, 2.2f) * num6;
				if (num8 > 0.7f)
				{
					num8 = 0.7f + (num8 - 0.7f) / (1f + (num8 - 0.7f) * 2.2f);
				}
				array[k] = (byte)Mathf.Clamp(Mathf.RoundToInt(Mathf.Pow(Mathf.Min(num8, 1f), 0.45454544f) * 255f), 0, 255);
			}
			return array;
		}

		private static long ShadeTriangle(float[] depth, float[] shade, int width, int height, Vector3 a, Vector3 b, Vector3 c, Vector3 na, Vector3 nb, Vector3 nc, Vector3 key, Vector3 eye)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: 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_02c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Max(0, Mathf.FloorToInt(Mathf.Min(a.x, Mathf.Min(b.x, c.x))));
			int num2 = Mathf.Min(width - 1, Mathf.CeilToInt(Mathf.Max(a.x, Mathf.Max(b.x, c.x))));
			int num3 = Mathf.Max(0, Mathf.FloorToInt(Mathf.Min(a.y, Mathf.Min(b.y, c.y))));
			int num4 = Mathf.Min(height - 1, Mathf.CeilToInt(Mathf.Max(a.y, Mathf.Max(b.y, c.y))));
			if (num > num2 || num3 > num4)
			{
				return 0L;
			}
			float num5 = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
			if (Mathf.Abs(num5) < 1E-06f)
			{
				return 0L;
			}
			float num6 = 1f / num5;
			long num7 = 0L;
			for (int i = num3; i <= num4; i++)
			{
				float num8 = (float)i + 0.5f;
				int num9 = i * width;
				for (int j = num; j <= num2; j++)
				{
					float num10 = (float)j + 0.5f;
					float num11 = ((b.x - a.x) * (num8 - a.y) - (b.y - a.y) * (num10 - a.x)) * num6;
					float num12 = ((c.x - b.x) * (num8 - b.y) - (c.y - b.y) * (num10 - b.x)) * num6;
					float num13 = ((a.x - c.x) * (num8 - c.y) - (a.y - c.y) * (num10 - c.x)) * num6;
					if (num11 < 0f || num12 < 0f || num13 < 0f)
					{
						continue;
					}
					int num14 = num9 + j;
					float num15 = a.z * num12 + b.z * num13 + c.z * num11;
					if (!(num15 >= depth[num14]))
					{
						if (depth[num14] == float.MaxValue)
						{
							num7++;
						}
						depth[num14] = num15;
						Vector3 val = na * num12 + nb * num13 + nc * num11;
						Vector3 val2 = ((Vector3)(ref val)).normalized;
						if (Vector3.Dot(val2, eye) > 0f)
						{
							val2 = -val2;
						}
						float num16 = Mathf.Max(0f, Vector3.Dot(val2, key));
						float num17 = Mathf.Max(0f, Vector3.Dot(val2, -key));
						shade[num14] = 0.37f + 0.84f * num16 + 0.12f * num17;
					}
				}
			}
			return num7;
		}

		private static byte Shaded(byte value, float light)
		{
			float num = Mathf.Pow((float)(int)value / 255f, 2.2f) * light;
			return (byte)Mathf.Clamp(Mathf.RoundToInt(Mathf.Pow(Mathf.Min(num, 1f), 0.45454544f) * 255f), 0, 255);
		}

		internal void SetShadows(bool on)
		{
			ui.ShadowsOn = on;
			target?.SetShadows(on);
		}

		internal void SetTPose(bool on)
		{
			if (target != null)
			{
				ui.TPoseOn = target.SetTPose(on);
			}
		}

		internal void SetFlatView(bool on)
		{
			if (target != null)
			{
				ui.FlatViewOn = target.SetFlatView(on);
			}
		}

		internal void SetCosmeticsVisible(bool on)
		{
			CosmeticsVisible = on;
			ui.CosmeticsOn = on;
			target?.SetCosmeticsVisible(on);
			ApplyGlobalCosmeticsVisibility(on);
			ui.Announce(on ? "Cosmetics: Shown" : "Cosmetics: Hidden");
		}

		internal void ApplyGlobalCosmeticsVisibility(bool on)
		{
			try
			{
				MonoBehaviour[] array = Object.FindObjectsOfType<MonoBehaviour>(true);
				foreach (MonoBehaviour val in array)
				{
					if ((Object)(object)val == (Object)null || ((object)val).GetType().Name != "CosmeticInstance")
					{
						continue;
					}
					Renderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<Renderer>(true);
					foreach (Renderer val2 in componentsInChildren)
					{
						if ((Object)(object)val2 != (Object)null)
						{
							val2.enabled = on;
						}
					}
				}
			}
			catch
			{
			}
		}
	}
	public static class ChameleonNet
	{
		private class Incoming
		{
			public uint BlobId;

			public byte[] Buffer;

			public bool[] Got;

			public int Received;

			public int ChunkCount;
		}

		private class Outgoing
		{
			public ulong Target;

			public ulong Sender;

			public uint BlobId;

			public byte[] Blob;

			public int NextChunk;

			public int ChunkCount;
		}

		private struct Decoded
		{
			public ulong ClientId;

			public byte[] Planes;

			public int Size;

			public byte[] Blob;
		}

		private struct Packed
		{
			public byte[] Blob;

			public ulong Hash;
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnHello;

			public static HandleNamedMessageDelegate <1>__OnData;

			public static Action<ulong> <2>__OnClientDisconnect;
		}

		private const string MsgHello = "MC_Hello";

		private const string MsgData = "MC_Data";

		private const byte Protocol = 1;

		private const int ChunkHeader = 22;

		private const int ChunkPayload = 8192;

		private const int MaxChunks = 514;

		private static NetworkManager boundTo;

		private static bool handlersRegistered;

		private static bool saidHello;

		private static byte[] localBlob;

		private static ulong localHash;

		private static bool compressing;

		private static bool blobDirty;

		private static uint nextBlobId = 1u;

		private static readonly HashSet<ulong> moddedClients = new HashSet<ulong>();

		private static readonly Dictionary<ulong, RemotePaint> remotes = new Dictionary<ulong, RemotePaint>();

		private static readonly Dictionary<ulong, byte[]> cache = new Dictionary<ulong, byte[]>();

		private static readonly Dictionary<ulong, Incoming> inbox = new Dictionary<ulong, Incoming>();

		private static readonly Queue<Outgoing> outbox = new Queue<Outgoing>();

		private static float budget;

		private static float lastTick;

		private static readonly ConcurrentQueue<Decoded> decoded = new ConcurrentQueue<Decoded>();

		private static readonly Dictionary<ulong, Decoded> latest = new Dictionary<ulong, Decoded>();

		private static readonly ConcurrentQueue<Packed> compressed = new ConcurrentQueue<Packed>();

		private static readonly List<ulong> scratchIds = new List<ulong>();

		private static int frame;

		private static NetworkManager Net
		{
			get
			{
				NetworkManager singleton = NetworkManager.Singleton;
				return ((Object)(object)singleton != (Object)null && singleton.IsListening) ? singleton : null;
			}
		}

		private static bool Enabled => Plugin.NetSync != null && Plugin.NetSync.Value;

		public static void Tick()
		{
			if (!Enabled)
			{
				if (handlersRegistered)
				{
					Unbind();
				}
				return;
			}
			DrainCompressed();
			NetworkManager net = Net;
			if ((Object)(object)net == (Object)null)
			{
				if (handlersRegistered)
				{
					Unbind();
				}
				return;
			}
			if (net != boundTo)
			{
				Bind(net);
			}
			if (handlersRegistered)
			{
				Handshake(net);
				if (blobDirty)
				{
					blobDirty = !BroadcastLocal(net);
				}
				PumpOutbox(net);
				ApplyOneDecoded();
				if (++frame % 60 == 0)
				{
					TickRemotes();
				}
			}
		}

		private static void Bind(NetworkManager nm)
		{
			//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_002e: Expected O, but got Unknown
			//IL_004f: 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_005a: Expected O, but got Unknown
			Unbind();
			try
			{
				CustomMessagingManager customMessagingManager = nm.CustomMessagingManager;
				object obj = <>O.<0>__OnHello;
				if (obj == null)
				{
					HandleNamedMessageDelegate val = OnHello;
					<>O.<0>__OnHello = val;
					obj = (object)val;
				}
				customMessagingManager.RegisterNamedMessageHandler("MC_Hello", (HandleNamedMessageDelegate)obj);
				CustomMessagingManager customMessagingManager2 = nm.CustomMessagingManager;
				object obj2 = <>O.<1>__OnData;
				if (obj2 == null)
				{
					HandleNamedMessageDelegate val2 = OnData;
					<>O.<1>__OnData = val2;
					obj2 = (object)val2;
				}
				customMessagingManager2.RegisterNamedMessageHandler("MC_Data", (HandleNamedMessageDelegate)obj2);
				nm.OnClientDisconnectCallback += OnClientDisconnect;
				boundTo = nm;
				handlersRegistered = true;
				saidHello = false;
				if (nm.IsServer)
				{
					moddedClients.Add(nm.LocalClientId);
				}
				if (localBlob != null)
				{
					blobDirty = true;
				}
				Plugin.Log.LogInfo((object)string.Format("[MC net] Bound as {0}, id {1}.", nm.IsServer ? "host" : "client", nm.LocalClientId));
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[MC net] Failed to register handlers: {arg}");
			}
		}

		private static void Unbind()
		{
			if ((Object)(object)boundTo != (Object)null)
			{
				try
				{
					CustomMessagingManager customMessagingManager = boundTo.CustomMessagingManager;
					if (customMessagingManager != null)
					{
						customMessagingManager.UnregisterNamedMessageHandler("MC_Hello");
					}
					CustomMessagingManager customMessagingManager2 = boundTo.CustomMessagingManager;
					if (customMessagingManager2 != null)
					{
						customMessagingManager2.UnregisterNamedMessageHandler("MC_Data");
					}
					boundTo.OnClientDisconnectCallback -= OnClientDisconnect;
				}
				catch
				{
				}
			}
			foreach (RemotePaint value in remotes.Values)
			{
				value.Dispose();
			}
			remotes.Clear();
			moddedClients.Clear();
			cache.Clear();
			inbox.Clear();
			outbox.Clear();
			latest.Clear();
			Decoded result;
			while (decoded.TryDequeue(out result))
			{
			}
			boundTo = null;
			handlersRegistered = false;
			saidHello = false;
		}

		public static void Shutdown()
		{
			Unbind();
		}

		private static void Handshake(NetworkManager nm)
		{
			if (!saidHello && !nm.IsServer && nm.IsConnectedClient)
			{
				SendHello(nm, 0uL);
				saidHello = true;
			}
		}

		private static void OnClientDisconnect(ulong clientId)
		{
			moddedClients.Remove(clientId);
			inbox.Remove(clientId);
			cache.Remove(clientId);
			latest.Remove(clientId);
			if (remotes.TryGetValue(clientId, out var value))
			{
				value.Dispose();
				remotes.Remove(clientId);
			}
			DropQueued((Outgoing o) => o.Target == clientId);
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton != (Object)null && !singleton.IsServer && clientId == singleton.LocalClientId)
			{
				Unbind();
			}
		}

		private static void DropQueued(Func<Outgoing, bool> drop)
		{
			if (outbox.Count == 0)
			{
				return;
			}
			int count = outbox.Count;
			for (int i = 0; i < count; i++)
			{
				Outgoing outgoing = outbox.Dequeue();
				if (!drop(outgoing))
				{
					outbox.Enqueue(outgoing);
				}
			}
		}

		public static void PublishLocal(Color32[] albedo, Color32[] mask, int srcSize)
		{
			if (!Enabled)
			{
				return;
			}
			if (compressing)
			{
				Plugin.Log.LogInfo((object)"[MC net] A publish is already packing; skipping this one.");
				return;
			}
			int num = ((Plugin.NetTextureSize != null) ? Plugin.NetTextureSize.Value : 512);
			byte[] planes = PaintCodec.ExtractPlanes(albedo, mask, srcSize, num);
			if (planes == null)
			{
				return;
			}
			ulong hash = PaintCodec.Hash(planes);
			if (hash == localHash && localBlob != null)
			{
				Plugin.Log.LogInfo((object)"[MC net] Paint unchanged since the last publish; nothing to send.");
				return;
			}
			int size = Mathf.Min(num, srcSize);
			compressing = true;
			Task.Run(delegate
			{
				try
				{
					compressed.Enqueue(new Packed
					{
						Blob = PaintCodec.Compress(planes, size),
						Hash = hash
					});
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("[MC net] Compression failed: " + ex.Message));
					compressed.Enqueue(new Packed
					{
						Blob = null,
						Hash = 0uL
					});
				}
			});
		}

		private static void DrainCompressed()
		{
			Packed result;
			while (compressed.TryDequeue(out result))
			{
				compressing = false;
				if (result.Blob != null && result.Blob.Length != 0)
				{
					if (result.Blob.Length > 4194304)
					{
						Plugin.Log.LogWarning((object)$"[MC net] Packed suit is {result.Blob.Length / 1024} KB, over the limit; not sending.");
						continue;
					}
					localBlob = result.Blob;
					localHash = result.Hash;
					blobDirty = true;
					Plugin.Log.LogInfo((object)$"[MC net] Paint packed to {(float)result.Blob.Length / 1024f:0.0} KB, queued for the lobby.");
				}
			}
		}

		private static bool BroadcastLocal(NetworkManager nm)
		{
			if (localBlob == null)
			{
				return true;
			}
			if (nm.IsServer)
			{
				cache[nm.LocalClientId] = localBlob;
				foreach (ulong moddedClient in moddedClients)
				{
					if (moddedClient != nm.LocalClientId)
					{
						Enqueue(moddedClient, nm.LocalClientId, localBlob);
					}
				}
				return true;
			}
			if (!saidHello || !nm.IsConnectedClient)
			{
				return false;
			}
			Enqueue(0uL, nm.LocalClientId, localBlob);
			return true;
		}

		private static void Enqueue(ulong target, ulong sender, byte[] blob)
		{
			if (blob == null)
			{
				return;
			}
			int num = (blob.Length + 8192 - 1) / 8192;
			if (num > 0 && num <= 514)
			{
				DropQueued((Outgoing o) => o.Target == target && o.Sender == sender);
				outbox.Enqueue(new Outgoing
				{
					Target = target,
					Sender = sender,
					BlobId = nextBlobId++,
					Blob = blob,
					NextChunk = 0,
					ChunkCount = num
				});
			}
		}

		private static void PumpOutbox(NetworkManager nm)
		{
			float unscaledTime = Time.unscaledTime;
			float num = ((lastTick <= 0f) ? 0f : Mathf.Min(unscaledTime - lastTick, 0.5f));
			lastTick = unscaledTime;
			int num2 = ((Plugin.NetUploadKBps != null) ? Plugin.NetUploadKBps.Value : 96);
			float num3 = (float)num2 * 1024f;
			budget = Mathf.Min(budget + num * num3, num3);
			while (outbox.Count > 0)
			{
				Outgoing outgoing = outbox.Peek();
				int num4 = outgoing.NextChunk * 8192;
				int num5 = Mathf.Min(8192, outgoing.Blob.Length - num4);
				if (num5 <= 0)
				{
					outbox.Dequeue();
					continue;
				}
				float num6 = num5 + 22;
				if (budget < num6)
				{
					break;
				}
				if (!SendChunk(nm, outgoing, num4, num5))
				{
					outbox.Dequeue();
					continue;
				}
				budget -= num6;
				if (++outgoing.NextChunk >= outgoing.ChunkCount)
				{
					outbox.Dequeue();
				}
			}
		}

		private unsafe static bool SendChunk(NetworkManager nm, Outgoing o, int offset, int len)
		{
			//IL_001c: 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_0033: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				FastBufferWriter val = default(FastBufferWriter);
				((FastBufferWriter)(ref val))..ctor(22 + len + 8, (Allocator)2, -1);
				try
				{
					((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref o.Sender, default(ForPrimitives));
					((FastBufferWriter)(ref val)).WriteValueSafe<uint>(ref o.BlobId, default(ForPrimitives));
					int num = o.Blob.Length;
					((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
					ushort num2 = (ushort)o.NextChunk;
					((FastBufferWriter)(ref val)).WriteValueSafe<ushort>(ref num2, default(ForPrimitives));
					num2 = (ushort)o.ChunkCount;
					((FastBufferWriter)(ref val)).WriteValueSafe<ushort>(ref num2, default(ForPrimitives));
					num2 = (ushort)len;
					((FastBufferWriter)(ref val)).WriteValueSafe<ushort>(ref num2, default(ForPrimitives));
					((FastBufferWriter)(ref val)).WriteBytesSafe(o.Blob, len, offset);
					nm.CustomMessagingManager.SendNamedMessage("MC_Data", o.Target, val, (NetworkDelivery)4);
				}
				finally
				{
					((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
				}
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)$"[MC net] Dropping transfer to {o.Target}: {ex.Message}");
				return false;
			}
		}

		private unsafe static void SendHello(NetworkManager nm, ulong target)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				FastBufferWriter val = default(FastBufferWriter);
				((FastBufferWriter)(ref val))..ctor(8, (Allocator)2, -1);
				try
				{
					byte b = 1;
					((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
					nm.CustomMessagingManager.SendNamedMessage("MC_Hello", target, val, (NetworkDelivery)2);
				}
				finally
				{
					((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)$"[MC net] Hello to {target} failed: {ex.Message}");
			}
		}

		private static void OnHello(ulong sender, FastBufferReader reader)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				byte b = default(byte);
				((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives));
				if (b != 1)
				{
					Plugin.Log.LogWarning((object)$"[MC net] Client {sender} runs protocol {b}, we run {(byte)1}; not syncing with them.");
					return;
				}
				NetworkManager net = Net;
				if ((Object)(object)net == (Object)null)
				{
					return;
				}
				moddedClients.Add(sender);
				if (net.IsServer)
				{
					SendHello(net, sender);
					int num = 0;
					foreach (KeyValuePair<ulong, byte[]> item in cache)
					{
						if (item.Key != sender)
						{
							Enqueue(sender, item.Key, item.Value);
							num++;
						}
					}
					Plugin.Log.LogInfo((object)$"[MC net] Client {sender} has the mod; sending {num} cached suit(s).");
				}
				else if (localBlob != null)
				{
					blobDirty = true;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)$"[MC net] Malformed hello from {sender}: {ex.Message}");
			}
		}

		private static void OnData(ulong sender, FastBufferReader reader)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager net = Net;
			if ((Object)(object)net == (Object)null)
			{
				return;
			}
			try
			{
				ulong num = default(ulong);
				((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives));
				uint num2 = default(uint);
				((FastBufferReader)(ref reader)).ReadValueSafe<uint>(ref num2, default(ForPrimitives));
				int num3 = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num3, default(ForPrimitives));
				ushort num4 = default(ushort);
				((FastBufferReader)(ref reader)).ReadValueSafe<ushort>(ref num4, default(ForPrimitives));
				ushort num5 = default(ushort);
				((FastBufferReader)(ref reader)).ReadValueSafe<ushort>(ref num5, default(ForPrimitives));
				ushort num6 = default(ushort);
				((FastBufferReader)(ref reader)).ReadValueSafe<ushort>(ref num6, default(ForPrimitives));
				ulong num7 = (net.IsServer ? sender : num);
				if (num3 <= 0 || num3 > 4194304 || num5 <= 0 || num5 > 514 || num4 >= num5 || num6 <= 0 || num6 > 8192 || num4 * 8192 + num6 > num3)
				{
					return;
				}
				if (!inbox.TryGetValue(num7, out var value) || value.BlobId != num2 || value.Buffer.Length != num3)
				{
					Incoming incoming = new Incoming();
					incoming.BlobId = num2;
					incoming.Buffer = new byte[num3];
					incoming.Got = new bool[num5];
					incoming.Received = 0;
					incoming.ChunkCount = num5;
					value = incoming;
					inbox[num7] = value;
				}
				if (!value.Got[num4])
				{
					byte[] src = new byte[num6];
					((FastBufferReader)(ref reader)).ReadBytesSafe(ref src, (int)num6, 0);
					Buffer.BlockCopy(src, 0, value.Buffer, num4 * 8192, num6);
					value.Got[num4] = true;
					if (++value.Received >= value.ChunkCount)
					{
						inbox.Remove(num7);
						OnBlobComplete(num7, value.Buffer);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)$"[MC net] Malformed chunk from {sender}: {ex.Message}");
			}
		}

		private static void OnBlobComplete(ulong owner, byte[] blob)
		{
			Task.Run(delegate
			{
				try
				{
					if (!PaintCodec.Decompress(blob, out var planes, out var size))
					{
						Plugin.Log.LogWarning((object)$"[MC net] Rejected an undecodable suit from {owner}.");
					}
					else
					{
						decoded.Enqueue(new Decoded
						{
							ClientId = owner,
							Planes = planes,
							Size = size,
							Blob = blob
						});
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)$"[MC net] Decode failed for {owner}: {ex.Message}");
				}
			});
		}

		private static void ApplyOneDecoded()
		{
			if (!decoded.TryDequeue(out var result))
			{
				return;
			}
			NetworkManager net = Net;
			if ((Object)(object)net == (Object)null)
			{
				return;
			}
			if (net.IsServer)
			{
				cache[result.ClientId] = result.Blob;
				foreach (ulong moddedClient in moddedClients)
				{
					if (moddedClient != result.ClientId && moddedClient != net.LocalClientId)
					{
						Enqueue(moddedClient, result.ClientId, result.Blob);
					}
				}
			}
			if (result.ClientId != net.LocalClientId)
			{
				latest[result.ClientId] = result;
				TryApply(result.ClientId);
			}
		}

		private static void TryApply(ulong clientId)
		{
			if (!latest.TryGetValue(clientId, out var value))
			{
				return;
			}
			PlayerControllerB val = FindPlayer(clientId);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (!remotes.TryGetValue(clientId, out var value2))
			{
				value2 = (remotes[clientId] = new RemotePaint(clientId));
			}
			try
			{
				value2.Apply(val, value.Planes, value.Size);
				latest.Remove(clientId);
				Plugin.Log.LogInfo((object)$"[MC net] Applied {val.playerUsername}'s paint ({value.Size}px).");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[MC net] Failed to apply " + val.playerUsername + "'s paint: " + ex.Message));
			}
		}

		private static void TickRemotes()
		{
			if (latest.Count > 0)
			{
				scratchIds.Clear();
				scratchIds.AddRange(latest.Keys);
				for (int i = 0; i < scratchIds.Count; i++)
				{
					TryApply(scratchIds[i]);
				}
			}
			if (remotes.Count == 0)
			{
				return;
			}
			foreach (KeyValuePair<ulong, RemotePaint> remote in remotes)
			{
				PlayerControllerB val = FindPlayer(remote.Key);
				i