using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ComputerysModdingUtilities; using HarmonyLib; using Microsoft.CodeAnalysis; 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: StraftatMod(true)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = "")] [assembly: AssemblyCompany("SpawnViewer")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("2.0.0.0")] [assembly: AssemblyInformationalVersion("2.0.0+e45159f2737e2cd33ed01304259752a621bf14bc")] [assembly: AssemblyProduct("SpawnViewer")] [assembly: AssemblyTitle("SpawnViewer")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 StraftatSpawnViewer { internal readonly struct SpawnPoint { public readonly Vector3 Pos; public readonly float Yaw; public readonly string Name; public SpawnPoint(Vector3 pos, float yaw, string name) { //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) Pos = pos; Yaw = yaw; Name = name; } } [BepInPlugin("suvilba.straftat.spawnviewer", "SpawnViewer", "2.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class SpawnViewer : BaseUnityPlugin { private enum GameMode { _2v2, _1v1 } private const string PluginGuid = "suvilba.straftat.spawnviewer"; private const string PluginName = "SpawnViewer"; private const string PluginVersion = "2.0.0"; private const string RootName = "StraftatSpawnViewer_ROOT"; internal static ManualLogSource Logger; private const float BallSize = 0.35f; private const float BeamLengthMin = 1f; private const float BeamLengthMax = 400f; private readonly LineRenderer[] _beams = (LineRenderer[])(object)new LineRenderer[4]; private readonly SpawnPoint[] _foundSpawns = new SpawnPoint[4]; private readonly GameObject[] _spawnPointGameObjects = (GameObject[])(object)new GameObject[4]; private ConfigEntry _cfgEnabled; private ConfigEntry _cfgToggleKey; private ConfigEntry _cfgRefreshKey; private ConfigEntry _cfgBeamLength; private ConfigEntry _cfgGameMode; private ConfigEntry _cfgTeamAColor; private ConfigEntry _cfgTeamBColor; private bool _enabled; private float _beamLength; private GameMode _gameMode; private Color _teamAColor; private Color _teamBColor; private Material _matA; private Material _matB; private bool _spawnsAlreadyFound; private int _amountFoundSpawns; private bool _rescan; private GameObject _root; private Harmony _harmony; private int SpawnCount => (_gameMode == GameMode._1v1) ? 2 : 4; private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; InitConfig(); EnsureRoot(); CreateSpawnpoints(forceRebuild: true); SceneManager.sceneLoaded += OnSceneLoaded; _rescan = true; TryHarmonyPatch(); } private void Update() { VisibilityToggle(); if (_enabled && _rescan) { _rescan = false; FindAndSetSpawns(); } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { _spawnsAlreadyFound = false; _amountFoundSpawns = 0; EnsureRoot(); CreateSpawnpoints(forceRebuild: false); _rescan = true; } private void VisibilityToggle() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = _cfgToggleKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { _cfgEnabled.Value = !_cfgEnabled.Value; } value = _cfgRefreshKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { _spawnsAlreadyFound = false; _amountFoundSpawns = 0; _rescan = true; } } private void InitConfig() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_00ff: 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_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) _cfgEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "Show Spawns", false, "Toggle spawn point visibility."); _cfgToggleKey = ((BaseUnityPlugin)this).Config.Bind("General", "Toggle Key", new KeyboardShortcut((KeyCode)286, Array.Empty()), "Keybind to toggle spawn point visibility."); _cfgRefreshKey = ((BaseUnityPlugin)this).Config.Bind("General", "Refresh Key", new KeyboardShortcut((KeyCode)287, Array.Empty()), "Keybind to refresh spawn points mid map."); _cfgGameMode = ((BaseUnityPlugin)this).Config.Bind("General", "Game Mode", GameMode._2v2, "Which spawn set to display."); _cfgBeamLength = ((BaseUnityPlugin)this).Config.Bind("Markers", "Beam Length", 5f, new ConfigDescription("Height of the spawn point beams.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 400f), Array.Empty())); _cfgTeamAColor = ((BaseUnityPlugin)this).Config.Bind("Markers", "Team A Color", new Color(0.25f, 0.75f, 1f), "Color of Team A spawnpoints."); _cfgTeamBColor = ((BaseUnityPlugin)this).Config.Bind("Markers", "Team B Color", new Color(1f, 0.35f, 0.55f), "Color of Team B spawnpoints."); _enabled = _cfgEnabled.Value; _beamLength = _cfgBeamLength.Value; _gameMode = _cfgGameMode.Value; _teamAColor = _cfgTeamAColor.Value; _teamBColor = _cfgTeamBColor.Value; _cfgEnabled.SettingChanged += delegate { _enabled = _cfgEnabled.Value; SetSpawnPointVisibility(_enabled); if (_enabled) { _rescan = true; } }; _cfgGameMode.SettingChanged += delegate { _gameMode = _cfgGameMode.Value; _spawnsAlreadyFound = false; _amountFoundSpawns = 0; SetSpawnPointVisibility(visible: false); _rescan = true; }; _cfgBeamLength.SettingChanged += delegate { _beamLength = _cfgBeamLength.Value; UpdateBeamLengths(); }; _cfgTeamAColor.SettingChanged += delegate { //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) _teamAColor = _cfgTeamAColor.Value; RebuildMaterials(); }; _cfgTeamBColor.SettingChanged += delegate { //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) _teamBColor = _cfgTeamBColor.Value; RebuildMaterials(); }; } private void FindAndSetSpawns() { EnsureRoot(); CreateSpawnpoints(forceRebuild: false); int spawnCount = SpawnCount; if (_spawnsAlreadyFound && _amountFoundSpawns == spawnCount) { UsePreviousSpawns(); return; } string log; List list = FindSpawns(out log, 800f); if (list.Count == 0) { string text = ((_gameMode == GameMode._1v1) ? "1v1" : "2v2"); Logger.LogWarning((object)("SpawnViewer: No " + text + " spawnpoints found. " + log)); SetSpawnPointVisibility(visible: false); return; } List list2 = Deduplicate(list); if (list2.Count < spawnCount) { string arg = ((_gameMode == GameMode._1v1) ? "1v1" : "2v2"); Logger.LogWarning((object)$"SpawnViewer: Found {list2.Count}/{spawnCount} unique {arg} spawnpoints."); SetSpawnPointVisibility(visible: false); return; } for (int i = 0; i < spawnCount; i++) { _foundSpawns[i] = list2[i]; } _amountFoundSpawns = spawnCount; _spawnsAlreadyFound = true; UsePreviousSpawns(); } private static List Deduplicate(List points) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) List list = new List(points.Count); foreach (SpawnPoint point in points) { bool flag = false; foreach (SpawnPoint item in list) { if (Vector3.Distance(point.Pos, item.Pos) < 0.5f) { flag = true; break; } } if (!flag) { list.Add(point); } } return list; } private void UsePreviousSpawns() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) EnsureRoot(); CreateSpawnpoints(forceRebuild: false); for (int i = 0; i < SpawnCount; i++) { SpawnPoint spawnPoint = _foundSpawns[i]; PlaceSpawn(i, spawnPoint.Pos, spawnPoint.Yaw); } for (int j = SpawnCount; j < 4; j++) { if ((Object)(object)_spawnPointGameObjects[j] != (Object)null) { _spawnPointGameObjects[j].SetActive(false); } } SetSpawnPointVisibility(visible: true); } private List FindSpawns(out string log, float maxDistance) { return (_gameMode == GameMode._1v1) ? Find1V1Spawns(out log, maxDistance) : Find2V2Spawns(out log, maxDistance); } private static List Find2V2Spawns(out string log, float maxDistance) { //IL_0090: 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_0098: Invalid comparison between Unknown and I4 //IL_00a4: 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_00c2: 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_00ff: 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) log = "no 2v2 spawnpoints found"; GameObject obj = GameObject.Find("Main Camera"); object obj2; if (obj == null) { obj2 = null; } else { Camera component = obj.GetComponent(); obj2 = ((component != null) ? ((Component)component).transform : null); } Transform val = (Transform)obj2; if ((Object)(object)val == (Object)null) { return new List(); } List list = new List(32); Transform[] array = Resources.FindObjectsOfTypeAll(); foreach (Transform val2 in array) { if ((Object)(object)val2 == (Object)null || !((Component)val2).gameObject.activeInHierarchy || (((Object)val2).hideFlags & 1) > 0) { continue; } Vector3 position = val2.position; if (!(((Vector3)(ref position)).sqrMagnitude < 1f) && !(Vector3.Distance(val.position, position) > maxDistance)) { string text = GetPath(val2).ToLowerInvariant(); if (text.Contains("spawnpoints4p")) { list.Add(new SpawnPoint(position, val2.eulerAngles.y, ((Object)val2).name)); } } } if (list.Count > 0) { log = string.Empty; } list.Sort((SpawnPoint a, SpawnPoint b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase)); return list; } private static List Find1V1Spawns(out string log, float maxDistance) { //IL_008f: 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_0097: Invalid comparison between Unknown and I4 //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_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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) log = "no 1v1 spawns found"; GameObject obj = GameObject.Find("Main Camera"); object obj2; if (obj == null) { obj2 = null; } else { Camera component = obj.GetComponent(); obj2 = ((component != null) ? ((Component)component).transform : null); } Transform val = (Transform)obj2; if ((Object)(object)val == (Object)null) { return new List(); } List list = new List(8); Transform[] array = Resources.FindObjectsOfTypeAll(); foreach (Transform val2 in array) { if ((Object)(object)val2 == (Object)null || !((Component)val2).gameObject.activeInHierarchy || (((Object)val2).hideFlags & 1) > 0) { continue; } Vector3 position = val2.position; if (!(((Vector3)(ref position)).sqrMagnitude < 1f) && !(Vector3.Distance(val.position, position) > maxDistance)) { string text = GetPath(val2).ToLowerInvariant(); if (text.Contains("gameplay") && !text.Contains("spawnpoints4p")) { list.Add(new SpawnPoint(position, val2.eulerAngles.y, ((Object)val2).name)); } } } if (list.Count > 0) { log = string.Empty; } list.Sort((SpawnPoint a, SpawnPoint b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase)); return list; } private void CreateSpawnpoints(bool forceRebuild) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown bool flag = forceRebuild; if (!flag) { for (int i = 0; i < 4; i++) { if ((Object)(object)_spawnPointGameObjects[i] == (Object)null || (Object)(object)_beams[i] == (Object)null) { flag = true; break; } } } if (flag) { RemoveSpawnpoints(); if (_matA == null) { _matA = new Material(Shader.Find("Unlit/Color")) { color = _teamAColor }; } if (_matB == null) { _matB = new Material(Shader.Find("Unlit/Color")) { color = _teamBColor }; } CreateSpawnPoint(0, "SpawnPoint_A1", _matA); CreateSpawnPoint(1, "SpawnPoint_B1", _matB); CreateSpawnPoint(2, "SpawnPoint_A2", _matA); CreateSpawnPoint(3, "SpawnPoint_B2", _matB); } } private void RemoveSpawnpoints() { for (int i = 0; i < 4; i++) { if ((Object)(object)_spawnPointGameObjects[i] != (Object)null) { Object.Destroy((Object)(object)_spawnPointGameObjects[i]); } _spawnPointGameObjects[i] = null; _beams[i] = null; } } private void CreateSpawnPoint(int slot, string spawnName, Material mat) { //IL_005d: 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_00aa: Expected O, but got Unknown //IL_00d6: 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_00ee: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_root == (Object)null)) { GameObject val = GameObject.CreatePrimitive((PrimitiveType)0); ((Object)val).name = spawnName; ((Object)val).hideFlags = (HideFlags)52; val.transform.SetParent(_root.transform, true); val.transform.localScale = new Vector3(0.35f, 0.35f, 0.35f); Object.Destroy((Object)(object)val.GetComponent()); Renderer component = val.GetComponent(); if ((Object)(object)component != (Object)null) { component.sharedMaterial = mat; } GameObject val2 = new GameObject(spawnName + "_Beam") { hideFlags = (HideFlags)52 }; val2.transform.SetParent(val.transform, false); LineRenderer val3 = val2.AddComponent(); val3.useWorldSpace = false; val3.positionCount = 2; val3.SetPosition(0, Vector3.zero); val3.SetPosition(1, Vector3.up * _beamLength); val3.startWidth = 0.15f; val3.endWidth = 0.15f; ((Renderer)val3).material = mat; val.SetActive(false); _spawnPointGameObjects[slot] = val; _beams[slot] = val3; } } private void PlaceSpawn(int slot, Vector3 pos, float yaw) { //IL_0031: 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_0046: 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) if (slot < 0 || slot >= 4) { return; } GameObject val = _spawnPointGameObjects[slot]; if (!((Object)(object)val == (Object)null)) { val.transform.position = pos + new Vector3(0f, 0.225f, 0f); val.transform.rotation = Quaternion.Euler(0f, yaw, 0f); if ((Object)(object)_beams[slot] != (Object)null) { ((Renderer)_beams[slot]).enabled = true; } } } private void SetSpawnPointVisibility(bool visible) { for (int i = 0; i < SpawnCount; i++) { if ((Object)(object)_spawnPointGameObjects[i] != (Object)null) { _spawnPointGameObjects[i].SetActive(visible); } } for (int j = SpawnCount; j < 4; j++) { if ((Object)(object)_spawnPointGameObjects[j] != (Object)null) { _spawnPointGameObjects[j].SetActive(false); } } for (int k = 0; k < SpawnCount; k++) { if ((Object)(object)_beams[k] != (Object)null) { ((Renderer)_beams[k]).enabled = visible; } } } private void UpdateBeamLengths() { //IL_0023: 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) for (int i = 0; i < 4; i++) { if (!((Object)(object)_beams[i] == (Object)null)) { _beams[i].SetPosition(1, Vector3.up * _beamLength); } } } private void RebuildMaterials() { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown if ((Object)(object)_matA != (Object)null) { Object.Destroy((Object)(object)_matA); } if ((Object)(object)_matB != (Object)null) { Object.Destroy((Object)(object)_matB); } if (_matA == null) { _matA = new Material(Shader.Find("Unlit/Color")) { color = _teamAColor }; } if (_matB == null) { _matB = new Material(Shader.Find("Unlit/Color")) { color = _teamBColor }; } for (int i = 0; i < 4; i++) { if (!((Object)(object)_spawnPointGameObjects[i] == (Object)null)) { Material val = ((i == 0 || i == 2) ? _matA : _matB); Renderer component = _spawnPointGameObjects[i].GetComponent(); if ((Object)(object)component != (Object)null) { component.sharedMaterial = val; } if ((Object)(object)_beams[i] != (Object)null) { ((Renderer)_beams[i]).material = val; } } } } private void EnsureRoot() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown if (!((Object)(object)_root != (Object)null)) { _root = GameObject.Find("StraftatSpawnViewer_ROOT"); if ((Object)(object)_root == (Object)null) { _root = new GameObject("StraftatSpawnViewer_ROOT"); Object.DontDestroyOnLoad((Object)(object)_root); } } } private static string GetPath(Transform t) { List list = new List(16); Transform val = t; int num = 0; while ((Object)(object)val != (Object)null && num++ < 6) { list.Add(((Object)val).name); val = val.parent; } list.Reverse(); return string.Join("/", list); } private void TryHarmonyPatch() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown try { _harmony = new Harmony("suvilba.straftat.spawnviewer"); Type type = AccessTools.TypeByName("PlayerManager"); if (!(type == null)) { PatchPostfixIfExists(type, "PopulateSpawnPoints"); PatchPostfixIfExists(type, "SetActiveSpawnPoints"); PatchPostfixIfExists(type, "RoundSpawn"); PatchPostfixIfExists(type, "NewSceneSpawn"); } } catch (Exception arg) { Logger.LogWarning((object)$"SpawnViewer Harmony patching failed: {arg}"); } } private void PatchPostfixIfExists(Type type, string methodName) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null); if (!(methodInfo == null)) { _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(SpawnViewer), "RefreshPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } public static void RefreshPostfix() { try { SpawnViewer[] array = Resources.FindObjectsOfTypeAll(); if (array != null && array.Length != 0) { array[0]._rescan = true; } } catch (Exception arg) { Debug.LogWarning((object)$"SpawnViewer RefreshPostfix failed: {arg}"); } } } }