Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of HostCharger v0.2.5
BepInEx/plugins/HostCharger/HostCharger.dll
Decompiled 8 hours ago
The result has been truncated due to the large size, download it to view full contents!
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 agousing 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"); } } }