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 BasedSpectateMode v0.0.1
BasedSpectateMode.dll
Decompiled 6 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BasedSpectate.Behaviours; using BasedSpectate.Compat; using BasedSpectate.Patches; using BasedSpectate.Utils; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using DunGen; using GameNetcodeStuff; using HarmonyLib; using LethalCompanyInputUtils.Api; using LethalCompanyInputUtils.BindingPathEnums; using LethalConfig; using LethalConfig.ConfigItems; using LethalConfig.ConfigItems.Options; using Microsoft.CodeAnalysis; using TMPro; using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Utilities; using UnityEngine.Rendering.HighDefinition; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("BasedSpectateMode")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.0.1.0")] [assembly: AssemblyInformationalVersion("0.0.1")] [assembly: AssemblyProduct("BasedSpectateMode")] [assembly: AssemblyTitle("BasedSpectateMode")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 BasedSpectate { internal enum SpectateMode { Vanilla, Freecam } internal static class Config { internal static ConfigEntry<SpectateMode> StartMode { get; private set; } internal static ConfigEntry<bool> EnableModeToggle { get; private set; } internal static ConfigEntry<bool> ShowNextPlayerHint { get; private set; } internal static ConfigEntry<bool> ShowToggleModeHint { get; private set; } internal static ConfigEntry<bool> ShowCameraInfoHint { get; private set; } internal static ConfigEntry<float> DefaultZoomDistance { get; private set; } internal static ConfigEntry<float> MinZoomDistance { get; private set; } internal static ConfigEntry<float> MaxZoomDistance { get; private set; } internal static ConfigEntry<float> ZoomSpeed { get; private set; } internal static ConfigEntry<bool> CameraClipsThroughWalls { get; private set; } internal static void Bind(ConfigFile config) { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Expected O, but got Unknown StartMode = config.Bind<SpectateMode>("General", "Start spectate mode", SpectateMode.Vanilla, "Choose which spectate mode you start with after you die"); EnableModeToggle = config.Bind<bool>("General", "Enable mode toggle", true, "Allow switching spectate mode while dead"); ShowNextPlayerHint = config.Bind<bool>("General", "Show next player hint", true, "Show the Next Player line on the death screen"); ShowToggleModeHint = config.Bind<bool>("General", "Show toggle mode hint", true, "Show the Toggle Mode line on the death screen"); ShowCameraInfoHint = config.Bind<bool>("General", "Show camera info hint", true, "Show the Brightness or Zoom line on the death screen"); DefaultZoomDistance = config.Bind<float>("Zoom", "Default zoom distance", 1.4f, new ConfigDescription("Starting zoom distance when spectating resets", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 50f), Array.Empty<object>())); MinZoomDistance = config.Bind<float>("Zoom", "Minimum zoom distance", 1f, new ConfigDescription("Closest the spectate camera can zoom in", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 50f), Array.Empty<object>())); MaxZoomDistance = config.Bind<float>("Zoom", "Maximum zoom distance", 15f, new ConfigDescription("Furthest the spectate camera can zoom out", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 50f), Array.Empty<object>())); ZoomSpeed = config.Bind<float>("Zoom", "Zoom speed", 0.4f, new ConfigDescription("How fast the mouse wheel zooms the camera", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); CameraClipsThroughWalls = config.Bind<bool>("Zoom", "Camera clips through walls", false, "Let the spectate camera pass through walls instead of stopping at them"); DefaultZoomDistance.SettingChanged += delegate { SpectateModePatches.ResetZoomDistance(); }; } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("MrHat.BasedSpectateMode", "BasedSpectateMode", "0.0.1")] internal class Plugin : BaseUnityPlugin { private const string LethalConfigGUID = "ainavt.lc.lethalconfig"; private const string CullFactoryGUID = "com.fumiko.CullFactory"; private const string LethalCompanyInputUtilsGUID = "com.rune580.LethalCompanyInputUtils"; internal const string modGUID = "MrHat.BasedSpectateMode"; internal const string modName = "BasedSpectateMode"; internal const string modVersion = "0.0.1"; internal static ManualLogSource mls; private readonly Harmony _harmony = new Harmony("MrHat.BasedSpectateMode"); internal static Plugin Instance { get; private set; } internal static SpectateMode CurrentMode { get; set; } private static bool hasLethalConfig => Chainloader.PluginInfos.ContainsKey("ainavt.lc.lethalconfig"); private static bool hasCullFactory => Chainloader.PluginInfos.ContainsKey("com.fumiko.CullFactory"); private void Awake() { Instance = this; mls = Logger.CreateLogSource("MrHat.BasedSpectateMode"); Config.Bind(((BaseUnityPlugin)this).Config); CurrentMode = Config.StartMode.Value; SpectateInputActions.Initialise(); if (hasLethalConfig) { LethalConfigCompat.Register(); mls.LogInfo((object)"LethalConfig compatibility ran"); } if (hasCullFactory) { mls.LogInfo((object)"CullFactory compatibility ran"); } else { _harmony.PatchAll(typeof(DisableVanillaCullingPatches)); } mls.LogDebug((object)"BasedSpectateMode patches running..."); _harmony.PatchAll(typeof(SpectateModePatches)); mls.LogInfo((object)"BasedSpectateMode loaded"); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "BasedSpectateMode"; public const string PLUGIN_NAME = "BasedSpectateMode"; public const string PLUGIN_VERSION = "0.0.1"; } } namespace BasedSpectate.Utils { internal class SpectateInputActions : LcInputActions { private const string KeyboardAndMouseGroup = "KeyboardAndMouse"; internal static SpectateInputActions Instance { get; private set; } internal InputAction MoveForwardAction => ((LcInputActions)this).Asset["freecamMoveForward"]; internal InputAction MoveBackwardAction => ((LcInputActions)this).Asset["freecamMoveBackward"]; internal InputAction MoveLeftAction => ((LcInputActions)this).Asset["freecamMoveLeft"]; internal InputAction MoveRightAction => ((LcInputActions)this).Asset["freecamMoveRight"]; internal InputAction MoveUpAction => ((LcInputActions)this).Asset["freecamMoveUp"]; internal InputAction MoveDownAction => ((LcInputActions)this).Asset["freecamMoveDown"]; internal InputAction SprintAction => ((LcInputActions)this).Asset["freecamSprint"]; internal InputAction NextPlayerAction => ((LcInputActions)this).Asset["freecamNextPlayer"]; internal InputAction ToggleModeAction => ((LcInputActions)this).Asset["toggleSpectateMode"]; internal static InputAction MoveForward => Instance.MoveForwardAction; internal static InputAction MoveBackward => Instance.MoveBackwardAction; internal static InputAction MoveLeft => Instance.MoveLeftAction; internal static InputAction MoveRight => Instance.MoveRightAction; internal static InputAction MoveUp => Instance.MoveUpAction; internal static InputAction MoveDown => Instance.MoveDownAction; internal static InputAction Sprint => Instance.SprintAction; internal static InputAction NextPlayer => Instance.NextPlayerAction; internal static InputAction ToggleMode => Instance.ToggleModeAction; internal static void Initialise() { if (Instance == null) { Instance = new SpectateInputActions(); } } internal static Vector2 ReadMoveInput() { //IL_007d: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor((MoveRight.IsPressed() ? 1f : 0f) - (MoveLeft.IsPressed() ? 1f : 0f), (MoveForward.IsPressed() ? 1f : 0f) - (MoveBackward.IsPressed() ? 1f : 0f)); return (((Vector2)(ref val)).sqrMagnitude > 1f) ? ((Vector2)(ref val)).normalized : val; } internal static float ReadVerticalInput() { return (MoveUp.IsPressed() ? 1f : 0f) - (MoveDown.IsPressed() ? 1f : 0f); } internal static bool SprintIsPressed() { return Sprint.IsPressed(); } internal static bool NextPlayerWasPressedThisFrame() { return NextPlayer.WasPressedThisFrame(); } internal static bool ToggleModeWasPressedThisFrame() { return ToggleMode.WasPressedThisFrame(); } internal static string GetNextPlayerBindingText() { return GetBindingText(NextPlayer); } internal static string GetToggleModeBindingText() { return GetBindingText(ToggleMode); } public override void CreateInputActions(in InputActionMapBuilder builder) { builder.NewActionBinding().WithActionId("freecamMoveForward").WithActionType((InputActionType)1) .WithKbmPath("<Keyboard>/w") .WithBindingName("Freecam Move Forward") .Finish(); builder.NewActionBinding().WithActionId("freecamMoveBackward").WithActionType((InputActionType)1) .WithKbmPath("<Keyboard>/s") .WithBindingName("Freecam Move Backward") .Finish(); builder.NewActionBinding().WithActionId("freecamMoveLeft").WithActionType((InputActionType)1) .WithKbmPath("<Keyboard>/a") .WithBindingName("Freecam Move Left") .Finish(); builder.NewActionBinding().WithActionId("freecamMoveRight").WithActionType((InputActionType)1) .WithKbmPath("<Keyboard>/d") .WithBindingName("Freecam Move Right") .Finish(); builder.NewActionBinding().WithActionId("freecamMoveUp").WithActionType((InputActionType)1) .WithKbmPath("<Keyboard>/space") .WithBindingName("Freecam Move Up") .Finish(); builder.NewActionBinding().WithActionId("freecamMoveDown").WithActionType((InputActionType)1) .WithKbmPath("<Keyboard>/leftCtrl") .WithBindingName("Freecam Move Down") .Finish(); builder.NewActionBinding().WithActionId("freecamSprint").WithActionType((InputActionType)1) .WithKbmPath("<Keyboard>/leftShift") .WithBindingName("Freecam Sprint") .Finish(); builder.NewActionBinding().WithActionId("freecamNextPlayer").WithActionType((InputActionType)1) .WithMouseControl((MouseControl)11) .WithBindingName("Freecam Next Player") .Finish(); builder.NewActionBinding().WithActionId("toggleSpectateMode").WithActionType((InputActionType)1) .WithKeyboardControl((KeyboardControl)42) .WithBindingName("Toggle Spectate Mode") .Finish(); } private static string FormatBindingText(string bindingText) { if (1 == 0) { } string result = bindingText switch { "Left Button" => "LMB", "Right Button" => "RMB", "Middle Button" => "MMB", "Left Shift" => "L.Shift", "Left Ctrl" => "L.Ctrl", "Left Control" => "L.Ctrl", _ => bindingText, }; if (1 == 0) { } return result; } private static string GetBindingText(InputAction action) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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_0010: 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) Enumerator<InputBinding> enumerator = action.bindings.GetEnumerator(); try { while (enumerator.MoveNext()) { InputBinding current = enumerator.Current; if (!((InputBinding)(ref current)).isComposite && !((InputBinding)(ref current)).isPartOfComposite && string.Equals(((InputBinding)(ref current)).groups, "KeyboardAndMouse", StringComparison.Ordinal) && !string.IsNullOrWhiteSpace(((InputBinding)(ref current)).effectivePath)) { string text = InputControlPath.ToHumanReadableString(((InputBinding)(ref current)).effectivePath, (HumanReadableStringOptions)2, (InputControl)null); if (!string.IsNullOrWhiteSpace(text)) { return FormatBindingText(text); } } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return "Unbound"; } } } namespace BasedSpectate.Patches { internal static class DisableVanillaCullingPatches { private static bool isFreecamSpectating; [HarmonyPatch(typeof(FreecamMode), "Enable")] [HarmonyPostfix] private static void EnablePostfix() { isFreecamSpectating = true; if ((Object)(object)StartOfRound.Instance?.occlusionCuller != (Object)null) { ((Behaviour)StartOfRound.Instance.occlusionCuller).enabled = false; } } [HarmonyPatch(typeof(FreecamMode), "Disable")] [HarmonyPostfix] private static void DisablePostfix() { if (isFreecamSpectating) { isFreecamSpectating = false; if ((Object)(object)StartOfRound.Instance?.occlusionCuller != (Object)null) { ((Behaviour)StartOfRound.Instance.occlusionCuller).enabled = true; } } } [HarmonyPatch(typeof(AdjacentRoomCullingModified), "UpdateRendererLists", new Type[] { typeof(List<Tile>), typeof(List<Door>) })] [HarmonyPrefix] private static bool UpdateRendererListsPrefix() { return !isFreecamSpectating; } } internal static class SpectateModePatches { private static Vector2 holdButtonToEndGameEarlyMeterPosition; private static Vector2 holdButtonToEndGameEarlyVotesTextPosition; private static float zoomDistance; private static bool hasHoldButtonToEndGameEarlyPositions; private static bool wasSpectating; private const float HitDistanceOffset = 0.25f; private const float OpenDistanceOffset = 0.1f; internal static float CurrentZoomDistance => Mathf.Clamp(zoomDistance, Config.MinZoomDistance.Value, Config.MaxZoomDistance.Value); internal static void ResetZoomDistance() { zoomDistance = Mathf.Clamp(Config.DefaultZoomDistance.Value, Config.MinZoomDistance.Value, Config.MaxZoomDistance.Value); Plugin.mls.LogDebug((object)$"Spectate zoom distance reset to {zoomDistance}"); } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPostfix] private static void StartOfRoundAwakePostfix(StartOfRound __instance) { ((Component)__instance.spectateCamera).gameObject.AddComponent<FreecamMode>(); } [HarmonyPatch(typeof(StartOfRound), "SwitchCamera")] [HarmonyPostfix] private static void SwitchCameraPostfix(StartOfRound __instance, Camera newCamera) { FreecamMode component = ((Component)__instance.spectateCamera).GetComponent<FreecamMode>(); if ((Object)(object)newCamera == (Object)(object)__instance.spectateCamera) { PlayerControllerB localPlayerController = __instance.localPlayerController; if (localPlayerController != null && localPlayerController.isPlayerDead && Plugin.CurrentMode == SpectateMode.Freecam) { component.Enable(__instance.localPlayerController, keepCurrentCameraPosition: false); return; } } if (((Behaviour)component).enabled) { component.Disable(); } } [HarmonyPatch(typeof(StartOfRound), "SetSpectateCameraToGameOverMode")] [HarmonyPrefix] private static bool SetSpectateCameraToGameOverModePrefix() { return Plugin.CurrentMode != SpectateMode.Freecam; } [HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")] [HarmonyPriority(800)] [HarmonyPrefix] private static void PlayerControllerBLateUpdatePrefix(PlayerControllerB __instance) { //IL_0195: Unknown result type (might be due to invalid IL or missing references) if ((!((NetworkBehaviour)__instance).IsOwner || (((NetworkBehaviour)__instance).IsServer && !__instance.isHostPlayerObject)) && !__instance.isTestingPlayer) { return; } if (!__instance.isPlayerDead) { wasSpectating = false; Plugin.CurrentMode = Config.StartMode.Value; return; } if (!wasSpectating) { Plugin.CurrentMode = Config.StartMode.Value; ResetZoomDistance(); wasSpectating = true; } bool flag = __instance.isTypingChat || __instance.inTerminalMenu || __instance.quickMenuManager.isMenuOpen; if (!Config.EnableModeToggle.Value) { Plugin.CurrentMode = Config.StartMode.Value; } else if (!flag && SpectateInputActions.ToggleModeWasPressedThisFrame()) { Plugin.CurrentMode = ((Plugin.CurrentMode == SpectateMode.Vanilla) ? SpectateMode.Freecam : SpectateMode.Vanilla); Plugin.mls.LogDebug((object)$"Spectate mode set to {Plugin.CurrentMode}"); } FreecamMode component = ((Component)__instance.playersManager.spectateCamera).GetComponent<FreecamMode>(); if (Plugin.CurrentMode == SpectateMode.Freecam) { __instance.playersManager.overrideSpectateCamera = true; component.Enable(__instance, keepCurrentCameraPosition: true); return; } if (((Behaviour)component).enabled) { component.Disable(); } if (__instance.playersManager.overrideSpectateCamera || flag || __instance.inSpecialInteractAnimation) { return; } Mouse current = Mouse.current; if (current != null) { float y = ((InputControl<Vector2>)(object)current.scroll).ReadValue().y; if (!Mathf.Approximately(y, 0f)) { zoomDistance = Mathf.Clamp(zoomDistance + y / -120f * Config.ZoomSpeed.Value, Config.MinZoomDistance.Value, Config.MaxZoomDistance.Value); } } } [HarmonyPatch(typeof(PlayerControllerB), "RaycastSpectateCameraAroundPivot")] [HarmonyPrefix] private static bool RaycastSpectateCameraAroundPivotPrefix(PlayerControllerB __instance) { //IL_0054: 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_00c3: 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_00b3: Unknown result type (might be due to invalid IL or missing references) if (((!((NetworkBehaviour)__instance).IsOwner || (((NetworkBehaviour)__instance).IsServer && !__instance.isHostPlayerObject)) && !__instance.isTestingPlayer) || !__instance.isPlayerDead || Plugin.CurrentMode != SpectateMode.Vanilla || __instance.playersManager.overrideSpectateCamera) { return true; } Ray val = default(Ray); ((Ray)(ref val))..ctor(__instance.spectateCameraPivot.position, -__instance.spectateCameraPivot.forward); Transform transform = ((Component)__instance.playersManager.spectateCamera).transform; float currentZoomDistance = CurrentZoomDistance; RaycastHit val2 = default(RaycastHit); transform.position = ((Config.CameraClipsThroughWalls.Value || !Physics.Raycast(val, ref val2, currentZoomDistance, __instance.walkableSurfacesNoPlayersMask, (QueryTriggerInteraction)1)) ? ((Ray)(ref val)).GetPoint(currentZoomDistance - 0.1f) : ((Ray)(ref val)).GetPoint(((RaycastHit)(ref val2)).distance - 0.25f)); transform.LookAt(__instance.spectateCameraPivot); return false; } [HarmonyPatch(typeof(HUDManager), "Update")] [HarmonyPostfix] private static void HUDManagerUpdatePostfix(HUDManager __instance) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0214: 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) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) if (!hasHoldButtonToEndGameEarlyPositions) { holdButtonToEndGameEarlyMeterPosition = ((Graphic)__instance.holdButtonToEndGameEarlyMeter).rectTransform.anchoredPosition; holdButtonToEndGameEarlyVotesTextPosition = ((TMP_Text)__instance.holdButtonToEndGameEarlyVotesText).rectTransform.anchoredPosition; hasHoldButtonToEndGameEarlyPositions = true; } if (!((Object)(object)GameNetworkManager.Instance?.localPlayerController != (Object)null) || !GameNetworkManager.Instance.localPlayerController.isPlayerDead) { ((Graphic)__instance.holdButtonToEndGameEarlyMeter).rectTransform.anchoredPosition = holdButtonToEndGameEarlyMeterPosition; ((TMP_Text)__instance.holdButtonToEndGameEarlyVotesText).rectTransform.anchoredPosition = holdButtonToEndGameEarlyVotesTextPosition; return; } string text = ((TMP_Text)__instance.holdButtonToEndGameEarlyText).text; string text2 = string.Empty; int num = 0; if (Config.ShowNextPlayerHint.Value) { text2 = "[" + SpectateInputActions.GetNextPlayerBindingText() + "] Next Player"; num++; } if (Config.EnableModeToggle.Value && Config.ShowToggleModeHint.Value) { string text3 = "[" + SpectateInputActions.GetToggleModeBindingText() + "] Toggle Mode"; text2 = (string.IsNullOrEmpty(text2) ? text3 : (text2 + "\n" + text3)); num++; } if (Config.ShowCameraInfoHint.Value) { string text4 = ((Plugin.CurrentMode == SpectateMode.Freecam) ? $"Brightness: [{FreecamMode.CurrentBrightness:0.0} / {FreecamMode.MaximumBrightness:0.0}]" : $"Zoom: [{CurrentZoomDistance:0.0} / {Config.MaxZoomDistance.Value:0.0}]"); text2 = (string.IsNullOrEmpty(text2) ? text4 : (text2 + "\n" + text4)); num++; } if (num == 0) { ((Graphic)__instance.holdButtonToEndGameEarlyMeter).rectTransform.anchoredPosition = holdButtonToEndGameEarlyMeterPosition; ((TMP_Text)__instance.holdButtonToEndGameEarlyVotesText).rectTransform.anchoredPosition = holdButtonToEndGameEarlyVotesTextPosition; return; } float num2 = -8f * (float)num; ((Graphic)__instance.holdButtonToEndGameEarlyMeter).rectTransform.anchoredPosition = holdButtonToEndGameEarlyMeterPosition + new Vector2(0f, num2); ((TMP_Text)__instance.holdButtonToEndGameEarlyVotesText).rectTransform.anchoredPosition = holdButtonToEndGameEarlyVotesTextPosition + new Vector2(0f, num2); ((TMP_Text)__instance.holdButtonToEndGameEarlyText).text = (string.IsNullOrEmpty(text) ? text2 : (text2 + "\n" + text)); } } } namespace BasedSpectate.Compat { internal static class LethalConfigCompat { internal static void Register() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //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_0058: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Expected O, but got Unknown //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Expected O, but got Unknown //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown //IL_013c: 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_014c: Expected O, but got Unknown //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Expected O, but got Unknown //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Expected O, but got Unknown //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Expected O, but got Unknown //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Expected O, but got Unknown LethalConfigManager.SkipAutoGen(); LethalConfigManager.AddConfigItem((BaseConfigItem)(object)new EnumDropDownConfigItem<SpectateMode>(Config.StartMode, new EnumDropDownOptions { RequiresRestart = false })); LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Config.EnableModeToggle, new BoolCheckBoxOptions { RequiresRestart = false })); LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Config.ShowNextPlayerHint, new BoolCheckBoxOptions { RequiresRestart = false })); LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Config.ShowToggleModeHint, new BoolCheckBoxOptions { RequiresRestart = false })); LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Config.ShowCameraInfoHint, new BoolCheckBoxOptions { RequiresRestart = false })); ConfigEntry<float> defaultZoomDistance = Config.DefaultZoomDistance; FloatSliderOptions val = new FloatSliderOptions(); ((BaseRangeOptions<float>)val).Min = 0.1f; ((BaseRangeOptions<float>)val).Max = 50f; ((BaseOptions)val).RequiresRestart = false; LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(defaultZoomDistance, val)); ConfigEntry<float> minZoomDistance = Config.MinZoomDistance; FloatSliderOptions val2 = new FloatSliderOptions(); ((BaseRangeOptions<float>)val2).Min = 0.1f; ((BaseRangeOptions<float>)val2).Max = 50f; ((BaseOptions)val2).RequiresRestart = false; LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(minZoomDistance, val2)); ConfigEntry<float> maxZoomDistance = Config.MaxZoomDistance; FloatSliderOptions val3 = new FloatSliderOptions(); ((BaseRangeOptions<float>)val3).Min = 0.1f; ((BaseRangeOptions<float>)val3).Max = 50f; ((BaseOptions)val3).RequiresRestart = false; LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(maxZoomDistance, val3)); ConfigEntry<float> zoomSpeed = Config.ZoomSpeed; FloatSliderOptions val4 = new FloatSliderOptions(); ((BaseRangeOptions<float>)val4).Min = 0f; ((BaseRangeOptions<float>)val4).Max = 5f; ((BaseOptions)val4).RequiresRestart = false; LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(zoomSpeed, val4)); LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Config.CameraClipsThroughWalls, new BoolCheckBoxOptions { RequiresRestart = false })); } } } namespace BasedSpectate.Behaviours { internal class FreecamMode : MonoBehaviour { private const float MoveSpeed = 10f; private const float SprintMultiplier = 5f; private const float SpeedLerp = 12f; private const float LookScale = 0.008f; private const float MinBrightness = 0f; private const float MaxBrightness = 800f; private const float BrightnessScrollSpeed = 200f; private const float BrightnessIntensityScale = 0.01f; private const float InsideFactoryY = -80f; private static float brightness; private readonly Light[] lights = (Light[])(object)new Light[4]; private PlayerControllerB? player; private float pitch; private float currentMoveSpeed; internal static float CurrentBrightness => Mathf.Clamp(brightness, 0f, MaximumBrightness); internal static float MaximumBrightness => 800f; private void Awake() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < lights.Length; i++) { if (1 == 0) { } Vector3 val = (Vector3)(i switch { 0 => new Vector3(50f, 0f, 0f), 1 => new Vector3(120f, 0f, 0f), 2 => new Vector3(50f, 90f, 0f), _ => new Vector3(50f, -90f, 0f), }); if (1 == 0) { } Vector3 eulerAngles = val; GameObject val2 = new GameObject(string.Format("{0} Freecam Light {1}", "BasedSpectateMode", i)); Light val3 = val2.AddComponent<Light>(); HDAdditionalLightData val4 = val2.AddComponent<HDAdditionalLightData>(); ((Object)val2).hideFlags = (HideFlags)52; val2.transform.eulerAngles = eulerAngles; val3.type = (LightType)1; val3.shadows = (LightShadows)0; ((Behaviour)val3).enabled = false; val4.affectsVolumetric = false; lights[i] = val3; } currentMoveSpeed = 10f; ((Behaviour)this).enabled = false; } internal void Enable(PlayerControllerB playerController, bool keepCurrentCameraPosition) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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) if (!((Behaviour)this).enabled || !((Object)(object)player == (Object)(object)playerController)) { player = playerController; brightness = 0f; currentMoveSpeed = 10f; ((Component)this).transform.SetParent((Transform)null); if (!keepCurrentCameraPosition) { Transform transform = ((Component)playerController.gameplayCamera).transform; ((Component)this).transform.SetPositionAndRotation(transform.position, transform.rotation); } pitch = ((Component)this).transform.eulerAngles.x; if (pitch > 180f) { pitch -= 360f; } StartOfRound.Instance.overrideSpectateCamera = true; ((Behaviour)this).enabled = true; } } internal void Disable() { if (!((Behaviour)this).enabled) { return; } for (int i = 0; i < lights.Length; i++) { if ((Object)(object)lights[i] != (Object)null) { ((Behaviour)lights[i]).enabled = false; } } ((Behaviour)this).enabled = false; player = null; if ((Object)(object)StartOfRound.Instance != (Object)null) { StartOfRound.Instance.overrideSpectateCamera = false; } } private void LateUpdate() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: 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_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: 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_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB? obj = player; if (obj == null || !obj.isPlayerDead) { Disable(); return; } bool flag = ((Component)this).transform.position.y < -80f; StartOfRound.Instance.overrideSpectateCamera = true; StartOfRound.Instance.SetOcclusionCullerToPosition(((Component)this).transform.position); StartOfRound.Instance.blackSkyVolume.weight = (flag ? 1f : 0f); ((Behaviour)TimeOfDay.Instance.sunDirect).enabled = !flag; ((Behaviour)TimeOfDay.Instance.sunIndirect).enabled = !flag; float intensity = CurrentBrightness * 0.01f; bool enabled = !Mathf.Approximately(CurrentBrightness, 0f); for (int i = 0; i < lights.Length; i++) { ((Behaviour)lights[i]).enabled = enabled; lights[i].intensity = intensity; } if (player.isTypingChat || player.inTerminalMenu || player.quickMenuManager.isMenuOpen) { return; } if (SpectateInputActions.NextPlayerWasPressedThisFrame()) { SwitchSpectatedPlayer(1); } Mouse current = Mouse.current; if (current != null) { float y = ((InputControl<Vector2>)(object)current.scroll).ReadValue().y; if (!Mathf.Approximately(y, 0f)) { brightness = Mathf.Clamp(brightness + y / 120f * 200f, 0f, MaximumBrightness); } } Vector2 val = SpectateInputActions.ReadMoveInput(); float num = (float)IngamePlayerSettings.Instance.settings.lookSensitivity * 0.008f; MovementActions movement = player.playerActions.Movement; Vector2 val2 = num * ((MovementActions)(ref movement)).Look.ReadValue<Vector2>(); if (!IngamePlayerSettings.Instance.settings.invertYAxis) { val2.y *= -1f; } ((Component)this).transform.Rotate(0f, val2.x, 0f, (Space)0); pitch = Mathf.Clamp(pitch + val2.y, -90f, 90f); ((Component)this).transform.eulerAngles = new Vector3(pitch, ((Component)this).transform.eulerAngles.y, 0f); float num2 = (SpectateInputActions.SprintIsPressed() ? 50f : 10f); currentMoveSpeed = Mathf.Lerp(currentMoveSpeed, num2, 12f * Time.deltaTime); float num3 = SpectateInputActions.ReadVerticalInput(); Vector3 val3 = ((Component)this).transform.right * val.x + ((Component)this).transform.forward * val.y + Vector3.up * num3; Transform transform = ((Component)this).transform; transform.position += currentMoveSpeed * Time.deltaTime * val3; } private void SwitchSpectatedPlayer(int direction) { //IL_011a: 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_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0134: 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) if ((Object)(object)player == (Object)null) { return; } PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; int num = (int)(((Object)(object)player.spectatedPlayerScript == (Object)null) ? player.playerClientId : player.spectatedPlayerScript.playerClientId); for (int i = 0; i < allPlayerScripts.Length; i++) { num += direction; if (num < 0) { num = allPlayerScripts.Length - 1; } else if (num >= allPlayerScripts.Length) { num = 0; } PlayerControllerB val = allPlayerScripts[num]; if (!((Object)(object)val == (Object)(object)player) && !val.isPlayerDead && val.isPlayerControlled) { player.spectatedPlayerScript = val; player.SetSpectatedPlayerEffects(false); HUDManager.Instance.SetSpectatingTextToPlayer(val); Transform transform = ((Component)val.gameplayCamera).transform; float num2 = Mathf.Clamp(Config.DefaultZoomDistance.Value, Config.MinZoomDistance.Value, Config.MaxZoomDistance.Value); ((Component)this).transform.SetPositionAndRotation(transform.position - transform.forward * num2, transform.rotation); pitch = ((Component)this).transform.eulerAngles.x; if (pitch > 180f) { pitch -= 360f; } Plugin.mls.LogDebug((object)("Freecam spectating " + val.playerUsername)); break; } } } private void OnDestroy() { for (int i = 0; i < lights.Length; i++) { if ((Object)(object)lights[i] != (Object)null) { Object.Destroy((Object)(object)((Component)lights[i]).gameObject); } } } } }