Decompiled source of HostCharger v0.2.5

BepInEx/plugins/HostCharger/HostCharger.dll

Decompiled 8 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using HostRoleSeries;
using Microsoft.CodeAnalysis;
using PersonalGamepad;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("0.2.5.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1")]
[assembly: AssemblyVersion("0.2.5.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 PersonalGamepad
{
	public enum PadButton
	{
		None,
		LeftShoulder,
		RightShoulder,
		LeftTrigger,
		RightTrigger,
		South,
		East,
		West,
		North,
		LeftStick,
		RightStick,
		DpadUp,
		DpadDown,
		DpadLeft,
		DpadRight
	}
	public sealed class GamepadControls
	{
		private sealed class KeyboardState
		{
			internal readonly KeyboardShortcut Shortcut;

			internal readonly ButtonGate Gate = new ButtonGate();

			internal KeyboardState(KeyboardShortcut shortcut)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				Shortcut = shortcut;
			}
		}

		private sealed class PairState
		{
			internal readonly CombinedGate Gate = new CombinedGate();

			internal int Frame = -1;
		}

		private readonly Func<bool> allowed;

		private readonly ButtonGate[] buttons = new ButtonGate[15];

		private readonly Dictionary<KeyboardShortcut, KeyboardState> keyboards = new Dictionary<KeyboardShortcut, KeyboardState>();

		private readonly Dictionary<string, PairState> pairs = new Dictionary<string, PairState>();

		private int frame = -1;

		private int deviceId = -1;

		private int blockedFrame = -1;

		private bool ready;

		private bool previouslyReady;

		private bool resetThisFrame;

		private static readonly FieldInfo rebind = AccessTools.Field(typeof(InputManager), "rebindingOperation");

		private static readonly FieldInfo textBlock = AccessTools.Field(typeof(InputManager), "gamepadTextInputBlockTimer");

		private static readonly MethodInfo vehicleOverride = AccessTools.Method(typeof(InputManager), "VehicleGamepadOverrideActive", (Type[])null, (Type[])null);

		public static Func<InputKey, PadButton, bool> Reservation;

		public static Func<InputKey, bool> KeyboardReservation;

		private static readonly Dictionary<int, ReservationGate> reservations = new Dictionary<int, ReservationGate>();

		private static int reservationDevice = -1;

		public GamepadControls(Func<bool> allowed)
		{
			this.allowed = allowed ?? throw new ArgumentNullException("allowed");
			for (int i = 0; i < buttons.Length; i++)
			{
				buttons[i] = new ButtonGate();
			}
		}

		public void Tick()
		{
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			if (frame == Time.frameCount)
			{
				return;
			}
			frame = Time.frameCount;
			Gamepad val = CurrentPad();
			int num = ((val == null) ? (-1) : ((InputDevice)val).deviceId);
			bool flag = num != deviceId;
			deviceId = num;
			ready = blockedFrame != frame && NativeInputsAllowed() && allowed();
			resetThisFrame = ready && !previouslyReady;
			previouslyReady = ready;
			for (int i = 1; i < buttons.Length; i++)
			{
				ButtonControl val2 = Control(val, (PadButton)i);
				buttons[i].Sample(val2 != null && val2.isPressed, ready, flag || resetThisFrame);
			}
			foreach (KeyboardState value in keyboards.Values)
			{
				value.Gate.Sample(KeyboardPressed(value.Shortcut), ready, resetThisFrame);
			}
			if (ready)
			{
				return;
			}
			foreach (PairState value2 in pairs.Values)
			{
				value2.Gate.Sample(keyboard: false, gamepad: false, allowed: false);
				value2.Frame = frame;
			}
		}

		public void Block()
		{
			blockedFrame = Time.frameCount;
			foreach (PairState value in pairs.Values)
			{
				value.Frame = -1;
			}
			frame = -1;
			Tick();
		}

		public bool PadHeld(PadButton button)
		{
			Tick();
			if (button > PadButton.None && (int)button < buttons.Length)
			{
				return buttons[(int)button].Held;
			}
			return false;
		}

		public bool Held(KeyboardShortcut keyboard, PadButton button)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return State(keyboard, button).Held;
		}

		public bool Held(KeyCode keyboard, PadButton button)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return this.Held(new KeyboardShortcut(keyboard, Array.Empty<KeyCode>()), button);
		}

		public bool Down(KeyboardShortcut keyboard, PadButton button)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return State(keyboard, button).Down;
		}

		public bool Down(KeyCode keyboard, PadButton button)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return this.Down(new KeyboardShortcut(keyboard, Array.Empty<KeyCode>()), button);
		}

		public bool Up(KeyboardShortcut keyboard, PadButton button)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return State(keyboard, button).Up;
		}

		public bool Up(KeyCode keyboard, PadButton button)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return this.Up(new KeyboardShortcut(keyboard, Array.Empty<KeyCode>()), button);
		}

		private unsafe CombinedGate State(KeyboardShortcut keyboard, PadButton button)
		{
			//IL_000c: 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_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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			Tick();
			if (!keyboards.TryGetValue(keyboard, out var value))
			{
				value = new KeyboardState(keyboard);
				keyboards.Add(keyboard, value);
				bool flag = KeyboardPressed(keyboard);
				bool flag2 = (int)((KeyboardShortcut)(ref keyboard)).MainKey != 0 && UnityInput.Current.GetKeyDown(((KeyboardShortcut)(ref keyboard)).MainKey);
				value.Gate.Sample(flag, ready, resetThisFrame || (flag && !flag2));
			}
			string? text = ((object)(*(KeyboardShortcut*)(&keyboard))/*cast due to .constrained prefix*/).ToString();
			int num = (int)button;
			string key = text + "|" + num;
			if (!pairs.TryGetValue(key, out var value2))
			{
				value2 = new PairState();
				pairs.Add(key, value2);
			}
			if (value2.Frame != frame)
			{
				value2.Frame = frame;
				value2.Gate.Sample(value.Gate.Held, PadHeld(button), ready);
			}
			return value2.Gate;
		}

		private static bool KeyboardPressed(KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !UnityInput.Current.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if (!UnityInput.Current.GetKey(modifier))
				{
					return false;
				}
			}
			return true;
		}

		private static Gamepad CurrentPad()
		{
			Gamepad current = Gamepad.current;
			if (current == null || !((InputDevice)current).added || !((InputDevice)current).enabled)
			{
				return null;
			}
			return current;
		}

		public static bool NativeInputsAllowed()
		{
			InputManager instance = InputManager.instance;
			if (!Application.isFocused || (Object)(object)instance == (Object)null || !((Behaviour)instance).isActiveAndEnabled)
			{
				return false;
			}
			InputAction action = instance.GetAction((InputKey)1);
			if (action == null || !action.enabled)
			{
				return false;
			}
			if (!SemiFunc.NoTextInputsActive() || !SemiFunc.NoExternalTextInputActive() || instance.textInputsActivePrevFrame || instance.externalTextInputActivePrevFrame)
			{
				return false;
			}
			if (rebind != null && rebind.GetValue(instance) != null)
			{
				return false;
			}
			if (textBlock != null && (float)textBlock.GetValue(instance) > 0f)
			{
				return false;
			}
			if (!instance.VehicleInputAllowed() || instance.ExpressionWheelActive())
			{
				return false;
			}
			if (vehicleOverride != null && (bool)vehicleOverride.Invoke(instance, null))
			{
				return false;
			}
			return true;
		}

		internal static ButtonControl Control(Gamepad pad, PadButton button)
		{
			if (pad == null)
			{
				return null;
			}
			return (ButtonControl)(button switch
			{
				PadButton.LeftShoulder => pad.leftShoulder, 
				PadButton.RightShoulder => pad.rightShoulder, 
				PadButton.LeftTrigger => pad.leftTrigger, 
				PadButton.RightTrigger => pad.rightTrigger, 
				PadButton.South => pad.buttonSouth, 
				PadButton.East => pad.buttonEast, 
				PadButton.West => pad.buttonWest, 
				PadButton.North => pad.buttonNorth, 
				PadButton.LeftStick => pad.leftStickButton, 
				PadButton.RightStick => pad.rightStickButton, 
				PadButton.DpadUp => pad.dpad.up, 
				PadButton.DpadDown => pad.dpad.down, 
				PadButton.DpadLeft => pad.dpad.left, 
				PadButton.DpadRight => pad.dpad.right, 
				_ => null, 
			});
		}

		public static void Install(Harmony harmony)
		{
			InstallPostfix(harmony, "KeyDown", "DownPostfix");
			InstallPostfix(harmony, "KeyHold", "HoldPostfix");
		}

		private static void InstallPostfix(Harmony harmony, string targetName, string patchName)
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(InputManager), targetName, new Type[2]
			{
				typeof(InputKey),
				typeof(bool)
			}, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(GamepadControls), patchName, (Type[])null, (Type[])null);
			Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
			if (patchInfo != null)
			{
				foreach (Patch postfix in patchInfo.Postfixes)
				{
					if (postfix.owner == harmony.Id && postfix.PatchMethod == methodInfo2)
					{
						return;
					}
				}
			}
			reservations.Clear();
			reservationDevice = -1;
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static void DownPostfix(InputManager __instance, InputKey key, ref bool __result)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			FilterNative(__instance, key, down: true, ref __result);
		}

		private static void HoldPostfix(InputManager __instance, InputKey key, ref bool __result)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			FilterNative(__instance, key, down: false, ref __result);
		}

		private static void FilterNative(InputManager manager, InputKey key, bool down, ref bool result)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Expected I4, but got Unknown
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			if (KeyboardReservation != null && KeyboardReservation(key))
			{
				result = false;
			}
			else
			{
				if ((int)key != 14 && (int)key != 11)
				{
					return;
				}
				Gamepad val = CurrentPad();
				int num = ((val == null) ? (-1) : ((InputDevice)val).deviceId);
				if (num != reservationDevice)
				{
					reservations.Clear();
					reservationDevice = num;
				}
				bool flag = val != null && NativeInputsAllowed();
				InputAction action = manager.GetAction(key);
				if (action == null)
				{
					return;
				}
				bool flag2 = false;
				bool flag3 = false;
				Enumerator<InputControl> enumerator = action.controls.GetEnumerator();
				try
				{
					while (enumerator.MoveNext())
					{
						InputControl current = enumerator.Current;
						ButtonControl val2 = (ButtonControl)(object)((current is ButtonControl) ? current : null);
						if (val2 == null)
						{
							continue;
						}
						bool flag4 = (down ? val2.wasPressedThisFrame : val2.isPressed);
						PadButton padButton = PadButton.None;
						if (val != null && (object)((InputControl)val2).device == val)
						{
							for (int i = 1; i <= 14; i++)
							{
								if (val2 == Control(val, (PadButton)i))
								{
									padButton = (PadButton)i;
									break;
								}
							}
						}
						if (padButton == PadButton.None)
						{
							flag3 = flag3 || flag4;
							continue;
						}
						int key2 = (int)(key * 100 + padButton);
						if (!reservations.TryGetValue(key2, out var value))
						{
							value = new ReservationGate();
							reservations.Add(key2, value);
						}
						bool requested = flag && Reservation != null && Reservation(key, padButton);
						bool flag5 = value.Sample(requested, val2.isPressed, val2.wasReleasedThisFrame, flag);
						flag2 = flag2 || flag5;
						flag3 = flag3 || (flag4 && !flag5);
					}
				}
				finally
				{
					((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
				}
				if (result && flag2 && !flag3)
				{
					result = false;
				}
			}
		}
	}
	internal sealed class ButtonGate
	{
		private bool armed = true;

		internal bool Held { get; private set; }

		internal bool Sample(bool pressed, bool allowed, bool reset = false)
		{
			if (reset || !allowed)
			{
				armed = !pressed;
				Held = false;
				return false;
			}
			if (!pressed)
			{
				armed = true;
			}
			Held = pressed && armed;
			return Held;
		}
	}
	internal sealed class CombinedGate
	{
		internal bool Held { get; private set; }

		internal bool Down { get; private set; }

		internal bool Up { get; private set; }

		internal void Sample(bool keyboard, bool gamepad, bool allowed)
		{
			bool flag = allowed && (keyboard || gamepad);
			Down = allowed && flag && !Held;
			Up = allowed && !flag && Held;
			Held = flag;
		}
	}
	internal sealed class ReservationGate
	{
		private bool latched;

		internal bool Sample(bool requested, bool pressed, bool released, bool usable)
		{
			if (!usable)
			{
				latched = false;
				return false;
			}
			if (requested && pressed)
			{
				latched = true;
			}
			bool result = latched && (pressed || released);
			if (!pressed && !released)
			{
				latched = false;
			}
			return result;
		}
	}
}
namespace HostCharger
{
	internal sealed class ChargeBeam : IDisposable
	{
		private const float Scale = 0.0001f;

