using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("HowToRounds")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.17.6.0")] [assembly: AssemblyInformationalVersion("0.17.6")] [assembly: AssemblyProduct("HowToRounds")] [assembly: AssemblyTitle("HowToRounds")] [assembly: AssemblyVersion("0.17.6.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 HowToRoundsMod { internal sealed class AmmoHud : MonoBehaviour { private GameObject _canvasObject; private TextMeshProUGUI _ammoText; private TextMeshProUGUI _reloadText; private Image _reloadFill; private void Update() { //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) if (!RoundUpgradeEffects.ModeActive || RoundUpgradeEffects.LocalEliminated) { SetVisible(visible: false); return; } Player localPlayer = Player.LocalPlayer; Weapon val = (((Object)(object)localPlayer != (Object)null && (Object)(object)localPlayer.Holding != (Object)null && (Object)(object)localPlayer.Holding.HeldItem != (Object)null) ? localPlayer.Holding.HeldItem.Weapon : null); if ((Object)(object)val == (Object)null || ((Object)val).name.IndexOf("pistol", StringComparison.OrdinalIgnoreCase) < 0) { SetVisible(visible: false); return; } EnsureUi(); SetVisible(visible: true); int num = (((Object)(object)val.Attachments != (Object)null) ? val.Attachments.AmmoPerMag : 0); ((TMP_Text)_ammoText).text = val.Ammo + " / " + num; bool flag = (bool)(AccessTools.Field(typeof(Weapon), "_isReloading")?.GetValue(val) ?? ((object)false)); float num2 = (flag ? GetReloadProgress(val) : 0f); _reloadFill.fillAmount = num2; ((TMP_Text)_reloadText).text = (flag ? ("RELOADING " + Mathf.RoundToInt(num2 * 100f) + "%") : "READY"); ((Graphic)_reloadText).color = (flag ? new Color(0.2f, 0.85f, 1f) : new Color(0.78f, 0.84f, 0.92f)); } private static float GetReloadProgress(Weapon weapon) { try { object obj = AccessTools.Field(typeof(Tool), "_anim")?.GetValue(weapon); string text = AccessTools.Field(typeof(Weapon), "_activeReloadAnimName")?.GetValue(weapon) as string; if (obj == null || string.IsNullOrEmpty(text)) { return 0f; } object obj2 = obj.GetType().GetProperty("Item")?.GetValue(obj, new object[1] { text }); if (obj2 == null) { return 0f; } object obj3 = obj2.GetType().GetProperty("normalizedTime")?.GetValue(obj2, null); return (obj3 != null) ? Mathf.Clamp01(Convert.ToSingle(obj3)) : 0f; } catch { return 0f; } } private void EnsureUi() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_009a: 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_00d8: 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_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: 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_0116: Unknown result type (might be due to invalid IL or missing references) //IL_012b: 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_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_022d: 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_0254: Unknown result type (might be due to invalid IL or missing references) //IL_025b: 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_0282: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Expected O, but got Unknown //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Unknown result type (might be due to invalid IL or missing references) //IL_039c: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_canvasObject != (Object)null)) { TMP_Text val = Object.FindObjectOfType(); TMP_FontAsset font = (((Object)(object)val != (Object)null) ? val.font : null); _canvasObject = new GameObject("HowToRounds_AmmoHud", new Type[1] { typeof(RectTransform) }); _canvasObject.transform.SetParent(((Component)this).transform, false); Canvas obj = _canvasObject.AddComponent(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 32060; CanvasScaler obj2 = _canvasObject.AddComponent(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = new Vector2(1920f, 1080f); GameObject val2 = new GameObject("Panel", new Type[1] { typeof(RectTransform) }); val2.transform.SetParent(_canvasObject.transform, false); RectTransform component = val2.GetComponent(); Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(1f, 0f); component.pivot = val3; Vector2 val4 = (component.anchorMin = (component.anchorMax = val3)); component.anchoredPosition = new Vector2(-32f, 42f); component.sizeDelta = new Vector2(270f, 118f); ((Graphic)val2.AddComponent()).color = new Color(0.1f, 0.17f, 0.29f, 0.94f); Outline obj3 = val2.AddComponent(); ((Shadow)obj3).effectColor = new Color(0.92f, 0.95f, 1f, 0.95f); ((Shadow)obj3).effectDistance = new Vector2(2f, -2f); AddText((Transform)(object)component, "AMMO", 19f, new Color(0.7f, 0.78f, 0.89f), new Vector2(0f, 42f), new Vector2(240f, 28f), font, out var _); AddText((Transform)(object)component, "3 / 3", 38f, Color.white, new Vector2(0f, 10f), new Vector2(240f, 46f), font, out _ammoText); GameObject val7 = new GameObject("ReloadTrack", new Type[1] { typeof(RectTransform) }); val7.transform.SetParent((Transform)(object)component, false); RectTransform component2 = val7.GetComponent(); ((Vector2)(ref val4))..ctor(0.5f, 0.5f); component2.anchorMax = val4; component2.anchorMin = val4; component2.anchoredPosition = new Vector2(0f, -27f); component2.sizeDelta = new Vector2(226f, 11f); ((Graphic)val7.AddComponent()).color = new Color(0.025f, 0.05f, 0.09f, 0.95f); GameObject val8 = new GameObject("Fill", new Type[1] { typeof(RectTransform) }); val8.transform.SetParent((Transform)(object)component2, false); RectTransform component3 = val8.GetComponent(); component3.anchorMin = Vector2.zero; component3.anchorMax = Vector2.one; val4 = (component3.offsetMin = (component3.offsetMax = Vector2.zero)); _reloadFill = val8.AddComponent(); ((Graphic)_reloadFill).color = new Color(0.12f, 0.78f, 1f, 1f); _reloadFill.type = (Type)3; _reloadFill.fillMethod = (FillMethod)0; _reloadFill.fillOrigin = 0; _reloadFill.fillAmount = 0f; AddText((Transform)(object)component, "READY", 16f, new Color(0.78f, 0.84f, 0.92f), new Vector2(0f, -46f), new Vector2(240f, 25f), font, out _reloadText); } } private static void AddText(Transform parent, string value, float size, Color color, Vector2 position, Vector2 dimensions, TMP_FontAsset font, out TextMeshProUGUI text) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0040: 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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(value, new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent(); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0.5f, 0.5f); component.anchorMax = val2; component.anchorMin = val2; component.anchoredPosition = position; component.sizeDelta = dimensions; text = val.AddComponent(); if ((Object)(object)font != (Object)null) { ((TMP_Text)text).font = font; } ((TMP_Text)text).text = value; ((TMP_Text)text).fontSize = size; ((Graphic)text).color = color; ((TMP_Text)text).alignment = (TextAlignmentOptions)514; ((Graphic)text).raycastTarget = false; } private void SetVisible(bool visible) { if ((Object)(object)_canvasObject != (Object)null && _canvasObject.activeSelf != visible) { _canvasObject.SetActive(visible); } } } internal sealed class ArenaRuntime { private static readonly Vector3 ArenaOrigin = new Vector3(0f, 750f, 0f); private readonly Plugin _plugin; private AssetBundle _bundle; private GameObject _arena; private Transform[] _spawns; private Collider _killVolume; private CSteamID _lobby; private Vector3 _localSpawnPosition; private float _localSpawnYaw; private float _killPlaneY; private bool _deploymentStarted; private bool _ready; private UpgradeDraft _draft; private readonly List _members = new List(); private bool _isHost; private int _localSlot = -1; private string _roundId = string.Empty; private string _roundState = string.Empty; private bool _preparingRound; private bool _draftFinished; private bool _combatStarted; private bool _localEliminated; private int _lastAliveSlot = -1; private int _upgradeEpoch; private float _nextNetworkPoll; private float _nextVitalsRefresh; private float _roundOverAt; private RoundResultUi _resultUi; private MatchDecisionUi _matchUi; private SpectatorController _spectator; private string _arenaId = "arena03"; private string _arenaName = "Arena03"; private const string RoundIdKey = "htr_round_id"; private const string RoundStateKey = "htr_round_state"; private const string RoundNumberKey = "htr_round_number"; private const string EligibleKey = "htr_round_eligible"; private const string WinnerKey = "htr_round_winner"; private const string UpgradeEpochKey = "htr_upgrade_epoch"; private const int WinsPerMatch = 10; internal ArenaRuntime(Plugin plugin) { _plugin = plugin; } internal void Begin(CSteamID lobby) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) _lobby = lobby; if (!_deploymentStarted) { _arenaId = NormalizeArenaId(SteamMatchmaking.GetLobbyData(lobby, "htr_arena")); _arenaName = DisplayName(_arenaId); _deploymentStarted = true; RoundUpgradeEffects.ModeActive = true; ((MonoBehaviour)_plugin).StartCoroutine(DeployWhenPlayerExists()); } } internal void Tick() { //IL_0077: Unknown result type (might be due to invalid IL or missing references) _draft?.Tick(); RoundUpgradeEffects.Tick(); if (!_ready || (Object)(object)Player.LocalPlayer == (Object)null) { return; } if (_roundState == "combat") { CheckLocalElimination(); } if (_draft != null && _draft.IsComplete && !_draftFinished) { _draftFinished = true; StartCombatLocally(); if (_isHost) { SteamMatchmaking.SetLobbyData(_lobby, "htr_round_state", "combat"); } } if (!(Time.unscaledTime < _nextNetworkPoll)) { _nextNetworkPoll = Time.unscaledTime + 0.1f; RefreshRoundState(); if (_isHost && Time.unscaledTime >= _nextVitalsRefresh) { _nextVitalsRefresh = Time.unscaledTime + 0.5f; RefillVitals(_roundState != "combat"); } if (_isHost && _roundState == "combat") { EvaluateWinner(); } if (_isHost && _roundState == "over" && Time.unscaledTime >= _roundOverAt + 3f) { BeginNextRound(); } } } private IEnumerator DeployWhenPlayerExists() { Plugin.Log.LogInfo((object)("Waiting for the local player before loading " + _arenaName + "...")); while ((Object)(object)Player.LocalPlayer == (Object)null || !((Component)Player.LocalPlayer).gameObject.activeInHierarchy) { yield return (object)new WaitForSecondsRealtime(0.25f); } yield return (object)new WaitForSecondsRealtime(1.25f); if (!LoadArena(_arenaId)) { yield break; } if (_spawns.Length == 0) { Plugin.Log.LogError((object)(_arenaName + " contains no HTR_Spawn_1-4 markers.")); yield break; } int spawnIndex = UpdateLocalSpawn(); Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer != (Object)null) { localPlayer.LocalTeleport(_localSpawnPosition, _localSpawnYaw, true); } yield return (object)new WaitForSecondsRealtime(0.45f); localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer != (Object)null && Vector3.Distance(GetPhysicalPosition(localPlayer), _localSpawnPosition) > 5f) { localPlayer.LocalTeleport(_localSpawnPosition, _localSpawnYaw, true); } if ((Object)(object)localPlayer != (Object)null) { yield return GrantStartingLoadout(localPlayer); } BuildMemberOrder(); _isHost = SteamMatchmaking.GetLobbyOwner(_lobby) == SteamUser.GetSteamID(); _localSlot = _members.IndexOf(SteamUser.GetSteamID()); _ready = true; if (_isHost) { _upgradeEpoch = 0; SteamMatchmaking.SetLobbyData(_lobby, "htr_upgrade_epoch", "0"); ResetScores(); StartRound(1, AllEligible()); } else { _upgradeEpoch = ParseInt(SteamMatchmaking.GetLobbyData(_lobby, "htr_upgrade_epoch"), 0); } Plugin.Log.LogInfo((object)(_arenaName + " ready. Local player assigned to spawn " + (spawnIndex + 1) + ".")); } private IEnumerator GrantStartingLoadout(Player player) { float deadline = Time.unscaledTime + 8f; while (((Object)(object)Server.Instance == (Object)null || (Object)(object)player.Inventory == (Object)null || (Object)(object)player.Holding == (Object)null) && Time.unscaledTime < deadline) { yield return (object)new WaitForSecondsRealtime(0.1f); } if ((Object)(object)Server.Instance == (Object)null || (Object)(object)player.Inventory == (Object)null || (Object)(object)player.Holding == (Object)null) { Plugin.Log.LogError((object)"Could not grant the starting loadout because the player network objects were not ready."); yield break; } Item spawnable = GameInfo.GetSpawnable("knife"); Item pistolPrefab = GameInfo.GetSpawnable("pistol"); if ((Object)(object)spawnable == (Object)null || (Object)(object)pistolPrefab == (Object)null) { Plugin.Log.LogError((object)("Could not find the vanilla Knife or Pistol prefabs (knife=" + ((Object)(object)spawnable != (Object)null) + ", pistol=" + ((Object)(object)pistolPrefab != (Object)null) + ").")); yield break; } Vector3 itemPosition = _localSpawnPosition + Vector3.up; Item heldItem = player.Holding.HeldItem; Server.Instance.BuyItem(spawnable.ID, player, heldItem, itemPosition, Quaternion.identity, true); deadline = Time.unscaledTime + 5f; while (!IsKnife(player.Holding.HeldItem) && Time.unscaledTime < deadline) { yield return (object)new WaitForSecondsRealtime(0.1f); } Item heldItem2 = player.Holding.HeldItem; if (!IsKnife(heldItem2)) { Plugin.Log.LogError((object)"The server did not equip the free starting Knife in time."); yield break; } Server.Instance.BuyItem(pistolPrefab.ID, player, heldItem2, itemPosition, Quaternion.identity, true); deadline = Time.unscaledTime + 5f; while (!IsPistol(player.Holding.HeldItem) && Time.unscaledTime < deadline) { yield return (object)new WaitForSecondsRealtime(0.1f); } if (!IsPistol(player.Holding.HeldItem)) { Plugin.Log.LogError((object)"The server did not equip the free starting Pistol in time."); } else { Plugin.Log.LogInfo((object)"Starting loadout granted: Pistol equipped and Knife stored in the inventory."); } } private static bool IsKnife(Item item) { if ((Object)(object)item != (Object)null && (Object)(object)item.Melee != (Object)null) { return ((Object)item).name.IndexOf("knife", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static bool IsPistol(Item item) { if ((Object)(object)item != (Object)null && (Object)(object)item.Weapon != (Object)null) { return ((Object)item).name.IndexOf("pistol", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private bool LoadArena(string requestedArenaId) { //IL_014e: 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) string text = NormalizeArenaId(requestedArenaId); if ((Object)(object)_arena != (Object)null && (Object)(object)_bundle != (Object)null && text == _arenaId) { return true; } try { string text2 = Path.GetDirectoryName(((BaseUnityPlugin)_plugin).Info.Location); string path = "howtorounds_" + text; if (text2 == null) { text2 = string.Empty; } string text3 = Path.Combine(text2, path); if (!File.Exists(text3)) { Plugin.Log.LogError((object)("Arena bundle was not found: " + text3)); return false; } AssetBundle val = AssetBundle.LoadFromFile(text3); if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)("Unity could not load the " + DisplayName(text) + " AssetBundle.")); return false; } GameObject val2 = val.LoadAsset("assets/howtorounds/prefabs/" + text + ".prefab"); if ((Object)(object)val2 == (Object)null) { string[] allAssetNames = val.GetAllAssetNames(); foreach (string text4 in allAssetNames) { val2 = val.LoadAsset(text4); if ((Object)(object)val2 != (Object)null) { break; } } } if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogError((object)(DisplayName(text) + " prefab was not present in the AssetBundle.")); val.Unload(true); return false; } GameObject val3 = Object.Instantiate(val2, ArenaOrigin, Quaternion.identity); if ((Object)(object)val3 == (Object)null) { Plugin.Log.LogError((object)(DisplayName(text) + " could not be instantiated.")); val.Unload(true); return false; } GameObject arena = _arena; AssetBundle bundle = _bundle; _arenaId = text; _arenaName = DisplayName(text); _arena = val3; _bundle = val; ((Object)_arena).name = "HowToRounds_" + _arenaName + "_Runtime"; Object.DontDestroyOnLoad((Object)(object)_arena); ConfigureLevelSurfaces(); ResolveArenaMarkers(); if ((Object)(object)arena != (Object)null) { Object.Destroy((Object)(object)arena); } if ((Object)(object)bundle != (Object)null) { bundle.Unload(false); } Plugin.Log.LogInfo((object)("Loaded " + _arenaName + " for round " + CurrentRoundNumber() + ".")); return true; } catch (Exception ex) { Plugin.Log.LogError((object)(_arenaName + " loading failed: " + ex)); return false; } } private void ConfigureLevelSurfaces() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //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) LayerMask val = GameInfo.LevelLayer; int value = ((LayerMask)(ref val)).value; int num = FirstLayerInMask(value); if (num < 0) { Plugin.Log.LogWarning((object)"GameInfo.LevelLayer is empty; arena surfaces could not be marked as jumpable."); return; } int num2 = 0; Collider[] componentsInChildren = _arena.GetComponentsInChildren(true); foreach (Collider val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null) && !val2.isTrigger) { GameObject gameObject = ((Component)val2).gameObject; gameObject.layer = num; try { gameObject.tag = "Level"; } catch (UnityException ex) { UnityException ex2 = ex; Plugin.Log.LogWarning((object)("Could not tag arena surface as Level: " + ((Exception)(object)ex2).Message)); } num2++; } } ManualLogSource log = Plugin.Log; string[] obj = new string[9] { "Configured ", num2.ToString(), " arena colliders on Level layer ", num.ToString(), " (LevelMask=", value.ToString(), ", CanJumpOnLayers=", null, null }; val = GameInfo.CanJumpOnLayers; obj[7] = ((LayerMask)(ref val)).value.ToString(); obj[8] = ")."; log.LogInfo((object)string.Concat(obj)); } private static int FirstLayerInMask(int mask) { for (int i = 0; i < 32; i++) { if ((mask & (1 << i)) != 0) { return i; } } return -1; } private void ResolveArenaMarkers() { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: 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) _killVolume = null; List list = new List(4); Transform[] componentsInChildren = _arena.GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if (((Object)val).name.StartsWith("HTR_Spawn_", StringComparison.Ordinal)) { list.Add(val); } else if (((Object)val).name == "HTR_KillVolume") { _killVolume = ((Component)val).GetComponent(); } } list.Sort((Transform left, Transform right) => string.CompareOrdinal(((Object)left).name, ((Object)right).name)); _spawns = list.ToArray(); if ((Object)(object)_killVolume != (Object)null) { Bounds bounds = _killVolume.bounds; _killPlaneY = ((Bounds)(ref bounds)).max.y; } else { _killPlaneY = ArenaOrigin.y - 20f; Plugin.Log.LogWarning((object)(_arenaName + " has no collider named HTR_KillVolume; only the fallback height check will work.")); } } private int UpdateLocalSpawn() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_0033: 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) int num = ResolveLocalSpawnIndex(_spawns.Length); Transform val = _spawns[num]; _localSpawnPosition = val.position + Vector3.up * 0.15f; _localSpawnYaw = val.eulerAngles.y; return num; } private static string NormalizeArenaId(string arenaId) { if (!TryNormalizeArenaId(arenaId, out var normalized)) { return "arena03"; } return normalized; } internal static string DisplayName(string arenaId) { string text = NormalizeArenaId(arenaId); return "Arena" + text.Substring(5); } private static bool TryNormalizeArenaId(string arenaId, out string normalized) { normalized = null; if (string.IsNullOrEmpty(arenaId)) { return false; } string text = arenaId.Trim().ToLowerInvariant(); if (!text.StartsWith("arena", StringComparison.Ordinal) || text.Length < 7) { return false; } for (int i = 5; i < text.Length; i++) { if (!char.IsDigit(text[i])) { return false; } } if (!int.TryParse(text.Substring(5), out var result) || result < 3) { return false; } normalized = "arena" + result.ToString("D2"); return true; } internal static List FindInstalledArenas(string pluginDirectory) { List list = new List(); if (string.IsNullOrEmpty(pluginDirectory) || !Directory.Exists(pluginDirectory)) { return list; } string[] files = Directory.GetFiles(pluginDirectory, "howtorounds_arena*"); for (int i = 0; i < files.Length; i++) { if (TryNormalizeArenaId(Path.GetFileName(files[i]).Substring("howtorounds_".Length), out var normalized) && !list.Contains(normalized)) { list.Add(normalized); } } list.Sort((string left, string right) => int.Parse(left.Substring(5)).CompareTo(int.Parse(right.Substring(5)))); return list; } private int ResolveLocalSpawnIndex(int spawnCount) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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_0013: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_004e: Unknown result type (might be due to invalid IL or missing references) try { CSteamID steamID = SteamUser.GetSteamID(); CSteamID lobbyOwner = SteamMatchmaking.GetLobbyOwner(_lobby); if (steamID == lobbyOwner) { return 0; } int num = 1; int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(_lobby); for (int i = 0; i < numLobbyMembers; i++) { CSteamID lobbyMemberByIndex = SteamMatchmaking.GetLobbyMemberByIndex(_lobby, i); if (!(lobbyMemberByIndex == lobbyOwner)) { if (lobbyMemberByIndex == steamID) { return num % spawnCount; } num++; } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not resolve the Steam spawn slot: " + ex.Message)); } return 0; } private void BuildMemberOrder() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //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_0017: 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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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_0047: 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_0049: 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) _members.Clear(); CSteamID lobbyOwner = SteamMatchmaking.GetLobbyOwner(_lobby); if (lobbyOwner.m_SteamID != 0L) { _members.Add(lobbyOwner); } int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(_lobby); for (int i = 0; i < numLobbyMembers; i++) { CSteamID lobbyMemberByIndex = SteamMatchmaking.GetLobbyMemberByIndex(_lobby, i); if (lobbyMemberByIndex != lobbyOwner) { _members.Add(lobbyMemberByIndex); } } } private bool[] AllEligible() { bool[] array = new bool[_members.Count]; for (int i = 0; i < array.Length; i++) { array[i] = true; } return array; } private void StartRound(int number, bool[] eligible) { //IL_0076: 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_00a0: 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_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) string text = (string.IsNullOrEmpty(_roundId) ? _arenaId : SelectArenaForNextRound()); string text2 = text + ":" + number + "-" + SteamUtils.GetServerRealTime() + "-" + Random.Range(100, 999); SteamMatchmaking.SetLobbyData(_lobby, "htr_arena", text); SteamMatchmaking.SetLobbyData(_lobby, "htr_round_number", number.ToString()); SteamMatchmaking.SetLobbyData(_lobby, "htr_round_eligible", EncodeEligible(eligible)); SteamMatchmaking.SetLobbyData(_lobby, "htr_round_winner", "-1"); SteamMatchmaking.SetLobbyData(_lobby, "htr_round_id", text2); SteamMatchmaking.SetLobbyData(_lobby, "htr_round_state", "draft"); ObserveNewRound(text2, eligible); } private void RefreshRoundState() { //IL_0001: 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_003e: 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) int num = ParseInt(SteamMatchmaking.GetLobbyData(_lobby, "htr_upgrade_epoch"), 0); if (num != _upgradeEpoch) { _upgradeEpoch = num; RoundUpgradeEffects.ResetAllUpgrades(); } string lobbyData = SteamMatchmaking.GetLobbyData(_lobby, "htr_round_id"); string lobbyData2 = SteamMatchmaking.GetLobbyData(_lobby, "htr_round_state"); if (!string.IsNullOrEmpty(lobbyData) && lobbyData != _roundId) { ObserveNewRound(lobbyData, DecodeEligible(SteamMatchmaking.GetLobbyData(_lobby, "htr_round_eligible"))); } if (!(lobbyData2 == _roundState)) { _roundState = lobbyData2; switch (lobbyData2) { case "combat": StartCombatLocally(); break; case "over": ShowRoundResult(); break; case "match_over": ShowMatchResult(); break; } } } private void ObserveNewRound(string id, bool[] eligible) { _roundId = id; _roundState = "draft"; _draft = null; _draftFinished = false; _combatStarted = false; _localEliminated = false; _lastAliveSlot = -1; _preparingRound = true; RoundUpgradeEffects.LocalEliminated = false; StopSpectating(); RoundUpgradeEffects.ResetProjectileTracking(); if ((Object)(object)_resultUi != (Object)null) { Object.Destroy((Object)(object)((Component)_resultUi).gameObject); } if ((Object)(object)_matchUi != (Object)null) { Object.Destroy((Object)(object)((Component)_matchUi).gameObject); } string roundArenaId = ArenaIdFromRoundId(id); ((MonoBehaviour)_plugin).StartCoroutine(PrepareRound(eligible, roundArenaId)); } private IEnumerator PrepareRound(bool[] eligible, string roundArenaId) { Player local = Player.LocalPlayer; RoundUpgradeEffects.SelectionActive = true; RoundUpgradeEffects.AllowRoundRespawn = true; if ((Object)(object)local != (Object)null && (Object)(object)local.Rigidbody != (Object)null) { local.Rigidbody.linearVelocity = Vector3.zero; local.Rigidbody.constraints = (RigidbodyConstraints)126; } if (!LoadArena(roundArenaId)) { RoundUpgradeEffects.AllowRoundRespawn = false; _preparingRound = false; yield break; } if (_spawns.Length == 0) { Plugin.Log.LogError((object)(_arenaName + " contains no HTR_Spawn_1-4 markers.")); RoundUpgradeEffects.AllowRoundRespawn = false; _preparingRound = false; yield break; } UpdateLocalSpawn(); if ((Object)(object)local != (Object)null && (Object)(object)local.Dying != (Object)null && local.Dying.IsDead && (Object)(object)Server.Instance != (Object)null) { Server.Instance.RespawnPlayer(local, _localSpawnPosition, Quaternion.Euler(0f, _localSpawnYaw, 0f)); float deadline = Time.unscaledTime + 6f; while (local.Dying.IsDead && Time.unscaledTime < deadline) { yield return (object)new WaitForSecondsRealtime(0.1f); } } RoundUpgradeEffects.AllowRoundRespawn = false; local = Player.LocalPlayer; if ((Object)(object)local != (Object)null) { local.LocalTeleport(_localSpawnPosition, _localSpawnYaw, true); if ((Object)(object)local.Rigidbody != (Object)null) { local.Rigidbody.linearVelocity = Vector3.zero; local.Rigidbody.constraints = (RigidbodyConstraints)126; } if (!IsPistol(((Object)(object)local.Holding != (Object)null) ? local.Holding.HeldItem : null)) { yield return GrantStartingLoadout(local); } } _draft = new UpgradeDraft(_lobby, eligible); _draft.Begin(); _preparingRound = false; SteamMatchmaking.SetLobbyMemberData(_lobby, "htr_life", _roundId + ":alive"); } private string SelectArenaForNextRound() { List list = FindInstalledArenas(Path.GetDirectoryName(((BaseUnityPlugin)_plugin).Info.Location) ?? string.Empty); if (list.Count == 0) { return _arenaId; } if (list.Count == 1) { return list[0]; } list.Remove(_arenaId); return list[Random.Range(0, list.Count)]; } private string ArenaIdFromRoundId(string roundId) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) int num = (string.IsNullOrEmpty(roundId) ? (-1) : roundId.IndexOf(':')); if (num > 0) { return NormalizeArenaId(roundId.Substring(0, num)); } return NormalizeArenaId(SteamMatchmaking.GetLobbyData(_lobby, "htr_arena")); } private void StartCombatLocally() { //IL_0079: 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) if (_combatStarted || _preparingRound) { return; } _combatStarted = true; _roundState = "combat"; _localEliminated = false; RoundUpgradeEffects.SelectionActive = false; RoundUpgradeEffects.LocalEliminated = false; Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer != (Object)null) { localPlayer.LocalTeleport(_localSpawnPosition, _localSpawnYaw, true); if ((Object)(object)localPlayer.Rigidbody != (Object)null) { localPlayer.Rigidbody.constraints = (RigidbodyConstraints)112; } } RoundUpgradeEffects.RefillLocalPistol(); SteamMatchmaking.SetLobbyMemberData(_lobby, "htr_life", _roundId + ":alive"); if (_isHost) { RefillVitals(includeHealth: true); } } private void CheckLocalElimination() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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_0060: 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_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) if (_localEliminated) { return; } Player localPlayer = Player.LocalPlayer; bool flag = (Object)(object)localPlayer.Dying != (Object)null && localPlayer.Dying.IsDead; bool flag2 = GetPhysicalPosition(localPlayer).y < _killPlaneY; if (flag || flag2) { if (flag2 && !flag && (Object)(object)Server.Instance != (Object)null) { Vector3 physicalPosition = GetPhysicalPosition(localPlayer); Server.Instance.HitPlayer(localPlayer, 10000, Vector3.down * 10f, physicalPosition, (byte)0, (Player)null); } _localEliminated = true; RoundUpgradeEffects.LocalEliminated = true; BeginSpectating(); SteamMatchmaking.SetLobbyMemberData(_lobby, "htr_life", _roundId + ":dead"); if ((Object)(object)localPlayer.Rigidbody != (Object)null) { localPlayer.Rigidbody.linearVelocity = Vector3.zero; localPlayer.Rigidbody.constraints = (RigidbodyConstraints)126; } Plugin.Log.LogInfo((object)("Local player eliminated from round " + CurrentRoundNumber() + ".")); } } private void EvaluateWinner() { //IL_000a: 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_009e: 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) int num = 0; int num2 = -1; for (int i = 0; i < _members.Count; i++) { if (!(SteamMatchmaking.GetLobbyMemberData(_lobby, _members[i], "htr_life") == _roundId + ":dead")) { num++; num2 = i; } } if (num == 1) { _lastAliveSlot = num2; } if (_members.Count >= 2 && num <= 1) { int num3 = ((num == 1) ? num2 : _lastAliveSlot); if (num3 < 0) { num3 = 0; } int num4 = GetWins(num3) + 1; SetWins(num3, num4); SteamMatchmaking.SetLobbyData(_lobby, "htr_round_winner", num3.ToString()); string text = ((num4 >= 10) ? "match_over" : "over"); SteamMatchmaking.SetLobbyData(_lobby, "htr_round_state", text); _roundState = text; _roundOverAt = Time.unscaledTime; if (text == "match_over") { ShowMatchResult(); } else { ShowRoundResult(); } } } private void ShowRoundResult() { //IL_0018: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_0072: 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) _roundOverAt = Time.unscaledTime; RoundUpgradeEffects.SelectionActive = true; StopSpectating(); int num = ParseInt(SteamMatchmaking.GetLobbyData(_lobby, "htr_round_winner"), -1); string winner = ((num >= 0 && num < _members.Count) ? SteamFriends.GetFriendPersonaName(_members[num]) : "PLAYER"); if (num >= 0 && num < _members.Count && _members[num] == SteamUser.GetSteamID()) { winner = SteamFriends.GetPersonaName(); } GameObject val = new GameObject("HowToRounds_RoundResult"); Object.DontDestroyOnLoad((Object)(object)val); _resultUi = val.AddComponent(); _resultUi.Build(winner, CurrentRoundNumber(), GetWins(num), 10); } private void ShowMatchResult() { //IL_0056: 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_007f: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) RoundUpgradeEffects.SelectionActive = true; StopSpectating(); Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer != (Object)null && (Object)(object)localPlayer.Rigidbody != (Object)null) { localPlayer.Rigidbody.linearVelocity = Vector3.zero; localPlayer.Rigidbody.constraints = (RigidbodyConstraints)126; } if (!((Object)(object)_matchUi != (Object)null)) { int slot = ParseInt(SteamMatchmaking.GetLobbyData(_lobby, "htr_round_winner"), -1); string winner = MemberName(slot); GameObject val = new GameObject("HowToRounds_MatchDecision"); Object.DontDestroyOnLoad((Object)(object)val); _matchUi = val.AddComponent(); _matchUi.Build(winner, _isHost, ContinueMatch, RestartMatch); } } private void ContinueMatch() { if (_isHost && !(_roundState != "match_over")) { ResetScores(); StartRound(CurrentRoundNumber() + 1, AllEligible()); } } private void RestartMatch() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (_isHost && !(_roundState != "match_over")) { _upgradeEpoch++; SteamMatchmaking.SetLobbyData(_lobby, "htr_upgrade_epoch", _upgradeEpoch.ToString()); RoundUpgradeEffects.ResetAllUpgrades(); ResetScores(); StartRound(1, AllEligible()); } } private string MemberName(int slot) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (slot < 0 || slot >= _members.Count) { return "PLAYER"; } if (_members[slot] == SteamUser.GetSteamID()) { return SteamFriends.GetPersonaName(); } string friendPersonaName = SteamFriends.GetFriendPersonaName(_members[slot]); if (!string.IsNullOrWhiteSpace(friendPersonaName) && !(friendPersonaName == "[unknown]")) { return friendPersonaName; } return "PLAYER " + (slot + 1); } private int GetWins(int slot) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return ParseInt(SteamMatchmaking.GetLobbyData(_lobby, "htr_wins_" + slot), 0); } private void SetWins(int slot, int wins) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) SteamMatchmaking.SetLobbyData(_lobby, "htr_wins_" + slot, Mathf.Max(0, wins).ToString()); } private void ResetScores() { for (int i = 0; i < _members.Count; i++) { SetWins(i, 0); } } private void BeginSpectating() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_spectator != (Object)null)) { GameObject val = new GameObject("HowToRounds_Spectator"); Object.DontDestroyOnLoad((Object)(object)val); _spectator = val.AddComponent(); _spectator.Begin(ArenaOrigin); } } private void StopSpectating() { if (!((Object)(object)_spectator == (Object)null)) { Object.Destroy((Object)(object)((Component)_spectator).gameObject); _spectator = null; } } private void BeginNextRound() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) int num = ParseInt(SteamMatchmaking.GetLobbyData(_lobby, "htr_round_winner"), -1); bool[] array = AllEligible(); if (num >= 0 && num < array.Length) { array[num] = false; } StartRound(CurrentRoundNumber() + 1, array); } private int CurrentRoundNumber() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return ParseInt(SteamMatchmaking.GetLobbyData(_lobby, "htr_round_number"), 1); } private void RefillVitals(bool includeHealth) { Player[] array = Object.FindObjectsOfType(); foreach (Player val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val.Vitals == (Object)null)) { if (includeHealth) { RoundUpgradeEffects.SetHealthToMaximum(val); } else { RoundUpgradeEffects.ClampHealthToMaximum(val); } val.Vitals.RestoreFullness(100); } } } private static string EncodeEligible(bool[] eligible) { char[] array = new char[eligible.Length]; for (int i = 0; i < array.Length; i++) { array[i] = (eligible[i] ? '1' : '0'); } return new string(array); } private bool[] DecodeEligible(string value) { bool[] array = new bool[_members.Count]; for (int i = 0; i < array.Length; i++) { array[i] = i < value.Length && value[i] == '1'; } return array; } private static int ParseInt(string value, int fallback) { if (!int.TryParse(value, out var result)) { return fallback; } return result; } private static Vector3 GetPhysicalPosition(Player player) { //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)player.Rigidbody != (Object)null)) { return ((Component)player).transform.position; } return player.Rigidbody.position; } } internal sealed class CrosshairHud : MonoBehaviour { private GameObject _canvasObject; private CanvasGroup _canvasGroup; private void Awake() { Build(); } private void Update() { if (!((Object)(object)_canvasGroup == (Object)null)) { bool flag = RoundUpgradeEffects.ModeActive && !RoundUpgradeEffects.SelectionActive && !RoundUpgradeEffects.LocalEliminated && !MainMenuManager.IsInMenu; _canvasGroup.alpha = (flag ? 1f : 0f); } } private void Build() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: 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_00dc: 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_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_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) _canvasObject = new GameObject("HowToRounds_Crosshair"); _canvasObject.transform.SetParent(((Component)this).transform, false); Canvas obj = _canvasObject.AddComponent(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 32060; CanvasScaler obj2 = _canvasObject.AddComponent(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = new Vector2(1920f, 1080f); obj2.matchWidthOrHeight = 0.5f; _canvasGroup = _canvasObject.AddComponent(); _canvasGroup.interactable = false; _canvasGroup.blocksRaycasts = false; _canvasGroup.alpha = 0f; CreateBar("OutlineHorizontal", new Vector2(22f, 4f), Color.black); CreateBar("OutlineVertical", new Vector2(4f, 22f), Color.black); CreateBar("Horizontal", new Vector2(18f, 2f), Color.white); CreateBar("Vertical", new Vector2(2f, 18f), Color.white); } private void CreateBar(string name, Vector2 size, Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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_0079: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(_canvasObject.transform, false); RectTransform obj = val.AddComponent(); obj.anchorMin = new Vector2(0.5f, 0.5f); obj.anchorMax = new Vector2(0.5f, 0.5f); obj.pivot = new Vector2(0.5f, 0.5f); obj.anchoredPosition = Vector2.zero; obj.sizeDelta = size; Image obj2 = val.AddComponent(); ((Graphic)obj2).color = color; ((Graphic)obj2).raycastTarget = false; } private void OnDestroy() { if ((Object)(object)_canvasObject != (Object)null) { Object.Destroy((Object)(object)_canvasObject); } } } internal sealed class PlayerHealthHud : MonoBehaviour { private sealed class Bar { internal GameObject Root; internal RectTransform Rect; internal Image Fill; internal TextMeshProUGUI Value; internal float Displayed = 1f; } private readonly Dictionary _worldBars = new Dictionary(); private readonly List _remove = new List(); private GameObject _canvasObject; private RectTransform _canvasRect; private Bar _localBar; private TMP_FontAsset _font; private VitalsUI _nativeVitals; private bool _nativeVitalsWasActive; private float _nextPlayerRefresh; private void Update() { if (!RoundUpgradeEffects.ModeActive) { SetCanvasVisible(visible: false); RestoreNativeVitals(); return; } HideNativeVitals(); EnsureCanvas(); SetCanvasVisible(visible: true); UpdateLocalBar(); if (Time.unscaledTime >= _nextPlayerRefresh) { _nextPlayerRefresh = Time.unscaledTime + 0.25f; RefreshPlayers(); } UpdateWorldBars(); } private void OnDestroy() { RestoreNativeVitals(); } private void HideNativeVitals() { if ((Object)(object)_nativeVitals == (Object)null) { _nativeVitals = Object.FindObjectOfType(); if ((Object)(object)_nativeVitals != (Object)null) { _nativeVitalsWasActive = ((Component)_nativeVitals).gameObject.activeSelf; } } if ((Object)(object)_nativeVitals != (Object)null && ((Component)_nativeVitals).gameObject.activeSelf) { ((Component)_nativeVitals).gameObject.SetActive(false); } } private void RestoreNativeVitals() { if (!((Object)(object)_nativeVitals == (Object)null)) { if (_nativeVitalsWasActive && !((Component)_nativeVitals).gameObject.activeSelf) { ((Component)_nativeVitals).gameObject.SetActive(true); } _nativeVitals = null; } } private void EnsureCanvas() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: 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_010e: 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) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_canvasObject != (Object)null)) { TMP_Text val = Object.FindObjectOfType(); _font = (((Object)(object)val != (Object)null) ? val.font : null); _canvasObject = new GameObject("HowToRounds_HealthHud", new Type[1] { typeof(RectTransform) }); _canvasObject.transform.SetParent(((Component)this).transform, false); _canvasRect = _canvasObject.GetComponent(); Canvas obj = _canvasObject.AddComponent(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 32055; CanvasScaler obj2 = _canvasObject.AddComponent(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = new Vector2(1920f, 1080f); _localBar = CreateBar((Transform)(object)_canvasRect, "LocalHealth", new Vector2(310f, 78f), local: true); RectTransform rect = _localBar.Rect; RectTransform rect2 = _localBar.Rect; Vector2 val2 = (_localBar.Rect.pivot = Vector2.zero); Vector2 anchorMin = (rect2.anchorMax = val2); rect.anchorMin = anchorMin; _localBar.Rect.anchoredPosition = new Vector2(32f, 42f); } } private void UpdateLocalBar() { Player localPlayer = Player.LocalPlayer; bool flag = (Object)(object)localPlayer != (Object)null && (Object)(object)localPlayer.Vitals != (Object)null && !RoundUpgradeEffects.LocalEliminated; if (_localBar.Root.activeSelf != flag) { _localBar.Root.SetActive(flag); } if (flag) { UpdateBar(_localBar, localPlayer.Vitals.Health, RoundUpgradeEffects.GetMaximumHealth(localPlayer)); } } private void RefreshPlayers() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) HashSet hashSet = new HashSet(); Player[] array = Object.FindObjectsOfType(); foreach (Player val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)Player.LocalPlayer) && !((Object)(object)val.Vitals == (Object)null)) { hashSet.Add(val); if (!_worldBars.ContainsKey(val)) { _worldBars[val] = CreateBar((Transform)(object)_canvasRect, "PlayerHealth", new Vector2(154f, 34f), local: false); } } } _remove.Clear(); foreach (KeyValuePair worldBar in _worldBars) { if ((Object)(object)worldBar.Key == (Object)null || !hashSet.Contains(worldBar.Key)) { _remove.Add(worldBar.Key); } } foreach (Player item in _remove) { if (_worldBars.TryGetValue(item, out var value) && (Object)(object)value.Root != (Object)null) { Object.Destroy((Object)(object)value.Root); } _worldBars.Remove(item); } } private void UpdateWorldBars() { //IL_0083: 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_0088: 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_00af: 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_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_00c0: 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_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014c: 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) Camera main = Camera.main; foreach (KeyValuePair worldBar in _worldBars) { Player key = worldBar.Key; Bar value = worldBar.Value; if ((Object)(object)key == (Object)null || (Object)(object)key.Vitals == (Object)null || (Object)(object)main == (Object)null) { value.Root.SetActive(false); continue; } Vector3 val = (((Object)(object)key.Rigidbody != (Object)null) ? key.Rigidbody.position : ((Component)key).transform.position); float num = Mathf.Pow(0.8f, (float)RoundUpgradeEffects.GetLevel(key, RoundUpgrade.Miniature)); Vector3 val2 = main.WorldToScreenPoint(val + Vector3.up * (2.25f * num)); bool flag = val2.z > 0f && val2.x >= 0f && val2.x <= (float)Screen.width && val2.y >= 0f && val2.y <= (float)Screen.height; if (value.Root.activeSelf != flag) { value.Root.SetActive(flag); } if (flag) { ((Transform)value.Rect).position = new Vector3(val2.x, val2.y, 0f); UpdateBar(value, key.Vitals.Health, RoundUpgradeEffects.GetMaximumHealth(key)); } } } private static void UpdateBar(Bar bar, int health, int maximum) { //IL_005b: 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_0075: Unknown result type (might be due to invalid IL or missing references) maximum = Mathf.Max(1, maximum); int num = Mathf.Clamp(health, 0, maximum); float num2 = (float)num / (float)maximum; bar.Displayed = Mathf.MoveTowards(bar.Displayed, num2, Time.unscaledDeltaTime * 2.5f); bar.Fill.fillAmount = bar.Displayed; ((Graphic)bar.Fill).color = Color.Lerp(new Color(0.95f, 0.18f, 0.14f), new Color(0.18f, 0.86f, 0.42f), num2); ((TMP_Text)bar.Value).text = num + " / " + maximum; } private Bar CreateBar(Transform parent, string name, Vector2 size, bool local) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0065: 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_0079: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: 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_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0173: 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_019d: 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_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Expected O, but got Unknown //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0207: 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_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Expected O, but got Unknown //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03d7: Unknown result type (might be due to invalid IL or missing references) //IL_03e9: Unknown result type (might be due to invalid IL or missing references) //IL_0402: Unknown result type (might be due to invalid IL or missing references) //IL_0409: Unknown result type (might be due to invalid IL or missing references) //IL_041b: Unknown result type (might be due to invalid IL or missing references) //IL_042f: Unknown result type (might be due to invalid IL or missing references) //IL_0490: Unknown result type (might be due to invalid IL or missing references) Bar bar = new Bar(); bar.Root = new GameObject(name, new Type[1] { typeof(RectTransform) }); bar.Root.transform.SetParent(parent, false); bar.Rect = bar.Root.GetComponent(); RectTransform rect = bar.Rect; RectTransform rect2 = bar.Rect; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0.5f, 0.5f); rect2.anchorMax = val; rect.anchorMin = val; bar.Rect.sizeDelta = size; ((Graphic)bar.Root.AddComponent()).color = new Color(0.08f, 0.13f, 0.22f, local ? 0.94f : 0.88f); Outline obj = bar.Root.AddComponent(); ((Shadow)obj).effectColor = new Color(0.92f, 0.95f, 1f, 0.95f); ((Shadow)obj).effectDistance = (local ? new Vector2(2f, -2f) : new Vector2(1f, -1f)); GameObject val2 = new GameObject("Track", new Type[1] { typeof(RectTransform) }); val2.transform.SetParent((Transform)(object)bar.Rect, false); RectTransform component = val2.GetComponent(); ((Vector2)(ref val))..ctor(0.5f, 0.5f); component.anchorMax = val; component.anchorMin = val; component.anchoredPosition = (Vector2)(local ? new Vector2(0f, -12f) : Vector2.zero); component.sizeDelta = (local ? new Vector2(270f, 25f) : new Vector2(140f, 20f)); ((Graphic)val2.AddComponent()).color = new Color(0.025f, 0.04f, 0.07f, 0.98f); GameObject val3 = new GameObject("Fill", new Type[1] { typeof(RectTransform) }); val3.transform.SetParent((Transform)(object)component, false); RectTransform component2 = val3.GetComponent(); component2.anchorMin = Vector2.zero; component2.anchorMax = Vector2.one; val = (component2.offsetMin = (component2.offsetMax = Vector2.zero)); bar.Fill = val3.AddComponent(); ((Graphic)bar.Fill).color = new Color(0.18f, 0.86f, 0.42f); bar.Fill.type = (Type)3; bar.Fill.fillMethod = (FillMethod)0; bar.Fill.fillOrigin = 0; bar.Fill.fillAmount = 1f; GameObject val5 = new GameObject("Value", new Type[1] { typeof(RectTransform) }); val5.transform.SetParent((Transform)(object)bar.Rect, false); RectTransform component3 = val5.GetComponent(); ((Vector2)(ref val))..ctor(0.5f, 0.5f); component3.anchorMax = val; component3.anchorMin = val; component3.anchoredPosition = (Vector2)(local ? new Vector2(0f, -12f) : Vector2.zero); component3.sizeDelta = (local ? new Vector2(280f, 32f) : new Vector2(150f, 26f)); bar.Value = val5.AddComponent(); if ((Object)(object)_font != (Object)null) { ((TMP_Text)bar.Value).font = _font; } ((TMP_Text)bar.Value).text = "100 / 100"; ((TMP_Text)bar.Value).fontSize = (local ? 21f : 15f); ((TMP_Text)bar.Value).fontStyle = (FontStyles)1; ((TMP_Text)bar.Value).alignment = (TextAlignmentOptions)514; ((Graphic)bar.Value).color = Color.white; ((Graphic)bar.Value).raycastTarget = false; if (local) { GameObject val6 = new GameObject("Title", new Type[1] { typeof(RectTransform) }); val6.transform.SetParent((Transform)(object)bar.Rect, false); RectTransform component4 = val6.GetComponent(); ((Vector2)(ref val))..ctor(0.5f, 0.5f); component4.anchorMax = val; component4.anchorMin = val; component4.anchoredPosition = new Vector2(0f, 23f); component4.sizeDelta = new Vector2(280f, 26f); TextMeshProUGUI val7 = val6.AddComponent(); if ((Object)(object)_font != (Object)null) { ((TMP_Text)val7).font = _font; } ((TMP_Text)val7).text = "HEALTH"; ((TMP_Text)val7).fontSize = 18f; ((TMP_Text)val7).alignment = (TextAlignmentOptions)514; ((Graphic)val7).color = new Color(0.72f, 0.81f, 0.92f); ((Graphic)val7).raycastTarget = false; } return bar; } private void SetCanvasVisible(bool visible) { if ((Object)(object)_canvasObject != (Object)null && _canvasObject.activeSelf != visible) { _canvasObject.SetActive(visible); } } } [BepInPlugin("com.reysher.howtofish.howtorounds", "How to ROUNDS", "0.17.6")] public sealed class Plugin : BaseUnityPlugin { internal enum LobbyFlow { None, Creating, Joining, Staging, Starting } internal const string PluginGuid = "com.reysher.howtofish.howtorounds"; internal const string PluginName = "How to ROUNDS"; internal const string PluginVersion = "0.17.6"; internal const string ArenaKey = "htr_arena"; internal static ManualLogSource Log; private RoundsMenuUi _menuUi; private Harmony _harmony; private CallResult _lobbySearchResult; private CSteamID _stagingLobby; private string _requestedRoomCode; private float _nextMenuProbe; private float _nextLobbyRefresh; private ArenaRuntime _arenaRuntime; private int _joinSearchAttempt; internal static Plugin Instance { get; private set; } internal LobbyFlow Flow { get; private set; } private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; _harmony = new Harmony("com.reysher.howtofish.howtorounds"); try { _harmony.PatchAll(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("One or more gameplay patches could not be applied: " + ex)); } ((Component)this).gameObject.AddComponent(); ((Component)this).gameObject.AddComponent(); ((Component)this).gameObject.AddComponent(); _lobbySearchResult = CallResult.Create((APIDispatchDelegate)OnLobbySearchCompleted); Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); ((BaseUnityPlugin)this).Logger.LogInfo((object)"How to ROUNDS staging lobby loaded."); } private void OnDestroy() { RoundUpgradeEffects.ModeActive = false; RoundUpgradeEffects.SelectionActive = false; RoundUpgradeEffects.LocalEliminated = false; Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { if (Time.unscaledTime >= _nextMenuProbe) { _nextMenuProbe = Time.unscaledTime + 0.3f; EnsureMenuUi(); if ((Object)(object)_menuUi != (Object)null) { _menuUi.SetMenuVisible(IsAtMainMenu()); } } if (Flow == LobbyFlow.Starting && _arenaRuntime != null) { _arenaRuntime.Tick(); } if (Flow == LobbyFlow.Staging && Time.unscaledTime >= _nextLobbyRefresh) { _nextLobbyRefresh = Time.unscaledTime + 0.35f; RefreshLobby(); } } private void EnsureMenuUi() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown if (!((Object)(object)_menuUi != (Object)null) && IsAtMainMenu()) { GameObject val = new GameObject("HowToRounds_MenuUi"); Object.DontDestroyOnLoad((Object)(object)val); _menuUi = val.AddComponent(); _menuUi.Initialize(this); } } private static bool IsAtMainMenu() { if (MainMenuManager.IsInMenu) { return (Object)(object)Object.FindObjectOfType() != (Object)null; } return false; } internal bool ShouldInterceptLobbyCreated() { return Flow == LobbyFlow.Creating; } internal bool IsDuplicateStagingEntry(ulong lobbyId) { if (Flow == LobbyFlow.Staging) { return _stagingLobby.m_SteamID == lobbyId; } return false; } internal void CreateRoom() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (Flow != LobbyFlow.None) { return; } try { _menuUi.SetBrowserStatus("Creating Steam room..."); ServerSaveObject curServerSave = SaveManager.CurServerSave; if (curServerSave == null) { SaveManager.CreateServer("How To ROUNDS", true, true, (Difficulty)1); curServerSave = SaveManager.CurServerSave; } if (curServerSave == null) { throw new InvalidOperationException("Could not prepare the How to ROUNDS world."); } curServerSave.UseSteam = true; curServerSave.IsPublic = true; Flow = LobbyFlow.Creating; SteamMatchmaking.CreateLobby((ELobbyType)2, GetMaxPlayers()); } catch (Exception ex) { Flow = LobbyFlow.None; Log.LogError((object)ex); _menuUi.SetBrowserStatus("Could not create the room. Check the console.", error: true); } } internal void JoinRoom(string code) { if (Flow != LobbyFlow.None) { return; } if (!RoomCode.TryNormalize(code, out var code2)) { _menuUi.SetBrowserStatus("Enter a valid 5-character room code.", error: true); return; } try { Flow = LobbyFlow.Joining; _requestedRoomCode = code2; _joinSearchAttempt = 0; _menuUi.SetBrowserStatus("Searching for room " + code2 + "..."); RequestRoomSearch(); } catch (Exception ex) { Flow = LobbyFlow.None; Log.LogError((object)ex); _menuUi.SetBrowserStatus("Could not join the room. Check the code.", error: true); } } private void OnLobbySearchCompleted(LobbyMatchList_t callback, bool ioFailure) { //IL_000d: 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_00c2: 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_0150: Unknown result type (might be due to invalid IL or missing references) if (Flow != LobbyFlow.Joining) { return; } if (ioFailure || callback.m_nLobbiesMatching == 0) { if (!ioFailure && ++_joinSearchAttempt < 4) { _menuUi.SetBrowserStatus("Steam is locating room " + _requestedRoomCode + "... attempt " + (_joinSearchAttempt + 1) + "/4"); ((MonoBehaviour)this).StartCoroutine(RetryRoomSearch()); } else { Flow = LobbyFlow.None; _menuUi.SetBrowserStatus(ioFailure ? "Steam could not search for rooms. Try again." : ("Room " + _requestedRoomCode + " is not visible. Make sure the host uses mod 0.17.6."), error: true); } return; } CSteamID lobbyByIndex = SteamMatchmaking.GetLobbyByIndex(0); if (lobbyByIndex.m_SteamID == 0L) { Flow = LobbyFlow.None; _menuUi.SetBrowserStatus("Steam returned an invalid room.", error: true); return; } string lobbyData = SteamMatchmaking.GetLobbyData(lobbyByIndex, "how_to_rounds"); if (lobbyData != "0.17.6") { Flow = LobbyFlow.None; _menuUi.SetBrowserStatus("Room found, but versions differ (host " + (string.IsNullOrEmpty(lobbyData) ? "unknown" : lobbyData) + ", you 0.17.6).", error: true); } else { _menuUi.SetBrowserStatus("Joining room " + _requestedRoomCode + "..."); SteamManager.JoinLobby(lobbyByIndex.m_SteamID); } } private void RequestRoomSearch() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) SteamMatchmaking.AddRequestLobbyListStringFilter("htr_code", _requestedRoomCode, (ELobbyComparison)0); SteamMatchmaking.AddRequestLobbyListDistanceFilter((ELobbyDistanceFilter)3); _lobbySearchResult.Set(SteamMatchmaking.RequestLobbyList(), (APIDispatchDelegate)null); } private IEnumerator RetryRoomSearch() { yield return (object)new WaitForSecondsRealtime(1.2f); if (Flow == LobbyFlow.Joining) { RequestRoomSearch(); } } internal void OnLobbyCreated(LobbyCreated_t callback) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0009: 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_0031: Unknown result type (might be due to invalid IL or missing references) if ((int)callback.m_eResult != 1 || callback.m_ulSteamIDLobby == 0L) { Flow = LobbyFlow.None; _menuUi.SetBrowserStatus("Steam could not create the room.", error: true); } else { EnterStagingLobby(new CSteamID(callback.m_ulSteamIDLobby), createdByLocalPlayer: true); } } internal void OnLobbyEntered(LobbyEnter_t callback) { //IL_0000: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_0067: 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) if (callback.m_EChatRoomEnterResponse != 1 || callback.m_ulSteamIDLobby == 0L) { Flow = LobbyFlow.None; _menuUi.SetBrowserStatus("Steam rejected the room connection.", error: true); return; } CSteamID val = default(CSteamID); ((CSteamID)(ref val))..ctor(callback.m_ulSteamIDLobby); string lobbyData = SteamMatchmaking.GetLobbyData(val, "version"); string lobbyData2 = SteamMatchmaking.GetLobbyData(val, "how_to_rounds"); if (lobbyData != Application.version || lobbyData2 != "0.17.6") { SteamMatchmaking.LeaveLobby(val); Flow = LobbyFlow.None; _menuUi.SetBrowserStatus("Room version mismatch. Install the same game and mod version.", error: true); } else { EnterStagingLobby(val, createdByLocalPlayer: false); } } private void EnterStagingLobby(CSteamID lobby, bool createdByLocalPlayer) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //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_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_0058: 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_0085: 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_009e: 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) _stagingLobby = lobby; SetCurrentLobbyId(lobby); Flow = LobbyFlow.Staging; if (createdByLocalPlayer) { _requestedRoomCode = RoomCode.Generate(); SteamMatchmaking.SetLobbyData(lobby, "how_to_rounds", "0.17.6"); SteamMatchmaking.SetLobbyData(lobby, "htr_state", "waiting"); SteamMatchmaking.SetLobbyData(lobby, "htr_arena", "arena03"); SteamMatchmaking.SetLobbyData(lobby, "htr_code", _requestedRoomCode); SteamMatchmaking.SetLobbyData(lobby, "name", SteamFriends.GetPersonaName() + "'s How to ROUNDS lobby"); SteamMatchmaking.SetLobbyData(lobby, "version", Application.version); SteamMatchmaking.SetLobbyType(lobby, (ELobbyType)2); SteamMatchmaking.SetLobbyJoinable(lobby, true); } string code = (GUIUtility.systemCopyBuffer = (createdByLocalPlayer ? _requestedRoomCode : SteamMatchmaking.GetLobbyData(lobby, "htr_code"))); _menuUi.ShowLobby(code, IsLocalLobbyOwner()); RefreshLobby(); } private void RefreshLobby() { //IL_0010: 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) //IL_0033: 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_003d: 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_0055: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_0096: Unknown result type (might be due to invalid IL or missing references) if (_stagingLobby.m_SteamID == 0L) { return; } try { int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(_stagingLobby); List list = new List(Math.Max(1, numLobbyMembers)); CSteamID lobbyOwner = SteamMatchmaking.GetLobbyOwner(_stagingLobby); if (lobbyOwner.m_SteamID != 0L) { list.Add(GetPersonaName(lobbyOwner)); } for (int i = 0; i < numLobbyMembers; i++) { CSteamID lobbyMemberByIndex = SteamMatchmaking.GetLobbyMemberByIndex(_stagingLobby, i); if (lobbyMemberByIndex != lobbyOwner) { list.Add(GetPersonaName(lobbyMemberByIndex)); } } bool flag = IsLocalLobbyOwner(); _menuUi.UpdateLobbyMembers(list, flag); if (!flag && SteamMatchmaking.GetLobbyData(_stagingLobby, "htr_state") == "starting") { BeginClientStart(); } } catch (Exception ex) { Log.LogWarning((object)("Lobby refresh failed: " + ex.Message)); } } private bool IsLocalLobbyOwner() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (_stagingLobby.m_SteamID != 0L) { return SteamMatchmaking.GetLobbyOwner(_stagingLobby) == SteamUser.GetSteamID(); } return false; } private static string GetPersonaName(CSteamID player) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: 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) string text = ((player == SteamUser.GetSteamID()) ? SteamFriends.GetPersonaName() : SteamFriends.GetFriendPersonaName(player)); if (!string.IsNullOrWhiteSpace(text) && !(text == "[unknown]")) { return text; } return "Steam player"; } internal void StartMatch() { //IL_0021: 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 (Flow == LobbyFlow.Staging && IsLocalLobbyOwner()) { Flow = LobbyFlow.Starting; string text = SelectArenaForMatch(); SteamMatchmaking.SetLobbyData(_stagingLobby, "htr_arena", text); SteamMatchmaking.SetLobbyData(_stagingLobby, "htr_state", "starting"); _menuUi.SetLobbyStatus("Starting " + ArenaRuntime.DisplayName(text) + "..."); ((MonoBehaviour)this).StartCoroutine(StartHostAfterSignal()); } } private string SelectArenaForMatch() { List list = ArenaRuntime.FindInstalledArenas(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? string.Empty); if (list.Count == 0) { Log.LogWarning((object)"No howtorounds_arenaNN bundles were found beside the plugin."); return "arena03"; } string text = list[Random.Range(0, list.Count)]; Log.LogInfo((object)("Host selected " + ArenaRuntime.DisplayName(text) + " from " + list.Count + " installed arena(s).")); return text; } private IEnumerator StartHostAfterSignal() { yield return (object)new WaitForSecondsRealtime(0.55f); if (!((Object)(object)ConnectionManager.Instance != (Object)null) || !ConnectionManager.Instance.CreateOnlineLobby(GetMaxPlayers())) { Flow = LobbyFlow.Staging; SteamMatchmaking.SetLobbyData(_stagingLobby, "htr_state", "waiting"); _menuUi.SetLobbyStatus("Could not start the host.", error: true); yield break; } yield return (object)new WaitForSecondsRealtime(0.25f); if (!((Object)(object)ConnectionManager.Instance != (Object)null) || !ConnectionManager.Instance.JoinOnlineLobby(_stagingLobby)) { Flow = LobbyFlow.Staging; SteamMatchmaking.SetLobbyData(_stagingLobby, "htr_state", "waiting"); _menuUi.SetLobbyStatus("Host server started, but the local player could not connect.", error: true); } else { BeginArenaDeployment(); } } private void BeginClientStart() { if (Flow == LobbyFlow.Staging) { Flow = LobbyFlow.Starting; _menuUi.SetLobbyStatus("Host is starting the match..."); ((MonoBehaviour)this).StartCoroutine(StartClientAfterHost()); } } private IEnumerator StartClientAfterHost() { yield return (object)new WaitForSecondsRealtime(1.1f); if (!((Object)(object)ConnectionManager.Instance != (Object)null) || !ConnectionManager.Instance.JoinOnlineLobby(_stagingLobby)) { Flow = LobbyFlow.Staging; _menuUi.SetLobbyStatus("Could not connect to the host.", error: true); } else { BeginArenaDeployment(); } } private void BeginArenaDeployment() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (_arenaRuntime == null) { _arenaRuntime = new ArenaRuntime(this); } _arenaRuntime.Begin(_stagingLobby); } internal void LeaveStagingLobby() { //IL_001e: 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_0033: 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) if (_stagingLobby.m_SteamID != 0L) { SteamMatchmaking.LeaveLobby(_stagingLobby); } _stagingLobby = default(CSteamID); _requestedRoomCode = null; SetCurrentLobbyId(default(CSteamID)); Flow = LobbyFlow.None; _menuUi.HideLobby(); } private static void SetCurrentLobbyId(CSteamID lobby) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) AccessTools.Field(typeof(SteamManager), "k__BackingField")?.SetValue(null, lobby); } private static int GetMaxPlayers() { if (!(AccessTools.Field(typeof(SteamManager), "MaxPlayers")?.GetValue(null) is int num) || num <= 0) { return 4; } return num; } } [HarmonyPatch(typeof(SteamManager), "OnLobbyCreated")] internal static class StagingLobbyCreatedPatch { private static bool Prefix(LobbyCreated_t callback) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) Plugin instance = Plugin.Instance; if ((Object)(object)instance == (Object)null || !instance.ShouldInterceptLobbyCreated()) { return true; } instance.OnLobbyCreated(callback); return false; } } [HarmonyPatch(typeof(SteamManager), "OnLobbyEntered")] internal static class StagingLobbyEnteredPatch { private static bool Prefix(LobbyEnter_t callback) { //IL_0024: 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) Plugin instance = Plugin.Instance; if ((Object)(object)instance == (Object)null) { return true; } if (instance.Flow == Plugin.LobbyFlow.Joining) { instance.OnLobbyEntered(callback); return false; } return !instance.IsDuplicateStagingEntry(callback.m_ulSteamIDLobby); } } internal static class RoomCode { private const string Alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; internal static string Generate() { byte[] array = Guid.NewGuid().ToByteArray(); StringBuilder stringBuilder = new StringBuilder(5); for (int i = 0; i < 5; i++) { stringBuilder.Append("ABCDEFGHJKLMNPQRSTUVWXYZ23456789"[array[i] % "ABCDEFGHJKLMNPQRSTUVWXYZ23456789".Length]); } return stringBuilder.ToString(); } internal static bool TryNormalize(string input, out string code) { code = (string.IsNullOrWhiteSpace(input) ? string.Empty : input.Trim().Replace("-", string.Empty).Replace(" ", string.Empty) .ToUpperInvariant()); if (code.Length != 5) { return false; } string text = code; foreach (char value in text) { if ("ABCDEFGHJKLMNPQRSTUVWXYZ23456789".IndexOf(value) < 0) { return false; } } return true; } } internal sealed class RoundsMenuUi : MonoBehaviour { private static readonly Color VanillaPanel = new Color(0.1f, 0.2f, 0.34f, 0.94f); private static readonly Color VanillaRow = new Color(0.13f, 0.25f, 0.4f, 0.92f); private static readonly Color White = new Color(0.97f, 0.98f, 1f, 1f); private static readonly Color Muted = new Color(0.76f, 0.82f, 0.88f, 1f); private static readonly Color Error = new Color(1f, 0.48f, 0.38f, 1f); private Plugin _plugin; private Canvas _canvas; private GameObject _menuButton; private GameObject _modal; private GameObject _browserPanel; private GameObject _lobbyPanel; private TMP_InputField _codeInput; private TMP_Text _browserStatus; private TMP_Text _lobbyCode; private TMP_Text _lobbyStatus; private TMP_Text _hostHint; private readonly List _memberRows = new List(); private GameObject _startButton; private TMP_FontAsset _font; private Sprite _buttonSprite; private Color _buttonColor = new Color(0.12f, 0.25f, 0.42f, 0.92f); private bool _modalOpen; internal void Initialize(Plugin plugin) { _plugin = plugin; TryAttachVanillaButton(); BuildModal(); if ((Object)(object)_menuButton == (Object)null) { CreateFallbackMenuButton(); } } internal void SetMenuVisible(bool visible) { if (visible) { TryAttachVanillaButton(); } if ((Object)(object)_menuButton != (Object)null) { _menuButton.SetActive(visible && !_modalOpen); } if (!visible && (Object)(object)_modal != (Object)null) { _modal.SetActive(false); } else if (visible && _modalOpen && (Object)(object)_modal != (Object)null) { _modal.SetActive(true); } } internal void SetBrowserStatus(string message, bool error = false) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_browserStatus == (Object)null)) { _browserStatus.text = message; ((Graphic)_browserStatus).color = (error ? Error : Muted); } } internal void ShowLobby(string code, bool isHost) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) _modalOpen = true; _modal.SetActive(true); _browserPanel.SetActive(false); _lobbyPanel.SetActive(true); if ((Object)(object)_menuButton != (Object)null) { _menuButton.SetActive(false); } _lobbyCode.text = "ROOM CODE: " + code; _lobbyStatus.text = "Waiting for players..."; ((Graphic)_lobbyStatus).color = Muted; SetHostControls(isHost); } internal void UpdateLobbyMembers(IReadOnlyList members, bool isHost) { //IL_00b3: 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) for (int i = 0; i < _memberRows.Count; i++) { if (i < members.Count) { _memberRows[i].text = i + 1 + ". " + members[i] + ((i == 0) ? " HOST" : string.Empty); } else { _memberRows[i].text = i + 1 + ". Waiting for player..."; } ((Graphic)_memberRows[i]).color = (Color)((i < members.Count) ? White : new Color(Muted.r, Muted.g, Muted.b, 0.55f)); } SetHostControls(isHost); } internal void SetLobbyStatus(string message, bool error = false) { //IL_001c: 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) _lobbyStatus.text = message; ((Graphic)_lobbyStatus).color = (error ? Error : Muted); } internal void HideLobby() { _modalOpen = false; _modal.SetActive(false); _browserPanel.SetActive(true); _lobbyPanel.SetActive(false); if ((Object)(object)_menuButton != (Object)null) { _menuButton.SetActive(true); } } private void TryAttachVanillaButton() { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_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_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) if ((Object)(object)_menuButton != (Object)null) { return; } Button val = FindCreateGameButton(); if (!((Object)(object)val == (Object)null)) { TMP_Text componentInChildren = ((Component)val).GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { _font = componentInChildren.font; } Image component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null) { _buttonSprite = component.sprite; _buttonColor = ((Graphic)component).color; } _menuButton = Object.Instantiate(((Component)val).gameObject, ((Component)val).transform.parent, false); ((Object)_menuButton).name = "HowToRounds_VanillaMenuButton"; Button component2 = _menuButton.GetComponent