Decompiled source of GhostPossession v0.2.0
GhostPossession.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using Peak; using Photon.Pun; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [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 GhostPossession { public static class ModConfig { public static ConfigFile Config { get; private set; } public static float GhostSpeed { get; private set; } public static float GhostSprintMultiplier { get; private set; } public static float PossessionScanRadius { get; private set; } public static float PossessionForce { get; private set; } public static float PossessionJumpForce { get; private set; } public static float PossessionTorque { get; private set; } public static bool DebugLogging { get; private set; } public static bool DebugPreventRunEnd { get; private set; } public static KeyCode ReviveKey { get; private set; } public static bool ReviveApplyStatus { get; private set; } public static void Init(ConfigFile config) { //IL_0135: Unknown result type (might be due to invalid IL or missing references) Config = config; GhostSpeed = config.Bind<float>("Ghost", "GhostSpeed", 8f, "Free-fly ghost movement speed in meters per second.").Value; GhostSprintMultiplier = config.Bind<float>("Ghost", "GhostSprintMultiplier", 2f, "Sprint multiplier while holding Left Shift.").Value; PossessionScanRadius = config.Bind<float>("Possession", "PossessionScanRadius", 15f, "Search radius for possession candidates in meters.").Value; PossessionForce = config.Bind<float>("Possession", "PossessionForce", 18f, "Horizontal force applied to possessed rigid bodies.").Value; PossessionJumpForce = config.Bind<float>("Possession", "PossessionJumpForce", 7f, "Upward impulse applied when jumping in possession mode.").Value; PossessionTorque = config.Bind<float>("Possession", "PossessionTorque", 30f, "Torque used to steer possessed rigid bodies.").Value; DebugLogging = config.Bind<bool>("Debug", "DebugLogging", true, "Enables verbose plugin logs for debugging and hotkey testing.").Value; DebugPreventRunEnd = config.Bind<bool>("Debug", "DebugPreventRunEnd", true, "Prevents the run from ending during ghost debug tests.").Value; ReviveKey = config.Bind<KeyCode>("Ghost", "ReviveKey", (KeyCode)103, "While a ghost, press this key to stop being a ghost and revive your character at the ghost's current position.").Value; ReviveApplyStatus = config.Bind<bool>("Ghost", "ReviveApplyStatus", false, "When reviving at the ghost position, also apply the vanilla post-revive penalty (revival curse + hunger). Off by default because this is a debug tool.").Value; } public static void Refresh() { //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) if (Config != null) { GhostSpeed = ((Config["Ghost", "GhostSpeed"].BoxedValue is float num) ? num : 8f); GhostSprintMultiplier = ((Config["Ghost", "GhostSprintMultiplier"].BoxedValue is float num2) ? num2 : 2f); PossessionScanRadius = ((Config["Possession", "PossessionScanRadius"].BoxedValue is float num3) ? num3 : 15f); PossessionForce = ((Config["Possession", "PossessionForce"].BoxedValue is float num4) ? num4 : 18f); PossessionJumpForce = ((Config["Possession", "PossessionJumpForce"].BoxedValue is float num5) ? num5 : 7f); PossessionTorque = ((Config["Possession", "PossessionTorque"].BoxedValue is float num6) ? num6 : 30f); DebugLogging = !(Config["Debug", "DebugLogging"].BoxedValue is bool flag) || flag; DebugPreventRunEnd = !(Config["Debug", "DebugPreventRunEnd"].BoxedValue is bool flag2) || flag2; ReviveKey = (KeyCode)((!(Config["Ghost", "ReviveKey"].BoxedValue is KeyCode val)) ? 103 : ((int)val)); ReviveApplyStatus = Config["Ghost", "ReviveApplyStatus"].BoxedValue is bool flag3 && flag3; } } } public sealed class GlobalGravityController { private const float WorldScale = 1200f; private GameObject _antiSphere; private float _messageUntil; private bool _hotkeyHeld; public void Update() { if ((Object)(object)_antiSphere == (Object)null) { AntiSphere[] array = Object.FindObjectsOfType<AntiSphere>(); foreach (AntiSphere val in array) { if ((Object)(object)val != (Object)null && ((Object)((Component)val).gameObject).name.Contains("GhostPossession World AntiSphere")) { _antiSphere = ((Component)val).gameObject; Configure(_antiSphere); break; } } } bool flag = Input.GetKey((KeyCode)282) || Input.GetKey((KeyCode)292) || Input.GetKey((KeyCode)257); bool num = flag && !_hotkeyHeld; _hotkeyHeld = flag; if (num) { GhostPossessionPlugin.Instance?.LogState("Antizooka hotkey received (F1/F11/Num1)"); if (!NetworkHelper.IsLocalHost()) { GhostPossessionPlugin.Instance.LogState("Antizooka field: host only"); } else if ((Object)(object)_antiSphere != (Object)null) { DisableField(); } else { EnableField(); } } } public void FixedUpdate() { if ((Object)(object)_antiSphere != (Object)null) { Configure(_antiSphere); } } public void OnGUI() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_antiSphere == (Object)null) || !(Time.unscaledTime > _messageUntil)) { GUI.Box(new Rect((float)Screen.width - 350f, 20f, 330f, 58f), ((Object)(object)_antiSphere != (Object)null) ? "WORLD ANTIZOOKA FIELD: ON\nF1/F11 — remove field" : "WORLD ANTIZOOKA FIELD: OFF"); } } public void Cleanup() { _antiSphere = null; } private void EnableField() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_002b: Unknown result type (might be due to invalid IL or missing references) Vector3 val = (((Object)(object)Camera.main != (Object)null) ? ((Component)Camera.main).transform.position : Vector3.zero); try { _antiSphere = PhotonNetwork.Instantiate("AntiSphere", val, Quaternion.identity, (byte)0, (object[])null); if ((Object)(object)_antiSphere == (Object)null) { throw new InvalidOperationException("Photon returned null for AntiSphere"); } ((Object)_antiSphere).name = "GhostPossession World AntiSphere"; Configure(_antiSphere); _messageUntil = Time.unscaledTime + 2.5f; GhostPossessionPlugin.Instance?.LogState("WORLD ANTIZOOKA FIELD ON, scale=" + 1200f); } catch (Exception ex) { _antiSphere = null; Debug.LogError((object)("[GhostPossession] Vanilla AntiSphere spawn failed: " + ex)); } } private void DisableField() { GameObject antiSphere = _antiSphere; _antiSphere = null; try { PhotonView val = (((Object)(object)antiSphere != (Object)null) ? antiSphere.GetComponent<PhotonView>() : null); if (PhotonNetwork.InRoom && (Object)(object)val != (Object)null && val.IsMine) { PhotonNetwork.Destroy(antiSphere); } else if ((Object)(object)antiSphere != (Object)null) { Object.Destroy((Object)(object)antiSphere); } _messageUntil = Time.unscaledTime + 2.5f; GhostPossessionPlugin.Instance?.LogState("World Antizooka field removed"); } catch (Exception ex) { Debug.LogError((object)("[GhostPossession] AntiSphere removal failed: " + ex)); } } private static void Configure(GameObject sphereObject) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sphereObject == (Object)null) { return; } ((Object)sphereObject).name = "GhostPossession World AntiSphere"; sphereObject.transform.localScale = Vector3.one * 1200f; AntiSphere val = sphereObject.GetComponent<AntiSphere>() ?? sphereObject.GetComponentInChildren<AntiSphere>(); if (!((Object)(object)val == (Object)null)) { SphereCollider component = ((Component)val).GetComponent<SphereCollider>(); if ((Object)(object)component != (Object)null) { ((Collider)component).enabled = true; ((Collider)component).isTrigger = true; } } } } public static class NetworkHelper { public static bool IsLocalHost() { try { return !PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient; } catch { return false; } } } public static class PlayerReflection { private const BindingFlags InstanceFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; public static Character GetLocalCharacter() { try { return Character.localCharacter; } catch (Exception ex) { Debug.LogException(ex); } return null; } public static bool IsLocalCharacter(Character c) { Character localCharacter = GetLocalCharacter(); if ((Object)(object)localCharacter != (Object)null) { return (Object)(object)localCharacter == (Object)(object)c; } return false; } public static void KillLocalCharacter(Character character) { if ((Object)(object)character == (Object)null) { return; } try { MethodInfo methodInfo = typeof(Character).GetMethod("DieInstantlyLocal", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(Character).GetMethod("DieInstantly", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(Character).GetMethod("Die", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (methodInfo == null) { Debug.LogError((object)"[GhostPossession] No compatible Character death method was found"); } else { methodInfo.Invoke(character, null); } } catch (Exception ex) { Debug.LogError((object)("[GhostPossession] Die() call failed: " + ex)); } } public static bool ReviveLocalCharacterAt(Character character, Vector3 position, bool applyStatus) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null) { return false; } try { object? obj = typeof(Character).GetField("view", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(character); PhotonView val = (PhotonView)(((obj is PhotonView) ? obj : null) ?? ((Component)character).GetComponentInParent<PhotonView>()); if ((Object)(object)val != (Object)null && PhotonNetwork.InRoom) { val.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { position, applyStatus, -1 }); return true; } MethodInfo method = typeof(Character).GetMethod("RPCA_ReviveAtPosition", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { Debug.LogError((object)"[GhostPossession] RPCA_ReviveAtPosition was not found on Character"); return false; } method.Invoke(character, new object[3] { position, applyStatus, -1 }); return true; } catch (Exception ex) { Debug.LogError((object)("[GhostPossession] Revive-at-position call failed: " + ex)); return false; } } } public static class RunEndHelper { public static bool AllowNextRunEnd { get; set; } public static void ForceRunEndIfPossible() { try { Character localCharacter = PlayerReflection.GetLocalCharacter(); if ((Object)(object)localCharacter != (Object)null) { MethodInfo method = typeof(Character).GetMethod("CheckEndGame", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { Debug.LogWarning((object)"[GhostPossession] Character.CheckEndGame was not found"); return; } AllowNextRunEnd = true; method.Invoke(localCharacter, null); Debug.Log((object)"[GhostPossession] Normal run-end check requested"); } } catch (Exception ex) { Debug.LogError((object)("[GhostPossession] Run end helper failed: " + ex)); } } } public sealed class SpawnedTestScoutMarker : MonoBehaviour { private static readonly List<SpawnedTestScoutMarker> Active = new List<SpawnedTestScoutMarker>(); private Character _character; private Renderer[] _renderers; private FieldInfo _deadField; private FieldInfo _passedOutField; public Character TargetCharacter => _character; public Vector3 WorldCenter { get { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (_renderers != null) { Renderer[] renderers = _renderers; foreach (Renderer val in renderers) { if ((Object)(object)val != (Object)null) { Bounds bounds = val.bounds; return ((Bounds)(ref bounds)).center; } } } return ((Component)this).transform.position; } } private void Awake() { //IL_0140: 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) _character = ((Component)this).GetComponent<Character>() ?? ((Component)this).GetComponentInChildren<Character>(); _renderers = ((Component)this).GetComponentsInChildren<Renderer>(true); if ((Object)(object)_character != (Object)null && (Object)(object)_character.data != (Object)null) { BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; _deadField = ((object)_character.data).GetType().GetField("<dead>k__BackingField", bindingAttr) ?? ((object)_character.data).GetType().GetField("dead", bindingAttr); _passedOutField = ((object)_character.data).GetType().GetField("fullyPassedOut", bindingAttr); } Behaviour[] componentsInChildren = ((Component)this).GetComponentsInChildren<Behaviour>(true); foreach (Behaviour val in componentsInChildren) { if (!((Object)(object)val == (Object)(object)this) && !((Object)(object)val == (Object)null)) { switch (((object)val).GetType().Name) { case "LocalPlayerRenderer": case "HideTheBody": case "CharacterInput": case "CharacterMovement": case "PlayerGhost": val.enabled = false; break; } } } Rigidbody[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Rigidbody>(true); foreach (Rigidbody obj in componentsInChildren2) { obj.velocity = Vector3.zero; obj.angularVelocity = Vector3.zero; obj.isKinematic = true; } Active.Add(this); ForceVisible(); } private void LateUpdate() { if ((Object)(object)_character != (Object)null) { _character.isBot = false; _character.isZombie = false; _character.isScoutmaster = false; ((Behaviour)_character).enabled = false; if ((Object)(object)_character.data != (Object)null) { _deadField?.SetValue(_character.data, false); _passedOutField?.SetValue(_character.data, false); } } ForceVisible(); } private void OnDestroy() { Active.Remove(this); GhostPossessionPlugin.Instance?.LogState("Test scout destroyed"); } private void ForceVisible() { if (_renderers == null) { return; } Renderer[] renderers = _renderers; foreach (Renderer val in renderers) { if ((Object)(object)val != (Object)null) { val.enabled = true; } } } public static void ForceAllVisible() { for (int num = Active.Count - 1; num >= 0; num--) { if ((Object)(object)Active[num] == (Object)null) { Active.RemoveAt(num); } else { Active[num].ForceVisible(); } } } public void HoldAt(Vector3 position, Quaternion rotation) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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) ((Component)this).transform.position = position; ((Component)this).transform.rotation = rotation; Rigidbody[] componentsInChildren = ((Component)this).GetComponentsInChildren<Rigidbody>(true); foreach (Rigidbody obj in componentsInChildren) { obj.isKinematic = true; obj.velocity = Vector3.zero; obj.angularVelocity = Vector3.zero; } } public void Throw(Vector3 velocity) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) Rigidbody[] componentsInChildren = ((Component)this).GetComponentsInChildren<Rigidbody>(true); foreach (Rigidbody obj in componentsInChildren) { obj.isKinematic = false; obj.velocity = velocity; } } } [BepInPlugin("GhostPossession", "GhostPossession", "0.2.0")] public class GhostPossessionPlugin : BaseUnityPlugin { private Harmony _harmony; private GhostController _ghostController; private PossessionManager _possessionManager; private DebugOverlay _debugOverlay; private CreatureSpawnMenu _spawnMenu; private ItemSpawnMenu _itemSpawnMenu; private EventMenu _eventMenu; private PlayerTeleportMenu _playerTeleportMenu; private GlobalGravityController _globalGravity; private bool _initialized; private float _debugHotkeyCooldown; public static GhostPossessionPlugin Instance { get; private set; } public bool IsGhostMode { get { if (_ghostController != null) { return _ghostController.IsGhostMode; } return false; } } private void Awake() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown Instance = this; ModConfig.Init(((BaseUnityPlugin)this).Config); _ghostController = new GhostController(); _possessionManager = new PossessionManager(); _debugOverlay = new DebugOverlay(); _spawnMenu = new CreatureSpawnMenu(); _itemSpawnMenu = new ItemSpawnMenu(); _eventMenu = new EventMenu(); _playerTeleportMenu = new PlayerTeleportMenu(); _globalGravity = new GlobalGravityController(); Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(HandleCameraPreCull)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] Plugin loaded"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] Attempting to patch death and run-end hooks"); try { _harmony = new Harmony("GhostPossession.Patches"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] Harmony patches active"); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"[GhostPossession] Harmony patch failed: {arg}"); } _initialized = true; } private void Update() { if (!_initialized) { return; } _debugHotkeyCooldown -= Time.deltaTime; HandleDebugHotkeys(); _ghostController.Update(); _possessionManager.Update(); _debugOverlay.Update(); _spawnMenu.Update(); _itemSpawnMenu.Update(); _eventMenu.Update(); _playerTeleportMenu.Update(); _globalGravity.Update(); if (Input.GetKeyDown((KeyCode)101) && _ghostController.IsGhostMode) { if (_possessionManager.IsPossessing) { _possessionManager.Release(); } else { _possessionManager.TryPossessCurrentTarget(); } } } private void OnDestroy() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(HandleCameraPreCull)); _ghostController?.Cleanup(); _possessionManager?.Release(); _globalGravity?.Cleanup(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void HandleDebugHotkeys() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (_debugHotkeyCooldown > 0f) { return; } if (IsGhostMode && Input.GetKeyDown(ModConfig.ReviveKey)) { _debugHotkeyCooldown = 0.25f; if (ModConfig.DebugLogging) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] DEBUG: revive-at-ghost hotkey received"); } ReviveAtGhostSpot(); return; } KeyCode[] array = new KeyCode[4]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); if (IsAnyKeyDown((KeyCode[])(object)array)) { _debugHotkeyCooldown = 0.25f; if (ModConfig.DebugLogging) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] DEBUG: death hotkey received"); } TriggerDebugDeath(); return; } KeyCode[] array2 = new KeyCode[4]; RuntimeHelpers.InitializeArray(array2, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); if (IsAnyKeyDown((KeyCode[])(object)array2)) { _debugHotkeyCooldown = 0.25f; if (ModConfig.DebugLogging) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] DEBUG: run-end hotkey received"); } if (ModConfig.DebugPreventRunEnd) { if (ModConfig.DebugLogging) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] Debug run end requested"); } RunEndHelper.ForceRunEndIfPossible(); } return; } KeyCode[] array3 = new KeyCode[3]; RuntimeHelpers.InitializeArray(array3, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); if (IsAnyKeyDown((KeyCode[])(object)array3)) { _debugHotkeyCooldown = 0.25f; if (ModConfig.DebugLogging) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] DEBUG: overlay hotkey received"); } _debugOverlay.Enabled = !_debugOverlay.Enabled; } } private void HandleCameraPreCull(Camera camera) { if (_initialized && (Object)(object)camera == (Object)(object)Camera.main) { _ghostController.ApplyCameraPose(); SpawnedTestScoutMarker.ForceAllVisible(); } } private void LateUpdate() { if (_initialized && !_spawnMenu.IsOpen && !_itemSpawnMenu.IsOpen && !_eventMenu.IsOpen && !_playerTeleportMenu.IsOpen) { _ghostController.LateUpdate(); } } private void FixedUpdate() { if (_initialized) { _globalGravity?.FixedUpdate(); } } private void OnGUI() { if (_initialized) { _spawnMenu.OnGUI(); _itemSpawnMenu.OnGUI(); _eventMenu.OnGUI(); _playerTeleportMenu.OnGUI(); _globalGravity.OnGUI(); _possessionManager.DrawHud(); } } private static bool IsAnyKeyDown(params KeyCode[] keys) { for (int i = 0; i < keys.Length; i++) { if (Input.GetKeyDown(keys[i])) { return true; } } return false; } public void TriggerDebugDeath() { if (IsGhostMode) { LogState("Already in ghost mode"); return; } Character localCharacter = PlayerReflection.GetLocalCharacter(); if ((Object)(object)localCharacter == (Object)null) { if (ModConfig.DebugLogging) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[GhostPossession] Debug death hotkey pressed but local Character was not found"); } return; } if (ModConfig.DebugLogging) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] DEBUG: killing local player"); } PlayerReflection.KillLocalCharacter(localCharacter); EnterGhostModeAfterDeath(); if (ModConfig.DebugPreventRunEnd && ModConfig.DebugLogging) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] Prevented run end for debug ghost test"); } } public void EnterGhostModeAfterDeath() { if (!_ghostController.IsGhostMode) { _ghostController.EnterGhostMode(); } } public void ReviveAtGhostSpot() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) if (_ghostController == null || !_ghostController.IsGhostMode) { LogState("Revive-at-ghost ignored: not in ghost mode"); return; } if (!TryGetGhostTeleportPosition(out var position)) { LogState("Revive-at-ghost failed: ghost position is unavailable"); return; } if (_possessionManager != null && _possessionManager.IsPossessing) { _possessionManager.Release(); } _ghostController.ReviveAtGhostPosition(position, ModConfig.ReviveApplyStatus); } public void SetPossessionCameraTarget(GameObject target) { _ghostController.SetPossessionTarget(((Object)(object)target != (Object)null) ? target.transform : null); } public void ReapplyGhostCamera() { _ghostController?.ApplyCameraPose(); _possessionManager?.ReapplyCreatureFacing(); } public bool TryGetPossessionCameraAnchor(out Vector3 position) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (_possessionManager != null) { return _possessionManager.TryGetCameraAnchor(out position); } position = Vector3.zero; return false; } public bool TryGetGhostTeleportPosition(out Vector3 position) { //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_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) if (_possessionManager != null && _possessionManager.TryGetCameraAnchor(out position)) { return true; } if (_ghostController != null && _ghostController.IsGhostMode) { position = _ghostController.GhostPosition; return true; } position = Vector3.zero; return false; } public void ApplyPossessionFixedInput(Character character) { _possessionManager?.ApplyBeforeCharacterFixedUpdate(character); } public void LogLocalTarget(string message) { if (ModConfig.DebugLogging) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[GhostPossession] Target: " + message)); } } public void LogState(string message) { if (ModConfig.DebugLogging) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[GhostPossession] " + message)); } } } public class GhostController { private Transform _cameraTransform; private float _pitch; private float _yaw; private Character _character; private CharacterInput _characterInput; private Transform _possessionTarget; private Vector3 _ghostPosition; private Quaternion _cameraRotation = Quaternion.identity; private readonly Dictionary<Renderer, bool> _rendererStates = new Dictionary<Renderer, bool>(); public bool IsGhostMode { get; private set; } public bool IsFreeFlyEnabled { get; private set; } public Vector3 GhostPosition => _ghostPosition; public void Update() { } public void LateUpdate() { if (IsGhostMode) { UpdateGhostMovement(); } } public void EnterGhostMode() { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: 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) IsGhostMode = true; IsFreeFlyEnabled = true; _character = PlayerReflection.GetLocalCharacter(); if ((Object)(object)_character != (Object)null) { _characterInput = _character.input; if ((Object)(object)_characterInput != (Object)null) { ResetInput(_characterInput); ((Behaviour)_characterInput).enabled = false; } _rendererStates.Clear(); Renderer[] componentsInChildren = ((Component)_character).GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { _rendererStates[val] = val.enabled; val.enabled = false; } } Camera main = Camera.main; if ((Object)(object)main != (Object)null) { _cameraTransform = ((Component)main).transform; _pitch = 0f; _yaw = _cameraTransform.eulerAngles.y; _ghostPosition = _cameraTransform.position; _cameraRotation = _cameraTransform.rotation; } GhostPossessionPlugin.Instance?.LogState("Entering free ghost mode"); } public void ExitGhostMode() { IsGhostMode = false; IsFreeFlyEnabled = false; RestoreCharacter(); GhostPossessionPlugin.Instance?.LogState("Leaving ghost mode"); } public unsafe bool ReviveAtGhostPosition(Vector3 position, bool applyStatus) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (!IsGhostMode) { return false; } Character val = PlayerReflection.GetLocalCharacter() ?? _character; if ((Object)(object)val == (Object)null) { GhostPossessionPlugin.Instance?.LogState("Revive failed: local Character was not found"); return false; } if (!PlayerReflection.ReviveLocalCharacterAt(val, position, applyStatus)) { return false; } IsGhostMode = false; IsFreeFlyEnabled = false; _possessionTarget = null; RestoreCharacter(); GhostPossessionPlugin.Instance?.LogState("Revived as human at ghost position " + ((object)(*(Vector3*)(&position))/*cast due to .constrained prefix*/).ToString()); return true; } public void SetPossessionTarget(Transform target) { _possessionTarget = target; } public void Cleanup() { IsGhostMode = false; IsFreeFlyEnabled = false; _possessionTarget = null; RestoreCharacter(); } private void RestoreCharacter() { foreach (KeyValuePair<Renderer, bool> rendererState in _rendererStates) { if ((Object)(object)rendererState.Key != (Object)null) { rendererState.Key.enabled = rendererState.Value; } } _rendererStates.Clear(); if ((Object)(object)_characterInput != (Object)null) { ((Behaviour)_characterInput).enabled = true; ResetInput(_characterInput); } _characterInput = null; _character = null; } private static void ResetInput(CharacterInput input) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_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) input.movementInput = Vector2.zero; input.lookInput = Vector2.zero; input.sprintIsPressed = false; input.jumpIsPressed = false; input.jumpWasPressed = false; input.usePrimaryIsPressed = false; input.usePrimaryWasPressed = false; input.useSecondaryIsPressed = false; input.useSecondaryWasPressed = false; } private void UpdateGhostMovement() { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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_00c2: 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_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: 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_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: 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_00ee: 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_00f4: 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_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: 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_013c: 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_0151: 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_0155: 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_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017b: 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_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Camera.main == (Object)null) { return; } float num = ModConfig.GhostSpeed; if (Input.GetKey((KeyCode)304)) { num *= ModConfig.GhostSprintMultiplier; } float axis = Input.GetAxis("Mouse X"); float axis2 = Input.GetAxis("Mouse Y"); _yaw += axis * 2.2f; _pitch -= axis2 * 1.8f; _pitch = Mathf.Clamp(_pitch, -85f, 85f); _cameraRotation = Quaternion.Euler(_pitch, _yaw, 0f); if ((Object)(object)_possessionTarget != (Object)null) { ApplyCameraPose(); return; } Vector3 val = _cameraRotation * Vector3.forward; Vector3 val2 = _cameraRotation * Vector3.right; Vector3 up = Vector3.up; Vector3 val3 = Vector3.zero; if (Input.GetKey((KeyCode)119)) { val3 += val; } if (Input.GetKey((KeyCode)115)) { val3 -= val; } if (Input.GetKey((KeyCode)100)) { val3 += val2; } if (Input.GetKey((KeyCode)97)) { val3 -= val2; } if (Input.GetKey((KeyCode)32)) { val3 += up; } if (Input.GetKey((KeyCode)306)) { val3 -= up; } if (((Vector3)(ref val3)).sqrMagnitude > 0f) { ((Vector3)(ref val3)).Normalize(); _ghostPosition += val3 * num * Time.deltaTime; } ApplyCameraPose(); } public void ApplyCameraPose() { //IL_0020: 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_0059: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_0079: 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) if (!IsGhostMode) { return; } Camera main = Camera.main; if (!((Object)(object)main == (Object)null)) { ((Component)main).transform.rotation = _cameraRotation; if ((Object)(object)_possessionTarget != (Object)null && (Object)(object)GhostPossessionPlugin.Instance != (Object)null && GhostPossessionPlugin.Instance.TryGetPossessionCameraAnchor(out var position)) { ((Component)main).transform.position = position + Vector3.up * 2.2f - _cameraRotation * Vector3.forward * 4f; } else { ((Component)main).transform.position = _ghostPosition; } } } } [HarmonyPatch(typeof(MainCameraMovement), "LateUpdate")] public static class MainCameraMovementGhostPatch { public static void Postfix() { GhostPossessionPlugin.Instance?.ReapplyGhostCamera(); } } [HarmonyPatch(typeof(MainCamera), "LateUpdate")] public static class MainCameraGhostPatch { public static void Postfix() { GhostPossessionPlugin.Instance?.ReapplyGhostCamera(); } } [HarmonyPatch(typeof(Character), "FixedUpdate")] public static class PossessedCharacterFixedUpdatePatch { public static void Prefix(Character __instance) { GhostPossessionPlugin.Instance?.ApplyPossessionFixedInput(__instance); } } [HarmonyPatch(typeof(Character), "Die")] public static class DiePatch { public static void Prefix(Character __instance, ref bool __state) { __state = PlayerReflection.IsLocalCharacter(__instance); } public static void Postfix(bool __state) { if (__state) { GhostPossessionPlugin.Instance?.LogState("Local player died"); GhostPossessionPlugin.Instance?.EnterGhostModeAfterDeath(); } } } [HarmonyPatch(typeof(Character), "NobodyIsAlive")] public static class NobodyIsAlivePatch { public static void Postfix(ref bool __result) { if ((Object)(object)GhostPossessionPlugin.Instance != (Object)null && GhostPossessionPlugin.Instance.IsGhostMode) { __result = false; } } } [HarmonyPatch(typeof(Scoutmaster), "CanSeeTarget")] public static class ScoutmasterCanSeeGhostPatch { public static void Postfix(Character currentTarget, ref bool __result) { if (__result && (Object)(object)GhostPossessionPlugin.Instance != (Object)null && GhostPossessionPlugin.Instance.IsGhostMode && PlayerReflection.IsLocalCharacter(currentTarget)) { __result = false; } } } [HarmonyPatch(typeof(Character), "CheckEndGame")] public static class RunEndPatch { public static bool Prefix(Character __instance) { if (!ModConfig.DebugPreventRunEnd || RunEndHelper.AllowNextRunEnd) { RunEndHelper.AllowNextRunEnd = false; return true; } if (PlayerReflection.IsLocalCharacter(__instance)) { GhostPossessionPlugin.Instance?.LogState("Prevented run end for debug ghost test"); return false; } return true; } } public class CreaturePossessable : IPossessable { private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private readonly Component _component; private readonly Scoutmaster _scoutmaster; private readonly Mob _mob; private readonly Character _controlledCharacter; private readonly CharacterInput _input; private readonly Rigidbody _body; private readonly Behaviour _aiBehaviour; private readonly GameObject _followObject; private readonly Rigidbody[] _characterBodies; private readonly FieldInfo _mobSleepingField; private readonly FieldInfo _mobForceNoMovementField; private bool _wasAiEnabled; private SpawnedTestScoutMarker _heldDummy; public bool IsValid { get { if ((Object)(object)_component != (Object)null) { return (Object)(object)_component.gameObject != (Object)null; } return false; } } public GameObject GameObject => _followObject; public Vector3 CameraAnchorPosition { get { //IL_003f: 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_0027: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_controlledCharacter != (Object)null)) { if (!((Object)(object)_body != (Object)null)) { return _component.transform.position; } return _body.worldCenterOfMass; } return _controlledCharacter.Center; } } public string DisplayName { get { if (!((Object)(object)_component != (Object)null)) { return "Creature"; } return ((object)_component).GetType().Name; } } public string ControlsText { get { if ((Object)(object)_scoutmaster != (Object)null) { return "WASD move | C climb | Space jump | Shift sprint | LMB grab | RMB FORCE THROW | E exit"; } if (_component is Beetle) { return "WASD move | Shift sprint | LMB bonk player | E exit"; } if (_component is Scorpion) { return "WASD move | Shift sprint | LMB sting player | E exit"; } if (_component is MushroomZombie) { return "WASD move | Shift sprint | LMB lunge at player | E exit"; } if (_component is BeeSwarm) { return "WASD fly | Space up | LMB anger at player | E exit"; } if (_component is Spider) { return "LMB grab player | RMB release | E exit"; } if (_component is FrogTongue) { return "WASD move | Shift sprint | LMB tongue attack | E exit"; } if (_component is GhostBall) { return "WASD float | Space jump | Shift sprint | E exit"; } return "WASD move | Space jump | Shift sprint | E exit"; } } public CreaturePossessable(Component component) { _component = component; _scoutmaster = (Scoutmaster)(object)((component is Scoutmaster) ? component : null); _mob = (Mob)(object)((component is Mob) ? component : null); _controlledCharacter = (((Object)(object)component != (Object)null) ? (component.GetComponent<Character>() ?? component.GetComponentInChildren<Character>() ?? component.GetComponentInParent<Character>()) : null); _input = (((Object)(object)_controlledCharacter != (Object)null) ? _controlledCharacter.input : null); _body = (Rigidbody)(((Object)(object)_mob != (Object)null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)(((Object)(object)component != (Object)null) ? (component.GetComponent<Rigidbody>() ?? component.GetComponentInChildren<Rigidbody>() ?? component.GetComponentInParent<Rigidbody>()) : null))); _aiBehaviour = (Behaviour)(object)((component is Behaviour) ? component : null); _followObject = (((Object)(object)_controlledCharacter != (Object)null) ? ((Component)_controlledCharacter).gameObject : (((Object)(object)_body != (Object)null) ? ((Component)_body).gameObject : component.gameObject)); _characterBodies = (Rigidbody[])(((Object)(object)_controlledCharacter != (Object)null) ? ((Array)((Component)_controlledCharacter).GetComponentsInChildren<Rigidbody>(true)) : ((Array)new Rigidbody[0])); _mobSleepingField = typeof(Mob).GetField("sleeping", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _mobForceNoMovementField = typeof(Mob).GetField("forceNoMovement", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } public void Enter() { if ((Object)(object)_input == (Object)null && (Object)(object)_body == (Object)null) { GhostPossessionPlugin.Instance?.LogState("Creature has no movable controller"); return; } _wasAiEnabled = (Object)(object)_aiBehaviour != (Object)null && _aiBehaviour.enabled; if ((Object)(object)_aiBehaviour != (Object)null && !(_component is BeeSwarm) && !(_component is FrogTongue)) { _aiBehaviour.enabled = false; } ResetInput(); GhostPossessionPlugin.Instance?.LogState("Creature control enabled"); } public void Exit() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_heldDummy != (Object)null) { _heldDummy.Throw(Vector3.zero); _heldDummy = null; } ResetInput(); if ((Object)(object)_aiBehaviour != (Object)null) { _aiBehaviour.enabled = _wasAiEnabled; } GhostPossessionPlugin.Instance?.LogState("Creature possession released"); } public void UpdateInput() { //IL_0045: 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_00c8: 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: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: 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_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_021f: 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_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0268: 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_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: 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) if (!IsValid) { return; } Camera main = Camera.main; ApplyFacing(main); UpdateHeldDummy(main); if ((Object)(object)_input != (Object)null) { _input.movementInput = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")); _input.sprintIsPressed = Input.GetKey((KeyCode)304); _input.jumpIsPressed = Input.GetKey((KeyCode)32); _input.jumpWasPressed = Input.GetKeyDown((KeyCode)32); if ((Object)(object)_scoutmaster != (Object)null) { UpdateScoutmasterClimbing(main); } } else if ((Object)(object)_body != (Object)null && (Object)(object)main != (Object)null) { Vector3 val = ((Component)main).transform.forward * Input.GetAxisRaw("Vertical") + ((Component)main).transform.right * Input.GetAxisRaw("Horizontal"); val.y = 0f; float num = (Input.GetKey((KeyCode)304) ? 6f : 3.5f); if ((Object)(object)_mob != (Object)null) { _mobSleepingField?.SetValue(_mob, false); _mobForceNoMovementField?.SetValue(_mob, _component is FrogTongue); if (((Vector3)(ref val)).sqrMagnitude > 0f) { _body.MovePosition(_body.position + ((Vector3)(ref val)).normalized * num * Time.deltaTime); } } else { Vector3 val2 = ((((Vector3)(ref val)).sqrMagnitude > 0f) ? (((Vector3)(ref val)).normalized * num) : Vector3.zero); Vector3 val3 = Vector3.MoveTowards(new Vector3(_body.velocity.x, 0f, _body.velocity.z), val2, 12f * Time.deltaTime); _body.velocity = new Vector3(val3.x, _body.velocity.y, val3.z); if (Input.GetKeyDown((KeyCode)32)) { _body.AddForce(Vector3.up * ModConfig.PossessionJumpForce, (ForceMode)1); } } } if (Input.GetMouseButtonDown(0)) { UsePrimaryAttack(); } if (((Object)(object)_scoutmaster != (Object)null || _component is Spider) && Input.GetMouseButtonDown(1)) { if ((Object)(object)_heldDummy != (Object)null) { Vector3 val4 = (((Object)(object)main != (Object)null) ? ((Component)main).transform.forward : _component.transform.forward); _heldDummy.Throw(val4 * 14f + Vector3.up * 5f); _heldDummy = null; } else if ((Object)(object)_scoutmaster != (Object)null) { ForceScoutmasterThrow(main); } else { Invoke("RPCA_LetGo"); } } } private void ForceScoutmasterThrow(Camera camera) { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0152: 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) if ((Object)(object)_controlledCharacter == (Object)null || (Object)(object)_controlledCharacter.data == (Object)null || _controlledCharacter.refs == null || (Object)(object)_controlledCharacter.refs.grabbing == (Object)null) { GhostPossessionPlugin.Instance?.LogState("Scoutmaster throw: grabbing controller is unavailable"); return; } object? obj = typeof(CharacterData).GetField("grabbedPlayer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(_controlledCharacter.data); Character val = (Character)((obj is Character) ? obj : null); if ((Object)(object)val == (Object)null) { GhostPossessionPlugin.Instance?.LogState("Scoutmaster throw: no grabbed player (grab with LMB first)"); return; } Vector3 val2 = (((Object)(object)camera != (Object)null) ? ((Component)camera).transform.forward : _component.transform.forward); if (((Vector3)(ref val2)).sqrMagnitude < 0.001f) { val2 = _component.transform.forward; } ((Vector3)(ref val2)).Normalize(); val2.y = Mathf.Max(val2.y, 0.3f); try { MethodInfo? method = typeof(CharacterGrabbing).GetMethod("Throw", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { throw new MissingMethodException("CharacterGrabbing.Throw"); } method.Invoke(_controlledCharacter.refs.grabbing, new object[2] { val2 * 1500f, 3f }); typeof(Scoutmaster).GetField("isThrowing", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(_scoutmaster, false); GhostPossessionPlugin.Instance?.LogState("Scoutmaster force-threw " + ((Object)val).name); } catch (Exception ex) { Debug.LogError((object)("[GhostPossession] Scoutmaster forced throw failed: " + ex)); } } private void ApplyFacing(Camera camera) { //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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0073: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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_00df: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)camera == (Object)null) { return; } Vector3 forward = ((Component)camera).transform.forward; forward.y = 0f; if (!(((Vector3)(ref forward)).sqrMagnitude < 0.001f)) { Quaternion val = Quaternion.LookRotation(((Vector3)(ref forward)).normalized, Vector3.up); if ((Object)(object)_scoutmaster != (Object)null && (Object)(object)_controlledCharacter != (Object)null) { Invoke("LookAt", _controlledCharacter.Center + ((Vector3)(ref forward)).normalized * 10f); } else if (_component is MushroomZombie && (Object)(object)_controlledCharacter != (Object)null) { Invoke("LookAt", _controlledCharacter.Center + ((Vector3)(ref forward)).normalized * 10f); } else if ((Object)(object)_body != (Object)null) { _body.MoveRotation(val); } else { _component.transform.rotation = val; } } } public void ReapplyFacing() { if (IsValid) { ApplyFacing(Camera.main); } } public void ApplyBeforeCharacterFixedUpdate(Character character) { //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) if (IsValid && !((Object)(object)character == (Object)null) && !((Object)(object)character != (Object)(object)_controlledCharacter) && !((Object)(object)_input == (Object)null)) { _input.movementInput = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")); _input.sprintIsPressed = Input.GetKey((KeyCode)304); _input.jumpIsPressed = Input.GetKey((KeyCode)32); _input.jumpWasPressed = Input.GetKeyDown((KeyCode)32); if ((Object)(object)_scoutmaster != (Object)null) { UpdateScoutmasterClimbing(Camera.main); ApplyScoutmasterClimbForce(Camera.main); } } } private void UsePrimaryAttack() { SpawnedTestScoutMarker spawnedTestScoutMarker = FindNearestDummy(4f); if ((Object)(object)spawnedTestScoutMarker != (Object)null) { AttackDummy(spawnedTestScoutMarker); return; } Character val = FindNearestLivingPlayer(6f); if ((Object)(object)val == (Object)null) { GhostPossessionPlugin.Instance?.LogState("Attack: no target within 6 meters"); } else if ((Object)(object)_scoutmaster != (Object)null) { ForceScoutmasterGrab(val); } else if (_component is Beetle || _component is Scorpion) { ForceMobAttack(val); } else if (_component is MushroomZombie) { Invoke("SetCurrentTarget", val, 5f); Invoke("StartLunging"); } else if (_component is BeeSwarm) { ((object)_component).GetType().GetField("currentAggroCharacter", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(_component, val); Invoke("SetBeesAngryRPC", true); Invoke("GetAngry", 12f); } else if (_component is Spider) { object obj = typeof(Character).GetField("view", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(val); Invoke("RPCA_GrabCharacter", obj); } else if (_component is FrogTongue) { ForceFrogAttack(val); } } private void ForceScoutmasterGrab(Character target) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) try { object? obj = typeof(Character).GetField("view", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(_controlledCharacter); object? obj2 = ((obj is PhotonView) ? obj : null); object? obj3 = typeof(Character).GetField("view", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target); PhotonView val = (PhotonView)((obj3 is PhotonView) ? obj3 : null); if ((Object)obj2 == (Object)null || (Object)(object)val == (Object)null) { throw new InvalidOperationException("missing PhotonView"); } ((PhotonView)obj2).RPC("RPCA_GrabAttach", (RpcTarget)0, new object[3] { val, 0, Vector3.zero }); Invoke("SetCurrentTarget", target, 8f); GhostPossessionPlugin.Instance?.LogState("Scoutmaster grabbed " + target.characterName + " (RMB to throw)"); } catch (Exception ex) { Debug.LogError((object)("[GhostPossession] Scoutmaster forced grab failed: " + ex)); } } private void ForceMobAttack(Character target) { try { PhotonView val = (((Object)(object)_mob != (Object)null) ? ((MonoBehaviourPun)_mob).photonView : null); object? obj = typeof(Character).GetField("view", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target); PhotonView val2 = (PhotonView)((obj is PhotonView) ? obj : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { throw new InvalidOperationException("missing PhotonView"); } val.RPC("RPC_SyncTargetCharacter", (RpcTarget)0, new object[1] { val2.ViewID }); val.RPC("RPC_StartAttack", (RpcTarget)0, Array.Empty<object>()); typeof(Mob).GetField("inRangeForAttackTime", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(_mob, typeof(Mob).GetField("attackTime", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(_mob) ?? ((object)0f)); GhostPossessionPlugin.Instance?.LogState(DisplayName + " network attack -> " + target.characterName); } catch (Exception ex) { Debug.LogError((object)("[GhostPossession] Mob network attack failed: " + ex)); } } private void ForceFrogAttack(Character target) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) try { Component component = _component; FrogTongue val = (FrogTongue)(object)((component is FrogTongue) ? component : null); PhotonView obj = (((Object)(object)val != (Object)null) ? ((MonoBehaviourPun)val).photonView : null); object? obj2 = typeof(Character).GetField("view", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target); PhotonView val2 = (PhotonView)((obj2 is PhotonView) ? obj2 : null); if ((Object)(object)obj == (Object)null || (Object)(object)val2 == (Object)null) { throw new InvalidOperationException("missing PhotonView"); } obj.RPC("RPCA_FrogAction", (RpcTarget)0, new object[3] { val2, (object)(FrogActionType)1, target.Center }); GhostPossessionPlugin.Instance?.LogState("Frog tongue attack -> " + target.characterName); } catch (Exception ex) { Debug.LogError((object)("[GhostPossession] Frog network attack failed: " + ex)); } } private void AttackDummy(SpawnedTestScoutMarker dummy) { Character targetCharacter = dummy.TargetCharacter; if ((Object)(object)_scoutmaster != (Object)null || _component is Spider) { _heldDummy = dummy; GhostPossessionPlugin.Instance?.LogState(DisplayName + " grabbed Test scout"); } else if ((_component is Beetle || _component is Scorpion) && (Object)(object)targetCharacter != (Object)null) { Invoke("InflictAttack", targetCharacter); GhostPossessionPlugin.Instance?.LogState(DisplayName + " attacked Test scout"); } else if (_component is MushroomZombie && (Object)(object)targetCharacter != (Object)null) { Invoke("OnBitCharacter", targetCharacter); GhostPossessionPlugin.Instance?.LogState("MushroomZombie bit Test scout"); } else if (_component is BeeSwarm && (Object)(object)targetCharacter != (Object)null) { ((object)_component).GetType().GetField("currentAggroCharacter", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(_component, targetCharacter); Invoke("SetBeesAngryRPC", true); Invoke("GetAngry", 12f); GhostPossessionPlugin.Instance?.LogState("BeeSwarm angered at Test scout"); } } private SpawnedTestScoutMarker FindNearestDummy(float maxDistance) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_001f: Unknown result type (might be due to invalid IL or missing references) SpawnedTestScoutMarker result = null; float num = maxDistance; Vector3 cameraAnchorPosition = CameraAnchorPosition; SpawnedTestScoutMarker[] array = Object.FindObjectsOfType<SpawnedTestScoutMarker>(); foreach (SpawnedTestScoutMarker spawnedTestScoutMarker in array) { float num2 = Vector3.Distance(cameraAnchorPosition, spawnedTestScoutMarker.WorldCenter); if (num2 < num) { result = spawnedTestScoutMarker; num = num2; } } return result; } private Character FindNearestLivingPlayer(float maxDistance) { //IL_0020: 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_0025: 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) Character result = null; float num = maxDistance; Vector3 val = (((Object)(object)_controlledCharacter != (Object)null) ? _controlledCharacter.Center : CameraAnchorPosition); foreach (Character allCharacter in Character.AllCharacters) { if (!((Object)(object)allCharacter == (Object)null) && !allCharacter.isBot && !((Object)(object)allCharacter.data == (Object)null) && !allCharacter.data.dead) { float num2 = Vector3.Distance(val, allCharacter.Center); if (num2 < num) { result = allCharacter; num = num2; } } } return result; } private void UpdateScoutmasterClimbing(Camera camera) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009e: 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_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)camera == (Object)null) && !((Object)(object)_controlledCharacter == (Object)null) && Input.GetKey((KeyCode)99)) { Vector3 forward = ((Component)camera).transform.forward; Vector3 val = _controlledCharacter.Center + Vector3.up * 0.5f; RaycastHit val3 = default(RaycastHit); Vector3 val2 = ((Physics.Raycast(val, forward, ref val3, 3f, -1, (QueryTriggerInteraction)1) && Vector3.Angle(((RaycastHit)(ref val3)).normal, Vector3.up) > 45f) ? (((RaycastHit)(ref val3)).point + Vector3.up * 3f) : (val + ((Vector3)(ref forward)).normalized * 5f + Vector3.up * 3f)); Invoke("ClimbTowards", val2, Input.GetKey((KeyCode)304) ? 1.6f : 1f); } } private void ApplyScoutmasterClimbForce(Camera camera) { //IL_0019: 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_007c: 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_008d: 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_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_00af: Unknown result type (might be due to invalid IL or missing references) if (!Input.GetKey((KeyCode)99) || (Object)(object)camera == (Object)null) { return; } Vector3 forward = ((Component)camera).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude > 0f) { ((Vector3)(ref forward)).Normalize(); } float num = (Input.GetKey((KeyCode)304) ? 5f : 3.2f); Rigidbody[] characterBodies = _characterBodies; foreach (Rigidbody val in characterBodies) { if (!((Object)(object)val == (Object)null) && !val.isKinematic) { Vector3 val2 = forward * 1.8f + Vector3.up * num; val.velocity = Vector3.MoveTowards(val.velocity, val2, 14f * Time.fixedDeltaTime); } } } private void UpdateHeldDummy(Camera camera) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_00a2: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_heldDummy == (Object)null) && (!((Object)(object)_scoutmaster == (Object)null) || _component is Spider)) { Vector3 val = (((Object)(object)camera != (Object)null) ? ((Component)camera).transform.forward : _component.transform.forward); val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { val = _component.transform.forward; } Vector3 val2 = (((Object)(object)_controlledCharacter != (Object)null) ? _controlledCharacter.Center : _component.transform.position); _heldDummy.HoldAt(val2 + Vector3.up * 1.2f + ((Vector3)(ref val)).normalized * 1.8f, Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up)); } } private void Invoke(string name, params object[] arguments) { try { ((object)_component).GetType().GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(_component, arguments); } catch (Exception ex) { Debug.LogError((object)("[GhostPossession] Creature action failed: " + ex)); } } private void ResetInput() { //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_0025: 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) if (!((Object)(object)_input == (Object)null)) { _input.movementInput = Vector2.zero; _input.lookInput = Vector2.zero; _input.sprintIsPressed = false; _input.jumpIsPressed = false; _input.jumpWasPressed = false; _input.usePrimaryIsPressed = false; _input.usePrimaryWasPressed = false; _input.useSecondaryIsPressed = false; _input.useSecondaryWasPressed = false; } } } public static class CreatureSupport { public static Component FindCreature(GameObject gameObject) { if ((Object)(object)gameObject == (Object)null) { return null; } Component val = (Component)(object)(gameObject.GetComponentInParent<Scoutmaster>() ?? gameObject.GetComponentInChildren<Scoutmaster>()); if ((Object)(object)val != (Object)null) { return val; } val = (Component)(object)(gameObject.GetComponentInParent<MushroomZombie>() ?? gameObject.GetComponentInChildren<MushroomZombie>()); if ((Object)(object)val != (Object)null) { return val; } val = (Component)(object)(gameObject.GetComponentInParent<Beetle>() ?? gameObject.GetComponentInChildren<Beetle>()); if ((Object)(object)val != (Object)null) { return val; } val = (Component)(object)(gameObject.GetComponentInParent<Scorpion>() ?? gameObject.GetComponentInChildren<Scorpion>()); if ((Object)(object)val != (Object)null) { return val; } val = (Component)(object)(gameObject.GetComponentInParent<BeeSwarm>() ?? gameObject.GetComponentInChildren<BeeSwarm>()); if ((Object)(object)val != (Object)null) { return val; } val = (Component)(object)(gameObject.GetComponentInParent<FrogTongue>() ?? gameObject.GetComponentInChildren<FrogTongue>()); if ((Object)(object)val != (Object)null) { return val; } val = (Component)(object)(gameObject.GetComponentInParent<GhostBall>() ?? gameObject.GetComponentInChildren<GhostBall>()); if ((Object)(object)val != (Object)null) { return val; } return (Component)(object)(gameObject.GetComponentInParent<Spider>() ?? gameObject.GetComponentInChildren<Spider>()); } } public class InteractablePossessable : IPossessable { private readonly Component _component; public bool IsValid { get { if ((Object)(object)_component != (Object)null) { return (Object)(object)_component.gameObject != (Object)null; } return false; } } public GameObject GameObject { get { if (!((Object)(object)_component != (Object)null)) { return null; } return _component.gameObject; } } public string DisplayName { get { if (!((Object)(object)_component != (Object)null)) { return "Interactable"; } return ((Object)_component).name; } } public InteractablePossessable(Component component) { _component = component; } public void Enter() { GhostPossessionPlugin.Instance?.LogState("Interactable possession placeholder"); } public void Exit() { GhostPossessionPlugin.Instance?.LogState("Released interactable possession"); } public void UpdateInput() { } } public interface IPossessable { bool IsValid { get; } GameObject GameObject { get; } string DisplayName { get; } void Enter(); void Exit(); void UpdateInput(); } public class PossessionManager { private IPossessable _currentPossession; private readonly List<GameObject> _recentTargets = new List<GameObject>(); private float _scanTimer; private const float ScanInterval = 2f; public bool IsPossessing { get { if (_currentPossession != null) { return _currentPossession.IsValid; } return false; } } public void DrawHud() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (IsPossessing) { string text = ((_currentPossession is CreaturePossessable creaturePossessable) ? creaturePossessable.ControlsText : "WASD — движение | Space — импульс | E — выйти"); GUI.Box(new Rect(20f, 20f, 460f, 74f), "ВСЕЛЕНИЕ: " + _currentPossession.DisplayName + "\n" + text); } } public void ReapplyCreatureFacing() { (_currentPossession as CreaturePossessable)?.ReapplyFacing(); } public bool TryGetCameraAnchor(out Vector3 position) { //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_0019: 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_005e: 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) if (_currentPossession is CreaturePossessable { IsValid: not false } creaturePossessable) { position = creaturePossessable.CameraAnchorPosition; return true; } if (_currentPossession != null && _currentPossession.IsValid && (Object)(object)_currentPossession.GameObject != (Object)null) { position = _currentPossession.GameObject.transform.position; return true; } position = Vector3.zero; return false; } public void ApplyBeforeCharacterFixedUpdate(Character character) { (_currentPossession as CreaturePossessable)?.ApplyBeforeCharacterFixedUpdate(character); } public void Update() { if ((Object)(object)GhostPossessionPlugin.Instance == (Object)null) { return; } if (!GhostPossessionPlugin.Instance.IsGhostMode) { if (_currentPossession != null) { Release(); } return; } if (_currentPossession != null && !_currentPossession.IsValid) { Release(); return; } if (_currentPossession != null) { _currentPossession.UpdateInput(); return; } _scanTimer -= Time.deltaTime; if (_scanTimer <= 0f) { _scanTimer = 2f; ScanNearbyTargets(); } } public void TryPossessCurrentTarget() { GameObject nearestCandidate = GetNearestCandidate(); if ((Object)(object)nearestCandidate == (Object)null) { GhostPossessionPlugin.Instance?.LogState("No possession target in range"); return; } if (!IsLocalHost()) { GhostPossessionPlugin.Instance?.LogState("Cannot possess network object: no authority"); return; } Component val = CreatureSupport.FindCreature(nearestCandidate); if ((Object)(object)val != (Object)null) { _currentPossession = new CreaturePossessable(val); _currentPossession.Enter(); GhostPossessionPlugin.Instance?.SetPossessionCameraTarget(_currentPossession.GameObject); GhostPossessionPlugin.Instance?.LogState("Possessing " + ((object)val).GetType().Name); return; } Rigidbody val2 = nearestCandidate.GetComponent<Rigidbody>() ?? nearestCandidate.GetComponentInChildren<Rigidbody>(); if ((Object)(object)val2 != (Object)null) { _currentPossession = new RigidbodyPossessable(val2); _currentPossession.Enter(); GhostPossessionPlugin.Instance?.SetPossessionCameraTarget(_currentPossession.GameObject); GhostPossessionPlugin.Instance?.LogState("Possessing"); } } public void Release() { if (_currentPossession != null) { _currentPossession.Exit(); _currentPossession = null; GhostPossessionPlugin.Instance?.SetPossessionCameraTarget(null); GhostPossessionPlugin.Instance?.LogState("Released"); } } private void ScanNearbyTargets() { if ((Object)(object)Camera.main == (Object)null) { return; } List<GameObject> list = PossessionScanner.FindCandidates(ModConfig.PossessionScanRadius); _recentTargets.Clear(); _recentTargets.AddRange(list); if (list.Count != 0) { GameObject nearestCandidate = GetNearestCandidate(); if ((Object)(object)nearestCandidate != (Object)null && ModConfig.DebugPreventRunEnd) { GhostPossessionPlugin.Instance?.LogLocalTarget(((Object)nearestCandidate).name); } } } private GameObject GetNearestCandidate() { //IL_0040: 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) Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return null; } GameObject result = null; float num = float.MaxValue; foreach (GameObject recentTarget in _recentTargets) { if (!((Object)(object)recentTarget == (Object)null)) { float num2 = Vector3.Distance(((Component)main).transform.position, recentTarget.transform.position); if (num2 < num) { result = recentTarget; num = num2; } } } return result; } private bool IsLocalHost() { return NetworkHelper.IsLocalHost(); } } public class PossessionScanner { private const int MaxColliders = 256; private static readonly Collider[] ColliderBuffer = (Collider[])(object)new Collider[256]; public static List<GameObject> FindCandidates(float radius) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) List<GameObject> list = new List<GameObject>(); Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return list; } HashSet<GameObject> hashSet = new HashSet<GameObject>(); Character localCharacter = PlayerReflection.GetLocalCharacter(); int num = Physics.OverlapSphereNonAlloc(((Component)main).transform.position, radius, ColliderBuffer); for (int i = 0; i < num; i++) { Collider val = ColliderBuffer[i]; ColliderBuffer[i] = null; if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null) { continue; } GameObject gameObject = ((Component)val).gameObject; if ((Object)(object)gameObject == (Object)null || string.IsNullOrEmpty(((Object)gameObject).name) || ((Object)(object)localCharacter != (Object)null && ((Object)(object)gameObject == (Object)(object)((Component)localCharacter).gameObject || gameObject.transform.IsChildOf(((Component)localCharacter).transform))) || IsExcluded(gameObject)) { continue; } Rigidbody val2 = gameObject.GetComponentInParent<Rigidbody>() ?? gameObject.GetComponentInChildren<Rigidbody>(); GameObject val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).gameObject : null); if ((Object)(object)val3 != (Object)null && (Object)(object)localCharacter != (Object)null && ((Object)(object)val3 == (Object)(object)((Component)localCharacter).gameObject || val3.transform.IsChildOf(((Component)localCharacter).transform))) { continue; } Component val4 = CreatureSupport.FindCreature(gameObject); if ((Object)(object)val4 != (Object)null) { if (hashSet.Add(val4.gameObject)) { list.Add(val4.gameObject); } } else if ((Object)(object)val3 != (Object)null && hashSet.Add(val3)) { list.Add(val3); } } return list; } public static bool IsExcluded(GameObject go) { if ((Object)(object)go == (Object)null) { return true; } if (((Object)go).name.Contains("Camera") || ((Object)go).name.Contains("UI") || (((Object)go).name.Contains("Ghost") && (Object)(object)CreatureSupport.FindCreature(go) == (Object)null)) { return true; } string tag = go.tag; if (!string.Equals(tag, "Terrain", StringComparison.Ordinal)) { string.Equals(tag, "Untagged", StringComparison.Ordinal); } return false; } } public class RigidbodyPossessable : IPossessable { private readonly Rigidbody _rigidbody; private readonly Transform _transform; private readonly Camera _camera; public bool IsValid { get { if ((Object)(object)_rigidbody != (Object)null) { return (Object)(object)((Component)_rigidbody).gameObject != (Object)null; } return false; } } public GameObject GameObject { get { if (!((Object)(object)_rigidbody != (Object)null)) { return null; } return ((Component)_rigidbody).gameObject; } } public string DisplayName { get { if (!((Object)(object)_rigidbody != (Object)null)) { return "Rigidbody"; } return ((Object)_rigidbody).name; } } public RigidbodyPossessable(Rigidbody rigidbody) { _rigidbody = rigidbody; _transform = (((Object)(object)rigidbody != (Object)null) ? ((Component)rigidbody).transform : null); _camera = Camera.main; } public void Enter() { GhostPossessionPlugin.Instance?.LogState("Possessing Rigidbody"); } public void Exit() { GhostPossessionPlugin.Instance?.LogState("Released Rigidbody possession"); } public void UpdateInput() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_0086: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) if (IsValid && !((Object)(object)_camera == (Object)null)) { Vector3 val = Vector3.zero; if (Input.GetKey((KeyCode)119)) { val += ((Component)_camera).transform.forward; } if (Input.GetKey((KeyCode)115)) { val -= ((Component)_camera).transform.forward; } if (Input.GetKey((KeyCode)100)) { val += ((Component)_camera).transform.right; } if (Input.GetKey((KeyCode)97)) { val -= ((Component)_camera).transform.right; } if (Input.GetKey((KeyCode)32)) { _rigidbody.AddForce(Vector3.up * ModConfig.PossessionJumpForce, (ForceMode)1); } if (((Vector3)(ref val)).sqrMagnitude > 0f) { ((Vector3)(ref val)).Normalize(); _rigidbody.AddForce(val * ModConfig.PossessionForce, (ForceMode)5); } if (Input.GetKey((KeyCode)304)) { _rigidbody.AddForce(((Component)_camera).transform.forward * ModConfig.PossessionForce * 0.6f, (ForceMode)5); } if (Input.GetKey((KeyCode)113)) { _rigidbody.AddTorque(Vector3.up * ModConfig.PossessionTorque, (ForceMode)5); } Input.GetKey((KeyCode)101); } } } public sealed class CreatureSpawnMenu { private struct SpawnEntry { public readonly string DisplayName; public readonly string PrefabName; public readonly Type ComponentType; public readonly bool IsTestScout; public SpawnEntry(string displayName, string prefabName, Type componentType, bool isTestScout = false) { DisplayName = displayName; PrefabName = prefabName; ComponentType = componentType; IsTestScout = isTestScout; } } private static readonly SpawnEntry[] Entries = new SpawnEntry[9] { new SpawnEntry("Scoutmaster", "Character_Scoutmaster", typeof(Scoutmaster)), new SpawnEntry("Beetle", "Beetle", typeof(Beetle)), new SpawnEntry("Scorpion", "Scorpion", typeof(Scorpion)), new SpawnEntry("Bee swarm", "BeeSwarm", typeof(BeeSwarm)), new SpawnEntry("Mushroom zombie", "MushroomZombie_Player", typeof(MushroomZombie)), new SpawnEntry("Spider", "Spider", typeof(Spider)), new SpawnEntry("Frog", "Frog", typeof(FrogTongue)), new SpawnEntry("Exploding ghost", "GhostBall", typeof(GhostBall)), new SpawnEntry("Test scout", null, typeof(Character), isTestScout: true) }; private Rect _windowRect = new Rect(0f, 0f, 400f, 540f); private CursorLockMode _previousLockMode; private bool _previousCursorVisible; private int _selectedIndex; private bool _isPlacing; private SpawnEntry _placementEntry; private GameObject _placementMarker; private Vector3 _placementPosition; private Vector3 _placementNormal; private bool _placementValid; public bool IsOpen { get; private set; } public void Update() { if (_isPlacing) { UpdatePlacement(); return; } if (Input.GetKeyDown((KeyCode)286)) { SetOpen(!IsOpen); } if (Input.GetKeyDown((KeyCode)127)) { DeleteNearestTestScout(); } if (IsOpen && Input.GetKeyDown((KeyCode)27)) { SetOpen(open: false); } if (!IsOpen) { return; } Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; if (Input.GetKeyDown((KeyCode)274) || Input.GetKeyDown((KeyCode)115)) { _selectedIndex = (_selectedIndex + 1) % Entries.Length; } if (Input.GetKeyDown((KeyCode)273) || Input.GetKeyDown((KeyCode)119)) { _selectedIndex = (_selectedIndex + Entries.Length - 1) % Entries.Length; } if (Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271)) { BeginPlacement(Entries[_selectedIndex]); } for (int i = 0; i < Entries.Length; i++) { if (Input.GetKeyDown((KeyCode)(49 + i)) || Input.GetKeyDown((KeyCode)(257 + i))) { _selectedIndex = i; BeginPlacement(Entries[i]); break; } } } public void OnGUI() { //IL_011b: 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_0136: Expected O, but got Unknown //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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) if (_isPlacing) { string text = (_placementValid ? (_placementEntry.DisplayName + "\nЛКМ — создать | ПКМ/Esc — отменить") : (_placementEntry.DisplayName + "\nНаведитесь на подходящую поверхность")); GUI.Box(new Rect((float)Screen.width * 0.5f - 190f, 80f, 380f, 58f), text); GUI.Label(new Rect((float)Screen.width * 0.5f - 10f, (float)Screen.height * 0.5f - 14f, 40f, 30f), _placementValid ? "+" : "X"); } else if (IsOpen) { Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; ((Rect)(ref _windowRect)).x = ((float)Screen.width - ((Rect)(ref _windowRect)).width) * 0.5f; ((Rect)(ref _windowRect)).y = ((float)Screen.height - ((Rect)(ref _windowRect)).height) * 0.5f; _windowRect = GUI.Window(904206, _windowRect, new WindowFunction(DrawWindow), "GhostPossession — существа"); } } private void DrawWindow(int id) { GUILayout.Label("Выберите существо, затем укажите место камерой.", Array.Empty<GUILayoutOption>()); GUILayout.Label("Стрелки/W/S + Enter или клавиши 1–7", Array.Empty<GUILayoutOption>()); GUILayout.Space(6f); for (int i = 0; i < Entries.Length; i++) { if (GUILayout.Button(((i == _selectedIndex) ? "> " : " ") + (i + 1) + ". " + Entries[i].DisplayName, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) })) { _selectedIndex = i; BeginPlacement(Entries[i]); } } GUILayout.Space(5f); if (GUILayout.Button("Удалить ближайшего Test scout", Array.Empty<GUILayoutOption>())) { DeleteNearestTestScout(); } if (GUILayout.Button("Удалить всех Test scout", Array.Empty<GUILayoutOption>())) { DeleteAllTestScouts(); } if (GUILayout.Button("Закрыть", Array.Empty<GUILayoutOption>())) { SetOpen(open: false); } } private void BeginPlacement(SpawnEntry entry) { _placementEntry = entry; _isPlacing = true; SetOpen(open: false); CreatePlacementMarker(); GhostPossessionPlugin.Instance?.LogState("Placement mode: " + entry.DisplayName); } private void UpdatePlacement() { //IL_0008: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_012a: 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) Camera main = Camera.main; RaycastHit val = default(RaycastHit); _placementValid = (Object)(object)main != (Object)null && Physics.Raycast(((Component)main).transform.position, ((Component)main).transform.forward, ref val, 100f, -1, (QueryTriggerInteraction)1); if (_placementValid) { _placementNormal = ((RaycastHit)(ref val)).normal; _placementPosition = ((RaycastHit)(ref val)).point + ((RaycastHit)(ref val)).normal * ((_placementEntry.ComponentType == typeof(Spider)) ? 0.15f : 1.2f); if ((Object)(object)_placementMarker != (Object)null) { _placementMarker.transform.position = _placementPosition; _placementMarker.SetActive(true); } } else if ((Object)(object)_placementMarker != (Object)null) { _placementMarker.SetActive(false); } if (Input.GetMouseButtonDown(1) || Input.GetKeyDown((KeyCode)27) || Input.GetKeyDown((KeyCode)286)) { EndPlacement(); } else if (_placementValid && Input.GetMouseButtonDown(0)) { Spawn(_placementEntry, _placementPosition, _placementNormal); EndPlacement(); } } private void Spawn(SpawnEntry entry, Vector3 position, Vector3 normal) { //IL_003d: 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_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0171: 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) if (!NetworkHelper.IsLocalHost()) { GhostPossessionPlugin.Instance?.LogState("Creature spawning requires host authority"); return; } Camera main = Camera.main; Quaternion val = Quaternion.Euler(0f, ((Object)(object)main != (Object)null) ? ((Component)main).transform.eulerAngles.y : 0f, 0f); try { GameObject val2 = null; if (entry.IsTestScout) { val2 = TrySpawnTestScout(position, val); } else { try { val2 = PhotonNetwork.InstantiateRoomObject(entry.PrefabName, position, val, (byte)0, (object[])null); } catch { } if ((Object)(object)val2 == (Object)null && (entry.ComponentType == typeof(Beetle) || entry.ComponentType == typeof(Scorpion) || entry.ComponentType == typeof(FrogTongue))) { try { val2 = PhotonNetwork.InstantiateItemRoom(entry.PrefabName, position, val); } catch (Exception ex) { Debug.LogError((object)("[GhostPossession] Network mob spawn failed for " + entry.DisplayName + ": " + ex)); } } } if (!entry.IsTestScout && ((Object)(object)val2 == (Object)null || (Object)(object)val2.GetComponentInChildren(entry.ComponentType) == (Object)null)) { if ((Object)(object)val2 != (Object)null) { PhotonView component = val2.GetComponent<PhotonView>(); if (PhotonNetwork.InRoom && (Object)(object)component != (Object)null && component.IsMine) { PhotonNetwork.Destroy(val2); } else { Object.Destroy((Object)(object)val2); } } if (!PhotonNetwork.InRoom) { val2 = TrySpawnLoadedCreature(entry, position, val); } } if ((Object)(object)val2 == (Object)null) { throw new InvalidOperationException("No network prefab for " + entry.DisplayName + "; local-only spawn was blocked"); } PrepareSpawnedCreature(val2, entry, position, normal); GhostPossessionPlugin.Instance?.LogState("Spawned " + entry.DisplayName + " at selected position"); } catch (Exception ex2) { Debug.LogError((object)("[GhostPossession] Creature spawn failed: " + ex2)); } } private static GameObject TrySpawnTestScout(Vector3 position, Quaternion rotation) { //IL_0017: 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) Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter == (Object)null) { return null; } GameObject val = Object.Instantiate<GameObject>(((Component)localCharacter).gameObject, position, rotation); Character.localCharacter = localCharacter; ((Object)val).name = "Test Scout (GhostPossession)"; val.AddComponent<SpawnedTestScoutMarker>(); val.SetActive(true); Character val2 = val.GetComponent<Character>() ?? val.GetComponentInChildren<Character>(); if ((Object)(object)val2 !=