		private readonly Plugin plugin;

		private readonly ItemBattery target;

		private GameObject root;

		private ItemDrone drone;

		private PhysGrabObject physics;

		private PhotonView view;

		private PhotonView targetView;

		private Transform attachment;

		private Transform hand;

		private Collider targetCollider;

		private int colliderId;

		private float createdAt;

		private float nextMove;

		private readonly Dictionary<int, float> observers = new Dictionary<int, float>();

		internal bool Ready { get; private set; }

		private Vector3 EndPoint
		{
			get
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: 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)
				Bounds bounds = targetCollider.bounds;
				return ((Bounds)(ref bounds)).center;
			}
		}

		internal ChargeBeam(Plugin owner, ItemBattery item)
		{
			plugin = owner;
			target = item;
		}

		internal bool Contains(Component c)
		{
			if (Object.op_Implicit((Object)(object)c) && Object.op_Implicit((Object)(object)root))
			{
				if (!((Object)(object)c.gameObject == (Object)(object)root))
				{
					return c.transform.IsChildOf(root.transform);
				}
				return true;
			}
			return false;
		}

		internal void Create()
		{
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			PlayerAvatarRightArm componentInChildren = ((Component)PlayerAvatar.instance.playerAvatarVisuals).GetComponentInChildren<PlayerAvatarRightArm>(true);
			if (!Object.op_Implicit((Object)(object)componentInChildren) || !Object.op_Implicit((Object)(object)componentInChildren.grabberTransform))
			{
				throw new InvalidOperationException("Charge beam hand unavailable.");
			}
			hand = componentInChildren.grabberTransform;
			colliderId = Native.Get<int>(PhysGrabber.instance, "grabbedPhysGrabObjectColliderID");
			if (colliderId < 0)
			{
				throw new InvalidOperationException("No native item collider for charge beam.");
			}
			PhysGrabObjectCollider[] componentsInChildren = ((Component)target).GetComponentsInChildren<PhysGrabObjectCollider>(true);
			foreach (PhysGrabObjectCollider val in componentsInChildren)
			{
				if (Native.Get<int>(val, "colliderID") == colliderId)
				{
					attachment = ((Component)val).transform;
					targetCollider = ((Component)val).GetComponent<Collider>();
					break;
				}
			}
			if (!Object.op_Implicit((Object)(object)attachment) || !Object.op_Implicit((Object)(object)targetCollider))
			{
				throw new InvalidOperationException("Charge beam target collider unavailable.");
			}
			targetView = ((Component)target).GetComponent<PhotonView>();
			if (SemiFunc.IsMultiplayer() && (!Object.op_Implicit((Object)(object)targetView) || targetView.ViewID <= 0))
			{
				throw new InvalidOperationException("Charge beam target has no network identity.");
			}
			PrefabRef val2 = null;
			foreach (Item value in StatsManager.instance.itemDictionary.Values)
			{
				if (Object.op_Implicit((Object)(object)value) && value.prefab != null && ((PrefabRef<GameObject>)(object)value.prefab).IsValid())
				{
					GameObject prefab = ((PrefabRef<GameObject>)(object)value.prefab).Prefab;
					if (Object.op_Implicit((Object)(object)prefab) && Object.op_Implicit((Object)(object)prefab.GetComponent<ItemDroneBattery>()) && Object.op_Implicit((Object)(object)prefab.GetComponent<ItemDrone>()) && !string.IsNullOrEmpty(((PrefabRef<GameObject>)(object)value.prefab).ResourcePath))
					{
						val2 = value.prefab;
						break;
					}
				}
			}
			if (val2 == null)
			{
				throw new InvalidOperationException("Native battery drone prefab unavailable.");
			}
			LineBetweenTwoPoints lineBetweenTwoPoints = ((PrefabRef<GameObject>)(object)val2).Prefab.GetComponent<ItemDrone>().lineBetweenTwoPoints;
			Transform val3 = (Object.op_Implicit((Object)(object)lineBetweenTwoPoints) ? ((Component)lineBetweenTwoPoints).transform.Find("Line") : null);
			LineRenderer val4 = (Object.op_Implicit((Object)(object)val3) ? ((Component)val3).GetComponent<LineRenderer>() : null);
			if (!Object.op_Implicit((Object)(object)val4) || !val4.useWorldSpace)
			{
				throw new InvalidOperationException("Native charge beam is not world-space; no host-only fallback.");
			}
			root = (SemiFunc.IsMultiplayer() ? PhotonNetwork.Instantiate(((PrefabRef<GameObject>)(object)val2).ResourcePath, hand.position, Quaternion.identity, (byte)0, new object[4] { 0.0001f, 0.0001f, 0.0001f, "local.bei.hostcharger" }) : Object.Instantiate<GameObject>(((PrefabRef<GameObject>)(object)val2).Prefab, hand.position, Quaternion.identity));
			if (!Object.op_Implicit((Object)(object)root))
			{
				throw new InvalidOperationException("Charge beam carrier failed to spawn.");
			}
			root.transform.localScale = Vector3.one * 0.0001f;
			drone = root.GetComponent<ItemDrone>();
			physics = root.GetComponent<PhysGrabObject>();
			view = root.GetComponent<PhotonView>();
			MonoBehaviour[] components = root.GetComponents<MonoBehaviour>();
			foreach (MonoBehaviour val5 in components)
			{
				if (val5 is ItemDrone || val5 is ItemDroneBattery || val5 is PhysGrabObject || val5 is PhysGrabObjectImpactDetector || val5 is ItemAttributes || val5 is ItemEquippable || val5 is ItemBattery || val5 is ItemToggle || val5 is RoomVolumeCheck)
				{
					((Behaviour)val5).enabled = false;
					val5.StopAllCoroutines();
				}
			}
			Rigidbody component = root.GetComponent<Rigidbody>();
			component.isKinematic = true;
			component.useGravity = false;
			component.detectCollisions = false;
			Native.Set(physics, "isKinematic", true);
			Native.Call(drone, "Start");
			Native.Call(root.GetComponent<ItemToggle>(), "Start");
			Native.Call(root.GetComponent<ItemToggle>(), "Update");
			Collider[] componentsInChildren2 = root.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				componentsInChildren2[i].enabled = false;
			}
			createdAt = Time.time;
			plugin.Detail("Charge beam carrier=" + ((PrefabRef<GameObject>)(object)val2).ResourcePath + "; native world-space line, identical prefab scale for all peers.");
		}

		internal void Tick()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)root) || !Object.op_Implicit((Object)(object)target) || !Object.op_Implicit((Object)(object)attachment) || !Object.op_Implicit((Object)(object)hand))
			{
				throw new InvalidOperationException("Charge beam target/hand lost.");
			}
			Transform overrideTransform = PlayerAvatar.instance.localCamera.GetOverrideTransform();
			Vector3 val = hand.position + overrideTransform.right * 0.04f;
			physics.SetPositionLogic(val, Quaternion.identity);
			if (Time.unscaledTime >= nextMove)
			{
				nextMove = Time.unscaledTime + 0.05f;
				if (SemiFunc.IsMultiplayer())
				{
					view.RPC("SetPositionRPC", (RpcTarget)1, new object[2]
					{
						val,
						Quaternion.identity
					});
				}
			}
			if (!Ready && Time.time - createdAt >= 0.2f)
			{
				Native.Call(root.GetComponent<ItemToggle>(), "ToggleItem", true, ((Component)PlayerAvatar.instance).GetComponent<PhotonView>().ViewID);
				Native.Call(drone, "NewRayHitPoint", EndPoint, Object.op_Implicit((Object)(object)targetView) ? targetView.ViewID : 0, colliderId, ((Component)target).transform);
				Native.Call(drone, "MagnetActiveToggle", true);
				Native.Call(drone, "StateSet", (object)(State)3);
				Ready = true;
				if (SemiFunc.IsMultiplayer())
				{
					Player[] playerList = PhotonNetwork.PlayerList;
					foreach (Player val2 in playerList)
					{
						observers[val2.ActorNumber] = -1f;
					}
				}
			}
			if (Ready && SemiFunc.IsMultiplayer())
			{
				SyncNewObservers();
			}
		}

		internal void Render()
		{
			if (Ready && Object.op_Implicit((Object)(object)root) && Object.op_Implicit((Object)(object)target) && Object.op_Implicit((Object)(object)attachment) && ((Component)target).gameObject.activeInHierarchy)
			{
				Native.Call(root.GetComponent<ItemToggle>(), "Update");
				Native.Call(drone, "StateAttached");
			}
		}

		private void SyncNewObservers()
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			Player[] playerList = PhotonNetwork.PlayerList;
			foreach (Player val in playerList)
			{
				if (!val.IsLocal)
				{
					if (!observers.TryGetValue(val.ActorNumber, out var value))
					{
						observers[val.ActorNumber] = Time.unscaledTime + 0.5f;
					}
					else if (!(value < 0f) && !(Time.unscaledTime < value))
					{
						view.RPC("NewRayHitPointRPC", val, new object[3] { EndPoint, targetView.ViewID, colliderId });
						view.RPC("MagnetActiveToggleRPC", val, new object[1] { true });
						view.RPC("StateSetRPC", val, new object[1] { 3 });
						observers[val.ActorNumber] = -1f;
					}
				}
			}
		}

		public void Dispose()
		{
			GameObject val = root;
			root = null;
			Ready = false;
			observers.Clear();
			if (Object.op_Implicit((Object)(object)val))
			{
				PhotonView component = val.GetComponent<PhotonView>();
				if (Object.op_Implicit((Object)(object)component) && component.ViewID > 0 && PhotonNetwork.InRoom && component.IsMine)
				{
					PhotonNetwork.Destroy(val);
				}
				else
				{
					Object.Destroy((Object)(object)val);
				}
			}
		}
	}
	internal sealed class ChargerRules
	{
		private const double InitialEnergy = 10.0;

		internal double Energy { get; private set; } = 10.0;

		internal double LaserCharge { get; private set; }

		internal bool CanTumbleZap => Energy >= 1.0;

		internal bool IsFull => Energy >= 20.0;

		internal bool CanFireLaser => LaserCharge > 0.0;

		internal double MovementMultiplier
		{
			get
			{
				if (!(Energy >= 10.0))
				{
					if (!(Energy >= 6.0))
					{
						if (!(Energy >= 2.0))
						{
							return 0.5;
						}
						return 0.7;
					}
					return 0.9;
				}
				return 1.0;
			}
		}

		internal void ResetRun()
		{
			Energy = 10.0;
			LaserCharge = 0.0;
		}

		internal void RecoverMovement(double dt, bool moving, bool running, bool laserFiring)
		{
			if (moving && dt > 0.0 && !double.IsInfinity(dt))
			{
				if (!IsFull)
				{
					Energy = Math.Min(20.0, Energy + dt * (running ? 0.0008 : 0.0003) * 20.0);
				}
				else if (!laserFiring)
				{
					LaserCharge = Math.Min(1.0, LaserCharge + dt * (running ? 0.05 : 0.02));
				}
			}
		}

		internal double SpendLaser(double dt)
		{
			if (!(dt > 0.0) || double.IsInfinity(dt))
			{
				return 0.0;
			}
			double num = Math.Min(LaserCharge, dt / 8.0);
			LaserCharge -= num;
			return num;
		}

		internal double RecoverAtStation(double dt, double chargeRate, ref double stationEnergy)
		{
			if (!(dt > 0.0) || double.IsInfinity(dt) || !(chargeRate > 0.0) || double.IsInfinity(chargeRate) || !(stationEnergy > 0.0) || double.IsInfinity(stationEnergy))
			{
				return 0.0;
			}
			double num = chargeRate * 10.0;
			double num2 = Math.Min(20.0 - Energy, Math.Min(dt * 2.0, stationEnergy / num));
			Energy += num2;
			stationEnergy = Math.Max(0.0, stationEnergy - num2 * num);
			return num2;
		}

		internal double Spend(double wanted)
		{
			if (!(wanted > 0.0) || double.IsInfinity(wanted))
			{
				return 0.0;
			}
			double num = Math.Min(Energy, wanted);
			Energy -= num;
			return num;
		}

		internal static double ChargePercentPerMemory(int droneBars)
		{
			if (droneBars < 1)
			{
				throw new ArgumentOutOfRangeException("droneBars");
			}
			return 2.0 * (100.0 / (double)droneBars);
		}
	}
	internal sealed class ChargerInput
	{
		private enum ActionMode
		{
			None,
			Charge,
			Laser
		}

		private bool prevChord;

		private bool blocked;

		private ActionMode mode;

		private int targetId;

		internal bool ChargeHeld { get; private set; }

		internal bool LaserHeld { get; private set; }

		internal bool PressStarted { get; private set; }

		internal void Block()
		{
			blocked = true;
			prevChord = false;
			mode = ActionMode.None;
			targetId = 0;
			bool flag = (PressStarted = false);
			bool chargeHeld = (LaserHeld = flag);
			ChargeHeld = chargeHeld;
		}

		internal void Step(bool allowed, bool down, bool up, bool holdingObject, int batteryId)
		{
			bool flag = (PressStarted = false);
			bool chargeHeld = (LaserHeld = flag);
			ChargeHeld = chargeHeld;
			if (!allowed)
			{
				Block();
				return;
			}
			if (blocked)
			{
				if (!down && !up)
				{
					blocked = false;
				}
				return;
			}
			if (!down || !up)
			{
				prevChord = false;
				mode = ActionMode.None;
				targetId = 0;
				return;
			}
			if (!prevChord)
			{
				PressStarted = true;
				targetId = batteryId;
				mode = ((!holdingObject) ? ActionMode.Laser : ((batteryId != 0) ? ActionMode.Charge : ActionMode.None));
			}
			prevChord = true;
			if ((mode == ActionMode.Charge && (!holdingObject || batteryId != targetId)) || (mode == ActionMode.Laser && holdingObject))
			{
				Block();
				return;
			}
			ChargeHeld = mode == ActionMode.Charge;
			LaserHeld = mode == ActionMode.Laser;
		}
	}
	[BepInPlugin("local.bei.hostcharger", "HostCharger", "0.2.5")]
	[BepInDependency("local.bei.hostroleselector", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(PhysGrabObject), "GrabStartedRPC")]
		private static class ProtectLaser
		{
			private static bool Prefix(PhysGrabObject __instance)
			{
				if (!Owns((Component)(object)__instance))
				{
					return true;
				}
				Current.StopAll();
				return false;
			}
		}

		[HarmonyPatch(typeof(PhysGrabObject), "GrabLink")]
		private static class ProtectLaserLink
		{
			private static bool Prefix(PhysGrabObject __instance)
			{
				if (!Owns((Component)(object)__instance))
				{
					return true;
				}
				Current.StopAll();
				return false;
			}
		}

		[HarmonyPatch(typeof(PlayerController), "FixedUpdate")]
		private static class ChargerMovementPatch
		{
			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				List<CodeInstruction> list = instructions.ToList();
				FieldInfo walk = AccessTools.Field(typeof(PlayerController), "MoveSpeed");
				FieldInfo sprint = AccessTools.Field(typeof(PlayerController), "SprintSpeed");
				FieldInfo crouch = AccessTools.Field(typeof(PlayerController), "CrouchSpeed");
				if (list.Count((CodeInstruction i) => CodeInstructionExtensions.LoadsField(i, walk, false)) != 2 || list.Count((CodeInstruction i) => CodeInstructionExtensions.LoadsField(i, sprint, false)) != 1 || list.Count((CodeInstruction i) => CodeInstructionExtensions.LoadsField(i, crouch, false)) != 1)
				{
					throw new InvalidOperationException("PlayerController locomotion calculation changed; refusing a broad movement patch.");
				}
				foreach (CodeInstruction item in list)
				{
					string text = (CodeInstructionExtensions.LoadsField(item, walk, false) ? "WalkSpeedForRole" : (CodeInstructionExtensions.LoadsField(item, sprint, false) ? "SprintSpeedForRole" : (CodeInstructionExtensions.LoadsField(item, crouch, false) ? "CrouchSpeedForRole" : null)));
					if (text != null)
					{
						item.opcode = OpCodes.Call;
						item.operand = AccessTools.Method(typeof(Plugin), text, (Type[])null, (Type[])null);
					}
					yield return item;
				}
			}
		}

		[HarmonyPatch(typeof(RunManager), "ResetProgress")]
		private static class ChargerNewRunPatch
		{
			private static void Postfix()
			{
				if (Object.op_Implicit((Object)(object)Current) && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMasterClientOrSingleplayer())
				{
					Current.rules.ResetRun();
				}
			}
		}

		[HarmonyPatch(typeof(ChargingStation), "ChargeAreaCheck")]
		private static class TruckChargePatch
		{
			private static void Prefix(ChargingStation __instance, out bool __state)
			{
				__state = false;
				if (!Object.op_Implicit((Object)(object)Current))
				{
					return;
				}
				Current.stationChecking = null;
				try
				{
					__state = Current.CanRechargeAt(__instance);
					if (__state)
					{
						Current.stationChecking = __instance;
						Current.stationCheckFrame = Time.frameCount;
					}
				}
				catch (Exception e)
				{
					Current.StationError(e);
				}
			}

			private static void Postfix(ChargingStation __instance, bool __state)
			{
				if (!Object.op_Implicit((Object)(object)Current))
				{
					return;
				}
				Current.stationChecking = null;
				if (!__state)
				{
					return;
				}
				try
				{
					Current.RechargeFromStation(__instance);
				}
				catch (Exception e)
				{
					Current.StationError(e);
				}
			}
		}

		[HarmonyPatch(typeof(ChargingStation), "StopCharge")]
		private static class KeepTruckChargeRunning
		{
			private static bool Prefix(ChargingStation __instance)
			{
				if (Object.op_Implicit((Object)(object)Current) && !((Object)(object)Current.stationChecking != (Object)(object)__instance))
				{
					return Current.stationCheckFrame != Time.frameCount;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(ChargingStation), "Update")]
		private static class KeepStationSegmentConsistent
		{
			private static void Postfix(ChargingStation __instance)
			{
				if (Object.op_Implicit((Object)(object)Current) && !((Object)(object)Current.stationRecovered != (Object)(object)__instance) && Current.stationRecoveredFrame == Time.frameCount)
				{
					Native.Set(__instance, "chargeSegmentCurrent", Native.Get<int>(__instance, "lastSentSegment"));
				}
			}
		}

		[HarmonyPatch(typeof(HurtCollider), "EnemyHurt")]
		private static class ChargerTumbleZapPatch
		{
			private static void Prefix(HurtCollider __instance, out bool __state)
			{
				__state = false;
				try
				{
					__state = Object.op_Implicit((Object)(object)Current) && Current.IsChargerTumbleHit(__instance);
				}
				catch (Exception e)
				{
					if (Object.op_Implicit((Object)(object)Current))
					{
						Current.ZapError(e);
					}
				}
			}

			private static void Postfix(HurtCollider __instance, Enemy __0, bool __result, bool __state)
			{
				if (!__state || !__result || !Object.op_Implicit((Object)(object)Current))
				{
					return;
				}
				try
				{
					Current.TumbleZap(__0, __instance);
				}
				catch (Exception e)
				{
					Current.ZapError(e);
				}
			}
		}

		private const int EnergyEyePriority = -998;

		private const float EnergyEyeLease = 0.2f;

		private float nextEnergyEyeSync;

		private GamepadControls gamepad;

		private ConfigEntry<PadButton> gamepadCharge;

		private ConfigEntry<PadButton> gamepadLaser;

		private ConfigEntry<bool> suppressGamepadConflicts;

		private GUIStyle labelStyle;

		private static readonly Color EnergyYellow = new Color(1f, 0.88f, 0.18f, 1f);

		public const string Id = "local.bei.hostcharger";

		internal static Plugin Current;

		private ConfigEntry<bool> modEnabled;

		private ConfigEntry<KeyboardShortcut> chargeKey;

		private ConfigEntry<KeyboardShortcut> laserKey;

		private readonly ChargerRules rules = new ChargerRules();

		private readonly ChargerInput input = new ChargerInput();

		private LaserCarrier laser;

		private Harmony harmony;

		private LevelGenerator stage;

		private int sceneHandle = -1;

		private bool hudVisible;

		private bool lastSelected;

		private bool retiredDragon;

		private ItemBattery pressedBattery;

		private float retryAt;

		private float nextError;

		private bool charging;

		private bool ownsChargingVisual;

		private ItemBattery chargeTarget;

		private double chargePercent;

		private ChargeBeam chargeBeam;

		private int droneBars;

		private ChargingStation stationChecking;

		private ChargingStation stationRecovered;

		private int stationCheckFrame = -1;

		private int stationRecoveredFrame = -1;

		private readonly List<ProdzapEffect> zapEffects = new List<ProdzapEffect>();

		private float zapPrepareRetry;

		private void TickLaserChargeEyes()
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Invalid comparison between Unknown and I4
			if (!rules.CanFireLaser || !ChargedRoleActive())
			{
				return;
			}
			PlayerAvatar instance = PlayerAvatar.instance;
			PlayerHealth playerHealth = instance.playerHealth;
			if (!Object.op_Implicit((Object)(object)playerHealth) || !((Behaviour)playerHealth).isActiveAndEnabled || playerHealth.isMenuAvatar)
			{
				return;
			}
			playerHealth.EyeMaterialOverride((EyeOverrideState)6, 0.2f, -998);
			if (SemiFunc.IsMultiplayer() && !(Time.unscaledTime < nextEnergyEyeSync))
			{
				nextEnergyEyeSync = Time.unscaledTime + 2f;
				if (Native.Get<bool>(playerHealth, "overrideEyeActive") && (int)Native.Get<EyeOverrideState>(playerHealth, "overrideEyeState") == 6)
				{
					instance.photonView.RPC("EyeMaterialOverrideRPC", (RpcTarget)1, new object[2]
					{
						(object)(EyeOverrideState)6,
						true
					});
				}
			}
		}

		private void InitializeGamepad()
		{
			gamepadCharge = ((BaseUnityPlugin)this).Config.Bind<PadButton>("Controls", "GamepadChargeButton", PadButton.None, "Native L1/LB modifier. Combine with GamepadLaserButton. None disables this gamepad binding; keyboard bindings remain available.");
			gamepadLaser = ((BaseUnityPlugin)this).Config.Bind<PadButton>("Controls", "GamepadLaserButton", PadButton.None, "Native R1/RB modifier. Hold both modifiers to recharge an item or fire the eye laser.");
			suppressGamepadConflicts = ((BaseUnityPlugin)this).Config.Bind<bool>("Controls", "SuppressConflictingGamepadActions", true, "Suppress native Tumble/Rotate from the same buttons while the Charger chord is held. Does not change saved game bindings. Press L1 before R1; R1 by itself retains native tumble.");
			gamepad = new GamepadControls(() => Object.op_Implicit((Object)(object)this) && ((Behaviour)this).isActiveAndEnabled && modEnabled.Value && WorldReady() && RoleMenu.IsSelected("local.bei.hostcharger") && ControlsReady());
			GamepadControls.KeyboardReservation = (InputKey key) => (int)key == 2 && Object.op_Implicit((Object)(object)this) && ((Behaviour)this).isActiveAndEnabled && modEnabled.Value && WorldReady() && RoleMenu.IsSelected("local.bei.hostcharger") && ControlsReady() && gamepad.Held(chargeKey.Value, PadButton.None);
			GamepadControls.Reservation = (InputKey key, PadButton button) => suppressGamepadConflicts.Value && gamepad.Held(chargeKey.Value, gamepadCharge.Value) && gamepad.Held(laserKey.Value, gamepadLaser.Value) && ((button == gamepadCharge.Value && gamepad.PadHeld(button)) || (button == gamepadLaser.Value && gamepad.PadHeld(button)));
		}

		private void OnGUI()
		{
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			//IL_0427: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0372: Unknown result type (might be due to invalid IL or missing references)
			//IL_0377: Unknown result type (might be due to invalid IL or missing references)
			//IL_037f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_0399: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a3: Expected O, but got Unknown
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Expected O, but got Unknown
			if (!hudVisible)
			{
				return;
			}
			Matrix4x4 matrix = GUI.matrix;
			Color color = GUI.color;
			Color contentColor = GUI.contentColor;
			int depth = GUI.depth;
			try
			{
				float num = (float)Screen.width / 1920f;
				float num2 = num * 0.7f;
				float num3 = (float)Screen.width - 110f * num - 210f * num2;
				float num4 = (float)Screen.height - 28f * num - 62f * num2;
				GUI.matrix = Matrix4x4.TRS(new Vector3(num3, num4, 0f), Quaternion.identity, Vector3.one * num2);
				GUI.color = (GUI.contentColor = Color.white);
				GUI.depth = -100;
				Fill(new Rect(0f, 0f, 210f, 62f), new Color(0.06f, 0.06f, 0.06f, 0.9f));
				Fill(new Rect(0f, 0f, 210f, 4f), EnergyYellow);
				Fill(new Rect(0f, 58f, 210f, 4f), EnergyYellow);
				Fill(new Rect(0f, 4f, 4f, 54f), EnergyYellow);
				Fill(new Rect(206f, 4f, 4f, 54f), EnergyYellow);
				for (int i = 0; i < 20; i++)
				{
					Fill(new Rect(12f + (float)i * 9.35f, 15f, 7.2f, 32f), new Color(0.22f, 0.19f, 0.05f, 1f));
					float num5 = Mathf.Clamp01((float)rules.Energy - (float)i);
					if (num5 > 0f)
					{
						Fill(new Rect(12f + (float)i * 9.35f, 15f + 32f * (1f - num5), 7.2f, 32f * num5), EnergyYellow);
					}
				}
				Fill(new Rect(-123f, 31f, 105f, 31f), new Color(0.06f, 0.06f, 0.06f, 0.9f));
				Fill(new Rect(-123f, 31f, 105f, 2f), EnergyYellow);
				Fill(new Rect(-123f, 60f, 105f, 2f), EnergyYellow);
				Fill(new Rect(-123f, 33f, 2f, 27f), EnergyYellow);
				Fill(new Rect(-20f, 33f, 2f, 27f), EnergyYellow);
				Fill(new Rect(-116f, 38.5f, 91f, 16f), new Color(0.22f, 0.19f, 0.05f, 1f));
				float num6 = Mathf.Clamp01((float)rules.LaserCharge);
				if (num6 > 0f)
				{
					Fill(new Rect(-116f, 38.5f, 91f * num6, 16f), EnergyYellow);
				}
				if (labelStyle == null)
				{
					labelStyle = new GUIStyle(GUI.skin.label)
					{
						fontSize = 25,
						fontStyle = (FontStyle)1,
						alignment = (TextAnchor)8,
						clipping = (TextClipping)0,
						padding = new RectOffset(0, 0, 0, 0),
						richText = false,
						wordWrap = false
					};
				}
				labelStyle.normal.textColor = Color.white;
				GUI.Label(new Rect(-70f, -48f, 280f, 38f), (laser != null && laser.IsFiring) ? "LASER" : (charging ? "RECHARGE" : "CHARGER"), labelStyle);
			}
			finally
			{
				GUI.matrix = matrix;
				GUI.color = color;
				GUI.contentColor = contentColor;
				GUI.depth = depth;
			}
		}

		private static void Fill(Rect rect, Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Color color2 = GUI.color;
			GUI.color = color;
			GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture);
			GUI.color = color2;
		}

		private void TickMovementRecovery(bool controlsReady)
		{
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: 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_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			PlayerAvatar instance = PlayerAvatar.instance;
			PlayerController instance2 = PlayerController.instance;
			if (!controlsReady || !Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)instance2) || !Object.op_Implicit((Object)(object)RunManager.instance) || Native.Get<bool>(RunManager.instance, "restarting") || !Native.Get<bool>(instance, "spawned") || Native.Get<bool>(instance, "deadSet") || Native.Get<bool>(instance, "isDisabled") || Native.Get<bool>(instance, "isTumbling") || Time.deltaTime <= 0f || Time.timeScale <= 0f || !Object.op_Implicit((Object)(object)instance2.CollisionController) || !instance2.CollisionController.Grounded || instance2.Sliding || Native.Get<float>(instance2, "MoveForceTimer") > 0f || Native.Get<float>(instance2, "InputDisableTimer") > 0f)
			{
				return;
			}
			Rigidbody rb = instance2.rb;
			if (Object.op_Implicit((Object)(object)rb) && !rb.isKinematic && !(((Vector3)(ref instance2.InputDirection)).sqrMagnitude <= 0.0001f))
			{
				Vector3 val = rb.linearVelocity;
				if (Native.Get<float>(instance2, "platformVelocityTimer") > 0f)
				{
					val -= Native.Get<Vector3>(instance2, "platformVelocity");
				}
				val.y = 0f;
				Vector3 val2 = ((Component)instance2).transform.TransformDirection(instance2.InputDirection);
				val2.y = 0f;
				bool moving = ((Vector3)(ref val)).sqrMagnitude > 0.0025f && ((Vector3)(ref val2)).sqrMagnitude > 0.0001f && Vector3.Dot(val, ((Vector3)(ref val2)).normalized) > 0.05f;
				rules.RecoverMovement(Time.deltaTime, moving, instance2.sprinting, laser != null && laser.IsFiring);
			}
		}

		private void Awake()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			Current = this;
			modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable Charger for host / single-player.");
			chargeKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "ChargeKey", new KeyboardShortcut((KeyCode)114, Array.Empty<KeyCode>()), "Hold together with LaserKey: held item = recharge, empty hands = eye laser. Release either key to stop.");
			laserKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "LaserKey", new KeyboardShortcut((KeyCode)101, Array.Empty<KeyCode>()), "Second key for both item recharge and eye laser; hold together with ChargeKey.");
			InitializeGamepad();
		}

		private void Start()
		{
			RoleMenu.Register("local.bei.hostcharger", "Charger", "20 main energy capacity; starts at 10 memories (50%) and is carried between stages. Walking restores 0.03%/s; running 0.08%/s. No full-charge stat bonuses. Native yellow eyes glow while any laser energy remains. Below 50/30/10%: movement 90/70/50% (no movement modifier in shops). With full main energy, walking/running fills the separate laser bar at 2/5% per second. Hold R + E: held item = recharge; empty hands = eye laser after 0.08s, up to 8 seconds per full laser bar. Truck recharge and tumble zap remain available.", 2, (Func<bool>)(() => Object.op_Implicit((Object)(object)this) && ((Behaviour)this).isActiveAndEnabled && modEnabled.Value), (Action<bool>)delegate(bool active)
			{
				if (!active)
				{
					StopAll();
				}
			});
		}

		private void RetireDragon()
		{
			if (!retiredDragon)
			{
				if (Chainloader.PluginInfos.TryGetValue("local.bei.hostdragonborn", out var value) && Object.op_Implicit((Object)(object)value.Instance))
				{
					((Behaviour)value.Instance).enabled = false;
				}
				RoleMenu.Unregister("local.bei.hostdragonborn");
				retiredDragon = true;
			}
		}

		private bool WorldReady()
		{
			if (Object.op_Implicit((Object)(object)GameManager.instance) && Object.op_Implicit((Object)(object)RunManager.instance) && !SemiFunc.MenuLevel() && SemiFunc.IsMasterClientOrSingleplayer() && Object.op_Implicit((Object)(object)LevelGenerator.Instance))
			{
				return LevelGenerator.Instance.Generated;
			}
			return false;
		}

		private bool ControlsReady()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Invalid comparison between Unknown and I4
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			PlayerAvatar instance = PlayerAvatar.instance;
			if (Object.op_Implicit((Object)(object)instance) && Object.op_Implicit((Object)(object)PlayerController.instance) && Object.op_Implicit((Object)(object)PhysGrabber.instance) && Object.op_Implicit((Object)(object)InputManager.instance) && !RoleMenu.InputBlocked && Object.op_Implicit((Object)(object)GameDirector.instance) && !GameDirector.instance.DisableInput && (int)GameDirector.instance.currentState == 2 && Time.timeScale > 0f && Native.Get<bool>(instance, "spawned") && !Native.Get<bool>(instance, "deadSet") && !Native.Get<bool>(instance, "isDisabled") && !Native.Get<bool>(instance, "isTumbling") && Native.Get<float>(PlayerController.instance, "InputDisableTimer") <= 0f && (!Object.op_Implicit((Object)(object)MenuManager.instance) || (int)Native.Get<MenuState>(MenuManager.instance, "currentMenuState") != 0) && (!Object.op_Implicit((Object)(object)ChatManager.instance) || !Native.Get<bool>(ChatManager.instance, "chatActive")) && (!Object.op_Implicit((Object)(object)instance.mapToolController) || !Native.Get<bool>(instance.mapToolController, "Active")))
			{
				return GUIUtility.keyboardControl == 0;
			}
			return false;
		}

		private static ItemBattery HeldBattery()
		{
			PhysGrabber instance = PhysGrabber.instance;
			PhysGrabObject val = ((Object.op_Implicit((Object)(object)instance) && instance.grabbed) ? Native.Get<PhysGrabObject>(instance, "grabbedPhysGrabObject") : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			return ((Component)val).GetComponent<ItemBattery>();
		}

		private void Update()
		{
			try
			{
				chargeBeam?.Render();
				TickZapEffects();
			}
			catch (Exception ex)
			{
				StopAll();
				((BaseUnityPlugin)this).Logger.LogError((object)("Charge beam stopped: " + ex));
			}
		}

		private void LateUpdate()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				gamepad?.Tick();
				RetireDragon();
				if (Object.op_Implicit((Object)(object)RunManager.instance) && SemiFunc.MenuLevel())
				{
					rules.ResetRun();
				}
				if (!WorldReady())
				{
					StopAll();
					stage = null;
					Harmony obj = harmony;
					if (obj != null)
					{
						obj.UnpatchSelf();
					}
					harmony = null;
					return;
				}
				Scene activeScene = SceneManager.GetActiveScene();
				int num = SceneHandle.op_Implicit(((Scene)(ref activeScene)).handle);
				if ((Object)(object)stage != (Object)(object)LevelGenerator.Instance || sceneHandle != num)
				{
					EnterLevel(num);
				}
				if (!modEnabled.Value || !RoleMenu.IsSelected("local.bei.hostcharger"))
				{
					if (lastSelected)
					{
						StopAll();
					}
					hudVisible = false;
					lastSelected = false;
					return;
				}
				if (!lastSelected)
				{
					input.Block();
				}
				lastSelected = true;
				if (harmony == null)
				{
					harmony = new Harmony("local.bei.hostcharger");
					try
					{
						harmony.PatchAll(typeof(Plugin).Assembly);
						GamepadControls.Install(harmony);
					}
					catch
					{
						harmony.UnpatchSelf();
						harmony = null;
						throw;
					}
				}
				bool flag = (hudVisible = ControlsReady());
				TickMovementRecovery(flag);
				ItemBattery val = (flag ? HeldBattery() : null);
				input.Step(flag, gamepad.Held(chargeKey.Value, gamepadCharge.Value), gamepad.Held(laserKey.Value, gamepadLaser.Value), flag && PhysGrabber.instance.grabbed, Object.op_Implicit((Object)(object)val) ? ((Object)val).GetInstanceID() : 0);
				if (!flag)
				{
					StopActivities();
					pressedBattery = null;
					TickLaserChargeEyes();
					return;
				}
				if (input.PressStarted)
				{
					pressedBattery = val;
				}
				if (!input.ChargeHeld || !Object.op_Implicit((Object)(object)val) || (Object)(object)val != (Object)(object)pressedBattery)
				{
					StopCharge();
				}
				if (input.PressStarted && input.ChargeHeld && Object.op_Implicit((Object)(object)val))
				{
					BeginCharge(val);
				}
				if (input.LaserHeld)
				{
					StopCharge();
					pressedBattery = null;
				}
				if (input.LaserHeld && (!rules.CanFireLaser || PhysGrabber.instance.grabbed))
				{
					input.Block();
				}
				if (input.LaserHeld && !PhysGrabber.instance.grabbed && rules.CanFireLaser && Time.unscaledTime >= retryAt)
				{
					if (laser == null)
					{
						LaserCarrier laserCarrier = new LaserCarrier(this);
						try
						{
							laserCarrier.Create();
							laser = laserCarrier;
						}
						catch
						{
							laserCarrier.Dispose();
							throw;
						}
					}
					laser.Place();
					if (laser.Ready && Time.deltaTime > 0f)
					{
						if (rules.SpendLaser(Time.deltaTime) > 0.0)
						{
							laser.Fire();
						}
						if (!rules.CanFireLaser)
						{
							input.Block();
							StopLaser();
						}
					}
				}
				else
				{
					StopLaser();
				}
				TickCharge(val);
				TickLaserChargeEyes();
			}
			catch (Exception ex)
			{
				StopAll();
				retryAt = Time.unscaledTime + 5f;
				if (Time.unscaledTime >= nextError)
				{
					nextError = Time.unscaledTime + 10f;
					((BaseUnityPlugin)this).Logger.LogError((object)("Charger stopped: " + ex));
				}
			}
		}

		private void StopLaser()
		{
			LaserCarrier laserCarrier = laser;
			laser = null;
			laserCarrier?.Dispose();
		}

		private void EnterLevel(int scene)
		{
			StopAll();
			stage = LevelGenerator.Instance;
			sceneHandle = scene;
			retryAt = 0f;
		}

		private void StopActivities()
		{
			try
			{
				StopLaser();
			}
			finally
			{
				StopCharge();
			}
		}

		private void StopAll()
		{
			StopZapEffects();
			try
			{
				StopActivities();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Cleanup: " + ex.Message));
			}
			pressedBattery = null;
			input.Block();
			hudVisible = false;
			lastSelected = false;
		}

		internal void Detail(string s)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[Charger] " + s));
		}

		internal void Warn(string s)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("[Charger] " + s));
		}

		internal static bool Owns(Component c)
		{
			if (Object.op_Implicit((Object)(object)Current))
			{
				if ((Current.laser == null || !Current.laser.Contains(c)) && (Current.chargeBeam == null || !Current.chargeBeam.Contains(c)))
				{
					return Current.OwnsZap(c);
				}
				return true;
			}
			return false;
		}

		private void OnDisable()
		{
			StopAll();
		}

		private void OnDestroy()
		{
			StopAll();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			RoleMenu.Unregister("local.bei.hostcharger");
			if ((Object)(object)Current == (Object)(object)this)
			{
				Current = null;
			}
		}

		private void BeginCharge(ItemBattery target)
		{
			ItemAttributes component = ((Component)target).GetComponent<ItemAttributes>();
			if (rules.Energy <= 0.0 || !SemiFunc.BatteryChargeCondition(target) || (Object.op_Implicit((Object)(object)component) && Native.Get<bool>(component, "shopItem")))
			{
				return;
			}
			if (droneBars < 1)
			{
				foreach (Item value in StatsManager.instance.itemDictionary.Values)
				{
					GameObject val = ((Object.op_Implicit((Object)(object)value) && value.prefab != null) ? ((PrefabRef<GameObject>)(object)value.prefab).Prefab : null);
					if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.GetComponent<ItemDroneBattery>()))
					{
						ItemBattery component2 = val.GetComponent<ItemBattery>();
						if (Object.op_Implicit((Object)(object)component2) && component2.batteryBars > 0)
						{
							droneBars = component2.batteryBars;
							break;
						}
					}
				}
				if (droneBars < 1)
				{
					throw new InvalidOperationException("Charge drone battery definition unavailable; no guessed transfer amount used.");
				}
				Detail("Charge drone bars=" + droneBars + "; returned percent per Charger memory=" + ChargerRules.ChargePercentPerMemory(droneBars));
			}
			chargePercent = ChargerRules.ChargePercentPerMemory(droneBars);
			ChargeBeam chargeBeam = new ChargeBeam(this, target);
			try
			{
				chargeBeam.Create();
				this.chargeBeam = chargeBeam;
			}
			catch
			{
				chargeBeam.Dispose();
				throw;
			}
			chargeTarget = target;
			charging = true;
			ownsChargingVisual = !Native.Get<bool>(target, "isCharging");
			if (ownsChargingVisual)
			{
				Native.Call(target, "BatteryChargeToggle", true);
			}
		}

		private void TickCharge(ItemBattery held)
		{
			if (!charging)
			{
				return;
			}
			if (!Object.op_Implicit((Object)(object)chargeTarget) || (Object)(object)held != (Object)(object)chargeTarget || chargeTarget.isUnchargable || chargeTarget.batteryLife >= 100f || rules.Energy <= 0.0)
			{
				StopCharge();
				return;
			}
			chargeBeam.Tick();
			if (!chargeBeam.Ready)
			{
				return;
			}
			if (!Native.Get<bool>(chargeTarget, "isCharging"))
			{
				ownsChargingVisual = true;
				Native.Call(chargeTarget, "BatteryChargeToggle", true);
			}
			double wanted = Math.Min((double)Time.deltaTime / 0.6, (double)(100f - chargeTarget.batteryLife) / chargePercent);
			double num = rules.Spend(wanted);
			if (!(num <= 0.0))
			{
				float num2 = Mathf.Clamp(chargeTarget.batteryLife + (float)(num * chargePercent), 0f, 100f);
				int num3 = Mathf.Clamp(Mathf.RoundToInt(num2 / (100f / (float)chargeTarget.batteryBars)), 0, chargeTarget.batteryBars);
				chargeTarget.batteryLife = num2;
				if (num3 != Native.Get<int>(chargeTarget, "batteryLifeInt"))
				{
					Native.Call(chargeTarget, "BatteryFullPercentChange", num3, true, true);
				}
				Native.Set(chargeTarget, "batteryLifeCountBarsPrev", num3);
				Native.Set(chargeTarget, "batteryLifeCountBars", num3);
				if (rules.Energy <= 0.0 || num2 >= 100f)
				{
					StopCharge();
					input.Block();
				}
			}
		}

		private void StopCharge()
		{
			ItemBattery val = chargeTarget;
			bool flag = ownsChargingVisual;
			chargeTarget = null;
			charging = false;
			ownsChargingVisual = false;
			ChargeBeam chargeBeam = this.chargeBeam;
			this.chargeBeam = null;
			try
			{
				chargeBeam?.Dispose();
			}
			finally
			{
				if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMasterClientOrSingleplayer())
				{
					if (flag && Native.Get<float>(val, "chargeTimer") <= 0f)
					{
						Native.Call(val, "BatteryChargeToggle", false);
					}
					ItemAttributes component = ((Component)val).GetComponent<ItemAttributes>();
					if (Object.op_Implicit((Object)(object)component) && !string.IsNullOrEmpty(Native.Get<string>(component, "instanceName")))
					{
						SemiFunc.StatSetBattery(Native.Get<string>(component, "instanceName"), Mathf.FloorToInt(val.batteryLife));
					}
				}
			}
		}

		private static bool ChargedRoleActive()
		{
			Plugin current = Current;
			PlayerAvatar instance = PlayerAvatar.instance;
			if (Object.op_Implicit((Object)(object)current) && ((Behaviour)current).isActiveAndEnabled && current.modEnabled.Value && current.RoleMenuSelected() && current.WorldReady() && Object.op_Implicit((Object)(object)instance) && Native.Get<bool>(instance, "spawned") && !Native.Get<bool>(instance, "deadSet"))
			{
				return !Native.Get<bool>(instance, "isDisabled");
			}
			return false;
		}

		private static float MovementScaleForRole(PlayerController player)
		{
			if (!Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)PlayerController.instance || !ChargedRoleActive() || SemiFunc.RunIsShop())
			{
				return 1f;
			}
			return (float)Current.rules.MovementMultiplier;
		}

		internal static float WalkSpeedForRole(PlayerController player)
		{
			return player.MoveSpeed * MovementScaleForRole(player);
		}

		internal static float SprintSpeedForRole(PlayerController player)
		{
			return player.SprintSpeed * MovementScaleForRole(player);
		}

		internal static float CrouchSpeedForRole(PlayerController player)
		{
			return player.CrouchSpeed * MovementScaleForRole(player);
		}

		private bool CanRechargeAt(ChargingStation station)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Invalid comparison between Unknown and I4
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			if (((Behaviour)this).isActiveAndEnabled && modEnabled.Value && RoleMenuSelected() && WorldReady() && !((Object)(object)stage != (Object)(object)LevelGenerator.Instance))
			{
				SceneHandle val = SceneHandle.op_Implicit(sceneHandle);
				Scene activeScene = SceneManager.GetActiveScene();
				if (!(val != ((Scene)(ref activeScene)).handle) && !(Time.deltaTime <= 0f) && !(Time.timeScale <= 0f) && Object.op_Implicit((Object)(object)GameDirector.instance) && (int)GameDirector.instance.currentState == 2 && !Native.Get<bool>(RunManager.instance, "restarting") && !SemiFunc.RunIsShop() && !Native.Get<bool>(RunManager.instance, "levelIsShop") && !(rules.Energy >= 20.0) && stationRecoveredFrame != Time.frameCount)
				{
					PlayerAvatar instance = PlayerAvatar.instance;
					if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)PlayerController.instance) || !Object.op_Implicit((Object)(object)PlayerController.instance.col) || !Native.Get<bool>(instance, "spawned") || Native.Get<bool>(instance, "deadSet") || Native.Get<bool>(instance, "isDisabled") || Native.Get<bool>(instance, "isTumbling"))
					{
						return false;
					}
					if (Native.Get<float>(station, "chargeFloat") <= 0f || Native.Get<int>(station, "chargeInt") <= 0)
					{
						return false;
					}
					Transform val2 = Native.Get<Transform>(station, "chargeArea");
					if (!Object.op_Implicit((Object)(object)val2))
					{
						return false;
					}
					Vector3 lossyScale = val2.lossyScale;
					Vector3 val3 = new Vector3(Mathf.Abs(lossyScale.x), Mathf.Abs(lossyScale.y), Mathf.Abs(lossyScale.z)) * 0.5f;
					Collider[] array = Physics.OverlapBox(val2.position, val3, val2.rotation, -1, (QueryTriggerInteraction)1);
					for (int i = 0; i < array.Length; i++)
					{
						if ((Object)(object)array[i] == (Object)(object)PlayerController.instance.col)
						{
							return true;
						}
					}
					return false;
				}
			}
			return false;
		}

		private bool RoleMenuSelected()
		{
			return RoleMenu.IsSelected("local.bei.hostcharger");
		}

		private void RechargeFromStation(ChargingStation station)
		{
			double stationEnergy = Native.Get<float>(station, "chargeFloat");
			if (rules.RecoverAtStation(Time.deltaTime, Native.Get<float>(station, "batteryChargeCost"), ref stationEnergy) <= 0.0)
			{
				return;
			}
			stationRecoveredFrame = Time.frameCount;
			stationRecovered = station;
			Native.Set(station, "chargeFloat", (float)stationEnergy);
			int num = Mathf.Clamp((int)(stationEnergy * 100.0), 0, 100);
			Native.Set(station, "chargeTotal", num);
			if (!Native.Get<bool>(station, "isCharging"))
			{
				Native.Call(station, "StartCharge");
			}
			Native.Call(station, "CrystalsItShouldHave");
			if (Object.op_Implicit((Object)(object)StatsManager.instance))
			{
				StatsManager.instance.runStats["chargingStationCharge"] = Native.Get<int>(station, "chargeInt");
				StatsManager.instance.runStats["chargingStationChargeTotal"] = num;
			}
			int num2 = Native.Get<int>(station, "chargeSegments");
			int num3 = Mathf.CeilToInt((float)stationEnergy * (float)num2);
			Native.Set(station, "chargeSegmentCurrent", num3);
			if (Native.Get<int>(station, "lastSentSegment") != num3)
			{
				Native.Set(station, "lastSentSegment", num3);
				if (SemiFunc.IsMultiplayer())
				{
					PhotonView obj = Native.Get<PhotonView>(station, "photonView");
					PhotonNetwork.RemoveBufferedRPCs(obj.ViewID, "ChargingStationSegmentChangedRPC", (int[])null);
					obj.RPC("ChargingStationSegmentChangedRPC", (RpcTarget)4, new object[1] { (byte)num3 });
				}
			}
		}

		private void StationError(Exception e)
		{
			stationChecking = null;
			if (!(Time.unscaledTime < nextError))
			{
				nextError = Time.unscaledTime + 10f;
				((BaseUnityPlugin)this).Logger.LogError((object)("Truck recharge stopped: " + e));
			}
		}

		private bool IsChargerTumbleHit(HurtCollider hitbox)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			PlayerAvatar instance = PlayerAvatar.instance;
			PlayerTumble val = (Object.op_Implicit((Object)(object)instance) ? Native.Get<PlayerTumble>(instance, "tumble") : null);
			if (((Behaviour)this).isActiveAndEnabled && modEnabled.Value && RoleMenuSelected() && WorldReady() && (Object)(object)stage == (Object)(object)LevelGenerator.Instance)
			{
				SceneHandle val2 = SceneHandle.op_Implicit(sceneHandle);
				Scene activeScene = SceneManager.GetActiveScene();
				if (val2 == ((Scene)(ref activeScene)).handle && rules.CanTumbleZap && Object.op_Implicit((Object)(object)instance) && Object.op_Implicit((Object)(object)val) && (Object)(object)val.hurtCollider == (Object)(object)hitbox && hitbox.enemyLogic && ((Component)hitbox).gameObject.activeInHierarchy && Native.Get<bool>(instance, "isTumbling"))
				{
					return !Native.Get<bool>(instance, "deadSet");
				}
			}
			return false;
		}

		private void TumbleZap(Enemy enemy, HurtCollider hitbox)
		{
			//IL_0066: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)enemy))
			{
				return;
			}
			ProdzapEffect prodzapEffect = null;
			try
			{
				PrefabRef val = ProdzapEffect.FindPrefab();
				HurtCollider componentInChildren = ((PrefabRef<GameObject>)(object)val).Prefab.GetComponentInChildren<HurtCollider>(true);
				if (!Object.op_Implicit((Object)(object)componentInChildren) || !componentInChildren.enemyStun || componentInChildren.enemyStunTime <= 0f)
				{
					throw new InvalidOperationException("Prodzap stun settings unavailable.");
				}
				Vector3 point = (Object.op_Implicit((Object)(object)enemy.CenterTransform) ? enemy.CenterTransform.position : ((Component)enemy).transform.position);
				foreach (ProdzapEffect zapEffect in zapEffects)
				{
					if (zapEffect.Available)
					{
						prodzapEffect = zapEffect;
						break;
					}
				}
				if (prodzapEffect == null)
				{
					prodzapEffect = new ProdzapEffect();
					prodzapEffect.Create(val);
					zapEffects.Add(prodzapEffect);
				}
				prodzapEffect.Reserve(point);
				EnemyStateStunned val2 = Native.Get<EnemyStateStunned>(enemy, "StateStunned");
				if (Native.Get<bool>(enemy, "HasStateStunned") && Object.op_Implicit((Object)(object)val2) && enemy.Type <= componentInChildren.enemyStunType)
				{
					val2.Set(componentInChildren.enemyStunTime);
				}
			}
			catch
			{
				prodzapEffect?.Dispose();
				if (prodzapEffect != null)
				{
					zapEffects.Remove(prodzapEffect);
				}
				throw;
			}
		}

		private void TickZapEffects()
		{
			for (int num = zapEffects.Count - 1; num >= 0; num--)
			{
				ProdzapEffect prodzapEffect = zapEffects[num];
				try
				{
					if (prodzapEffect.Tick())
					{
						continue;
					}
				}
				catch (Exception e)
				{
					ZapError(e);
				}
				prodzapEffect.Dispose();
				zapEffects.RemoveAt(num);
			}
			if (!modEnabled.Value || !RoleMenuSelected() || !WorldReady() || (Object)(object)stage != (Object)(object)LevelGenerator.Instance || !rules.CanTumbleZap || Time.unscaledTime < zapPrepareRetry)
			{
				return;
			}
			foreach (ProdzapEffect zapEffect in zapEffects)
			{
				if (zapEffect.Available)
				{
					return;
				}
			}
			ProdzapEffect prodzapEffect2 = new ProdzapEffect();
			try
			{
				prodzapEffect2.Create(ProdzapEffect.FindPrefab());
				zapEffects.Add(prodzapEffect2);
			}
			catch (Exception e2)
			{
				prodzapEffect2.Dispose();
				zapPrepareRetry = Time.unscaledTime + 5f;
				ZapError(e2);
			}
		}

		private void StopZapEffects()
		{
			foreach (ProdzapEffect zapEffect in zapEffects)
			{
				try
				{
					zapEffect.Dispose();
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Prodzap cleanup: " + ex.Message));
				}
			}
			zapEffects.Clear();
		}

		private bool OwnsZap(Component c)
		{
			foreach (ProdzapEffect zapEffect in zapEffects)
			{
				if (zapEffect.Contains(c))
				{
					return true;
				}
			}
			return false;
		}

		private void ZapError(Exception e)
		{
			if (!(Time.unscaledTime < nextError))
			{
				nextError = Time.unscaledTime + 10f;
				((BaseUnityPlugin)this).Logger.LogError((object)("Prodzap tumble effect failed: " + e));
			}
		}
	}
	internal sealed class LaserCarrier : IDisposable
	{
		private const float Scale = 0.0001f;

		private readonly Plugin plugin;

		private GameObject root;

		private PhysGrabObject physics;

		private ItemGun gun;

		private ItemGunLaser nativeLaser;

		private PlayerEyes eyes;

		private PlayerAvatar player;

		private Vector3 muzzleOffset;

		private Quaternion muzzleRotation;

		private float createdAt;

		private float nextMove;

		private float nextNoise;

		private bool positioned;

		private bool firing;

		internal const float ActivationDelay = 0.08f;

		internal bool Ready
		{
			get
			{
				if (positioned && Object.op_Implicit((Object)(object)root))
				{
					return Time.time - createdAt >= 0.08f;
				}
				return false;
			}
		}

		internal bool IsFiring
		{
			get
			{
				if (firing)
				{
					return Object.op_Implicit((Object)(object)root);
				}
				return false;
			}
		}

		internal LaserCarrier(Plugin owner)
		{
			plugin = owner;
		}

		internal bool Contains(Component c)
		{
			if (Object.op_Implicit((Object)(object)c) && Object.op_Implicit((Object)(object)root))
			{
				if (!((Object)(object)c.gameObject == (Object)(object)root))
				{
					return c.transform.IsChildOf(root.transform);
				}
				return true;
			}
			return false;
		}

		private static PrefabRef FindPrefab()
		{
			foreach (Item value in StatsManager.instance.itemDictionary.Values)
			{
				if (Object.op_Implicit((Object)(object)value) && value.prefab != null && ((PrefabRef<GameObject>)(object)value.prefab).IsValid())
				{
					GameObject prefab = ((PrefabRef<GameObject>)(object)value.prefab).Prefab;
					if (Object.op_Implicit((Object)(object)prefab) && Object.op_Implicit((Object)(object)prefab.GetComponent<ItemGunLaser>()) && Object.op_Implicit((Object)(object)prefab.GetComponent<ItemGun>()) && Object.op_Implicit((Object)(object)prefab.GetComponent<PhysGrabObject>()) && !string.IsNullOrEmpty(((PrefabRef<GameObject>)(object)value.prefab).ResourcePath))
					{
						return value.prefab;
					}
				}
			}
			throw new InvalidOperationException("Native ItemGunLaser item prefab unavailable.");
		}

		internal void Create()
		{
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			player = PlayerAvatar.instance;
			eyes = (Object.op_Implicit((Object)(object)player.playerAvatarVisuals) ? player.playerAvatarVisuals.playerEyes : null);
			if (!Object.op_Implicit((Object)(object)eyes) || !Object.op_Implicit((Object)(object)eyes.pupilLeft) || !Object.op_Implicit((Object)(object)eyes.pupilRight) || !Object.op_Implicit((Object)(object)player.localCamera))
			{
				throw new InvalidOperationException("Laser eye anchors unavailable.");
			}
			PrefabRef val = FindPrefab();
			Relative(((PrefabRef<GameObject>)(object)val).Prefab.GetComponent<ItemGunLaser>().muzzleTransform, ((PrefabRef<GameObject>)(object)val).Prefab.transform, out muzzleOffset, out muzzleRotation, out var _);
			root = (SemiFunc.IsMultiplayer() ? PhotonNetwork.Instantiate(((PrefabRef<GameObject>)(object)val).ResourcePath, new Vector3(0f, 5000f, 0f), Quaternion.identity, (byte)0, new object[4] { 0.0001f, 0.0001f, 0.0001f, "local.bei.hostcharger" }) : Object.Instantiate<GameObject>(((PrefabRef<GameObject>)(object)val).Prefab, new Vector3(0f, 5000f, 0f), Quaternion.identity));
			if (!Object.op_Implicit((Object)(object)root))
			{
				throw new InvalidOperationException("Laser carrier failed to spawn.");
			}
			root.transform.localScale = Vector3.one * 0.0001f;
			physics = root.GetComponent<PhysGrabObject>();
			gun = root.GetComponent<ItemGun>();
			nativeLaser = root.GetComponent<ItemGunLaser>();
			MonoBehaviour[] components = root.GetComponents<MonoBehaviour>();
			foreach (MonoBehaviour val2 in components)
			{
				if (val2 is PhysGrabObject || val2 is PhysGrabObjectImpactDetector || val2 is ItemAttributes || val2 is ItemEquippable || val2 is ItemBattery || val2 is ItemToggle || val2 is ItemGun || val2 is ItemGunLaser || val2 is RoomVolumeCheck)
				{
					((Behaviour)val2).enabled = false;
					val2.StopAllCoroutines();
				}
			}
			Rigidbody component = root.GetComponent<Rigidbody>();
			component.isKinematic = true;
			component.useGravity = false;
			component.detectCollisions = false;
			Native.Set(physics, "isKinematic", true);
			Native.Set(physics, "lastPlayerGrabbing", player);
			Collider[] componentsInChildren = root.GetComponentsInChildren<Collider>(true);
			foreach (Collider val3 in componentsInChildren)
			{
				if (!Object.op_Implicit((Object)(object)((Component)val3).GetComponentInParent<HurtCollider>()))
				{
					val3.enabled = false;
				}
			}
			HurtCollider[] componentsInChildren2 = root.GetComponentsInChildren<HurtCollider>(true);
			foreach (HurtCollider val4 in componentsInChildren2)
			{
				if (!val4.ignorePlayers.Contains(player))
				{
					val4.ignorePlayers.Add(player);
				}
				if (!val4.ignoreObjects.Contains(physics))
				{
					val4.ignoreObjects.Add(physics);
				}
				Native.Set(val4, "playerCausingHurt", player);
				Native.Set(val4, "playerCausingHurtOverride", player);
			}
			RestoreHitboxScale();
			Native.Call(gun, "Start");
			Native.Call(nativeLaser, "Start");
			createdAt = Time.time;
			plugin.Detail("Laser carrier=" + ((PrefabRef<GameObject>)(object)val).ResourcePath + "; range=" + gun.gunRange + "; scale=" + 0.0001f);
		}

		private void RestoreHitboxScale()
		{
			//IL_0059: 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_0079: 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)
			Transform hurtColliderRotation = nativeLaser.semiLaser.hurtColliderRotation;
			if (!Object.op_Implicit((Object)(object)hurtColliderRotation) || !hurtColliderRotation.IsChildOf(root.transform) || ((Component)hurtColliderRotation).GetComponentsInChildren<HurtCollider>(true).Length != 1 || ((Component)hurtColliderRotation).GetComponentsInChildren<Renderer>(true).Length != 0 || ((Component)hurtColliderRotation).GetComponentsInChildren<Light>(true).Length != 0)
			{
				throw new InvalidOperationException("Laser damage branch is not an isolated invisible hitbox; no visual-scale fallback.");
			}
			hurtColliderRotation.localScale /= 0.0001f;
			plugin.Detail("Laser hitbox restored: world scale=" + ((object)hurtColliderRotation.lossyScale/*cast due to .constrained prefix*/).ToString() + "; native thickness=" + nativeLaser.semiLaser.hurtColliderBeamThickness);
		}

		internal void Place()
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)root) || !Object.op_Implicit((Object)(object)eyes) || !Object.op_Implicit((Object)(object)eyes.pupilLeft) || !Object.op_Implicit((Object)(object)eyes.pupilRight) || !Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)player.localCamera))
			{
				throw new InvalidOperationException("Laser carrier/eye anchors lost.");
			}
			Transform overrideTransform = player.localCamera.GetOverrideTransform();
			Vector3 val = (eyes.pupilLeft.position + eyes.pupilRight.position) * 0.5f + overrideTransform.forward * 0.08f;
			Vector3 position = overrideTransform.position;
			Vector3 val2 = val - position;
			RaycastHit val3 = default(RaycastHit);
			if (((Vector3)(ref val2)).sqrMagnitude > 1E-06f && Physics.Raycast(position, ((Vector3)(ref val2)).normalized, ref val3, ((Vector3)(ref val2)).magnitude, LayerMask.op_Implicit(SemiFunc.LayerMaskGetVisionObstruct())))
			{
				val = ((RaycastHit)(ref val3)).point - ((Vector3)(ref val2)).normalized * 0.03f;
			}
			Quaternion val4 = overrideTransform.rotation * Quaternion.Inverse(muzzleRotation);
			Vector3 val5 = val - val4 * (muzzleOffset * 0.0001f);
			physics.SetPositionLogic(val5, val4);
			if (Time.unscaledTime >= nextMove)
			{
				nextMove = Time.unscaledTime + 0.05f;
				if (SemiFunc.IsMultiplayer())
				{
					root.GetComponent<PhotonView>().RPC("SetPositionRPC", (RpcTarget)1, new object[2] { val5, val4 });
				}
			}
			positioned = true;
		}

		internal void Fire()
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			if (!Ready)
			{
				return;
			}
			if (!firing)
			{
				firing = true;
				Native.Call(nativeLaser, "OnStateShootStart");
				if (SemiFunc.IsMultiplayer())
				{
					root.GetComponent<PhotonView>().RPC("StateSetRPC", (RpcTarget)1, new object[1] { 3 });
				}
			}
			Native.Call(nativeLaser, "LaserShooting");
			Native.Call(nativeLaser, "Update");
			if (Time.time >= nextNoise && Object.op_Implicit((Object)(object)EnemyDirector.instance))
			{
				nextNoise = Time.time + 0.5f;
				EnemyDirector.instance.SetInvestigate(nativeLaser.muzzleTransform.position, gun.investigateRadius, false);
			}
		}

		public void Dispose()
		{
			GameObject val = root;
			root = null;
			positioned = (firing = false);
			if (Object.op_Implicit((Object)(object)val))
			{
				HurtCollider[] componentsInChildren = val.GetComponentsInChildren<HurtCollider>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					((Component)componentsInChildren[i]).gameObject.SetActive(false);
				}
				PhotonView component = val.GetComponent<PhotonView>();
				if (Object.op_Implicit((Object)(object)component) && component.ViewID > 0 && PhotonNetwork.InRoom && component.IsMine)
				{
					PhotonNetwork.Destroy(val);
				}
				else
				{
					Object.Destroy((Object)(object)val);
				}
			}
		}

		private static void Relative(Transform part, Transform root, out Vector3 position, out Quaternion rotation, out Vector3 size)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_0064: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			Matrix4x4 val = Matrix4x4.identity;
			rotation = Quaternion.identity;
			size = Vector3.one;
			Transform val2 = part;
			while ((Object)(object)val2 != (Object)(object)root)
			{
				if (!Object.op_Implicit((Object)(object)val2))
				{
					throw new InvalidOperationException("Laser is not a prefab child.");
				}
				val = Matrix4x4.TRS(val2.localPosition, val2.localRotation, val2.localScale) * val;
				rotation = val2.localRotation * rotation;
				size = Vector3.Scale(size, val2.localScale);
				val2 = val2.parent;
			}
			position = ((Matrix4x4)(ref val)).MultiplyPoint3x4(Vector3.zero);
		}
	}
	internal sealed class ProdzapEffect : IDisposable
	{
		private const float Scale = 0.0001f;

		private GameObject root;

		private ItemMelee melee;

		private PhysGrabObject physics;

		private float createdAt;

		private float playedAt;

		private float lifetime;

		private float warmup;

		private bool played;

		private bool reserved;

		private Vector3 impactPoint;

		internal bool Available
		{
			get
			{
				if (Object.op_Implicit((Object)(object)root))
				{
					return !reserved;
				}
				return false;
			}
		}

		internal static PrefabRef FindPrefab()
		{
			foreach (Item value in StatsManager.instance.itemDictionary.Values)
			{
				if (Object.op_Implicit((Object)(object)value) && value.prefab != null && ((PrefabRef<GameObject>)(object)value.prefab).IsValid())
				{
					GameObject prefab = ((PrefabRef<GameObject>)(object)value.prefab).Prefab;
					if (Object.op_Implicit((Object)(object)prefab) && Object.op_Implicit((Object)(object)prefab.GetComponent<ItemStunBaton>()) && Object.op_Implicit((Object)(object)prefab.GetComponent<ItemMelee>()) && Object.op_Implicit((Object)(object)prefab.GetComponent<PhysGrabObject>()) && !string.IsNullOrEmpty(((PrefabRef<GameObject>)(object)value.prefab).ResourcePath))
					{
						return value.prefab;
					}
				}
			}
			throw new InvalidOperationException("Native Prodzap prefab unavailable; no local-only substitute.");
		}

		internal void Create(PrefabRef source)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Invalid comparison between Unknown and I4
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: 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)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: 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)
			ItemStunBaton component = ((PrefabRef<GameObject>)(object)source).Prefab.GetComponent<ItemStunBaton>();
			ItemMelee component2 = ((PrefabRef<GameObject>)(object)source).Prefab.GetComponent<ItemMelee>();
			bool flag = false;
			for (int i = 0; i < ((UnityEventBase)component2.onHit).GetPersistentEventCount(); i++)
			{
				if (((UnityEventBase)component2.onHit).GetPersistentTarget(i) == (Object)(object)component && ((UnityEventBase)component2.onHit).GetPersistentMethodName(i) == "PlayParticles")
				{
					flag = true;
				}
			}
			if (!flag || !Object.op_Implicit((Object)(object)component.stunBatonEffects))
			{
				throw new InvalidOperationException("Prodzap native hit-to-particle route unavailable.");
			}
			ParticleSystem[] componentsInChildren = ((Component)component.stunBatonEffects).GetComponentsInChildren<ParticleSystem>(true);
			if (componentsInChildren.Length == 0)
			{
				throw new InvalidOperationException("Prodzap has no native electric particles.");
			}
			lifetime = 1f;
			warmup = 0.4f;
			ParticleSystem[] array = componentsInChildren;
			for (int j = 0; j < array.Length; j++)
			{
				MainModule main = array[j].main;
				if ((int)((MainModule)(ref main)).scalingMode != 1 || ((MainModule)(ref main)).loop)
				{
					throw new InvalidOperationException("Prodzap particles cannot preserve native size/lifetime on all peers.");
				}
				float num = lifetime;
				float duration = ((MainModule)(ref main)).duration;
				MinMaxCurve val = ((MainModule)(ref main)).startLifetime;
				float num2 = duration + ((MinMaxCurve)(ref val)).constantMax;
				val = ((MainModule)(ref main)).startDelay;
				lifetime = Mathf.Max(num, num2 + ((MinMaxCurve)(ref val)).constantMax);
				float num3 = warmup;
				float duration2 = ((MainModule)(ref main)).duration;
				val = ((MainModule)(ref main)).startLifetime;
				float num4 = duration2 + ((MinMaxCurve)(ref val)).constantMax;
				val = ((MainModule)(ref main)).startDelay;
				warmup = Mathf.Max(num3, num4 + ((MinMaxCurve)(ref val)).constantMax + 0.1f);
			}
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(0f, 5000f, 0f);
			root = (SemiFunc.IsMultiplayer() ? PhotonNetwork.Instantiate(((PrefabRef<GameObject>)(object)source).ResourcePath, val2, Quaternion.identity, (byte)0, new object[4] { 0.0001f, 0.0001f, 0.0001f, "local.bei.hostcharger" }) : Object.Instantiate<GameObject>(((PrefabRef<GameObject>)(object)source).Prefab, val2, Quaternion.identity));
			if (!Object.op_Implicit((Object)(object)root))
			{
				throw new InvalidOperationException("Prodzap effect carrier failed to spawn.");
			}
			root.transform.localScale = Vector3.one * 0.0001f;
			physics = root.GetComponent<PhysGrabObject>();
			melee = root.GetComponent<ItemMelee>();
			ItemStunBaton component3 = root.GetComponent<ItemStunBaton>();
			MonoBehaviour[] components = root.GetComponents<MonoBehaviour>();
			foreach (MonoBehaviour val3 in components)
			{
				if (val3 is PhysGrabObject || val3 is PhysGrabObjectImpactDetector || val3 is ItemAttributes || val3 is ItemEquippable || val3 is ItemBattery || val3 is ItemMelee || val3 is ItemStunBaton || val3 is RoomVolumeCheck)
				{
					((Behaviour)val3).enabled = false;
					val3.StopAllCoroutines();
				}
			}
			Rigidbody component4 = root.GetComponent<Rigidbody>();
			component4.isKinematic = true;
			component4.useGravity = false;
			component4.detectCollisions = false;
			Native.Set(physics, "isKinematic", true);
			Native.Call(melee, "Start");
			Native.Call(component3, "Start");
			melee.usesBatteryLogic = false;
			HurtCollider[] componentsInChildren2 = root.GetComponentsInChildren<HurtCollider>(true);
			foreach (HurtCollider obj in componentsInChildren2)
			{
				((Behaviour)obj).enabled = false;
				((MonoBehaviour)obj).StopAllCoroutines();
				((Component)obj).gameObject.SetActive(false);
			}
			Collider[] componentsInChildren3 = root.GetComponentsInChildren<Collider>(true);
			for (int j = 0; j < componentsInChildren3.Length; j++)
			{
				componentsInChildren3[j].enabled = false;
			}
			createdAt = Time.time;
		}

		internal bool Tick()
		{
			//IL_003f: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)root))
			{
				return false;
			}
			if (!reserved)
			{
				return true;
			}
			if (!played && Time.time - createdAt >= warmup)
			{
				physics.SetPositionLogic(impactPoint, Quaternion.identity);
				if (SemiFunc.IsMultiplayer())
				{
					root.GetComponent<PhotonView>().RPC("SetPositionRPC", (RpcTarget)1, new object[2]
					{
						impactPoint,
						Quaternion.identity
					});
				}
				Native.Call(melee, "SwingHit");
				played = true;
				playedAt = Time.time;
			}
			if (played)
			{
				return Time.time - playedAt < lifetime;
			}
			return true;
		}

		internal void Reserve(Vector3 point)
		{
			//IL_001b: 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)
			if (!Available)
			{
				throw new InvalidOperationException("Prodzap carrier is already in use.");
			}
			reserved = true;
			impactPoint = point;
		}

		internal bool Contains(Component c)
		{
			if (Object.op_Implicit((Object)(object)root) && Object.op_Implicit((Object)(object)c))
			{
				if (!((Object)(object)c.gameObject == (Object)(object)root))
				{
					return c.transform.IsChildOf(root.transform);
				}
				return true;
			}
			return false;
		}

		public void Dispose()
		{
			if (Object.op_Implicit((Object)(object)root))
			{
				GameObject val = root;
				root = null;
				if (SemiFunc.IsMultiplayer())
				{
					PhotonNetwork.Destroy(val);
				}
				else
				{
					Object.Destroy((Object)(object)val);
				}
			}
		}
	}
	internal static class Native
	{
		internal const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		internal static FieldInfo Field(Type type, string name)
		{
			return type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingFieldException(type.FullName, name);
		}

		internal static T Get<T>(object target, string name)
		{
			return (T)Field(target.GetType(), name).GetValue(target);
		}

		internal static void Set(object target, string name, object value)
		{
			Field(target.GetType(), name).SetValue(target, value);
		}

		internal static void Call(object target, string name, params object[] args)
		{
			MethodInfo? method = target.GetType().GetMethod(name, BindingFlags.Instance | BindingFlags.Static

BepInEx/plugins/HostRoleSeries/HostRoleSelector.dll

Decompiled 8 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace HostRoleSeries;

[BepInPlugin("local.bei.hostroleselector", "Host Role Selector", "1.0.0")]
public sealed class RoleMenu : BaseUnityPlugin
{
	public const string PluginId = "local.bei.hostroleselector";

	private static RoleMenu instance;

	private readonly RoleRegistry roles = new RoleRegistry();

	private ConfigEntry<KeyboardShortcut> menuKey;

	private ConfigEntry<string> preferred;

	private readonly List<InputKey> blockInputs = new List<InputKey>();

	private bool open;

	private bool initialized;

	private int highlighted;

	private string pending;

	private string notice = "";

	private float noticeUntil;

	private GUIStyle title;

	private GUIStyle text;

	private GUIStyle small;

	private GUIStyle button;

	private Texture2D pointer;

	private static readonly FieldInfo dead = typeof(PlayerAvatar).GetField("deadSet", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo spawned = typeof(PlayerAvatar).GetField("spawned", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo chat = typeof(ChatManager).GetField("chatActive", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo menuState = typeof(MenuManager).GetField("currentMenuState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	public static bool InputBlocked
	{
		get
		{
			if (Object.op_Implicit((Object)(object)instance))
			{
				return instance.open;
			}
			return false;
		}
	}

	private void Awake()
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		menuKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "RoleMenuKey", new KeyboardShortcut((KeyCode)286, Array.Empty<KeyCode>()), "Open the shared host-role menu. Arrows: select; Enter: apply; Escape: cancel.");
		preferred = ((BaseUnityPlugin)this).Config.Bind<string>("Selection", "SelectedRole", "", "Last selected role ID, or none. Empty selects the first installed enabled role on startup.");
		instance = this;
	}

	public static void Register(string id, string name, string description, int order, Func<bool> available, Action<bool> apply)
	{
		if (!Object.op_Implicit((Object)(object)instance))
		{
			throw new InvalidOperationException("Host Role Selector is not loaded.");
		}
		instance.roles.Register(new RoleEntry(id, name, description, order, available, apply));
	}

	public static void Unregister(string id)
	{
		if (Object.op_Implicit((Object)(object)instance))
		{
			instance.roles.Remove(id);
		}
	}

	public static bool IsSelected(string id)
	{
		if (Object.op_Implicit((Object)(object)instance) && ((Behaviour)instance).isActiveAndEnabled && WorldReady())
		{
			return instance.roles.ActiveId == id;
		}
		return false;
	}

	private static bool WorldReady()
	{
		if (Object.op_Implicit((Object)(object)GameManager.instance) && Object.op_Implicit((Object)(object)RunManager.instance) && SemiFunc.IsMasterClientOrSingleplayer() && !SemiFunc.MenuLevel() && (Object)(object)LevelGenerator.Instance != (Object)null)
		{
			return LevelGenerator.Instance.Generated;
		}
		return false;
	}

	private static bool MenuReady()
	{
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Invalid comparison between Unknown and I4
		PlayerAvatar val = PlayerAvatar.instance;
		if (WorldReady() && Object.op_Implicit((Object)(object)val) && dead != null && spawned != null && (bool)spawned.GetValue(val) && !(bool)dead.GetValue(val) && Object.op_Implicit((Object)(object)GameDirector.instance) && (int)GameDirector.instance.currentState == 2 && (!Object.op_Implicit((Object)(object)ChatManager.instance) || chat == null || !(bool)chat.GetValue(ChatManager.instance)))
		{
			if (Object.op_Implicit((Object)(object)MenuManager.instance) && !(menuState == null))
			{
				return (int)menuState.GetValue(MenuManager.instance) != 0;
			}
			return true;
		}
		return false;
	}

	private bool MenuPressed()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: 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_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		KeyboardShortcut value = menuKey.Value;
		if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !UnityInput.Current.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey))
		{
			return false;
		}
		foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
		{
			if (!UnityInput.Current.GetKey(modifier))
			{
				return false;
			}
		}
		return true;
	}

	private void Update()
	{
		try
		{
			if (!WorldReady())
			{
				open = false;
				pending = null;
				roles.Select("none");
				initialized = false;
				return;
			}
			if (!initialized)
			{
				roles.Select(roles.Initial(preferred.Value));
				initialized = true;
			}
			roles.Validate();
			if (!MenuReady())
			{
				open = false;
				pending = null;
				return;
			}
			RoleEntry[] entries = roles.Entries;
			if (MenuPressed())
			{
				open = !open;
				pending = null;
				highlighted = Array.FindIndex(entries, (RoleEntry e) => e.Id == roles.ActiveId) + 1;
			}
			if (!open)
			{
				return;
			}
			if (UnityInput.Current.GetKeyDown((KeyCode)27))
			{
				open = false;
				pending = null;
				return;
			}
			if (Object.op_Implicit((Object)(object)CursorManager.instance))
			{
				SemiFunc.CursorUnlock(0.1f);
			}
			if (Object.op_Implicit((Object)(object)CameraAim.Instance))
			{
				CameraAim.Instance.OverrideAimStop();
			}
			if (Object.op_Implicit((Object)(object)InputManager.instance))
			{
				InputManager.instance.DisableControlsExcept(0.1f, blockInputs);
			}
			int num = entries.Length + 1;
			highlighted = Mathf.Clamp(highlighted, 0, num - 1);
			if (UnityInput.Current.GetKeyDown((KeyCode)276) || UnityInput.Current.GetKeyDown((KeyCode)273))
			{
				highlighted = (highlighted + num - 1) % num;
			}
			if (UnityInput.Current.GetKeyDown((KeyCode)275) || UnityInput.Current.GetKeyDown((KeyCode)274))
			{
				highlighted = (highlighted + 1) % num;
			}
			if (UnityInput.Current.GetKeyDown((KeyCode)8))
			{
				pending = "none";
			}
			if (UnityInput.Current.GetKeyDown((KeyCode)13))
			{
				pending = ((highlighted == 0) ? "none" : entries[highlighted - 1].Id);
			}
			if (pending == null)
			{
				return;
			}
			string requested = pending;
			pending = null;
			if (!roles.Select(requested))
			{
				notice = "This role is disabled in its config.";
				return;
			}
			preferred.Value = requested;
			if (!((BaseUnityPlugin)this).Config.SaveOnConfigSet)
			{
				((BaseUnityPlugin)this).Config.Save();
			}
			notice = "Role: " + ((requested == "none") ? "NONE" : Array.Find(entries, (RoleEntry e) => e.Id == requested).Name);
			noticeUntil = Time.unscaledTime + 4f;
			open = false;
		}
		catch (Exception ex)
		{
			open = false;
			pending = null;
			((BaseUnityPlugin)this).Logger.LogError((object)("Role selection failed: " + ex));
		}
	}

	private static void Fill(Rect rect, Color color)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		Color color2 = GUI.color;
		GUI.color = color;
		GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture);
		GUI.color = color2;
	}

	private void OnGUI()
	{
		//IL_0532: Unknown result type (might be due to invalid IL or missing references)
		//IL_0538: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Expected O, but got Unknown
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: 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_0073: Expected O, but got Unknown
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Expected O, but got Unknown
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Expected O, but got Unknown
		//IL_00c1: Expected O, but got Unknown
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0217: Unknown result type (might be due to invalid IL or missing references)
		//IL_022f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0267: Unknown result type (might be due to invalid IL or missing references)
		//IL_0296: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_044b: Unknown result type (might be due to invalid IL or missing references)
		//IL_049c: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0507: Unknown result type (might be due to invalid IL or missing references)
		//IL_050c: Unknown result type (might be due to invalid IL or missing references)
		//IL_038e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0367: Unknown result type (might be due to invalid IL or missing references)
		//IL_037b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0552: Unknown result type (might be due to invalid IL or missing references)
		//IL_0558: Invalid comparison between Unknown and I4
		if (!MenuReady())
		{
			return;
		}
		if (this.text == null)
		{
			this.text = new GUIStyle(GUI.skin.label)
			{
				fontSize = 19,
				wordWrap = true,
				richText = false
			};
			this.text.normal.textColor = Color.white;
			title = new GUIStyle(this.text)
			{
				fontSize = 26,
				fontStyle = (FontStyle)1
			};
			small = new GUIStyle(this.text)
			{
				fontSize = 15
			};
			button = new GUIStyle(GUI.skin.button)
			{
				fontSize = 20,
				alignment = (TextAnchor)3,
				padding = new RectOffset(18, 12, 8, 8)
			};
		}
		if (!open)
		{
			if (Time.unscaledTime < noticeUntil)
			{
				Fill(new Rect(22f, 22f, 460f, 55f), new Color(0.08f, 0.1f, 0.14f, 0.95f));
				GUI.Label(new Rect(34f, 33f, 438f, 35f), notice, this.text);
			}
			return;
		}
		Matrix4x4 matrix = GUI.matrix;
		Color color = GUI.color;
		bool enabled = GUI.enabled;
		try
		{
			RoleEntry[] entries = roles.Entries;
			highlighted = Mathf.Clamp(highlighted, 0, entries.Length);
			float num = 230 + 62 * (entries.Length + 1);
			float num2 = Mathf.Min(1.1f, Mathf.Min((float)Screen.width / 820f, (float)Screen.height / (num + 60f)));
			GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one * num2);
			float num3 = ((float)Screen.width / num2 - 760f) / 2f;
			float num4 = ((float)Screen.height / num2 - num) / 2f;
			Fill(new Rect(num3, num4, 760f, num), new Color(0.1f, 0.12f, 0.16f, 0.98f));
			Fill(new Rect(num3, num4, 760f, 58f), new Color(0.12f, 0.32f, 0.55f));
			GUI.Label(new Rect(num3 + 22f, num4 + 14f, 660f, 40f), "HOST ROLES / SELECT YOUR ROLE", title);
			if (GUI.Button(new Rect(num3 + 702f, num4 + 12f, 40f, 34f), "X"))
			{
				open = false;
				pending = null;
			}
			Rect val = default(Rect);
			for (int i = 0; i <= entries.Length; i++)
			{
				string text = ((i == 0) ? "none" : entries[i - 1].Id);
				string text2 = ((i == 0) ? "NONE" : entries[i - 1].Name);
				bool flag = i == 0 || entries[i - 1].IsAvailable;
				((Rect)(ref val))..ctor(num3 + 22f, num4 + 76f + (float)(i * 62), 716f, 52f);
				if (highlighted == i)
				{
					Fill(new Rect(((Rect)(ref val)).x - 4f, ((Rect)(ref val)).y - 3f, ((Rect)(ref val)).width + 8f, ((Rect)(ref val)).height + 6f), new Color(0.23f, 0.57f, 0.95f));
				}
				GUI.enabled = enabled && flag;
				if (GUI.Button(val, text2 + ((text == roles.ActiveId) ? "   [ACTIVE]" : "") + (flag ? "" : "   [CFG OFF]"), button))
				{
					highlighted = i;
				}
			}
			GUI.enabled = enabled;
			float num5 = num4 + 76f + (float)((entries.Length + 1) * 62);
			string text3 = ((highlighted == 0) ? "No host-role abilities. Stored resources are kept." : entries[Mathf.Clamp(highlighted - 1, 0, entries.Length - 1)].Description);
			GUI.Label(new Rect(num3 + 24f, num5 + 4f, 712f, 52f), text3, small);
			GUI.enabled = enabled && (highlighted == 0 || entries[highlighted - 1].IsAvailable);
			if (GUI.Button(new Rect(num3 + 22f, num5 + 62f, 716f, 43f), "APPLY SELECTED ROLE", button))
			{
				pending = ((highlighted == 0) ? "none" : entries[highlighted - 1].Id);
			}
			GUI.enabled = enabled;
			GUI.Label(new Rect(num3 + 24f, num5 + 117f, 714f, 25f), "Arrows: select   Enter: apply   Backspace: none   " + ((object)menuKey.Value/*cast due to .constrained prefix*/).ToString() + " / Esc: close", small);
		}
		finally
		{
			GUI.matrix = matrix;
			GUI.color = color;
			GUI.enabled = enabled;
		}
		if (open && (int)Event.current.type == 7)
		{
			DrawPointer();
		}
	}

	private void DrawPointer()
	{
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: 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_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		//IL_004a: 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_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)pointer))
		{
			pointer = new Texture2D(20, 28, (TextureFormat)4, false);
			Color[] array = (Color[])(object)new Color[560];
			for (int i = 0; i < 28; i++)
			{
				for (int j = 0; j < 20; j++)
				{
					array[(27 - i) * 20 + j] = (((float)j <= (float)i * 0.6f) ? ((j > 1 && (float)j < (float)i * 0.6f - 2f) ? Color.white : Color.black) : Color.clear);
				}
			}
			pointer.SetPixels(array);
			pointer.Apply();
		}
		Vector3 mousePosition = Input.mousePosition;
		GUI.DrawTexture(new Rect(mousePosition.x, (float)Screen.height - mousePosition.y, 20f, 28f), (Texture)(object)pointer);
	}

	private void OnDisable()
	{
		open = false;
		pending = null;
		roles.Select("none");
		initialized = false;
	}

	private void OnDestroy()
	{
		try
		{
			roles.Select("none");
		}
		finally
		{
			if (Object.op_Implicit((Object)(object)pointer))
			{
				Object.Destroy((Object)(object)pointer);
			}
			if ((Object)(object)instance == (Object)(object)this)
			{
				instance = null;
			}
		}
	}
}
public sealed class RoleEntry
{
	public string Id { get; }

