using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using 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 = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("SpawnViewer")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("suvilba.straftat.spawnviewer")] [assembly: AssemblyFileVersion("2.1.0.0")] [assembly: AssemblyInformationalVersion("2.1.0+efc8b8e4df3f52e0040d34943932a5c82cd2ea6c")] [assembly: AssemblyProduct("SpawnViewer")] [assembly: AssemblyTitle("SpawnViewer")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace StraftatSpawnViewer { public enum GameMode { _2v2, _1v1 } public static class Configs { private const float BeamLengthMin = 1f; private const float BeamLengthMax = 400f; public static ConfigEntry Enabled { get; private set; } public static ConfigEntry ToggleKey { get; private set; } public static ConfigEntry RefreshKey { get; private set; } public static ConfigEntry Mode { get; private set; } public static ConfigEntry BeamLength { get; private set; } public static ConfigEntry TeamAColor { get; private set; } public static ConfigEntry TeamBColor { get; private set; } public static event Action EnabledChanged; public static event Action ModeChanged; public static event Action BeamLengthChanged; public static event Action ColorsChanged; internal static void Init(ConfigFile config) { //IL_0032: 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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) Enabled = config.Bind("General", "Show Spawns", false, "Toggle spawn point visibility."); ToggleKey = config.Bind("General", "Toggle Key", new KeyboardShortcut((KeyCode)286, Array.Empty()), "Keybind to toggle spawn point visibility."); RefreshKey = config.Bind("General", "Refresh Key", new KeyboardShortcut((KeyCode)287, Array.Empty()), "Keybind to refresh spawn points mid map."); Mode = config.Bind("General", "Game Mode", GameMode._2v2, "Which spawn set to display."); BeamLength = config.Bind("Markers", "Beam Length", 5f, new ConfigDescription("Height of the spawn point beams.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 400f), Array.Empty())); TeamAColor = config.Bind("Markers", "Team A Color", new Color(0.25f, 0.75f, 1f), "Color of Team A spawnpoints."); TeamBColor = config.Bind("Markers", "Team B Color", new Color(1f, 0.35f, 0.55f), "Color of Team B spawnpoints."); Enabled.SettingChanged += delegate { Configs.EnabledChanged?.Invoke(); }; Mode.SettingChanged += delegate { Configs.ModeChanged?.Invoke(); }; BeamLength.SettingChanged += delegate { Configs.BeamLengthChanged?.Invoke(); }; TeamAColor.SettingChanged += delegate { Configs.ColorsChanged?.Invoke(); }; TeamBColor.SettingChanged += delegate { Configs.ColorsChanged?.Invoke(); }; } } [BepInPlugin("suvilba.straftat.spawnviewer", "SpawnViewer", "2.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class SpawnViewer : BaseUnityPlugin { private const string RootName = "StraftatSpawnViewer_ROOT"; internal static ManualLogSource Logger; private GameObject _root; private SpawnpointDisplay _display; private Harmony _harmony; private bool _spawnsLocked; private bool _rescan; private int SpawnCount => (Configs.Mode.Value == GameMode._1v1) ? 2 : 4; private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; Configs.Init(((BaseUnityPlugin)this).Config); SubscribeToConfig(); EnsureDisplay(); SceneManager.sceneLoaded += OnSceneLoaded; _rescan = true; TryHarmonyPatch(); } private void Update() { HandleInput(); if (Configs.Enabled.Value && _rescan) { _rescan = false; RefreshSpawns(); } } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { _spawnsLocked = false; _rescan = true; } private void HandleInput() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_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) KeyboardShortcut value = Configs.ToggleKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { Configs.Enabled.Value = !Configs.Enabled.Value; } value = Configs.RefreshKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { _spawnsLocked = false; _rescan = true; } } private void SubscribeToConfig() { Configs.EnabledChanged += delegate { if (Configs.Enabled.Value) { _spawnsLocked = false; _rescan = true; } else { _display.Hide(); } }; Configs.ModeChanged += delegate { _spawnsLocked = false; _display.Hide(); _rescan = true; }; Configs.BeamLengthChanged += delegate { _display.SetBeamLength(Configs.BeamLength.Value); }; Configs.ColorsChanged += delegate { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) _display.SetColors(Configs.TeamAColor.Value, Configs.TeamBColor.Value); }; } private void RefreshSpawns() { EnsureDisplay(); if (!_spawnsLocked) { List list = SpawnFinder.Find(Configs.Mode.Value); int spawnCount = SpawnCount; if (list.Count < spawnCount) { string arg = ((Configs.Mode.Value == GameMode._1v1) ? "1v1" : "2v2"); Logger.LogWarning((object)$"SpawnViewer: Found {list.Count}/{spawnCount} {arg} spawnpoints."); _display.Hide(); } else { _display.Show(list, spawnCount); _spawnsLocked = true; } } } private void EnsureDisplay() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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); } } if ((Object)(object)_display == (Object)null) { _display = _root.GetComponent() ?? _root.AddComponent(); } } 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]._spawnsLocked = false; array[0]._rescan = true; } } catch (Exception arg) { Debug.LogWarning((object)$"SpawnViewer RefreshPostfix failed: {arg}"); } } } internal static class PluginInfo { public const string PLUGIN_GUID = "suvilba.straftat.spawnviewer"; public const string PLUGIN_NAME = "SpawnViewer"; public const string PLUGIN_VERSION = "2.1.0"; } internal static class SpawnFinder { private const string Tag1v1 = "Spawnpoints"; private const string Tag2v2 = "Spawnpoints4Player"; internal static List Find(GameMode mode) { string tag = ((mode == GameMode._1v1) ? "Spawnpoints" : "Spawnpoints4Player"); return (from s in (from s in Object.FindObjectsByType((FindObjectsSortMode)0) where (Object)(object)((Component)s).transform.parent != (Object)null && ((Component)((Component)s).transform.parent).CompareTag(tag) select s).OrderBy((SpawnPoint s) => ((Object)s).name, StringComparer.OrdinalIgnoreCase) select ((Component)s).transform).ToList(); } } public sealed class SpawnpointDisplay : MonoBehaviour { private const float BallSize = 0.35f; private readonly GameObject[] _spheres = (GameObject[])(object)new GameObject[4]; private readonly LineRenderer[] _beams = (LineRenderer[])(object)new LineRenderer[4]; private Material _matA; private Material _matB; private void Awake() { BuildPool(); } private void OnDestroy() { DestroyPool(); if ((Object)(object)_matA != (Object)null) { Object.Destroy((Object)(object)_matA); } if ((Object)(object)_matB != (Object)null) { Object.Destroy((Object)(object)_matB); } } public void Show(IReadOnlyList spawns, int count) { //IL_0015: 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) EnsurePool(); for (int i = 0; i < count && i < spawns.Count; i++) { PlaceSphere(i, spawns[i].position, spawns[i].eulerAngles.y); } for (int j = 0; j < 4; j++) { bool flag = j < count; if ((Object)(object)_spheres[j] != (Object)null) { _spheres[j].SetActive(flag); } if ((Object)(object)_beams[j] != (Object)null) { ((Renderer)_beams[j]).enabled = flag; } } } public void Hide() { for (int i = 0; i < 4; i++) { if ((Object)(object)_spheres[i] != (Object)null) { _spheres[i].SetActive(false); } if ((Object)(object)_beams[i] != (Object)null) { ((Renderer)_beams[i]).enabled = false; } } } public void SetBeamLength(float length) { //IL_0020: 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) for (int i = 0; i < 4; i++) { if ((Object)(object)_beams[i] != (Object)null) { _beams[i].SetPosition(1, Vector3.up * length); } } } public void SetColors(Color teamA, Color teamB) { //IL_003a: 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) if ((Object)(object)_matA != (Object)null) { Object.Destroy((Object)(object)_matA); } if ((Object)(object)_matB != (Object)null) { Object.Destroy((Object)(object)_matB); } _matA = MakeMaterial(teamA); _matB = MakeMaterial(teamB); for (int i = 0; i < 4; i++) { if (!((Object)(object)_spheres[i] == (Object)null)) { Material val = ((i == 0 || i == 2) ? _matA : _matB); Renderer component = _spheres[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 EnsurePool() { for (int i = 0; i < 4; i++) { if ((Object)(object)_spheres[i] == (Object)null || (Object)(object)_beams[i] == (Object)null) { BuildPool(); break; } } } private void BuildPool() { //IL_0016: 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) DestroyPool(); if (_matA == null) { _matA = MakeMaterial(Configs.TeamAColor.Value); } if (_matB == null) { _matB = MakeMaterial(Configs.TeamBColor.Value); } CreateSphere(0, "Spawnpoint_A1", _matA); CreateSphere(1, "Spawnpoint_B1", _matB); CreateSphere(2, "Spawnpoint_A2", _matA); CreateSphere(3, "Spawnpoint_B2", _matB); } private void DestroyPool() { for (int i = 0; i < 4; i++) { if ((Object)(object)_spheres[i] != (Object)null) { Object.Destroy((Object)(object)_spheres[i]); } _spheres[i] = null; _beams[i] = null; } } private void CreateSphere(int slot, string objectName, Material mat) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_008e: Expected O, but got Unknown //IL_00ba: 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_00d6: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.CreatePrimitive((PrimitiveType)0); ((Object)val).name = objectName; ((Object)val).hideFlags = (HideFlags)52; val.transform.SetParent(((Component)this).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(objectName + "_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 * Configs.BeamLength.Value); val3.startWidth = 0.15f; val3.endWidth = 0.15f; ((Renderer)val3).material = mat; val.SetActive(false); _spheres[slot] = val; _beams[slot] = val3; } private void PlaceSphere(int slot, Vector3 pos, float yaw) { //IL_001d: 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_0032: 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) GameObject val = _spheres[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); } } private static Material MakeMaterial(Color color) { //IL_000a: 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_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return new Material(Shader.Find("Unlit/Color")) { color = color }; } } }