Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of DeadPossession v0.7.24
DeadPossession.dll
Decompiled 7 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using REPOLib.Modules; using UnityEngine; using UnityEngine.AI; using UnityEngine.InputSystem; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("DeadPossession")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.7.24.0")] [assembly: AssemblyInformationalVersion("0.7.24+de4485b5cf72e35f8232bae2215441ec021813bc")] [assembly: AssemblyProduct("DeadPossession")] [assembly: AssemblyTitle("DeadPossession")] [assembly: AssemblyVersion("0.7.24.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DeadPossession { public static class ConfigSettings { public static ConfigEntry<float> MaxPossessionDuration { get; private set; } public static ConfigEntry<float> PossessionCooldown { get; private set; } public static ConfigEntry<float> SenseBlurIntensity { get; private set; } public static ConfigEntry<KeyCode> PossessionKey { get; private set; } public static ConfigEntry<float> MouseSensitivity { get; private set; } public static ConfigEntry<float> PuppetFloorBump { get; private set; } public static ConfigEntry<bool> DebugPossessWhileAlive { get; private set; } public static ConfigEntry<bool> DebugKillOnLevelStart { get; private set; } public static void Bind(ConfigFile config) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Expected O, but got Unknown MaxPossessionDuration = config.Bind<float>("Possession", "MaxPossessionDuration", 60f, new ConfigDescription("Maximum possession duration in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 300f), Array.Empty<object>())); PossessionCooldown = config.Bind<float>("Possession", "PossessionCooldown", 120f, new ConfigDescription("Cooldown before the dead player can possess again, in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), Array.Empty<object>())); SenseBlurIntensity = config.Bind<float>("Possession", "SenseBlurIntensity", 0f, new ConfigDescription("Amount of vision blurring while possessing (0 = none, 1 = fully blind).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); PossessionKey = config.Bind<KeyCode>("Possession", "PossessionKey", (KeyCode)102, "Key to start/end possession (Unity KeyCode name)."); MouseSensitivity = config.Bind<float>("Possession", "MouseSensitivity", 0.1f, new ConfigDescription("Mouse look multiplier while possessing (vanilla mouse feel is around 0.25 for this input scale).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>())); PuppetFloorBump = config.Bind<float>("Possession", "PuppetFloorBump", 0f, new ConfigDescription("Vertical bias of the possessed model anchor, in meters. The mod anchors the model's origin to the floor under the player body; shift up/down here if it floats or sinks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2f, 2f), Array.Empty<object>())); DebugPossessWhileAlive = config.Bind<bool>("Debug", "DebugPossessWhileAlive", false, "TESTING ONLY: allow starting possession while alive (no need to die). Use with the PossessionKey."); DebugKillOnLevelStart = config.Bind<bool>("Debug", "DebugKillOnLevelStart", false, "TESTING ONLY: vanilla-kill the local player a few seconds after entering a level and disable the all-players-dead run end. Gives the real dead/spectate flow in singleplayer."); } } public static class HostConfig { private static float[] hostValues; private static bool AppliesLocal { get { if (GameManager.Multiplayer()) { return PhotonNetwork.IsMasterClient; } return true; } } public static float MaxPossessionDuration => Get(0, ConfigSettings.MaxPossessionDuration.Value); public static float PossessionCooldown => Get(1, ConfigSettings.PossessionCooldown.Value); public static float SenseBlurIntensity => Get(2, ConfigSettings.SenseBlurIntensity.Value); private static float Get(int index, float localValue) { if (AppliesLocal || hostValues == null || hostValues.Length < 3) { return localValue; } return hostValues[index]; } public static void Accept(float[] values) { if (values != null && values.Length == 3) { hostValues = values; Plugin.Log($"Host config accepted (duration={values[0]:F0}, cooldown={values[1]:F0}, blur={values[2]:F2})"); } } } [BepInPlugin("yo.DeadPossession", "DeadPossession", "0.7.24")] [BepInProcess("REPO.exe")] public class Plugin : BaseUnityPlugin { private static ManualLogSource logSource; public static Plugin Instance { get; private set; } private void Awake() { //IL_0025: 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_003f: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) Instance = this; ConfigSettings.Bind(((BaseUnityPlugin)this).Config); logSource = Logger.CreateLogSource("DeadPossession"); new Harmony("yo.DeadPossession").PatchAll(); GameObject val = new GameObject("DeadPossession"); Object.DontDestroyOnLoad((Object)val); ((Object)val).hideFlags = (HideFlags)61; val.AddComponent<PossessionBehavior>(); val.AddComponent<PossessionNetworking>(); Log(string.Format("{0} v{1} loaded | DebugKillOnLevelStart={2} | DebugPossessWhileAlive={3}", "DeadPossession", "0.7.24", ConfigSettings.DebugKillOnLevelStart.Value, ConfigSettings.DebugPossessWhileAlive.Value)); } public static void Log(string message) { logSource.LogInfo((object)message); } } public static class PluginInfo { public const string PLUGIN_GUID = "yo.DeadPossession"; public const string PLUGIN_NAME = "DeadPossession"; public const string PLUGIN_VERSION = "0.7.24"; } [DefaultExecutionOrder(32766)] public class PossessionBehavior : MonoBehaviour { private const float SearchRadius = 20f; private const float PuppetScale = 1f; private const float CameraEyeHeight = 0.95f; private float lastTimeNotifiedMissing; private bool flashlightWasOn; private float lookYaw; private float lookPitch; private float levelEnterTime = -999f; private bool previousInLevel; private bool killedThisLevel; private float lastKillAttempt; private bool debugWasInMainMenu; private GameObject possessedPuppet; private GameObject hiddenPlayerVisuals; private bool debugEnergyWas; private float attackDamageCooldown; private Light possessionLight; private float nextMoveBroadcast; private const float PuppetDriftFreeze = 0.05f; private Dictionary<Transform, Vector3> puppetSnapshot; private static bool possessionStartedDead; private bool forcedMainState; private gameState savedGameState; private int inputClearLogs; private bool avatarWasActive; private string noVisionSteamId; private Vector3 aliveBodyReturnPos; private bool aliveReturnPlanned; private float? savedGrabRange; private Behaviour parkedLocalCamera; public static PlayerAvatar LocalAvatar { get; set; } public static EnemyGnome PossessedGnome { get; private set; } public static bool SpectateOwnedByMod { get; private set; } public static Transform PossessedRoot { get; private set; } public static bool AttackWindowOpen { get; private set; } private void Awake() { LocalAvatar = null; PossessedGnome = null; PossessedRoot = null; SpectateOwnedByMod = false; } private void Start() { ResolveLocalAvatar(); } private static bool ResolveLocalAvatar() { if ((Object)(object)LocalAvatar != (Object)null) { return true; } LocalAvatar = PlayerAvatar.instance; return (Object)(object)LocalAvatar != (Object)null; } private bool EnsureBodyAwake() { Transform val = PlayerBodyRoot(); object? obj = AccessTools.Field(typeof(PlayerController), "instance")?.GetValue(null); PlayerController val2 = (PlayerController)((obj is PlayerController) ? obj : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { return true; } if (!((Behaviour)val2).enabled) { ((Behaviour)val2).enabled = true; Plugin.Log("PlayerController component was DISABLED — re-enabled for possession"); } Transform val3 = val; while ((Object)(object)val3 != (Object)null) { if (!((Component)val3).gameObject.activeSelf) { ((Component)val3).gameObject.SetActive(true); Plugin.Log("Body ancestor '" + ((Object)((Component)val3).gameObject).name + "' was INACTIVE — re-activated for possession"); } val3 = val3.parent; } return ((Component)val).gameObject.activeInHierarchy; } private void FixedUpdate() { if (PossessionController.IsPossessing) { EnsureBodyAwake(); PinPuppetToBody(); } } private void PinPuppetToBody() { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0140: 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) //IL_0150: 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_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) Transform val = PlayerBodyRoot(); if ((Object)(object)val == (Object)null || (Object)(object)possessedPuppet == (Object)null) { return; } if ((Object)(object)possessedPuppet.transform.parent != (Object)(object)val) { string text = (((Object)(object)possessedPuppet.transform.parent != (Object)null) ? ((Object)((Component)possessedPuppet.transform.parent).gameObject).name : "(none)"); possessedPuppet.transform.SetParent(val, false); Plugin.Log("Puppet re-parented (was under " + text + ")"); } Vector3 position = val.position; float num = GroundBelow(position, val) - position.y + ConfigSettings.PuppetFloorBump.Value; Vector3 localPosition = possessedPuppet.transform.localPosition; Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(0f, num, 0f); Vector3 value = localPosition - val2; if (((Vector3)(ref value)).sqrMagnitude > 0.0001f) { possessedPuppet.transform.localPosition = val2; } if (puppetSnapshot == null) { return; } float num2 = 0.0025000002f; foreach (KeyValuePair<Transform, Vector3> item in puppetSnapshot) { item.Deconstruct(out var key, out value); Transform val3 = key; Vector3 val4 = value; if (!((Object)(object)val3 == (Object)null)) { Vector3 val5 = val3.localPosition - val4; if (((Vector3)(ref val5)).sqrMagnitude > num2) { val3.localPosition = val4; Plugin.Log("Puppet child drift frozen: " + ((Object)((Component)val3).gameObject).name + " (was " + ((Vector3)(ref val5)).ToString("F2") + ")"); } } } } private void CapturePuppetSnapshot() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)possessedPuppet == (Object)null)) { puppetSnapshot = new Dictionary<Transform, Vector3>(); Transform[] componentsInChildren = possessedPuppet.GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { puppetSnapshot[val] = val.localPosition; } Plugin.Log("Puppet snapshot captured (" + puppetSnapshot.Count + " nodes)"); } } private float GroundBelow(Vector3 from, Transform bodyOf) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: 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) RaycastHit[] array = Physics.RaycastAll(from + Vector3.up * 2f, Vector3.down, 25f); Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array2 = array; for (int num = 0; num < array2.Length; num++) { RaycastHit val = array2[num]; if (!((Object)(object)((RaycastHit)(ref val)).collider == (Object)null)) { Transform root = ((Component)((RaycastHit)(ref val)).collider).transform.root; if ((!((Object)(object)possessedPuppet != (Object)null) || !((Component)((RaycastHit)(ref val)).collider).transform.IsChildOf(possessedPuppet.transform)) && !((Object)(object)root == (Object)(object)bodyOf.root)) { return ((RaycastHit)(ref val)).point.y; } } } return from.y - 1.8f; } private void DrivePuppetWalk() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_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_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) if ((Object)(object)possessedPuppet == (Object)null) { return; } Animator componentInChildren = possessedPuppet.GetComponentInChildren<Animator>(); Rigidbody val = PlayerBodyRb(); if (!((Object)(object)componentInChildren == (Object)null) && !((Object)(object)val == (Object)null)) { Vector3 velocity = val.velocity; Vector3 val2 = new Vector3(velocity.x, 0f, velocity.z); int num; if (!(((Vector3)(ref val2)).magnitude > 0.2f)) { val2 = val.angularVelocity; num = ((((Vector3)(ref val2)).magnitude > 0.5f) ? 1 : 0); } else { num = 1; } bool flag = (byte)num != 0; componentInChildren.SetBool("Moving", flag); } } private static Rigidbody PlayerBodyRb() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown object? obj = AccessTools.Field(typeof(PlayerController), "instance")?.GetValue(null); PlayerController val = (PlayerController)((obj is PlayerController) ? obj : null); if (!((Object)(object)val != (Object)null)) { return null; } return (Rigidbody)(AccessTools.Field(typeof(PlayerController), "rb")?.GetValue(val)); } private static bool LocalAvatarDead() { if (PossessionController.IsPossessing) { return possessionStartedDead; } if ((Object)(object)LocalAvatar != (Object)null) { return (bool)AccessTools.Field(typeof(PlayerAvatar), "deadSet").GetValue(LocalAvatar); } return false; } private unsafe void ForceMainGameState(bool deadPossession) { //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: 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_0154: Invalid comparison between Unknown and I4 //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) FieldInfo fieldInfo = AccessTools.Field(typeof(GameDirector), "currentState"); GameDirector instance = GameDirector.instance; if (fieldInfo == null || (Object)(object)instance == (Object)null || !deadPossession) { if (deadPossession && (Object)(object)instance == (Object)null) { Plugin.Log("Main-state force skipped: no GameDirector.instance"); } return; } FieldInfo fieldInfo2 = AccessTools.Field(typeof(GameDirector), "outroStart"); if (fieldInfo2 != null && (bool)fieldInfo2.GetValue(instance)) { fieldInfo2.SetValue(instance, false); } if (instance.DisableInput) { instance.DisableInput = false; } object? obj = AccessTools.Field(typeof(PlayerController), "instance")?.GetValue(null); PlayerController val = (PlayerController)((obj is PlayerController) ? obj : null); if ((Object)(object)val != (Object)null) { FieldInfo fieldInfo3 = AccessTools.Field(typeof(PlayerController), "InputDisableTimer"); if (fieldInfo3 != null) { float num = (float)fieldInfo3.GetValue(val); if (num > 0f) { if (inputClearLogs < 5) { inputClearLogs++; Plugin.Log("InputDisable timer was " + num.ToString("0.000") + " — cleared for possession"); } fieldInfo3.SetValue(val, 0f); } } } gameState val2 = (gameState)fieldInfo.GetValue(instance); if ((int)val2 != 2) { savedGameState = val2; forcedMainState = true; fieldInfo.SetValue(instance, (object)(gameState)2); Plugin.Log("GameDirector state " + ((object)(*(gameState*)(&val2))/*cast due to .constrained prefix*/).ToString() + " -> Main (player body physics awake)"); } } private void RestoreMainGameState() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_0025: 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) if (!forcedMainState) { return; } forcedMainState = false; if ((int)savedGameState == 3) { Plugin.Log("Release: kept Main state (saved state was Outro)"); savedGameState = (gameState)2; return; } FieldInfo fieldInfo = AccessTools.Field(typeof(GameDirector), "currentState"); GameDirector instance = GameDirector.instance; if (!(fieldInfo == null) && !((Object)(object)instance == (Object)null)) { fieldInfo.SetValue(instance, savedGameState); Plugin.Log("GameDirector state restored to " + ((object)Unsafe.As<gameState, gameState>(ref savedGameState)/*cast due to .constrained prefix*/).ToString()); } } public static bool IsEnemyOwned(Component component) { if ((Object)(object)component == (Object)null) { return false; } if (PossessionController.IsPossessing && (Object)(object)PossessedRoot != (Object)null && (Object)(object)component.transform.root == (Object)(object)PossessedRoot.root) { return true; } return PossessionNetworking.IsRootPossessed(component.transform.root); } private bool CanPossess(bool isDead) { if (isDead) { return true; } if (ConfigSettings.DebugKillOnLevelStart.Value) { return false; } return ConfigSettings.DebugPossessWhileAlive.Value; } private static bool InLevel() { if ((Object)(object)LevelGenerator.Instance == (Object)null || (Object)(object)RunManager.instance == (Object)null || !(bool)AccessTools.Field(typeof(RunManager), "runStarted").GetValue(RunManager.instance)) { return false; } Level levelCurrent = RunManager.instance.levelCurrent; if ((Object)(object)levelCurrent != (Object)null) { return levelCurrent.HasEnemies; } return false; } private void UpdateDebugAutoRestart() { if (!ConfigSettings.DebugKillOnLevelStart.Value) { return; } bool flag = SemiFunc.IsMainMenu(); if (flag && !debugWasInMainMenu && Time.time > 2f) { if (AccessTools.Field(typeof(MainMenuOpen), "instance")?.GetValue(null) != null && !((Object)(object)RunManager.instance == (Object)null)) { debugWasInMainMenu = true; SemiFunc.MainMenuSetSingleplayer(); SemiFunc.MenuActionSingleplayerGame((string)null, (List<string>)null); Plugin.Log("Debug: main menu entered — starting fresh singleplayer run"); } } else if (!flag) { debugWasInMainMenu = false; } } private void Update() { //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) PossessionController.Tick(); UpdateDebugAutoRestart(); if (!ResolveLocalAvatar()) { return; } bool flag = InLevel(); if (!flag) { previousInLevel = false; killedThisLevel = false; SpectateOwnedByMod = false; if (PossessionController.IsPossessing) { EndPossession(); } return; } if (!previousInLevel) { levelEnterTime = Time.time; } previousInLevel = flag; bool flag2 = LocalAvatarDead(); SpectateOwnedByMod = (ConfigSettings.DebugKillOnLevelStart.Value && flag2) || PossessionController.IsPossessing; if (PossessionController.IsPossessing) { if (!CanPossess(flag2) || (Object)(object)PossessedGnome == (Object)null) { EndPossession(); return; } ForceMainGameState(flag2); EnsureVanillaGrabUsable(); ReadLook(); AttackPossessed(); DrivePuppetWalk(); if (attackDamageCooldown > 0f) { attackDamageCooldown -= Time.deltaTime; } EnergyRefill(); EnsurePossessionVision(); if ((Object)(object)PossessedGnome != (Object)null && Time.time > nextMoveBroadcast) { nextMoveBroadcast = Time.time + 0.1f; Transform val = PlayerBodyRoot(); PhotonView val2 = PossessionNetworking.ViewIdOf(PossessedGnome); if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null) { PossessionNetworking.BroadcastMove(val2.ViewID, val.position); } } } if (ConfigSettings.DebugKillOnLevelStart.Value) { UpdateLevelKill(flag2); } if (CanPossess(flag2) && Input.GetKeyDown(ConfigSettings.PossessionKey.Value)) { if (PossessionController.IsPossessing) { EndPossession(); } else if (PossessionController.IsEligible()) { TryStartPossession(); } } } private void UpdateLevelKill(bool isDead) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Invalid comparison between Unknown and I4 if (isDead) { if (killedThisLevel) { Plugin.Log("Debug: local player confirmed dead"); } killedThisLevel = false; } else if (ConfigSettings.DebugKillOnLevelStart.Value && !(Time.time - levelEnterTime < 3f) && !((Object)(object)GameDirector.instance == (Object)null) && (int)GameDirector.instance.currentState == 2) { if (!killedThisLevel) { killedThisLevel = true; Plugin.Log("Debug: level entered, executing vanilla debug kill"); } if (!(Time.time - lastKillAttempt < 2f)) { lastKillAttempt = Time.time; KillLocalPlayerForTesting(); } } } private static void KillLocalPlayerForTesting() { if ((Object)(object)LocalAvatar == (Object)null) { Plugin.Log("Debug kill: no local avatar yet"); return; } object obj = AccessTools.Field(typeof(RunManager), "instance")?.GetValue(null); if (obj != null) { AccessTools.Field(typeof(RunManager), "allPlayersDeadCheckDisabled")?.SetValue(obj, true); Plugin.Log("Debug: allPlayersDeadCheckDisabled = true (run end disabled)"); } else { Plugin.Log("Debug kill: RunManager.instance not found"); } MethodInfo methodInfo = AccessTools.Method(typeof(PlayerAvatar), "PlayerDeath", (Type[])null, (Type[])null); if (methodInfo == null) { Plugin.Log("Debug kill: PlayerDeath method not found"); return; } try { methodInfo.Invoke(LocalAvatar, new object[1] { -1 }); Plugin.Log("Debug: vanilla kill executed (waiting deadSet confirmation)"); } catch (Exception ex) { Plugin.Log("Debug kill: PlayerDeath invoke failed: " + ex.Message); } } public static Transform RootOf(EnemyGnome gnome) { Enemy val = (((Object)(object)gnome != (Object)null) ? gnome.enemy : null); EnemyParent val2 = (((Object)(object)val == (Object)null) ? null : Traverse.Create((object)val).Field("EnemyParent").GetValue<EnemyParent>()); if (!((Object)(object)val2 != (Object)null)) { return ((Component)gnome).transform.root; } return ((Component)val2).transform; } public static void StripComponents(EnemyGnome gnome, Transform root) { if ((Object)(object)gnome == (Object)null || (Object)(object)root == (Object)null) { return; } HashSet<Type> hashSet = new HashSet<Type> { typeof(EnemyGnome), typeof(EnemyGnomeAnim), typeof(EnemyHealth), typeof(EnemyParent), typeof(Enemy), typeof(EnemyRigidbody), typeof(EnemyNavMeshAgent), typeof(EnemyGrounded), typeof(EnemyJump), typeof(PhysGrabObjectCollider), typeof(PhysGrabObjectCapsuleCollider), typeof(PhysGrabObjectMeshCollider), typeof(PhysGrabObjectSphereCollider), typeof(PhysGrabObjectBoxCollider) }; List<(MonoBehaviour, Type)> list = new List<(MonoBehaviour, Type)>(); MonoBehaviour[] componentsInChildren = ((Component)root).GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { Type type = ((object)val).GetType(); if (!hashSet.Contains(type)) { list.Add((val, type)); } } } DestroyImmediateTopological(root, list); } private static void DestroyImmediateTopological(Transform root, List<(MonoBehaviour component, Type type)> candidates) { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown HashSet<Object> hashSet = new HashSet<Object>(); foreach (var (val, type) in candidates) { if ((Object)(object)val == (Object)null || hashSet.Contains((Object)(object)val)) { continue; } bool flag = false; if ((Object)(object)root != (Object)null) { foreach (var candidate in candidates) { if ((Object)(object)candidate.component == (Object)null || (Object)(object)candidate.component == (Object)(object)val) { continue; } object[] customAttributes = ((object)candidate.component).GetType().GetCustomAttributes(typeof(RequireComponent), inherit: true); for (int i = 0; i < customAttributes.Length; i++) { RequireComponent val2 = (RequireComponent)customAttributes[i]; if (val2.m_Type0 == type || val2.m_Type1 == type || val2.m_Type2 == type) { flag = true; } } } } if (!flag) { Object.DestroyImmediate((Object)(object)val); hashSet.Add((Object)(object)val); } } foreach (var candidate2 in candidates) { MonoBehaviour item = candidate2.component; if ((Object)(object)item != (Object)null) { Object.DestroyImmediate((Object)(object)item); } } } private void ActivatePossession(EnemyGnome gnome) { //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_0125: 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_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_010f: 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) PossessedGnome = gnome; PossessedRoot = RootOf(gnome); AttackWindowOpen = false; attackDamageCooldown = 0f; bool flag = (Object)(object)LocalAvatar != (Object)null && (bool)AccessTools.Field(typeof(PlayerAvatar), "deadSet").GetValue(LocalAvatar); possessionStartedDead = flag; PossessionController.StartPossession(); if (!flag) { SetLocalFlashlight(on: false); } ForceMainGameState(flag); Player localPlayer = PhotonNetwork.LocalPlayer; PossessionNetworking.BroadcastPossession((localPlayer != null) ? localPlayer.ActorNumber : (-1), gnome); Plugin.Log("Possession activated" + (flag ? " (dead flow)" : " (debug alive)")); ((Component)PossessedRoot).gameObject.SetActive(false); Plugin.Log("Original enemy hidden: " + ((Object)((Component)PossessedRoot).gameObject).name); if (!flag) { object? obj = AccessTools.Field(typeof(PlayerController), "instance")?.GetValue(null); PlayerController val = (PlayerController)((obj is PlayerController) ? obj : null); if ((Object)(object)val != (Object)null) { aliveBodyReturnPos = ((Component)val).transform.position; aliveReturnPlanned = true; } } TeleportPlayer(PossessedRoot.position + Vector3.up * 0.3f); ParkLocalCamera(); BuildPuppet(); object obj2 = AccessTools.Field(typeof(PlayerController), "instance")?.GetValue(null); if (obj2 != null) { FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerController), "DebugEnergy"); if (fieldInfo != null) { try { debugEnergyWas = (bool)fieldInfo.GetValue(obj2); fieldInfo.SetValue(obj2, true); Plugin.Log("PlayerController.DebugEnergy = true (no stamina)"); } catch (Exception ex) { Plugin.Log("DebugEnergy set failed: " + ex.Message); } } } Camera main = Camera.main; if ((Object)(object)main != (Object)null) { lookYaw = ((Component)main).transform.eulerAngles.y; lookPitch = 0f; } ApplyLookToVanillaRig(); AddPossessionVisionLight(); EnsurePossessionVision(); } private static Transform PlayerBodyRoot() { object obj = AccessTools.Field(typeof(PlayerController), "instance")?.GetValue(null); if (obj == null) { return null; } return ((Component)((obj is PlayerController) ? obj : null)).transform; } private unsafe static void TeleportPlayer(Vector3 destination) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_00cf: Unknown result type (might be due to invalid IL or missing references) object obj = AccessTools.Field(typeof(PlayerController), "instance")?.GetValue(null); if (obj == null) { Plugin.Log("Teleport: no PlayerController.instance"); return; } Transform transform = ((Component)((obj is PlayerController) ? obj : null)).transform; object? obj2 = AccessTools.Field(typeof(PlayerController), "rb")?.GetValue(obj); Rigidbody val = (Rigidbody)((obj2 is Rigidbody) ? obj2 : null); if ((Object)(object)val != (Object)null) { ((Component)val).transform.position = destination; val.velocity = Vector3.zero; val.angularVelocity = Vector3.zero; } else { Plugin.Log("Teleport: PlayerController rb not found"); } transform.position = destination; object obj3 = AccessTools.Field(typeof(CameraPosition), "instance")?.GetValue(null); if (obj3 != null) { ((Component)((obj3 is CameraPosition) ? obj3 : null)).transform.position = destination; } Vector3 val2 = destination; Plugin.Log("Player teleported to " + ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString()); } private void BuildPuppet() { //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)possessedPuppet != (Object)null) { Object.Destroy((Object)(object)possessedPuppet); possessedPuppet = null; } if ((Object)(object)PossessedRoot == (Object)null || (Object)(object)PlayerBodyRoot() == (Object)null) { return; } _ = ((Component)PossessedRoot).gameObject.activeInHierarchy; ((Component)PossessedRoot).gameObject.SetActive(true); GameObject val = Object.Instantiate<GameObject>(((Component)PossessedRoot).gameObject); ((Component)PossessedRoot).gameObject.SetActive(false); MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null) { ((Behaviour)val2).enabled = false; } } NavMeshAgent[] componentsInChildren2 = val.GetComponentsInChildren<NavMeshAgent>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { ((Behaviour)componentsInChildren2[i]).enabled = false; } EnemyRigidbody[] componentsInChildren3 = val.GetComponentsInChildren<EnemyRigidbody>(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Object.Destroy((Object)(object)componentsInChildren3[i]); } EnemyParent[] componentsInChildren4 = val.GetComponentsInChildren<EnemyParent>(true); for (int i = 0; i < componentsInChildren4.Length; i++) { Object.Destroy((Object)(object)componentsInChildren4[i]); } PhotonView[] componentsInChildren5 = val.GetComponentsInChildren<PhotonView>(true); for (int i = 0; i < componentsInChildren5.Length; i++) { Object.Destroy((Object)(object)componentsInChildren5[i]); } Rigidbody[] componentsInChildren6 = val.GetComponentsInChildren<Rigidbody>(true); for (int i = 0; i < componentsInChildren6.Length; i++) { componentsInChildren6[i].isKinematic = true; } Collider[] componentsInChildren7 = val.GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren7.Length; i++) { componentsInChildren7[i].enabled = false; } Transform val3 = PlayerBodyRoot(); ((Object)val).name = "PossessionPuppet"; val.transform.SetParent(val3, false); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one * 1f; possessedPuppet = val; if (!val.activeSelf) { val.SetActive(true); } Animator componentInChildren = val.GetComponentInChildren<Animator>(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.applyRootMotion = false; componentInChildren.cullingMode = (AnimatorCullingMode)0; Plugin.Log("Puppet animator: root motion off, culling always-animate"); } object? obj = AccessTools.Field(typeof(PlayerAvatar), "playerAvatarVisuals")?.GetValue(LocalAvatar); PlayerAvatarVisuals val4 = (PlayerAvatarVisuals)((obj is PlayerAvatarVisuals) ? obj : null); if ((Object)(object)val4 != (Object)null) { hiddenPlayerVisuals = ((Component)val4).gameObject; hiddenPlayerVisuals.SetActive(false); } avatarWasActive = ((Component)LocalAvatar).gameObject.activeSelf; if (!avatarWasActive) { ((Component)LocalAvatar).gameObject.SetActive(true); Plugin.Log("Local avatar GO re-activated (vanilla PhysGrabber)"); } CapturePuppetSnapshot(); Plugin.Log("Puppet built (scale " + 1f + ") under " + ((Object)val3).name + ", player model hidden"); } private void ReadLook() { //IL_001a: 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) //IL_0027: 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) float value = ConfigSettings.MouseSensitivity.Value; Mouse current = Mouse.current; if (current != null) { Vector2 val = ((InputControl<Vector2>)(object)((Pointer)current).delta).ReadValue(); lookYaw += val.x * value; lookPitch = Mathf.Clamp(lookPitch - val.y * value, -80f, 80f); } else { lookYaw += Input.GetAxis("Mouse X") * value; lookPitch = Mathf.Clamp(lookPitch - Input.GetAxis("Mouse Y") * value, -80f, 80f); } ApplyLookToVanillaRig(); } private void ApplyLookToVanillaRig() { //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) //IL_0026: 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) CameraAim instance = CameraAim.Instance; Quaternion val = Quaternion.Euler(0f, lookYaw, 0f); if ((Object)(object)instance != (Object)null) { instance.SetPlayerAim(val, true); return; } object? obj = AccessTools.Field(typeof(PlayerController), "instance")?.GetValue(null); PlayerController val2 = (PlayerController)((obj is PlayerController) ? obj : null); GameObject val3 = val2?.cameraGameObject ?? val2?.cameraGameObjectLocal; if (!((Object)(object)val3 == (Object)null)) { val3.transform.localRotation = val; } } private void AttackPossessed() { if (Input.GetMouseButtonDown(1) && !(attackDamageCooldown > 0f)) { PlayAttackAnimation(); ManualAttackDamage(); } } private void PlayAttackAnimation() { Animator val = (((Object)(object)possessedPuppet != (Object)null) ? possessedPuppet.GetComponentInChildren<Animator>() : null); if ((Object)(object)val != (Object)null) { val.SetTrigger("Attack"); } else { Plugin.Log("Attack: no animator found on puppet"); } } private void ManualAttackDamage() { //IL_001c: 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_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_0041: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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_00ad: 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) Transform val = PlayerBodyRoot(); if ((Object)(object)val == (Object)null) { return; } attackDamageCooldown = 0.75f; Vector3 position = val.position; Vector3 val2 = Quaternion.Euler(0f, lookYaw, 0f) * Vector3.forward; Enemy[] array = Object.FindObjectsOfType<Enemy>(); foreach (Enemy val3 in array) { if (((Object)(object)PossessedGnome != (Object)null && (Object)(object)val3 == (Object)(object)PossessedGnome.enemy) || Vector3.Distance(((Component)val3).transform.position, position) > 1.5f) { continue; } Vector3 val4 = ((Component)val3).transform.position - position; Vector3 normalized = ((Vector3)(ref val4)).normalized; if (!(Vector3.Angle(val2, normalized) > 50f)) { EnemyHealth value = Traverse.Create((object)val3).Field("Health").GetValue<EnemyHealth>(); if (!((Object)(object)value == (Object)null)) { value.Hurt(1, normalized); } } } } private void EnsureVanillaGrabUsable() { if ((Object)(object)LocalAvatar == (Object)null) { return; } AccessTools.Field(typeof(PlayerAvatar), "isDisabled")?.SetValue(LocalAvatar, false); AccessTools.Field(typeof(PlayerAvatar), "deadSet")?.SetValue(LocalAvatar, false); SetLocalFlashlight(on: false); if ((Object)(object)LocalAvatar.playerHealth != (Object)null) { LocalAvatar.playerHealth.InvincibleSet(1000f); } EnemyDirector instance = EnemyDirector.instance; string text = (string)AccessTools.Field(typeof(PlayerAvatar), "steamID")?.GetValue(LocalAvatar); if ((Object)(object)instance != (Object)null && text != null) { List<string> list = (List<string>)AccessTools.Field(typeof(EnemyDirector), "debugNoVision").GetValue(instance); if (list != null && !list.Contains(text)) { list.Add(text); noVisionSteamId = text; } } GameObject val = (((Object)(object)Aim.instance != (Object)null) ? ((Component)Aim.instance).gameObject : null); if ((Object)(object)val != (Object)null && !val.activeInHierarchy) { Transform val2 = val.transform; List<string> list2 = new List<string>(); while ((Object)(object)val2 != (Object)null && !((Component)val2).gameObject.activeSelf) { ((Component)val2).gameObject.SetActive(true); list2.Add(((Object)((Component)val2).gameObject).name); val2 = val2.parent; } Plugin.Log("Aim UI re-activated: " + ((Object)val).name + " ancestors=[" + string.Join(", ", list2) + "]"); } if (!((Component)LocalAvatar).gameObject.activeSelf) { ((Component)LocalAvatar).gameObject.SetActive(true); Plugin.Log("Local avatar GO re-asserted active"); } PhysGrabber physGrabber = LocalAvatar.physGrabber; if ((Object)(object)physGrabber != (Object)null) { if (!savedGrabRange.HasValue) { savedGrabRange = physGrabber.grabRange; } physGrabber.grabRange = savedGrabRange.Value + 2.42f; } } private void ReleaseVanillaGrab() { //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: 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_01ef: Unknown result type (might be due to invalid IL or missing references) PhysGrabber val = (((Object)(object)LocalAvatar != (Object)null) ? LocalAvatar.physGrabber : null); if ((Object)(object)val != (Object)null && val.grabbed) { val.ReleaseObject(-1, 0.1f); Plugin.Log("Vanilla grab released on end possession"); } if ((Object)(object)val != (Object)null && savedGrabRange.HasValue) { val.grabRange = savedGrabRange.Value; savedGrabRange = null; } if ((Object)(object)LocalAvatar != (Object)null && !avatarWasActive) { ((Component)LocalAvatar).gameObject.SetActive(false); Plugin.Log("Local avatar GO de-activated again (vanilla death state)"); } avatarWasActive = false; if ((Object)(object)LocalAvatar != (Object)null && (Object)(object)LocalAvatar.playerHealth != (Object)null) { LocalAvatar.playerHealth.InvincibleSet(0.1f); } if (noVisionSteamId != null) { EnemyDirector instance = EnemyDirector.instance; (((Object)(object)instance != (Object)null) ? ((List<string>)AccessTools.Field(typeof(EnemyDirector), "debugNoVision").GetValue(instance)) : null)?.Remove(noVisionSteamId); noVisionSteamId = null; } if (!possessionStartedDead || !((Object)(object)LocalAvatar != (Object)null)) { return; } AccessTools.Field(typeof(PlayerAvatar), "isDisabled")?.SetValue(LocalAvatar, true); AccessTools.Field(typeof(PlayerAvatar), "deadSet")?.SetValue(LocalAvatar, true); object? obj = AccessTools.Field(typeof(PlayerAvatar), "playerDeathHead")?.GetValue(LocalAvatar); Component val2 = (Component)((obj is Component) ? obj : null); if ((Object)(object)val2 != (Object)null) { TeleportPlayer(val2.transform.position + Vector3.up * 0.3f); object? obj2 = AccessTools.Field(typeof(PlayerController), "instance")?.GetValue(null); PlayerController val3 = (PlayerController)((obj2 is PlayerController) ? obj2 : null); if ((Object)(object)val3 != (Object)null) { AccessTools.Field(typeof(PlayerController), "InputDisableTimer")?.SetValue(val3, 1f); } Plugin.Log("Body teleported back to death spot"); } SpectateCamera instance2 = SpectateCamera.instance; if ((Object)(object)instance2 != (Object)null) { Traverse.Create((object)instance2).Method("UpdateState", new object[1] { (object)(State)2 }).GetValue(); Plugin.Log("Spectate re-pinned to death head (vanilla dead state restored)"); } } private void EnergyRefill() { object obj = AccessTools.Field(typeof(PlayerController), "instance")?.GetValue(null); if (obj != null) { object value = AccessTools.Field(typeof(PlayerController), "EnergyStart")?.GetValue(obj); AccessTools.Field(typeof(PlayerController), "EnergyCurrent")?.SetValue(obj, value); } } private void EndPossession() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) ReleaseVanillaGrab(); if (aliveReturnPlanned && !possessionStartedDead) { TeleportPlayer(aliveBodyReturnPos); aliveReturnPlanned = false; Plugin.Log("Debug alive release: body returned to pre-possession spot"); } Player localPlayer = PhotonNetwork.LocalPlayer; PossessionNetworking.BroadcastPossession((localPlayer != null) ? localPlayer.ActorNumber : (-1), null); PossessionController.EndPossession(); AttackWindowOpen = false; RestoreMainGameState(); if ((Object)(object)possessedPuppet != (Object)null) { Object.Destroy((Object)(object)possessedPuppet); possessedPuppet = null; } if ((Object)(object)hiddenPlayerVisuals != (Object)null) { hiddenPlayerVisuals.SetActive(!LocalAvatarDead()); hiddenPlayerVisuals = null; } RestoreLocalCamera(); if ((Object)(object)possessionLight != (Object)null) { Object.Destroy((Object)(object)((Component)possessionLight).gameObject); possessionLight = null; } RemovePossessionVision(); if ((Object)(object)PossessedRoot != (Object)null) { ((Component)PossessedRoot).gameObject.SetActive(true); Plugin.Log("Original enemy restored: " + ((Object)((Component)PossessedRoot).gameObject).name); } PossessedGnome = null; PossessedRoot = null; object obj = AccessTools.Field(typeof(PlayerController), "instance")?.GetValue(null); if (obj != null && AccessTools.Field(typeof(PlayerController), "DebugEnergy") != null) { AccessTools.Field(typeof(PlayerController), "DebugEnergy")?.SetValue(obj, debugEnergyWas); } if (!LocalAvatarDead()) { SetLocalFlashlight(on: true); } else { SetLocalFlashlight(on: false); } } private void AddPossessionVisionLight() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_003d: 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) Transform val = PlayerBodyRoot(); if (!((Object)(object)val == (Object)null)) { GameObject val2 = new GameObject("PossessionVisionLight"); val2.transform.SetParent(val, false); val2.transform.localPosition = new Vector3(0f, 2f, 0f); possessionLight = val2.AddComponent<Light>(); possessionLight.type = (LightType)1; possessionLight.intensity = 0.25f; possessionLight.shadows = (LightShadows)0; possessionLight.color = new Color(0.35f, 0.4f, 0.75f, 1f); } } private void LateUpdate() { //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: 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_0104: 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_0233: 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_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) bool flag = PossessionController.IsPossessing && (Object)(object)PossessedRoot != (Object)null; if (!SpectateOwnedByMod && !flag) { return; } Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return; } Transform val = PlayerBodyRoot(); if (flag && (Object)(object)val != (Object)null) { Quaternion rotation = val.rotation; float y = ((Quaternion)(ref rotation)).eulerAngles.y; Vector3 val2 = val.position + Vector3.up * 0.95f; Vector3 val3 = Quaternion.Euler(0f, y, 0f) * (Vector3.back * 2.2f + Vector3.up * 1f); Vector3 position = val2 + val3; RaycastHit val4 = default(RaycastHit); if (Physics.Raycast(val2, ((Vector3)(ref val3)).normalized, ref val4, ((Vector3)(ref val3)).magnitude, LayerMask.GetMask(new string[1] { "Default" }), (QueryTriggerInteraction)1)) { position = ((RaycastHit)(ref val4)).point + ((RaycastHit)(ref val4)).normal * 0.2f; } ((Component)main).transform.position = position; ((Component)main).transform.rotation = Quaternion.Euler(lookPitch * 0.4f, y, 0f); if ((Object)(object)possessedPuppet != (Object)null) { possessedPuppet.transform.localRotation = Quaternion.identity; } } else if ((Object)(object)val != (Object)null) { lookYaw += Input.GetAxis("Mouse X"); lookPitch = Mathf.Clamp(lookPitch - Input.GetAxis("Mouse Y"), -80f, 80f); ((Component)main).transform.position = val.position + Vector3.up * 2.5f; ((Component)main).transform.rotation = Quaternion.Euler(lookPitch, lookYaw, 0f); } main.nearClipPlane = 0.05f; main.farClipPlane = 500f; if (flag && (Object)(object)val != (Object)null) { if ((Object)(object)parkedLocalCamera != (Object)null) { ((Component)parkedLocalCamera).transform.SetPositionAndRotation(((Component)main).transform.position, ((Component)main).transform.rotation); } PlayerVisionTarget playerVisionTarget = LocalAvatar.PlayerVisionTarget; if ((Object)(object)playerVisionTarget != (Object)null && (Object)(object)playerVisionTarget.VisionTransform != (Object)null) { playerVisionTarget.VisionTransform.SetPositionAndRotation(((Component)main).transform.position, ((Component)main).transform.rotation); } } } private void TryStartPossession() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0072: 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_009c: Unknown result type (might be due to invalid IL or missing references) EnemyGnome val = null; float num = 20f; float y = ((Component)LocalAvatar).transform.position.y; bool flag = false; EnemyGnome[] array = Object.FindObjectsOfType<EnemyGnome>(); foreach (EnemyGnome val2 in array) { if ((Object)(object)val2.enemy == (Object)null || PossessionController.IsPossessing || IsEnemyOwned((Component)(object)val2)) { continue; } Vector3 position = RootOf(val2).position; if (position.y > y + 3f || position.y < y - 6f) { flag = true; continue; } float num2 = Vector3.Distance(((Component)val2).transform.position, ((Component)LocalAvatar).transform.position); if (num2 < num) { val = val2; num = num2; } } if (flag && (Object)(object)val == (Object)null) { Plugin.Log("Possession: gnomes found but drifting over/under the plane — spawning fresh"); } if ((Object)(object)val == (Object)null) { TrySpawnGnome(); } else { ActivatePossession(val); } } private void ParkLocalCamera() { PlayerLocalCamera val = (((Object)(object)LocalAvatar != (Object)null) ? LocalAvatar.localCamera : null); if ((Object)(object)val != (Object)null) { ((Behaviour)val).enabled = false; parkedLocalCamera = (Behaviour)(object)val; Plugin.Log("Vanilla local camera parked"); } else { Plugin.Log("Local camera park skipped (no localCamera)"); } } private void RestoreLocalCamera() { if ((Object)(object)parkedLocalCamera != (Object)null) { parkedLocalCamera.enabled = true; parkedLocalCamera = null; Plugin.Log("Vanilla local camera restored"); } } private void SetLocalFlashlight(bool on) { FlashlightController val = LocalAvatar?.flashlightController; if (!((Object)(object)val == (Object)null)) { if (!on) { FieldInfo fieldInfo = AccessTools.Field(typeof(FlashlightController), "active"); flashlightWasOn = fieldInfo != null && (bool)fieldInfo.GetValue(val); AccessTools.Method(typeof(FlashlightController), "LightOff", (Type[])null, (Type[])null)?.Invoke(val, null); } else if (flashlightWasOn) { AccessTools.Method(typeof(FlashlightController), "LightOn", (Type[])null, (Type[])null)?.Invoke(val, null); flashlightWasOn = false; } } } private void TrySpawnGnome() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: 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_00d5: 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) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: 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_011a: 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_0125: 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_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: 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_0093: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.CurrentRoom == null || PhotonNetwork.IsMasterClient || PhotonNetwork.CurrentRoom.PlayerCount <= 1) { Plugin.Log("No gnome nearby — spawning one (host)"); EnemySetup val = FindGnomeSetup(); if ((Object)(object)val == (Object)null) { Plugin.Log("Gnome EnemySetup not found"); return; } LevelPoint val2 = SemiFunc.LevelPointGet(((Component)LocalAvatar).transform.position, 15f, 40f) ?? SemiFunc.LevelPointGetFurthestFromPlayer(((Component)LocalAvatar).transform.position, 20f) ?? SemiFunc.LevelPointGetFurthestFromPlayer(((Component)LocalAvatar).transform.position, 5f); Vector3 val3 = ((Component)LocalAvatar).transform.position + Quaternion.Euler(0f, Random.Range(0f, 360f), 0f) * Vector3.forward * 3f; if ((Object)(object)val2 != (Object)null) { val3 = ((Component)val2).transform.position; Plugin.Log($"Spawn point picked: {val3} ({((Object)val2).name})"); } val3 += Vector3.up * 1.5f; List<EnemyParent> list = Enemies.SpawnEnemy(val, val3, Quaternion.identity, false); if (list != null) { Plugin.Log($"SpawnEnemy returned {list.Count} parents"); foreach (EnemyParent item in list) { EnemyGnome componentInChildren = ((Component)item).gameObject.GetComponentInChildren<EnemyGnome>(); if ((Object)(object)PossessedGnome == (Object)null && (Object)(object)componentInChildren != (Object)null) { PossessedGnome = componentInChildren; Plugin.Log("Spawn: possessing " + ((Object)componentInChildren).name + " under parent " + ((Object)item).name); } else { Plugin.Log("Spawn: removing extra " + (((componentInChildren != null) ? ((Object)componentInChildren).name : null) ?? "(no gnome)") + " under parent " + ((Object)item).name); RemoveExtra(item); } } } if ((Object)(object)PossessedGnome != (Object)null) { ActivatePossession(PossessedGnome); } else { Plugin.Log("Spawn succeeded but no EnemyGnome component found"); } } else if (Time.time - lastTimeNotifiedMissing > 3f) { lastTimeNotifiedMissing = Time.time; Plugin.Log("No gnome nearby and you are not the host — ask the host"); } } private static void RemoveExtra(EnemyParent parent) { if (!((Object)(object)parent == (Object)null)) { PhotonView value = Traverse.Create((object)parent).Field("photonView").GetValue<PhotonView>(); if ((Object)(object)value != (Object)null && PhotonNetwork.CurrentRoom != null && PhotonNetwork.IsMasterClient) { PhotonNetwork.Destroy(value); } else { Object.Destroy((Object)(object)((Component)parent).gameObject); } } } private static EnemySetup FindGnomeSetup() { foreach (EnemySetup allEnemy in Enemies.AllEnemies) { if (((Object)allEnemy).name != null && ((Object)allEnemy).name.ToLower().Contains("gnome")) { return allEnemy; } } return null; } private void EnsurePossessionVision() { Camera main = Camera.main; if (!((Object)(object)main == (Object)null)) { PossessionVision possessionVision = ((Component)main).GetComponent<PossessionVision>(); if ((Object)(object)possessionVision == (Object)null) { possessionVision = ((Component)main).gameObject.AddComponent<PossessionVision>(); } possessionVision.pixelation = HostConfig.SenseBlurIntensity; } } private static void RemovePossessionVision() { Camera main = Camera.main; if (!((Object)(object)main == (Object)null)) { PossessionVision component = ((Component)main).GetComponent<PossessionVision>(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } } } private void OnGUI() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_0035: 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_00b9: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) if (ResolveLocalAvatar() && InLevel() && CanPossess(LocalAvatarDead())) { GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 22 }; GUI.color = Color.white; if (PossessionController.IsPossessing) { GUI.Label(new Rect(20f, (float)(Screen.height - 60), 700f, 30f), "[F] End possession · [RMB] Attack · [LMB] Grab / [Wheel] push-pull", val); } else if (PossessionController.IsEligible()) { GUI.Label(new Rect(20f, (float)(Screen.height - 60), 700f, 30f), "[F] Possess a nearby gnome", val); } else { GUI.Label(new Rect(20f, (float)(Screen.height - 60), 700f, 30f), "Possession on cooldown", val); } if (PossessionController.IsPossessing && HostConfig.SenseBlurIntensity > 0f) { GUI.color = new Color(0f, 0f, 0f, HostConfig.SenseBlurIntensity); GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)Texture2D.whiteTexture); GUI.color = Color.white; } } } } public static class PossessionController { private static readonly Stopwatch cooldownStopwatch = new Stopwatch(); private static float possessionEndTime; public static bool IsPossessing { get; private set; } public static bool IsEligible() { if (IsPossessing) { return false; } if (ConfigSettings.DebugPossessWhileAlive.Value || ConfigSettings.DebugKillOnLevelStart.Value) { return true; } if (cooldownStopwatch.IsRunning) { return cooldownStopwatch.Elapsed.TotalSeconds >= (double)HostConfig.PossessionCooldown; } return true; } public static void StartPossession() { IsPossessing = true; bool flag = ConfigSettings.DebugPossessWhileAlive.Value || ConfigSettings.DebugKillOnLevelStart.Value; possessionEndTime = (flag ? float.MaxValue : (Time.time + HostConfig.MaxPossessionDuration)); Plugin.Log("Possession started" + (flag ? " (debug: no time limit)" : "")); } public static void EndPossession() { IsPossessing = false; cooldownStopwatch.Restart(); Plugin.Log("Possession ended"); } public static void Tick() { if (IsPossessing && Time.time >= possessionEndTime) { EndPossession(); } } } public class PossessionNetworking : MonoBehaviour, IOnEventCallback { private class PossessedPlayer { public int ActorNumber; public int GnomeViewId; public Vector3 Position; public bool Active; public bool RenderersHidden; public bool Stripped; public Transform Root; public readonly List<Renderer> HiddenRenderers = new List<Renderer>(); } private const byte PossessionStateEvent = 71; private const byte PossessionMoveEvent = 72; private const byte PossessionConfigEvent = 73; private const float CacheRefreshInterval = 2f; private const float ConfigBroadcastInterval = 10f; private static float nextConfigBroadcast; private readonly Dictionary<int, PossessedPlayer> possessed = new Dictionary<int, PossessedPlayer>(); private readonly Dictionary<int, EnemyGnome> gnomeByViewId = new Dictionary<int, EnemyGnome>(); private readonly Dictionary<int, PlayerVoiceChat> voiceByActor = new Dictionary<int, PlayerVoiceChat>(); private float nextCacheRefresh; private bool registered; public static PossessionNetworking Instance { get; private set; } private void Awake() { Instance = this; } private void OnDisable() { Unregister(); foreach (PossessedPlayer value in possessed.Values) { HideActorMeshes(value, hide: false); } possessed.Clear(); } private static bool GameReady() { if ((Object)(object)RunManager.instance != (Object)null && (Object)(object)GameDirector.instance != (Object)null) { return SemiFunc.RunIsLevel(); } return false; } private void EnsureRegistered() { if (!registered && PhotonNetwork.InRoom) { PhotonNetwork.AddCallbackTarget((object)this); registered = true; } } private void Unregister() { if (registered) { PhotonNetwork.RemoveCallbackTarget((object)this); registered = false; } } private void Update() { if (!GameReady()) { Unregister(); return; } EnsureRegistered(); if (Time.time < nextCacheRefresh) { return; } nextCacheRefresh = Time.time + 2f; CacheVoiceChats(); CacheGnomes(); BroadcastHostConfigIfNeeded(); foreach (PossessedPlayer value in possessed.Values) { if (value.Active && !value.Stripped) { resolveRoot(value); TryStrip(value); } if (value.Active && !value.RenderersHidden) { HideActorMeshes(value, hide: true); } } } private void TryStrip(PossessedPlayer entry) { if (entry.Stripped || entry.GnomeViewId <= 0 || (Object)(object)entry.Root == (Object)null) { return; } gnomeByViewId.TryGetValue(entry.GnomeViewId, out var value); if (!((Object)(object)value == (Object)null)) { int actorNumber = entry.ActorNumber; Player localPlayer = PhotonNetwork.LocalPlayer; if (actorNumber == ((localPlayer != null) ? new int?(localPlayer.ActorNumber) : ((int?)null))) { entry.Stripped = true; return; } PossessionBehavior.StripComponents(value, entry.Root); entry.Stripped = true; Plugin.Log($"Networked strip applied (actor {entry.ActorNumber})"); } } private void LateUpdate() { //IL_0057: 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) if (possessed.Count == 0) { return; } int num = LocalActor(); foreach (PossessedPlayer value2 in possessed.Values) { if (value2.Active) { if (value2.ActorNumber != num && (Object)(object)resolveRoot(value2) != (Object)null) { resolveRoot(value2).position = value2.Position; } if (value2.ActorNumber != num && voiceByActor.TryGetValue(value2.ActorNumber, out var value) && (Object)(object)value != (Object)null) { value.OverridePosition(value2.Position, 1.5f); } } } } public static PhotonView ViewIdOf(EnemyGnome gnome) { if (!((Object)(object)gnome == (Object)null)) { return Traverse.Create((object)gnome).Field("photonView").GetValue<PhotonView>(); } return null; } private static PhotonView VoiceView(PlayerVoiceChat voice) { if (!((Object)(object)voice == (Object)null)) { return Traverse.Create((object)voice).Field("photonView").GetValue<PhotonView>(); } return null; } private static PlayerAvatar VoiceAvatar(PlayerVoiceChat voice) { if (!((Object)(object)voice == (Object)null)) { return Traverse.Create((object)voice).Field("playerAvatar").GetValue<PlayerAvatar>(); } return null; } public void OnEvent(EventData eventData) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (eventData.Code == 71 && eventData.CustomData is int[] array && array.Length >= 2) { HandleState(array[0], array[1]); } else if (eventData.Code == 72 && eventData.CustomData is float[] array2 && array2.Length >= 4) { ApplyMove((int)array2[0], new Vector3(array2[1], array2[2], array2[3])); } else if (eventData.Code == 73 && eventData.CustomData is float[] array3 && array3.Length == 3) { HostConfig.Accept(array3); } } public static void BroadcastPossession(int actorNumber, EnemyGnome gnome) { //IL_003e: 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_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_0054: Expected O, but got Unknown if (ShouldNetwork()) { int[] array = new int[2] { actorNumber, ((Object)(object)gnome != (Object)null && (Object)(object)ViewIdOf(gnome) != (Object)null) ? ViewIdOf(gnome).ViewID : 0 }; PhotonNetwork.RaiseEvent((byte)71, (object)array, new RaiseEventOptions { Receivers = (ReceiverGroup)1 }, SendOptions.SendReliable); } } public static void BroadcastMove(int viewId, Vector3 position) { //IL_0015: 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_0027: 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_0039: 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_0048: Expected O, but got Unknown if (ShouldNetwork()) { float[] array = new float[4] { viewId, position.x, position.y, position.z }; PhotonNetwork.RaiseEvent((byte)72, (object)array, new RaiseEventOptions { Receivers = (ReceiverGroup)0 }, SendOptions.SendUnreliable); } } public static bool IsGnomePossessed(EnemyGnome gnome) { if ((Object)(object)Instance == (Object)null || (Object)(object)gnome == (Object)null || Instance.possessed.Count == 0) { return false; } PhotonView val = ViewIdOf(gnome); if ((Object)(object)val == (Object)null) { return false; } int viewID = val.ViewID; foreach (PossessedPlayer value in Instance.possessed.Values) { if (value.Active && value.GnomeViewId == viewID) { return true; } } return false; } private Transform resolveRoot(PossessedPlayer entry) { if ((Object)(object)entry.Root == (Object)null) { gnomeByViewId.TryGetValue(entry.GnomeViewId, out var value); entry.Root = (((Object)(object)value != (Object)null) ? PossessionBehavior.RootOf(value) : null); } return entry.Root; } public static bool IsRootPossessed(Transform root) { if ((Object)(object)Instance == (Object)null || (Object)(object)root == (Object)null || Instance.possessed.Count == 0) { return false; } foreach (PossessedPlayer value in Instance.possessed.Values) { if (value.Active && (Object)(object)value.Root == (Object)(object)root) { return true; } } return false; } private static bool ShouldNetwork() { Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != null) { return currentRoom.PlayerCount > 1; } return false; } private static void BroadcastHostConfigIfNeeded() { //IL_005c: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown if (ShouldNetwork() && PhotonNetwork.IsMasterClient && !(Time.time < nextConfigBroadcast)) { nextConfigBroadcast = Time.time + 10f; float[] array = new float[3] { ConfigSettings.MaxPossessionDuration.Value, ConfigSettings.PossessionCooldown.Value, ConfigSettings.SenseBlurIntensity.Value }; PhotonNetwork.RaiseEvent((byte)73, (object)array, new RaiseEventOptions { Receivers = (ReceiverGroup)0 }, SendOptions.SendReliable); } } private static int LocalActor() { Player localPlayer = PhotonNetwork.LocalPlayer; if (localPlayer == null) { return -1; } return localPlayer.ActorNumber; } private void HandleState(int actorNumber, int viewId) { PossessedPlayer value3; if (viewId > 0) { if (!possessed.TryGetValue(actorNumber, out var value)) { value = new PossessedPlayer { ActorNumber = actorNumber }; possessed[actorNumber] = value; } value.GnomeViewId = viewId; value.Active = true; gnomeByViewId.TryGetValue(viewId, out var value2); value.Root = (((Object)(object)value2 != (Object)null) ? PossessionBehavior.RootOf(value2) : null); TryStrip(value); HideActorMeshes(value, hide: true); } else if (possessed.TryGetValue(actorNumber, out value3)) { value3.Active = false; value3.Root = null; HideActorMeshes(value3, hide: false); } } private void ApplyMove(int viewId, Vector3 position) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) foreach (PossessedPlayer value in possessed.Values) { if (value.Active && value.GnomeViewId == viewId) { value.Position = position; break; } } } private void CacheVoiceChats() { voiceByActor.Clear(); PlayerVoiceChat[] array = Object.FindObjectsOfType<PlayerVoiceChat>(); foreach (PlayerVoiceChat val in array) { PhotonView val2 = VoiceView(val); if (!((Object)(object)val2 == (Object)null)) { int num = ((val2.Owner != null) ? val2.Owner.ActorNumber : (-1)); if (num > 0 && !voiceByActor.ContainsKey(num)) { voiceByActor[num] = val; } } } } private void CacheGnomes() { gnomeByViewId.Clear(); EnemyGnome[] array = Object.FindObjectsOfType<EnemyGnome>(); foreach (EnemyGnome val in array) { PhotonView val2 = ViewIdOf(val); if (!((Object)(object)val2 == (Object)null)) { gnomeByViewId[val2.ViewID] = val; } } } private void HideActorMeshes(PossessedPlayer entry, bool hide) { voiceByActor.TryGetValue(entry.ActorNumber, out var value); PlayerAvatar val = VoiceAvatar(value); if ((Object)(object)val == (Object)null) { return; } if (hide) { entry.HiddenRenderers.Clear(); Renderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null) && val2.enabled) { entry.HiddenRenderers.Add(val2); val2.enabled = false; } } entry.RenderersHidden = true; } else { if (!entry.RenderersHidden) { return; } foreach (Renderer hiddenRenderer in entry.HiddenRenderers) { if ((Object)(object)hiddenRenderer != (Object)null) { hiddenRenderer.enabled = true; } } entry.HiddenRenderers.Clear(); entry.RenderersHidden = false; } } } public class PossessionVision : MonoBehaviour { public float pixelation; private void OnRenderImage(RenderTexture source, RenderTexture destination) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (pixelation <= 0f) { Graphics.Blit((Texture)(object)source, destination); return; } int num = Mathf.Max(1, (int)(2f + pixelation * 18f)); RenderTexture temporary = RenderTexture.GetTemporary(Mathf.Max(16, ((Texture)source).width / num), Mathf.Max(16, ((Texture)source).height / num), 0, source.format); ((Texture)temporary).filterMode = (FilterMode)0; Graphics.Blit((Texture)(object)source, temporary); Graphics.Blit((Texture)(object)temporary, destination); RenderTexture.ReleaseTemporary(temporary); } } } namespace DeadPossession.Patches { [HarmonyPatch(typeof(Enemy), "Update")] [HarmonyPatch(typeof(EnemyStateRoaming), "Update")] [HarmonyPatch(typeof(EnemyStateInvestigate), "Update")] [HarmonyPatch(typeof(EnemyStateChase), "Update")] [HarmonyPatch(typeof(EnemyStateChaseBegin), "Update")] [HarmonyPatch(typeof(EnemyStateChaseEnd), "Update")] [HarmonyPatch(typeof(EnemyStateChaseSlow), "Update")] [HarmonyPatch(typeof(EnemyStateLookUnder), "Update")] [HarmonyPatch(typeof(EnemyStateSneak), "Update")] [HarmonyPatch(typeof(EnemyStateSpawn), "Update")] [HarmonyPatch(typeof(EnemyStateStunned), "Update")] [HarmonyPatch(typeof(EnemyStateDespawn), "Update")] [HarmonyPatch(typeof(EnemyNavMeshAgent), "Update")] [HarmonyPatch(typeof(EnemyRigidbody), "Update")] [HarmonyPatch(typeof(EnemyRigidbody), "FixedUpdate")] [HarmonyPatch(typeof(EnemyParent), "Update")] [HarmonyPatch(typeof(EnemyGrounded), "Update")] [HarmonyPatch(typeof(EnemyGnomeAnim), "Update")] [HarmonyPatch(typeof(PhysGrabObject), "Update")] [HarmonyPatch(typeof(PhysGrabObject), "FixedUpdate")] public static class EnemyAiPatch { [HarmonyPrefix] public static bool SkipWhenPossessed(object __instance) { Component val = (Component)((__instance is Component) ? __instance : null); if (!((Object)(object)val == (Object)null)) { return !PossessionBehavior.IsEnemyOwned(val); } return true; } } [HarmonyPatch(typeof(EnemyGnome), "Update")] [HarmonyPatch(typeof(EnemyGnome), "FixedUpdate")] public static class EnemyGnomeUpdatePatch { [HarmonyPrefix] public static bool SkipWhilePossessed(object __instance) { EnemyGnome val = (EnemyGnome)((__instance is EnemyGnome) ? __instance : null); if ((Object)(object)val == (Object)null) { return true; } if ((Object)(object)val == (Object)(object)PossessionBehavior.PossessedGnome) { return PossessionBehavior.AttackWindowOpen; } return !PossessionBehavior.IsEnemyOwned((Component)(object)val); } } [HarmonyPatch] public static class PlayerAvatarPatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(PlayerAvatar), "Revive", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(PlayerAvatar), "ReviveRPC", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(PlayerTumble), "TumbleRequest", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(PlayerTumble), "TumbleRequestRPC", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(PlayerTumble), "TumbleSet", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(PlayerTumble), "TumbleSetRPC", (Type[])null, (Type[])null); } private static bool Prefix(MethodBase __originalMethod) { if (PossessionController.IsPossessing) { Plugin.Log("Blocked vanilla body call while possessing: " + __originalMethod.Name); return false; } return true; } } [HarmonyPatch(typeof(SpectateCamera), "Update")] [HarmonyPatch(typeof(SpectateCamera), "LateUpdate")] public static class SpectateCameraPatch { private static bool Prefix() { return !PossessionBehavior.SpectateOwnedByMod; } } [HarmonyPatch(typeof(SpectateHeadUI), "Update")] public static class SpectateHeadUIPatch { private static bool Prefix() { if (!ConfigSettings.DebugKillOnLevelStart.Value) { return !ConfigSettings.DebugPossessWhileAlive.Value; } return false; } } }