	public string Name { get; }

	public string Description { get; }

	internal int Order { get; }

	internal Func<bool> Available { get; }

	internal Action<bool> Apply { get; }

	public bool IsAvailable => Available();

	public RoleEntry(string id, string name, string description, int order, Func<bool> available, Action<bool> apply)
	{
		Id = id;
		Name = name;
		Description = description;
		Order = order;
		Available = available;
		Apply = apply;
	}
}
public sealed class RoleRegistry
{
	public const string None = "none";

	private readonly Dictionary<string, RoleEntry> entries = new Dictionary<string, RoleEntry>();

	public string ActiveId { get; private set; } = "none";

	public RoleEntry[] Entries => entries.Values.OrderBy((RoleEntry r) => r.Order).ThenBy<RoleEntry, string>((RoleEntry r) => r.Id, StringComparer.Ordinal).ToArray();

	public void Register(RoleEntry entry)
	{
		if (entry == null || string.IsNullOrWhiteSpace(entry.Id) || entry.Id == "none" || entries.ContainsKey(entry.Id))
		{
			throw new ArgumentException("Duplicate or invalid role registration.");
		}
		entries.Add(entry.Id, entry);
	}

	public bool Select(string id)
	{
		if (id == ActiveId)
		{
			return true;
		}
		RoleEntry value = null;
		if (id != "none" && (!entries.TryGetValue(id, out value) || !value.IsAvailable))
		{
			return false;
		}
		string activeId = ActiveId;
		ActiveId = "none";
		if (entries.TryGetValue(activeId, out var value2))
		{
			value2.Apply(obj: false);
		}
		if (value == null)
		{
			return true;
		}
		try
		{
			ActiveId = id;
			value.Apply(obj: true);
		}
		catch
		{
			ActiveId = "none";
			value.Apply(obj: false);
			throw;
		}
		return true;
	}

	public void Remove(string id)
	{
		if (ActiveId == id)
		{
			Select("none");
		}
		entries.Remove(id);
	}

	public string Initial(string preferred)
	{
		if (preferred == "none")
		{
			return "none";
		}
		if (preferred == null || !entries.TryGetValue(preferred, out var value))
		{
			return Entries.FirstOrDefault((RoleEntry e) => e.IsAvailable)?.Id ?? "none";
		}
		if (!value.IsAvailable)
		{
			return "none";
		}
		return preferred;
	}

	public void Validate()
	{
		if (entries.TryGetValue(ActiveId, out var value) && !value.IsAvailable)
		{
			Select("none");
		}
	}
}