using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.AI; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ExitLineFromEnteredDoor { internal class ExitLineController : MonoBehaviour { private sealed class DotLine { public GameObject Container; public readonly List Dots = new List(); public NavMeshPath Path; public bool HasPath; public float RecomputeIn; public Vector3 LastDestination; public Vector3[] Corners; public float[] CumLen; public float TotalLen; public readonly List BaseArcs = new List(); public float OverflowArc; public float Phase; public bool IsFireExit; public int AppliedColorKind = -1; } private static readonly FieldInfo PingScanField = AccessTools.Field(typeof(HUDManager), "playerPingingScan"); private static readonly FieldInfo IsScreenOnField = AccessTools.Field(typeof(ManualCameraRenderer), "isScreenOn"); private const int MaxDotsPerLine = 400; private readonly List _lines = new List(); private readonly List _insideDoors = new List(); private readonly List _destinations = new List(); private readonly List _destinationIsFireExit = new List(); private bool _wasInside; private bool _wasVisible; private float _lastPing; private float _pulseTimer; private float _lastScanTime = -9999f; private MineshaftElevatorController _elevator; private bool _searchedElevator; private int _worldLayer; private bool _worldLayerResolved; private float _doorRescanCooldown; private float _errorLogCooldown; private static Mesh _dotMesh; private static Material _dotMatMain; private static Material _dotMatFire; private static readonly List ArcScratch = new List(); private Color _mainColor = new Color(0.38f, 1f, 0.44f, 1f); private Color _fireColor = new Color(1f, 0.3f, 0.3f, 1f); private string _parsedMainText; private string _parsedFireText; private int _dotBudget; private bool _loggedArcFallback; private bool _snapshotDirty; private void Update() { try { UpdateInternal(); } catch (Exception ex) { if (Time.unscaledTime >= _errorLogCooldown) { _errorLogCooldown = Time.unscaledTime + 10f; ExitLinePlugin.Log.LogWarning((object)("ExitLineController error: " + ex)); } HideAll(); } } private void UpdateInternal() { //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_03da: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Unknown result type (might be due to invalid IL or missing references) //IL_03bd: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) GameNetworkManager instance = GameNetworkManager.Instance; PlayerControllerB val = (((Object)(object)instance != (Object)null) ? instance.localPlayerController : null); StartOfRound instance2 = StartOfRound.Instance; if ((Object)(object)val == (Object)null || (Object)(object)instance2 == (Object)null) { HideAll(); return; } DetectScan(); bool isInsideFactory = val.isInsideFactory; if (!isInsideFactory) { ExitLinePlugin.LastEnteredEntranceId = -1; } if (isInsideFactory && !_wasInside) { OnEnteredInterior(); } _wasInside = isInsideFactory; _doorRescanCooldown -= Time.deltaTime; if (!IsLineVisible(val, instance2, isInsideFactory)) { _wasVisible = false; HideAll(); return; } if (!_wasVisible) { _snapshotDirty = true; for (int i = 0; i < _lines.Count; i++) { _lines[i].RecomputeIn = 0f; } } _wasVisible = true; if (!EnsureDotAssets()) { HideAll(); return; } EnsureWorldLayer(val); bool value = ExitLinePlugin.OnlyShowAfterScan.Value; if (!value || _snapshotDirty) { _destinations.Clear(); _destinationIsFireExit.Clear(); ResolveDestinations(val); if (value && _destinations.Count > 0) { for (int j = 0; j < _lines.Count; j++) { _lines[j].HasPath = false; _lines[j].RecomputeIn = 0f; } _snapshotDirty = false; } } if (_destinations.Count == 0) { HideAll(); return; } EnsurePool(_destinations.Count); _dotBudget = 80; float deltaTime = Time.deltaTime; bool num = _pulseTimer > 0f && ExitLinePlugin.PulseOnScan.Value; _pulseTimer = Mathf.Max(0f, _pulseTimer - deltaTime); float num2 = (num ? (_pulseTimer / Mathf.Max(0.5f, ExitLinePlugin.PulseDuration.Value)) : 0f); float num3 = ExitLinePlugin.FlowSpeed.Value * Mathf.Pow(num2, 1.5f); float value2 = ExitLinePlugin.BreatheStrength.Value; float num4 = Mathf.Max(0.25f, ExitLinePlugin.BreathePeriod.Value); float num5 = 1f + value2 * 0.5f * Mathf.Sin(Time.time * 2f * (float)Math.PI / num4); num5 += ExitLinePlugin.PulseBrightness.Value * num2; if (ExitLinePlugin.OnlyShowAfterScan.Value) { float num6 = ExitLinePlugin.ShowDurationAfterScan.Value - (Time.time - _lastScanTime); num5 *= Mathf.Clamp01(num6 / 1.2f); } ApplyBrightness(num5); Vector3 position = ((Component)val).transform.position; for (int k = 0; k < _lines.Count; k++) { DotLine dotLine = _lines[k]; if (k >= _destinations.Count) { dotLine.RecomputeIn = 0f; SetLineActive(dotLine, on: false); continue; } dotLine.IsFireExit = k < _destinationIsFireExit.Count && _destinationIsFireExit[k]; ApplyLineMaterial(dotLine); if (value) { if (!dotLine.HasPath) { dotLine.RecomputeIn -= deltaTime; if (dotLine.RecomputeIn <= 0f) { ComputePath(dotLine, position, _destinations[k]); } } } else { dotLine.RecomputeIn -= deltaTime; if (dotLine.RecomputeIn <= 0f) { goto IL_03d7; } if (dotLine.HasPath) { Vector3 val2 = _destinations[k] - dotLine.LastDestination; if (((Vector3)(ref val2)).sqrMagnitude > 1f) { goto IL_03d7; } } } goto IL_03ee; IL_03d7: ComputePath(dotLine, position, _destinations[k]); goto IL_03ee; IL_03ee: if (!dotLine.HasPath) { SetLineActive(dotLine, on: false); continue; } if (num3 > 0f) { dotLine.Phase = Mathf.Repeat(dotLine.Phase + deltaTime * num3, 1f); RepositionDots(dotLine); } else if (dotLine.Dots.Count < dotLine.BaseArcs.Count + 1) { RepositionDots(dotLine); } SetLineActive(dotLine, on: true); } BillboardDots(val); } private void BillboardDots(PlayerControllerB localPlayer) { //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_0071: Unknown result type (might be due to invalid IL or missing references) Camera gameplayCamera = localPlayer.gameplayCamera; if ((Object)(object)gameplayCamera == (Object)null) { return; } Quaternion rotation = ((Component)gameplayCamera).transform.rotation; for (int i = 0; i < _lines.Count; i++) { DotLine dotLine = _lines[i]; if ((Object)(object)dotLine.Container == (Object)null || !dotLine.Container.activeSelf) { continue; } List dots = dotLine.Dots; for (int j = 0; j < dots.Count; j++) { Transform val = dots[j]; if (((Component)val).gameObject.activeSelf) { val.rotation = rotation; } } } } private bool IsLineVisible(PlayerControllerB localPlayer, StartOfRound sor, bool inside) { if (!ExitLinePlugin.Enabled.Value) { return false; } if (!inside || localPlayer.isPlayerDead || !localPlayer.isPlayerControlled) { return false; } if (sor.inShipPhase) { return false; } if (ExitLinePlugin.RequirePlayerInShip.Value && !AnyPlayerInShip(sor)) { return false; } if (ExitLinePlugin.RequireShipCameraOnYou.Value && !ShipCameraOnLocal(sor, localPlayer)) { return false; } if (ExitLinePlugin.OnlyShowAfterScan.Value && Time.time - _lastScanTime > ExitLinePlugin.ShowDurationAfterScan.Value) { return false; } return true; } private static bool AnyPlayerInShip(StartOfRound sor) { PlayerControllerB[] allPlayerScripts = sor.allPlayerScripts; if (allPlayerScripts == null) { return false; } foreach (PlayerControllerB val in allPlayerScripts) { if ((Object)(object)val != (Object)null && val.isPlayerControlled && !val.isPlayerDead && val.isInHangarShipRoom) { return true; } } return false; } private static bool ShipCameraOnLocal(StartOfRound sor, PlayerControllerB localPlayer) { ManualCameraRenderer mapScreen = sor.mapScreen; if ((Object)(object)mapScreen == (Object)null || (Object)(object)mapScreen.targetedPlayer != (Object)(object)localPlayer) { return false; } if (IsScreenOnField != null && !(bool)IsScreenOnField.GetValue(mapScreen)) { return false; } return true; } private void DetectScan() { HUDManager instance = HUDManager.Instance; if (!((Object)(object)instance == (Object)null) && !(PingScanField == null)) { float num = (float)PingScanField.GetValue(instance); if (num > 0f && _lastPing <= 0f) { _lastScanTime = Time.time; _pulseTimer = ExitLinePlugin.PulseDuration.Value; _snapshotDirty = true; } _lastPing = num; } } private void OnEnteredInterior() { RescanDoors(); _elevator = null; _searchedElevator = false; foreach (DotLine line in _lines) { line.HasPath = false; line.RecomputeIn = 0f; } } private void RescanDoors() { _insideDoors.Clear(); EntranceTeleport[] array = Object.FindObjectsOfType(); foreach (EntranceTeleport val in array) { if ((Object)(object)val != (Object)null && !val.isEntranceToBuilding) { _insideDoors.Add(val); } } _doorRescanCooldown = 5f; } private void ResolveDestinations(PlayerControllerB localPlayer) { //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0126: 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) bool flag = _insideDoors.Count == 0; for (int num = _insideDoors.Count - 1; num >= 0; num--) { if ((Object)(object)_insideDoors[num] == (Object)null) { _insideDoors.RemoveAt(num); flag = true; } } if (flag && _doorRescanCooldown <= 0f) { RescanDoors(); } if (_insideDoors.Count == 0) { return; } RoundManager instance = RoundManager.Instance; if ((Object)(object)instance != (Object)null && instance.currentDungeonType == 4) { if (!_searchedElevator || (Object)(object)_elevator == (Object)null) { _elevator = Object.FindObjectOfType(); _searchedElevator = true; } if ((Object)(object)_elevator != (Object)null && (Object)(object)_elevator.elevatorTopPoint != (Object)null && (Object)(object)_elevator.elevatorBottomPoint != (Object)null && _elevator.elevatorTopPoint.position.y - ((Component)localPlayer).transform.position.y > 10f) { EntranceTeleport val = ResolveModeDoor(_elevator.elevatorTopPoint.position); AddDestination(_elevator.elevatorBottomPoint.position, (Object)(object)val != (Object)null && IsFireExitDoor(val)); return; } } if (ExitLinePlugin.Mode.Value == DoorMode.AllDoors) { for (int i = 0; i < _insideDoors.Count; i++) { AddDoorDestination(_insideDoors[i]); } return; } EntranceTeleport val2 = ResolveModeDoor(((Component)localPlayer).transform.position); if ((Object)(object)val2 != (Object)null) { AddDoorDestination(val2); } } private EntranceTeleport ResolveModeDoor(Vector3 from) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) if (ExitLinePlugin.Mode.Value == DoorMode.EnteredDoor) { int lastEnteredEntranceId = ExitLinePlugin.LastEnteredEntranceId; if (lastEnteredEntranceId >= 0) { for (int i = 0; i < _insideDoors.Count; i++) { if ((Object)(object)_insideDoors[i] != (Object)null && _insideDoors[i].entranceId == lastEnteredEntranceId) { return _insideDoors[i]; } } } } return ClosestDoorTo(from); } private EntranceTeleport ClosestDoorTo(Vector3 from) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) EntranceTeleport result = null; float num = float.MaxValue; for (int i = 0; i < _insideDoors.Count; i++) { EntranceTeleport val = _insideDoors[i]; if (!((Object)(object)val == (Object)null)) { Vector3 val2 = DoorPosition(val) - from; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = val; } } } return result; } private void AddDoorDestination(EntranceTeleport door) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) AddDestination(DoorPosition(door), IsFireExitDoor(door)); } private void AddDestination(Vector3 pos, bool isFireExit) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) _destinations.Add(pos); _destinationIsFireExit.Add(isFireExit); } private static bool IsFireExitDoor(EntranceTeleport door) { return door.entranceId != 0; } private static Vector3 DoorPosition(EntranceTeleport door) { //IL_0020: 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) if (!((Object)(object)door.entrancePoint != (Object)null)) { return ((Component)door).transform.position; } return door.entrancePoint.position; } private void ComputePath(DotLine line, Vector3 start, Vector3 destination) { //IL_0012: 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_0014: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_0046: 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_0040: 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_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_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_00bb: 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_00e2: 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_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0111: 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_015e: Unknown result type (might be due to invalid IL or missing references) line.HasPath = false; line.RecomputeIn = 1f; Vector3 val = start; NavMeshHit val2 = default(NavMeshHit); if (NavMesh.SamplePosition(start, ref val2, 4f, -1)) { val = ((NavMeshHit)(ref val2)).position; } Vector3 val3 = destination; if (NavMesh.SamplePosition(destination, ref val2, 4f, -1)) { val3 = ((NavMeshHit)(ref val2)).position; } if (!NavMesh.CalculatePath(val, val3, -1, line.Path)) { return; } Vector3[] corners = line.Path.corners; if (corners.Length >= 2) { float value = ExitLinePlugin.LineHeight.Value; int num = corners.Length; line.Corners = (Vector3[])(object)new Vector3[num]; line.CumLen = new float[num]; float num2 = 0f; line.Corners[0] = corners[0] + Vector3.up * value; line.CumLen[0] = 0f; for (int i = 1; i < num; i++) { line.Corners[i] = corners[i] + Vector3.up * value; num2 += Vector3.Distance(line.Corners[i - 1], line.Corners[i]); line.CumLen[i] = num2; } line.TotalLen = num2; if (!(num2 < 0.5f)) { GenerateBaseArcs(line); RepositionDots(line); line.HasPath = true; line.LastDestination = destination; line.RecomputeIn = ((num > 50) ? 2f : ((num < 36) ? 0.4f : 1f)); } } } private void GenerateBaseArcs(DotLine line) { float value = ExitLinePlugin.DotSpacingNear.Value; float far = Mathf.Max(value, ExitLinePlugin.DotSpacingFar.Value); float value2 = ExitLinePlugin.DotSpacingFarDistance.Value; float num = 1f; for (int i = 0; i < 4; i++) { float num2 = FillArcs(line.BaseArcs, line.TotalLen, value, far, value2, num, 400); if (num2 >= line.TotalLen) { line.OverflowArc = num2; return; } num *= 1.6f; } float num3 = FillArcs(ArcScratch, line.TotalLen, value, far, value2, num, 1600); if (num3 < line.TotalLen) { ArcScratch.Clear(); float num4 = line.TotalLen / 400f; for (int j = 0; j < 400; j++) { ArcScratch.Add(0.3f + (float)j * num4); } num3 = 0.3f + 400f * num4; } line.BaseArcs.Clear(); if (ArcScratch.Count <= 400) { line.BaseArcs.AddRange(ArcScratch); } else { for (int k = 0; k < 400; k++) { line.BaseArcs.Add(ArcScratch[Mathf.RoundToInt((float)(k * (ArcScratch.Count - 1)) / 399f)]); } } line.OverflowArc = num3; if (!_loggedArcFallback) { _loggedArcFallback = true; ExitLinePlugin.Log.LogInfo((object)("Very long path (" + line.TotalLen.ToString("F0") + "m) - dot trail thinned to stay under the dot cap.")); } } private static float FillArcs(List arcs, float totalLen, float near, float far, float farDist, float scale, int cap) { arcs.Clear(); float num; for (num = 0.3f; num < totalLen; num += Mathf.Lerp(near, far, Mathf.Clamp01(num / farDist)) * scale) { if (arcs.Count >= cap) { break; } arcs.Add(num); } return num; } private void RepositionDots(DotLine line) { //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) int num = line.BaseArcs.Count + 1; while (line.Dots.Count < num && _dotBudget > 0) { line.Dots.Add(CreateDot(line.Container.transform, LineMaterial(line))); _dotBudget--; } float value = ExitLinePlugin.DotSize.Value; Vector3 localScale = default(Vector3); ((Vector3)(ref localScale))..ctor(value, value, value); int segCursor = line.CumLen.Length - 1; for (int i = 0; i < line.Dots.Count; i++) { Transform val = line.Dots[i]; if (i >= num) { if (((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(false); } continue; } float num2 = ((i < line.BaseArcs.Count) ? line.BaseArcs[i] : line.OverflowArc); float num3 = ((i == 0) ? 0f : line.BaseArcs[i - 1]); float num4 = num2 - line.Phase * (num2 - num3); if (num4 < 0.05f || num4 > line.TotalLen - 0.05f) { if (((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(false); } continue; } val.position = SampleAlongPath(line, line.TotalLen - num4, ref segCursor); val.localScale = localScale; if (!((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); } } } private static Vector3 SampleAlongPath(DotLine line, float arcFromStart, ref int segCursor) { //IL_001b: 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_007c: 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) float[] cumLen = line.CumLen; if (arcFromStart >= line.TotalLen) { return line.Corners[cumLen.Length - 1]; } if (segCursor < 1) { segCursor = 1; } while (segCursor > 1 && arcFromStart <= cumLen[segCursor - 1]) { segCursor--; } float num = cumLen[segCursor] - cumLen[segCursor - 1]; float num2 = ((num > 0.0001f) ? ((arcFromStart - cumLen[segCursor - 1]) / num) : 0f); return Vector3.Lerp(line.Corners[segCursor - 1], line.Corners[segCursor], Mathf.Clamp01(num2)); } private bool EnsureDotAssets() { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_dotMesh == (Object)null) { GameObject obj = GameObject.CreatePrimitive((PrimitiveType)5); obj.SetActive(false); _dotMesh = obj.GetComponent().sharedMesh; Object.Destroy((Object)(object)obj); } if ((Object)(object)_dotMatMain == (Object)null || (Object)(object)_dotMatFire == (Object)null) { Shader val = Shader.Find("HDRP/Unlit"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Sprites/Default"); } if ((Object)(object)val == (Object)null) { ExitLinePlugin.Log.LogWarning((object)"No usable shader found for the exit dots."); return false; } if ((Object)(object)_dotMatMain == (Object)null) { _dotMatMain = MakeDotMaterial(val); } if ((Object)(object)_dotMatFire == (Object)null) { _dotMatFire = MakeDotMaterial(val); } } _mainColor = ParseColor(ExitLinePlugin.DotColorMainEntrance.Value, ref _parsedMainText, _mainColor, "DotColorMainEntrance"); _fireColor = ParseColor(ExitLinePlugin.DotColorFireExit.Value, ref _parsedFireText, _fireColor, "DotColorFireExit"); return true; } private static Material MakeDotMaterial(Shader shader) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown Material val = new Material(shader); if (val.HasProperty("_DoubleSidedEnable")) { val.SetFloat("_DoubleSidedEnable", 1f); val.EnableKeyword("_DOUBLESIDED_ON"); } if (val.HasProperty("_CullMode")) { val.SetFloat("_CullMode", 0f); } return val; } private static Color ParseColor(string text, ref string cached, Color current, string settingName) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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) if (text == cached) { return current; } cached = text; Color result = default(Color); if (ColorUtility.TryParseHtmlString(text.StartsWith("#") ? text : ("#" + text), ref result)) { return result; } ExitLinePlugin.Log.LogWarning((object)("Could not parse " + settingName + " '" + text + "', keeping previous color.")); return current; } private void ApplyBrightness(float brightness) { //IL_0006: 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) ApplyColor(_dotMatMain, _mainColor, brightness); ApplyColor(_dotMatFire, _fireColor, brightness); } private static void ApplyColor(Material mat, Color baseColor, float brightness) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_0040: 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) Color val = default(Color); ((Color)(ref val))..ctor(baseColor.r * brightness, baseColor.g * brightness, baseColor.b * brightness, baseColor.a); if (mat.HasProperty("_UnlitColor")) { mat.SetColor("_UnlitColor", val); } else { mat.color = val; } } private Transform CreateDot(Transform parent, Material mat) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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) GameObject val = new GameObject("Dot") { layer = _worldLayer }; val.transform.SetParent(parent, false); val.AddComponent().sharedMesh = _dotMesh; MeshRenderer obj = val.AddComponent(); ((Renderer)obj).sharedMaterial = mat; ((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)obj).receiveShadows = false; val.SetActive(false); return val.transform; } private static Material LineMaterial(DotLine line) { if (!line.IsFireExit) { return _dotMatMain; } return _dotMatFire; } private void ApplyLineMaterial(DotLine line) { int num = (line.IsFireExit ? 1 : 0); if (line.AppliedColorKind == num) { return; } line.AppliedColorKind = num; Material sharedMaterial = LineMaterial(line); for (int i = 0; i < line.Dots.Count; i++) { Transform val = line.Dots[i]; if (!((Object)(object)val == (Object)null)) { MeshRenderer component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null) { ((Renderer)component).sharedMaterial = sharedMaterial; } } } } private void EnsureWorldLayer(PlayerControllerB localPlayer) { if (_worldLayerResolved) { return; } Camera gameplayCamera = localPlayer.gameplayCamera; if ((Object)(object)gameplayCamera == (Object)null) { return; } int cullingMask = gameplayCamera.cullingMask; if ((cullingMask & 1) != 0) { _worldLayer = 0; } else { for (int i = 0; i < 32; i++) { if ((cullingMask & (1 << i)) != 0 && i != 5) { _worldLayer = i; break; } } } _worldLayerResolved = true; foreach (DotLine line in _lines) { if ((Object)(object)line.Container != (Object)null) { line.Container.layer = _worldLayer; } foreach (Transform dot in line.Dots) { if ((Object)(object)dot != (Object)null) { ((Component)dot).gameObject.layer = _worldLayer; } } } } private void EnsurePool(int needed) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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 while (_lines.Count < needed) { GameObject val = new GameObject("ExitLineFromEnteredDoor_Dots"); val.transform.SetParent(((Component)this).transform, false); val.layer = _worldLayer; val.SetActive(false); _lines.Add(new DotLine { Container = val, Path = new NavMeshPath() }); } } private static void SetLineActive(DotLine line, bool on) { if ((Object)(object)line.Container != (Object)null && line.Container.activeSelf != on) { line.Container.SetActive(on); } } private void HideAll() { for (int i = 0; i < _lines.Count; i++) { SetLineActive(_lines[i], on: false); } } } public enum DoorMode { EnteredDoor, ClosestDoor, AllDoors } [BepInPlugin("Haaylo.ExitLineFromEnteredDoor", "ExitLineFromEnteredDoor", "1.0.1")] public class ExitLinePlugin : BaseUnityPlugin { public const string Guid = "Haaylo.ExitLineFromEnteredDoor"; public const string Name = "ExitLineFromEnteredDoor"; public const string Version = "1.0.1"; internal static ManualLogSource Log; internal static ConfigEntry Enabled; internal static ConfigEntry Mode; internal static ConfigEntry RequirePlayerInShip; internal static ConfigEntry RequireShipCameraOnYou; internal static ConfigEntry LineHeight; internal static ConfigEntry DotSize; internal static ConfigEntry DotColorMainEntrance; internal static ConfigEntry DotColorFireExit; internal static ConfigEntry DotSpacingNear; internal static ConfigEntry DotSpacingFar; internal static ConfigEntry DotSpacingFarDistance; internal static ConfigEntry BreathePeriod; internal static ConfigEntry BreatheStrength; internal static ConfigEntry PulseOnScan; internal static ConfigEntry PulseDuration; internal static ConfigEntry FlowSpeed; internal static ConfigEntry PulseBrightness; internal static ConfigEntry OnlyShowAfterScan; internal static ConfigEntry ShowDurationAfterScan; internal static int LastEnteredEntranceId = -1; private void Awake() { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Expected O, but got Unknown //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Expected O, but got Unknown //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Expected O, but got Unknown //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Expected O, but got Unknown //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Expected O, but got Unknown //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Expected O, but got Unknown //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Expected O, but got Unknown //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0350: Expected O, but got Unknown //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Expected O, but got Unknown //IL_03b7: Unknown result type (might be due to invalid IL or missing references) //IL_03d0: Unknown result type (might be due to invalid IL or missing references) //IL_03d5: Unknown result type (might be due to invalid IL or missing references) //IL_03db: Expected O, but got Unknown //IL_03db: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Master switch for the exit line."); Mode = ((BaseUnityPlugin)this).Config.Bind("General", "DoorMode", DoorMode.EnteredDoor, "Which exit the line leads to. EnteredDoor = the door you came in through (falls back to closest if unknown, e.g. after a teleport). ClosestDoor = nearest exit by distance. AllDoors = one line per exit."); RequirePlayerInShip = ((BaseUnityPlugin)this).Config.Bind("Conditions", "RequirePlayerInShip", false, "Only show the line while at least one living player is inside the ship."); RequireShipCameraOnYou = ((BaseUnityPlugin)this).Config.Bind("Conditions", "RequireShipCameraOnYou", false, "Only show the line while the ship's map screen is on and its radar is targeting you."); LineHeight = ((BaseUnityPlugin)this).Config.Bind("Visuals", "LineHeight", 0.1f, new ConfigDescription("How high above the floor the dots sit, in meters. 0.1 hugs the ground.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); DotSize = ((BaseUnityPlugin)this).Config.Bind("Visuals", "DotSize", 0.04f, new ConfigDescription("Diameter of each dot, in meters. Keep it tiny for a subtle pixel-like trail.", (AcceptableValueBase)(object)new AcceptableValueRange(0.005f, 0.5f), Array.Empty())); DotColorMainEntrance = ((BaseUnityPlugin)this).Config.Bind("Visuals", "DotColorMainEntrance", "62FF71", "Dot color when the trail leads to the main entrance, as an RGB hex value (radar green by default)."); DotColorFireExit = ((BaseUnityPlugin)this).Config.Bind("Visuals", "DotColorFireExit", "FF4D4D", "Dot color when the trail leads to a fire exit, as an RGB hex value (red by default), so you can tell at a glance which way out you're being pointed."); DotSpacingNear = ((BaseUnityPlugin)this).Config.Bind("Visuals", "DotSpacingNear", 0.4f, new ConfigDescription("Distance between dots right next to the exit door, in meters (dense end).", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 5f), Array.Empty())); DotSpacingFar = ((BaseUnityPlugin)this).Config.Bind("Visuals", "DotSpacingFar", 2f, new ConfigDescription("Distance between dots far away from the exit door, in meters (sparse end). The trail getting denser tells you which way the door is.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 10f), Array.Empty())); DotSpacingFarDistance = ((BaseUnityPlugin)this).Config.Bind("Visuals", "DotSpacingFarDistance", 40f, new ConfigDescription("How many meters from the door the spacing reaches its sparsest.", (AcceptableValueBase)(object)new AcceptableValueRange(5f, 200f), Array.Empty())); BreathePeriod = ((BaseUnityPlugin)this).Config.Bind("Visuals", "BreathePeriod", 2.5f, new ConfigDescription("Seconds per breathing cycle.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 10f), Array.Empty())); BreatheStrength = ((BaseUnityPlugin)this).Config.Bind("Visuals", "BreatheStrength", 0.35f, new ConfigDescription("How strongly the dots breathe (brightness swing). 0 disables breathing.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); PulseOnScan = ((BaseUnityPlugin)this).Config.Bind("Scan", "PulseOnScan", true, "Make the dots flow toward the exit right after a scan, slowing back down to a static trail."); PulseDuration = ((BaseUnityPlugin)this).Config.Bind("Scan", "PulseDuration", 3f, new ConfigDescription("How long the scan flow takes to settle back to static, in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 10f), Array.Empty())); FlowSpeed = ((BaseUnityPlugin)this).Config.Bind("Scan", "FlowSpeed", 4f, new ConfigDescription("How fast dots travel toward the exit at the peak of the scan flow (dots per second).", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 20f), Array.Empty())); PulseBrightness = ((BaseUnityPlugin)this).Config.Bind("Scan", "PulseBrightness", 1f, new ConfigDescription("Extra brightness at the start of the scan flow.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); OnlyShowAfterScan = ((BaseUnityPlugin)this).Config.Bind("Scan", "OnlyShowAfterScan", true, "Hide the trail by default and only reveal it for a few seconds after each scan. The trail is a snapshot: it runs from where you scanned to the door and stays put. Turning this off keeps an always-on trail that follows you instead."); ShowDurationAfterScan = ((BaseUnityPlugin)this).Config.Bind("Scan", "ShowDurationAfterScan", 5f, new ConfigDescription("How long the trail stays visible after a scan when OnlyShowAfterScan is on (fades out at the end).", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 60f), Array.Empty())); new Harmony("Haaylo.ExitLineFromEnteredDoor").PatchAll(typeof(EntranceTeleportPatch)); GameObject val = new GameObject("ExitLineFromEnteredDoorController"); Object.DontDestroyOnLoad((Object)val); ((Object)val).hideFlags = (HideFlags)61; val.AddComponent(); Log.LogInfo((object)"ExitLineFromEnteredDoor 1.0.1 loaded."); } } [HarmonyPatch(typeof(EntranceTeleport), "TeleportPlayer")] internal static class EntranceTeleportPatch { private static void Postfix(EntranceTeleport __instance) { try { if (!((Object)(object)__instance.exitScript == (Object)null)) { ExitLinePlugin.LastEnteredEntranceId = (__instance.isEntranceToBuilding ? __instance.entranceId : (-1)); } } catch { } } } }