Decompiled source of ValheimLocalCoOp v1.0.16

ValheimLocalCoop.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.UI;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimLocalCoop
{
	public enum SplitMode
	{
		SideBySide,
		TopBottom
	}
	public enum P1Device
	{
		KeyboardMouse,
		Gamepad0
	}
	public enum FrameMode
	{
		GameFramebuffer,
		ScreenRect
	}
	public enum HudMode
	{
		FitToViewport,
		LeaveFullScreen
	}
	public enum P2HudMode
	{
		Mirror,
		Simple
	}
	public enum WheelMouseMode
	{
		PointerFix,
		Off,
		VirtualStick
	}
	[BepInPlugin("dev.example.valheim.localcoop", "Valheim Local Co-op", "1.0.16")]
	public class SplitScreenPlugin : BaseUnityPlugin
	{
		public const string Guid = "dev.example.valheim.localcoop";

		public const string Name = "Valheim Local Co-op";

		public const string Version = "1.0.16";

		internal static ManualLogSource Log;

		internal static ConfigEntry<SplitMode> Mode;

		internal static ConfigEntry<FrameMode> Frame;

		internal static ConfigEntry<HudMode> P1Hud;

		internal static ConfigEntry<P1Device> Player1Device;

		internal static ConfigEntry<KeyboardShortcut> ToggleKey;

		internal static ConfigEntry<float> LeashDistance;

		internal static ConfigEntry<KeyboardShortcut> RescueKey;

		internal static ConfigEntry<bool> Player2Audio;

		internal static ConfigEntry<int> Player2AreaReduction;

		internal static ConfigEntry<bool> GrassAroundBothPlayers;

		internal static ConfigEntry<WheelMouseMode> WheelMouse;

		internal static ConfigEntry<bool> MouseHelpsP2;

		internal static ConfigEntry<bool> RouteSharedInput;

		internal static ConfigEntry<float> RespawnDelay;

		internal static ConfigEntry<float> CameraDistance;

		internal static ConfigEntry<bool> InvertStickY;

		internal static ConfigEntry<bool> InvertLookY;

		internal static ConfigEntry<int> Pad1Index;

		internal static ConfigEntry<int> Pad2Index;

		internal static ConfigEntry<KeyboardShortcut> DebugKey;

		internal static ConfigEntry<bool> AskForDevices;

		internal static ConfigEntry<P2HudMode> Player2Hud;

		internal static ConfigEntry<float> InventoryScale;

		internal static ConfigEntry<bool> SeparateInventories;

		internal static ConfigEntry<bool> AskForCharacter;

		internal static ConfigEntry<string> LastP2Character;

		internal static ConfigEntry<KeyboardShortcut> AppearanceKey;

		internal static ConfigEntry<float> ExtraGrassDistance;

		internal static ConfigEntry<bool> PerPlayerNameplates;

		internal static ConfigEntry<bool> WorldAroundBothPlayers;

		private Harmony _harmony;

		private bool _showDebug;

		private bool _spyPatched;

		private void Awake()
		{
			//IL_012e: 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_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0408: Unknown result type (might be due to invalid IL or missing references)
			//IL_0422: Unknown result type (might be due to invalid IL or missing references)
			//IL_042c: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Mode = ((BaseUnityPlugin)this).Config.Bind<SplitMode>("Layout", "SplitMode", SplitMode.SideBySide, "Viewport arrangement.");
			Frame = ((BaseUnityPlugin)this).Config.Bind<FrameMode>("Layout", "FrameMode", FrameMode.GameFramebuffer, "GameFramebuffer: reuse the game's own framebuffer (recommended for Valheim 1.0). ScreenRect: Camera.rect fallback.");
			P1Hud = ((BaseUnityPlugin)this).Config.Bind<HudMode>("Layout", "Player1Hud", HudMode.FitToViewport, "FitToViewport: squeeze P1's real HUD into its half. LeaveFullScreen: leave it untouched.");
			Player2Hud = ((BaseUnityPlugin)this).Config.Bind<P2HudMode>("Layout", "Player2Hud", P2HudMode.Mirror, "Mirror (experimental): the game's real HUD is drawn twice per frame, once per player. Simple: a small HUD drawn by this plugin for P2 (use if Mirror misbehaves).");
			InventoryScale = ((BaseUnityPlugin)this).Config.Bind<float>("Layout", "InventoryScale", 0.8f, "Scale of the inventory window while split (it is placed in the half of the player who opened it).");
			SeparateInventories = ((BaseUnityPlugin)this).Config.Bind<bool>("Layout", "SeparateInventories", true, "true: Player 2 gets their own copy of the real inventory window (both can be open at once). false: one shared window + a simple backpack window for the other player.");
			AskForCharacter = ((BaseUnityPlugin)this).Config.Bind<bool>("Characters", "AskForCharacter", true, "After choosing devices, Player 2 picks an existing character, makes a new one, or plays as a guest.");
			LastP2Character = ((BaseUnityPlugin)this).Config.Bind<string>("Characters", "LastPlayer2Character", "", "Remembered automatically.");
			AppearanceKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Characters", "AppearanceKey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Opens the appearance panel (body, hair, beard, colours, name, costume). Use the mouse.");
			ExtraGrassDistance = ((BaseUnityPlugin)this).Config.Bind<float>("World", "ExtraGrassDistance", 50f, "How far (meters) the grass radius may grow so grass also covers Player 2. 0 = off. Higher costs FPS.");
			WorldAroundBothPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("World", "WorldAroundBothPlayers", true, "Load objects, zones and creature AI around Player 2 as well as Player 1.");
			PerPlayerNameplates = ((BaseUnityPlugin)this).Config.Bind<bool>("Layout", "PerPlayerNameplates", true, "Give Player 2 their own enemy/player name plates (a copy of the game's name-plate overlay).");
			Player1Device = ((BaseUnityPlugin)this).Config.Bind<P1Device>("Input", "Player1Device", P1Device.KeyboardMouse, "KeyboardMouse: P1 ignores pads. Gamepad0: P1 uses a gamepad.");
			ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Input", "JoinLeaveKey", new KeyboardShortcut((KeyCode)291, Array.Empty<KeyCode>()), "Join/leave key.");
			InvertStickY = ((BaseUnityPlugin)this).Config.Bind<bool>("Input", "InvertStickY", true, "Only for the legacy single-axis stick methods. Flip if P2 moves inverted.");
			InvertLookY = ((BaseUnityPlugin)this).Config.Bind<bool>("Input", "InvertLookY", false, "Flip P2's vertical look if it feels inverted.");
			Pad1Index = ((BaseUnityPlugin)this).Config.Bind<int>("Input", "Player1PadIndex", 0, "Gamepad index (0-3) used by P1 when P1Device = Gamepad0.");
			Pad2Index = ((BaseUnityPlugin)this).Config.Bind<int>("Input", "Player2PadIndex", 1, "Gamepad index (0-3) used by P2. If fewer pads are connected, the last connected pad is used.");
			LeashDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Co-op", "TetherDistance", 200f, "Meters. Beyond this, Player 2 vanishes in a puff of smoke and reappears next to Player 1. 0 = off (not recommended).");
			RescueKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Co-op", "RescueKey", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Pull Player 2 next to Player 1 and repair Player 1's view (black screen etc.).");
			Player2Audio = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "Player2Sounds", true, "Each player hears the action sounds nearest to them (footsteps, combat, cooking, bows ...) from their own point of view, in 3D. Music and ambience are shared.");
			Player2AreaReduction = ((BaseUnityPlugin)this).Config.Bind<int>("World", "Player2AreaReduction", 0, "Load a smaller area around Player 2 (in zones) to save performance when far apart. 0 = same as Player 1.");
			RouteSharedInput = ((BaseUnityPlugin)this).Config.Bind<bool>("Input", "RouteSharedInput", true, "Game code that doesn't belong to either player (menu buttons, build-menu tabs and close buttons ...) only hears ONE controller: the build menu's owner while it is open, otherwise Player 1. Turn off only if some menu stops reacting to Player 1's controller.");
			MouseHelpsP2 = ((BaseUnityPlugin)this).Config.Bind<bool>("Input", "MouseCanHelpPlayer2", true, "The mouse belongs to Player 1, but can also drag and sort items in Player 2's open inventory. Also switchable on the F10 setup screen and in the F8 panel.");
			WheelMouse = ((BaseUnityPlugin)this).Config.Bind<WheelMouseMode>("Input", "WheelMouseMode", WheelMouseMode.PointerFix, "How the keyboard player's mouse drives the radial wheels (G / T). PointerFix: re-centre the mouse on that player's half. Off: the game's own handling. VirtualStick: turn mouse movement into a stick, like a controller.");
			GrassAroundBothPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("World", "GrassAroundBothPlayers", true, "Give Player 2 their own normal-radius grass when far from Player 1 (instead of one huge grass circle).");
			RespawnDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Co-op", "RespawnDelay", 10f, "Seconds before P2 respawns near P1.");
			CameraDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "P2CameraDistance", 3.5f, "Third-person distance for P2.");
			AskForDevices = ((BaseUnityPlugin)this).Config.Bind<bool>("Input", "AskForDevices", true, "true: F10 opens a setup screen where each player presses a key/button on the device they want (like Project Zomboid). false: use Player1Device / pad indices below without asking.");
			DebugKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Debug", "DebugKey", new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>()), "Toggles the debug overlay and dumps diagnostics + a spy on ZInput calls to the log.");
			_harmony = new Harmony("dev.example.valheim.localcoop");
			Type[] types = typeof(SplitScreenPlugin).Assembly.GetTypes();
			foreach (Type type in types)
			{
				if (!(type == typeof(ZInput_Spy)))
				{
					try
					{
						_harmony.CreateClassProcessor(type).Patch();
					}
					catch (Exception ex)
					{
						Log.LogError((object)("Patch class failed: " + type.Name + " -> " + ex.Message));
					}
				}
			}
			Log.LogInfo((object)"Valheim Local Co-op 1.0.16 loaded.");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void Update()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			LocalPlayerManager.TrackPrimary();
			InvClone.TickRestore();
			NameplateCopy.Ui.TickRestore();
			GrassCopy.TickRestore();
			RadialCopy.TickRestore();
			KeyboardShortcut value = DebugKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				_showDebug = !_showDebug;
				if (_showDebug && !_spyPatched)
				{
					_spyPatched = true;
					try
					{
						_harmony.CreateClassProcessor(typeof(ZInput_Spy)).Patch();
					}
					catch (Exception ex)
					{
						Log.LogError((object)("Input spy failed (continuing without it): " + ex.Message));
					}
				}
				Diagnostics.SpyOn = _showDebug;
				if (_showDebug)
				{
					Diagnostics.Dump();
					if (LocalPlayerManager.Joined)
					{
						SplitCheck.Run(always: true);
					}
				}
			}
			if ((Object)(object)Game.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				DevicePicker.Cancel();
				if (LocalPlayerManager.Joined)
				{
					LocalPlayerManager.Leave();
				}
				return;
			}
			value = ToggleKey.Value;
			bool flag = ((KeyboardShortcut)(ref value)).IsDown();
			Player val = LocalPlayerManager.Players[0];
			SetupUi.Update();
			VMenus.Update();
			if (DevicePicker.Active)
			{
				if (flag || (Object)(object)val == (Object)null)
				{
					DevicePicker.Cancel();
				}
				else if (DevicePicker.Poll())
				{
					AfterDevices(val);
				}
			}
			else if (CharacterPicker.Active)
			{
				if (flag || (Object)(object)val == (Object)null)
				{
					CharacterPicker.Cancel();
				}
				else if (CharacterPicker.Poll())
				{
					LocalPlayerManager.Join(val);
				}
			}
			else if (!LocalPlayerManager.Joined)
			{
				bool flag2 = !AskForDevices.Value && Pads.Down(Pads.Resolve(Pad2Index.Value), 16);
				if ((Object)(object)val != (Object)null && (flag || flag2))
				{
					if (AskForDevices.Value)
					{
						DevicePicker.Begin();
					}
					else
					{
						DeviceMap.ApplyDefaults();
						AfterDevices(val);
					}
				}
			}
			else if (flag)
			{
				LocalPlayerManager.Leave();
			}
			AppearanceUi.Update();
			if (LocalPlayerManager.Joined)
			{
				value = RescueKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					Rescue.Run();
				}
				Rescue.Watchdog();
				SplitCheck.Tick();
				MouseUse.Tick();
				MenuNav.Tick();
				P2Build.Tick();
				if ((Object)(object)val != (Object)null)
				{
					LocalPlayerManager.Tick(val);
				}
				SplitLayout.Tick();
				GameBindings.PollAll();
				Backpack.UpdateInput();
				DragPanels.Update();
				WorldPriority.Tick();
				RadialCopy.TrackOwnerFromInput();
				WheelMouseState.Tick();
				Diagnostics.WheelProbe();
				AudioProxy.Tick();
			}
			else
			{
				AudioProxy.Clear();
			}
		}

		private void AfterDevices(Player p1)
		{
			if (AskForCharacter.Value)
			{
				CharacterPicker.Begin();
				return;
			}
			CharacterSlot.SetPending(null, null);
			LocalPlayerManager.Join(p1);
		}

		private void LateUpdate()
		{
			Costume.Tick();
			if (LocalPlayerManager.Joined)
			{
				SplitLayout.Reassert();
				HudMirror.Render();
			}
		}

		private void OnGUI()
		{
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: 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)
			P2Hud.Draw();
			Backpack.Draw();
			P2Build.Draw();
			if (_showDebug)
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("SPLITSCREEN DEBUG v1.0.16  (F9 hides)");
				stringBuilder.AppendLine("Joined=" + LocalPlayerManager.Joined + "  ActiveSlot=" + LocalPlayerManager.ActiveSlot + "  ctxDepth=" + LocalPlayerManager.Depth + "  (should be 0 / 0 here)");
				stringBuilder.AppendLine("Gamepads seen by Input System: " + Pads.Count);
				for (int i = 0; i < Mathf.Max(1, Mathf.Min(Pads.Count, 4)); i++)
				{
					Pads.Snapshot snapshot = Pads.Cur(i);
					stringBuilder.AppendLine("pad" + i + ": " + (snapshot.Connected ? "CONNECTED" : "-") + "  btn=" + snapshot.Buttons.ToString("X") + "  L=(" + snapshot.LX.ToString("F2") + "," + snapshot.LY.ToString("F2") + ")  R=(" + snapshot.RX.ToString("F2") + "," + snapshot.RY.ToString("F2") + ")");
				}
				Player val = LocalPlayerManager.Players[0];
				Player val2 = LocalPlayerManager.Players[1];
				object obj;
				Vector3 position;
				if (!((Object)(object)val != (Object)null))
				{
					obj = "none";
				}
				else
				{
					position = ((Component)val).transform.position;
					obj = ((Vector3)(ref position)).ToString("F1");
				}
				object obj2;
				if (!((Object)(object)val2 != (Object)null))
				{
					obj2 = "none";
				}
				else
				{
					position = ((Component)val2).transform.position;
					obj2 = ((Vector3)(ref position)).ToString("F1");
				}
				stringBuilder.AppendLine("P1: " + (string?)obj + "   P2: " + (string?)obj2);
				stringBuilder.AppendLine("Cursor: lock=" + ((object)Cursor.lockState/*cast due to .constrained prefix*/).ToString() + " visible=" + Cursor.visible);
				stringBuilder.AppendLine("Frame=" + Frame.Value.ToString() + "  P1Hud=" + P1Hud.Value.ToString() + "  " + SplitLayout.Describe());
				stringBuilder.AppendLine("Devices: P1=" + DeviceMap.Label(0) + "   P2=" + DeviceMap.Label(1) + "   Ask=" + AskForDevices.Value);
				Rect val3 = default(Rect);
				((Rect)(ref val3))..ctor(10f, 10f, 760f, 220f);
				GUI.Box(val3, GUIContent.none);
				GUI.Label(val3, stringBuilder.ToString());
			}
		}
	}
	internal static class Pads
	{
		public struct Snapshot
		{
			public bool Connected;

			public ushort Buttons;

			public float LX;

			public float LY;

			public float RX;

			public float RY;

			public float LT;

			public float RT;

			public bool Has(ushort mask)
			{
				return (Buttons & mask) != 0;
			}
		}

		public const ushort UP = 1;

		public const ushort DOWN = 2;

		public const ushort LEFT = 4;

		public const ushort RIGHT = 8;

		public const ushort START = 16;

		public const ushort BACK = 32;

		public const ushort L3 = 64;

		public const ushort R3 = 128;

		public const ushort LB = 256;

		public const ushort RB = 512;

		public const ushort A = 4096;

		public const ushort B = 8192;

		public const ushort X = 16384;

		public const ushort Y = 32768;

		private static readonly Snapshot[] _cur = new Snapshot[8];

		private static readonly Snapshot[] _prev = new Snapshot[8];

		private static int _frame = -1;

		public static int Count
		{
			get
			{
				//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)
				try
				{
					return Gamepad.all.Count;
				}
				catch
				{
					return 0;
				}
			}
		}

		public static int DeviceIdAt(int i)
		{
			//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)
			try
			{
				ReadOnlyArray<Gamepad> all = Gamepad.all;
				return (i >= 0 && i < all.Count) ? ((InputDevice)all[i]).deviceId : (-1);
			}
			catch
			{
				return -1;
			}
		}

		public static int IndexOfDevice(int id)
		{
			//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)
			try
			{
				ReadOnlyArray<Gamepad> all = Gamepad.all;
				for (int i = 0; i < all.Count && i < 8; i++)
				{
					if (all[i] != null && ((InputDevice)all[i]).deviceId == id)
					{
						return i;
					}
				}
			}
			catch
			{
			}
			return -1;
		}

		public static string NameAt(int i)
		{
			//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)
			try
			{
				ReadOnlyArray<Gamepad> all = Gamepad.all;
				if (i < 0 || i >= all.Count)
				{
					return "Gamepad";
				}
				return (string.IsNullOrEmpty(((InputControl)all[i]).displayName) ? "Gamepad" : ((InputControl)all[i]).displayName) + " #" + (i + 1);
			}
			catch
			{
				return "Gamepad";
			}
		}

		public static int Resolve(int idx)
		{
			int count = Count;
			if (count <= 0)
			{
				return 0;
			}
			return Mathf.Clamp(idx, 0, Mathf.Min(count, 8) - 1);
		}

		public static Snapshot Cur(int i)
		{
			Refresh();
			return _cur[Mathf.Clamp(i, 0, 7)];
		}

		public static Snapshot Prev(int i)
		{
			Refresh();
			return _prev[Mathf.Clamp(i, 0, 7)];
		}

		public static bool Down(int i, ushort mask)
		{
			Snapshot snapshot = Cur(i);
			Snapshot snapshot2 = Prev(i);
			return snapshot.Has(mask) && !snapshot2.Has(mask);
		}

		private static void Refresh()
		{
			if (_frame != Time.frameCount)
			{
				_frame = Time.frameCount;
				for (int i = 0; i < 8; i++)
				{
					_prev[i] = _cur[i];
					_cur[i] = Read(i);
				}
			}
		}

		private static Snapshot Read(int i)
		{
			//IL_000a: 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_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			Snapshot result = default(Snapshot);
			try
			{
				ReadOnlyArray<Gamepad> all = Gamepad.all;
				if (i >= all.Count)
				{
					return result;
				}
				Gamepad val = all[i];
				if (val == null)
				{
					return result;
				}
				result.Connected = true;
				ushort num = 0;
				if (val.buttonSouth.isPressed)
				{
					num |= 0x1000;
				}
				if (val.buttonEast.isPressed)
				{
					num |= 0x2000;
				}
				if (val.buttonWest.isPressed)
				{
					num |= 0x4000;
				}
				if (val.buttonNorth.isPressed)
				{
					num |= 0x8000;
				}
				if (val.leftShoulder.isPressed)
				{
					num |= 0x100;
				}
				if (val.rightShoulder.isPressed)
				{
					num |= 0x200;
				}
				if (val.leftStickButton.isPressed)
				{
					num |= 0x40;
				}
				if (val.rightStickButton.isPressed)
				{
					num |= 0x80;
				}
				if (val.startButton.isPressed)
				{
					num |= 0x10;
				}
				if (val.selectButton.isPressed)
				{
					num |= 0x20;
				}
				if (val.dpad.up.isPressed)
				{
					num |= 1;
				}
				if (val.dpad.down.isPressed)
				{
					num |= 2;
				}
				if (val.dpad.left.isPressed)
				{
					num |= 4;
				}
				if (val.dpad.right.isPressed)
				{
					num |= 8;
				}
				result.Buttons = num;
				Vector2 val2 = Deadzone(((InputControl<Vector2>)(object)val.leftStick).ReadValue(), 0.15f);
				Vector2 val3 = Deadzone(((InputControl<Vector2>)(object)val.rightStick).ReadValue(), 0.15f);
				result.LX = val2.x;
				result.LY = val2.y;
				result.RX = val3.x;
				result.RY = val3.y;
				result.LT = ((InputControl<float>)(object)val.leftTrigger).ReadValue();
				result.RT = ((InputControl<float>)(object)val.rightTrigger).ReadValue();
			}
			catch (Exception ex)
			{
				if (_frame % 600 == 0)
				{
					SplitScreenPlugin.Log.LogWarning((object)("Gamepad read failed: " + ex.Message));
				}
			}
			return result;
		}

		private static Vector2 Deadzone(Vector2 v, float dz)
		{
			//IL_0019: 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_0036: 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_0016: 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)
			float magnitude = ((Vector2)(ref v)).magnitude;
			if (magnitude < dz)
			{
				return Vector2.zero;
			}
			return v * (Mathf.Min(1f, (magnitude - dz) / (1f - dz)) / magnitude);
		}
	}
	internal static class InputRouter
	{
		private class HoldTrack
		{
			public float Start = -1f;

			public float LastPress = -1000f;

			public float LastDur;

			public int ReleaseFrame = -10;
		}

		public static int Bypass;

		private static readonly Dictionary<string, HoldTrack>[] _holds = new Dictionary<string, HoldTrack>[2]
		{
			new Dictionary<string, HoldTrack>(),
			new Dictionary<string, HoldTrack>()
		};

		private static bool Applies()
		{
			if (!LocalPlayerManager.Joined || Bypass > 0)
			{
				return false;
			}
			return LocalPlayerManager.Depth > 0;
		}

		public static void Veto(string method, string button, ref bool result)
		{
			if (!result || button == null || Bypass > 0 || !LocalPlayerManager.Joined || LocalPlayerManager.Depth > 0 || (Object)(object)LocalPlayerManager.Players[1] == (Object)null || !SplitScreenPlugin.RouteSharedInput.Value || DevicePicker.Active || CharacterPicker.Active)
			{
				return;
			}
			int owner = MenuNav.Owner;
			int s = 1 - owner;
			if (DeviceMap.IsKbm(s))
			{
				return;
			}
			int num = DeviceMap.PadIndex(s);
			if (num < 0 || !GameBindings.TryQuery(method, button, num, out var result2) || !result2)
			{
				return;
			}
			if (DeviceMap.IsKbm(owner))
			{
				if (button.StartsWith("Joy", StringComparison.OrdinalIgnoreCase))
				{
					result = false;
				}
				return;
			}
			int num2 = DeviceMap.PadIndex(owner);
			if (num2 >= 0 && GameBindings.TryQuery(method, button, num2, out var result3) && !result3)
			{
				result = false;
			}
		}

		private static int CurrentSlot()
		{
			return LocalPlayerManager.ActiveSlot;
		}

		private static bool Pressed(Pads.Snapshot s, string logical)
		{
			return logical.ToLowerInvariant() switch
			{
				"jump" => s.Has(4096), 
				"dodge" => s.Has(8192), 
				"use" => s.Has(16384), 
				"inventory" => s.Has(32768), 
				"attack" => s.RT > 0.5f, 
				"secondaryattack" => s.Has(512), 
				"block" => s.LT > 0.5f, 
				"altplace" => s.Has(256), 
				"run" => s.Has(64), 
				"crouch" => s.Has(128), 
				"map" => s.Has(32), 
				"hotbarleft" => s.Has(4), 
				"hotbarright" => s.Has(8), 
				"buttona" => s.Has(4096), 
				"buttonb" => s.Has(8192), 
				"buttonx" => s.Has(16384), 
				"buttony" => s.Has(32768), 
				"lbumper" => s.Has(256), 
				"rbumper" => s.Has(512), 
				"ltrigger" => s.LT > 0.5f, 
				"rtrigger" => s.RT > 0.5f, 
				"back" => s.Has(32), 
				"start" => s.Has(16), 
				"lstick" => s.Has(64), 
				"rstick" => s.Has(128), 
				"dpadup" => s.Has(1), 
				"dpaddown" => s.Has(2), 
				"dpadleft" => s.Has(4), 
				"dpadright" => s.Has(8), 
				"lstickleft" => s.LX < -0.5f, 
				"lstickright" => s.LX > 0.5f, 
				"lstickup" => s.LY > 0.5f, 
				"lstickdown" => s.LY < -0.5f, 
				"rstickleft" => s.RX < -0.5f, 
				"rstickright" => s.RX > 0.5f, 
				"rstickup" => s.RY > 0.5f, 
				"rstickdown" => s.RY < -0.5f, 
				_ => false, 
			};
		}

		public static bool OverrideBool(string method, string button, ref bool result)
		{
			if (WheelMouseState.On)
			{
				if (method == "IsGamepadActive" || method == "IsExclusiveGamepadActive")
				{
					result = true;
					return false;
				}
				if (method == "IsMouseActive" || method == "IsGamepadMouseActive")
				{
					result = false;
					return false;
				}
			}
			if (UiInput.BlockKeyboard && button != null && !button.StartsWith("Joy", StringComparison.OrdinalIgnoreCase))
			{
				result = false;
				return false;
			}
			if (!Applies())
			{
				return true;
			}
			int num = CurrentSlot();
			bool flag = DeviceMap.IsKbm(num);
			if (button != null && UiInput.Blocks(num))
			{
				result = false;
				return false;
			}
			if (button != null && !flag && MouseUse.MouseOwnsDrag(num) && (button == "JoyButtonA" || button == "JoyButtonX" || button == "JoyButtonY"))
			{
				result = false;
				return false;
			}
			if (button != null && flag && MouseUse.OverOtherWindow(num) && (button == "Attack" || button == "SecondaryAttack" || button == "Block"))
			{
				result = false;
				return false;
			}
			if (method == "IsGamepadActive" || method == "IsExclusiveGamepadActive")
			{
				result = !flag;
				return false;
			}
			if (method == "IsMouseActive")
			{
				result = flag;
				return false;
			}
			if (method == "IsGamepadMouseActive")
			{
				result = false;
				return false;
			}
			if (button == null)
			{
				return true;
			}
			bool flag2 = button.StartsWith("Joy", StringComparison.OrdinalIgnoreCase);
			if (flag)
			{
				if (flag2)
				{
					result = false;
					return false;
				}
				return true;
			}
			int num2 = DeviceMap.PadIndex(num);
			if (num2 < 0)
			{
				result = false;
				return false;
			}
			if (GameBindings.TryQuery(method, button, num2, out var result2))
			{
				result = result2;
				return false;
			}
			string logical = (flag2 ? button.Substring(3) : button);
			bool flag3 = Pressed(Pads.Cur(num2), logical);
			bool flag4 = Pressed(Pads.Prev(num2), logical);
			if (method == "GetButtonDown")
			{
				result = flag3 && !flag4;
			}
			else if (method == "GetButtonUp")
			{
				result = !flag3 && flag4;
			}
			else
			{
				result = flag3;
			}
			return false;
		}

		public static bool OverrideTimer(string method, string button, ref float result)
		{
			if (!Applies() || button == null)
			{
				return true;
			}
			int num = CurrentSlot();
			bool flag = button.StartsWith("Joy", StringComparison.OrdinalIgnoreCase);
			if (DeviceMap.IsKbm(num))
			{
				if (flag)
				{
					result = 0f;
					return false;
				}
				return true;
			}
			int num2 = DeviceMap.PadIndex(num);
			if (num2 < 0 || !flag)
			{
				result = 0f;
				return false;
			}
			if (!GameBindings.TryQuery("GetButton", button, num2, out var result2))
			{
				result2 = false;
			}
			if (!_holds[num].TryGetValue(button, out var value))
			{
				value = new HoldTrack();
				_holds[num][button] = value;
			}
			float time = Time.time;
			if (result2)
			{
				if (value.Start < 0f)
				{
					value.Start = time;
					value.LastPress = time;
				}
				value.LastDur = time - value.Start;
			}
			else if (value.Start >= 0f)
			{
				value.Start = -1f;
				value.ReleaseFrame = Time.frameCount;
			}
			if (method == "GetButtonLastPressedTimer")
			{
				result = time - value.LastPress;
			}
			else
			{
				result = (result2 ? value.LastDur : ((Time.frameCount - value.ReleaseFrame <= 1) ? value.LastDur : 0f));
			}
			return false;
		}

		public static bool OverrideFloat(string method, ref float result)
		{
			if (!Applies())
			{
				return true;
			}
			int num = CurrentSlot();
			int num2 = DeviceMap.PadIndex(num);
			if (DeviceMap.IsKbm(num) || num2 < 0 || UiInput.Blocks(num))
			{
				result = 0f;
				return false;
			}
			Pads.Snapshot snapshot = Pads.Cur(num2);
			float num3 = (SplitScreenPlugin.InvertStickY.Value ? (-1f) : 1f);
			switch (method)
			{
			case "GetJoyLeftStickX":
				result = snapshot.LX;
				break;
			case "GetJoyLeftStickY":
				result = num3 * snapshot.LY;
				break;
			case "GetJoyRightStickX":
				result = snapshot.RX;
				break;
			case "GetJoyRightStickY":
				result = num3 * snapshot.RY;
				break;
			case "GetJoyLTrigger":
				result = snapshot.LT;
				break;
			case "GetJoyRTrigger":
				result = snapshot.RT;
				break;
			default:
				return true;
			}
			return false;
		}

		public static bool OverrideVector2(string method, ref Vector2 result)
		{
			//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_007e: 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_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_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			if (WheelMouseState.On && (method == "GetJoyLeftStick" || method == "GetJoyRightStick"))
			{
				result = WheelMouseState.Stick;
				return false;
			}
			if (!Applies())
			{
				return true;
			}
			int num = CurrentSlot();
			int num2 = DeviceMap.PadIndex(num);
			if (DeviceMap.IsKbm(num) || num2 < 0 || UiInput.Blocks(num))
			{
				result = Vector2.zero;
				return false;
			}
			Pads.Snapshot snapshot = Pads.Cur(num2);
			if (!(method == "GetJoyLeftStick"))
			{
				if (!(method == "GetJoyRightStick"))
				{
					return true;
				}
				result = new Vector2(snapshot.RX, SplitScreenPlugin.InvertLookY.Value ? (0f - snapshot.RY) : snapshot.RY);
			}
			else
			{
				result = new Vector2(snapshot.LX, snapshot.LY);
			}
			return false;
		}
	}
	internal static class ZInputBoolTargets
	{
		public static IEnumerable<MethodInfo> All()
		{
			foreach (MethodInfo m in AccessTools.GetDeclaredMethods(typeof(ZInput)))
			{
				if (m.ReturnType == typeof(bool) && !m.GetParameters().Any((ParameterInfo p) => p.ParameterType.IsByRef) && (m.Name.StartsWith("GetButton") || m.Name == "IsGamepadActive" || m.Name == "IsExclusiveGamepadActive" || m.Name == "IsMouseActive" || m.Name == "IsGamepadMouseActive"))
				{
					yield return m;
				}
			}
		}

		public static bool NamedButton(MethodInfo m)
		{
			ParameterInfo[] parameters = m.GetParameters();
			return parameters.Length != 0 && parameters[0].ParameterType == typeof(string);
		}
	}
	[HarmonyPatch]
	internal static class ZInput_Bool
	{
		private static bool Prepare()
		{
			return TargetMethods().Any();
		}

		private static IEnumerable<MethodBase> TargetMethods()
		{
			return ZInputBoolTargets.All().Where(ZInputBoolTargets.NamedButton).Cast<MethodBase>();
		}

		private static bool Prefix(MethodBase __originalMethod, string __0, ref bool __result)
		{
			return InputRouter.OverrideBool(__originalMethod.Name, __0, ref __result);
		}

		private static void Postfix(MethodBase __originalMethod, string __0, ref bool __result)
		{
			InputRouter.Veto(__originalMethod.Name, __0, ref __result);
		}
	}
	[HarmonyPatch]
	internal static class ZInput_BoolOther
	{
		private static bool Prepare()
		{
			return TargetMethods().Any();
		}

		private static IEnumerable<MethodBase> TargetMethods()
		{
			return (from m in ZInputBoolTargets.All()
				where !ZInputBoolTargets.NamedButton(m)
				select m).Cast<MethodBase>();
		}

		private static bool Prefix(MethodBase __originalMethod, ref bool __result)
		{
			return InputRouter.OverrideBool(__originalMethod.Name, null, ref __result);
		}
	}
	[HarmonyPatch]
	internal static class ZInput_Timers
	{
		private static bool Prepare()
		{
			return TargetMethods().Any();
		}

		private static IEnumerable<MethodBase> TargetMethods()
		{
			foreach (MethodInfo m in AccessTools.GetDeclaredMethods(typeof(ZInput)))
			{
				ParameterInfo[] ps = m.GetParameters();
				if (m.ReturnType == typeof(float) && m.Name.StartsWith("GetButton") && m.Name.EndsWith("Timer") && ps.Length >= 1 && ps[0].ParameterType == typeof(string))
				{
					yield return m;
				}
			}
		}

		private static bool Prefix(MethodBase __originalMethod, string __0, ref float __result)
		{
			return InputRouter.OverrideTimer(__originalMethod.Name, __0, ref __result);
		}
	}
	[HarmonyPatch]
	internal static class ZInput_Float
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			foreach (MethodInfo m in AccessTools.GetDeclaredMethods(typeof(ZInput)))
			{
				if (m.ReturnType == typeof(float) && m.Name.StartsWith("GetJoy"))
				{
					yield return m;
				}
			}
		}

		private static bool Prefix(MethodBase __originalMethod, ref float __result)
		{
			return InputRouter.OverrideFloat(__originalMethod.Name, ref __result);
		}
	}
	[HarmonyPatch]
	internal static class ZInput_Stick
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			foreach (MethodInfo m in AccessTools.GetDeclaredMethods(typeof(ZInput)))
			{
				if (m.ReturnType == typeof(Vector2) && (m.Name == "GetJoyLeftStick" || m.Name == "GetJoyRightStick"))
				{
					yield return m;
				}
			}
		}

		private static bool Prefix(MethodBase __originalMethod, ref Vector2 __result)
		{
			return InputRouter.OverrideVector2(__originalMethod.Name, ref __result);
		}
	}
	[HarmonyPatch]
	internal static class ZInput_MouseDelta
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			foreach (MethodInfo m in AccessTools.GetDeclaredMethods(typeof(ZInput)))
			{
				if (m.ReturnType == typeof(Vector2) && m.Name == "GetMouseDelta")
				{
					yield return m;
				}
			}
		}

		private static bool Prefix(ref Vector2 __result)
		{
			//IL_0043: 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)
			if (UiInput.BlockKeyboard || WheelMouseState.On || (LocalPlayerManager.Joined && LocalPlayerManager.Depth > 0 && (!DeviceMap.IsKbm(LocalPlayerManager.ActiveSlot) || UiInput.Blocks(LocalPlayerManager.ActiveSlot))))
			{
				__result = Vector2.zero;
				return false;
			}
			return true;
		}
	}
	internal static class Refl
	{
		private const BindingFlags All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly Dictionary<string, FieldInfo> _fields = new Dictionary<string, FieldInfo>();

		public static FieldInfo Field(Type t, string name)
		{
			if (t == null || string.IsNullOrEmpty(name))
			{
				return null;
			}
			string key = t.AssemblyQualifiedName + "|" + name;
			if (_fields.TryGetValue(key, out var value))
			{
				return value;
			}
			Type type = t;
			while (type != null && value == null)
			{
				try
				{
					value = type.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				catch
				{
				}
				type = type.BaseType;
			}
			_fields[key] = value;
			return value;
		}

		public static FieldInfo FieldOrType(Type t, string name, Type want)
		{
			FieldInfo value = Field(t, name);
			if (value != null || t == null || want == null)
			{
				return value;
			}
			string key = t.AssemblyQualifiedName + "|type:" + want.FullName;
			if (_fields.TryGetValue(key, out value))
			{
				return value;
			}
			Type type = t;
			while (type != null && value == null)
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (want.IsAssignableFrom(fieldInfo.FieldType))
					{
						value = fieldInfo;
						break;
					}
				}
				type = type.BaseType;
			}
			_fields[key] = value;
			return value;
		}

		public static MethodInfo DeclaredMethod(Type t, string name, Type[] args = null)
		{
			if (t == null)
			{
				return null;
			}
			try
			{
				if (args != null)
				{
					return t.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, args, null);
				}
				MethodInfo[] methods = t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.Name == name)
					{
						return methodInfo;
					}
				}
			}
			catch
			{
			}
			return null;
		}

		public static MethodInfo Method(Type t, string name, Type[] args = null)
		{
			Type type = t;
			while (type != null)
			{
				MethodInfo methodInfo = DeclaredMethod(type, name, args);
				if (methodInfo != null)
				{
					return methodInfo;
				}
				type = type.BaseType;
			}
			return null;
		}

		public static GameObject GoOf(object el)
		{
			if (el == null)
			{
				return null;
			}
			GameObject val = (GameObject)((el is GameObject) ? el : null);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			Component val2 = (Component)((el is Component) ? el : null);
			if ((Object)(object)val2 != (Object)null)
			{
				return val2.gameObject;
			}
			FieldInfo fieldInfo = FieldOrType(el.GetType(), "m_go", typeof(GameObject));
			if (fieldInfo != null)
			{
				object? value = fieldInfo.GetValue(el);
				return (GameObject)((value is GameObject) ? value : null);
			}
			fieldInfo = FieldOrType(el.GetType(), "m_go", typeof(RectTransform)) ?? FieldOrType(el.GetType(), "m_go", typeof(Component));
			Component val3 = (Component)((fieldInfo != null) ? /*isinst with value type is only supported in some contexts*/: null);
			return ((Object)(object)val3 != (Object)null) ? val3.gameObject : null;
		}
	}
	internal static class LocalPlayerManager
	{
		private struct Ctx
		{
			public Player Player;

			public int Slot;

			public bool PoseSwapped;

			public Vector3 Pos;

			public Quaternion Rot;

			public bool InvSwapped;

			public InventoryGui Inv;

			public bool EhSwapped;

			public Component Eh;

			public bool GrassSwapped;

			public Component Grass;

			public object[] RadialPrev;

			public bool RefSaved;

			public Vector3 Ref;
		}

		public const int MaxLocal = 2;

		public static readonly Player[] Players = (Player[])(object)new Player[2];

		public static readonly PlayerController[] Controllers = (PlayerController[])(object)new PlayerController[2];

		public static bool Joined;

		public static int InventoryOwner;

		public static float RespawnAt;

		private static readonly FieldInfo _refPos = Refl.Field(typeof(ZNet), "m_referencePosition");

		private static readonly Stack<Ctx> _stack = new Stack<Ctx>();

		public static int SkipInventoryGuiFrame = -1;

		private static bool _spawnedOnce;

		private static bool _deathSaved;

		internal static readonly MethodInfo TeleportToMethod = Refl.Method(typeof(Player), "TeleportTo", new Type[3]
		{
			typeof(Vector3),
			typeof(Quaternion),
			typeof(bool)
		});

		private static bool _p1Travelling;

		public static int ActiveSlot { get; private set; }

		public static int Depth => _stack.Count;

		public static void Enter(int slot)
		{
			//IL_0149: 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_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_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: 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)
			Ctx item = new Ctx
			{
				Player = Player.m_localPlayer,
				Slot = ActiveSlot
			};
			if ((Object)(object)Players[slot] != (Object)null)
			{
				Player.m_localPlayer = Players[slot];
			}
			if (InvClone.Active)
			{
				item.InvSwapped = true;
				item.Inv = InventoryGui.instance;
				InvClone.SetInstance((slot == 1) ? InvClone.Gui2 : InvClone.Gui1);
			}
			UiCopy ui = NameplateCopy.Ui;
			if (ui.Active)
			{
				item.EhSwapped = true;
				item.Eh = ui.GetInstance();
				ui.SetInstance((slot == 1) ? ui.Copy : ui.Orig);
			}
			if (GrassCopy.Active)
			{
				item.GrassSwapped = true;
				item.Grass = GrassCopy.GetInstance();
				GrassCopy.SetInstance((slot == 1) ? GrassCopy.Copy : GrassCopy.Orig);
			}
			if (RadialCopy.Active)
			{
				item.RadialPrev = RadialCopy.SwapTo(slot == 1);
			}
			if (slot == 1 && (Object)(object)SecondaryCamera.Instance != (Object)null && (Object)(object)GameCamera.instance != (Object)null)
			{
				Transform transform = ((Component)GameCamera.instance).transform;
				item.PoseSwapped = true;
				item.Pos = transform.position;
				item.Rot = transform.rotation;
				transform.SetPositionAndRotation(((Component)SecondaryCamera.Instance).transform.position, ((Component)SecondaryCamera.Instance).transform.rotation);
			}
			if (slot == 1 && ActiveSlot != 1 && _refPos != null && (Object)(object)ZNet.instance != (Object)null)
			{
				try
				{
					item.Ref = (Vector3)_refPos.GetValue(ZNet.instance);
					item.RefSaved = true;
				}
				catch
				{
				}
			}
			ActiveSlot = slot;
			_stack.Push(item);
		}

		public static void Exit()
		{
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			if (_stack.Count == 0)
			{
				return;
			}
			Ctx ctx = _stack.Pop();
			Player.m_localPlayer = (((Object)(object)ctx.Player != (Object)null) ? ctx.Player : null);
			if (ctx.InvSwapped)
			{
				InvClone.SetInstance(ctx.Inv);
			}
			if (ctx.EhSwapped)
			{
				NameplateCopy.Ui.SetInstance(ctx.Eh);
			}
			if (ctx.GrassSwapped)
			{
				GrassCopy.SetInstance(ctx.Grass);
			}
			if (ctx.RadialPrev != null)
			{
				RadialCopy.Restore(ctx.RadialPrev);
			}
			if (ctx.PoseSwapped && (Object)(object)GameCamera.instance != (Object)null)
			{
				((Component)GameCamera.instance).transform.SetPositionAndRotation(ctx.Pos, ctx.Rot);
			}
			if (ctx.RefSaved && (Object)(object)ZNet.instance != (Object)null)
			{
				try
				{
					_refPos.SetValue(ZNet.instance, ctx.Ref);
				}
				catch
				{
				}
			}
			ActiveSlot = ctx.Slot;
		}

		public static bool EnterFor(object instance)
		{
			if (!Joined || (Object)(object)Players[1] == (Object)null)
			{
				return false;
			}
			int num = SlotFor(instance);
			if (num < 0)
			{
				return false;
			}
			Enter(num);
			return true;
		}

		private static int SlotFor(object inst)
		{
			Player val = (Player)((inst is Player) ? inst : null);
			if ((Object)(object)val != (Object)null)
			{
				return ((Object)(object)val == (Object)(object)Players[1]) ? 1 : ((!((Object)(object)val == (Object)(object)Players[0])) ? (-1) : 0);
			}
			PlayerController val2 = (PlayerController)((inst is PlayerController) ? inst : null);
			if ((Object)(object)val2 != (Object)null)
			{
				return ((Object)(object)val2 == (Object)(object)Controllers[1]) ? 1 : ((!((Object)(object)val2 == (Object)(object)Controllers[0])) ? (-1) : 0);
			}
			InventoryGui val3 = (InventoryGui)((inst is InventoryGui) ? inst : null);
			if ((Object)(object)val3 != (Object)null)
			{
				return (!InvClone.Active) ? InventoryOwner : (((Object)(object)val3 == (Object)(object)InvClone.Gui2) ? 1 : 0);
			}
			return -1;
		}

		public static void HandleInventoryButtons()
		{
			bool flag = InventoryGui.IsVisible();
			bool flag2 = InventoryOpenPressedBy(0);
			bool flag3 = InventoryOpenPressedBy(1);
			bool flag4 = false;
			if (flag2 && Backpack.Open[0])
			{
				Backpack.Close(0);
				flag2 = false;
				flag4 = true;
			}
			if (flag3 && Backpack.Open[1])
			{
				Backpack.Close(1);
				flag3 = false;
				flag4 = true;
			}
			if (flag)
			{
				if (flag2 && InventoryOwner != 0)
				{
					Backpack.OpenFor(0);
					flag4 = true;
				}
				if (flag3 && InventoryOwner != 1)
				{
					Backpack.OpenFor(1);
					flag4 = true;
				}
			}
			else if (flag2 && flag3)
			{
				Backpack.OpenFor(1);
				InventoryOwner = 0;
			}
			else
			{
				InventoryOwner = (flag3 ? 1 : 0);
			}
			if (flag4)
			{
				SkipInventoryGuiFrame = Time.frameCount;
			}
		}

		private static bool InventoryOpenPressedBy(int slot)
		{
			if (DeviceMap.IsKbm(slot))
			{
				if (_stack.Count != 0)
				{
					return false;
				}
				InputRouter.Bypass++;
				try
				{
					return ZInput.GetButtonDown("Inventory");
				}
				catch
				{
					return false;
				}
				finally
				{
					InputRouter.Bypass--;
				}
			}
			int num = DeviceMap.PadIndex(slot);
			if (num < 0)
			{
				return false;
			}
			if (GameBindings.TryQuery("GetButtonDown", "JoyInventory", num, out var result) && result)
			{
				return true;
			}
			return Pads.Down(num, 32768);
		}

		public static void TrackPrimary()
		{
			if (_stack.Count == 0)
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null && (Object)(object)localPlayer != (Object)(object)Players[1])
				{
					Players[0] = localPlayer;
					Controllers[0] = ((Component)localPlayer).GetComponent<PlayerController>();
				}
			}
		}

		public static void Join(Player p1)
		{
			Joined = true;
			RespawnAt = 0f;
			_spawnedOnce = false;
			CharacterSlot.OnJoin();
			SecondaryCamera.Create();
			SpawnSecondary(p1);
			SplitLayout.ApplyAll();
			SetupUi.BannerUntil = Time.unscaledTime + 7f;
			SplitScreenPlugin.Log.LogInfo((object)("Player 2 joined.  P1=" + DeviceMap.Label(0) + "  P2=" + DeviceMap.Label(1)));
		}

		public static void Leave()
		{
			CharacterSlot.SaveP2();
			P2Build.Reset();
			if ((Object)(object)Players[1] != (Object)null)
			{
				Costume.Clear(Players[1]);
			}
			AppearanceUi.CloseAll();
			NameEntry.Close(cancelled: false);
			WorldPriority.Restore();
			SplitLayout.Reset();
			if ((Object)(object)Players[1] != (Object)null && (Object)(object)ZNetScene.instance != (Object)null)
			{
				ZNetScene.instance.Destroy(((Component)Players[1]).gameObject);
			}
			Players[1] = null;
			Controllers[1] = null;
			SecondaryCamera.Destroy();
			Joined = false;
			InventoryOwner = 0;
			RespawnAt = 0f;
			_stack.Clear();
			ActiveSlot = 0;
			Backpack.CloseAll();
			SplitScreenPlugin.Log.LogInfo((object)"Player 2 left.");
		}

		public static void SpawnSecondary(Player p1)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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)
			GameObject playerPrefab = Game.instance.m_playerPrefab;
			Vector3 val = Rescue.LandingSpot(p1);
			Player localPlayer = Player.m_localPlayer;
			GameObject val2 = Object.Instantiate<GameObject>(playerPrefab, val, ((Component)p1).transform.rotation);
			Player.m_localPlayer = localPlayer;
			Player component = val2.GetComponent<Player>();
			Players[1] = component;
			Controllers[1] = val2.GetComponent<PlayerController>();
			RespawnAt = 0f;
			try
			{
				ZNetView component2 = val2.GetComponent<ZNetView>();
				if ((Object)(object)component2 != (Object)null && component2.IsValid())
				{
					component2.GetZDO().Set("playerName", "Player 2");
				}
			}
			catch (Exception ex)
			{
				SplitScreenPlugin.Log.LogWarning((object)("Could not name P2: " + ex.Message));
			}
			if ((Object)(object)SecondaryCamera.Instance != (Object)null)
			{
				SecondaryCamera.Instance.Target = component;
			}
			RadialCopy.FixPlayer(component);
			CharacterSlot.ApplyOnSpawn(component, _spawnedOnce);
			_spawnedOnce = true;
			_deathSaved = false;
		}

		public static void Tick(Player p1)
		{
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: 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)
			Player val = Players[1];
			if ((Object)(object)val == (Object)null)
			{
				if (Time.time >= RespawnAt && !((Character)p1).IsDead() && !((Character)p1).IsTeleporting())
				{
					SpawnSecondary(p1);
				}
			}
			else if (((Character)val).IsDead())
			{
				if (!_deathSaved)
				{
					_deathSaved = true;
					CharacterSlot.SaveP2();
				}
				if (RespawnAt <= 0f)
				{
					RespawnAt = Time.time + SplitScreenPlugin.RespawnDelay.Value;
				}
				if (Time.time >= RespawnAt)
				{
					ZNetScene.instance.Destroy(((Component)val).gameObject);
					Players[1] = null;
				}
			}
			else if (((Character)p1).IsTeleporting() || ((Character)p1).IsDead())
			{
				if (((Character)p1).IsTeleporting())
				{
					_p1Travelling = true;
				}
			}
			else if (_p1Travelling)
			{
				_p1Travelling = false;
				if (Vector3.Distance(((Component)p1).transform.position, ((Component)val).transform.position) > 15f)
				{
					Rescue.PullToP1("followed Player 1 through a portal");
				}
			}
			else
			{
				if (((Character)val).IsTeleporting())
				{
					return;
				}
				float value = SplitScreenPlugin.LeashDistance.Value;
				if (value > 0f)
				{
					Vector3 val2 = ((Component)val).transform.position - ((Component)p1).transform.position;
					if (((Vector3)(ref val2)).sqrMagnitude > value * value)
					{
						Rescue.PullToP1("tether " + value.ToString("F0") + " m");
					}
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class ContextPatches
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			List<KeyValuePair<Type, string>> wanted = new List<KeyValuePair<Type, string>>
			{
				new KeyValuePair<Type, string>(typeof(Player), "Update"),
				new KeyValuePair<Type, string>(typeof(Player), "FixedUpdate"),
				new KeyValuePair<Type, string>(typeof(Player), "LateUpdate"),
				new KeyValuePair<Type, string>(typeof(Player), "OnDeath"),
				new KeyValuePair<Type, string>(typeof(PlayerController), "FixedUpdate"),
				new KeyValuePair<Type, string>(typeof(PlayerController), "LateUpdate")
			};
			foreach (KeyValuePair<Type, string> kv in wanted)
			{
				MethodInfo m = Refl.DeclaredMethod(kv.Key, kv.Value);
				if (m != null)
				{
					yield return m;
				}
				else
				{
					SplitScreenPlugin.Log.LogWarning((object)("Not found (skipped): " + kv.Key.Name + "." + kv.Value));
				}
			}
		}

		private static bool Prefix(object __instance, out bool __state)
		{
			__state = LocalPlayerManager.EnterFor(__instance);
			return true;
		}

		private static Exception Finalizer(Exception __exception, bool __state)
		{
			if (__state)
			{
				LocalPlayerManager.Exit();
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(PlayerController), "TakeInput")]
	internal static class TakeInputPatch
	{
		private static bool Prefix(ref bool __result)
		{
			if (DevicePicker.Active || CharacterPicker.Active)
			{
				__result = false;
				return false;
			}
			if (LocalPlayerManager.Joined && LocalPlayerManager.Depth > 0 && UiInput.Blocks(LocalPlayerManager.ActiveSlot))
			{
				__result = false;
				return false;
			}
			if (LocalPlayerManager.Joined && LocalPlayerManager.Depth > 0 && Backpack.Open[LocalPlayerManager.ActiveSlot])
			{
				__result = false;
				return false;
			}
			if (!LocalPlayerManager.Joined || LocalPlayerManager.Depth == 0 || LocalPlayerManager.ActiveSlot != 1)
			{
				return true;
			}
			Player val = LocalPlayerManager.Players[1];
			bool flag = (InvClone.Active ? InventoryGui.IsVisible() : (InventoryGui.IsVisible() && LocalPlayerManager.InventoryOwner == 1));
			bool flag2 = (RadialCopy.Active ? RadialCopy.CopyOpen() : (RadialState.Open() && RadialState.Owner == 1));
			__result = (Object)(object)val != (Object)null && !((Character)val).IsDead() && !flag && !flag2;
			return false;
		}

		private static void Postfix(ref bool __result)
		{
			if (!__result && LocalPlayerManager.Joined && LocalPlayerManager.Depth > 0 && LocalPlayerManager.ActiveSlot == 0 && !DevicePicker.Active && !CharacterPicker.Active && !Backpack.Open[0] && !RadialCopy.Active && RadialState.Open() && RadialState.Owner == 1 && !Menu.IsVisible() && !Minimap.IsOpen() && !InvClone.IsVisibleSafe(0))
			{
				Player val = LocalPlayerManager.Players[0];
				if ((Object)(object)val != (Object)null && !((Character)val).IsDead())
				{
					__result = true;
					return;
				}
			}
			if (!__result && !DevicePicker.Active && LocalPlayerManager.Joined && LocalPlayerManager.Depth != 0 && LocalPlayerManager.ActiveSlot == 0 && !Backpack.Open[0] && !InvClone.Active && InventoryGui.IsVisible() && LocalPlayerManager.InventoryOwner == 1 && !Menu.IsVisible() && !Minimap.IsOpen())
			{
				Player val2 = LocalPlayerManager.Players[0];
				if ((Object)(object)val2 != (Object)null && !((Character)val2).IsDead())
				{
					__result = true;
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerController), "InInventoryEtc")]
	internal static class InInventoryEtcPatch
	{
		private static void Postfix(ref bool __result)
		{
			if (!InvClone.Active && __result && LocalPlayerManager.Joined && LocalPlayerManager.Depth > 0 && InventoryGui.IsVisible() && LocalPlayerManager.InventoryOwner != LocalPlayerManager.ActiveSlot && !Menu.IsVisible() && !Minimap.IsOpen())
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
	internal static class MouseCapturePatch
	{
		private static void Postfix()
		{
			if (CharacterPicker.Active || NameEntry.Active)
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
			else
			{
				if (!LocalPlayerManager.Joined)
				{
					return;
				}
				if (UiInput.KbmSlot >= 0 && VMenus.AnyFor(UiInput.KbmSlot))
				{
					Cursor.lockState = (CursorLockMode)0;
					Cursor.visible = true;
					return;
				}
				int num = ((!DeviceMap.IsKbm(0)) ? (DeviceMap.IsKbm(1) ? 1 : (-1)) : 0);
				if (num >= 0 && Backpack.Open[num])
				{
					Cursor.lockState = (CursorLockMode)0;
					Cursor.visible = true;
					return;
				}
				Keyboard current = Keyboard.current;
				if (current != null && (((ButtonControl)current.leftAltKey).isPressed || ((ButtonControl)current.rightAltKey).isPressed) && !Menu.IsVisible())
				{
					Cursor.lockState = (CursorLockMode)0;
					Cursor.visible = true;
				}
				else if (InvClone.Active)
				{
					if (num < 0 && MouseUse.HelpAllowed && InvClone.IsVisible(InvClone.Gui2) && !Menu.IsVisible())
					{
						Cursor.lockState = (CursorLockMode)0;
						Cursor.visible = true;
					}
					else if (num == 1)
					{
						if (InvClone.IsVisible(InvClone.Gui2))
						{
							Cursor.lockState = (CursorLockMode)0;
							Cursor.visible = true;
						}
						else if (!Menu.IsVisible() && !Minimap.IsOpen())
						{
							Cursor.lockState = (CursorLockMode)1;
							Cursor.visible = false;
						}
					}
				}
				else if (InventoryGui.IsVisible() && !DeviceMap.IsKbm(LocalPlayerManager.InventoryOwner) && !Menu.IsVisible() && !Minimap.IsOpen())
				{
					Cursor.lockState = (CursorLockMode)1;
					Cursor.visible = false;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Game), "RequestRespawn")]
	internal static class RequestRespawnPatch
	{
		private static bool Prefix()
		{
			if (LocalPlayerManager.Joined && LocalPlayerManager.ActiveSlot == 1)
			{
				LocalPlayerManager.RespawnAt = Time.time + SplitScreenPlugin.RespawnDelay.Value;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Show")]
	internal static class InventoryShowPatch
	{
		private static void Postfix()
		{
			if (LocalPlayerManager.Joined && LocalPlayerManager.Depth > 0 && !InvClone.Active)
			{
				LocalPlayerManager.InventoryOwner = LocalPlayerManager.ActiveSlot;
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Hide")]
	internal static class InventoryHidePatch
	{
		private static void Postfix()
		{
			if (LocalPlayerManager.Joined)
			{
				LocalPlayerManager.InventoryOwner = 0;
			}
		}
	}
	internal class SecondaryCamera : MonoBehaviour
	{
		public static SecondaryCamera Instance;

		public Camera Cam;

		public Player Target;

		public static void Create()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			Destroy();
			Camera mainCam = SplitLayout.MainCam;
			if ((Object)(object)mainCam == (Object)null)
			{
				SplitScreenPlugin.Log.LogError((object)"No main camera.");
				return;
			}
			GameObject val = new GameObject("SplitScreen_P2_Camera");
			val.SetActive(false);
			Camera val2 = val.AddComponent<Camera>();
			val2.CopyFrom(mainCam);
			val2.targetTexture = null;
			val2.ResetAspect();
			CopyPostProcessing(mainCam, val);
			SecondaryCamera secondaryCamera = val.AddComponent<SecondaryCamera>();
			secondaryCamera.Cam = val2;
			Instance = secondaryCamera;
			val.SetActive(true);
		}

		public static void Destroy()
		{
			if ((Object)(object)Instance != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)Instance).gameObject);
			}
			Instance = null;
		}

		private static void CopyPostProcessing(Camera src, GameObject dst)
		{
			Behaviour[] components = ((Component)src).GetComponents<Behaviour>();
			foreach (Behaviour val in components)
			{
				Type type = ((object)val).GetType();
				string text = type.Namespace ?? "";
				if (!text.StartsWith("UnityEngine.PostProcessing") && !text.StartsWith("UnityEngine.Rendering.PostProcessing"))
				{
					continue;
				}
				try
				{
					Component val2 = dst.AddComponent(type);
					CopySerializedFields((Component)(object)val, val2);
					FieldInfo field = type.GetField("volumeTrigger");
					if (field != null && field.FieldType == typeof(Transform))
					{
						field.SetValue(val2, dst.transform);
					}
				}
				catch (Exception ex)
				{
					SplitScreenPlugin.Log.LogWarning((object)("PostFX copy failed for " + type.Name + ": " + ex.Message));
				}
			}
		}

		internal static void CopySerializedFields(Component from, Component to)
		{
			Type type = ((object)from).GetType();
			while (type != null && type != typeof(Behaviour) && type != typeof(Component))
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (fieldInfo.IsInitOnly || fieldInfo.IsLiteral || fieldInfo.IsNotSerialized || (!fieldInfo.IsPublic && fieldInfo.GetCustomAttributes(typeof(SerializeField), inherit: true).Length == 0))
					{
						continue;
					}
					try
					{
						object obj = fieldInfo.GetValue(from);
						ScriptableObject val = (ScriptableObject)((obj is ScriptableObject) ? obj : null);
						if ((Object)(object)val != (Object)null && fieldInfo.Name.IndexOf("profile", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							obj = Object.Instantiate<ScriptableObject>(val);
						}
						fieldInfo.SetValue(to, obj);
					}
					catch
					{
					}
				}
				type = type.BaseType;
			}
		}

		private void LateUpdate()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: 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)
			if (!((Object)(object)Target == (Object)null))
			{
				Vector3 lookDir = ((Character)Target).GetLookDir();
				Vector3 eyePoint = ((Character)Target).GetEyePoint();
				float value = SplitScreenPlugin.CameraDistance.Value;
				Vector3 val = eyePoint - lookDir * value + Vector3.up * 0.3f;
				Vector3 val2 = val - eyePoint;
				RaycastHit val3 = default(RaycastHit);
				if (Physics.Raycast(eyePoint, ((Vector3)(ref val2)).normalized, ref val3, value, -1, (QueryTriggerInteraction)1))
				{
					val = ((RaycastHit)(ref val3)).point + ((RaycastHit)(ref val3)).normal * 0.2f;
				}
				((Component)this).transform.SetPositionAndRotation(val, Quaternion.LookRotation(lookDir));
			}
		}
	}
	internal static class SplitLayout
	{
		public static bool Active;

		public static RenderTexture Rt1;

		private static Camera _main;

		private static int _w;

		private static int _h;

		private static bool _useGameFb;

		private static RawImage _gameRaw;

		private static bool _nativeMode;

		private static GameObject _viewsGo;

		private static RawImage _p1Raw;

		private static RawImage _p2Raw;

		private static Material _blitMat;

		private static int _invSlotApplied = -1;

		public static readonly HalfWrap HudWrap = new HalfWrap();

		public static readonly HalfWrap InvWrap = new HalfWrap();

		public static readonly HalfWrap InvWrap2 = new HalfWrap();

		public static int UiLayer => LayerMask.NameToLayer("UI");

		public static Camera MainCam
		{
			get
			{
				if ((Object)(object)_main == (Object)null && (Object)(object)GameCamera.instance != (Object)null)
				{
					_main = ((Component)GameCamera.instance).GetComponent<Camera>();
				}
				return _main;
			}
		}

		public static string Describe()
		{
			Texture val = P1Source();
			return (_useGameFb ? "GameFB" : "ScreenRect") + " P1src=" + (((Object)(object)val != (Object)null) ? (((Object)val).name + " " + val.width + "x" + val.height) : "none") + " P2rt=" + (((Object)(object)Rt1 != (Object)null) ? (((Texture)Rt1).width + "x" + ((Texture)Rt1).height) : "none") + " P1aspect=" + (((Object)(object)MainCam != (Object)null) ? MainCam.aspect.ToString("F2") : "?") + " HudMirror=" + HudMirror.Active + " InvOwner=P" + (LocalPlayerManager.InventoryOwner + 1);
		}

		public static Rect HalfFor(int slot)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if (SplitScreenPlugin.Mode.Value == SplitMode.SideBySide)
			{
				return (slot == 0) ? new Rect(0f, 0f, 0.5f, 1f) : new Rect(0.5f, 0f, 0.5f, 1f);
			}
			return (slot == 0) ? new Rect(0f, 0.5f, 1f, 0.5f) : new Rect(0f, 0f, 1f, 0.5f);
		}

		public static Rect ViewportFor(int slot)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_008e: 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_0054: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			if (!Active)
			{
				return new Rect(0f, 0f, 1f, 1f);
			}
			if (SplitScreenPlugin.Mode.Value == SplitMode.SideBySide)
			{
				return (slot == 0) ? new Rect(0f, 0f, 0.5f, 1f) : new Rect(0.5f, 0f, 0.5f, 1f);
			}
			return (slot == 0) ? new Rect(0f, 0.5f, 1f, 0.5f) : new Rect(0f, 0f, 1f, 0.5f);
		}

		public static void ApplyAll()
		{
			Active = true;
			Rebuild();
		}

		private static void Rebuild()
		{
			_w = Screen.width;
			_h = Screen.height;
			Teardown();
			Active = true;
			FindGameViewport();
			Camera mainCam = MainCam;
			_useGameFb = SplitScreenPlugin.Frame.Value == FrameMode.GameFramebuffer && (Object)(object)mainCam != (Object)null && ((Object)(object)_gameRaw != (Object)null || (Object)(object)mainCam.targetTexture != (Object)null);
			if (SplitScreenPlugin.Frame.Value == FrameMode.GameFramebuffer && !_useGameFb)
			{
				SplitScreenPlugin.Log.LogWarning((object)"Game framebuffer not found; falling back to ScreenRect mode.");
			}
			if (_useGameFb)
			{
				BuildViews();
			}
			else
			{
				ApplyCameraRects();
			}
			if ((SplitScreenPlugin.Player2Hud.Value != P2HudMode.Mirror || !HudMirror.Start()) && SplitScreenPlugin.P1Hud.Value == HudMode.FitToViewport)
			{
				FitHud();
			}
			if (SplitScreenPlugin.SeparateInventories.Value)
			{
				InvClone.Create();
			}
			if (SplitScreenPlugin.PerPlayerNameplates.Value)
			{
				NameplateCopy.Create();
			}
			RadialCopy.Create();
			if (!RadialCopy.Active)
			{
				RadialState.Scan();
			}
			WrapInventory();
			if (InvClone.Active)
			{
				UiContext.Setup(InvClone.Gui1, InvClone.Gui2);
			}
			try
			{
				BuildUiContext.Setup();
			}
			catch (Exception ex)
			{
				SplitScreenPlugin.Log.LogWarning((object)("Build UI routing failed: " + ex.Message));
			}
			Reassert();
		}

		public static void Tick()
		{
			if (Active && (Screen.width != _w || Screen.height != _h))
			{
				Rebuild();
			}
		}

		public static void Reset()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			Teardown();
			Active = false;
			Camera mainCam = MainCam;
			if ((Object)(object)mainCam != (Object)null)
			{
				mainCam.ResetAspect();
				mainCam.rect = new Rect(0f, 0f, 1f, 1f);
			}
		}

		private static void Teardown()
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			RadialState.Clear();
			HudMirror.Stop();
			DragPanels.RemoveAll();
			HudWrap.Unwrap();
			InvWrap.Unwrap();
			InvWrap2.Unwrap();
			MouseUse.Reset();
			MenuNav.Reset();
			UiContext.Clear();
			BuildUiContext.Clear();
			InvClone.Destroy();
			NameplateCopy.Ui.Destroy();
			GrassCopy.Destroy();
			RadialCopy.Destroy();
			_invSlotApplied = -1;
			Camera val = (((Object)(object)SecondaryCamera.Instance != (Object)null) ? SecondaryCamera.Instance.Cam : null);
			if ((Object)(object)val != (Object)null)
			{
				val.targetTexture = null;
				val.rect = new Rect(0f, 0f, 1f, 1f);
			}
			if ((Object)(object)_viewsGo != (Object)null)
			{
				Object.Destroy((Object)(object)_viewsGo);
			}
			_viewsGo = null;
			_p1Raw = null;
			_p2Raw = null;
			if ((Object)(object)Rt1 != (Object)null)
			{
				Rt1.Release();
				Object.Destroy((Object)(object)Rt1);
				Rt1 = null;
			}
			Camera mainCam = MainCam;
			if ((Object)(object)mainCam != (Object)null)
			{
				mainCam.ResetAspect();
				mainCam.rect = new Rect(0f, 0f, 1f, 1f);
			}
			_gameRaw = null;
			_useGameFb = false;
			_nativeMode = false;
		}

		private static void FindGameViewport()
		{
			_gameRaw = null;
			Canvas[] array = Object.FindObjectsByType<Canvas>((FindObjectsSortMode)0);
			foreach (Canvas val in array)
			{
				if (!val.isRootCanvas || ((Object)((Component)val).gameObject).name != "Scaled 3D Viewport")
				{
					continue;
				}
				RawImage[] componentsInChildren = ((Component)val).GetComponentsInChildren<RawImage>(true);
				foreach (RawImage val2 in componentsInChildren)
				{
					SplitScreenPlugin.Log.LogInfo((object)("Game viewport RawImage '" + ((Object)val2).name + "' active=" + ((Behaviour)val2).isActiveAndEnabled + " tex=" + (((Object)(object)val2.texture != (Object)null) ? (((Object)val2.texture).name + " " + val2.texture.width + "x" + val2.texture.height) : "none")));
					if ((Object)(object)_gameRaw == (Object)null || (!((Behaviour)_gameRaw).isActiveAndEnabled && ((Behaviour)val2).isActiveAndEnabled))
					{
						_gameRaw = val2;
					}
				}
			}
		}

		private static Texture P1Source()
		{
			if ((Object)(object)_gameRaw != (Object)null && (Object)(object)_gameRaw.texture != (Object)null)
			{
				return _gameRaw.texture;
			}
			Camera mainCam = MainCam;
			return (Texture)(object)(((Object)(object)mainCam != (Object)null) ? mainCam.targetTexture : null);
		}

		private static RawImage MakeRaw(Transform parent, string name, Rect vp, Texture tex)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_003f: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.layer = UiLayer;
			val.transform.SetParent(parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = ((Rect)(ref vp)).min;
			component.anchorMax = ((Rect)(ref vp)).max;
			component.offsetMin = Vector2.zero;
			component.offsetMax = Vector2.zero;
			RawImage val2 = val.AddComponent<RawImage>();
			val2.texture = tex;
			((Graphic)val2).raycastTarget = false;
			if ((Object)(object)_blitMat != (Object)null)
			{
				((Graphic)val2).material = _blitMat;
			}
			return val2;
		}

		private static void BuildViews()
		{
			//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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_00d1: 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_0143: Expected O, but got Unknown
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: 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_0120: Expected O, but got Unknown
			Camera val = (((Object)(object)SecondaryCamera.Instance != (Object)null) ? SecondaryCamera.Instance.Cam : null);
			if ((Object)(object)val == (Object)null)
			{
				SplitScreenPlugin.Log.LogError((object)"P2 camera missing.");
				return;
			}
			Rect vp = ViewportFor(1);
			int num = Mathf.Max(16, Mathf.RoundToInt((float)Screen.width * ((Rect)(ref vp)).width));
			int num2 = Mathf.Max(16, Mathf.RoundToInt((float)Screen.height * ((Rect)(ref vp)).height));
			Rt1 = new RenderTexture(num, num2, 24, (RenderTextureFormat)0);
			((Object)Rt1).name = "SplitScreen_P2_RT";
			Rt1.antiAliasing = Mathf.Max(1, QualitySettings.antiAliasing);
			Rt1.Create();
			val.rect = new Rect(0f, 0f, 1f, 1f);
			val.targetTexture = Rt1;
			if ((Object)(object)_blitMat == (Object)null)
			{
				Shader val2 = Shader.Find("Hidden/BlitCopy");
				if ((Object)(object)val2 != (Object)null)
				{
					_blitMat = new Material(val2);
				}
			}
			_viewsGo = new GameObject("SplitScreen_Views", new Type[1] { typeof(RectTransform) });
			_viewsGo.layer = UiLayer;
			Canvas val3 = _viewsGo.AddComponent<Canvas>();
			val3.renderMode = (RenderMode)0;
			val3.sortingOrder = 50;
			_p1Raw = MakeRaw(_viewsGo.transform, "P1View", ViewportFor(0), P1Source());
			_p2Raw = MakeRaw(_viewsGo.transform, "P2View", vp, (Texture)(object)Rt1);
		}

		public static void Reassert()
		{
			//IL_0038: 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_01bb: 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_01ce: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			if (!Active)
			{
				return;
			}
			Camera mainCam = MainCam;
			if ((Object)(object)mainCam == (Object)null)
			{
				return;
			}
			if (_useGameFb)
			{
				Rect val = ViewportFor(0);
				Texture val2 = P1Source();
				if ((Object)(object)val2 != (Object)null)
				{
					if (_nativeMode)
					{
						_nativeMode = false;
						SplitScreenPlugin.Log.LogInfo((object)"Rendering: scaled - Player 1 shown from the game's picture.");
					}
					float num = (float)Screen.width * ((Rect)(ref val)).width / Mathf.Max(1f, (float)Screen.height * ((Rect)(ref val)).height);
					if (!Mathf.Approximately(mainCam.aspect, num))
					{
						mainCam.aspect = num;
					}
					if (mainCam.rect != new Rect(0f, 0f, 1f, 1f))
					{
						mainCam.rect = new Rect(0f, 0f, 1f, 1f);
					}
					if ((Object)(object)_p1Raw != (Object)null)
					{
						if (!((Behaviour)_p1Raw).enabled)
						{
							((Behaviour)_p1Raw).enabled = true;
						}
						if ((Object)(object)_p1Raw.texture != (Object)(object)val2)
						{
							_p1Raw.texture = val2;
						}
						if ((Object)(object)_gameRaw != (Object)null)
						{
							_p1Raw.uvRect = _gameRaw.uvRect;
						}
					}
				}
				else
				{
					if (!_nativeMode)
					{
						_nativeMode = true;
						mainCam.ResetAspect();
						SplitScreenPlugin.Log.LogInfo((object)"Rendering: native - Player 1's camera draws straight into its half.");
					}
					if (mainCam.rect != val)
					{
						mainCam.rect = val;
					}
					if ((Object)(object)_p1Raw != (Object)null && ((Behaviour)_p1Raw).enabled)
					{
						((Behaviour)_p1Raw).enabled = false;
					}
				}
			}
			else
			{
				ApplyCameraRects();
			}
			RadialState.Reassert();
			int inventoryOwner = LocalPlayerManager.InventoryOwner;
			if (InvWrap.Wrapped && !InvClone.Active && inventoryOwner != _invSlotApplied)
			{
				InvWrap.SetViewport(ViewportFor(inventoryOwner));
				_invSlotApplied = inventoryOwner;
			}
		}

		public static void ApplyCameraRects()
		{
			//IL_0016: 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)
			if ((Object)(object)MainCam != (Object)null)
			{
				MainCam.rect = ViewportFor(0);
			}
			if ((Object)(object)SecondaryCamera.Instance != (Object)null)
			{
				SecondaryCamera.Instance.Cam.rect = ViewportFor(1);
			}
		}

		private static void FitHud()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			Hud instance = Hud.instance;
			if ((Object)(object)instance == (Object)null)
			{
				SplitScreenPlugin.Log.LogWarning((object)"Hud.instance is null; P1 HUD left as is.");
				return;
			}
			HalfWrap hudWrap = HudWrap;
			Transform transform = ((Component)instance).transform;
			hudWrap.Wrap((RectTransform)(object)((transform is RectTransform) ? transform : null), ViewportFor(0), 1f);
		}

		private static void WrapInventory()
		{
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)instance == (Object)null)
			{
				SplitScreenPlugin.Log.LogWarning((object)"InventoryGui.instance is null; inventory left full-screen.");
				return;
			}
			Canvas componentInParent = ((Component)instance).GetComponentInParent<Canvas>();
			if ((Object)(object)componentInParent == (Object)null)
			{
				SplitScreenPlugin.Log.LogWarning((object)"No Canvas above InventoryGui; inventory left full-screen.");
				return;
			}
			componentInParent = componentInParent.rootCanvas;
			float scale = Mathf.Clamp(SplitScreenPlugin.InventoryScale.Value, 0.3f, 1f);
			int num = ((!InvClone.Active) ? LocalPlayerManager.InventoryOwner : 0);
			HalfWrap invWrap = InvWrap;
			Transform transform = ((Component)componentInParent).transform;
			invWrap.Wrap((RectTransform)(object)((transform is RectTransform) ? transform : null), ViewportFor(num), scale);
			_invSlotApplied = num;
			SplitScreenPlugin.Log.LogInfo((object)("Inventory canvas '" + ((Object)componentInParent).name + "' wrapped."));
			DragPanels.Attach(instance);
			if (InvClone.Active)
			{
				Canvas componentInParent2 = ((Component)InvClone.Gui2).GetComponentInParent<Canvas>();
				if ((Object)(object)componentInParent2 != (Object)null)
				{
					HalfWrap invWrap2 = InvWrap2;
					Transform transform2 = ((Component)componentInParent2.rootCanvas).transform;
					invWrap2.Wrap((RectTransform)(object)((transform2 is RectTransform) ? transform2 : null), ViewportFor(1), scale);
					DragPanels.Attach(InvClone.Gui2);
				}
			}
		}
	}
	internal class HalfWrap
	{
		private RectTransform _root;

		private RectTransform _wrap;

		private readonly List<Transform> _kids = new List<Transform>();

		public bool Wrapped => (Object)(object)_wrap != (Object)null;

		public RectTransform Wrapper => _wrap;

		public void Wrap(RectTransform root, Rect vp, float scale)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0072: 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_0096: 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_00c6: Expected O, but got Unknown
			Unwrap();
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			GameObject val = new GameObject("SplitScreen_Wrapper", new Type[1] { typeof(RectTransform) });
			val.layer = ((Component)root).gameObject.layer;
			_wrap = val.GetComponent<RectTransform>();
			((Transform)_wrap).SetParent((Transform)(object)root, false);
			_wrap.pivot = new Vector2(0.5f, 0.5f);
			((Transform)_wrap).localScale = new Vector3(scale, scale, 1f);
			SetViewport(vp);
			_root = root;
			_kids.Clear();
			foreach (Transform item in (Transform)root)
			{
				Transform val2 = item;
				if ((Object)(object)val2 != (Object)(object)_wrap)
				{
					_kids.Add(val2);
				}
			}
			foreach (Transform kid in _kids)
			{
				kid.SetParent((Transform)(object)_wrap, false);
			}
		}

		public void SetViewport(Rect vp)
		{
			//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)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_wrap == (Object)null))
			{
				_wrap.anchorMin = ((Rect)(ref vp)).min;
				_wrap.anchorMax = ((Rect)(ref vp)).max;
				_wrap.offsetMin = Vector2.zero;
				_wrap.offsetMax = Vector2.zero;
			}
		}

		public void Unwrap()
		{
			if ((Object)(object)_wrap == (Object)null)
			{
				return;
			}
			if ((Object)(object)_root != (Object)null)
			{
				for (int i = 0; i < _kids.Count; i++)
				{
					if (!((Object)(object)_kids[i] == (Object)null))
					{
						_kids[i].SetParent((Transform)(object)_root, false);
						_kids[i].SetSiblingIndex(Mathf.Min(i, ((Transform)_root).childCount - 1));
					}
				}
			}
			_kids.Clear();
			Object.Destroy((Object)(object)((Component)_wrap).gameObject);
			_wrap = null;
			_root = null;
		}
	}
	internal static class HudMirror
	{
		public static bool Active;

		private static Canvas _canvas;

		private static RenderMode _prevMode;

		private static Camera _prevCam;

		private static float _prevPlane;

		private static GameObject _camGo;

		private static GameObject _viewsGo;

		private static Camera _cam;

		private static RenderTexture _rt;

		private static bool _p2Failed;

		private static readonly MethodInfo _hudUpdate = Refl.Method(typeof(Hud), "Update");

		private static readonly List<KeyValuePair<Component, MethodInfo>> _extra = new List<KeyValuePair<Component, MethodInfo>>();

		public static bool InP2Pass;

		private static List<CanvasGroup> _groups;

		private static float[] _a1;

		private static float[] _a2;

		private static bool _a2Set;

		public static List<KeyValuePair<Component, MethodInfo>> Bars => _extra;

		private static void InitGroups()
		{
			if (_groups == null && !((Object)(object)_canvas == (Object)null))
			{
				_groups = (from g in ((Component)_canvas).GetComponentsInChildren<CanvasGroup>(true)
					where (Object)(object)g != (Object)null && !RadialCopy.Manages(g) && !RadialState.Manages(g)
					select g).ToList();
				_a1 = new float[_groups.Count];
				_a2 = new float[_groups.Count];
				_a2Set = false;
			}
		}

		private static void SaveAlpha(float[] a)
		{
			for (int i = 0; i < _groups.Count; i++)
			{
				if ((Object)(object)_groups[i] != (Object)null)
				{
					a[i] = _groups[i].alpha;
				}
			}
		}

		private static void LoadAlpha(float[] a)
		{
			for (int i = 0; i < _groups.Count; i++)
			{
				if ((Object)(object)_groups[i] != (Object)null)
				{
					_groups[i].alpha = a[i];
				}
			}
		}

		public static bool Start()
		{
			//IL_0092: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Expected O, but got Unknown
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Expected O, but got Unknown
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Expected O, but got Unknown
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Expected O, but got Unknown
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: 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_02c6: Unknown result type (might be due to invalid IL or missing references)
			Stop();
			Hud instance = Hud.instance;
			if ((Object)(object)instance == (Object)null || _hudUpdate == null)
			{
				SplitScreenPlugin.Log.LogWarning((object)"HUD mirror unavailable (Hud or Hud.Update not found); using the simple P2 HUD.");
				return false;
			}
			Canvas val = ((Component)instance).GetComponent<Canvas>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)instance).GetComponentInParent<Canvas>();
			}
			if ((Object)(object)val == (Object)null)
			{
				SplitScreenPlugin.Log.LogWarning((object)"HUD mirror: no canvas found.");
				return false;
			}
			val = (_canvas = val.rootCanvas);
			_prevMode = val.renderMode;
			_prevCam = val.worldCamera;
			_prevPlane = val.planeDistance;
			int sortingOrder = val.sortingOrder;
			_rt = new RenderTexture(Mathf.Max(16, Screen.width), Mathf.Max(16, Screen.height), 16, (RenderTextureFormat)0);
			((Object)_rt).name = "SplitScreen_HUD_RT";
			_rt.Create();
			_camGo = new GameObject("SplitScreen_HudMirrorCam");
			_cam = _camGo.AddComponent<Camera>();
			((Behaviour)_cam).enabled = false;
			_cam.clearFlags = (CameraClearFlags)2;
			_cam.backgroundColor = new Color(0f, 0f, 0f, 0f);
			_cam.cullingMask = 1 << ((Component)val).gameObject.layer;
			_cam.orthographic = true;
			_cam.orthographicSize = 1f;
			_cam.nearClipPlane = 0.1f;
			_cam.farClipPlane = 20f;
			_cam.allowHDR = false;
			_cam.allowMSAA = false;
			_cam.targetTexture = _rt;
			_cam.rect = SplitLayout.ViewportFor(0);
			val.renderMode = (RenderMode)1;
			val.worldCamera = _cam;
			val.planeDistance = 5f;
			_viewsGo = new GameObject("SplitScreen_HudViews", new Type[1] { typeof(RectTransform) });
			_viewsGo.layer = SplitLayout.UiLayer;
			Canvas val2 = _viewsGo.AddComponent<Canvas>();
			val2.renderMode = (RenderMode)0;
			val2.sortingOrder = sortingOrder;
			GameObject val3 = new GameObject("HudView", new Type[1] { typeof(RectTransform) });
			val3.layer = SplitLayout.UiLayer;
			val3.transform.SetParent(_viewsGo.transform, false);
			RectTransform component = val3.GetComponent<RectTransform>();
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = Vector2.zero;
			component.offsetMax = Vector2.zero;
			RawImage val4 = val3.AddComponent<RawImage>();
			val4.texture = (Texture)(object)_rt;
			((Graphic)val4).raycastTarget = false;
			HotbarState.Reset(_extra);
			_extra.Clear();
			Component[] componentsInChildren = ((Component)val).GetComponentsInChildren<Component>(true);
			foreach (Component val5 in componentsInChildren)
			{
				if (!((Object)(object)val5 == (Object)null) && !(((object)val5).GetType().Name != "HotkeyBar"))
				{
					MethodInfo methodInfo = Refl.Method(((object)val5).GetType(), "Update");
					if (methodInfo != null)
					{
						_extra.Add(new KeyValuePair<Component, MethodInfo>(val5, methodInfo));
					}
				}
			}
			_p2Failed = false;
			_groups = null;
			Active = true;
			SplitScreenPlugin.Log.LogInfo((object)("HUD mirror on. Canvas '" + ((Object)val).name + "', hotbars=" + _extra.Count));
			return true;
		}

		public static void Stop()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_canvas != (Object)null)
			{
				_canvas.renderMode = _prevMode;
				_canvas.worldCamera = _prevCam;
				_canvas.planeDistance = _prevPlane;
			}
			_canvas = null;
			if ((Object)(object)_viewsGo != (Object)null)
			{
				Object.Destroy((Object)(object)_viewsGo);
			}
			if ((Object)(object)_camGo != (Object)null)
			{
				Object.Destroy((Object)(object)_camGo);
			}
			_viewsGo = null;
			_camGo = null;
			_cam = null;
			if ((Object)(object)_rt != (Object)null)
			{
				_rt.Release();
				Object.Destroy((Object)(object)_rt);
				_rt = null;
			}
			HotbarState.Reset(_extra);
			_extra.Clear();
			Active = false;
		}

		private static bool PauseP2()
		{
			if (MenuNav.SessionOpen || MenuNav.RawBuildVisible())
			{
				return true;
			}
			if (RadialCopy.Active)
			{
				return false;
			}
			return RadialState.Open() && RadialState.Owner == 0;
		}

		public static void Render()
		{
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || (Object)(object)_cam == (Object)null || (Object)(object)_canvas == (Object)null)
			{
				return;
			}
			if ((Object)(object)LocalPlayerManager.Players[1] != (Object)null && MenuNav.SessionOpen && MenuNav.Owner == 1)
			{
				InitGroups();
				HotbarState.SwapToP2(_extra);
				try
				{
					LocalPlayerManager.Enter(1);
					try
					{
						foreach (KeyValuePair<Component, MethodInfo> item in _extra)
						{
							if ((Object)(object)item.Key != (Object)null)
							{
								item.Value.Invoke(item.Key, null);
							}
						}
						HotbarState.RefreshIcons(_extra, LocalPlayerManager.Players[1]);
					}
					catch
					{
					}
					finally
					{
						LocalPlayerManager.Exit();
					}
					RadialState.SetPassVisibility(1);
					RadialCopy.SetPass(1);
					Canvas.ForceUpdateCanvases();
					_cam.rect = SplitLayout.ViewportFor(1);
					_cam.Render();
					RadialCopy.SetPass(0);
				}
				finally
				{
					HotbarState.SwapBackToP1(_extra);
				}
				_cam.rect = SplitLayout.ViewportFor(DeviceMap.IsKbm(1) ? 1 : 0);
				return;
			}
			InitGroups();
			SaveAlpha(_a1);
			RadialState.SetPassVisibility(0);
			RadialCopy.SetPass(0);
			Canvas.ForceUpdateCanvases();
			_cam.rect = SplitLayout.ViewportFor(0);
			_cam.Render();
			Hud instance = Hud.instance;
			if ((Object)(object)LocalPlayerManager.Players[1] != (Object)null && (Object)(object)instance != (Object)null && !_p2Failed && !PauseP2())
			{
				if (_a2Set)
				{
					LoadAlpha(_a2);
				}
				else
				{
					SaveAlpha(_a2);
				}
				InP2Pass = true;
				HotbarState.SwapToP2(_extra);
				LocalPlayerManager.Enter(1);
				try
				{
					_hudUpdate.Invoke(instance, null);
					foreach (KeyValuePair<Component, MethodInfo> item2 in _extra)
					{
						if ((Object)(object)item2.Key != (Object)null)
						{
							item2.Value.Invoke(item2.Key, null);
						}
					}
					HotbarState.RefreshIcons(_extra, LocalPlayerManager.Players[1]);
					MinimapP2.Update();
				}
				catch (Exception ex)
				{
					_p2Failed = true;
					Exception? obj2 = ex.InnerException ?? ex;
					SplitScreenPlugin.Log.LogError((object)("HUD mirror P2 pass failed (P2 HUD disabled): " + obj2));
				}
				finally
				{
					LocalPlayerManager.Exit();
					InP2Pass = false;
				}
				try
				{
					SaveAlpha(_a2);
					_a2Set = true;
					RadialState.SetPassVisibility(1);
					RadialCopy.SetPass(1);
					Canvas.ForceUpdateCanvases();
					_cam.rect = SplitLayout.ViewportFor(1);
					_cam.Render();
					LoadAlpha(_a1);
					RadialCopy.SetPass(0);
				}
				finally
				{
					HotbarState.SwapBackToP1(_extra);
				}
			}
			int slot = (DeviceMap.IsKbm(1) ? 1 : 0);
			_cam.rect = SplitLayout.ViewportFor(slot);
		}
	}
	[HarmonyPatch(typeof(GameCamera), "LateUpdate")]
	internal static class GameCameraPatch
	{
		private static void Postfix()
		{
			if (SplitLayout.Active)
			{
				SplitLayout.Reassert();
			}
		}
	}
	internal static class P2Hud
	{
		private static GUIStyle _label;

		private static readonly MethodInfo _getHover = Refl.Method(typeof(Player), "GetHoverObject");

		private static void Fill(Rect r, Color c)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Color color = GUI.color;
			GUI.color = c;
			GUI.DrawTexture(r, (Texture)(object)Texture2D.whiteTexture);
			GUI.color = color;
		}

		private static void Text(Rect r, string text, int size, TextAnchor anchor)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0031: Expected O, but got Unknown
			if (_label == null)
			{
				_label = new GUIStyle(GUI.skin.label)
				{
					richText = true,
					wordWrap = true
				};
			}
			_label.fontSize = size;
			_label.alignment = anchor;
			_label.normal.textColor = new Color(0f, 0f, 0f, 0.9f);
			GUI.Label(new Rect(((Rect)(ref r)).x + 1.5f, ((Rect)(ref r)).y + 1.5f, ((Rect)(ref r)).width, ((Rect)(ref r)).height), text, _label);
			_label.normal.textColor = Color.white;
			GUI.Label(r, text, _label);
		}

		private static void Bar(Rect r, float frac, Color c, string text, float s)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			Fill(r, new Color(0f, 0f, 0f, 0.6f));
			Fill(new Rect(((Rect)(ref r)).x + 2f * s, ((Rect)(ref r)).y + 2f * s, (((Rect)(ref r)).width - 4f * s) * Mathf.Clamp01(frac), ((Rect)(ref r)).height - 4f * s), c);
			if (!string.IsNullOrEmpty(text))
			{
				Text(r, text, Mathf.RoundToInt(13f * s), (TextAnchor)4);
			}
		}

		public static void Draw()
		{
			//IL_05e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0598: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Invalid comparison between Unknown and I4
			//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_00b5: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: 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_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: 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_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: 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_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0412: Unknown result type (might be due to invalid IL or missing references)
			//IL_042e: Unknown result type (might be due to invalid IL or missing references)
			//IL_047e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0492: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d7: Unknown result type (might be due to invalid IL or missing references)
			Player val = LocalPlayerManager.Players[1];
			if (!LocalPlayerManager.Joined || (Object)(object)val == (Object)null || !SplitLayout.Active || HudMirror.Active || (int)Event.current.type != 7)
			{
				return;
			}
			Rect val2 = SplitLayout.ViewportFor(1);
			float num = Screen.width;
			float num2 = Screen.heigh