using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BoneLib; using BoneLib.BoneMenu; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSLZ.Marrow; using MelonLoader; using MelonLoader.Preferences; using SpectatorMod; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(SpectatorModMain), "Spectator Cam", "2.4.0", "Int_Void", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("SpectatorMod")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SpectatorMod")] [assembly: AssemblyTitle("SpectatorMod")] [assembly: AssemblyVersion("1.0.0.0")] namespace SpectatorMod; public class SpectatorModMain : MelonMod { public enum ControllerSide { Left, Right, Both } private class TrackedPlayer { public Transform HeadBone; public string Name; } public static MelonPreferences_Category PrefCategory; public static MelonPreferences_Entry PrefController; public static MelonPreferences_Entry PrefIsEnabled; private bool _isSpectating = false; private Camera _specCamera; private float _buttonPressTime = -1f; private const float MAX_HOLD_TIME = 0.4f; private bool _isButtonHeld = false; private List _players = new List(); private int _currentPlayerIndex = 0; private TrackedPlayer _currentPlayer; private Vector3 _cameraOffset = new Vector3(0f, 0.12f, 0.05f); public override void OnInitializeMelon() { ((MelonBase)this).LoggerInstance.Msg("Spectator Mod v2.4 Initialized!"); Hooking.OnLevelLoaded += OnLevelLoaded; SetupPreferences(); SetupBoneMenu(); } private void SetupPreferences() { PrefCategory = MelonPreferences.CreateCategory("SpectatorMod", "Spectator Mod"); PrefIsEnabled = PrefCategory.CreateEntry("IsEnabled", true, "Enable Mod", (string)null, false, false, (ValueValidator)null, (string)null); PrefController = PrefCategory.CreateEntry("ControllerSide", ControllerSide.Left, "Controller Side", (string)null, false, false, (ValueValidator)null, (string)null); } private void SetupBoneMenu() { //IL_000b: 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_0045: Unknown result type (might be due to invalid IL or missing references) Page val = Page.Root.CreatePage("Spectator Mod", Color.white, 0, true); val.CreateBool("Mod Enabled", Color.green, PrefIsEnabled.Value, (Action)delegate(bool flag) { PrefIsEnabled.Value = flag; PrefCategory.SaveToFile(false); if (!flag && _isSpectating) { StopSpectating(); } }); val.CreateEnum("Controller Side", Color.white, (Enum)PrefController.Value, (Action)delegate(Enum obj) { PrefController.Value = (ControllerSide)(object)obj; PrefCategory.SaveToFile(false); }); } private void OnLevelLoaded(LevelInfo info) { StopSpectating(); } public override void OnUpdate() { //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) if (!PrefIsEnabled.Value || (Object)(object)Player.RigManager == (Object)null) { return; } bool flag = false; bool flag2 = false; bool flag3 = false; try { BaseController leftController = Player.LeftController; BaseController rightController = Player.RightController; bool flag4 = PrefController.Value == ControllerSide.Left || PrefController.Value == ControllerSide.Both; bool flag5 = PrefController.Value == ControllerSide.Right || PrefController.Value == ControllerSide.Both; bool flag6 = flag4 && (Object)(object)leftController != (Object)null && leftController.GetBButtonDown(); bool flag7 = flag5 && (Object)(object)rightController != (Object)null && rightController.GetBButtonDown(); bool flag8 = flag4 && (Object)(object)leftController != (Object)null && leftController.GetBButton(); bool flag9 = flag5 && (Object)(object)rightController != (Object)null && rightController.GetBButton(); bool flag10 = flag8 || flag9; if ((flag6 || flag7) && !_isButtonHeld) { _buttonPressTime = Time.time; _isButtonHeld = true; } else if (!flag10 && _isButtonHeld) { _isButtonHeld = false; float num = Time.time - _buttonPressTime; if (num <= 0.4f && _buttonPressTime > 0f) { flag2 = true; } _buttonPressTime = -1f; } Vector2 thumbStickAxis; if (flag4 && (Object)(object)leftController != (Object)null) { bool num2 = flag3; thumbStickAxis = leftController.GetThumbStickAxis(); flag3 = num2 | (((Vector2)(ref thumbStickAxis)).magnitude > 0.2f); } if (flag5 && (Object)(object)rightController != (Object)null) { bool num3 = flag3; thumbStickAxis = rightController.GetThumbStickAxis(); flag3 = num3 | (((Vector2)(ref thumbStickAxis)).magnitude > 0.2f); } } catch { } if (Input.GetKeyDown((KeyCode)107)) { flag2 = true; } if (Input.GetKey((KeyCode)119) || Input.GetKey((KeyCode)97) || Input.GetKey((KeyCode)115) || Input.GetKey((KeyCode)100)) { flag3 = true; } if (flag2) { if (!_isSpectating) { StartSpectating(); } else { CycleTarget(); } } if (_isSpectating) { if (flag3) { StopSpectating(); } else { UpdateCameraPosition(); } } } private void StartSpectating() { RefreshPlayers(); if (_players.Count != 0) { _isSpectating = true; _currentPlayerIndex = 0; SetupCamera(); AttachToCurrentPlayer(); } } private void StopSpectating() { _isSpectating = false; _currentPlayer = null; if ((Object)(object)_specCamera != (Object)null) { Object.Destroy((Object)(object)((Component)_specCamera).gameObject); _specCamera = null; } } private void CycleTarget() { RefreshPlayers(); if (_players.Count == 0) { StopSpectating(); return; } _currentPlayerIndex++; if (_currentPlayerIndex >= _players.Count) { _currentPlayerIndex = 0; } AttachToCurrentPlayer(); } private void RefreshPlayers() { _players.Clear(); RigManager rigManager = Player.RigManager; object obj; if (rigManager == null) { obj = null; } else { PhysicsRig physicsRig = rigManager.physicsRig; obj = ((physicsRig != null) ? ((Rig)physicsRig).m_head : null); } if ((Object)obj != (Object)null) { _players.Add(new TrackedPlayer { HeadBone = ((Rig)Player.RigManager.physicsRig).m_head, Name = "LOCAL PLAYER" }); } Il2CppArrayBase val = Object.FindObjectsOfType(); foreach (RigManager item in val) { if ((Object)(object)item != (Object)(object)Player.RigManager) { PhysicsRig physicsRig2 = item.physicsRig; if ((Object)(object)((physicsRig2 != null) ? ((Rig)physicsRig2).m_head : null) != (Object)null) { _players.Add(new TrackedPlayer { HeadBone = ((Rig)item.physicsRig).m_head, Name = "FUSION PLAYER" }); } } } } private void SetupCamera() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown if (!((Object)(object)_specCamera != (Object)null)) { GameObject val = new GameObject("SpectatorCamera_VR"); _specCamera = val.AddComponent(); if ((Object)(object)Camera.main != (Object)null) { _specCamera.CopyFrom(Camera.main); } else { _specCamera.fieldOfView = 90f; } _specCamera.nearClipPlane = 0.15f; _specCamera.targetTexture = null; _specCamera.depth = 100f; ((Behaviour)_specCamera).enabled = true; } } private void AttachToCurrentPlayer() { if (_players.Count != 0 && _currentPlayerIndex < _players.Count) { _currentPlayer = _players[_currentPlayerIndex]; } } private void UpdateCameraPosition() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_0075: 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_0087: 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_009f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_currentPlayer?.HeadBone == (Object)null || (Object)(object)_specCamera == (Object)null) { StopSpectating(); return; } Transform headBone = _currentPlayer.HeadBone; Vector3 val = headBone.up * _cameraOffset.y + headBone.forward * _cameraOffset.z; ((Component)_specCamera).transform.position = headBone.position + val; ((Component)_specCamera).transform.rotation = headBone.rotation; } public override void OnGUI() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) if (PrefIsEnabled.Value && _isSpectating && _currentPlayer != null) { GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 30, fontStyle = (FontStyle)1 }; val.normal.textColor = Color.cyan; GUIStyle val2 = val; GUIStyle val3 = new GUIStyle(GUI.skin.label) { fontSize = 20 }; val3.normal.textColor = Color.white; GUIStyle val4 = val3; GUI.Label(new Rect(20f, 20f, 800f, 50f), "SPECTATING: " + _currentPlayer.Name, val2); GUI.Label(new Rect(20f, 55f, 600f, 30f), "Tap Y/B (<0.4s) to cycle | Stick to exit", val4); } } }