Decompiled source of Puppeteer v1.0.5
BepInEx/plugins/Puppeteer.dll
Decompiled 3 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using Fusion; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Microsoft.CodeAnalysis; using Pathfinding; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("Puppeteer")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Puppeteer")] [assembly: AssemblyTitle("Puppeteer")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.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 ShiftAtMidnightPuppeteer { internal sealed class AnimatorDriver { private enum CueKind { None, Trigger, Bool, State } private struct Cue { public CueKind Kind; public int Hash; public bool Valid => Kind != CueKind.None; } private static readonly string[] MoveNames = new string[5] { "walking", "walk", "moving", "ismoving", "iswalking" }; private static readonly string[] RunNames = new string[6] { "running", "run", "sprint", "sprinting", "isrunning", "chasing" }; private static readonly string[] CrouchNames = new string[3] { "crouching", "crouch", "iscrouching" }; private static readonly string[] SpeedNames = new string[3] { "speed", "movespeed", "velocity" }; private Animator _animator; private readonly List<int> _moveBools = new List<int>(); private readonly List<int> _runBools = new List<int>(); private readonly List<int> _crouchBools = new List<int>(); private readonly List<int> _speedFloats = new List<int>(); private readonly Dictionary<string, AnimatorControllerParameter> _paramsByName = new Dictionary<string, AnimatorControllerParameter>(StringComparer.OrdinalIgnoreCase); private Cue _walkCue; private Cue _runCue; private Cue _idleCue; private Cue _actionCue; private Cue _activeCue; private bool _useOverrides; private int _walkState; private int _runState; private int _idleState; private int _currentState; private int _walkTrigger; private int _runTrigger; private int _idleTrigger; private int _currentTrigger; public bool HasAnyMapping => _moveBools.Count > 0 || _runBools.Count > 0 || _crouchBools.Count > 0 || _speedFloats.Count > 0; public string MappingSummary => HasTriggers ? $"triggers walk/run/idle={_walkTrigger != 0}/{_runTrigger != 0}/{_idleTrigger != 0}" : (HasStates ? $"states walk/run/idle={_walkState != 0}/{_runState != 0}/{_idleState != 0}" : (HasAnyMapping ? $"params move:{_moveBools.Count} run:{_runBools.Count} crouch:{_crouchBools.Count}" : "nothing drivable - playing default clip")); public bool HasOverrides => _useOverrides; public bool HasAction => _actionCue.Valid; public bool HasTriggers => _walkTrigger != 0 || _runTrigger != 0 || _idleTrigger != 0; public bool HasStates => _walkState != 0 || _runState != 0 || _idleState != 0; public void Bind(GameObject model) { //IL_0156: 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_018b: Invalid comparison between Unknown and I4 //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Invalid comparison between Unknown and I4 //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Invalid comparison between Unknown and I4 _animator = null; _moveBools.Clear(); _walkTrigger = (_runTrigger = (_idleTrigger = (_currentTrigger = 0))); _paramsByName.Clear(); _useOverrides = false; _walkCue = (_runCue = (_idleCue = (_actionCue = (_activeCue = default(Cue))))); _runBools.Clear(); _crouchBools.Clear(); _speedFloats.Clear(); if ((Object)(object)model == (Object)null) { return; } _animator = PickAnimator(model); if ((Object)(object)_animator == (Object)null) { return; } Il2CppReferenceArray<AnimatorControllerParameter> parameters = _animator.parameters; if (parameters == null) { return; } List<string> list = new List<string>(); foreach (AnimatorControllerParameter item in (Il2CppArrayBase<AnimatorControllerParameter>)(object)parameters) { if (item == null) { continue; } string text = item.name.ToLowerInvariant(); list.Add($"{item.name}:{item.type}"); _paramsByName[item.name] = item; if ((int)item.type == 4) { if (Matches(text, RunNames)) { _runBools.Add(item.nameHash); } else if (Matches(text, CrouchNames)) { _crouchBools.Add(item.nameHash); } else if (Matches(text, MoveNames)) { _moveBools.Add(item.nameHash); } } else if ((int)item.type == 1) { if (Matches(text, SpeedNames)) { _speedFloats.Add(item.nameHash); } } else if ((int)item.type == 9) { CollectTrigger(item.name, text, item.nameHash); } } BindStates(); } [Conditional("DEVTOOLS")] private void DumpPlayableStates() { RuntimeAnimatorController runtimeAnimatorController = _animator.runtimeAnimatorController; if ((Object)(object)runtimeAnimatorController == (Object)null) { return; } Il2CppReferenceArray<AnimationClip> animationClips = runtimeAnimatorController.animationClips; if (animationClips == null || ((Il2CppArrayBase<AnimationClip>)(object)animationClips).Length == 0) { return; } for (int i = 0; i < ((Il2CppArrayBase<AnimationClip>)(object)animationClips).Length; i++) { AnimationClip val = ((Il2CppArrayBase<AnimationClip>)(object)animationClips)[i]; if ((Object)(object)val == (Object)null) { continue; } string name = ((Object)val).name; string text = ""; string[] array = new string[2] { name, "Base Layer." + name }; foreach (string text2 in array) { try { if (_animator.HasState(0, Animator.StringToHash(text2))) { text = text + " PLAYABLE:\"" + text2 + "\""; } } catch { } } } } private static Animator PickAnimator(GameObject model) { Il2CppArrayBase<Animator> componentsInChildren = model.GetComponentsInChildren<Animator>(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { return null; } Animator val = null; Animator val2 = null; int num = -1; int num2 = -1; foreach (Animator item in componentsInChildren) { if ((Object)(object)item == (Object)null) { continue; } RuntimeAnimatorController runtimeAnimatorController = item.runtimeAnimatorController; Il2CppReferenceArray<AnimationClip> val3 = (((Object)(object)runtimeAnimatorController != (Object)null) ? runtimeAnimatorController.animationClips : null); int num3 = ((Il2CppArrayBase<AnimationClip>)(object)val3)?.Length ?? 0; int num4 = 0; if (val3 != null) { foreach (AnimationClip item2 in (Il2CppArrayBase<AnimationClip>)(object)val3) { if (!((Object)(object)item2 == (Object)null)) { string text = ((Object)item2).name.ToLowerInvariant(); if (text.Contains("walk") || text.Contains("run") || text.Contains("chase") || text.Contains("move")) { num4++; } } } } if (num4 > num) { num = num4; val = item; } if (num3 > num2) { num2 = num3; val2 = item; } } Animator val4 = ((num > 0) ? val : val2); if ((Object)(object)val4 != (Object)null) { } return val4; } private static bool Matches(string name, string[] candidates) { foreach (string text in candidates) { if (name == text) { return true; } } foreach (string value in candidates) { if (name.Contains(value)) { return true; } } return false; } private Cue Resolve(string name) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Invalid comparison between Unknown and I4 //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Invalid comparison between Unknown and I4 if (string.IsNullOrEmpty(name) || (Object)(object)_animator == (Object)null) { return default(Cue); } if (_paramsByName.TryGetValue(name, out var value)) { if ((int)value.type == 9) { return new Cue { Kind = CueKind.Trigger, Hash = value.nameHash }; } if ((int)value.type == 4) { return new Cue { Kind = CueKind.Bool, Hash = value.nameHash }; } } string[] array = new string[2] { name, "Base Layer." + name }; foreach (string text in array) { int num = Animator.StringToHash(text); try { if (_animator.HasState(0, num)) { return new Cue { Kind = CueKind.State, Hash = num }; } } catch { } } return default(Cue); } public void ApplyOverrides(VerifiedEntity cfg) { _useOverrides = false; if (cfg != null && !((Object)(object)_animator == (Object)null)) { _walkCue = Resolve(cfg.Walk); _runCue = Resolve(cfg.Run); _idleCue = Resolve(cfg.Idle); _actionCue = Resolve(cfg.Action); _activeCue = default(Cue); _useOverrides = _walkCue.Valid || _idleCue.Valid || _runCue.Valid; } } private void Fire(Cue cue, bool on = true) { if (!cue.Valid) { return; } try { if (cue.Kind == CueKind.Trigger) { _animator.SetTrigger(cue.Hash); } else if (cue.Kind == CueKind.Bool) { _animator.SetBool(cue.Hash, on); } else { _animator.Play(cue.Hash, 0, 0f); } } catch { } } public void PlayAction() { if (_actionCue.Valid) { Fire(_actionCue); _activeCue = default(Cue); } } private void TickOverrides(bool isMoving, bool isRunning) { Cue cue = ((!isMoving) ? _idleCue : ((isRunning && _runCue.Valid) ? _runCue : _walkCue)); if (!cue.Valid) { cue = _idleCue; } if (cue.Valid) { if (_walkCue.Kind == CueKind.Bool) { Fire(_walkCue, isMoving); } if (_runCue.Kind == CueKind.Bool) { Fire(_runCue, isMoving && isRunning); } if (cue.Kind != CueKind.Bool && (cue.Hash != _activeCue.Hash || cue.Kind != _activeCue.Kind)) { _activeCue = cue; Fire(cue); } } } private void CollectTrigger(string original, string lower, int hash) { if (!lower.Contains("drunk") && !lower.Contains("zombie") && !lower.Contains("injured") && !lower.Contains("cane") && !lower.Contains("pistol") && !lower.Contains("crawl") && !lower.Contains("moonwalk") && !lower.Contains("catwalk") && !lower.Contains("slow")) { if (lower == "standard walk" || (_walkTrigger == 0 && lower.Contains("walk"))) { _walkTrigger = hash; } if (lower == "standard run" || (_runTrigger == 0 && (lower.Contains("run") || lower == "jog"))) { _runTrigger = hash; } if (lower == "standard idle" || (_idleTrigger == 0 && lower.Contains("idle"))) { _idleTrigger = hash; } } } private void BindStates() { _walkState = (_runState = (_idleState = (_currentState = 0))); RuntimeAnimatorController runtimeAnimatorController = _animator.runtimeAnimatorController; Il2CppReferenceArray<AnimationClip> val = (((Object)(object)runtimeAnimatorController != (Object)null) ? runtimeAnimatorController.animationClips : null); if (val == null) { return; } foreach (AnimationClip item in (Il2CppArrayBase<AnimationClip>)(object)val) { if ((Object)(object)item == (Object)null) { continue; } int num = Animator.StringToHash(((Object)item).name); try { if (!_animator.HasState(0, num)) { continue; } } catch { continue; } string text = ((Object)item).name.ToLowerInvariant(); if (!text.Contains("crawl") && !text.Contains("zombie") && !text.Contains("drunk") && !text.Contains("injured") && !text.Contains("pistol") && !text.Contains("cane")) { if (_runState == 0 && (text.Contains("standard run") || text.Contains("jog") || text == "run")) { _runState = num; } if (_walkState == 0 && (text.Contains("standard walk") || text.Contains("male walking"))) { _walkState = num; } if (_idleState == 0 && text.Contains("standard idle")) { _idleState = num; } } } foreach (AnimationClip item2 in (Il2CppArrayBase<AnimationClip>)(object)val) { if ((Object)(object)item2 == (Object)null) { continue; } int num2 = Animator.StringToHash(((Object)item2).name); try { if (!_animator.HasState(0, num2)) { continue; } } catch { continue; } string text2 = ((Object)item2).name.ToLowerInvariant(); if (_walkState == 0 && text2.Contains("walk")) { _walkState = num2; } if (_runState == 0 && text2.Contains("run")) { _runState = num2; } if (_idleState == 0 && text2.Contains("idle")) { _idleState = num2; } } } public void Tick(bool isMoving, bool isRunning, bool isCrouching) { if ((Object)(object)_animator == (Object)null) { return; } if (_useOverrides || HasStates || HasTriggers) { if (_useOverrides) { TickOverrides(isMoving, isRunning); } else if (HasTriggers) { int num = ((!isMoving) ? _idleTrigger : ((isRunning && _runTrigger != 0) ? _runTrigger : _walkTrigger)); if (num == 0) { num = _idleTrigger; } if (num != 0 && num != _currentTrigger) { _currentTrigger = num; try { _animator.SetTrigger(num); } catch { } } } else { int num2 = ((!isMoving) ? _idleState : ((isRunning && _runState != 0) ? _runState : _walkState)); if (num2 == 0) { num2 = _idleState; } if (num2 != 0 && num2 != _currentState) { _currentState = num2; try { _animator.Play(num2, 0, 0f); } catch { } } } } if (!HasAnyMapping) { return; } foreach (int moveBool in _moveBools) { _animator.SetBool(moveBool, isMoving); } foreach (int runBool in _runBools) { _animator.SetBool(runBool, isRunning); } foreach (int crouchBool in _crouchBools) { _animator.SetBool(crouchBool, isCrouching); } if (_speedFloats.Count <= 0) { return; } float num3 = ((!isMoving) ? 0f : (isRunning ? 1f : 0.5f)); foreach (int speedFloat in _speedFloats) { _animator.SetFloat(speedFloat, num3); } } } internal sealed class BodyPark { private const float DriftTolerance = 0.75f; private const float DeliberateMoveDistance = 15f; private const float CorrectionCooldown = 0.5f; private const int MaxCorrections = 20; private Vector3 _spot; private Quaternion _rotation; private bool _weSetLockMove; private float _nextCorrection; private int _corrections; public bool Parked { get; private set; } public Vector3 Spot => _spot; public void Park() { //IL_002a: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; if ((Object)(object)localPlayerManager == (Object)null) { ModLog.Warning("Cannot park: no local player."); return; } _spot = ((Component)localPlayerManager).transform.position; _rotation = ((Component)localPlayerManager).transform.rotation; _nextCorrection = 0f; _corrections = 0; FPSController fpsScript = localPlayerManager.fpsScript; if ((Object)(object)fpsScript != (Object)null) { try { _weSetLockMove = !fpsScript.lockMove; fpsScript.lockMove = true; fpsScript.verticalVelocity = 0f; } catch (Exception ex) { ModLog.Warning("Could not lock body movement: " + ex.Message); } } Parked = true; } public void Hold() { //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_00a9: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) if (!Parked) { return; } PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; if ((Object)(object)localPlayerManager == (Object)null) { return; } FPSController fpsScript = localPlayerManager.fpsScript; if ((Object)(object)fpsScript != (Object)null) { try { if (!fpsScript.lockMove) { fpsScript.lockMove = true; } } catch { } } float num = Vector3.Distance(((Component)localPlayerManager).transform.position, _spot); if (num <= 0.75f) { return; } if (num >= 15f) { _spot = ((Component)localPlayerManager).transform.position; _rotation = ((Component)localPlayerManager).transform.rotation; } else { if (Time.time < _nextCorrection) { return; } _nextCorrection = Time.time + 0.5f; if (++_corrections > 20) { ModLog.Warning($"Body will not stay parked after {20} attempts - " + "leaving it where it is and unlocking it."); Unlock(); Parked = false; return; } TeleportPlayer val = Teleporter(localPlayerManager); if (!((Object)(object)val == (Object)null)) { try { val.RequestTeleport(_spot, _rotation); } catch (Exception ex) { ModLog.Warning("Drift correction failed, leaving the body where it is: " + ex.Message); } } } } public void Relocate(Vector3 position) { //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_0045: 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) PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; if ((Object)(object)localPlayerManager == (Object)null) { return; } TeleportPlayer val = Teleporter(localPlayerManager); if ((Object)(object)val == (Object)null) { ModLog.Warning("No teleporter - body left where it was."); return; } try { val.RequestTeleport(position, _rotation); _spot = position; } catch (Exception ex) { ModLog.Warning("Could not bring the body over: " + ex.Message); } } private static TeleportPlayer Teleporter(PlayerManager pm) { try { if ((Object)(object)pm.tpPlayer != (Object)null) { return pm.tpPlayer; } ClientPlayer localPlayer = NetworkContext.LocalPlayer; if ((Object)(object)localPlayer != (Object)null && (Object)(object)localPlayer.teleportPlayer != (Object)null) { return localPlayer.teleportPlayer; } } catch { } return null; } private void Unlock() { if (!_weSetLockMove) { return; } _weSetLockMove = false; PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; FPSController val = (((Object)(object)localPlayerManager != (Object)null) ? localPlayerManager.fpsScript : null); if ((Object)(object)val == (Object)null) { return; } try { val.lockMove = false; } catch (Exception ex) { ModLog.Warning("Could not restore movement lock: " + ex.Message); } } public void Release() { if (Parked || _weSetLockMove) { Parked = false; Unlock(); } } } internal sealed class MorphEntry { public string Name; public string Category; public GameObject Prefab; public bool Networked; public bool Curated; public bool Configured; public bool Released; public bool Verified; public float GroundOffset; public float ScaleOverride; public VerifiedEntity Anim; public string Label => (Configured ? "* " : " ") + Name + (Networked ? "" : " [local only]"); } internal sealed class VerifiedEntity { public readonly string Match; public readonly float GroundOffset; public readonly float ScaleOverride; public readonly bool Released; public readonly float SweepRadius; public readonly string Walk; public readonly string Run; public readonly string Idle; public readonly string Action; public readonly string[] Pacify; public readonly string[] Hostility; public readonly string ActionMethod; public readonly string[] DeathFields; public readonly string[] ForceTrue; public readonly string FreezeField; public readonly string ActionTargetField; public readonly float ActionReleaseTime; public readonly string[] AttackGate; public readonly string SecondaryMethod; public readonly string[] SecondaryFields; public readonly float ActionDuration; public readonly float ActionCooldown; public readonly float SecondaryCooldown; public readonly string DetectionField; public readonly string DetectionListField; public readonly string DetectionThresholdField; public readonly string InFlightField; public VerifiedEntity(string match, float groundOffset = 0f, float scaleOverride = 0f, bool released = false, float sweepRadius = 0f, string walk = null, string run = null, string idle = null, string action = null, string[] pacify = null, string[] hostility = null, string[] attackGate = null, string actionMethod = null, string secondaryMethod = null, string[] deathFields = null, string[] forceTrue = null, string freezeField = null, string actionTargetField = null, float actionReleaseTime = 0f, string[] secondaryFields = null, float actionDuration = 1.5f, float actionCooldown = 1.2f, float secondaryCooldown = 2f, string detectionField = null, string detectionListField = null, string detectionThresholdField = null, string inFlightField = null) { Match = match; Released = released; GroundOffset = groundOffset; ScaleOverride = scaleOverride; SweepRadius = sweepRadius; Walk = walk; Run = run; Idle = idle; Action = action; Pacify = pacify; Hostility = hostility; AttackGate = attackGate; ActionMethod = actionMethod; DeathFields = deathFields; ForceTrue = forceTrue; FreezeField = freezeField; ActionTargetField = actionTargetField; ActionReleaseTime = actionReleaseTime; SecondaryMethod = secondaryMethod; SecondaryFields = secondaryFields; ActionDuration = actionDuration; ActionCooldown = actionCooldown; SecondaryCooldown = secondaryCooldown; DetectionField = detectionField; DetectionListField = detectionListField; DetectionThresholdField = detectionThresholdField; InFlightField = inFlightField; } } internal sealed class PlayableCreature { public readonly string Display; public readonly string Prefab; public PlayableCreature(string display, string prefab) { Display = display; Prefab = prefab; } } internal static class EntityCatalog { internal static readonly PlayableCreature[] Playables = new PlayableCreature[5] { new PlayableCreature("Spider", "Spider (Lv1)"), new PlayableCreature("Spider II", "Spider (Lv2)"), new PlayableCreature("Spider III", "Spider (Lv3)"), new PlayableCreature("Shrieking Doll", "Shrieking Doll LVL 1"), new PlayableCreature("Shrieking Doll II", "Shrieking Doll LVL 2") }; private static readonly string[] BrowserPacify = new string[19] { "target", "goals", "generatedGoals", "useShelfGoals", "stopAtShelf", "goBehindCheckout", "waitingAtCounter", "hasPatience", "leaving", "forceTalkAtVeryStart", "dialogueInteractable", "_wanderAroundAimlessly", "timeStoppedWhileWandering", "isThief", "hasStolenItems", "doesntGiveBackItems", "countsAsCustomer", "addToReport", "startedFadingAway" }; private static readonly string[] BrowserHostility = new string[3] { "chasingPlayer", "targPlayerMan", "attacking" }; private static readonly string[] BrowserAttackGate = new string[1] { "chasingPlayer" }; private static readonly string[] BrowserForceTrue = new string[1] { "canNeverInteract" }; private static readonly VerifiedEntity[] Verified = new VerifiedEntity[23] { new VerifiedEntity("Rat", -0.08f, 0f, released: false, 0f, "Walk", null, "Idle", "Die"), new VerifiedEntity("Roach", -0.08f, 1f), new VerifiedEntity("Demented", -0.12f, 0f, released: false, 0f, "Standard Walk", "Standard Run", "Standard Idle", "Zombie Scream", new string[4] { "barricadeTarget", "breakingBarricade", "justAttackedBarricade", "spiderSpawn" }, new string[1] { "chaseTarget" }, new string[1] { "canAttack" }, null, null, null, null, "playersLookingAt", "chasingPlayerTarg"), new VerifiedEntity("Player Doppelgangers"), new VerifiedEntity("Player Doppelganger", -0.14f, 1f, released: false, 0f, "Standard Walk", "Standard Run", "Standard Idle", "Dancing", BrowserPacify, BrowserHostility, BrowserAttackGate, "Attack", "BreakFrontDoorBarricade", null, BrowserForceTrue, null, "targPlayerMan", 0f, null, 1.2f), new VerifiedEntity("PubertMotorCycle"), new VerifiedEntity("Pubert", -0.46f, 0f, released: false, 0f, "Standard Walk", "Standard Run", "Standard Idle", "Breakdancing", BrowserPacify, BrowserHostility, BrowserAttackGate, "Attack", "BreakFrontDoorBarricade", null, BrowserForceTrue, null, "targPlayerMan", 0f, null, 1.2f), new VerifiedEntity("Camouflaged", 0f, 0f, released: false, 0f, "Standard Walk", "Standard Run", "Standard Idle", "Airhorning"), new VerifiedEntity("Shrieking Doll", 0f, 0f, released: true, 0f, "Crawl", null, "Doll_Still", null, new string[8] { "barricadeTarget", "walkTarget", "breakingBarricade", "justAttackedBarricade", "chasingNonPlayerObject", "shotProj", "spiderSpawn", "dealtDamage" }, new string[3] { "chaseTarget", "scentTarget", "playerScentTarget" }, new string[1] { "canAttack" }, "JumpAtPlayer", null, forceTrue: new string[1] { "fastPacingButDontChasePlayer" }, deathFields: new string[2] { "died", "dealtDamage" }, freezeField: null, actionTargetField: "chasingPlayerTarg", actionReleaseTime: 3.5f, secondaryFields: null, actionDuration: 1.5f, actionCooldown: 1.2f, secondaryCooldown: 2f, detectionField: "detectionOfEachPlayer", detectionListField: "playerMans", detectionThresholdField: "detectsBeforeLookForJumpPoint", inFlightField: "actuallyJumping"), new VerifiedEntity("Bathroom Guy", -0.58f), new VerifiedEntity("Cow", -0.09f, 0f, released: false, 0f, "Walk", null, "Idle"), new VerifiedEntity("PET_Cat", -0.09f, 0f, released: false, 0f, "Arm_Cat|Walk_F_IP", "Arm_Cat|Run_F_IP", "Arm_Cat|Idle_1", "Arm_Cat|Lick"), new VerifiedEntity("PET_Puppy", -0.09f, 0f, released: false, 0f, "Arm_Labrador_Trot_F_IP", null, "Arm_Labrador_Idle_1", "Arm_Labrador_Eat_loop"), new VerifiedEntity("PET_Husky", -0.09f, 0f, released: false, 0f, "Arm_Husky_Trot_F_IP", null, "Arm_Husky_Idle_1", "Arm_Husky_Eat_loop"), new VerifiedEntity("PET_", -0.09f, 0f, released: false, 0f, "Walking", null, null, "Eat"), new VerifiedEntity("Tofu", -0.14f, 0f, released: false, 0f, "Walk", "Run", "Arm_Labrador|Idle_1", "Arm_Labrador|Bark", BrowserPacify, BrowserHostility, BrowserAttackGate, "Attack", "BreakFrontDoorBarricade", null, BrowserForceTrue, null, "targPlayerMan", 0f, null, 1.2f), new VerifiedEntity("Herbert", -0.12f, 0f, released: false, 0f, "Walk", "Run", "Idle", "Attack", BrowserPacify, BrowserHostility, BrowserAttackGate, "Attack", "BreakFrontDoorBarricade", null, BrowserForceTrue, null, "targPlayerMan", 0f, null, 1.2f), new VerifiedEntity("Marionette", 0f, 0f, released: false, 0f, "Bloodwraith_Idle", null, "Bloodwraith_Idle", "Marionette_Attack"), new VerifiedEntity("Fast Run", 0f, 0f, released: false, 0f, "Fast Run", "Fast Run", "Standing", "Zombie Attack"), new VerifiedEntity("Spider", 0f, 0f, released: true, 0f, null, null, null, "Attack", new string[9] { "silkEgg", "silkProjectile", "shotProj", "barricadeTarget", "ventTarget", "walkTarget", "breakingBarricade", "checkingVent", "chasingNonPlayerObject" }, new string[6] { "chasingPlayer", "chasingTarget", "chaseTarget", "chasingPlayerTarg", "scentTarget", "playerScentTarget" }, new string[1] { "canAttack" }, null, "PlaceInterstitialCobweb", null, null, null, null, 0f, new string[2] { "interstitialCobweb", "interstitialCobwebSpawnPoint" }), new VerifiedEntity("Dentist"), new VerifiedEntity("Vanessa"), new VerifiedEntity("Creepy Painting") }; private static string[] _verifiedNames; private static List<MorphEntry> _entries; private static Dictionary<IntPtr, MorphEntry> _byObject; private static bool _prefabTableLoaded; public static string[] PlayableNames => Playables.Select((PlayableCreature p) => p.Display).ToArray(); public static string[] VerifiedNames { get { if (_verifiedNames == null) { _verifiedNames = (from n in Verified.Select((VerifiedEntity v) => v.Match).Distinct() orderby n select n).ToArray(); } return _verifiedNames; } } public static List<MorphEntry> Entries { get { if (_entries == null) { Build(); } return _entries; } } public static List<MorphEntry> Supported => Entries.Where((MorphEntry e) => e.Released).ToList(); private static VerifiedEntity FindVerified(string name) { VerifiedEntity[] verified = Verified; foreach (VerifiedEntity verifiedEntity in verified) { if (MatchesWord(name, verifiedEntity.Match)) { return verifiedEntity; } } return null; } private static bool MatchesWord(string name, string match) { int startIndex = 0; while (true) { startIndex = name.IndexOf(match, startIndex, StringComparison.OrdinalIgnoreCase); if (startIndex < 0) { return false; } if (startIndex == 0 || !char.IsLetter(name[startIndex - 1])) { break; } startIndex++; } return true; } public static MorphEntry FindCurated(string match) { if (string.IsNullOrEmpty(match)) { return null; } MorphEntry morphEntry = null; foreach (MorphEntry entry in Entries) { if (entry.Anim != null && string.Equals(entry.Anim.Match, match, StringComparison.OrdinalIgnoreCase)) { if (entry.Networked) { return entry; } if (morphEntry == null) { morphEntry = entry; } } } return morphEntry; } public static void Invalidate() { _entries = null; _byObject = null; _prefabTableLoaded = false; } public static MorphEntry FindPlayable(string display) { if (string.IsNullOrWhiteSpace(display)) { return null; } string wanted = display; PlayableCreature[] playables = Playables; foreach (PlayableCreature playableCreature in playables) { if (string.Equals(playableCreature.Display, display, StringComparison.OrdinalIgnoreCase)) { wanted = playableCreature.Prefab; break; } } MorphEntry morphEntry = Resolve(wanted); if (morphEntry != null) { return morphEntry; } if (LoadPrefabTable()) { morphEntry = Resolve(wanted); if (morphEntry != null) { return morphEntry; } } List<MorphEntry> supported = Supported; ModLog.Warning($"'{display}' was not found in this game build, even after loading the prefab table. Falling back to '{((supported.Count > 0) ? supported[0].Name : "nothing - no creature is available")}'."); return (supported.Count > 0) ? supported[0] : null; } private static MorphEntry Resolve(string wanted) { List<MorphEntry> supported = Supported; foreach (MorphEntry item in supported) { if (string.Equals(item.Name, wanted, StringComparison.OrdinalIgnoreCase)) { return item; } } foreach (MorphEntry item2 in supported) { if (item2.Name.StartsWith(wanted, StringComparison.OrdinalIgnoreCase)) { return item2; } } foreach (MorphEntry item3 in supported) { if (MatchesWord(item3.Name, wanted)) { return item3; } } return null; } private static bool LoadPrefabTable() { if (_prefabTableLoaded || _byObject == null) { return false; } _prefabTableLoaded = true; Stopwatch stopwatch = Stopwatch.StartNew(); int count = _byObject.Count; AddPrefabTable(_byObject); Compile(); stopwatch.Stop(); return true; } private static void Build() { _byObject = new Dictionary<IntPtr, MorphEntry>(); _prefabTableLoaded = false; Stopwatch stopwatch = Stopwatch.StartNew(); AddCurated(_byObject); Compile(); stopwatch.Stop(); } private static void Compile() { foreach (MorphEntry value in _byObject.Values) { VerifiedEntity verifiedEntity = FindVerified(value.Name); if (verifiedEntity != null) { value.Verified = true; value.Configured = (verifiedEntity.Pacify != null && verifiedEntity.Pacify.Length != 0) || (verifiedEntity.Hostility != null && verifiedEntity.Hostility.Length != 0); value.Released = verifiedEntity.Released; value.GroundOffset = verifiedEntity.GroundOffset; value.ScaleOverride = verifiedEntity.ScaleOverride; value.Anim = verifiedEntity; } } _entries = (from e in _byObject.Values where e.Networked orderby e.Released descending, e.Configured descending, e.Verified descending, e.Curated descending, e.Category, e.Name select e).ToList(); } private static void Add(Dictionary<IntPtr, MorphEntry> map, GameObject go, string name, string category, bool curated) { if ((Object)(object)go == (Object)null) { return; } IntPtr pointer = ((Il2CppObjectBase)go).Pointer; if (map.TryGetValue(pointer, out var value)) { if (curated && !value.Curated) { value.Name = name; value.Category = category; value.Curated = true; } } else if (HasVisibleGeometry(go)) { map[pointer] = new MorphEntry { Name = (string.IsNullOrEmpty(name) ? ((Object)go).name : name), Category = category, Prefab = go, Networked = IsSpawnablePrefab(go), Curated = curated }; } } private static void AddPrefabTable(Dictionary<IntPtr, MorphEntry> map) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) try { NetworkProjectConfig global = NetworkProjectConfig.Global; NetworkPrefabTable val = ((global != null) ? global.PrefabTable : null); List<INetworkPrefabSource> val2 = ((val != null) ? val._sources : null); if (val2 == null) { ModLog.Warning("Fusion prefab table unavailable."); return; } int num = 0; int num2 = 0; for (int i = 0; i < val2.Count; i++) { try { INetworkPrefabSource val3 = val2[i]; if (val3 != null) { NetworkPrefabId id = val.GetId(val3.AssetGuid); NetworkObject val4 = val.Load(id, true); if ((Object)(object)val4 == (Object)null) { num2++; continue; } Add(map, ((Component)val4).gameObject, ((Object)((Component)val4).gameObject).name, "Networked", curated: false); num++; } } catch { num2++; } } } catch (Exception ex) { ModLog.Warning("Prefab table pass failed: " + ex.Message); } } private static bool HasVisibleGeometry(GameObject go) { if ((Object)(object)go.GetComponent<RectTransform>() != (Object)null) { return false; } if ((Object)(object)go.GetComponentInChildren<SkinnedMeshRenderer>(true) != (Object)null) { return true; } return (Object)(object)go.GetComponentInChildren<MeshRenderer>(true) != (Object)null; } private static bool IsSpawnablePrefab(GameObject go) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (!HasNetworkIdentity(go)) { return false; } Scene scene = go.scene; return !((Scene)(ref scene)).IsValid(); } private static bool HasNetworkIdentity(GameObject go) { if ((Object)(object)go == (Object)null) { return false; } try { return (Object)(object)go.GetComponent<NetworkObject>() != (Object)null; } catch { return false; } } private static void AddCurated(Dictionary<IntPtr, MorphEntry> map) { TryAdd(delegate { HuntManager instance = HuntManager.Instance; if (!((Object)(object)instance == (Object)null)) { foreach (GameObject item in Interop.Safe<GameObject>(instance.monsterObjs)) { Add(map, item, ((Object)item).name, "Monster", curated: true); } Add(map, instance.spiderLvl1, "Spider (Lv1)", "Monster", curated: true); Add(map, instance.spiderLvl2, "Spider (Lv2)", "Monster", curated: true); Add(map, instance.spiderLvl3, "Spider (Lv3)", "Monster", curated: true); Add(map, instance.jackInTheBox, "Jack In The Box", "Monster", curated: true); } }, "HuntManager"); TryAdd(delegate { CurrentDayManager instance = CurrentDayManager.Instance; if ((Object)(object)instance == (Object)null) { return; } Add(map, instance.cow, "Cow", "Creature", curated: true); Add(map, instance.bathroomGuy, "Bathroom Guy", "Creature", curated: true); Add(map, instance.camouflagedMonster, "Camouflaged Monster", "Monster", curated: true); Add(map, instance.crawlingDentist, "Crawling Dentist", "Monster", curated: true); Add(map, instance.forestLimbs, "Forest Limbs", "Monster", curated: true); foreach (GameObject item2 in Interop.Safe<GameObject>(instance.allCars)) { Add(map, item2, ((Object)item2).name, "Vehicle", curated: true); } foreach (GameObject item3 in Interop.Safe<GameObject>(instance.thieves)) { Add(map, item3, ((Object)item3).name, "NPC", curated: true); } foreach (GameObject item4 in Interop.Safe<GameObject>(instance.eventNpcs)) { Add(map, item4, ((Object)item4).name, "NPC", curated: true); } foreach (Pet item5 in Interop.Safe<Pet>(instance.allPets)) { if ((Object)(object)item5 != (Object)null) { Add(map, ((Component)item5).gameObject, ((Object)((Component)item5).gameObject).name, "Pet", curated: true); } } }, "CurrentDayManager"); TryAdd(delegate { EventManager instance = EventManager.Instance; if (!((Object)(object)instance == (Object)null)) { Add(map, instance.playerDoppelganger, "Player Doppelganger", "Monster", curated: true); Add(map, instance.multiplePlayerDoppelgangers, "Player Doppelgangers (group)", "Monster", curated: true); Add(map, instance.rat, "Rat", "Creature", curated: true); Add(map, instance.roach, "Roach", "Creature", curated: true); if ((Object)(object)instance.vanessa != (Object)null) { Add(map, ((Component)instance.vanessa).gameObject, "Vanessa", "NPC", curated: true); } } }, "EventManager"); TryAdd(delegate { StoreManager instance = StoreManager.Instance; if ((Object)(object)instance == (Object)null) { return; } foreach (GameObject item6 in Interop.Safe<GameObject>(instance.allBrowsingNpcs)) { Add(map, item6, ((Object)item6).name, "Customer", curated: true); } foreach (GameObject item7 in Interop.Safe<GameObject>(instance.allNuisanceNpcs)) { Add(map, item7, ((Object)item7).name, "Customer", curated: true); } }, "StoreManager"); } private static void TryAdd(Action action, string source) { try { action(); } catch (Exception ex) { ModLog.Warning("Curated source '" + source + "' failed: " + ex.Message); } } } internal static class GameInput { private static InputAction _move; private static InputAction _sprint; private static InputAction _jump; private static InputAction _crouch; private static bool _resolved; private static bool _loggedFallback; public static Vector2 Move { get { //IL_0069: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) EnsureResolved(); if (_move != null) { try { Object val = _move.ReadValueAsObject(); return (val == null) ? Vector2.zero : ((Il2CppObjectBase)val).Unbox<Vector2>(); } catch (Exception ex) { FallbackOnce("move read failed: " + ex.Message); _move = null; } } return new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")); } } public static bool Sprint => Held(ref _sprint, (KeyCode)304); public static bool Jump => Held(ref _jump, (KeyCode)32); public static bool Crouch => Held(ref _crouch, (KeyCode)306); public static void Invalidate() { _resolved = false; _move = (_sprint = (_jump = (_crouch = null))); } private static void Resolve() { try { PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; FPSController val = (((Object)(object)localPlayerManager != (Object)null) ? localPlayerManager.fpsScript : null); PlayerInput val2 = (((Object)(object)val != (Object)null) ? val.playerInput : null); InputActionAsset val3 = (((Object)(object)val2 != (Object)null) ? val2.actions : null); if (!((Object)(object)val3 == (Object)null)) { _move = val3.FindAction(InputConstants.k_MoveActionID, false); _sprint = val3.FindAction(InputConstants.k_SprintActionID, false); _jump = val3.FindAction(InputConstants.k_JumpActionID, false); _crouch = val3.FindAction(InputConstants.k_CrouchActionID, false); _resolved = _move != null; } } catch (Exception ex) { ModLog.Warning("Could not bind input actions, falling back to legacy: " + ex.Message); } } private static string Describe(InputAction action) { if (action == null) { return "unbound"; } try { return "'" + action.name + "'"; } catch { return "bound"; } } private static void EnsureResolved() { if (!_resolved) { Resolve(); } } private static bool Held(ref InputAction action, KeyCode legacy) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) EnsureResolved(); if (action != null) { try { return action.IsPressed(); } catch (Exception ex) { FallbackOnce("button read failed: " + ex.Message); action = null; } } return Input.GetKey(legacy); } private static void FallbackOnce(string reason) { if (!_loggedFallback) { _loggedFallback = true; ModLog.Warning("Input System read failed, using legacy keys from here on (" + reason + "). Rebound keys and gamepads will not be honoured."); } } } internal static class Interop { private static Assembly _gameAssembly; private static Type[] _types; public static Assembly GameAssembly { get { if (_gameAssembly == null) { _gameAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "Assembly-CSharp"); } return _gameAssembly; } } public static Type[] GameTypes { get { if (_types != null) { return _types; } Assembly gameAssembly = GameAssembly; if (gameAssembly == null) { return _types = Array.Empty<Type>(); } try { _types = gameAssembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { _types = ex.Types.Where((Type t) => t != null).ToArray(); } catch (Exception ex2) { ModLog.Warning("Could not enumerate game types: " + ex2.Message); _types = Array.Empty<Type>(); } return _types; } } public static object WrapAs(Type generatedType, Component component) { return Activator.CreateInstance(generatedType, ((Il2CppObjectBase)component).Pointer); } public static Component FindComponent(GameObject go, Type generatedType, bool includeInactive = true) { Type val = Il2CppType.From(generatedType); if (val == (Type)null) { return null; } return go.GetComponentInChildren(val, includeInactive); } public static List<MoverType> DiscoverMoverTypes() { List<MoverType> list = new List<MoverType>(); Type[] gameTypes = GameTypes; Type[] array = gameTypes; foreach (Type type in array) { if (type == null || !type.IsClass || type.IsAbstract) { continue; } PropertyInfo property = type.GetProperty("NetworkedPosition", BindingFlags.Instance | BindingFlags.Public); PropertyInfo property2 = type.GetProperty("NetworkedRotation", BindingFlags.Instance | BindingFlags.Public); if (!(property == null) && !(property2 == null) && property.CanWrite && property2.CanWrite && !(property.PropertyType != typeof(Vector3)) && !(property2.PropertyType != typeof(Quaternion))) { PropertyInfo propertyInfo = type.GetProperty("IsPositionInitialised", BindingFlags.Instance | BindingFlags.Public); if (propertyInfo != null && (!propertyInfo.CanWrite || propertyInfo.PropertyType != typeof(NetworkBool))) { propertyInfo = null; } list.Add(new MoverType { Type = type, Position = property, Rotation = property2, Initialised = propertyInfo }); } } return list; } public static IEnumerable<T> Safe<T>(Il2CppReferenceArray<T> array) where T : Il2CppObjectBase { if (array == null) { yield break; } for (int i = 0; i < ((Il2CppArrayBase<T>)(object)array).Length; i++) { T v = ((Il2CppArrayBase<T>)(object)array)[i]; if (v != null) { yield return v; } } } public static IEnumerable<T> Safe<T>(List<T> list) { if (list == null) { yield break; } for (int i = 0; i < list.Count; i++) { T v = list[i]; if (v != null) { yield return v; } } } } internal sealed class MoverType { public Type Type; public PropertyInfo Position; public PropertyInfo Rotation; public PropertyInfo Initialised; } internal static class LocalModel { private const int MaxComponents = 4000; public static GameObject Create(GameObject prefab, Transform parent) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)prefab == (Object)null) { return null; } GameObject val = null; try { val = new GameObject("MorphHolder"); val.SetActive(false); Object.DontDestroyOnLoad((Object)(object)val); GameObject val2 = Object.Instantiate<GameObject>(prefab, val.transform); int length = val2.GetComponentsInChildren<Component>(true).Length; if (length > 4000) { ModLog.Warning($"'{((Object)prefab).name}' has {length} components - too large to " + "strip safely, skipping to avoid freezing the game."); return null; } Stopwatch stopwatch = Stopwatch.StartNew(); Strip(val2); Activate(val2); val2.transform.SetParent(parent, false); val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; ((Object)val2).name = "Morph_" + ((Object)prefab).name; val2.SetActive(true); return val2; } catch (Exception value) { ModLog.Error($"Failed to build local model for '{((Object)prefab).name}': {value}"); return null; } finally { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } } public static void Activate(GameObject root) { root.SetActive(true); foreach (SkinnedMeshRenderer componentsInChild in root.GetComponentsInChildren<SkinnedMeshRenderer>(true)) { if ((Object)(object)componentsInChild == (Object)null) { continue; } ((Renderer)componentsInChild).enabled = true; Transform val = ((Component)componentsInChild).transform; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root.transform) { if (!((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); } val = val.parent; } } foreach (MeshRenderer componentsInChild2 in root.GetComponentsInChildren<MeshRenderer>(true)) { if ((Object)(object)componentsInChild2 != (Object)null && ((Component)componentsInChild2).gameObject.activeInHierarchy) { ((Renderer)componentsInChild2).enabled = true; } } } private static void Strip(GameObject root) { Il2CppArrayBase<Component> componentsInChildren = root.GetComponentsInChildren<Component>(true); foreach (Component item in componentsInChildren) { if (!((Object)(object)item == (Object)null) && !((Object)(object)((Il2CppObjectBase)item).TryCast<Transform>() != (Object)null) && !((Object)(object)((Il2CppObjectBase)item).TryCast<Animator>() != (Object)null) && !((Object)(object)((Il2CppObjectBase)item).TryCast<SkinnedMeshRenderer>() != (Object)null) && !((Object)(object)((Il2CppObjectBase)item).TryCast<MeshRenderer>() != (Object)null) && !((Object)(object)((Il2CppObjectBase)item).TryCast<MeshFilter>() != (Object)null)) { try { Object.DestroyImmediate((Object)(object)item, true); } catch { } } } foreach (Collider componentsInChild in root.GetComponentsInChildren<Collider>(true)) { if ((Object)(object)componentsInChild != (Object)null) { try { Object.DestroyImmediate((Object)(object)componentsInChild, true); } catch { } } } } } internal static class ModLog { public static ManualLogSource Source; [Conditional("DEVTOOLS")] public static void Debug(string message) { ManualLogSource source = Source; if (source != null) { source.LogInfo((object)message); } } public static void Msg(string message) { ManualLogSource source = Source; if (source != null) { source.LogInfo((object)message); } } public static void Warning(string message) { ManualLogSource source = Source; if (source != null) { source.LogWarning((object)message); } } public static void Error(string message) { ManualLogSource source = Source; if (source != null) { source.LogError((object)message); } } } internal enum MorphMode { Phantom, Doppelganger, Puppet } [BepInPlugin("clementinise.shiftatmidnight.puppeteer", "Puppeteer", "1.0.0")] public class MorphPlugin : BasePlugin { public const string Guid = "clementinise.shiftatmidnight.puppeteer"; internal static ConfigEntry<KeyCode> MorphKey; internal static ConfigEntry<KeyCode> MarkKey; internal static ConfigEntry<string> DefaultCreature; internal static ConfigEntry<MorphMode> Mode; public override void Load() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) ModLog.Source = ((BasePlugin)this).Log; MorphKey = ((BasePlugin)this).Config.Bind<KeyCode>("Keybinds", "MorphKey", (KeyCode)285, "Become a creature, or return to your body. Also the way out if anything goes wrong."); MarkKey = ((BasePlugin)this).Config.Bind<KeyCode>("Keybinds", "MarkKey", (KeyCode)284, "Mark where you are standing. The next creature appears there instead of on you."); DefaultCreature = ((BasePlugin)this).Config.Bind<string>("Creature", "DefaultCreature", "Spider", new ConfigDescription("Which creature you become.", (AcceptableValueBase)(object)new AcceptableValueList<string>(EntityCatalog.PlayableNames), Array.Empty<object>())); Mode = ((BasePlugin)this).Config.Bind<MorphMode>("Creature", "Mode", MorphMode.Phantom, "Phantom: your body vanishes and you return to where you left it. Doppelganger: your body vanishes and you reappear where the creature was. Puppet: your body stays visible where it is while you drive the creature."); ClassInjector.RegisterTypeInIl2Cpp<MorphBehaviour>(); ((BasePlugin)this).AddComponent<MorphBehaviour>(); ModLog.Msg($"Puppeteer ready [{Mode.Value}]. {MorphKey.Value} to swap into a creature and back, {MarkKey.Value} to mark a spawn point."); } } public class MorphBehaviour : MonoBehaviour { private PuppetController _puppet; private ThirdPersonView _thirdPerson; private int _lastSceneHandle; private float _nextHeartbeat; private static bool MenuOpen => false; public MorphBehaviour(IntPtr handle) : base(handle) { } private void Awake() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) _puppet = new PuppetController(); _thirdPerson = new ThirdPersonView(); _puppet.OnMorphed = delegate { _thirdPerson.Enable(); _thirdPerson.SetDistance(_puppet.CameraDistance); }; _puppet.OnReverted = delegate { _thirdPerson.Disable(); }; Scene activeScene = SceneManager.GetActiveScene(); _lastSceneHandle = ((Scene)(ref activeScene)).handle; } [Conditional("DEVTOOLS")] private void Heartbeat() { if (Time.unscaledTime < _nextHeartbeat) { return; } _nextHeartbeat = Time.unscaledTime + 5f; if (!_puppet.Active && !_thirdPerson.Active && !MenuOpen) { return; } string text = "no player"; try { PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; if ((Object)(object)localPlayerManager != (Object)null) { FPSController fpsScript = localPlayerManager.fpsScript; text = $"lockCam={(((Object)(object)fpsScript != (Object)null) ? fpsScript.lockCam.ToString() : "?")} lockMove={(((Object)(object)fpsScript != (Object)null) ? fpsScript.lockMove.ToString() : "?")} paused={localPlayerManager.paused} dead={localPlayerManager.dead} noCursorLock={localPlayerManager.dontAllowLockCursor} timeScale={Time.timeScale:0.##}"; } } catch (Exception ex) { text = "read failed: " + ex.Message; } } private void Update() { //IL_001a: 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_00e0: Unknown result type (might be due to invalid IL or missing references) try { DetectSceneChange(); PauseSettings.Tick(); Notify.Tick(); if (Input.GetKeyDown(MorphPlugin.MorphKey.Value)) { ToggleMorph(); } if (Input.GetKeyDown(MorphPlugin.MarkKey.Value)) { MarkSpawnPoint(); } if (Input.GetMouseButtonDown(0) && !MenuOpen) { _puppet.PlayAction(); } if (Input.GetMouseButtonDown(1) && !MenuOpen) { _puppet.PlaySecondary(); } _puppet.Tick(_thirdPerson.Camera, !MenuOpen); _thirdPerson.Tick(!MenuOpen); if (_puppet.Active) { _thirdPerson.Target = _puppet.PuppetAnchor; _thirdPerson.PivotHeight = _puppet.CameraPivotHeight; } else { _thirdPerson.Target = null; } } catch (Exception value) { ModLog.Error($"Update: {value}"); } } private static bool HostOnlyRefused() { MorphTier tier = NetworkContext.Tier; object message; switch (tier) { case MorphTier.Authority: return false; default: message = "Not in a game yet - nothing to morph into"; break; case MorphTier.Client: message = "You are not the host - only the host can morph"; break; } Notify.Show((string)message); ModLog.Msg($"Refused: tier is {tier}, host or solo required."); return true; } private void ToggleMorph() { if (_puppet.Active || _thirdPerson.Active) { ResetEverything(); } else if (!HostOnlyRefused()) { MorphEntry morphEntry; try { morphEntry = EntityCatalog.FindPlayable(MorphPlugin.DefaultCreature.Value); } catch (Exception ex) { ModLog.Error("Creature list: " + ex.Message); return; } if (morphEntry == null) { ModLog.Msg("No creatures available yet - the list is built when a day loads."); } else { _puppet.Apply(morphEntry); } } } private void MarkSpawnPoint() { //IL_00c7: 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_00cc: 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_00fc: 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 (HostOnlyRefused()) { return; } if (MorphPlugin.Mode.Value == MorphMode.Doppelganger) { Notify.Show("Not used in Doppelganger - you swap places with the creature"); return; } if (_puppet.SpawnOverride.HasValue) { _puppet.SpawnOverride = null; Notify.Show("Spawn point cleared"); ModLog.Msg("Spawn point cleared - creatures appear where you are again."); return; } PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; if ((Object)(object)localPlayerManager == (Object)null) { Notify.Show("No player to mark from"); return; } Vector3 value = (_puppet.Active ? _puppet.PuppetAnchor : ((Component)localPlayerManager).transform.position); _puppet.SpawnOverride = value; Notify.Show($"Spawn point set - press {MorphPlugin.MarkKey.Value} again to clear"); ModLog.Msg($"Spawn point set at {((Vector3)(ref value)).ToString("0.#")} - creatures will appear there until you press {MorphPlugin.MarkKey.Value} again."); } private void ResetEverything() { try { _thirdPerson.Disable(); } catch (Exception ex) { ModLog.Error("Reset camera: " + ex.Message); } try { _puppet.Revert(); } catch (Exception ex2) { ModLog.Error("Reset puppet: " + ex2.Message); } try { PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; if ((Object)(object)localPlayerManager != (Object)null) { localPlayerManager.dontAllowLockCursor = false; FPSController fpsScript = localPlayerManager.fpsScript; if ((Object)(object)fpsScript != (Object)null) { fpsScript.lockCam = false; fpsScript.lockMove = false; fpsScript.LockCursor(); } } } catch (Exception ex3) { ModLog.Error("Reset input: " + ex3.Message); } ModLog.Msg("Reset - body restored, camera unlocked."); } private void FixedUpdate() { try { _puppet.FixedTick(); } catch (Exception value) { ModLog.Error($"FixedUpdate: {value}"); } } private void LateUpdate() { try { _puppet.ReassertHide(); _puppet.TickPendingRestore(); _puppet.TickRealign(); _thirdPerson.LateTick(); } catch (Exception value) { ModLog.Error($"LateUpdate: {value}"); } } private void OnDestroy() { try { ResetEverything(); } catch { } } private void DetectSceneChange() { //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) Scene activeScene = SceneManager.GetActiveScene(); int handle = ((Scene)(ref activeScene)).handle; if (handle != _lastSceneHandle) { _lastSceneHandle = handle; _puppet.Revert(); _thirdPerson.Disable(); EntityCatalog.Invalidate(); PauseSettings.Forget(); Notify.Forget(); _puppet.SpawnOverride = null; GameInput.Invalidate(); } } } internal enum MorphTier { Offline, Authority, Client } internal static class NetworkContext { public static NetworkRunner Runner { get { FusionNetworkManager instance = FusionNetworkManager.Instance; if ((Object)(object)instance == (Object)null) { return null; } NetworkRunner runner = instance._runner; if ((Object)(object)runner == (Object)null || !runner.IsRunning) { return null; } return runner; } } public static MorphTier Tier { get { NetworkRunner runner = Runner; if ((Object)(object)runner == (Object)null) { return MorphTier.Offline; } if (runner.IsServer && runner.CanSpawn) { return MorphTier.Authority; } return MorphTier.Client; } } public static string TierDescription => Tier switch { MorphTier.Authority => "Host/Solo - everyone sees your morph, mod or not", MorphTier.Client => "Client - morphing is disabled, only the host can morph", _ => "Not in a session", }; public static ClientPlayer LocalPlayer => ClientPlayer.Instance; public static PlayerManager LocalPlayerManager { get { ClientPlayer instance = ClientPlayer.Instance; return ((Object)(object)instance == (Object)null) ? null : instance.playerMan; } } public static ThirdPersonManager LocalBody { get { PlayerManager localPlayerManager = LocalPlayerManager; return ((Object)(object)localPlayerManager == (Object)null) ? null : localPlayerManager.thirdPersonMan; } } } internal static class Notify { private const float DefaultSeconds = 3f; private const float BottomMargin = 140f; private static GameObject _label; private static TextMeshProUGUI _text; private static float _hideAt; private static float _nextComplaint; public static void Show(string message, float seconds = 3f) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(message)) { return; } try { if (Ensure()) { ((TMP_Text)_text).text = message; ((TMP_Text)_text).alpha = 1f; Color color = ((Graphic)_text).color; ((Graphic)_text).color = new Color(color.r, color.g, color.b, 1f); ((Behaviour)_text).enabled = true; _label.SetActive(true); _hideAt = Time.unscaledTime + seconds; } } catch (Exception ex) { ModLog.Warning("Notification failed: " + ex.Message); } } public static void Tick() { if ((Object)(object)_label == (Object)null || !_label.activeSelf || Time.unscaledTime < _hideAt) { return; } try { _label.SetActive(false); } catch { } } public static void Forget() { _label = null; _text = null; _hideAt = 0f; } private static bool Ensure() { //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_label != (Object)null && (Object)(object)_text != (Object)null) { return true; } TextMeshProUGUI val = Source(); if ((Object)(object)val == (Object)null) { Complain("StoreManager.hintText is not available yet"); return false; } Canvas val2 = LiveCanvas(); if ((Object)(object)val2 == (Object)null) { Complain("no live UI canvas to attach to"); return false; } _label = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val2).transform); ((Object)_label).name = "Puppeteer Notification"; _text = _label.GetComponent<TextMeshProUGUI>(); if ((Object)(object)_text == (Object)null) { _text = _label.GetComponentInChildren<TextMeshProUGUI>(true); } if ((Object)(object)_text == (Object)null) { Object.Destroy((Object)(object)_label); _label = null; Complain("the cloned label has no TextMeshProUGUI"); return false; } StripInterference(_label); RectTransform component = _label.GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null) { component.anchorMin = new Vector2(0.5f, 0f); component.anchorMax = new Vector2(0.5f, 0f); component.pivot = new Vector2(0.5f, 0f); component.anchoredPosition = new Vector2(0f, 140f); ((Transform)component).localScale = Vector3.one; ((Transform)component).localRotation = Quaternion.identity; if (component.sizeDelta.x < 400f) { component.sizeDelta = new Vector2(900f, Mathf.Max(component.sizeDelta.y, 60f)); } } try { ((TMP_Text)_text).alignment = (TextAlignmentOptions)514; ((TMP_Text)_text).enableAutoSizing = false; } catch { } _label.transform.SetAsLastSibling(); _label.SetActive(false); return true; } private static void Complain(string why) { if (!(Time.unscaledTime < _nextComplaint)) { _nextComplaint = Time.unscaledTime + 10f; ModLog.Warning("[notify] cannot build the label yet - " + why + "."); } } private static void StripInterference(GameObject go) { StringBuilder stringBuilder = new StringBuilder(); foreach (Component componentsInChild in go.GetComponentsInChildren<Component>(true)) { if ((Object)(object)componentsInChild == (Object)null) { continue; } string text = TypeName(componentsInChild); if (text == "LanguageText" || text.IndexOf("Fade", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Animator", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Hint", StringComparison.OrdinalIgnoreCase) >= 0) { try { Object.Destroy((Object)(object)componentsInChild); stringBuilder.Append(text).Append(' '); } catch { } } } foreach (CanvasGroup componentsInChild2 in go.GetComponentsInChildren<CanvasGroup>(true)) { if (!((Object)(object)componentsInChild2 == (Object)null)) { try { componentsInChild2.alpha = 1f; componentsInChild2.blocksRaycasts = false; componentsInChild2.interactable = false; } catch { } } } if (stringBuilder.Length <= 0) { } } private static TextMeshProUGUI Source() { try { StoreManager instance = StoreManager.Instance; return ((Object)(object)instance != (Object)null) ? instance.hintText : null; } catch { return null; } } private static Canvas LiveCanvas() { try { PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; GameObject val = (((Object)(object)localPlayerManager != (Object)null) ? localPlayerManager.pauseMenu : null); if ((Object)(object)val == (Object)null) { return null; } Canvas val2 = Highest(val.transform); if ((Object)(object)val2 == (Object)null) { return null; } if (!((Component)val2).gameObject.activeInHierarchy) { Complain("canvas '" + ((Object)val2).name + "' is inactive"); return null; } return val2; } catch { return null; } } private static Canvas Highest(Transform from) { Canvas result = null; try { Transform val = from; while ((Object)(object)val != (Object)null) { Canvas component = ((Component)val).GetComponent<Canvas>(); if ((Object)(object)component != (Object)null) { result = component; } val = val.parent; } } catch { } return result; } private static string Describe(GameObject go) { StringBuilder stringBuilder = new StringBuilder(); foreach (Component component in go.GetComponents<Component>()) { if ((Object)(object)component != (Object)null) { stringBuilder.Append(TypeName(component)).Append(' '); } } return stringBuilder.ToString(); } private static string TypeName(Component c) { try { string text = ((Object)c).ToString(); int num = text.LastIndexOf('('); int num2 = text.LastIndexOf(')'); if (num < 0 || num2 <= num) { return text; } string text2 = text.Substring(num + 1, num2 - num - 1); int num3 = text2.LastIndexOf('.'); return (num3 >= 0) ? text2.Substring(num3 + 1) : text2; } catch { return "?"; } } } internal static class PauseSettings { private const string ButtonHolder = "Button Vertical Layout Group"; private const string ButtonTemplate = "Button Vertical Layout Group/Audio Button"; private static readonly Vector2 CornerMargin = new Vector2(-70f, 60f); private const string PanelTemplate = "Video Menu"; private const string ContentPath = "Scroll View/Viewport/Content"; private const string KeyRowTemplate = "Controls Menu/Scroll View/Viewport/Content/Jump"; private const string DropRowTemplate = "Video Menu/Scroll View/Viewport/Content/Change Resolution"; private static GameObject _builtFor; private static GameObject _panel; private static GameObject _button; private static PauseMenu _pauseMenu; private static ControlsMenuSwitcher _switcher; private static Transform _holder; private static Transform _proxy; private static readonly List<GameObject> _overlays = new List<GameObject>(); private static ConfigEntry<KeyCode> _capturing; private static TextMeshProUGUI _capturingText; private static GameObject _capturingBar; private static readonly KeyCode[] _keyCodes = BuildKeyCodes(); public static void Tick() { try { PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; GameObject val = (((Object)(object)localPlayerManager != (Object)null) ? localPlayerManager.pauseMenu : null); if (!((Object)(object)val == (Object)null)) { if ((Object)(object)_button == (Object)null || (Object)(object)_builtFor != (Object)(object)val) { Build(val); } FollowMenuVisibility(); YieldToOtherMenus(); CloseWithMenu(val); TickCapture(); } } catch (Exception value) { ModLog.Error($"Pause settings: {value}"); _builtFor = null; } } public static void Forget() { _builtFor = null; _panel = null; _button = null; _holder = null; _proxy = null; _overlays.Clear(); _pauseMenu = null; _capturing = null; } private static void FollowMenuVisibility() { if (!((Object)(object)_button == (Object)null) && !((Object)(object)_proxy == (Object)null)) { bool flag = ((Component)_proxy).gameObject.activeInHierarchy && Alpha(_proxy) > 0.01f && !AnyMenuOpen(); if (_button.activeSelf != flag) { _button.SetActive(flag); } } } private static bool AnyMenuOpen() { if (AnyOverlayOpen()) { return true; } try { if ((Object)(object)_pauseMenu == (Object)null) { return false; } if (_pauseMenu.inSubMenu) { return true; } Il2CppReferenceArray<GameObject> subMenus = _pauseMenu.subMenus; if (subMenus == null) { return false; } for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)subMenus).Length; i++) { if ((Object)(object)((Il2CppArrayBase<GameObject>)(object)subMenus)[i] != (Object)null && ((Il2CppArrayBase<GameObject>)(object)subMenus)[i].activeSelf) { return true; } } } catch { } return false; } private static void CollectOverlays(GameObject menu) { _overlays.Clear(); try { if ((Object)(object)_switcher != (Object)null) { Add(_switcher.gamepadControls); } foreach (KickPlayerMenu componentsInChild in menu.GetComponentsInChildren<KickPlayerMenu>(true)) { if ((Object)(object)componentsInChild != (Object)null) { _overlays.Add(((Component)componentsInChild).gameObject); } } } catch (Exception ex) { ModLog.Warning("[pause] overlay scan: " + ex.Message); } } private static void Add(Il2CppReferenceArray<GameObject> items) { if (items == null) { return; } for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)items).Length; i++) { if ((Object)(object)((Il2CppArrayBase<GameObject>)(object)items)[i] != (Object)null) { _overlays.Add(((Il2CppArrayBase<GameObject>)(object)items)[i]); } } } private static bool AnyOverlayOpen() { for (int i = 0; i < _overlays.Count; i++) { GameObject val = _overlays[i]; if ((Object)(object)val != (Object)null && val.activeInHierarchy) { return true; } } return false; } private static float Alpha(Transform t) { float num = 1f; try { Transform val = t; while ((Object)(object)val != (Object)null) { CanvasGroup component = ((Component)val).GetComponent<CanvasGroup>(); if ((Object)(object)component != (Object)null) { num *= component.alpha; if (component.ignoreParentGroups) { break; } } val = val.parent; } } catch { } return num; } private static void YieldToOtherMenus() { if ((Object)(object)_panel == (Object)null || !_panel.activeSelf) { return; } if (AnyOverlayOpen()) { _panel.SetActive(false); return; } try { Il2CppReferenceArray<GameObject> val = (((Object)(object)_pauseMenu != (Object)null) ? _pauseMenu.subMenus : null); if (val == null) { return; } for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)val).Length; i++) { GameObject val2 = ((Il2CppArrayBase<GameObject>)(object)val)[i]; if (!((Object)(object)val2 == (Object)null) && !(((Il2CppObjectBase)val2).Pointer == ((Il2CppObjectBase)_panel).Pointer) && val2.activeSelf) { _panel.SetActive(false); break; } } } catch { } } private static void CloseWithMenu(GameObject menu) { if (!((Object)(object)_panel == (Object)null) && _panel.activeSelf && !menu.activeInHierarchy) { _panel.SetActive(false); } } private static void Build(GameObject menu) { Transform transform = menu.transform; Transform template = Require(transform, "Button Vertical Layout Group/Audio Button"); Transform template2 = Require(transform, "Video Menu"); Transform keyRow = Require(transform, "Controls Menu/Scroll View/Viewport/Content/Jump"); Transform dropRow = Require(transform, "Video Menu/Scroll View/Viewport/Content/Change Resolution"); Transform val = Require(transform, "Button Vertical Layout Group"); _proxy = transform.Find("Button Vertical Layout Group/Quit Button"); if ((Object)(object)_proxy == (Object)null) { _proxy = val; } CollectOverlays(menu); _pauseMenu = menu.GetComponentInChildren<PauseMenu>(true); _switcher = menu.GetComponentInChildren<ControlsMenuSwitcher>(true); _panel = BuildPanel(template2, keyRow, dropRow); _button = BuildButton(template, transform, ScreenRect(menu)); _holder = val; _builtFor = menu; RegisterSubMenu(_panel); } private static GameObject BuildPanel(Transform template, Transform keyRow, Transform dropRow) { GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, template.parent); ((Object)val).name = "Puppeteer Menu"; val.SetActive(false); Transform val2 = val.transform.Find("TITLE"); if ((Object)(object)val2 != (Object)null) { SetLabel(((Component)val2).gameObject, "PUPPETEER"); } Transform val3 = val.transform.Find("Scroll View/Viewport/Content"); if ((Object)(object)val3 == (Object)null) { throw new InvalidOperationException("Cloned panel has no Content."); } for (int num = val3.childCount - 1; num >= 0; num--) { Object.DestroyImmediate((Object)(object)((Component)val3.GetChild(num)).gameObject); } AddDropdownRow(val3, dropRow, "Creature", MorphPlugin.DefaultCreature, EntityCatalog.PlayableNames); AddModeRow(val3, dropRow, "Mode", MorphPlugin.Mode); AddKeyRow(val3, keyRow, "Become creature / return", MorphPlugin.MorphKey); AddKeyRow(val3, keyRow, "Mark spawn point", MorphPlugin.MarkKey); return val; } private static RectTransform ScreenRect(GameObject menu) { try { Canvas componentInParent = menu.GetComponentInParent<Canvas>(); if ((Object)(object)componentInParent == (Object)null) { return null; } Canvas val = (((Object)(object)componentInParent.rootCanvas != (Object)null) ? componentInParent.rootCanvas : componentInParent); RectTransform component = ((Component)val).GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null) { } return component; } catch { return null; } } private static GameObject BuildButton(Transform template, Transform menuRoot, RectTransform screen) { //IL_005e: 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_008a: 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_00a2: 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) DestroyStrays(screen); Transform val = (((Object)(object)screen != (Object)null) ? ((Component)screen).transform : menuRoot); GameObject val2 = Object.Instantiate<GameObject>(((Component)template).gameObject, val); ((Object)val2).name = "Puppeteer Button"; SetLabel(val2, "PUPPETEER"); RectTransform component = val2.GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null) { component.anchorMin = new Vector2(1f, 0f); component.anchorMax = new Vector2(1f, 0f); component.pivot = new Vector2(1f, 0f); component.anchoredPosition = CornerMargin; ((Transform)component).localScale = Vector3.one; ((Transform)component).localRotation = Quaternion.identity; } val2.transform.SetAsLastSibling(); Wire(val2, Open); return val2; } private static void DestroyStrays(RectTransform screen) { if ((Object)(object)screen == (Object)null) { return; } try { for (int num = ((Transform)screen).childCount - 1; num >= 0; num--) { Transform child = ((Transform)screen).GetChild(num); if ((Object)(object)child != (Object)null && ((Object)((Component)child).gameObject).name == "Puppeteer Button") { Object.DestroyImmediate((Object)(object)((Component)child).gameObject); } } } catch { } } private static void Wire(GameObject go, Action onClick) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown Button component = go.GetComponent<Button>(); if (!((Object)(object)component == (Object)null)) { component.onClick = new ButtonClickedEvent(); ((UnityEvent)component.onClick).AddListener(DelegateSupport.ConvertDelegate<UnityAction>((Delegate)onClick)); } } private static void AddKeyRow(Transform content, Transform template, string label, ConfigEntry<KeyCode> entry) { //IL_00ea: 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) if (entry == null) { return; } GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, content); ((Object)val).name = "Key " + label; val.SetActive(true); Transform val2 = val.transform.Find("Title"); if ((Object)(object)val2 != (Object)null) { SetLabel(((Component)val2).gameObject, label); } Transform val3 = val.transform.Find("Button"); if (!((Object)(object)val3 == (Object)null)) { TextMeshProUGUI text = ((Component)val3).GetComponentInChildren<TextMeshProUGUI>(true); Transform bar = val.transform.Find("EditingBar"); if ((Object)(object)text != (Object)null) { Strip(((Component)text).gameObject); ((TMP_Text)text).text = ((object)entry.Value/*cast due to .constrained prefix*/).ToString(); } Wire(((Component)val3).gameObject, delegate { BeginCapture(entry, text, ((Object)(object)bar != (Object)null) ? ((Component)bar).gameObject : null); }); } } private static void AddModeRow(Transform content, Transform template, string label, ConfigEntry<MorphMode> entry) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown if (entry == null) { return; } MorphMode[] modes = (MorphMode[])Enum.GetValues(typeof(MorphMode)); string[] array = new string[modes.Length]; for (int i = 0; i < modes.Length; i++) { array[i] = modes[i].ToString(); } TMP_Dropdown val = BuildDropdown(content, template, label, array, Array.IndexOf(modes, entry.Value)); if ((Object)(object)val == (Object)null) { return; } val.onValueChanged = new DropdownEvent(); ((UnityEvent<int>)(object)val.onValueChanged).AddListener(DelegateSupport.ConvertDelegate<UnityAction<int>>((Delegate)(Action<int>)delegate(int index) { if (index >= 0 && index < modes.Length) { entry.Value = modes[index]; } })); } private static void AddDropdownRow(Transform content, Transform template, string label, ConfigEntry<string> entry, string[] options) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown if (entry == null || options == null || options.Length == 0) { return; } int selected = 0; for (int i = 0; i < options.Length; i++) { if (string.Equals(options[i], entry.Value, StringComparison.OrdinalIgnoreCase)) { selected = i; } } TMP_Dropdown val = BuildDropdown(content, template, label, options, selected); if ((Object)(object)val == (Object)null) { return; } val.onValueChanged = new DropdownEvent(); ((UnityEvent<int>)(object)val.onValueChanged).AddListener(DelegateSupport.ConvertDelegate<UnityAction<int>>((Delegate)(Action<int>)delegate(int index) { if (index >= 0 && index < options.Length) { entry.Value = options[index]; } })); } private static TMP_Dropdown BuildDropdown(Transform content, Transform template, string label, string[] options, int selected) { GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, content); ((Object)val).name = "Choice " + label; val.SetActive(true); Transform val2 = val.transform.Find("Title"); if ((Object)(object)val2 != (Object)null) { SetLabel(((Component)val2).gameObject, label); } TMP_Dropdown componentInChildren = val.GetComponentInChildren<TMP_Dropdown>(true); if ((Object)(object)componentInChildren == (Object)null) { return null; } StripForeignBehaviours(((Component)componentInChildren).gameObject); List<string> val3 = new List<string>(); for (int i = 0; i < options.Length; i++) { val3.Add(options[i]); } componentInChildren.ClearOptions(); componentInChildren.AddOptions(val3); componentInChildren.SetValueWithoutNotify(Mathf.Clamp(selected, 0, Mathf.Max(options.Length - 1, 0))); componentInChildren.RefreshShownValue(); return componentInChildren; } private static void BeginCapture(ConfigEntry<KeyCode> entry, TextMeshProUGUI text, GameObject bar) { CancelCapture(); _capturing = entry; _capturingText = text; _capturingBar = bar; if ((Object)(object)_capturingText != (Object)null) { ((TMP_Text)_capturingText).text = "..."; } if ((Object)(object)_capturingBar != (Object)null) { _capturingBar.SetActive(true); } } private static void CancelCapture() { if ((Object)(object)_capturingBar != (Object)null) { _capturingBar.SetActive(false); } _capturing = null; _capturingText = null; _capturingBar = null; } private unsafe static void TickCapture() { //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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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) if (_capturing == null || !Input.anyKeyDown) { return; } if (Input.GetKeyDown((KeyCode)27)) { KeyCode value = _capturing.Value; TextMeshProUGUI capturingText = _capturingText; CancelCapture(); if ((Object)(object)capturingText != (Object)null) { ((TMP_Text)capturingText).text = ((object)(*(KeyCode*)(&value))/*cast due to .constrained prefix*/).ToString(); } return; } KeyCode[] keyCodes = _keyCodes; for (int i = 0; i < keyCodes.Length; i++) { KeyCode val = keyCodes[i]; if (Input.GetKeyDown(val)) { _capturing.Value = val; if ((Object)(object)_capturingText != (Object)null) { ((TMP_Text)_capturingText).text = ((object)(*(KeyCode*)(&val))/*cast due to .constrained prefix*/).ToString(); } CancelCapture(); break; } } } private static KeyCode[] BuildKeyCodes() { //IL_0029: 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_0033: Invalid comparison between Unknown and I4 //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Invalid comparison between Unknown and I4 //IL_004c: 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_0054: Invalid comparison between Unknown and I4 //IL_0062: Unknown result type (might be due to invalid IL or missing references) KeyCode[] array = (KeyCode[])Enum.GetValues(typeof(KeyCode)); List<KeyCode> list = new List<KeyCode>(array.Length); KeyCode[] array2 = array; foreach (KeyCode val in array2) { if (((int)val < 323 || (int)val > 329) && (int)val != 0 && (int)val != 27) { list.Add(val); } } return list.ToArray(); } private static void Open() { if ((Object)(object)_panel == (Object)null) { return; } HideSiblingMenus(); _panel.SetActive(true); try { if ((Object)(object)_pauseMenu != (Object)null) { _pauseMenu.inSubMenu = true; } } catch { } } private static void HideSiblingMenus() { try { Il2CppReferenceArray<GameObject> val = (((Object)(object)_pauseMenu != (Object)null) ? _pauseMenu.subMenus : null); if (val == null) { return; } for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)val).Length; i++) { GameObject val2 = ((Il2CppArrayBase<GameObject>)(object)val)[i]; if ((Object)(object)val2 != (Object)null && ((Il2CppObjectBase)val2).Pointer != ((Il2CppObjectBase)_panel).Pointer) { val2.SetActive(false); } } } catch { } } private static void RegisterSubMenu(GameObject panel) { try { Il2CppReferenceArray<GameObject> val = (((Object)(object)_pauseMenu != (Object)null) ? _pauseMenu.subMenus : null); if (val == null) { return; } for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)val).Length; i++) { if ((Object)(object)((Il2CppArrayBase<GameObject>)(object)val)[i] != (Object)null && ((Object)((Il2CppArrayBase<GameObject>)(object)val)[i]).name == ((Object)panel).name) { return; } } Il2CppReferenceArray<GameObject> val2 = new Il2CppReferenceArray<GameObject>((long)(((Il2CppArrayBase<GameObject>)(object)val).Length + 1)); for (int j = 0; j < ((Il2CppArrayBase<GameObject>)(object)val).Length; j++) { ((Il2CppArrayBase<GameObject>)(object)val2)[j] = ((Il2CppArrayBase<GameObject>)(object)val)[j]; } ((Il2CppArrayBase<GameObject>)(object)val2)[((Il2CppArrayBase<GameObject>)(object)val).Length] = panel; _pauseMenu.subMenus = val2; } catch (Exception ex) { ModLog.Warning("Could not register the sub-menu: " + ex.Message); } } private static Transform Require(Transform root, string path) { Transform val = root.Find(path); if ((Object)(object)val == (Object)null) { throw new InvalidOperationException("Pause menu path missing: '" + path + "'"); } return val; } private static void SetLabel(GameObject root, string text) { TextMeshProUGUI componentInChildren = root.GetComponentInChildren<TextMeshProUGUI>(true); if (!((Object)(object)componentInChildren == (Object)null)) { Strip(((Component)componentInChildren).gameObject); ((TMP_Text)componentInChildren).text = text; } } private static void Strip(GameObject go) { try { LanguageText component = go.GetComponent<LanguageText>(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } } catch { } } private static void StripForeignBehaviours(GameObject go) { TryDestroy((Component)(object)go.GetComponent<ResolutionDropdown>()); TryDestroy((Component)(object)go.GetComponent<MicPickerDropdown>()); } private static void TryDestroy(Component c) { try { if ((Object)(object)c != (Object)null) { Object.Destroy((Object)(object)c); } } catch { } } } internal sealed class PossessionDriver { private const float Gravity = 22f; private const float TerminalVelocity = 30f; private const float GroundSnapTolerance = 0.35f; private const float GroundProbeHeight = 1.5f; private const float GroundProbeDepth = 8f; private const float TurnDegreesPerSecond = 540f; private const float MoveDeadzone = 0.1f; private const float SweepSkin = 0.05f; private const float DefaultRadius = 0.35f; private Vector3 _feet; private float _centreHeight = 0.9f; private float _radius = 0.35f; private float _verticalVelocity; private float _yaw; private GameObject _self; private Transform _body; private bool _sweepFailed; private const int MaxSweepHits = 16; private Il2CppStructArray<RaycastHit> _sweepHits; private bool _radiusSet; public Vector3 Position => _feet + Vector3.up * _centreHeight; public Vector3 Feet => _feet; public Quaternion Rotation => Quaternion.Euler(0f, _yaw, 0f); public bool Begun { get; private set; } public bool IsMoving { get; private set; } public bool IsRunning { get; private set; } public bool IsCrouching { get; private set; } public bool Grounded { get; private set; } public void Begin(PlayerManager pm, GameObject puppet, Vector3? origin = null, float yaw = 0f) { //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0111: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_0077: 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) _self = puppet; _body = (((Object)(object)pm != (Object)null) ? ((Component)pm).transform : null); _verticalVelocity = 0f; bool flag = (IsCrouching = false); bool isMoving = (IsRunning = flag); IsMoving = isMoving; Vector3 val = (Vector3)(((??)origin) ?? ((Component)pm).transform.position); _yaw = (origin.HasValue ? yaw : ((Component)pm).transform.eulerAngles.y); try { CharacterController charController = pm.charController; if ((Object)(object)charController != (Object)null && charController.height > 0.1f) { _centreHeight = charController.height * 0.5f - charController.center.y; if (!_radiusSet) { _radius = Mathf.Max(charController.radius, 0.1f); } } } catch { } _feet = val - Vector3.up * _centreHeight; SnapToGround(_feet.y); Begun = true; } public void End() { Begun = false; _radiusSet = false; _sweepFailed = false; } public void SyncFrom(Vector3 position) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) _feet = position - Vector3.up * _centreHeight; _verticalVelocity = 0f; SnapToGround(_feet.y); } public void Tick(Camera camera, PlayerManager pm, bool inputAllowed) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: 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_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_00a3: 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_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_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_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: 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_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) float deltaTime = Time.deltaTime; if (deltaTime <= 0f) { return; } Vector2 val = (inputAllowed ? GameInput.Move : Vector2.zero); IsRunning = inputAllowed && GameInput.Sprint && ((Vector2)(ref val)).sqrMagnitude > 0.010000001f; IsCrouching = inputAllowed && GameInput.Crouch; IsMoving = ((Vector2)(ref val)).sqrMagnitude > 0.010000001f; Vector3 val2 = Vector3.zero; if (IsMoving) { float num = (((Object)(object)camera != (Object)null) ? ((Component)camera).transform.eulerAngles.y : _yaw); Vector3 val3 = Quaternion.Euler(0f, num, 0f) * new Vector3(val.x, 0f, val.y); if (((Vector3)(ref val3)).sqrMagnitude > 1f) { ((Vector3)(ref val3)).Normalize(); } val2 = val3 * SpeedFor(pm) * deltaTime; _yaw = Mathf.MoveTowardsAngle(_yaw, Mathf.Atan2(val3.x, val3.z) * 57.29578f, 540f * deltaTime); } if (!_sweepFailed) { try { val2 = Sweep(val2); } catch (Exception ex) { _sweepFailed = true; ModLog.Error("Wall collision disabled for this session: " + ex.Message); } } _feet += val2; float y = _feet.y; ApplyGravity(deltaTime); SnapToGround(y); } private float SpeedFor(PlayerManager pm) { float num = 4f; float num2 = 7f; float result = 2f; try { FPSController val = (((Object)(object)pm != (Object)null) ? pm.fpsScript : null); if ((Object)(object)val != (Object)null) { if (val.walkSpeed > 0.01f) { num = val.walkSpeed; } if (val.runSpeed > 0.01f) { num2 = val.runSpeed; } if (val.crouchSpeed > 0.01f) { result = val.crouchSpeed; } } } catch { } if (IsCrouching) { return result; } return IsRunning ? num2 : num; } private Vector3 Sweep(Vector3 step) { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: 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_002e: 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_0024: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to inv