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 Extraction v0.2.37
plugins/Extraction/DoorLockpickPlus.dll
Decompiled 19 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using UnityEngine; using UnityEngine.Events; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ScrapVisbility")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ScrapVisbility")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("8a6853bd-bdc9-4741-95c7-5aa2c8c6a6f9")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace DoorLockpickPlus; [BepInPlugin("YourFurnace.DoorLockpickPlus", "DoorLockpickPlus", "1.3.8")] public class DoorLockpickPlus : BaseUnityPlugin { private const string modGUID = "YourFurnace.DoorLockpickPlus"; private const string modName = "DoorLockpickPlus"; private const string modVersion = "1.3.8"; private readonly Harmony harmony = new Harmony("YourFurnace.DoorLockpickPlus"); internal static DoorLockpickPlus Instance; internal static ManualLogSource Log; internal static ConfigEntry<bool> EnableNormalDoorLockpicking; internal static ConfigEntry<bool> EnableBigDoorHacking; internal static ConfigEntry<bool> EnableBigDoorInPersonClose; internal static ConfigEntry<bool> DebugRollLogging; internal static ConfigEntry<bool> EnableLockpickSounds; internal static ConfigEntry<float> NormalDoorPickTime; internal static ConfigEntry<float> NormalDoorSuccessChance; internal static ConfigEntry<float> BigDoorHackTime; internal static ConfigEntry<float> BigDoorSuccessChance; internal static ConfigEntry<float> BigDoorCloseTime; internal static ConfigEntry<float> RetryCooldown; internal static ConfigEntry<float> FailFlashTime; internal static ConfigEntry<float> LockpickSoundVolume; internal static ConfigEntry<float> NormalDoorTriggerWidth; internal static ConfigEntry<float> NormalDoorTriggerHeight; internal static ConfigEntry<float> NormalDoorTriggerDepth; internal static ConfigEntry<float> DoorTintStrength; internal static ConfigEntry<float> DoorOverlayAlpha; internal static ConfigEntry<float> DoorEmissionStrength; internal static ConfigEntry<float> DoorLightStrength; internal static ConfigEntry<float> NormalDoorVisualMultiplier; internal static ConfigEntry<float> BigDoorVisualMultiplier; private float nextScanTime = 0f; private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; EnableNormalDoorLockpicking = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable normal door lockpicking", true, "Adds a normal Lethal Company E hold prompt to locked normal doors."); EnableBigDoorHacking = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable big door prying", true, "Adds a normal Lethal Company E hold prompt to closed terminal controlled big doors."); EnableBigDoorInPersonClose = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable big door in-person close", true, "Adds a normal Lethal Company E hold prompt to close open terminal controlled big doors."); EnableLockpickSounds = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "Enable lockpick sounds", true, "Plays the base game lockpicking sound while holding E on a locked normal door."); LockpickSoundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "Lockpick sound volume", 0.75f, "Volume for lockpick, success, and fail sounds."); NormalDoorPickTime = ((BaseUnityPlugin)this).Config.Bind<float>("Normal Doors", "Normal door pick time", 10f, "Seconds required to lockpick a normal locked door."); NormalDoorSuccessChance = ((BaseUnityPlugin)this).Config.Bind<float>("Normal Doors", "Normal door success chance", 0.5f, "Chance to unlock a normal locked door. 0.50 means 50%."); BigDoorHackTime = ((BaseUnityPlugin)this).Config.Bind<float>("Big Doors", "Big door pry time", 25f, "Seconds required to pry open a terminal controlled big door."); BigDoorSuccessChance = ((BaseUnityPlugin)this).Config.Bind<float>("Big Doors", "Big door pry success chance", 0.33f, "Chance to pry open a terminal controlled big door. 0.33 means 33%."); BigDoorCloseTime = ((BaseUnityPlugin)this).Config.Bind<float>("Big Doors", "Big door close time", 2f, "Seconds required to close an open terminal controlled big door in person. This is always successful."); RetryCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Safety", "Retry cooldown", 2f, "Cooldown after a lockpick or pry attempt finishes. Helps prevent retry race conditions."); FailFlashTime = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "Fail flash time", 1.5f, "How long a failed door flashes red."); DebugRollLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Debug roll logging", true, "Logs lockpick and pry rolls to the BepInEx console. Leave this on while playtesting."); NormalDoorTriggerWidth = ((BaseUnityPlugin)this).Config.Bind<float>("Trigger Sizes", "Normal door trigger width", 2.25f, "Minimum width of the invisible lockpick interaction trigger on normal doors."); NormalDoorTriggerHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Trigger Sizes", "Normal door trigger height", 3.5f, "Minimum height of the invisible lockpick interaction trigger on normal doors."); NormalDoorTriggerDepth = ((BaseUnityPlugin)this).Config.Bind<float>("Trigger Sizes", "Normal door trigger depth", 2.25f, "Minimum depth of the invisible lockpick interaction trigger on normal doors."); DoorTintStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Door Visuals", "Door tint strength", 0.55f, "How much the real door mesh is tinted while lockpicking or failing. This belongs to DoorLockpickPlus only."); DoorOverlayAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("Door Visuals", "Door overlay alpha", 0.18f, "Transparent overlay strength for the door mesh. Lower this if the highlight is too solid."); DoorEmissionStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Door Visuals", "Door emission strength", 1.15f, "Emission pushed into the door material while highlighted."); DoorLightStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Door Visuals", "Door light strength", 0.55f, "Point light strength while highlighted."); NormalDoorVisualMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Door Visuals", "Normal door visual multiplier", 1.35f, "Extra brightness multiplier for normal doors. Raise this if normal doors are too faint."); BigDoorVisualMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Door Visuals", "Big door visual multiplier", 0.35f, "Brightness multiplier for big doors. Lower this if big doors are too bright."); harmony.PatchAll(); Log.LogInfo((object)"DoorLockpickPlus 1.3.8 loaded. Scene-safe big door commands and fixed door highlights enabled."); } private void OnDestroy() { harmony.UnpatchSelf(); } private void Update() { if (!(Time.time < nextScanTime)) { nextScanTime = Time.time + 1f; AttachToNormalDoors(); AttachToBigDoors(); } } private void AttachToNormalDoors() { if (EnableNormalDoorLockpicking == null || !EnableNormalDoorLockpicking.Value) { return; } DoorLock[] array = Object.FindObjectsOfType<DoorLock>(); DoorLock[] array2 = array; foreach (DoorLock val in array2) { if (!((Object)(object)val == (Object)null) && (Object)(object)((Component)val).GetComponent<NormalDoorLockpickTarget>() == (Object)null) { NormalDoorLockpickTarget normalDoorLockpickTarget = ((Component)val).gameObject.AddComponent<NormalDoorLockpickTarget>(); normalDoorLockpickTarget.Init(val); } } } private void AttachToBigDoors() { if ((EnableBigDoorHacking == null || !EnableBigDoorHacking.Value) && (EnableBigDoorInPersonClose == null || !EnableBigDoorInPersonClose.Value)) { return; } TerminalAccessibleObject[] array = Object.FindObjectsOfType<TerminalAccessibleObject>(); TerminalAccessibleObject[] array2 = array; foreach (TerminalAccessibleObject val in array2) { if (!((Object)(object)val == (Object)null) && BigDoorUtil.IsProbablyBigDoor(val) && (Object)(object)((Component)val).GetComponent<BigDoorLockpickTarget>() == (Object)null) { BigDoorLockpickTarget bigDoorLockpickTarget = ((Component)val).gameObject.AddComponent<BigDoorLockpickTarget>(); bigDoorLockpickTarget.Init(val); } } } internal static void ShowTip(string header, string body, bool warning) { try { HUDManager val = Object.FindObjectOfType<HUDManager>(); if ((Object)(object)val == (Object)null) { return; } MethodInfo methodInfo = AccessTools.Method(typeof(HUDManager), "DisplayTip", new Type[5] { typeof(string), typeof(string), typeof(bool), typeof(bool), typeof(string) }, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(val, new object[5] { header, body, warning, false, "DoorLockpickPlus" }); return; } MethodInfo methodInfo2 = AccessTools.Method(typeof(HUDManager), "DisplayTip", (Type[])null, (Type[])null); if (methodInfo2 == null) { return; } ParameterInfo[] parameters = methodInfo2.GetParameters(); object[] array = new object[parameters.Length]; int num = 0; for (int i = 0; i < parameters.Length; i++) { Type parameterType = parameters[i].ParameterType; if (parameterType == typeof(string)) { switch (num) { case 0: array[i] = header; break; case 1: array[i] = body; break; default: array[i] = "DoorLockpickPlus"; break; } num++; } else if (parameterType == typeof(bool)) { array[i] = warning; } else { array[i] = null; } } methodInfo2.Invoke(val, array); } catch { } } internal static Color YellowHighlight() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) return new Color(1f, 0.78f, 0.08f, 1f); } internal static Color RedHighlight() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) return new Color(1f, 0.12f, 0.08f, 1f); } } internal class NormalDoorLockpickTarget : MonoBehaviour { [CompilerGenerated] private sealed class <EndOfFrameUnlockGuard>d__21 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public NormalDoorLockpickTarget <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EndOfFrameUnlockGuard>d__21(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; <>4__this.MaintainDoorUnlockedState(); break; } if (<>4__this.unlockedByThisMod && (Object)(object)<>4__this.door != (Object)null) { <>2__current = (object)new WaitForEndOfFrame(); <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private DoorLock door; private DoorVisualHighlighter highlighter; private DoorAudioController audioController; private readonly List<InteractTrigger> vanillaTriggers = new List<InteractTrigger>(); private readonly Dictionary<InteractTrigger, TriggerSnapshot> vanillaSnapshots = new Dictionary<InteractTrigger, TriggerSnapshot>(); private GameObject customTriggerObject; private InteractTrigger customTrigger; private float cooldownUntil = 0f; private float redFlashUntil = 0f; private bool resolvingAttempt = false; private bool unlockedByThisMod = false; private bool unlockGuardStarted = false; private bool unlockMethodsCalled = false; private bool wasHoldingLockpick = false; public void Init(DoorLock targetDoor) { //IL_0009: 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_002c: Unknown result type (might be due to invalid IL or missing references) door = targetDoor; Bounds doorFocusBounds = GetDoorFocusBounds(); highlighter = ((Component)this).gameObject.AddComponent<DoorVisualHighlighter>(); highlighter.Init(((Component)this).gameObject, doorFocusBounds, bigDoor: false); audioController = ((Component)this).gameObject.AddComponent<DoorAudioController>(); audioController.Init(door); CacheVanillaTriggers(); CreateCustomTrigger(); } private Bounds GetDoorFocusBounds() { //IL_0009: 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_0018: 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_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = default(Bounds); ((Bounds)(ref bounds))..ctor(((Component)this).transform.position, Vector3.one * 2f); bool hasBounds = false; if ((Object)(object)door != (Object)null && (Object)(object)door.doorTrigger != (Object)null) { BoundsUtil.EncapsulateTransformBounds(((Component)door.doorTrigger).transform, ref bounds, ref hasBounds); } if ((Object)(object)door != (Object)null && (Object)(object)door.doorTriggerB != (Object)null) { BoundsUtil.EncapsulateTransformBounds(((Component)door.doorTriggerB).transform, ref bounds, ref hasBounds); } if (!hasBounds) { bounds = BoundsUtil.GetBounds(((Component)this).gameObject); return bounds; } return bounds; } private void CacheVanillaTriggers() { TryAddVanillaTrigger(door.doorTrigger); TryAddVanillaTrigger(door.doorTriggerB); InteractTrigger[] componentsInChildren = ((Component)door).GetComponentsInChildren<InteractTrigger>(true); InteractTrigger[] array = componentsInChildren; foreach (InteractTrigger trigger in array) { TryAddVanillaTrigger(trigger); } } private void TryAddVanillaTrigger(InteractTrigger trigger) { if (!((Object)(object)trigger == (Object)null) && !vanillaTriggers.Contains(trigger)) { vanillaTriggers.Add(trigger); vanillaSnapshots[trigger] = new TriggerSnapshot(trigger); } } private void CreateCustomTrigger() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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_0018: Expected O, but got Unknown //IL_0025: 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_0067: 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_00a9: 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) Bounds doorFocusBounds = GetDoorFocusBounds(); customTriggerObject = new GameObject("DoorLockpickPlus_NormalDoor_InteractTrigger"); customTriggerObject.transform.position = ((Bounds)(ref doorFocusBounds)).center; customTriggerObject.transform.rotation = Quaternion.identity; BoxCollider val = customTriggerObject.AddComponent<BoxCollider>(); ((Collider)val).isTrigger = true; val.size = new Vector3(Mathf.Max(DoorLockpickPlus.NormalDoorTriggerWidth.Value, ((Bounds)(ref doorFocusBounds)).size.x + 1f), Mathf.Max(DoorLockpickPlus.NormalDoorTriggerHeight.Value, ((Bounds)(ref doorFocusBounds)).size.y + 0.8f), Mathf.Max(DoorLockpickPlus.NormalDoorTriggerDepth.Value, ((Bounds)(ref doorFocusBounds)).size.z + 1f)); InteractTriggerUtil.MakeGameObjectARealInteractTrigger(customTriggerObject); customTrigger = customTriggerObject.AddComponent<InteractTrigger>(); InteractTriggerUtil.ConfigureBaseTrigger(customTrigger); InteractTriggerUtil.CopyIconFromTriggers(customTrigger, vanillaTriggers); InteractTriggerUtil.AddInteractListener(customTrigger, OnDoorInteract); customTriggerObject.SetActive(false); } private void Update() { //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)door == (Object)null) { ClearAll(); return; } if (unlockedByThisMod) { StopLockpickLoopIfNeeded(); MaintainDoorUnlockedState(); ConfigureUnlockedVanillaTriggers(); SetCustomTriggerActive(active: false); highlighter.Clear(); return; } if (!IsLocked()) { StopLockpickLoopIfNeeded(); ConfigureUnlockedVanillaTriggers(); SetCustomTriggerActive(active: false); highlighter.Clear(); return; } DisableVanillaTriggersWhileLocked(); UpdateCustomTriggerPosition(); bool flag = Time.time < cooldownUntil; bool flag2 = (Object)(object)customTrigger != (Object)null && customTrigger.isBeingHeldByPlayer; ConfigureCustomTrigger(flag); UpdateLockpickLoop(flag2 && !flag && !resolvingAttempt); if (Time.time < redFlashUntil) { highlighter.Apply(DoorLockpickPlus.RedHighlight(), 1f, enableLight: true, DoorLockpickPlus.NormalDoorVisualMultiplier.Value); } else if (flag2 || resolvingAttempt) { highlighter.Apply(DoorLockpickPlus.YellowHighlight(), 1f, enableLight: true, DoorLockpickPlus.NormalDoorVisualMultiplier.Value); } else { highlighter.Clear(); } } private void LateUpdate() { if (unlockedByThisMod) { MaintainDoorUnlockedState(); } } [IteratorStateMachine(typeof(<EndOfFrameUnlockGuard>d__21))] private IEnumerator EndOfFrameUnlockGuard() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <EndOfFrameUnlockGuard>d__21(0) { <>4__this = this }; } private void UpdateLockpickLoop(bool shouldPlay) { if (DoorLockpickPlus.EnableLockpickSounds == null || !DoorLockpickPlus.EnableLockpickSounds.Value) { StopLockpickLoopIfNeeded(); } else if (shouldPlay) { if (!wasHoldingLockpick) { wasHoldingLockpick = true; if ((Object)(object)audioController != (Object)null) { audioController.StartLockpickLoop(); } } } else { StopLockpickLoopIfNeeded(); } } private void StopLockpickLoopIfNeeded() { if (wasHoldingLockpick) { wasHoldingLockpick = false; if ((Object)(object)audioController != (Object)null) { audioController.StopLockpickLoop(); } } } private void UpdateCustomTriggerPosition() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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_0041: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)customTriggerObject == (Object)null)) { Bounds doorFocusBounds = GetDoorFocusBounds(); customTriggerObject.transform.position = ((Bounds)(ref doorFocusBounds)).center; customTriggerObject.transform.rotation = Quaternion.identity; BoxCollider component = customTriggerObject.GetComponent<BoxCollider>(); if ((Object)(object)component != (Object)null) { component.size = new Vector3(Mathf.Max(DoorLockpickPlus.NormalDoorTriggerWidth.Value, ((Bounds)(ref doorFocusBounds)).size.x + 1f), Mathf.Max(DoorLockpickPlus.NormalDoorTriggerHeight.Value, ((Bounds)(ref doorFocusBounds)).size.y + 0.8f), Mathf.Max(DoorLockpickPlus.NormalDoorTriggerDepth.Value, ((Bounds)(ref doorFocusBounds)).size.z + 1f)); } InteractTriggerUtil.MakeGameObjectARealInteractTrigger(customTriggerObject); } } private void ConfigureCustomTrigger(bool inCooldown) { if (!((Object)(object)customTrigger == (Object)null)) { InteractTriggerUtil.ConfigureBaseTrigger(customTrigger); customTrigger.interactable = !inCooldown && !resolvingAttempt; customTrigger.timeToHold = Mathf.Max(0.1f, DoorLockpickPlus.NormalDoorPickTime.Value); customTrigger.hoverTip = (inCooldown ? "Lockpick cooling down..." : "Pick lock"); customTrigger.holdTip = "Lockpicking..."; SetCustomTriggerActive(active: true); } } private void SetCustomTriggerActive(bool active) { if ((Object)(object)customTriggerObject != (Object)null && customTriggerObject.activeSelf != active) { customTriggerObject.SetActive(active); } } private void DisableVanillaTriggersWhileLocked() { foreach (InteractTrigger vanillaTrigger in vanillaTriggers) { if (!((Object)(object)vanillaTrigger == (Object)null)) { vanillaTrigger.interactable = false; vanillaTrigger.hoverTip = "Locked"; vanillaTrigger.holdTip = "Locked"; } } } private void RestoreVanillaTriggers() { foreach (KeyValuePair<InteractTrigger, TriggerSnapshot> vanillaSnapshot in vanillaSnapshots) { if ((Object)(object)vanillaSnapshot.Key != (Object)null) { vanillaSnapshot.Value.Restore(vanillaSnapshot.Key); } } } private void OnDoorInteract(PlayerControllerB player) { if ((Object)(object)door == (Object)null || (Object)(object)player == (Object)null) { return; } StopLockpickLoopIfNeeded(); if (!IsLocked()) { return; } if (resolvingAttempt || Time.time < cooldownUntil) { DoorLockpickPlus.ShowTip("Lockpick", "Wait a moment before trying again.", warning: true); return; } resolvingAttempt = true; float num = Mathf.Clamp01(DoorLockpickPlus.NormalDoorSuccessChance.Value); float num2 = Random.Range(0f, 1f); bool flag = num2 <= num; if (DoorLockpickPlus.DebugRollLogging != null && DoorLockpickPlus.DebugRollLogging.Value && DoorLockpickPlus.Log != null) { DoorLockpickPlus.Log.LogInfo((object)("Normal door lockpick roll: " + num2.ToString("0.000") + " / chance " + num.ToString("0.000") + " / success " + flag)); } if (flag) { unlockedByThisMod = true; unlockMethodsCalled = false; CallKeyStyleUnlockOnce(); MaintainDoorUnlockedState(); ConfigureUnlockedVanillaTriggers(); SetCustomTriggerActive(active: false); if ((Object)(object)audioController != (Object)null) { audioController.PlayUnlockSoundOnce(); } if (!unlockGuardStarted) { unlockGuardStarted = true; ((MonoBehaviour)this).StartCoroutine(EndOfFrameUnlockGuard()); } DoorLockpickPlus.ShowTip("Lockpick Success", "The door unlocked.", warning: false); cooldownUntil = Time.time + 0.5f; } else { if ((Object)(object)audioController != (Object)null) { audioController.PlayFailSoundOnce(); } DoorLockpickPlus.ShowTip("Lockpick Failed", "The lock held. Try again.", warning: true); redFlashUntil = Time.time + Mathf.Max(0.1f, DoorLockpickPlus.FailFlashTime.Value); cooldownUntil = Time.time + Mathf.Max(0.1f, DoorLockpickPlus.RetryCooldown.Value); } resolvingAttempt = false; } private bool IsLocked() { if ((Object)(object)door == (Object)null) { return false; } return door.isLocked; } private void CallKeyStyleUnlockOnce() { if (!((Object)(object)door == (Object)null) && !unlockMethodsCalled) { unlockMethodsCalled = true; CallUnlockMethodsOnDoor(door); if ((Object)(object)door.twinDoor != (Object)null) { CallUnlockMethodsOnDoor(door.twinDoor); } } } private void CallUnlockMethodsOnDoor(DoorLock targetDoor) { if (!((Object)(object)targetDoor == (Object)null) && !ReflectionUtil.CallNoArgExact(targetDoor, "UnlockDoorSyncWithServer")) { ReflectionUtil.CallNoArgExact(targetDoor, "UnlockDoor"); ReflectionUtil.CallNoArgExact(targetDoor, "UnlockDoorServerRpc"); } } private void MaintainDoorUnlockedState() { MaintainDoorUnlockedStateFor(door); if ((Object)(object)door != (Object)null && (Object)(object)door.twinDoor != (Object)null) { MaintainDoorUnlockedStateFor(door.twinDoor); } } private void MaintainDoorUnlockedStateFor(DoorLock targetDoor) { if (!((Object)(object)targetDoor == (Object)null)) { targetDoor.isLocked = false; targetDoor.isPickingLock = false; targetDoor.lockPickTimeLeft = 0f; targetDoor.canBeLocked = false; if ((Object)(object)targetDoor.doorTrigger != (Object)null) { targetDoor.doorTrigger.interactable = true; targetDoor.doorTrigger.timeToHoldSpeedMultiplier = 1f; targetDoor.doorTrigger.timeToHold = targetDoor.defaultTimeToHold; } if ((Object)(object)targetDoor.doorTriggerB != (Object)null) { targetDoor.doorTriggerB.interactable = true; targetDoor.doorTriggerB.timeToHoldSpeedMultiplier = 1f; targetDoor.doorTriggerB.timeToHold = targetDoor.defaultTimeToHold; } } } private void ConfigureUnlockedVanillaTriggers() { ConfigureUnlockedVanillaTriggersFor(door); if ((Object)(object)door != (Object)null && (Object)(object)door.twinDoor != (Object)null) { ConfigureUnlockedVanillaTriggersFor(door.twinDoor); } } private void ConfigureUnlockedVanillaTriggersFor(DoorLock targetDoor) { if (!((Object)(object)targetDoor == (Object)null)) { if ((Object)(object)targetDoor.doorTrigger != (Object)null) { targetDoor.doorTrigger.interactable = true; targetDoor.doorTrigger.oneHandedItemAllowed = true; targetDoor.doorTrigger.twoHandedItemAllowed = true; targetDoor.doorTrigger.timeToHoldSpeedMultiplier = 1f; targetDoor.doorTrigger.timeToHold = targetDoor.defaultTimeToHold; } if ((Object)(object)targetDoor.doorTriggerB != (Object)null) { targetDoor.doorTriggerB.interactable = true; targetDoor.doorTriggerB.oneHandedItemAllowed = true; targetDoor.doorTriggerB.twoHandedItemAllowed = true; targetDoor.doorTriggerB.timeToHoldSpeedMultiplier = 1f; targetDoor.doorTriggerB.timeToHold = targetDoor.defaultTimeToHold; } } } private void ClearAll() { StopLockpickLoopIfNeeded(); RestoreVanillaTriggers(); if ((Object)(object)customTriggerObject != (Object)null) { Object.Destroy((Object)(object)customTriggerObject); customTriggerObject = null; } if ((Object)(object)highlighter != (Object)null) { highlighter.Clear(); } } private void OnDestroy() { ClearAll(); } } internal class BigDoorLockpickTarget : MonoBehaviour { [CompilerGenerated] private sealed class <ExecuteBigDoorCommand>d__20 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public bool targetOpen; public BigDoorLockpickTarget <>4__this; private bool <beforeOpen>5__1; private bool <afterTerminal>5__2; private bool <actualOpen>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ExecuteBigDoorCommand>d__20(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Expected O, but got Unknown //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Expected O, but got Unknown //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if ((Object)(object)<>4__this.bigDoor == (Object)null) { <>4__this.resolvingAttempt = false; return false; } <beforeOpen>5__1 = BigDoorUtil.IsOpen(<>4__this.bigDoor); if (<beforeOpen>5__1 == targetOpen) { if (targetOpen) { DoorLockpickPlus.ShowTip("Big Door", "The big door is already open.", warning: false); } else { DoorLockpickPlus.ShowTip("Big Door", "The big door is already closed.", warning: false); } <>4__this.cooldownUntil = Time.time + 0.5f; <>4__this.resolvingAttempt = false; return false; } if (DoorLockpickPlus.DebugRollLogging != null && DoorLockpickPlus.DebugRollLogging.Value && DoorLockpickPlus.Log != null) { DoorLockpickPlus.Log.LogInfo((object)("Big door command start. targetOpen=" + targetOpen + " beforeOpen=" + <beforeOpen>5__1 + " code=" + BigDoorUtil.GetObjectCode(<>4__this.bigDoor))); } BigDoorUtil.ClearCooldown(<>4__this.bigDoor); BigDoorUtil.SendTerminalCommand(<>4__this.bigDoor); <>2__current = (object)new WaitForSeconds(0.35f); <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)<>4__this.bigDoor == (Object)null) { <>4__this.resolvingAttempt = false; return false; } <afterTerminal>5__2 = BigDoorUtil.IsOpen(<>4__this.bigDoor); if (<afterTerminal>5__2 != targetOpen) { BigDoorUtil.ClearCooldown(<>4__this.bigDoor); BigDoorUtil.ForceSetOpen(<>4__this.bigDoor, targetOpen); <>2__current = (object)new WaitForSeconds(0.2f); <>1__state = 2; return true; } goto IL_023f; case 2: <>1__state = -1; goto IL_023f; case 3: { <>1__state = -1; break; } IL_023f: if ((Object)(object)<>4__this.bigDoor != (Object)null && BigDoorUtil.IsOpen(<>4__this.bigDoor) != targetOpen) { BigDoorUtil.ForceSetOpen(<>4__this.bigDoor, targetOpen); <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 3; return true; } break; } <actualOpen>5__3 = (Object)(object)<>4__this.bigDoor != (Object)null && BigDoorUtil.IsOpen(<>4__this.bigDoor); if (DoorLockpickPlus.DebugRollLogging != null && DoorLockpickPlus.DebugRollLogging.Value && DoorLockpickPlus.Log != null) { DoorLockpickPlus.Log.LogInfo((object)("Big door command end. targetOpen=" + targetOpen + " actualOpen=" + <actualOpen>5__3)); } if (<actualOpen>5__3 == targetOpen) { if (targetOpen) { DoorLockpickPlus.ShowTip("Pry Success", "The big door opened.", warning: false); } else { DoorLockpickPlus.ShowTip("Big Door Closed", "The big door closed.", warning: false); } } else { DoorLockpickPlus.ShowTip("Door Command Failed", "The command ran but the door did not reach the expected state.", warning: true); } <>4__this.cooldownUntil = Time.time + 0.5f; <>4__this.resolvingAttempt = false; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private TerminalAccessibleObject bigDoor; private DoorVisualHighlighter highlighter; private readonly List<InteractTrigger> triggers = new List<InteractTrigger>(); private readonly List<GameObject> triggerObjects = new List<GameObject>(); private float cooldownUntil = 0f; private float redFlashUntil = 0f; private bool resolvingAttempt = false; private float nextTriggerRefreshTime = 0f; private int lastBoundsSignature = 0; public void Init(TerminalAccessibleObject targetDoor) { //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_0031: Unknown result type (might be due to invalid IL or missing references) bigDoor = targetDoor; Bounds bounds = BoundsUtil.GetBounds(((Component)this).gameObject); highlighter = ((Component)this).gameObject.AddComponent<DoorVisualHighlighter>(); highlighter.Init(((Component)this).gameObject, bounds, bigDoor: true); RebuildSurfaceTriggers(); } private void Update() { //IL_00d5: 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) if ((Object)(object)bigDoor == (Object)null || (Object)(object)((Component)bigDoor).gameObject == (Object)null) { Clear(); return; } if (!((Component)bigDoor).gameObject.activeInHierarchy) { Clear(); return; } if (Time.time >= nextTriggerRefreshTime) { nextTriggerRefreshTime = Time.time + 0.75f; RebuildSurfaceTriggersIfNeeded(); } bool isOpen = BigDoorUtil.IsOpen(bigDoor); bool inCooldown = Time.time < cooldownUntil; bool flag = AnyTriggerHeld(); UpdateTriggerTransforms(); ConfigureTriggers(isOpen, inCooldown); if (Time.time < redFlashUntil) { highlighter.Apply(DoorLockpickPlus.RedHighlight(), 1f, enableLight: true, DoorLockpickPlus.BigDoorVisualMultiplier.Value); } else if (flag || resolvingAttempt) { highlighter.Apply(DoorLockpickPlus.YellowHighlight(), 1f, enableLight: true, DoorLockpickPlus.BigDoorVisualMultiplier.Value); } else { highlighter.Clear(); } } private bool AnyTriggerHeld() { for (int i = 0; i < triggers.Count; i++) { if ((Object)(object)triggers[i] != (Object)null && triggers[i].isBeingHeldByPlayer) { return true; } } return false; } private void RebuildSurfaceTriggersIfNeeded() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) List<Bounds> individualVisualBounds = BoundsUtil.GetIndividualVisualBounds(((Component)this).gameObject, bigDoor: true); if (individualVisualBounds.Count == 0) { individualVisualBounds.Add(BoundsUtil.GetBounds(((Component)this).gameObject)); } int num = Mathf.Clamp(individualVisualBounds.Count, 1, 8); int boundsSignature = GetBoundsSignature(individualVisualBounds, num); if (num != triggerObjects.Count || boundsSignature != lastBoundsSignature) { RebuildSurfaceTriggers(); } } private int GetBoundsSignature(List<Bounds> boundsList, int count) { //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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_00b3: Unknown result type (might be due to invalid IL or missing references) int num = 17; num = num * 31 + count; for (int i = 0; i < count && i < boundsList.Count; i++) { Bounds val = boundsList[i]; num = num * 31 + Mathf.RoundToInt(((Bounds)(ref val)).center.x * 10f); num = num * 31 + Mathf.RoundToInt(((Bounds)(ref val)).center.y * 10f); num = num * 31 + Mathf.RoundToInt(((Bounds)(ref val)).center.z * 10f); num = num * 31 + Mathf.RoundToInt(((Bounds)(ref val)).size.x * 10f); num = num * 31 + Mathf.RoundToInt(((Bounds)(ref val)).size.y * 10f); num = num * 31 + Mathf.RoundToInt(((Bounds)(ref val)).size.z * 10f); } return num; } private void RebuildSurfaceTriggers() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) DestroyTriggers(); if (!((Object)(object)bigDoor == (Object)null) && !((Object)(object)((Component)bigDoor).gameObject == (Object)null)) { List<Bounds> individualVisualBounds = BoundsUtil.GetIndividualVisualBounds(((Component)this).gameObject, bigDoor: true); if (individualVisualBounds.Count == 0) { individualVisualBounds.Add(BoundsUtil.GetBounds(((Component)this).gameObject)); } int num = Mathf.Clamp(individualVisualBounds.Count, 1, 8); lastBoundsSignature = GetBoundsSignature(individualVisualBounds, num); for (int i = 0; i < num; i++) { CreateSurfaceTrigger(i, individualVisualBounds[i]); } UpdateTriggerTransforms(); } } private void CreateSurfaceTrigger(int index, Bounds bounds) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("DoorLockpickPlus_BigDoor_SurfaceTrigger_" + index); if ((Object)(object)bigDoor != (Object)null) { val.transform.SetParent(((Component)bigDoor).transform, true); } BoxCollider val2 = val.AddComponent<BoxCollider>(); ((Collider)val2).isTrigger = true; ConfigureSurfaceBox(val2, bounds); InteractTriggerUtil.MakeGameObjectARealInteractTrigger(val); InteractTrigger val3 = val.AddComponent<InteractTrigger>(); InteractTriggerUtil.ConfigureBaseTrigger(val3); InteractTriggerUtil.CopyIconFromScene(val3); InteractTriggerUtil.AddInteractListener(val3, OnBigDoorInteract); triggerObjects.Add(val); triggers.Add(val3); } private void UpdateTriggerTransforms() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)bigDoor == (Object)null || (Object)(object)((Component)bigDoor).gameObject == (Object)null) { return; } List<Bounds> individualVisualBounds = BoundsUtil.GetIndividualVisualBounds(((Component)this).gameObject, bigDoor: true); if (individualVisualBounds.Count == 0) { individualVisualBounds.Add(BoundsUtil.GetBounds(((Component)this).gameObject)); } int num = Mathf.Min(triggerObjects.Count, individualVisualBounds.Count); for (int i = 0; i < num; i++) { GameObject val = triggerObjects[i]; if (!((Object)(object)val == (Object)null)) { if ((Object)(object)val.transform.parent != (Object)(object)((Component)bigDoor).transform) { val.transform.SetParent(((Component)bigDoor).transform, true); } Transform transform = val.transform; Bounds val2 = individualVisualBounds[i]; transform.position = ((Bounds)(ref val2)).center; val.transform.rotation = Quaternion.identity; BoxCollider component = val.GetComponent<BoxCollider>(); if ((Object)(object)component != (Object)null) { ConfigureSurfaceBox(component, individualVisualBounds[i]); } InteractTriggerUtil.MakeGameObjectARealInteractTrigger(val); } } } private void ConfigureSurfaceBox(BoxCollider box, Bounds bounds) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0035: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)box == (Object)null)) { Vector3 size = ((Bounds)(ref bounds)).size; size.x = Mathf.Max(0.6f, size.x); size.y = Mathf.Max(1.2f, size.y); size.z = Mathf.Max(0.45f, size.z); box.center = Vector3.zero; box.size = size; } } private void ConfigureTriggers(bool isOpen, bool inCooldown) { bool flag = false; float timeToHold = 1f; string hoverTip = ""; string holdTip = ""; if (isOpen && DoorLockpickPlus.EnableBigDoorInPersonClose.Value) { flag = true; timeToHold = Mathf.Max(0.1f, DoorLockpickPlus.BigDoorCloseTime.Value); hoverTip = (inCooldown ? "Door controls cooling down..." : "Close big door"); holdTip = "Closing door..."; } else if (!isOpen && DoorLockpickPlus.EnableBigDoorHacking.Value) { flag = true; timeToHold = Mathf.Max(0.1f, DoorLockpickPlus.BigDoorHackTime.Value); hoverTip = (inCooldown ? "Pry attempt cooling down..." : "Pry open big door"); holdTip = "Attempting to pry open..."; } for (int i = 0; i < triggers.Count; i++) { InteractTrigger val = triggers[i]; if (!((Object)(object)val == (Object)null)) { InteractTriggerUtil.ConfigureBaseTrigger(val); val.interactable = flag && !inCooldown && !resolvingAttempt; val.timeToHold = timeToHold; val.hoverTip = hoverTip; val.holdTip = holdTip; } } } private void OnBigDoorInteract(PlayerControllerB player) { if ((Object)(object)bigDoor == (Object)null || (Object)(object)player == (Object)null) { resolvingAttempt = false; return; } if (resolvingAttempt || Time.time < cooldownUntil) { DoorLockpickPlus.ShowTip("Door Controls", "Wait a moment before trying again.", warning: true); return; } resolvingAttempt = true; bool flag = BigDoorUtil.IsOpen(bigDoor); if (DoorLockpickPlus.DebugRollLogging != null && DoorLockpickPlus.DebugRollLogging.Value && DoorLockpickPlus.Log != null) { DoorLockpickPlus.Log.LogInfo((object)("Big door interact on " + ((Object)bigDoor).name + " / current open " + flag)); } if (flag) { ((MonoBehaviour)this).StartCoroutine(ExecuteBigDoorCommand(targetOpen: false)); return; } float num = Mathf.Clamp01(DoorLockpickPlus.BigDoorSuccessChance.Value); float num2 = Random.Range(0f, 1f); bool flag2 = num2 <= num; if (DoorLockpickPlus.DebugRollLogging != null && DoorLockpickPlus.DebugRollLogging.Value && DoorLockpickPlus.Log != null) { DoorLockpickPlus.Log.LogInfo((object)("Big door pry roll: " + num2.ToString("0.000") + " / chance " + num.ToString("0.000") + " / success " + flag2)); } if (flag2) { ((MonoBehaviour)this).StartCoroutine(ExecuteBigDoorCommand(targetOpen: true)); return; } DoorLockpickPlus.ShowTip("Pry Failed", "You failed to pry it open. Try again.", warning: true); redFlashUntil = Time.time + Mathf.Max(0.1f, DoorLockpickPlus.FailFlashTime.Value); cooldownUntil = Time.time + Mathf.Max(0.1f, DoorLockpickPlus.RetryCooldown.Value); resolvingAttempt = false; } [IteratorStateMachine(typeof(<ExecuteBigDoorCommand>d__20))] private IEnumerator ExecuteBigDoorCommand(bool targetOpen) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ExecuteBigDoorCommand>d__20(0) { <>4__this = this, targetOpen = targetOpen }; } private void DestroyTriggers() { for (int i = 0; i < triggerObjects.Count; i++) { if ((Object)(object)triggerObjects[i] != (Object)null) { Object.Destroy((Object)(object)triggerObjects[i]); } } triggerObjects.Clear(); triggers.Clear(); } private void Clear() { resolvingAttempt = false; if ((Object)(object)highlighter != (Object)null) { highlighter.Clear(); } DestroyTriggers(); } private void OnDisable() { resolvingAttempt = false; DestroyTriggers(); } private void OnDestroy() { Clear(); } } internal class DoorAudioController : MonoBehaviour { private DoorLock door; private AudioSource source; private AudioClip pickingClip; private AudioClip unlockClip; private AudioClip failClip; public void Init(DoorLock targetDoor) { door = targetDoor; source = ((Component)this).gameObject.GetComponent<AudioSource>(); if ((Object)(object)source == (Object)null) { source = ((Component)this).gameObject.AddComponent<AudioSource>(); } source.playOnAwake = false; source.loop = false; source.spatialBlend = 1f; source.rolloffMode = (AudioRolloffMode)1; source.minDistance = 1f; source.maxDistance = 18f; source.dopplerLevel = 0f; source.spatialize = false; pickingClip = AudioUtil.GetAudioClip(door, new string[3] { "pickingLockSFX", "pickLockSFX", "lockpickSFX" }); unlockClip = AudioUtil.GetAudioClip(door, new string[3] { "unlockSFX", "unlockDoorSFX", "doorUnlockSFX" }); failClip = AudioUtil.GetAudioClip(door, new string[3] { "doorLockSFX", "lockedDoorSFX", "lockSFX" }); } public void StartLockpickLoop() { if (!((Object)(object)source == (Object)null) && !((Object)(object)pickingClip == (Object)null)) { float volume = ((DoorLockpickPlus.LockpickSoundVolume != null) ? Mathf.Clamp01(DoorLockpickPlus.LockpickSoundVolume.Value) : 0.75f); if (source.isPlaying && (Object)(object)source.clip == (Object)(object)pickingClip && source.loop) { source.volume = volume; return; } source.Stop(); source.clip = pickingClip; source.loop = true; source.volume = volume; source.Play(); } } public void StopLockpickLoop() { if (!((Object)(object)source == (Object)null) && (Object)(object)source.clip == (Object)(object)pickingClip && source.loop) { source.Stop(); source.loop = false; source.clip = null; } } public void PlayUnlockSoundOnce() { StopLockpickLoop(); PlayOneShotClean(unlockClip); } public void PlayFailSoundOnce() { StopLockpickLoop(); PlayOneShotClean(failClip); } private void PlayOneShotClean(AudioClip clip) { if (!((Object)(object)source == (Object)null) && !((Object)(object)clip == (Object)null)) { float num = ((DoorLockpickPlus.LockpickSoundVolume != null) ? Mathf.Clamp01(DoorLockpickPlus.LockpickSoundVolume.Value) : 0.75f); source.loop = false; source.clip = null; source.Stop(); source.PlayOneShot(clip, num); } } private void OnDestroy() { if ((Object)(object)source != (Object)null) { source.Stop(); } } } internal class DoorVisualHighlighter : MonoBehaviour { private readonly List<Renderer> renderers = new List<Renderer>(); private readonly Dictionary<Renderer, MaterialPropertyBlock> blocks = new Dictionary<Renderer, MaterialPropertyBlock>(); private readonly List<GameObject> overlayObjects = new List<GameObject>(); private readonly List<Material> overlayMaterials = new List<Material>(); private GameObject lightObject; private Light lightSource; private bool isBigDoor; public void Init(GameObject root, Bounds focusBounds, bool bigDoor) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) isBigDoor = bigDoor; CacheRenderers(root, focusBounds, bigDoor); CreateOverlayMeshes(); CreateLight(); if (DoorLockpickPlus.Log != null) { string text = (((Object)(object)root != (Object)null) ? ((Object)root).name : "null"); DoorLockpickPlus.Log.LogInfo((object)("DoorLockpickPlus visual renderers for " + text + ": " + renderers.Count)); } } private void CacheRenderers(GameObject root, Bounds focusBounds, bool bigDoor) { //IL_0037: 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_00c7: 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_0124: Expected O, but got Unknown renderers.Clear(); blocks.Clear(); if ((Object)(object)root == (Object)null) { return; } List<Renderer> list = new List<Renderer>(); CollectRendererCandidates(root.transform, focusBounds, bigDoor, list); if (!bigDoor && list.Count == 0 && (Object)(object)root.transform.parent != (Object)null) { CollectRendererCandidates(root.transform.parent, focusBounds, bigDoor, list); } if (!bigDoor && list.Count == 0 && (Object)(object)root.transform.parent != (Object)null && (Object)(object)root.transform.parent.parent != (Object)null) { CollectRendererCandidates(root.transform.parent.parent, focusBounds, bigDoor, list); } for (int i = 0; i < list.Count; i++) { Renderer val = list[i]; if (!((Object)(object)val == (Object)null) && !renderers.Contains(val)) { renderers.Add(val); blocks[val] = new MaterialPropertyBlock(); } } } private void CollectRendererCandidates(Transform root, Bounds focusBounds, bool bigDoor, List<Renderer> output) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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 ((Object)(object)root == (Object)null || output == null) { return; } Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(true); Bounds val = focusBounds; ((Bounds)(ref val)).Expand(bigDoor ? 4f : 5f); Renderer[] array = componentsInChildren; foreach (Renderer val2 in array) { if (!RendererUtil.IsVisibleDoorRenderer(val2, bigDoor)) { continue; } if (!bigDoor && !((Bounds)(ref val)).Intersects(val2.bounds)) { Bounds bounds = val2.bounds; float num = Vector3.Distance(((Bounds)(ref bounds)).center, ((Bounds)(ref focusBounds)).center); if (num > 5.5f) { continue; } } if (!output.Contains(val2)) { output.Add(val2); } } } private void CreateOverlayMeshes() { foreach (Renderer renderer in renderers) { if ((Object)(object)renderer == (Object)null) { continue; } MeshFilter component = ((Component)renderer).GetComponent<MeshFilter>(); if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null) { CreateMeshOverlay(renderer, component.sharedMesh); continue; } SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); if ((Object)(object)val != (Object)null && (Object)(object)val.sharedMesh != (Object)null) { CreateSkinnedMeshOverlay(val); } } } private void CreateMeshOverlay(Renderer originalRenderer, Mesh mesh) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("DoorLockpickPlus_OverlayMesh"); val.transform.SetParent(((Component)originalRenderer).transform, false); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one * 1.006f; val.layer = ((Component)originalRenderer).gameObject.layer; MeshFilter val2 = val.AddComponent<MeshFilter>(); val2.sharedMesh = mesh; MeshRenderer val3 = val.AddComponent<MeshRenderer>(); Material item = (((Renderer)val3).sharedMaterial = CreateOverlayMaterial(Color.clear)); ((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)val3).receiveShadows = false; ((Renderer)val3).enabled = false; overlayObjects.Add(val); overlayMaterials.Add(item); } private void CreateSkinnedMeshOverlay(SkinnedMeshRenderer originalRenderer) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("DoorLockpickPlus_OverlaySkinnedMesh"); val.transform.SetParent(((Component)originalRenderer).transform, false); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one * 1.006f; val.layer = ((Component)originalRenderer).gameObject.layer; SkinnedMeshRenderer val2 = val.AddComponent<SkinnedMeshRenderer>(); val2.sharedMesh = originalRenderer.sharedMesh; val2.bones = originalRenderer.bones; val2.rootBone = originalRenderer.rootBone; Material item = (((Renderer)val2).sharedMaterial = CreateOverlayMaterial(Color.clear)); ((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)val2).receiveShadows = false; ((Renderer)val2).enabled = false; overlayObjects.Add(val); overlayMaterials.Add(item); } private Material CreateOverlayMaterial(Color color) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) Shader val = Shader.Find("Sprites/Default"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Particles/Standard Unlit"); } if ((Object)(object)val == (Object)null) { val = Shader.Find("Unlit/Color"); } if ((Object)(object)val == (Object)null) { val = Shader.Find("Standard"); } Material val2 = new Material(val); ((Object)val2).name = "DoorLockpickPlus_OverlayMaterial"; val2.renderQueue = 3100; if (val2.HasProperty("_SrcBlend")) { val2.SetInt("_SrcBlend", 5); } if (val2.HasProperty("_DstBlend")) { val2.SetInt("_DstBlend", 10); } if (val2.HasProperty("_ZWrite")) { val2.SetInt("_ZWrite", 0); } if (val2.HasProperty("_Cull")) { val2.SetInt("_Cull", 0); } SetMaterialColor(val2, color, 1f); return val2; } private void CreateLight() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) lightObject = new GameObject("DoorLockpickPlus_HighlightLight"); lightObject.transform.SetParent(((Component)this).transform, false); lightObject.transform.localPosition = Vector3.zero; lightSource = lightObject.AddComponent<Light>(); lightSource.type = (LightType)2; lightSource.range = 4f; lightSource.intensity = 0f; lightSource.shadows = (LightShadows)0; lightSource.renderMode = (LightRenderMode)1; ((Behaviour)lightSource).enabled = false; } public void Apply(Color color, float strength, bool enableLight, float multiplier) { //IL_0091: 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_00a0: 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_00a4: 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_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) float num = ((DoorLockpickPlus.DoorTintStrength != null) ? Mathf.Clamp01(DoorLockpickPlus.DoorTintStrength.Value) : 0.55f); float num2 = ((DoorLockpickPlus.DoorOverlayAlpha != null) ? Mathf.Clamp01(DoorLockpickPlus.DoorOverlayAlpha.Value) : 0.18f); float num3 = ((DoorLockpickPlus.DoorEmissionStrength != null) ? Mathf.Max(0f, DoorLockpickPlus.DoorEmissionStrength.Value) : 1.15f); float num4 = ((DoorLockpickPlus.DoorLightStrength != null) ? Mathf.Max(0f, DoorLockpickPlus.DoorLightStrength.Value) : 0.55f); float num5 = Mathf.Max(0f, multiplier); Color val = Color.Lerp(Color.white, color, num * num5); Color val2 = color * num3 * strength * num5; foreach (Renderer renderer in renderers) { if (!((Object)(object)renderer == (Object)null)) { MaterialPropertyBlock val3 = blocks[renderer]; renderer.GetPropertyBlock(val3); val3.SetColor("_Color", val); val3.SetColor("_BaseColor", val); val3.SetColor("_EmissionColor", val2); val3.SetColor("_EmissiveColor", val2); renderer.SetPropertyBlock(val3); } } Color color2 = color; color2.a = num2 * num5; for (int i = 0; i < overlayObjects.Count; i++) { GameObject val4 = overlayObjects[i]; if (!((Object)(object)val4 == (Object)null)) { Renderer component = val4.GetComponent<Renderer>(); if ((Object)(object)component != (Object)null) { component.enabled = true; } if (i < overlayMaterials.Count && (Object)(object)overlayMaterials[i] != (Object)null) { SetMaterialColor(overlayMaterials[i], color2, num5); } } } if ((Object)(object)lightSource != (Object)null) { Bounds acceptedRendererBounds = GetAcceptedRendererBounds(); ((Component)lightSource).transform.position = ((Bounds)(ref acceptedRendererBounds)).center; lightSource.color = color; Light obj = lightSource; Vector3 extents = ((Bounds)(ref acceptedRendererBounds)).extents; obj.range = Mathf.Clamp(((Vector3)(ref extents)).magnitude * (isBigDoor ? 0.75f : 1.05f), 1.5f, isBigDoor ? 5.5f : 7f); lightSource.intensity = (enableLight ? Mathf.Clamp(num4 * strength * num5, 0f, isBigDoor ? 1.2f : 2.5f) : 0f); ((Behaviour)lightSource).enabled = enableLight && renderers.Count > 0; } } public void Clear() { foreach (Renderer renderer in renderers) { if (!((Object)(object)renderer == (Object)null)) { renderer.SetPropertyBlock((MaterialPropertyBlock)null); } } for (int i = 0; i < overlayObjects.Count; i++) { GameObject val = overlayObjects[i]; if (!((Object)(object)val == (Object)null)) { Renderer component = val.GetComponent<Renderer>(); if ((Object)(object)component != (Object)null) { component.enabled = false; } } } if ((Object)(object)lightSource != (Object)null) { ((Behaviour)lightSource).enabled = false; lightSource.intensity = 0f; } } private Bounds GetAcceptedRendererBounds() { //IL_0009: 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_007c: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = default(Bounds); ((Bounds)(ref bounds))..ctor(((Component)this).transform.position, Vector3.one); bool flag = false; for (int i = 0; i < renderers.Count; i++) { Renderer val = renderers[i]; if (!((Object)(object)val == (Object)null)) { if (!flag) { bounds = val.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val.bounds); } } } return bounds; } private void SetMaterialColor(Material mat, Color color, float multiplier) { //IL_0025: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)mat == (Object)null)) { if (mat.HasProperty("_Color")) { mat.SetColor("_Color", color); } if (mat.HasProperty("_BaseColor")) { mat.SetColor("_BaseColor", color); } if (mat.HasProperty("_EmissionColor")) { mat.SetColor("_EmissionColor", color * (1f + multiplier)); } } } private void OnDestroy() { Clear(); for (int i = 0; i < overlayObjects.Count; i++) { if ((Object)(object)overlayObjects[i] != (Object)null) { Object.Destroy((Object)(object)overlayObjects[i]); } } overlayObjects.Clear(); for (int j = 0; j < overlayMaterials.Count; j++) { if ((Object)(object)overlayMaterials[j] != (Object)null) { Object.Destroy((Object)(object)overlayMaterials[j]); } } overlayMaterials.Clear(); if ((Object)(object)lightObject != (Object)null) { Object.Destroy((Object)(object)lightObject); lightObject = null; } } } internal class TriggerSnapshot { private readonly string hoverTip; private readonly string holdTip; private readonly bool interactable; private readonly bool holdInteraction; private readonly float timeToHold; private readonly float timeToHoldSpeedMultiplier; private readonly bool oneHandedItemAllowed; private readonly bool twoHandedItemAllowed; private readonly bool interactCooldown; private readonly float cooldownTime; private readonly bool triggerOnce; public TriggerSnapshot(InteractTrigger trigger) { hoverTip = trigger.hoverTip; holdTip = trigger.holdTip; interactable = trigger.interactable; holdInteraction = trigger.holdInteraction; timeToHold = trigger.timeToHold; timeToHoldSpeedMultiplier = trigger.timeToHoldSpeedMultiplier; oneHandedItemAllowed = trigger.oneHandedItemAllowed; twoHandedItemAllowed = trigger.twoHandedItemAllowed; interactCooldown = trigger.interactCooldown; cooldownTime = trigger.cooldownTime; triggerOnce = trigger.triggerOnce; } public void Restore(InteractTrigger trigger) { trigger.hoverTip = hoverTip; trigger.holdTip = holdTip; trigger.interactable = interactable; trigger.holdInteraction = holdInteraction; trigger.timeToHold = timeToHold; trigger.timeToHoldSpeedMultiplier = timeToHoldSpeedMultiplier; trigger.oneHandedItemAllowed = oneHandedItemAllowed; trigger.twoHandedItemAllowed = twoHandedItemAllowed; trigger.interactCooldown = interactCooldown; trigger.cooldownTime = cooldownTime; trigger.triggerOnce = triggerOnce; } } internal static class InteractTriggerUtil { private static readonly FieldInfo onInteractField = AccessTools.Field(typeof(InteractTrigger), "onInteract"); private static readonly FieldInfo onInteractEarlyField = AccessTools.Field(typeof(InteractTrigger), "onInteractEarly"); private static readonly FieldInfo onStopInteractField = AccessTools.Field(typeof(InteractTrigger), "onStopInteract"); private static readonly FieldInfo holdingInteractEventField = AccessTools.Field(typeof(InteractTrigger), "holdingInteractEvent"); private static readonly FieldInfo onCancelAnimationField = AccessTools.Field(typeof(InteractTrigger), "onCancelAnimation"); public static void MakeGameObjectARealInteractTrigger(GameObject obj) { if (!((Object)(object)obj == (Object)null)) { TrySetTag(obj, "InteractTrigger"); obj.layer = LayerUtil.InteractableLayer(); Collider component = obj.GetComponent<Collider>(); if ((Object)(object)component != (Object)null) { component.isTrigger = true; } Renderer component2 = obj.GetComponent<Renderer>(); if ((Object)(object)component2 != (Object)null) { component2.enabled = false; } } } private static void TrySetTag(GameObject obj, string tag) { try { obj.tag = tag; } catch { } } public static void ConfigureBaseTrigger(InteractTrigger trigger) { if (!((Object)(object)trigger == (Object)null)) { MakeGameObjectARealInteractTrigger(((Component)trigger).gameObject); trigger.interactable = true; trigger.oneHandedItemAllowed = true; trigger.twoHandedItemAllowed = true; trigger.holdInteraction = true; trigger.timeToHoldSpeedMultiplier = 1f; trigger.interactCooldown = true; trigger.cooldownTime = 0.5f; trigger.triggerOnce = false; trigger.stopAnimationString = "SA_stopAnimation"; trigger.animationWaitTime = 2f; trigger.lockPlayerPosition = true; trigger.disableTriggerMesh = true; EnsureEventObject(trigger, onInteractField); EnsureEventObject(trigger, onInteractEarlyField); EnsureEventObject(trigger, onStopInteractField); EnsureEventObject(trigger, holdingInteractEventField); EnsureEventObject(trigger, onCancelAnimationField); CopyIconFromScene(trigger); } } public static void CopyIconFromTriggers(InteractTrigger target, List<InteractTrigger> templates) { if ((Object)(object)target == (Object)null) { return; } if (templates != null) { for (int i = 0; i < templates.Count; i++) { InteractTrigger val = templates[i]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)target)) { if ((Object)(object)val.hoverIcon != (Object)null) { target.hoverIcon = val.hoverIcon; } if ((Object)(object)val.disabledHoverIcon != (Object)null) { target.disabledHoverIcon = val.disabledHoverIcon; } if ((Object)(object)target.hoverIcon != (Object)null) { return; } } } } CopyIconFromScene(target); } public static void CopyIconFromScene(InteractTrigger target) { if ((Object)(object)target == (Object)null || (Object)(object)target.hoverIcon != (Object)null) { return; } InteractTrigger[] array = Object.FindObjectsOfType<InteractTrigger>(); foreach (InteractTrigger val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)target) && (Object)(object)val.hoverIcon != (Object)null) { target.hoverIcon = val.hoverIcon; target.disabledHoverIcon = (((Object)(object)val.disabledHoverIcon != (Object)null) ? val.disabledHoverIcon : val.hoverIcon); break; } } } private static object EnsureEventObject(InteractTrigger trigger, FieldInfo field) { try { if ((Object)(object)trigger == (Object)null || field == null) { return null; } object obj = field.GetValue(trigger); if (obj == null) { obj = Activator.CreateInstance(field.FieldType); field.SetValue(trigger, obj); } return obj; } catch { return null; } } public static void AddInteractListener(InteractTrigger trigger, Action<PlayerControllerB> callback) { try { if ((Object)(object)trigger == (Object)null || callback == null || onInteractField == null) { return; } object obj = EnsureEventObject(trigger, onInteractField); if (obj == null) { return; } UnityAction<PlayerControllerB> val = callback.Invoke; MethodInfo method = obj.GetType().GetMethod("AddListener", new Type[1] { typeof(UnityAction<PlayerControllerB>) }); if (method != null) { method.Invoke(obj, new object[1] { val }); return; } MethodInfo[] methods = obj.GetType().GetMethods(); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo.Name != "AddListener")) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 1) { methodInfo.Invoke(obj, new object[1] { val }); break; } } } } catch (Exception ex) { if (DoorLockpickPlus.Log != null) { DoorLockpickPlus.Log.LogWarning((object)("Failed to add InteractTrigger listener: " + ex.Message)); } } } } internal static class BigDoorUtil { public static bool IsProbablyBigDoor(TerminalAccessibleObject obj) { if ((Object)(object)obj == (Object)null) { return false; } if (obj.isBigDoor) { return true; } string text = ((Object)((Component)obj).gameObject).name.ToLowerInvariant(); if (text.Contains("bigdoor") || text.Contains("big door")) { return true; } Transform parent = ((Component)obj).transform.parent; while ((Object)(object)parent != (Object)null) { string text2 = ((Object)parent).name.ToLowerInvariant(); if (text2.Contains("bigdoor") || text2.Contains("big door")) { return true; } parent = parent.parent; } return false; } public static bool IsOpen(TerminalAccessibleObject obj) { if ((Object)(object)obj == (Object)null) { return false; } return ReflectionUtil.GetBoolFieldExact(obj, "isDoorOpen"); } public static string GetObjectCode(TerminalAccessibleObject obj) { if ((Object)(object)obj == (Object)null) { return ""; } try { if (!string.IsNullOrEmpty(obj.objectCode)) { return obj.objectCode; } } catch { } return ""; } public static void ClearCooldown(TerminalAccessibleObject obj) { if (!((Object)(object)obj == (Object)null)) { ReflectionUtil.SetBoolFieldExact(obj, "inCooldown", value: false); ReflectionUtil.SetFloatFieldExact(obj, "currentCooldownTimer", 0f); } } public static void SendTerminalCommand(TerminalAccessibleObject obj) { if (!((Object)(object)obj == (Object)null)) { ClearCooldown(obj); ReflectionUtil.CallNoArgExact(obj, "CallFunctionFromTerminal"); } } public static void ForceSetOpen(TerminalAccessibleObject obj, bool open) { if (!((Object)(object)obj == (Object)null)) { ClearCooldown(obj); ReflectionUtil.SetBoolFieldExact(obj, "isDoorOpen", open); ReflectionUtil.CallBoolArgExact(obj, "SetDoorOpen", open); ReflectionUtil.CallBoolArgExact(obj, "SetDoorLocalClient", open); ReflectionUtil.CallBoolArgExact(obj, "SetDoorOpenClientRpc", open); ReflectionUtil.CallBoolArgExact(obj, "SetDoorOpenServerRpc", open); ReflectionUtil.SetBoolFieldExact(obj, "isDoorOpen", open); } } } internal static class AudioUtil { public static AudioClip GetAudioClip(object instance, string[] fieldNames) { if (instance == null || fieldNames == null) { return null; } for (int i = 0; i < fieldNames.Length; i++) { AudioClip fieldValueExact = ReflectionUtil.GetFieldValueExact<AudioClip>(instance, fieldNames[i]); if ((Object)(object)fieldValueExact != (Object)null) { return fieldValueExact; } } return null; } } internal static class RendererUtil { public static bool IsVisibleDoorRenderer(Renderer renderer, bool bigDoor) { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)renderer == (Object)null) { return false; } if (!renderer.enabled || !((Component)renderer).gameObject.activeInHierarchy) { return false; } string lowerName = ((Object)((Component)renderer).gameObject).name.ToLowerInvariant(); string text = GetPath(((Component)renderer).transform).ToLowerInvariant(); string text2 = ((object)renderer).GetType().Name.ToLowerInvariant(); if (text2.Contains("particle") || text2.Contains("line") || text2.Contains("trail")) { return false; } if (ShouldSkipVisualName(lowerName) || ShouldSkipVisualName(text)) { return false; } Bounds bounds = renderer.bounds; Vector3 size = ((Bounds)(ref bounds)).size; if (((Vector3)(ref size)).sqrMagnitude <= 0.0001f) { return false; } MeshFilter component = ((Component)renderer).GetComponent<MeshFilter>(); SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); if (((Object)(object)component == (Object)null || (Object)(object)component.sharedMesh == (Object)null) && ((Object)(object)val == (Object)null || (Object)(object)val.sharedMesh == (Object)null)) { return false; } if (bigDoor && (text.Contains("doorcode") || text.Contains("map") || text.Contains("screen") || text.Contains("ui"))) { return false; } return true; } private static bool ShouldSkipVisualName(string lowerName) { if (string.IsNullOrEmpty(lowerName)) { return false; } return lowerName.Contains("trigger") || lowerName.Contains("collider") || lowerName.Contains("collision") || lowerName.Contains("hitbox") || lowerName.Contains("lockpickplus") || lowerName.Contains("interact") || lowerName.Contains("scan") || lowerName.Contains("node") || lowerName.Contains("radar") || lowerName.Contains("code") || lowerName.Contains("ui") || lowerName.Contains("audio") || lowerName.Contains("light") || lowerName.Contains("particle") || lowerName.Contains("spark") || lowerName.Contains("nav") || lowerName.Contains("bounds"); } private static string GetPath(Transform transform) { if ((Object)(object)transform == (Object)null) { return ""; } string text = ((Object)transform).name; Transform parent = transform.parent; int num = 0; while ((Object)(object)parent != (Object)null && num < 12) { text = ((Object)parent).name + "/" + text; parent = parent.parent; num++; } return text; } } internal static class LayerUtil { public static int InteractableLayer() { int num = LayerMask.NameToLayer("InteractableObject"); if (num >= 0) { return num; } num = LayerMask.NameToLayer("Interactable"); if (num >= 0) { return num; } return 0; } } internal static class BoundsUtil { public static Bounds GetBounds(GameObject root) { //IL_002d: 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_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_014e: 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_011a: 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 ((Object)(object)root == (Object)null) { return new Bounds(Vector3.zero, Vector3.one); } Bounds bounds = default(Bounds); ((Bounds)(ref bounds))..ctor(root.transform.position, Vector3.one); bool flag = false; Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true); Renderer[] array = componentsInChildren; foreach (Renderer val in array) { if (RendererUtil.IsVisibleDoorRenderer(val, bigDoor: true) || RendererUtil.IsVisibleDoorRenderer(val, bigDoor: false)) { if (!flag) { bounds = val.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val.bounds); } } } if (flag) { return bounds; } Collider[] componentsInChildren2 = root.GetComponentsInChildren<Collider>(true); Collider[] array2 = componentsInChildren2; foreach (Collider val2 in array2) { if ((Object)(object)val2 == (Object)null) { continue; } string lowerName = ((Object)((Component)val2).gameObject).name.ToLowerInvariant(); if (!ShouldSkipBoundsName(lowerName)) { if (!flag) { bounds = val2.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val2.bounds); } } } if (flag) { return bounds; } return new Bounds(root.transform.position, Vector3.one * 3f); } public static List<Bounds> GetIndividualVisualBounds(GameObject root, bool bigDoor) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) List<Bounds> list = new List<Bounds>(); if ((Object)(object)root == (Object)null) { return list; } Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true); Renderer[] array = componentsInChildren; Vector3 size; foreach (Renderer val in array) { if (RendererUtil.IsVisibleDoorRenderer(val, bigDoor)) { Bounds bounds = val.bounds; size = ((Bounds)(ref bounds)).size; if (!(((Vector3)(ref size)).sqrMagnitude <= 0.0001f)) { list.Add(bounds); } } } if (list.Count == 0) { Bounds bounds2 = GetBounds(root); size = ((Bounds)(ref bounds2)).size; if (((Vector3)(ref size)).sqrMagnitude > 0.0001f) { list.Add(bounds2); } } return list; } public static void EncapsulateTransformBounds(Transform transform, ref Bounds bounds, ref bool hasBounds) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)transform == (Object)null) { return; } Collider component = ((Component)transform).GetComponent<Collider>(); if ((Object)(object)component != (Object)null) { if (!hasBounds) { bounds = component.bounds; hasBounds = true; } else { ((Bounds)(ref bounds)).Encapsulate(component.bounds); } return; } Renderer component2 = ((Component)transform).GetComponent<Renderer>(); if ((Object)(object)component2 != (Object)null) { if (!hasBounds) { bounds = component2.bounds; hasBounds = true; } else { ((Bounds)(ref bounds)).Encapsulate(component2.bounds); } } } private static bool ShouldSkipBoundsName(string lowerName) { if (string.IsNullOrEmpty(lowerName)) { return false; } return lowerName.Contains("trigger") || lowerName.Contains("lockpickplus") || lowerName.Contains("interact") || lowerName.Contains("scan") || lowerName.Contains("node") || lowerName.Contains("ui") || lowerName.Contains("audio") || lowerName.Contains("light"); } } internal static class ReflectionUtil { public static T GetFieldValueExact<T>(object instance, string fieldName) where T : class { try { if (instance == null) { return null; } FieldInfo field = instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return null; } object value = field.GetValue(instance); return value as T; } catch { return null; } } public static bool GetBoolFieldExact(object instance, string fieldName) { try { if (instance == null) { return false; } FieldInfo field = instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null || field.FieldType != typeof(bool)) { return false; } object value = field.GetValue(instance); if (value is bool) { return (bool)value; } } catch { } return false; } public static void SetBoolFieldExact(object instance, string fieldName, bool value) { try { if (instance != null) { FieldInfo field = instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field == null) && !(field.FieldType != typeof(bool))) { field.SetValue(instance, value); } } } catch { } } public static void SetFloatFieldExact(object instance, string fieldName, float value) { try { if (instance != null) { FieldInfo field = instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field == null) && !(field.FieldType != typeof(float))) { field.SetValue(instance, value); } } } catch { } } public static bool CallNoArgExact(object instance, string methodName) { try { if (instance == null) { return false; } MethodInfo method = instance.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null || method.GetParameters().Length != 0) { return false; } method.Invoke(instance, null); return true; } catch { return false; } } public static bool CallBoolArgExact(object instance, string methodName, bool value) { try { if (instance == null) { return false; } MethodInfo method = instance.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { return false; } ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != 1 || parameters[0].ParameterType != typeof(bool)) { return false; } method.Invoke(instance, new object[1] { value }); return true; } catch { return false; } } }
plugins/Extraction/Extraction.dll
Decompiled 19 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ScrapVisbility")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ScrapVisbility")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("8a6853bd-bdc9-4741-95c7-5aa2c8c6a6f9")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace Extraction; [BepInPlugin("robert.lethalcompany.extraction", "Extraction", "0.2.37")] public sealed class Plugin : BaseUnityPlugin { private struct CubeShape { public Vector3 Center; public Vector3 Size; public CubeShape(Vector3 center, Vector3 size) { //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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) Center = center; Size = size; } } private struct DynamicBoundarySegment { public int Axis; public int Sign; public float FixedCoord; public float FromCoord; public float ToCoord; public DynamicBoundarySegment(int axis, int sign, float fixedCoord, float fromCoord, float toCoord) { Axis = axis; Sign = sign; FixedCoord = fixedCoord; FromCoord = fromCoord; ToCoord = toCoord; } } private struct ShipDoorAudioState { internal readonly bool Mute; internal readonly float Volume; internal ShipDoorAudioState(bool mute, float volume) { Mute = mute; Volume = volume; } } private sealed class ScrapGlowState { private readonly GrabbableObject _item; private readonly Dictionary<Renderer, MaterialPropertyBlock> _originalBlocks = new Dictionary<Renderer, MaterialPropertyBlock>(); private GameObject _lightObject; internal ScrapGlowState(GrabbableObject item) { _item = item; } internal void Apply() { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0117: 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_0133: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Expected O, but got Unknown //IL_01e5: 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) //IL_0212: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_item == (Object)null) { return; } Renderer[] componentsInChildren = ((Component)_item).GetComponentsInChildren<Renderer>(true); Color val = default(Color); ((Color)(ref val))..ctor(1f, 0.03f, 0.02f, 1f); float num = Mathf.Max(0f, (_cubeScrapGlowEmissionStrength != null) ? _cubeScrapGlowEmissionStrength.Value : 4f); Color val2 = val * Mathf.Max(1f, num); Renderer[] array = componentsInChildren; foreach (Renderer val3 in array) { if (!((Object)(object)val3 == (Object)null) && val3.enabled && !(val3 is ParticleSystemRenderer)) { MaterialPropertyBlock val4 = new MaterialPropertyBlock(); val3.GetPropertyBlock(val4); _originalBlocks[val3] = val4; MaterialPropertyBlock val5 = new MaterialPropertyBlock(); val3.GetPropertyBlock(val5); val5.SetColor("_Color", val); val5.SetColor("_BaseColor", val); val5.SetColor("_TintColor", val); val5.SetColor("_MainColor", val); val5.SetColor("_EmissionColor", val2); val5.SetColor("_EmissiveColor", val2); val5.SetFloat("_UseEmissiveIntensity", 1f); val5.SetFloat("_EmissiveIntensity", num); val3.SetPropertyBlock(val5); } } float num2 = Mathf.Max(0f, (_cubeScrapGlowLightIntensity != null) ? _cubeScrapGlowLightIntensity.Value : 1.25f); if (num2 > 0f) { _lightObject = new GameObject("Extraction_CubeScrap_RedGlowLight"); _lightObject.transform.SetParent(((Component)_item).transform, false); _lightObject.transform.localPosition = Vector3.up * 0.15f; Light val6 = _lightObject.AddComponent<Light>(); val6.type = (LightType)2; val6.color = val; val6.intensity = num2; val6.range = Mathf.Max(0.25f, (_cubeScrapGlowLightRange != null) ? _cubeScrapGlowLightRange.Value : 2.25f); val6.shadows = (LightShadows)0; val6.renderMode = (LightRenderMode)1; } } internal void Restore() { foreach (KeyValuePair<Renderer, MaterialPropertyBlock> originalBlock in _originalBlocks) { if ((Object)(object)originalBlock.Key != (Object)null) { originalBlock.Key.SetPropertyBlock(originalBlock.Value); } } _originalBlocks.Clear(); if ((Object)(object)_lightObject != (Object)null) { Object.Destroy((Object)(object)_lightObject); _lightObject = null; } } } internal sealed class ScrapValueHighlighter : MonoBehaviour { private GrabbableObject item; private GameObject textObject; private TextMesh textMesh; private MeshRenderer textRenderer; private Material textMaterial; private GameObject lightObject; private Light glowLight; private readonly List<Renderer> targetRenderers = new List<Renderer>(); private readonly Dictionary<Renderer, MaterialPropertyBlock> blocks = new Dictionary<Renderer, MaterialPropertyBlock>(); private int lastValue = -999999; private string lastName = string.Empty; private Color lastColor = Color.clear; private bool textVisible; private float lastGoodTextVisibleTime; private static readonly FieldInfo fieldIsHeld = typeof(GrabbableObject).GetField("isHeld", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo fieldIsPocketed = typeof(GrabbableObject).GetField("isPocketed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo fieldIsHeldByEnemy = typeof(GrabbableObject).GetField("isHeldByEnemy", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo fieldPlayerHeldBy = typeof(GrabbableObject).GetField("playerHeldBy", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo fieldCurrentlyHeldObjectServer = typeof(PlayerControllerB).GetField("currentlyHeldObjectServer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo fieldCurrentlyHeldObject = typeof(PlayerControllerB).GetField("currentlyHeldObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal void Init(GrabbableObject grabbable) { item = grabbable; CacheTargetRenderers(); CreateText(); CreateApparatusLight(); SetVisualsActive(active: false); } private void CacheTargetRenderers() { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown targetRenderers.Clear(); blocks.Clear(); if ((Object)(object)item == (Object)null) { return; } Renderer[] componentsInChildren = ((Component)item).GetComponentsInChildren<Renderer>(true); Renderer[] array = componentsInChildren; foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null)) { string lowerName = ((Object)((Component)val).gameObject).name.ToLowerInvariant(); if (!ShouldSkipRenderer(val, lowerName)) { targetRenderers.Add(val); blocks[val] = new MaterialPropertyBlock(); } } } } private bool ShouldSkipRenderer(Renderer renderer, string lowerName) { if ((Object)(object)renderer == (Object)null) { return true; } if (!renderer.enabled) { return true; } if (string.IsNullOrEmpty(lowerName)) { lowerName = ((Object)((Component)renderer).gameObject).name.ToLowerInvariant(); } string text = ((object)renderer).GetType().Name.ToLowerInvariant(); if (text.Contains("particle") || text.Contains("trail") || text.Contains("line")) { return true; } if (lowerName.Contains("scan") || lowerName.Contains("scannode") || lowerName.Contains("scan node") || lowerName.Contains("trigger") || lowerName.Contains("collider") || lowerName.Contains("collision") || lowerName.Contains("hitbox") || lowerName.Contains("interact") || lowerName.Contains("scrapvisibility") || lowerName.Contains("mapdot") || lowerName.Contains("radar") || lowerName.Contains("audio") || lowerName.Contains("sound") || lowerName.Contains("light") || lowerName.Contains("vfx") || lowerName.Contains("sfx")) { return true; } return false; } private void CreateText() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_004e: 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_005d: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Expected O, but got Unknown //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Expected O, but got Unknown //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)textObject != (Object)null) { return; } textObject = new GameObject("ScrapVisibility_3DText"); textObject.transform.SetParent(GetScrapTextRoot(), false); textObject.transform.position = ((Component)this).transform.position + Vector3.up * 0.5f; textObject.transform.rotation = Quaternion.identity; textObject.transform.localScale = Vector3.one; textMesh = textObject.AddComponent<TextMesh>(); textMesh.text = string.Empty; textMesh.alignment = (TextAlignment)1; textMesh.anchor = (TextAnchor)4; textMesh.fontSize = 90; textMesh.characterSize = 0.022f; textMesh.color = Color.white; Font builtinResource = Resources.GetBuiltinResource<Font>("Arial.ttf"); if ((Object)(object)builtinResource != (Object)null) { textMesh.font = builtinResource; } textRenderer = textObject.GetComponent<MeshRenderer>(); if ((Object)(object)textRenderer == (Object)null) { textRenderer = textObject.AddComponent<MeshRenderer>(); } if ((Object)(object)textMesh.font != (Object)null && (Object)(object)textMesh.font.material != (Object)null) { textMaterial = new Material(textMesh.font.material); } else { Shader val = Shader.Find("GUI/Text Shader"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Unlit/Transparent"); } if ((Object)(object)val == (Object)null) { val = Shader.Find("Sprites/Default"); } textMaterial = new Material(val); } ((Object)textMaterial).name = "ScrapVisibility_ReadableTextMaterial"; textMaterial.renderQueue = 3000; if (textMaterial.HasProperty("_Cull")) { textMaterial.SetInt("_Cull", 0); } if (textMaterial.HasProperty("_ZWrite")) { textMaterial.SetInt("_ZWrite", 0); } if (textMaterial.HasProperty("_Color")) { textMaterial.SetColor("_Color", Color.white); } if (textMaterial.HasProperty("_FaceColor")) { textMaterial.SetColor("_FaceColor", Color.white); } ((Renderer)textRenderer).sharedMaterial = textMaterial; ((Renderer)textRenderer).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)textRenderer).receiveShadows = false; } private void CreateApparatusLight() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0049: 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) if (!((Object)(object)lightObject != (Object)null)) { lightObject = new GameObject("ScrapVisibility_ApparatusStyleLight"); lightObject.transform.SetParent(((Component)this).transform, false); lightObject.transform.localPosition = Vector3.zero; glowLight = lightObject.AddComponent<Light>(); glowLight.type = (LightType)2; glowLight.color = Color.white; glowLight.intensity = 6f; glowLight.range = 6f; ((Behaviour)glowLight).enabled = false; glowLight.shadows = (LightShadows)2; glowLight.renderMode = (LightRenderMode)1; glowLight.cullingMask = -1; glowLight.bounceIntensity = 1.2f; } } private void LateUpdate() { //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)item == (Object)null) { DestroySelf(); return; } if ((Object)(object)item.itemProperties == (Object)null) { ClearGlow(); SetVisualsActive(active: false); return; } PlayerControllerB localPlayer = GetLocalPlayer(); if ((Object)(object)localPlayer == (Object)null || !localPlayer.isPlayerControlled || localPlayer.isPlayerDead) { ClearGlow(); SetVisualsActive(active: false); return; } if (IsHeldByAnyone(localPlayer)) { ClearGlow(); SetVisualsActive(active: false); return; } if (!((Component)item).gameObject.activeInHierarchy) { ClearGlow(); SetVisualsActive(active: false); return; } if (!TryGetBounds(out var bounds)) { ClearGlow(); SetVisualsActive(active: false); return; } float num = Vector3.Distance(((Component)localPlayer).transform.position, ((Bounds)(ref bounds)).center); if (_scrapVisibilityMaxDistance != null && num > _scrapVisibilityMaxDistance.Value) { ClearGlow(); SetVisualsActive(active: false); } else { UpdateVisuals(bounds, num); SetVisualsActive(active: true); } } private PlayerControllerB GetLocalPlayer() { if ((Object)(object)GameNetworkManager.Instance == (Object)null) { return null; } return GameNetworkManager.Instance.localPlayerController; } private bool IsHeldByAnyone(PlayerControllerB localPlayer) { if (GetBoolField(fieldIsHeld)) { return true; } if (GetBoolField(fieldIsPocketed)) { return true; } if (GetBoolField(fieldIsHeldByEnemy)) { return true; } if (GetObjectField(fieldPlayerHeldBy) != null) { return true; } if ((Object)(object)localPlayer != (Object)null) { object playerObjectField = GetPlayerObjectField(localPlayer, fieldCurrentlyHeldObjectServer); object playerObjectField2 = GetPlayerObjectField(localPlayer, fieldCurrentlyHeldObject); if (playerObjectField == item || playerObjectField2 == item) { return true; } } Transform parent = ((Component)item).transform.parent; if ((Object)(object)parent != (Object)null) { string text = ((Object)parent).name.ToLowerInvariant(); if (text.Contains("player") || text.Contains("hand") || text.Contains("hold") || text.Contains("itemholder") || text.Contains("pocket")) { return true; } } return false; } private bool GetBoolField(FieldInfo field) { if (field == null || (Object)(object)item == (Object)null) { return false; } object value = field.GetValue(item); bool flag = default(bool); int num; if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } private object GetObjectField(FieldInfo field) { if (field == null || (Object)(object)item == (Object)null) { return null; } return field.GetValue(item); } private object GetPlayerObjectField(PlayerControllerB player, FieldInfo field) { if (field == null || (Object)(object)player == (Object)null) { return null; } return field.GetValue(player); } private bool TryGetBounds(out Bounds bounds) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_0090: 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) bounds = new Bounds(((Component)this).transform.position, Vector3.one * 0.25f); bool flag = false; foreach (Renderer targetRenderer in targetRenderers) { if ((Object)(object)targetRenderer == (Object)null) { continue; } string lowerName = ((Object)((Component)targetRenderer).gameObject).name.ToLowerInvariant(); if (!ShouldSkipRenderer(targetRenderer, lowerName) && ((Component)targetRenderer).gameObject.activeInHierarchy) { if (!flag) { bounds = targetRenderer.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(targetRenderer.bounds); } } } return flag; } private void UpdateVisuals(Bounds bounds, float distance) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: 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_00f7: 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_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0119: 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_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_015f: 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) bool flag = (Object)(object)item.itemProperties != (Object)null && item.itemProperties.isScrap; int num = Mathf.Max(0, item.scrapValue); string text = "Item"; if ((Object)(object)item.itemProperties != (Object)null && !string.IsNullOrEmpty(item.itemProperties.itemName)) { text = item.itemProperties.itemName; } Color scrapDisplayColor = GetScrapDisplayColor(flag, num); if (ScrapIsRegisteredInsideCubeForVisuals(item)) { ((Color)(ref scrapDisplayColor))..ctor(1f, 0.03f, 0.02f, 1f); } float num2 = 0.78f + Mathf.Sin(Time.time * GetPulseSpeed()) * 0.22f; Color tintColor = Color.Lerp(Color.white, scrapDisplayColor, GetTintStrength()); tintColor.a = 1f; Color emissionColor = scrapDisplayColor * GetEmissionStrength() * num2; emissionColor.a = 1f; ApplyGlow(tintColor, emissionColor); if (num != lastValue || text != lastName || scrapDisplayColor != lastColor) { lastValue = num; lastName = text; lastColor = scrapDisplayColor; if ((Object)(object)textMesh != (Object)null) { if (flag) { textMesh.text = text + "\n$" + num; } else { textMesh.text = text; } } } UpdateApparatusLight(bounds, flag, num, scrapDisplayColor, num2); UpdateText(bounds, distance, scrapDisplayColor); } private void UpdateApparatusLight(Bounds bounds, bool isScrap, int value, Color color, float pulse) { //IL_0029: 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) if (!((Object)(object)glowLight == (Object)null)) { float lightMultiplierForItem = GetLightMultiplierForItem(isScrap, value); ((Component)glowLight).transform.position = ((Bounds)(ref bounds)).center; glowLight.color = color; glowLight.intensity = GetLightIntensity() * lightMultiplierForItem * pulse; glowLight.range = GetLightRange() * lightMultiplierForItem; glowLight.bounceIntensity = 1.5f + lightMultiplierForItem * 0.35f; } } private float GetLightMultiplierForItem(bool isScrap, int value) { if (!isScrap) { return 1.25f; } if (value >= 300) { return 2.25f; } if (value >= 150) { return 1.8f; } if (value >= 100) { return 1.45f; } if (value >= 50) { return 1.15f; } return 0.9f; } private void ApplyGlow(Color tintColor, Color emissionColor) { //IL_008e: 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_00a8: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown if (_showScrapModelGlow == null || !_showScrapModelGlow.Value) { ClearGlow(); return; } foreach (Renderer targetRenderer in targetRenderers) { if (!((Object)(object)targetRenderer == (Object)null)) { if (!blocks.TryGetValue(targetRenderer, out var value)) { value = new MaterialPropertyBlock(); blocks[targetRenderer] = value; } targetRenderer.GetPropertyBlock(value); value.SetColor("_Color", tintColor); value.SetColor("_BaseColor", tintColor); value.SetColor("_EmissionColor", emissionColor); value.SetColor("_EmissiveColor", emissionColor); targetRenderer.SetPropertyBlock(value); } } } private void ClearGlow() { foreach (Renderer targetRenderer in targetRenderers) { if (!((Object)(object)targetRenderer == (Object)null)) { targetRenderer.SetPropertyBlock((MaterialPropertyBlock)null); } } } private void UpdateText(Bounds bounds, float distance, Color color) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00dc: 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_0117: 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) if ((Object)(object)textObject == (Object)null || (Object)(object)textMesh == (Object)null) { return; } Transform scrapTextRoot = GetScrapTextRoot(); if ((Object)(object)textObject.transform.parent != (Object)(object)scrapTextRoot) { textObject.transform.SetParent(scrapTextRoot, true); } textObject.transform.position = GetStableLabelPosition(bounds); Camera main = Camera.main; if ((Object)(object)main != (Object)null) { textObject.transform.rotation = ((Component)main).transform.rotation; } textVisible = IsObjectVisibleForText(bounds); textMesh.characterSize = GetTextSize(); textObject.transform.localScale = Vector3.one; textMesh.color = color; if ((Object)(object)textMaterial != (Object)null) { if (textMaterial.HasProperty("_Color")) { textMaterial.SetColor("_Color", color); } if (textMaterial.HasProperty("_FaceColor")) { textMaterial.SetColor("_FaceColor", color); } } } private Vector3 GetStableLabelPosition(Bounds bounds) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) return ((Bounds)(ref bounds)).center + Vector3.up * (((Bounds)(ref bounds)).extents.y + GetTextHeightOffset()); } private Vector3 GetParentScaleCompensatedLocalScale(float desiredWorldScale) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_002e: 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_0075: Unknown result type (might be due to invalid IL or missing references) Transform val = (((Object)(object)textObject != (Object)null) ? textObject.transform.parent : null); if ((Object)(object)val == (Object)null) { return Vector3.one * desiredWorldScale; } Vector3 lossyScale = val.lossyScale; return new Vector3(desiredWorldScale / SafeSignedScale(lossyScale.x), desiredWorldScale / SafeSignedScale(lossyScale.y), desiredWorldScale / SafeSignedScale(lossyScale.z)); } private float SafeSignedScale(float value) { if (Mathf.Abs(value) < 0.001f) { return (value < 0f) ? (-0.001f) : 0.001f; } return value; } private bool IsObjectVisibleForText(Bounds bounds) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004b: 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_005a: 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_0062: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011d: 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) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012e: 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_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //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_015a: 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_0166: 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) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017f: 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_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: 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_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: 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) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) if (_hideScrapTextBehindWalls == null || !_hideScrapTextBehindWalls.Value) { return true; } Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return true; } Vector3 center = ((Bounds)(ref bounds)).center; Vector3 extents = ((Bounds)(ref bounds)).extents; Vector3[] array = (Vector3[])(object)new Vector3[15] { center, center + new Vector3(0f, extents.y, 0f), center - new Vector3(0f, extents.y, 0f), center + new Vector3(extents.x, 0f, 0f), center - new Vector3(extents.x, 0f, 0f), center + new Vector3(0f, 0f, extents.z), center - new Vector3(0f, 0f, extents.z), center + new Vector3(extents.x, extents.y, extents.z), center + new Vector3(0f - extents.x, extents.y, extents.z), center + new Vector3(extents.x, extents.y, 0f - extents.z), center + new Vector3(0f - extents.x, extents.y, 0f - extents.z), center + new Vector3(extents.x, 0f - extents.y, extents.z), center + new Vector3(0f - extents.x, 0f - extents.y, extents.z), center + new Vector3(extents.x, 0f - extents.y, 0f - extents.z), center + new Vector3(0f - extents.x, 0f - extents.y, 0f - extents.z) }; Vector3[] array2 = array; foreach (Vector3 point in array2) { if (PointIsOnScreenAndNotBlocked(main, point)) { lastGoodTextVisibleTime = Time.time; return true; } } float num = ((_scrapTextVisibilityGraceTime != null) ? Mathf.Max(0f, _scrapTextVisibilityGraceTime.Value) : 0.2f); return Time.time - lastGoodTextVisibleTime <= num; } private bool PointIsOnScreenAndNotBlocked(Camera cam, Vector3 point) { //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_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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_0056: 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_0080: 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_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_00ae: 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_00d9: 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_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) Vector3 val = cam.WorldToViewportPoint(point); if (val.z < 0f) { return false; } float num = ((_scrapScreenEdgeMargin != null) ? Mathf.Clamp(_scrapScreenEdgeMargin.Value, 0f, 0.35f) : 0.12f); if (val.x < 0f - num || val.x > 1f + num) { return false; } if (val.y < 0f - num || val.y > 1f + num) { return false; } Vector3 position = ((Component)cam).transform.position; Vector3 val2 = point - position; float magnitude = ((Vector3)(ref val2)).magnitude; if (magnitude <= 0.05f) { return true; } Vector3 normalized = ((Vector3)(ref val2)).normalized; position += normalized * 0.25f; float num2 = ((_scrapTextOcclusionPadding != null) ? Mathf.Clamp(_scrapTextOcclusionPadding.Value, 0.01f, 1f) : 0.12f); float num3 = Mathf.Max(0.05f, magnitude - num2); RaycastHit[] array = Physics.RaycastAll(position, normalized, num3, -1, (QueryTriggerInteraction)1); if (array == null || array.Length == 0) { return true; } Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); PlayerControllerB localPlayer = GetLocalPlayer(); RaycastHit[] array2 = array; for (int i = 0; i < array2.Length; i++) { RaycastHit val3 = array2[i]; if ((Object)(object)((RaycastHit)(ref val3)).collider == (Object)null) { continue; } Transform transform = ((Component)((RaycastHit)(ref val3)).collider).transform; if ((Object)(object)textObject != (Object)null && transform.IsChildOf(textObject.transform)) { continue; } if (transform.IsChildOf(((Component)item).transform)) { return true; } GrabbableObject componentInParent = ((Component)((RaycastHit)(ref val3)).collider).GetComponentInParent<GrabbableObject>(); if ((Object)(object)componentInParent == (Object)(object)item) { return true; } if ((!((Object)(object)localPlayer != (Object)null) || !transform.IsChildOf(((Component)localPlayer).transform)) && !((Object)(object)componentInParent != (Object)null)) { string text = ((Object)transform).name.ToLowerInvariant(); if (!text.Contains("player") && !text.Contains("camera") && !text.Contains("hand") && !text.Contains("itemholder") && !text.Contains("held") && !text.Contains("helmet") && !text.Contains("scan") && !text.Contains("trigger")) { return false; } } } return true; } private void SetVisualsActive(bool active) { bool flag = active && textVisible && _showScrapValueText != null && _showScrapValueText.Value; bool enabled = active && _showScrapLight != null && _showScrapLight.Value; if ((Object)(object)textObject != (Object)null && textObject.activeSelf != flag) { textObject.SetActive(flag); } if ((Object)(object)glowLight != (Object)null) { ((Behaviour)glowLight).enabled = enabled; } } private float GetTintStrength() { if (_scrapTintStrength == null) { return 1f; } return Mathf.Clamp01(_scrapTintStrength.Value); } private float GetEmissionStrength() { if (_scrapEmissionStrength == null) { return 5.5f; } return Mathf.Clamp(_scrapEmissionStrength.Value, 0f, 12f); } private float GetPulseSpeed() { if (_scrapPulseSpeed == null) { return 2.8f; } return Mathf.Max(0f, _scrapPulseSpeed.Value); } private float GetLightIntensity() { if (_scrapLightIntensity == null) { return 6f; } return Mathf.Clamp(_scrapLightIntensity.Value, 0f, 30f); } private float GetLightRange() { if (_scrapLightRange == null) { return 6f; } return Mathf.Clamp(_scrapLightRange.Value, 0f, 20f); } private float GetTextSize() { if (_scrapTextSize == null) { return 0.022f; } return Mathf.Clamp(_scrapTextSize.Value, 0.005f, 0.14f); } private float GetTextHeightOffset() { if (_scrapTextHeightOffset == null) { return 0.22f; } return Mathf.Clamp(_scrapTextHeightOffset.Value, 0f, 2f); } internal void DestroySelf() { ClearGlow(); if ((Object)(object)textObject != (Object)null) { Object.Destroy((Object)(object)textObject); textObject = null; } if ((Object)(object)lightObject != (Object)null) { Object.Destroy((Object)(object)lightObject); lightObject = null; } if ((Object)(object)textMaterial != (Object)null) { Object.Destroy((Object)(object)textMaterial); textMaterial = null; } Object.Destroy((Object)(object)this); } private void OnDestroy() { ClearGlow(); if ((Object)(object)textObject != (Object)null) { Object.Destroy((Object)(object)textObject); } if ((Object)(object)lightObject != (Object)null) { Object.Destroy((Object)(object)lightObject); } if ((Object)(object)textMaterial != (Object)null) { Object.Destroy((Object)(object)textMaterial); } } } [HarmonyPatch(typeof(EntranceTeleport), "StartOpeningEntrance")] private static class EntranceTeleport_StartOpeningEntrance_Patch { private static bool Prefix(EntranceTeleport __instance) { if (_disableFacilityExitInteractions == null || !_disableFacilityExitInteractions.Value) { return true; } ForceFacilityExitInteractionsDisabled(); D("Blocked facility entrance/fire-exit interaction: " + GetEntranceDebugName(__instance)); return false; } } [HarmonyPatch(typeof(EntranceTeleport), "TeleportPlayer")] private static class EntranceTeleport_TeleportPlayer_Patch { private static bool Prefix(EntranceTeleport __instance) { if (_disableFacilityExitInteractions == null || !_disableFacilityExitInteractions.Value) { return true; } ForceFacilityExitInteractionsDisabled(); D("Blocked facility entrance/fire-exit teleport: " + GetEntranceDebugName(__instance)); return false; } } [HarmonyPatch(typeof(StartOfRound), "OpenShipDoors")] private static class StartOfRound_OpenShipDoors_Patch { private static void Postfix() { if (_keepShipDoorsClosed != null && _keepShipDoorsClosed.Value && !IsAtTheCompany()) { ForceShipDoorsClosedNow(); D("OpenShipDoors ran normally. Extraction hides the moving vanilla ship door and keeps the closed-door overlay."); } } } [HarmonyPatch(typeof(StartOfRound), "openingDoorsSequence")] private static class StartOfRound_OpeningDoorsSequence_Patch { private static void Postfix() { if (_keepShipDoorsClosed != null && _keepShipDoorsClosed.Value && !IsAtTheCompany()) { ForceShipDoorsClosedNow(); D("openingDoorsSequence ran normally. Extraction hides the moving vanilla ship door and keeps the closed-door overlay."); } } } [HarmonyPatch(typeof(HangarShipDoor), "SetDoorOpen")] private static class HangarShipDoor_SetDoorOpen_Patch { private static void Postfix(HangarShipDoor __instance) { if (_keepShipDoorsClosed != null && _keepShipDoorsClosed.Value && !IsAtTheCompany()) { ForceShipDoorsClosedNow(); } } } [HarmonyPatch(typeof(HangarShipDoor), "PlayDoorAnimation")] private static class HangarShipDoor_PlayDoorAnimation_Patch { private static void Postfix(HangarShipDoor __instance) { if (_keepShipDoorsClosed != null && _keepShipDoorsClosed.Value && !IsAtTheCompany()) { ForceShipDoorsClosedNow(); } } } [HarmonyPatch(typeof(StartOfRound), "ShipLeave")] private static class StartOfRound_ShipLeave_Patch { private static void Prefix() { D("StartOfRound.ShipLeave prefix fired."); LocalShipLeavePrefix(); } } [HarmonyPatch(typeof(StartOfRound), "ShipHasLeft")] private static class StartOfRound_ShipHasLeft_Patch { private static void Postfix() { D("StartOfRound.ShipHasLeft postfix fired."); ApplyPendingQuotaValueOnHost("StartOfRound.ShipHasLeft postfix"); ResetRoundState(); } } [HarmonyPatch(typeof(HUDManager), "FillEndGameStats")] private static class HUDManager_FillEndGameStats_Patch { private static void Prefix() { D("HUDManager.FillEndGameStats prefix fired."); ApplyPendingQuotaValueOnHost("HUDManager.FillEndGameStats prefix"); } } [HarmonyPatch(typeof(RoundManager), "FinishGeneratingNewLevelClientRpc")] private static class RoundManager_FinishGeneratingNewLevelClientRpc_Patch { private static void Postfix() { NotifyPlayersFinishedGeneratingNewLevel(); } } [HarmonyPatch(typeof(TimeOfDay), "VoteShipToLeaveEarly")] private static class TimeOfDay_VoteShipToLeaveEarly_Patch { private static bool Prefix() { if (!BaseGameSpectatorVoteToLeaveDisabled()) { return true; } D("Blocked vanilla dead-spectator vote to leave early because DisableBaseGameSpectatorVoteToLeave is true."); if ((Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.DisplayTip("Vote to leave disabled", "The vanilla spectator vote to leave early is disabled by this mod.", false, false, "LC_Tip1"); } return false; } private static void Postfix() { if (!BaseGameSpectatorVoteToLeaveDisabled()) { ObserveBaseGameVoteToLeave("local vanilla VoteShipToLeaveEarly called"); } } } [HarmonyPatch(typeof(TimeOfDay), "SetShipLeaveEarlyServerRpc")] private static class TimeOfDay_SetShipLeaveEarlyServerRpc_Patch { private static bool Prefix() { if (!BaseGameSpectatorVoteToLeaveDisabled()) { return true; } D("Blocked vanilla SetShipLeaveEarlyServerRpc because DisableBaseGameSpectatorVoteToLeave is true."); return false; } } [HarmonyPatch(typeof(TimeOfDay), "AddVoteForShipToLeaveEarlyClientRpc")] private static class TimeOfDay_AddVoteForShipToLeaveEarlyClientRpc_Patch { private static void Postfix() { if (!BaseGameSpectatorVoteToLeaveDisabled()) { ObserveBaseGameVoteToLeave("vanilla AddVoteForShipToLeaveEarlyClientRpc fired"); } } } [HarmonyPatch(typeof(TimeOfDay), "SetShipLeaveEarlyClientRpc")] private static class TimeOfDay_SetShipLeaveEarlyClientRpc_Patch { private static void Postfix() { if (!BaseGameSpectatorVoteToLeaveDisabled()) { ObserveBaseGameVoteToLeave("vanilla SetShipLeaveEarlyClientRpc fired"); } } } [HarmonyPatch(typeof(HUDManager), "DisplaySpectatorVoteTip")] private static class HUDManager_DisplaySpectatorVoteTip_Patch { private static bool Prefix() { return !BaseGameSpectatorVoteToLeaveDisabled(); } } [HarmonyPatch(typeof(HUDManager), "AddPlayerChatMessageServerRpc")] private static class HUDManager_AddPlayerChatMessageServerRpc_Patch { private static bool Prefix(string chatMessage, int playerId) { try { if (!IsServer()) { return true; } return !HandleChatCommand(chatMessage, playerId); } catch (Exception arg) { Log.LogWarning((object)$"[Extraction] Chat command handler failed: {arg}"); return true; } } } [HarmonyPatch(typeof(HUDManager), "PingScan_performed")] private static class HUDManager_PingScan_performed_Patch { private static bool Prefix() { bool flag = ShouldBlockManualScanner(); if (flag) { D("Blocked manual right click scan because integrated scrap visibility is enabled."); } return !flag; } } [CompilerGenerated] private sealed class <ApplyRoundStartCubeTeleportLocalCoroutine>d__429 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public int token; public Vector3 position; public string source; private int <attempt>5__1; private PlayerControllerB <player>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ApplyRoundStartCubeTeleportLocalCoroutine>d__429(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <player>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_00ff: 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) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <attempt>5__1 = 0; goto IL_017b; case 1: <>1__state = -1; goto IL_007e; case 2: { <>1__state = -1; goto IL_007e; } IL_007e: if (_cubeExtractionPassed || ((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.shipIsLeaving)) { break; } <player>5__2 = StartOfRound.Instance?.localPlayerController; if (!((Object)(object)<player>5__2 == (Object)null) && <player>5__2.isPlayerControlled && !<player>5__2.isPlayerDead && !<player>5__2.disconnectedMidGame) { TeleportLocalPlayer(position, toShip: false); _localAppliedRoundStartCubeTeleportToken = token; _localPendingRoundStartCubeTeleportToken = -1; D($"Applied round-start cube teleport locally. token={token}, source={source}, attempt={<attempt>5__1 + 1}, pos={position}"); return false; } <attempt>5__1++; goto IL_017b; IL_017b: if (<attempt>5__1 < 28) { if (<attempt>5__1 > 0) { <>2__current = (object)new WaitForSeconds(0.25f); <>1__state = 1; return true; } <>2__current = null; <>1__state = 2; return true; } break; } if (_localPendingRoundStartCubeTeleportToken == token) { _localPendingRoundStartCubeTeleportToken = -1; } D($"Failed to apply round-start cube teleport locally before retry attempts ended. token={token}, source={source}"); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <ClientCubeVisualRefreshRoutine>d__419 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Vector3 center; private int <i>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ClientCubeVisualRefreshRoutine>d__419(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>1__state = -2; } private bool MoveNext() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) bool result; try { switch (<>1__state) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; _clientCubeVisualRefreshRunning = true; <>1__state = -3; <i>5__1 = 0; break; case 1: <>1__state = -3; if (_hasCube) { if ((Object)(object)_cubeVisual == (Object)null) { CreateOrMoveCubeVisual(center); } else { if (!_cubeVisual.activeSelf) { _cubeVisual.SetActive(true); } ForceCubeVisualVisible(); UpdateCubePulseVisual(force: true); } D($"Client forced Extraction Area visual visibility nudge {<i>5__1 + 1}/6. visualExists={(Object)(object)_cubeVisual != (Object)null}, active={(Object)(object)_cubeVisual != (Object)null && _cubeVisual.activeSelf}, dynamicReady={_cubeDynamicFootprintReady}, cells={_cubeDynamicFootprintCells.Count}"); <i>5__1++; break; } result = false; <>m__Finally1(); goto end_IL_0000; } if (<i>5__1 < 6) { <>2__current = (object)new WaitForSeconds(0.75f); <>1__state = 1; result = true; } else { <>m__Finally1(); result = false; } end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; _clientCubeVisualRefreshRunning = false; } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <EmptyCoroutine>d__398 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EmptyCoroutine>d__398(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { if (<>1__state != 0) { return false; } <>1__state = -1; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <KeepShipDoorsClosedWhileRunning>d__399 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public IEnumerator original; public string source; private bool <moveNext>5__1; private object <current>5__2; private Exception <ex>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <KeepShipDoorsClosedWhileRunning>d__399(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <current>5__2 = null; <ex>5__3 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (original == null) { return false; } break; case 1: <>1__state = -1; ForceShipDoorsClosedNow(); <current>5__2 = null; break; } try { <moveNext>5__1 = original.MoveNext(); <current>5__2 = (<moveNext>5__1 ? original.Current : null); } catch (Exception ex) { <ex>5__3 = ex; D("Ship door coroutine wrapper from " + source + " failed: " + <ex>5__3.Message); throw; } ForceShipDoorsClosedNow(); if (<moveNext>5__1) { <>2__current = <current>5__2; <>1__state = 1; return true; } ForceShipDoorsClosedNow(); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <MaintainLocalInsideFactoryStateCoroutine>d__453 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public float seconds; private float <end>5__1; private PlayerControllerB <player>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <MaintainLocalInsideFactoryStateCoroutine>d__453(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <player>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <end>5__1 = Time.realtimeSinceStartup + Mathf.Max(0.25f, seconds); break; case 1: <>1__state = -1; <player>5__2 = null; break; } if (Time.realtimeSinceStartup < <end>5__1) { <player>5__2 = StartOfRound.Instance?.localPlayerController; if ((Object)(object)<player>5__2 == (Object)null || <player>5__2.isPlayerDead || <player>5__2.disconnectedMidGame) { return false; } if ((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.shipIsLeaving) { return false; } ApplyPlayerInsideFactoryState(<player>5__2); <>2__current = (object)new WaitForSeconds(0.2f); <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <RoundStartFacilityTeleportRoutine>d__357 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string reason; private float <delay>5__1; private float <waitForLandingMax>5__2; private float <landingWaitStart>5__3; private int <token>5__4; private float <retrySeconds>5__5; private float <retryInterval>5__6; private float <endTime>5__7; private string <destination>5__8; private int <pass>5__9; private int <sent>5__10; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RoundStartFacilityTeleportRoutine>d__357(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <destination>5__8 = null; <>1__state = -2; } private bool MoveNext() { //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (!IsServer() || !_hasCube || (Object)(object)StartOfRound.Instance == (Object)null) { return false; } _roundStartTeleportRoutineRunning = true; <delay>5__1 = Mathf.Max(0f, (_roundStartTeleportDelay != null) ? _roundStartTeleportDelay.Value : 1.25f); if (<delay>5__1 > 0f) { <>2__current = (object)new WaitForSeconds(<delay>5__1); <>1__state = 1; return true; } <>2__current = null; <>1__state = 2; return true; case 1: <>1__state = -1; goto IL_00de; case 2: <>1__state = -1; goto IL_00de; case 3: <>1__state = -1; goto IL_017e; case 4: { <>1__state = -1; break; } IL_00de: <waitForLandingMax>5__2 = Mathf.Max(0f, (_roundStartTeleportWaitForLandingSeconds != null) ? _roundStartTeleportWaitForLandingSeconds.Value : 12f); <landingWaitStart>5__3 = Time.realtimeSinceStartup; goto IL_017e; IL_017e: if (!IsRoundStartFacilityTeleportMomentSafe()) { if (!(<waitForLandingMax>5__2 <= 0f) && !(Time.realtimeSinceStartup - <landingWaitStart>5__3 >= <waitForLandingMax>5__2)) { <>2__current = (object)new WaitForSeconds(0.25f); <>1__state = 3; return true; } D($"Round-start teleport landing wait expired after {<waitForLandingMax>5__2:0.0}s. Applying anyway."); } if (!IsServer() || !_hasCube || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.shipIsLeaving || _cubeExtractionPassed) { _roundStartTeleportRoutineRunning = false; return false; } _roundStartCubeTeleportToken++; <token>5__4 = _roundStartCubeTeleportToken; _roundStartTeleportTargetsByClient.Clear(); <retrySeconds>5__5 = Mathf.Max(2f, (_roundStartTeleportRetrySeconds != null) ? _roundStartTeleportRetrySeconds.Value : 12f); <retryInterval>5__6 = Mathf.Clamp((_roundStartTeleportRetryInterval != null) ? _roundStartTeleportRetryInterval.Value : 0.75f, 0.15f, 3f); <endTime>5__7 = Time.realtimeSinceStartup + <retrySeconds>5__5; _roundStartCubeTeleportWindowOpen = true; _roundStartCubeTeleportWindowEndTime = <endTime>5__7; <destination>5__8 = (RoundStartTeleportUsesCube() ? "the Extraction Area" : "random facility spot"); D($"Started token-safe round-start facility teleport token={<token>5__4}, destination={<destination>5__8}, reason={reason}, retrySeconds={<retrySeconds>5__5:0.0}, interval={<retryInterval>5__6:0.00}"); <pass>5__9 = 0; break; } if (Time.realtimeSinceStartup <= <endTime>5__7) { <pass>5__9++; if (IsServer() && _hasCube && !((Object)(object)StartOfRound.Instance == (Object)null) && !StartOfRound.Instance.shipIsLeaving && !_cubeExtractionPassed) { <sent>5__10 = TeleportAllControlledPlayersIntoFacilityOnHost(<token>5__4, reason, <pass>5__9); if (<pass>5__9 == 1 || <sent>5__10 > 0) { D($"Round-start teleport pass {<pass>5__9} sent/applied token={<token>5__4} to {<sent>5__10} living controlled player(s)."); } BroadcastCubePosition(); <>2__current = (object)new WaitForSeconds(<retryInterval>5__6); <>1__state = 4; return true; } } _roundStartCubeTeleportWindowOpen = false; _roundStartCubeTeleportWindowEndTime = 0f; _roundStartTeleportRoutineRunning = false; BroadcastCubePosition(); D($"Round-start facility teleport retry window closed. token={<token>5__4}"); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SpawnCubeAfterFrame>d__197 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SpawnCubeAfterFrame>d__197(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_014d: 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_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; _processedThisTakeoff = false; _cubeEffectiveHeightOverride = -1f; _cubeExtractionPassed = false; _earlyExtractionCountdownActive = false; _earlyExtractionCountdownEndTime = 0f; _earlyExtractionCountdownSecondsRemaining = 0; _earlyExtractionTriggered = false; ClearBaseGameSpectatorVoteToLeaveState("round cube spawn start", resetVanillaTimeOfDayFields: true); CaptureNormalShipLeaveAutomaticallyTime("round cube spawn start"); _earlyVoteEligible = false; _earlyVoteCount = 0; _earlyVoteRequired = 0; _localEarlyVoteSubmitted = false; _earlyVoteRosterKey = string.Empty; _earlyExtractionVotes.Clear(); _lastEarlyVoteSyncSignature = string.Empty; _currentCubeScrapRawValue = 0; _currentCubeScrapCount = 0; _roundStartCubeTeleportWindowOpen = false; _roundStartCubeTeleportWindowEndTime = 0f; _roundStartTeleportRequested = false; _roundStartTeleportFloorReady = false; _roundStartTeleportStarted = false; _roundStartTeleportRoutineRunning = false; _cubePostReadyPlacementFinalized = false; _roundStartTeleportRequestTime = 0f; _roundStartTeleportRequestReason = string.Empty; _roundStartTeleportTargetsByClient.Clear(); _lastInsideFactoryBestEffortTimeByClient.Clear(); _lastInsideAudioLightingBestEffortTimeByClient.Clear(); _cachedInteriorEntranceReachabilityAnchors.Clear(); _cachedInteriorEntranceReachabilityAnchorsFrame = -1; _localPendingRoundStartCubeTeleportToken = -1; _localAppliedRoundStartCubeTeleportToken = -1; if (IsServer()) { _cubeCenter = PickCubePosition(); _hasCube = true; D($"Host picked Extraction Area center: {_cubeCenter}"); CreateOrMoveCubeVisual(_cubeCenter); BroadcastCubePosition(); if (_teleportPlayersToCubeOnRoundStart.Value) { RequestRoundStartCubeTeleport("round start cube placed"); } } else { D("Client finished dungeon generation. Waiting for host cube sync."); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public const string ModGuid = "robert.lethalcompany.extraction"; public const string ModName = "Extraction"; public const string ModVersion = "0.2.37"; private const string MsgCubeSync = "Extraction_CubeSync_v1"; private const string MsgTeleport = "Extraction_Teleport_v1"; private const string MsgQuotaSync = "Extraction_QuotaSync_v1"; private const string MsgCubeClosed = "Extraction_CubeClosed_v1"; private const string MsgEarlyVoteRequest = "Extraction_EarlyVoteRequest_v1"; private const string MsgEarlyVoteSync = "Extraction_EarlyVoteSync_v1"; private const string MsgRoundStartCubeTeleport = "Extraction_RoundStartCubeTeleport_v1"; internal static Plugin Instance; internal static ManualLogSource Log; private static Harmony _harmony; private static ConfigEntry<bool> _debugLogging; private static ConfigEntry<bool> _enableDebugCommands; private static ConfigEntry<bool> _hostOnlyDebugCommands; private static ConfigEntry<float> _cubeSize; private static ConfigEntry<float> _cubeHeight; private static ConfigEntry<float> _cubeVisualAlpha; private static ConfigEntry<float> _groundSnapRayStartHeight; private static ConfigEntry<float> _groundSnapRayDistance; private static ConfigEntry<bool> _applyCompanyBuyingRate; private static ConfigEntry<bool> _requireAllControlledPlayersAlive; private static ConfigEntry<int> _minDistanceFromShip; private static ConfigEntry<float> _cubePlacementWallClearance; private static ConfigEntry<float> _cubePlacementFloorInset; private static ConfigEntry<float> _cubePlacementMaxFloorDrop; private static ConfigEntry<float> _cubePlacementSearchRadius; private static ConfigEntry<float> _cubePlacementSearchStep; private static ConfigEntry<int> _cubePlacementMaxCandidates; private static ConfigEntry<bool> _cubePlacementRejectDangerTriggers; private static ConfigEntry<bool> _cubePlacementRequireNavMesh; private static ConfigEntry<bool> _cubePlacementRequireReachablePathFromEntrance; private static ConfigEntry<bool> _cubePlacementRejectBackfaceGeometry; private static ConfigEntry<bool> _cubePlacementPreferScrapSpawnAnchors; private static ConfigEntry<bool> _cubePlacementUseEntrancesAndFireExitsOnly; private static ConfigEntry<bool> _adaptiveForcefieldBounds; private static ConfigEntry<bool> _adaptiveForcefieldDynamicFootprint; private static ConfigEntry<bool> _adaptiveForcefieldFreezeShapeAfterBuild; private static ConfigEntry<bool> _adaptiveForcefieldSimplifyMesh; private static ConfigEntry<float> _adaptiveForcefieldClearance; private static ConfigEntry<float> _adaptiveForcefieldMinimumSide; private static ConfigEntry<float> _adaptiveForcefieldFloorProbeStep; private static ConfigEntry<float> _adaptiveForcefieldBoundaryInset; private static ConfigEntry<bool> _showInsideCubeHud; private static ConfigEntry<bool> _showInsideCubeTips; private static ConfigEntry<bool> _teleportPlayersToCubeOnRoundStart; private static ConfigEntry<bool> _roundStartTeleportToCube; private static ConfigEntry<float> _roundStartTeleportDelay; private static ConfigEntry<float> _roundStartTeleportRetrySeconds; private static ConfigEntry<float> _roundStartTeleportRetryInterval; private static ConfigEntry<float> _roundStartTeleportMaxWaitForFloorReady; private static ConfigEntry<float> _roundStartTeleportMaintainInsideSeconds; private static ConfigEntry<float> _roundStartTeleportWaitForLandingSeconds; private static ConfigEntry<bool> _enableCubeLight; private static ConfigEntry<float> _cubeLightIntensity; private static ConfigEntry<float> _cubeLightRange; private static ConfigEntry<bool> _enableCubeScrapGlow; private static ConfigEntry<float> _cubeScrapGlowRefreshInterval; private static ConfigEntry<float> _cubeScrapGlowEmissionStrength; private static ConfigEntry<float> _cubeScrapGlowLightIntensity; private static ConfigEntry<float> _cubeScrapGlowLightRange; private static ConfigEntry<bool> _enableEarlyExtractionVote; private static ConfigEntry<KeyCode> _earlyExtractionVoteKey; private static ConfigEntry<float> _earlyExtractionVoteSyncInterval; private static ConfigEntry<float> _earlyExtractionCountdownSeconds; private static ConfigEntry<bool> _disableBaseGameSpectatorVoteToLeave; private static ConfigEntry<bool> _keepShipDoorsClosed; private static ConfigEntry<bool> _disableFacilityExitInteractions; private static ConfigEntry<bool> _enableScrapVisibility; private static ConfigEntry<bool> _disableManualRightClickScan; private static ConfigEntry<bool> _showScrapValueText; private static ConfigEntry<bool> _showScrapModelGlow; private static ConfigEntry<bool> _showScrapLight; private static ConfigEntry<bool> _hideScrapTextBehindWalls; private static ConfigEntry<float> _scrapVisibilityMaxDistance; private static ConfigEntry<float> _scrapVisibilityRefreshInterval; private static ConfigEntry<float> _scrapTextSize; private static ConfigEntry<float> _scrapTextHeightOffset; private static ConfigEntry<float> _scrapTintStrength; private static ConfigEntry<float> _scrapEmissionStrength; private static ConfigEntry<float> _scrapLightIntensity; private static ConfigEntry<float> _scrapLightRange; private static ConfigEntry<float> _scrapPulseSpeed; private static ConfigEntry<float> _scrapTextOcclusionPadding; private static ConfigEntry<float> _scrapScreenEdgeMargin; private static ConfigEntry<float> _scrapTextVisibilityGraceTime; private static GameObject _cubeVisual; private static string _cubeVisualMeshSignature = string.Empty; private static bool _clientCubeVisualRefreshRunning; private static GameObject _cubeLightObject; private static GameObject _shipDoorClosedOverlay; private static GameObject _shipDoorFallbackPanel; private static Material _shipDoorFallbackMaterial; private static bool _shipDoorOverlaySourceMissingLogged; private static readonly Dictionary<Renderer, bool> _shipDoorOriginalRendererStates = new Dictionary<Renderer, bool>(); private static readonly Dictionary<Component, ShipDoorAudioState> _shipDoorOriginalAudioStates = new Dictionary<Component, ShipDoorAudioState>(); private static readonly Dictionary<GrabbableObject, ScrapGlowState> _glowingCubeScrap = new Dictionary<GrabbableObject, ScrapGlowState>(); private static bool _localPlayerInsideCube; private static float _cubeScrapGlowTimer; private GUIStyle _insideCubeHudStyle; private static Vector3 _cubeCenter; private static Vector3 _cubeDimensions = new Vector3(6f, 6f, 6f); private static float _cubeEffectiveHeightOverride = -1f; private static bool _cubeDynamicFootprintReady; private static float _cubeDynamicFootprintCellSize = 0.75f; private static float _cubeDynamicFootprintBottomY; private static float _cubeDynamicFootprintHorizontalSize = 6f; private static float _cubeDynamicFootprintHeight = 6f; private static Bounds _cubeDynamicFootprintBounds; private static readonly HashSet<int> _cubeDynamicFootprintCells = new HashSet<int>(); private static bool _cubeDynamicFootprintLocked; private static Vector3 _cubeDynamicFootprintLockedCenter; private static float _cubeDynamicFootprintLockedSize; private static float _cubeDynamicFootprintLockedHeight; private static float _cubeDynamicFootprintLockedCellSize; private static Mesh _cubeDynamicFootprintSurfaceMesh; private static Mesh _cubeDynamicFootprintFrameMesh; private static Mesh _cubeDynamicFootprintBandMesh; private static bool _hasCube; private static bool _processedThisTakeoff; private static bool _messagesRegistered; private static bool _clientConnectCallbackRegistered; private static RoundManager _eventSubscribedRoundManager; private static bool _cubeExtractionPassed; private static float _cubeScrapValueTimer; private static int _currentCubeScrapRawValue; private static int _currentCubeScrapCount; private static int _pendingQuotaValue; private static int _pendingRawValue; private static int _pendingItemCount; private static bool _pendingQuotaApplied; private static Transform _scrapTextRoot; private static float _scrapVisibilityAttachTimer; private static readonly HashSet<int> _earlyExtractionVotes = new HashSet<int>(); private static bool _earlyVoteEligible; private static int _earlyVoteCount; private static int _earlyVoteRequired; private static bool _localEarlyVoteSubmitted; private static bool _earlyExtractionCountdownActive; private static float _earlyExtractionCountdownEndTime; private static int _earlyExtractionCountdownSecondsRemaining; private static bool _earlyExtractionTriggered; private static bool _baseGameVoteToLeaveUrgencyActive; private static bool _baseGameVoteToLeaveObserved; private static bool _normalShipLeaveAutomaticallyTimeCaptured; private static float _normalShipLeaveAutomaticallyTime = -1f; private static string _earlyVoteRosterKey = string.Empty; private static string _lastEarlyVoteSyncSignature = string.Empty; private static float _earlyVoteSyncTimer; private static bool _roundStartCubeTeleportWindowOpen; private static int _roundStartCubeTeleportToken; private static int _localAppliedRoundStartCubeTeleportToken = -1; private static int _localPendingRoundStartCubeTeleportToken = -1; private static float _roundStartCubeTeleportWindowEndTime; private static bool _roundStartTeleportRequested; private static bool _roundStartTeleportFloorReady; private static bool _roundStartTeleportStarted; private static float _roundStartTeleportRequestTime; private static string _roundStartTeleportRequestReason = string.Empty; private static bool _roundStartTeleportRoutineRunning; private static bool _cubePostReadyPlacementFinalized; private static readonly Dictionary<ulong, Vector3> _roundStartTeleportTargetsByClient = new Dictionary<ulong, Vector3>(); private static readonly Dictionary<ulong, float> _lastInsideFactoryBestEffortTimeByClient = new Dictionary<ulong, float>(); private static readonly Dictionary<ulong, float> _lastInsideAudioLightingBestEffortTimeByClient = new Dictionary<ulong, float>(); private static Type _audioReverbTriggerType; private static bool _audioReverbTriggerTypeSearched; private static readonly List<Vector3> _cachedInteriorEntranceReachabilityAnchors = new List<Vector3>(); private static int _cachedInteriorEntranceReachabilityAnchorsFrame = -1; private static bool _legacyInputFailureLogged; private static bool _inputSystemFailureLogged; private static bool _navMeshReflectionInitialized; private static bool _navMeshReflectionAvailable; private static bool _navMeshUnavailableLogged; private static Type _navMeshType; private static Type _navMeshHitType; private static MethodInfo _navMeshSamplePositionMethod; private static Type _navMeshPathType; private static MethodInfo _navMeshCalculatePathMethod; private static PropertyInfo _navMeshPathStatusProperty; private static bool _navMeshPathUnavailableLogged; private static bool _entrancePathUnavailableLogged; private static PropertyInfo _navMeshHitPositionProperty; private static FieldInfo _navMeshHitPositionField; private float _lateSyncTimer; private float _exitInteractionClampTimer; private void Awake() { //IL_0c17: Unknown result type (might be due to invalid IL or missing references) //IL_0c21: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; _debugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogging", true, "Write detailed Extraction logs to the BepInEx console/log file."); _enableDebugCommands = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableChatDebugCommands", true, "Enables chat commands: tpcube, endday, cubepos, countcube, extractionhelp."); _hostOnlyDebugCommands = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "HostOnlyDebugCommands", true, "Only the host can use debug commands."); _cubeSize = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubeSizeMeters", 6f, "Horizontal size of the Extraction Area in meters. This controls width and depth only."); _cubeHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubeHeightMeters", 6f, "Requested roof height of the Extraction Area in meters. The mod will try to place the area where this full height fits. If it cannot, it retries at 80% height steps."); _cubeVisualAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubeVisualAlpha", 0.1f, "Transparency of the Extraction Area visual. 0 is invisible. 1 is solid. Default is 0.1."); _groundSnapRayStartHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "GroundSnapRayStartHeight", 6f, "How far above the picked node to start the downward floor snap ray."); _groundSnapRayDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "GroundSnapRayDistance", 20f, "How far below the picked node to search for floor when placing the Extraction Area."); _minDistanceFromShip = ((BaseUnityPlugin)this).Config.Bind<int>("Cube", "MinimumDistanceFromShip", 25, "Try to place the Extraction Area at least this many meters from the ship/elevator transform."); _cubePlacementWallClearance = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubePlacementWallClearanceMeters", 2.5f, "Extra empty space required past the Extraction Area footprint when choosing a spawn position. Higher values keep the placement farther from walls and map edges."); _cubePlacementFloorInset = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubePlacementFloorSampleInsetMeters", 0.2f, "How far inside the Extraction Area edge the floor safety samples are checked. Smaller values are stricter near voids and ledges."); _cubePlacementMaxFloorDrop = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubePlacementMaxFloorDropMeters", 1.25f, "Maximum allowed drop from an inside AI node to the snapped floor. Prevents snapping the Extraction Area down into pits, lower catwalk kill boxes, or the void."); _cubePlacementSearchRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubePlacementSearchRadiusMeters", 12f, "How far around each inside AI node to search for a centered safe cube position."); _cubePlacementSearchStep = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubePlacementSearchStepMeters", 1.5f, "Grid step used while searching around an inside AI node for a safe cube position."); _cubePlacementMaxCandidates = ((BaseUnityPlugin)this).Config.Bind<int>("Cube", "CubePlacementMaxCandidates", 8000, "Maximum number of cube placement candidates to test before using the safest emergency fallback."); _cubePlacementRejectDangerTriggers = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "CubePlacementRejectDangerTriggers", true, "Reject cube positions overlapping kill boxes, death triggers, out-of-bounds triggers, pits, or other dangerous trigger volumes."); _cubePlacementRequireNavMesh = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "CubePlacementRequireNavMesh", true, "Require the Extraction Area teleport spot to be close to the facility navmesh when Unity exposes it. This helps prevent out-of-map or unreachable placements."); _cubePlacementRequireReachablePathFromEntrance = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "CubePlacementRequireReachablePathFromEntrance", true, "Require the Extraction Area center/player spawn spot to have a complete NavMesh path from an interior entrance. This is the main guard against inaccessible prefab corners, voids, and out-of-map rooms."); _cubePlacementRejectBackfaceGeometry = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "CubePlacementRejectBackfaceGeometry", true, "Reject spots where physics rays detect the player is on the back side of one-sided level geometry. This catches many out-of-bounds/backside-wall cases."); _cubePlacementPreferScrapSpawnAnchors = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "CubePlacementPreferScrapSpawnAnchors", true, "Legacy fallback only. Ignored when CubePlacementUseEntrancesAndFireExitsOnly is true."); _cubePlacementUseEntrancesAndFireExitsOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "CubePlacementUseEntrancesAndFireExitsOnly", true, "If true, the Extraction Area only spawns at the real underground/interior side of main entrances and fire exits. This avoids slow wide-area searches, surface door spawns, and unreachable prefab corners."); _adaptiveForcefieldBounds = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "AdaptiveForcefieldBounds", true, "If true, the Extraction Area forcefield uses adaptive environment shaping instead of clipping through walls, ledges, pits, and non-navmesh space. Props are ignored."); _adaptiveForcefieldDynamicFootprint = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "AdaptiveForcefieldDynamicFootprint", true, "If true, the Extraction Area uses a connected navmesh footprint that can form L shapes and wrap around invalid walkable space instead of only resizing as a box."); _adaptiveForcefieldFreezeShapeAfterBuild = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "AdaptiveForcefieldFreezeShapeAfterBuild", true, "If true, the Extraction Area calculates its dynamic footprint once when spawned, then never recalculates it until the Extraction Area is moved for a new round."); _adaptiveForcefieldSimplifyMesh = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "AdaptiveForcefieldSimplifyMesh", true, "If true, merges dynamic forcefield cell slices into long faces and main corners after the footprint is finalized."); _adaptiveForcefieldClearance = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "AdaptiveForcefieldClearanceMeters", 0.18f, "Gap kept between the forcefield wall and nearby level geometry or ceiling when adaptive bounds are enabled."); _adaptiveForcefieldMinimumSide = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "AdaptiveForcefieldMinimumSideMeters", 1.25f, "Smallest horizontal side the Extraction Area forcefield may shrink to when adaptive bounds are enabled."); _adaptiveForcefieldFloorProbeStep = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "AdaptiveForcefieldFloorProbeStepMeters", 0.45f, "Step size used to stop the adaptive Extraction Area bounds before non-navmesh cells, floor gaps, pits, or unsupported catwalk edges."); _adaptiveForcefieldBoundaryInset = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "AdaptiveForcefieldBoundaryInsetMeters", 0f, "Deprecated. Boundary inset is ignored and kept at 0 so the forcefield footprint is not artificially shrunken."); if (_adaptiveForcefieldBoundaryInset != null && _adaptiveForcefieldBoundaryInset.Value > 0f) { _adaptiveForcefieldBoundaryInset.Value = 0f; } _showInsideCubeHud = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "ShowInsideCubeHud", true, "Show an on-screen message while your local player is inside the Extraction Area."); _showInsideCubeTips = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "ShowInsideCubeEnterExitTips", true, "Legacy config. No longer used because cube detection now only updates the HUD overlay."); _teleportPlayersToCubeOnRoundStart = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "TeleportPlayersToCubeOnRoundStart", true, "Master toggle for round-start facility teleport. If false, players stay wherever vanilla puts them."); _roundStartTeleportToCube = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "RoundStartTeleportToCube", true, "If true, round-start teleport sends players to the Extraction Area. If false, players are sent to a random safe facility position and must find the Extraction Area."); _roundStartTeleportDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "RoundStartCubeTeleportDelaySeconds", 1.25f, "Delay after the game reports players finished generating the floor before the teleport routine begins."); _roundStartTeleportRetrySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "RoundStartCubeTeleportRetrySeconds", 12f, "How long the host keeps resending the same round-start teleport token. Clients only apply that token once."); _roundStartTeleportRetryInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "RoundStartCubeTeleportRetryIntervalSeconds", 0.75f, "How often the host resends the same round-start teleport token during the retry window."); _roundStartTeleportMaxWaitForFloorReady = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "RoundStartCubeTeleportMaxWaitForFloorReadySeconds", 45f, "Fallback only. If the game never fires the fully-ready level callback, start round-start facility teleport after this many seconds."); _roundStartTeleportMaintainInsideSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "RoundStartMaintainInsideStateSeconds", 8f, "After round-start teleport, keep reapplying inside-factory player flags for this long to stop vanilla from snapping players back to ship state."); _roundStartTeleportWaitForLandingSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "RoundStartWaitForLandingMaxSeconds", 12f, "Maximum extra time to wait for the ship/round start state before applying the facility teleport."); _enableCubeLight = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableCubeLight", true, "Adds a yellow point light inside the Extraction Area."); _cubeLightIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CubeLightIntensity", 2.2f, "Point light intensity for the Extraction Area."); _cubeLightRange = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CubeLightRange", 7.5f, "Point light range for the Extraction Area."); _enableCubeScrapGlow = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableCubeScrapGlow", true, "Loose scrap currently inside the Extraction Area glows red. This is visual only."); _cubeScrapGlowRefreshInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CubeScrapGlowRefreshInterval", 0.15f, "How often to refresh red glow state for scrap inside the Extraction Area."); _cubeScrapGlowEmissionStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CubeScrapGlowEmissionStrength", 4f, "Red emission strength used on scrap that is inside the Extraction Area."); _cubeScrapGlowLightIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CubeScrapGlowLightIntensity", 1.25f, "Small red point light intensity on scrap that is inside the Extraction Area. Set to 0 to disable item lights."); _cubeScrapGlowLightRange = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CubeScrapGlowLightRange", 2.25f, "Small red point light range on scrap that is inside the Extraction Area."); _enableEarlyExtractionVote = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "EnableEarlyExtractionVote", true, "If true, all living players can vote from inside the Extraction Area to extract early."); _earlyExtractionVoteKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Rules", "EarlyExtractionVoteKey", (KeyCode)114, "Key used to vote for early extraction while all living players are inside the Extraction Area."); _earlyExtractionVoteSyncInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "EarlyExtractionVoteSyncInterval", 0.2f, "How often the host refreshes the early extraction vote HUD state while eligible."); _earlyExtractionCountdownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "EarlyExtractionCountdownSeconds", 10f, "Seconds to wait after all required Extraction Area votes are in before early extraction starts. If anyone leaves the Extraction Area during this countdown, voting resets."); _disableBaseGameSpectatorVoteToLeave = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "DisableBaseGameSpectatorVoteToLeave", false, "If true, blocks the vanilla dead-spectator vote to leave early. This does not affect the Extraction Area early extraction vote."); _keepShipDoorsClosed = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "KeepShipDoorsClosed", true, "If true, players see and collide with a closed ship door overlay and the door buttons are disabled. Vanilla door coroutines are allowed to run so level loading does not get stuck."); _disableFacilityExitInteractions = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "DisableFacilityExitInteractions", true, "If true, main entrances and fire exits cannot be used and their interact prompts are hidden. Players must leave through the Extraction Area."); if (Mathf.Approximately(_cubeSize.Value, 3f)) { _cubeSize.Value = 6f; } if (Mathf.Approximately(_cubeVisualAlpha.Value, 0.5f)) { _cubeVisualAlpha.Value = 0.1f; } if (Mathf.Approximately(_cubePlacementWallClearance.Value, 0.65f) || Mathf.Approximately(_cubePlacementWallClearance.Value, 1.75f)) { _cubePlacementWallClearance.Value = 2.5f; } if (Mathf.Approximately(_cubePlacementFloorInset.Value, 0.45f)) { _cubePlacementFloorInset.Value = 0.2f; } if (_cubePlacementMaxCandidates.Value == 4500) { _cubePlacementMaxCandidates.Value = 8000; } if (Mathf.Approximately(_cubePlacementSearchRadius.Value, 9f)) { _cubePlacementSearchRadius.Value = 12f; } if (Mathf.Approximately(_roundStartTeleportDelay.Value, 2.5f) || Mathf.Approximately(_roundStartTeleportDelay.Value, 0.75f)) { _roundStartTeleportDelay.Value = 1.25f; } if (Mathf.Approximately(_roundStartTeleportRetrySeconds.Value, 0f) || Mathf.Approximately(_roundStartTeleportRetrySeconds.Value, 16f) || Mathf.Approximately(_roundStartTeleportRetrySeconds.Value, 28f)) { _roundStartTeleportRetrySeconds.Value = 12f; } if (Mathf.Approximately(_roundStartTeleportRetryInterval.Value, 0f) || Mathf.Approximately(_roundStartTeleportRetryInterval.Value, 1f)) { _roundStartTeleportRetryInterval.Value = 0.75f; } _enableScrapVisibility = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable integrated scrap visibility", true, "If true, the Extraction Area uses the original ScrapVisibility highlighter code inside this plugin. This includes tools/non-scrap items."); _disableManualRightClickScan = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Disable manual right click scan", true, "If true, normal right click scan is blocked."); _showScrapModelGlow = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "Show model glow", true, "Tints the real item model."); _showScrapValueText = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "Show 3D text", true, "Show item name and value above scrap, and item names above tools/non-scrap items."); _showScrapLight = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "Show apparatus style light", true, "Adds a real 3D point light to items."); _hideScrapTextBehindWalls = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "Hide text behind walls", true, "If true, text label hides when the item itself is blocked by walls."); _scrapVisibilityMaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Visibility", "Max display distance", 120f, "Maximum distance for item highlights and labels."); _scrapVisibilityRefreshInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "Refresh interval", 1f, "How often the mod searches for items."); _scrapTintStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Tint strength", 1f, "How strongly the model gets tinted."); _scrapEmissionStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Emission strength", 5.5f, "How strongly the material emission is pushed."); _scrapTextSize = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Text size", 0.022f, "Base size of the 3D text above items."); _scrapTextHeightOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Text height offset", 0.38f, "How far above the item the text floats."); _scrapLightIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Light intensity", 6f, "Base brightness of the apparatus style light."); _scrapLightRange = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Light range", 6f, "Base range of the apparatus style light."); _scrapPulseSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Pulse speed", 2.8f, "How fast the glow pulses."); _scrapTextOcclusionPadding = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Text occlusion padding", 0.12f, "How much of the end of the ray to ignore when checking if the item is blocked."); _scrapScreenEdgeMargin = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Screen edge margin", 0.12f, "Extra margin around the screen so text still shows near the edge/peripheral view."); _scrapTextVisibilityGraceTime = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Text visibility grace time", 0.2f, "How long text stays visible after one bad raycast. Helps stop flicker while moving."); _applyCompanyBuyingRate = ((BaseUnityPlugin)this).Config.Bind<bool>("Payout", "ApplyCompanyBuyingRate", false, "If true, cube scrap payout is multiplied by the current company buying rate. If false, full scrap value goes toward quota."); _requireAllControlledPlayersAlive = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "RequireAllControlledPlayersAlive", false, "If true, extraction and Extraction Area payout only work when every controlled connected player is alive. If false, Extraction Area payout works as long as at least one controlled player is alive."); _harmony = new Harmony("robert.lethalcompany.extraction"); _harmony.PatchAll(); D("Plugin loaded. Harmony patches applied."); } private void Update() { EnsureMessageHandlers(); EnsureRoundManagerEventSubscription(); UpdateInsideCubeHudState(); UpdateCubeScrapValueCacheLoop(); UpdateEarlyExtractionVoteSystem(); HandleEarlyExtractionVoteInput(); UpdateQueuedRoundStartCubeTeleportFallback(); UpdateBaseGameVoteToLeaveUrgencyState(); UpdateShipDoorsLockedClosed(); UpdateFacilityExitInteractionsLocked(); UpdateCubePulseVisual(); UpdateScrapVisibilityLoop(); if (_enableScrapVisibility == null || !_enableScrapVisibility.Value) { UpdateCubeScrapGlowLoop(); } else if (_glowingCubeScrap.Count > 0) { ClearAllCubeScrapGlow(); } if (IsServer() && _hasCube && (Object)(object)NetworkManager.Singleton != (Object)null) { _lateSyncTimer += Time.deltaTime; if (_lateSyncTimer >= 5f) { _lateSyncTimer = 0f; BroadcastCubePosition(); } } } private void OnGUI() { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result typ
plugins/Extraction/RandomSuit.dll
Decompiled 19 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Unity.Netcode; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ScrapVisbility")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ScrapVisbility")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("8a6853bd-bdc9-4741-95c7-5aa2c8c6a6f9")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace YourFurnace.RandomStartSuit; [BepInPlugin("YourFurnace.RandomStartSuit", "RandomStartSuit", "1.1.0")] public class Plugin : BaseUnityPlugin { private sealed class Assignment { public ulong ClientId; public int PlayerIndex; public int SuitId; public string SuitName; public float ResendUntil; public float NextResend; } private sealed class SuitChoice { public int SuitId; public string SuitName; public object UnlockableItem; } [CompilerGenerated] private sealed class <GetAllPlayerScripts>d__38 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; private int <>l__initialThreadId; private object startOfRound; public object <>3__startOfRound; private object <playersObject>5__1; private IEnumerable <players>5__2; private IEnumerator <>s__3; private object <player>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <GetAllPlayerScripts>d__38(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <playersObject>5__1 = null; <players>5__2 = null; <>s__3 = null; <player>5__4 = null; <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -3; goto IL_00de; } <>1__state = -1; if (startOfRound == null) { return false; } <playersObject>5__1 = GetMemberValue(startOfRound, startOfRound.GetType(), "allPlayerScripts"); <players>5__2 = <playersObject>5__1 as IEnumerable; if (<players>5__2 == null) { return false; } <>s__3 = <players>5__2.GetEnumerator(); <>1__state = -3; goto IL_00e6; IL_00de: <player>5__4 = null; goto IL_00e6; IL_00e6: if (<>s__3.MoveNext()) { <player>5__4 = <>s__3.Current; if (<player>5__4 != null) { <>2__current = <player>5__4; <>1__state = 1; return true; } goto IL_00de; } <>m__Finally1(); <>s__3 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>s__3 is IDisposable disposable) { disposable.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<object> IEnumerable<object>.GetEnumerator() { <GetAllPlayerScripts>d__38 <GetAllPlayerScripts>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <GetAllPlayerScripts>d__ = this; } else { <GetAllPlayerScripts>d__ = new <GetAllPlayerScripts>d__38(0); } <GetAllPlayerScripts>d__.startOfRound = <>3__startOfRound; return <GetAllPlayerScripts>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<object>)this).GetEnumerator(); } } private const string PluginGuid = "YourFurnace.RandomStartSuit"; private const string PluginName = "RandomStartSuit"; private const string PluginVersion = "1.1.0"; private static ManualLogSource Log; private static readonly BindingFlags Flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private readonly Dictionary<ulong, Assignment> assignmentsByClientId = new Dictionary<ulong, Assignment>(); private ConfigEntry<string> allowedSuitsCsv; private ConfigEntry<float> firstAssignmentDelay; private ConfigEntry<float> rescanInterval; private ConfigEntry<float> serverResendSeconds; private ConfigEntry<float> serverResendInterval; private ConfigEntry<bool> onlyAssignInShipLobby; private ConfigEntry<bool> useUnlockableSuitRpcFirst; private ConfigEntry<bool> useStartOfRoundRpcFallback; private ConfigEntry<bool> setPlayerSuitFieldsAsBackup; private ConfigEntry<bool> logDebug; private Random rng; private int currentStartOfRoundId; private float nextScanTime; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; rng = new Random(); allowedSuitsCsv = ((BaseUnityPlugin)this).Config.Bind<string>("Suit Selection", "Allowed suit names", "FemaleBlue,FemaleClothed,FemaleLime,FemaleOrange,FemalePink,FemaleStar,RealMan", "Comma separated exact unlockable names. FemaleBlue will NOT match FemaleBlueOpen. FemaleStar will NOT match FemaleStarOpen."); firstAssignmentDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Assignment", "First assignment delay seconds", 3f, "How long to wait after StartOfRound exists before assigning suits."); rescanInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Assignment", "Rescan interval seconds", 2f, "How often the host checks for players without assigned suits."); serverResendSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Assignment", "Server resend seconds", 12f, "How long the host keeps reapplying the picked suit. This fights vanilla or other mods setting default suit after spawn."); serverResendInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Assignment", "Server resend interval seconds", 1f, "How often the host reapplies during the resend window."); onlyAssignInShipLobby = ((BaseUnityPlugin)this).Config.Bind<bool>("Assignment", "Only assign while in ship lobby", true, "Recommended true. Stops suit changing after landing."); useUnlockableSuitRpcFirst = ((BaseUnityPlugin)this).Config.Bind<bool>("Apply", "Use UnlockableSuit RPC first", true, "Recommended true. This matches the original working approach. It calls SwitchSuitClientRpc on the matching UnlockableSuit object by suit ID."); useStartOfRoundRpcFallback = ((BaseUnityPlugin)this).Config.Bind<bool>("Apply", "Use StartOfRound RPC fallback", true, "Uses StartOfRound suit switching only if the UnlockableSuit object method cannot be found."); setPlayerSuitFieldsAsBackup = ((BaseUnityPlugin)this).Config.Bind<bool>("Apply", "Set player suit fields as backup", false, "Leave false unless the suit still does not show. Direct fields can fight Netcode if done too early."); logDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Log debug info", true, "Logs parsed whitelist, allowed exact unlockable matches, chosen suit, and apply method calls."); SceneManager.sceneLoaded += OnSceneLoaded; ((BaseUnityPlugin)this).Logger.LogInfo((object)"RandomStartSuit 1.1.0 loaded. Exact comma whitelist. UnlockablesList based. No suit rack required."); } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (IsMenuScene(((Scene)(ref scene)).name)) { assignmentsByClientId.Clear(); currentStartOfRoundId = 0; } nextScanTime = Time.realtimeSinceStartup + Mathf.Max(0.1f, firstAssignmentDelay.Value); } private void Update() { try { if (!IsHostOrServer()) { return; } object startOfRound = GetStartOfRound(); if (startOfRound == null) { return; } int instanceId = GetInstanceId(startOfRound); if (instanceId != currentStartOfRoundId) { currentStartOfRoundId = instanceId; assignmentsByClientId.Clear(); nextScanTime = Time.realtimeSinceStartup + Mathf.Max(0.1f, firstAssignmentDelay.Value); DebugLog("New StartOfRound detected. Assignment state cleared."); } else if (IsSafeAssignTime(startOfRound)) { if (Time.realtimeSinceStartup >= nextScanTime) { nextScanTime = Time.realtimeSinceStartup + Mathf.Max(0.25f, rescanInterval.Value); AssignMissingPlayers(startOfRound); } ResendAssignments(startOfRound); } } catch (Exception ex) { Log.LogWarning((object)("RandomStartSuit update failed safely: " + ShortException(ex))); } } private void AssignMissingPlayers(object startOfRound) { List<SuitChoice> allowedSuitsFromUnlockables = GetAllowedSuitsFromUnlockables(startOfRound); if (allowedSuitsFromUnlockables.Count == 0) { Log.LogWarning((object)"No allowed exact suit names were found in StartOfRound.unlockablesList."); Log.LogWarning((object)("Raw config value: " + allowedSuitsCsv.Value)); LogAvailableSuitLikeUnlockables(startOfRound); return; } foreach (object allPlayerScript in GetAllPlayerScripts(startOfRound)) { if (IsRealPlayer(allPlayerScript)) { ulong playerClientId = GetPlayerClientId(allPlayerScript); int playerIndex = GetPlayerIndex(startOfRound, allPlayerScript); if (playerIndex >= 0 && !assignmentsByClientId.ContainsKey(playerClientId)) { SuitChoice suitChoice = allowedSuitsFromUnlockables[rng.Next(allowedSuitsFromUnlockables.Count)]; Assignment assignment = new Assignment { ClientId = playerClientId, PlayerIndex = playerIndex, SuitId = suitChoice.SuitId, SuitName = suitChoice.SuitName, ResendUntil = Time.realtimeSinceStartup + Mathf.Max(0f, serverResendSeconds.Value), NextResend = 0f }; assignmentsByClientId[playerClientId] = assignment; Log.LogInfo((object)("Assigned " + PlayerLabel(allPlayerScript) + " playerIndex=" + playerIndex + " clientId=" + playerClientId + " exactSuit=" + suitChoice.SuitName + " suitID=" + suitChoice.SuitId)); ApplyAssignment(startOfRound, assignment, "initial"); } } } } private void ResendAssignments(object startOfRound) { float realtimeSinceStartup = Time.realtimeSinceStartup; float num = Mathf.Max(0.25f, serverResendInterval.Value); foreach (Assignment item in assignmentsByClientId.Values.ToList()) { if (!(realtimeSinceStartup > item.ResendUntil) && !(realtimeSinceStartup < item.NextResend)) { item.NextResend = realtimeSinceStartup + num; ApplyAssignment(startOfRound, item, "resend"); } } } private void ApplyAssignment(object startOfRound, Assignment assignment, string reason) { if (startOfRound == null || assignment == null) { return; } object obj = FindPlayerByClientIdOrIndex(startOfRound, assignment.ClientId, assignment.PlayerIndex); bool flag = false; if (useUnlockableSuitRpcFirst.Value) { object obj2 = FindUnlockableSuitObjectById(assignment.SuitId); if (obj2 != null) { flag |= InvokeSuitMethod(obj2, "SwitchSuitClientRpc", assignment.PlayerIndex, assignment.SuitId, obj); flag |= InvokeSuitMethod(obj2, "SwitchSuitServerRpc", assignment.PlayerIndex, assignment.SuitId, obj); flag |= InvokeSuitMethod(obj2, "SwitchSuitToThis", assignment.PlayerIndex, assignment.SuitId, obj); } else { DebugLog("No UnlockableSuit component object found for suitID=" + assignment.SuitId + " " + assignment.SuitName); } } if (!flag && useStartOfRoundRpcFallback.Value) { flag |= InvokeSuitMethod(startOfRound, "SwitchSuitClientRpc", assignment.PlayerIndex, assignment.SuitId, obj); flag |= InvokeSuitMethod(startOfRound, "SwitchSuitServerRpc", assignment.PlayerIndex, assignment.SuitId, obj); flag |= InvokeSuitMethod(startOfRound, "SwitchSuitForPlayer", assignment.PlayerIndex, assignment.SuitId, obj); } if (setPlayerSuitFieldsAsBackup.Value && obj != null) { SetPlayerSuitFields(obj, assignment.SuitId); } DebugLog("Apply " + reason + " playerIndex=" + assignment.PlayerIndex + " clientId=" + assignment.ClientId + " suit=" + assignment.SuitName + " id=" + assignment.SuitId + " applied=" + flag); } private List<SuitChoice> GetAllowedSuitsFromUnlockables(object startOfRound) { HashSet<string> hashSet = ParseWhitelist(allowedSuitsCsv.Value); bool flag = hashSet.Contains("all"); DebugLog("Raw whitelist config: " + allowedSuitsCsv.Value); DebugLog("Parsed whitelist tokens: " + string.Join(", ", hashSet.ToArray())); List<SuitChoice> list = new List<SuitChoice>(); IList unlockablesList = GetUnlockablesList(startOfRound); if (unlockablesList == null) { Log.LogWarning((object)"Could not read StartOfRound.unlockablesList.unlockables."); return list; } for (int i = 0; i < unlockablesList.Count; i++) { object obj = unlockablesList[i]; if (obj == null) { continue; } string unlockableName = GetUnlockableName(obj); if (!string.IsNullOrWhiteSpace(unlockableName)) { string item = Normalize(unlockableName); if (flag || hashSet.Contains(item)) { list.Add(new SuitChoice { SuitId = i, SuitName = unlockableName, UnlockableItem = obj }); } } } if (list.Count > 0) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("Allowed exact unlockable matches: "); foreach (SuitChoice item2 in list) { stringBuilder.Append("[").Append(item2.SuitName).Append(" id=") .Append(item2.SuitId) .Append("] "); } Log.LogInfo((object)stringBuilder.ToString()); } return list; } private static HashSet<string> ParseWhitelist(string csv) { HashSet<string> hashSet = new HashSet<string>(); if (string.IsNullOrWhiteSpace(csv)) { return hashSet; } string[] array = csv.Split(new char[6] { ',', ';', '|', '\n', '\r', '\t' }, StringSplitOptions.RemoveEmptyEntries); string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim().Trim(new char[1] { '"' }).Trim(new char[1] { '\'' }); string text3 = Normalize(text2); if (!string.IsNullOrWhiteSpace(text3)) { hashSet.Add(text3); } } return hashSet; } private void LogAvailableSuitLikeUnlockables(object startOfRound) { IList unlockablesList = GetUnlockablesList(startOfRound); if (unlockablesList == null) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("Available suit-like unlockables: "); for (int i = 0; i < unlockablesList.Count; i++) { object obj = unlockablesList[i]; if (obj == null) { continue; } string unlockableName = GetUnlockableName(obj); if (!string.IsNullOrWhiteSpace(unlockableName)) { string text = unlockableName.ToLowerInvariant(); if (text.Contains("female") || text.Contains("suit") || text.Contains("realman")) { stringBuilder.Append("[").Append(unlockableName).Append(" id=") .Append(i) .Append("] "); } } } Log.LogWarning((object)stringBuilder.ToString()); } private static IList GetUnlockablesList(object startOfRound) { if (startOfRound == null) { return null; } object memberValue = GetMemberValue(startOfRound, startOfRound.GetType(), "unlockablesList"); if (memberValue == null) { return null; } object memberValue2 = GetMemberValue(memberValue, memberValue.GetType(), "unlockables"); return memberValue2 as IList; } private static string GetUnlockableName(object unlockable) { if (unlockable == null) { return null; } return GetMemberValue(unlockable, unlockable.GetType(), "unlockableName")?.ToString(); } private static object FindUnlockableSuitObjectById(int suitId) { Component[] array = Resources.FindObjectsOfTypeAll<Component>(); Component[] array2 = array; foreach (Component val in array2) { if ((Object)(object)val == (Object)null) { continue; } Type type = ((object)val).GetType(); if (IsUnlockableSuitType(type)) { int intMember = GetIntMember(val, type, "suitID", -1); if (intMember == suitId) { return val; } } } return null; } private bool InvokeSuitMethod(object target, string methodName, int playerIndex, int suitId, object player) { if (target == null) { return false; } Type type = target.GetType(); MethodInfo[] methods = type.GetMethods(Flags); bool result = false; MethodInfo[] array = methods; foreach (MethodInfo methodInfo in array) { if (!(methodInfo.Name != methodName) && TryBuildMethodArgs(methodInfo, playerIndex, suitId, player, out var args)) { try { methodInfo.Invoke(target, args); result = true; DebugLog("Called " + type.FullName + "." + methodInfo.Name + "(" + ArgsToString(args) + ") for suitID=" + suitId); } catch (Exception ex) { DebugLog("Call failed " + type.FullName + "." + methodInfo.Name + ": " + ShortException(ex)); } } } return result; } private static bool TryBuildMethodArgs(MethodInfo method, int playerIndex, int suitId, object player, out object[] args) { ParameterInfo[] parameters = method.GetParameters(); args = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { ParameterInfo parameterInfo = parameters[i]; Type parameterType = parameterInfo.ParameterType; Type type = Nullable.GetUnderlyingType(parameterType) ?? parameterType; string text = (parameterInfo.Name ?? string.Empty).ToLowerInvariant(); if (player != null && parameterType.IsAssignableFrom(player.GetType())) { args[i] = player; } else if (type == typeof(int)) { if (text.Contains("suit") || text.Contains("unlockable") || i == 1) { args[i] = suitId; } else { args[i] = playerIndex; } } else if (type == typeof(uint)) { if (text.Contains("suit") || text.Contains("unlockable") || i == 1) { args[i] = (uint)Mathf.Max(0, suitId); } else { args[i] = (uint)Mathf.Max(0, playerIndex); } } else if (type == typeof(ulong)) { if (text.Contains("suit") || text.Contains("unlockable") || i == 1) { args[i] = (ulong)Mathf.Max(0, suitId); } else { args[i] = (ulong)Mathf.Max(0, playerIndex); } } else if (type == typeof(bool)) { args[i] = false; } else if (type == typeof(float)) { args[i] = 0f; } else if (parameterType.IsValueType) { args[i] = Activator.CreateInstance(parameterType); } else { args[i] = null; } } return true; } private static void SetPlayerSuitFields(object player, int suitId) { if (player != null) { Type type = player.GetType(); string[] array = new string[6] { "suitID", "suitId", "currentSuitID", "currentSuitId", "syncedSuitID", "syncedSuitId" }; foreach (string name in array) { SetMemberValue(player, type, name, suitId); } } } private static object GetStartOfRound() { Type type = Type.GetType("StartOfRound, Assembly-CSharp"); if (type == null) { return null; } object memberValue = GetMemberValue(null, type, "Instance"); if (memberValue != null) { return memberValue; } memberValue = GetMemberValue(null, type, "instance"); if (memberValue != null) { return memberValue; } Object[] array = Resources.FindObjectsOfTypeAll(type); if (array != null && array.Length != 0) { return array[0]; } return null; } [IteratorStateMachine(typeof(<GetAllPlayerScripts>d__38))] private static IEnumerable<object> GetAllPlayerScripts(object startOfRound) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <GetAllPlayerScripts>d__38(-2) { <>3__startOfRound = startOfRound }; } private static object FindPlayerByClientIdOrIndex(object startOfRound, ulong clientId, int fallbackIndex) { int num = 0; foreach (object allPlayerScript in GetAllPlayerScripts(startOfRound)) { if (GetPlayerClientId(allPlayerScript) == clientId) { return allPlayerScript; } if (fallbackIndex >= 0 && num == fallbackIndex) { return allPlayerScript; } num++; } return null; } private static int GetPlayerIndex(object startOfRound, object player) { if (startOfRound == null || player == null) { return -1; } int num = 0; foreach (object allPlayerScript in GetAllPlayerScripts(startOfRound)) { if (allPlayerScript == player) { return num; } num++; } return -1; } private static bool IsRealPlayer(object player) { if (player == null) { return false; } Type type = player.GetType(); bool boolMember = GetBoolMember(player, type, "isPlayerControlled", fallback: false); bool boolMember2 = GetBoolMember(player, type, "isPlayerDead", fallback: false); return boolMember && !boolMember2; } private static ulong GetPlayerClientId(object player) { if (player == null) { return 0uL; } Type type = player.GetType(); string[] array = new string[3] { "actualClientId", "playerClientId", "clientId" }; foreach (string name in array) { object memberValue = GetMemberValue(player, type, name); if (memberValue != null) { try { return Convert.ToUInt64(memberValue, CultureInfo.InvariantCulture); } catch { } } } return 0uL; } private static bool IsSafeAssignTime(object startOfRound) { if (startOfRound == null) { return false; } if (!IsNetworkActive()) { return false; } if (!NetworkManager.Singleton.IsServer && !NetworkManager.Singleton.IsHost) { return false; } if (!PluginInstanceOnlyAssignInLobby()) { return true; } Type type = startOfRound.GetType(); bool boolMember = GetBoolMember(startOfRound, type, "shipHasLanded", fallback: false); bool boolMember2 = GetBoolMember(startOfRound, type, "shipIsLeaving", fallback: false); bool boolMember3 = GetBoolMember(startOfRound, type, "inShipPhase", fallback: true); return !boolMember && !boolMember2 && boolMember3; } private static bool PluginInstanceOnlyAssignInLobby() { try { Plugin plugin = Object.FindObjectOfType<Plugin>(); return (Object)(object)plugin == (Object)null || plugin.onlyAssignInShipLobby == null || plugin.onlyAssignInShipLobby.Value; } catch { return true; } } private static bool IsNetworkActive() { try { NetworkManager singleton = NetworkManager.Singleton; return (Object)(object)singleton != (Object)null && singleton.IsListening && !singleton.ShutdownInProgress; } catch { return false; } } private static bool IsHostOrServer() { try { NetworkManager singleton = NetworkManager.Singleton; return (Object)(object)singleton != (Object)null && singleton.IsListening && (singleton.IsHost || singleton.IsServer); } catch { return false; } } private static bool IsMenuScene(string sceneName) { if (string.IsNullOrWhiteSpace(sceneName)) { return false; } string text = sceneName.ToLowerInvariant(); return text.Contains("menu") || text.Contains("main"); } private static bool IsUnlockableSuitType(Type type) { if (type == null) { return false; } string text = type.Name ?? string.Empty; string text2 = type.FullName ?? string.Empty; return text.Equals("UnlockableSuit", StringComparison.OrdinalIgnoreCase) || text2.EndsWith(".UnlockableSuit", StringComparison.OrdinalIgnoreCase); } private static string Normalize(string text) { if (string.IsNullOrWhiteSpace(text)) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(text.Length); foreach (char c in text) { if (char.IsLetterOrDigit(c)) { stringBuilder.Append(char.ToLowerInvariant(c)); } } return stringBuilder.ToString(); } private static object GetMemberValue(object instance, Type type, string name) { if (type == null || string.IsNullOrWhiteSpace(name)) { return null; } try { FieldInfo field = type.GetField(name, Flags); if (field != null) { return field.GetValue(instance); } PropertyInfo property = type.GetProperty(name, Flags); if (property != null && property.GetIndexParameters().Length == 0) { return property.GetValue(instance, null); } } catch { } return null; } private static void SetMemberValue(object instance, Type type, string name, object value) { if (instance == null || type == null || string.IsNullOrWhiteSpace(name)) { return; } try { FieldInfo field = type.GetField(name, Flags); if (field != null) { object value2 = Convert.ChangeType(value, Nullable.GetUnderlyingType(field.FieldType) ?? field.FieldType, CultureInfo.InvariantCulture); field.SetValue(instance, value2); return; } PropertyInfo property = type.GetProperty(name, Flags); if (property != null && property.CanWrite) { object value3 = Convert.ChangeType(value, Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType, CultureInfo.InvariantCulture); property.SetValue(instance, value3, null); } } catch { } } private static int GetIntMember(object instance, Type type, string name, int fallback) { object memberValue = GetMemberValue(instance, type, name); if (memberValue == null) { return fallback; } try { return Convert.ToInt32(memberValue, CultureInfo.InvariantCulture); } catch { return fallback; } } private static bool GetBoolMember(object instance, Type type, string name, bool fallback) { object memberValue = GetMemberValue(instance, type, name); if (memberValue == null) { return fallback; } try { return Convert.ToBoolean(memberValue, CultureInfo.InvariantCulture); } catch { return fallback; } } private static int GetInstanceId(object obj) { Object val = (Object)((obj is Object) ? obj : null); return (val != (Object)null) ? val.GetInstanceID() : 0; } private static string PlayerLabel(object player) { if (player == null) { return "<null player>"; } object memberValue = GetMemberValue(player, player.GetType(), "playerUsername"); if (memberValue != null && !string.IsNullOrWhiteSpace(memberValue.ToString())) { return memberValue.ToString(); } Object val = (Object)((player is Object) ? player : null); if (val != (Object)null) { return val.name; } return player.ToString(); } private void DebugLog(string msg) { if (logDebug != null && logDebug.Value) { Log.LogInfo((object)msg); } } private static string ArgsToString(object[] args) { if (args == null) { return string.Empty; } return string.Join(", ", args.Select((object a) => (a == null) ? "null" : a.ToString()).ToArray()); } private static string ShortException(Exception ex) { if (ex == null) { return "<null exception>"; } while (ex.InnerException != null) { ex = ex.InnerException; } return ex.GetType().Name + ": " + ex.Message; } }