Decompiled source of PeakScoreboard v1.0.0
plugins/PeakScoreboard.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
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 HarmonyLib; using Microsoft.CodeAnalysis; using PeakScoreboard.Api; using PeakScoreboard.UI; using Photon.Pun; using Photon.Realtime; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.UI; using Zorro.ControllerSupport; using Zorro.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Arman Ossi Loko")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) 2026 Arman Ossi Loko and Fake Game Developers")] [assembly: AssemblyDescription("Toggle PEAK scoreboard with alive/dead status, host-only respawn, and a public API for other mods to add columns and actions.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+da3161ecd2c433122af6cb2607bc483f6439456f")] [assembly: AssemblyProduct("PeakScoreboard")] [assembly: AssemblyTitle("PeakScoreboard")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace PeakScoreboard { internal static class AfflictionIconResolver { private static readonly Dictionary<STATUSTYPE, Sprite> Sprites = new Dictionary<STATUSTYPE, Sprite>(); private static readonly Dictionary<STATUSTYPE, Color> Colors = new Dictionary<STATUSTYPE, Color>(); private static float _nextRetryAt; public static void EnsureCache() { if (Sprites.Count < 8 && !(Time.unscaledTime < _nextRetryAt)) { _nextRetryAt = Time.unscaledTime + 1f; TryCacheFromStatusSprites(); TryCacheFromStaminaBar(); } } public static bool TryGet(STATUSTYPE type, out Sprite? sprite, out Color color) { //IL_0006: 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_0016: Unknown result type (might be due to invalid IL or missing references) EnsureCache(); color = GetColor(type); if (Sprites.TryGetValue(type, out sprite) && (Object)(object)sprite != (Object)null) { return true; } sprite = null; return false; } public static Color GetColor(STATUSTYPE type) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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) EnsureCache(); if (!Colors.TryGetValue(type, out var value)) { return FallbackColor(type); } return value; } public unsafe static string DisplayName(STATUSTYPE type) { return ((object)(*(STATUSTYPE*)(&type))/*cast due to .constrained prefix*/).ToString(); } private static void TryCacheFromStatusSprites() { //IL_0028: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) Sprite[] all; try { all = Resources.FindObjectsOfTypeAll<Sprite>(); } catch { return; } foreach (STATUSTYPE value in Enum.GetValues(typeof(STATUSTYPE))) { if (!Sprites.ContainsKey(value)) { Sprite val2 = FindStatusSprite(all, value); if ((Object)(object)val2 != (Object)null) { Sprites[value] = val2; } } } } private unsafe static Sprite? FindStatusSprite(Sprite[] all, STATUSTYPE type) { string text = ((object)(*(STATUSTYPE*)(&type))/*cast due to .constrained prefix*/).ToString(); string[] array = new string[4] { "Status_" + text, "Status " + text, "Status" + text, text + "_Status" }; string[] array2 = array; foreach (string value in array2) { foreach (Sprite val in all) { if ((Object)(object)val != (Object)null && ((Object)val).name.Equals(value, StringComparison.OrdinalIgnoreCase)) { return val; } } } foreach (Sprite val2 in all) { if (!((Object)(object)val2 == (Object)null)) { string name = ((Object)val2).name; if (name.IndexOf("Status", StringComparison.OrdinalIgnoreCase) >= 0 && name.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) { return val2; } } } return null; } private static void TryCacheFromStaminaBar() { //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) GUIManager instance = GUIManager.instance; StaminaBar val = (((Object)(object)instance != (Object)null) ? instance.bar : null); if ((Object)(object)val == (Object)null) { return; } if (val.afflictions != null) { BarAffliction[] afflictions = val.afflictions; foreach (BarAffliction val2 in afflictions) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.icon == (Object)null)) { Colors[val2.afflictionType] = ((Graphic)val2.icon).color; if (!Sprites.ContainsKey(val2.afflictionType) && (Object)(object)val2.icon.sprite != (Object)null) { Sprites[val2.afflictionType] = val2.icon.sprite; } } } } if ((Object)(object)val.petrifyAffliction != (Object)null && (Object)(object)val.petrifyAffliction.icon != (Object)null) { Colors[(STATUSTYPE)13] = ((Graphic)val.petrifyAffliction.icon).color; if (!Sprites.ContainsKey((STATUSTYPE)13) && (Object)(object)val.petrifyAffliction.icon.sprite != (Object)null) { Sprites[(STATUSTYPE)13] = val.petrifyAffliction.icon.sprite; } } } private static Color FallbackColor(STATUSTYPE type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected I4, but got Unknown //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_007a: 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_0099: 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_00b8: 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_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: 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_0134: 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_0153: 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_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) return (Color)((int)type switch { 0 => new Color(0.92f, 0.35f, 0.32f, 1f), 1 => new Color(0.92f, 0.62f, 0.28f, 1f), 2 => new Color(0.45f, 0.75f, 0.95f, 1f), 3 => new Color(0.55f, 0.85f, 0.35f, 1f), 8 => new Color(0.95f, 0.45f, 0.2f, 1f), 6 => new Color(0.65f, 0.55f, 0.85f, 1f), 5 => new Color(0.55f, 0.3f, 0.7f, 1f), 9 => new Color(0.7f, 0.8f, 0.35f, 1f), 10 => new Color(0.75f, 0.55f, 0.9f, 1f), 7 => new Color(0.55f, 0.4f, 0.28f, 1f), 11 => new Color(0.85f, 0.85f, 0.8f, 1f), 12 => new Color(0.9f, 0.75f, 0.4f, 1f), 13 => new Color(0.55f, 0.55f, 0.6f, 1f), 4 => new Color(0.9f, 0.4f, 0.35f, 1f), 14 => new Color(0.4f, 0.75f, 0.4f, 1f), _ => Color.white, }); } } internal sealed class ModConfig { public ConfigEntry<string> KeyboardHoldPath { get; } public ConfigEntry<string> ControllerHoldPath { get; } public ConfigEntry<bool> ApplyRevivePenalty { get; } public ConfigEntry<bool> RespawnBesideLocal { get; } public ConfigEntry<float> RespawnVerticalOffset { get; } public ModConfig(ConfigFile config) { KeyboardHoldPath = config.Bind<string>("Controls", "KeyboardHoldPath", "<Keyboard>/z", "Default / config keyboard path for the scoreboard toggle. Examples: <Keyboard>/z, <Keyboard>/tab, <Keyboard>/capsLock, <Mouse>/forwardButton. Leave empty to disable the keyboard binding. In-game rebinds (Pause → CONTROLS → Scoreboard) take priority and sync back here."); ControllerHoldPath = config.Bind<string>("Controls", "ControllerHoldPath", "<Gamepad>/select", "Default / config gamepad path for the scoreboard toggle. Examples: <Gamepad>/select, <Gamepad>/start, <Gamepad>/leftShoulder. Leave empty to disable the controller binding. In-game rebinds (Pause → CONTROLS → Scoreboard) take priority and sync back here."); ApplyRevivePenalty = config.Bind<bool>("Respawn", "ApplyRevivePenalty", true, "If true, revived scouts receive the vanilla revive curse and hunger. If false, they come back clean."); RespawnBesideLocal = config.Bind<bool>("Respawn", "RespawnBesideLocal", true, "If true, dead scouts respawn next to you (when you are alive). Otherwise they revive at their current position."); RespawnVerticalOffset = config.Bind<float>("Respawn", "RespawnVerticalOffset", 2f, "Meters above the revive anchor used when warping a revived scout (helps avoid physics flings)."); } } internal readonly struct ScoutAvatar { public Color SkinColor { get; } public Texture? SteamAvatar { get; } public Texture? Eyes { get; } public Texture? Mouth { get; } public Texture? Accessory { get; } public bool HasSteamAvatar => (Object)(object)SteamAvatar != (Object)null; public static ScoutAvatar Fallback { get; } = new ScoutAvatar(new Color(0.55f, 0.58f, 0.56f, 1f), null, null, null, null); public ScoutAvatar(Color skinColor, Texture? steamAvatar, Texture? eyes, Texture? mouth, Texture? accessory) { //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) SkinColor = skinColor; SteamAvatar = steamAvatar; Eyes = eyes; Mouth = mouth; Accessory = accessory; } } internal static class PlayerAvatarResolver { private static readonly Dictionary<ulong, Texture2D> SteamAvatarCache = new Dictionary<ulong, Texture2D>(); private static readonly HashSet<ulong> SteamAvatarRequested = new HashSet<ulong>(); public static ScoutAvatar Resolve(Character character) { //IL_001e: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)character == (Object)null) { return ScoutAvatar.Fallback; } Color skinColor = ScoutAvatar.Fallback.SkinColor; if ((Object)(object)character.refs?.customization != (Object)null) { skinColor = character.refs.customization.PlayerColor; } Texture steamAvatar = TryGetSteamAvatar(character); CharacterCustomizationData val = TryGetCustomizationData(character); Customization instance = Singleton<Customization>.Instance; Texture eyes = null; Texture mouth = null; Texture accessory = null; if (val != null && (Object)(object)instance != (Object)null) { eyes = SafeTexture(instance.eyes, val.currentEyes); mouth = SafeTexture(instance.mouths, val.currentMouth); accessory = SafeAccessory(instance.accessories, val.currentAccessory); } return new ScoutAvatar(skinColor, steamAvatar, eyes, mouth, accessory); } catch { return ScoutAvatar.Fallback; } } private static Texture? TryGetSteamAvatar(Character character) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown if (!SteamManager.Initialized) { return null; } try { PhotonView photonView = ((MonoBehaviourPun)character).photonView; Player val = ((photonView != null) ? photonView.Owner : null); if (val == null || string.IsNullOrEmpty(val.UserId)) { return null; } if (!ulong.TryParse(val.UserId, out var result) || result == 0L) { return null; } if (SteamAvatarCache.TryGetValue(result, out Texture2D value) && (Object)(object)value != (Object)null) { return (Texture?)(object)value; } CSteamID val2 = default(CSteamID); ((CSteamID)(ref val2))..ctor(result); int largeFriendAvatar = SteamFriends.GetLargeFriendAvatar(val2); switch (largeFriendAvatar) { case -1: if (SteamAvatarRequested.Add(result)) { SteamFriends.RequestUserInformation(val2, false); } return null; case 0: return null; default: { uint num = default(uint); uint num2 = default(uint); if (!SteamUtils.GetImageSize(largeFriendAvatar, ref num, ref num2) || num == 0 || num2 == 0) { return null; } byte[] array = new byte[num * num2 * 4]; if (!SteamUtils.GetImageRGBA(largeFriendAvatar, array, array.Length)) { return null; } FlipVertically(array, (int)num, (int)num2); Texture2D val3 = new Texture2D((int)num, (int)num2, (TextureFormat)4, false); ((Object)val3).name = $"PeakScoreboard_SteamAvatar_{result}"; val3.LoadRawTextureData(array); val3.Apply(false, true); SteamAvatarCache[result] = val3; return (Texture?)(object)val3; } } } catch { return null; } } private static void FlipVertically(byte[] rgba, int width, int height) { int num = width * 4; byte[] array = new byte[num]; for (int i = 0; i < height / 2; i++) { int num2 = i * num; int num3 = (height - 1 - i) * num; Buffer.BlockCopy(rgba, num2, array, 0, num); Buffer.BlockCopy(rgba, num3, rgba, num2, num); Buffer.BlockCopy(array, 0, rgba, num3, num); } } private static CharacterCustomizationData? TryGetCustomizationData(Character character) { try { PhotonView photonView = ((MonoBehaviourPun)character).photonView; Player val = ((photonView != null) ? photonView.Owner : null); if (val == null) { return null; } PersistentPlayerDataService service = GameHandler.GetService<PersistentPlayerDataService>(); return ((service != null) ? service.GetPlayerData(val) : null)?.customizationData; } catch { return null; } } private static Texture? SafeTexture(CustomizationOption[]? options, int index) { if (options == null || index < 0 || index >= options.Length) { return null; } CustomizationOption val = options[index]; if ((Object)(object)val == (Object)null || val.isBlank || (Object)(object)val.texture == (Object)null) { return null; } return val.texture; } private static Texture? SafeAccessory(CustomizationOption[]? options, int index) { if (options == null || index < 0 || index >= options.Length) { return null; } CustomizationOption val = options[index]; if ((Object)(object)val == (Object)null || val.isBlank || val.isThirdEye || (Object)(object)val.texture == (Object)null) { return null; } return val.texture; } } internal readonly struct PlayerRunStats { public float HeightMeters { get; } public float MaxHeightMeters { get; } public float DistanceMeters { get; } public int Deaths { get; } public PlayerRunStats(float heightMeters, float maxHeightMeters, float distanceMeters, int deaths) { HeightMeters = heightMeters; MaxHeightMeters = maxHeightMeters; DistanceMeters = distanceMeters; Deaths = deaths; } } internal static class PlayerStatsTracker { private sealed class TrackedScout { private Vector3? _lastPosition; private bool _wasDead; private bool _initialized; public int ActorId { get; } public float DistanceMeters { get; private set; } public float MaxHeightMeters { get; private set; } public int Deaths { get; private set; } public TrackedScout(int actorId) { ActorId = actorId; } public void Update(Character character) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: 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_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) bool flag = (Object)(object)character.data != (Object)null && (character.data.dead || character.IsGhost); if (_initialized && !_wasDead && flag) { Deaths++; } _wasDead = flag; _initialized = true; CharacterStats val = ((character.refs != null) ? character.refs.stats : null); if ((Object)(object)val != (Object)null) { MaxHeightMeters = Mathf.Max(MaxHeightMeters, val.heightInMeters); } if (flag || character.warping) { _lastPosition = null; return; } Vector3 center = character.Center; if (!_lastPosition.HasValue) { _lastPosition = center; return; } Vector3 val2 = center - _lastPosition.Value; val2.y = 0f; float magnitude = ((Vector3)(ref val2)).magnitude; _lastPosition = center; if (!(magnitude < 0.02f) && !(magnitude > 12f)) { DistanceMeters += magnitude * CharacterStats.unitsToMeters; } } } private const float MinStepUnits = 0.02f; private const float MaxStepUnits = 12f; private static readonly Dictionary<int, TrackedScout> ByActor = new Dictionary<int, TrackedScout>(); private static Guid _runId = Guid.Empty; public static void Tick() { EnsureRun(); foreach (Character item in EnumeratePlayerCharacters()) { int actorId = GetActorId(item); if (actorId > 0) { if (!ByActor.TryGetValue(actorId, out TrackedScout value)) { value = new TrackedScout(actorId); ByActor[actorId] = value; } value.Update(item); } } } public static PlayerRunStats GetStats(Character character, int actorId) { EnsureRun(); float num = 0f; int num2 = 0; CharacterStats val = ((character.refs != null) ? character.refs.stats : null); if ((Object)(object)val != (Object)null) { num = val.heightInMeters; num2 = CountTimelineDeaths(val); } if (actorId > 0 && ByActor.TryGetValue(actorId, out TrackedScout value)) { return new PlayerRunStats(num, Mathf.Max(value.MaxHeightMeters, num), value.DistanceMeters, Math.Max(value.Deaths, num2)); } return new PlayerRunStats(num, num, 0f, num2); } private static IEnumerable<Character> EnumeratePlayerCharacters() { if (PlayerHandler.Exists) { List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters(); if (allPlayerCharacters != null && allPlayerCharacters.Count > 0) { foreach (Character item in allPlayerCharacters) { if ((Object)(object)item != (Object)null && !item.isBot && !item.isZombie) { yield return item; } } yield break; } } foreach (Character allCharacter in Character.AllCharacters) { if ((Object)(object)allCharacter != (Object)null && !allCharacter.isBot && !allCharacter.isZombie) { yield return allCharacter; } } } private static int GetActorId(Character character) { try { PhotonView photonView = ((MonoBehaviourPun)character).photonView; return (photonView != null) ? photonView.OwnerActorNr : (-1); } catch { return -1; } } private static void EnsureRun() { Guid guid = Guid.Empty; try { if ((Object)(object)RunManager.Instance != (Object)null) { guid = RunManager.Instance.RunId; } } catch { } if (!(guid == Guid.Empty) && _runId != guid) { _runId = guid; ByActor.Clear(); } } private static int CountTimelineDeaths(CharacterStats stats) { //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) if (stats.timelineInfo == null || stats.timelineInfo.Count == 0) { return 0; } int num = 0; foreach (TimelineInfo item in stats.timelineInfo) { TimelineInfo current = item; if (((TimelineInfo)(ref current)).died) { num++; } } return num; } } internal readonly struct PlayerStatusRow { public Character Character { get; } public int ActorId { get; } public string Name { get; } public bool IsLocal { get; } public bool IsDead { get; } public bool IsPassedOut { get; } public PlayerRunStats Stats { get; } public PlayerVitals Vitals { get; } public string StatusLabel { get { if (IsDead) { return "Dead"; } if (IsPassedOut) { return "Down"; } return "Alive"; } } public bool CanRespawn { get { if (!IsDead) { return Character.IsGhost; } return true; } } public int StatusRank { get { if (!IsDead) { return IsPassedOut ? 1 : 0; } return 2; } } public PlayerStatusRow(Character character, int actorId, string name, bool isLocal, bool isDead, bool isPassedOut, PlayerRunStats stats, PlayerVitals vitals) { Character = character; ActorId = actorId; Name = name; IsLocal = isLocal; IsDead = isDead; IsPassedOut = isPassedOut; Stats = stats; Vitals = vitals; } } internal static class PlayerStatusService { public static IReadOnlyList<PlayerStatusRow> Capture() { Character[] playerCharacters = GetPlayerCharacters(); List<PlayerStatusRow> list = new List<PlayerStatusRow>(playerCharacters.Length); Character[] array = playerCharacters; foreach (Character val in array) { int actorId = GetActorId(val); string name = ResolveName(val); bool flag = (Object)(object)val.data != (Object)null && (val.data.dead || val.IsGhost); bool isPassedOut = !flag && (Object)(object)val.data != (Object)null && (val.data.passedOut || val.data.fullyPassedOut); PlayerRunStats stats = PlayerStatsTracker.GetStats(val, actorId); PlayerVitals vitals = PlayerVitals.Capture(val); list.Add(new PlayerStatusRow(val, actorId, name, (Object)(object)val == (Object)(object)Character.localCharacter, flag, isPassedOut, stats, vitals)); } return (from row in list orderby row.StatusRank, row.Stats.MaxHeightMeters descending, row.Stats.HeightMeters descending, row.Stats.DistanceMeters descending, row.Stats.Deaths select row).ThenBy<PlayerStatusRow, string>((PlayerStatusRow row) => row.Name, StringComparer.OrdinalIgnoreCase).ThenBy((PlayerStatusRow row) => row.ActorId).ToArray(); } private static Character[] GetPlayerCharacters() { if (!PlayerHandler.Exists) { return Filter(Character.AllCharacters); } List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters(); if (allPlayerCharacters != null && allPlayerCharacters.Count > 0) { return Filter(allPlayerCharacters); } return Filter(Character.AllCharacters); } private static Character[] Filter(IEnumerable<Character>? source) { if (source == null) { return Array.Empty<Character>(); } return source.Where((Character character) => (Object)(object)character != (Object)null && !character.isBot && !character.isZombie).ToArray(); } private static string ResolveName(Character character) { if (!string.IsNullOrWhiteSpace(character.characterName)) { return character.characterName; } try { PhotonView photonView = ((MonoBehaviourPun)character).photonView; object obj; if (photonView == null) { obj = null; } else { Player owner = photonView.Owner; obj = ((owner != null) ? owner.NickName : null); } string text = (string)obj; if (!string.IsNullOrWhiteSpace(text)) { return text; } } catch { } if (!((Object)(object)((Component)character).gameObject != (Object)null)) { return "Scout"; } return ((Object)((Component)character).gameObject).name; } private static int GetActorId(Character character) { try { PhotonView photonView = ((MonoBehaviourPun)character).photonView; return (photonView != null) ? photonView.OwnerActorNr : (-1); } catch { return -1; } } } internal readonly struct PlayerEffect { public STATUSTYPE Type { get; } public float Amount { get; } public int Points => Mathf.RoundToInt(Amount * 100f); public PlayerEffect(STATUSTYPE type, float amount) { //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) Type = type; Amount = amount; } } internal readonly struct PlayerVitals { private static readonly STATUSTYPE[] TrackedStatuses; public bool IsHost { get; } public float Stamina { get; } public float ExtraStamina { get; } public float MaxStamina { get; } public float AvailableStamina { get; } public IReadOnlyList<PlayerEffect> Effects { get; } public float ExtraStaminaFraction => Mathf.Clamp01(ExtraStamina); public int AvailablePoints => Mathf.RoundToInt(Mathf.Clamp01(AvailableStamina) * 100f); public PlayerVitals(bool isHost, float stamina, float extraStamina, float maxStamina, float availableStamina, IReadOnlyList<PlayerEffect> effects) { IsHost = isHost; Stamina = stamina; ExtraStamina = extraStamina; MaxStamina = maxStamina; AvailableStamina = availableStamina; Effects = effects; } public static PlayerVitals Capture(Character character) { bool flag = false; try { PhotonView photonView = ((MonoBehaviourPun)character).photonView; Player val = ((photonView != null) ? photonView.Owner : null); flag = val != null && val.IsMasterClient; if (!flag && (Object)(object)character == (Object)(object)Character.localCharacter && PhotonNetwork.IsMasterClient) { flag = true; } } catch { } float num = 0f; float extraStamina = 0f; float maxStamina = 1f; float availableStamina = 0f; if ((Object)(object)character.data != (Object)null) { num = Mathf.Clamp01(character.data.currentStamina); extraStamina = Mathf.Clamp01(character.data.extraStamina); try { maxStamina = Mathf.Max(0f, character.GetMaxStamina()); } catch { maxStamina = 1f; } availableStamina = num; } return new PlayerVitals(flag, num, extraStamina, maxStamina, availableStamina, CaptureEffects(character)); } private static IReadOnlyList<PlayerEffect> CaptureEffects(Character character) { //IL_003a: 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_0040: Invalid comparison between Unknown and I4 //IL_006c: 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) CharacterAfflictions val = ((character.refs != null) ? character.refs.afflictions : null); if ((Object)(object)val == (Object)null) { return Array.Empty<PlayerEffect>(); } List<PlayerEffect> list = new List<PlayerEffect>(6); STATUSTYPE[] trackedStatuses = TrackedStatuses; foreach (STATUSTYPE val2 in trackedStatuses) { try { float num = (((int)val2 != 13 || !((Object)(object)character.data != (Object)null)) ? val.GetCurrentStatus(val2) : Mathf.Clamp01((float)character.data.petrifyAmount / 100f)); if (num >= 0.0095f) { list.Add(new PlayerEffect(val2, num)); } } catch { } } return list; } static PlayerVitals() { STATUSTYPE[] array = new STATUSTYPE[15]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); TrackedStatuses = (STATUSTYPE[])(object)array; } } [BepInPlugin("PeakScoreboard", "PeakScoreboard", "1.0.0")] public class Plugin : BaseUnityPlugin { private Harmony? _harmony; private ModConfig _config; private ScoreboardController? _controller; public const string Id = "PeakScoreboard"; internal static Plugin? Instance { get; private set; } internal static ManualLogSource Log { get; private set; } public static string Name => "PeakScoreboard"; public static string Version => "1.0.0"; private void Awake() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; _config = new ModConfig(((BaseUnityPlugin)this).Config); ScoreboardAction.Initialize(Log, _config); _controller = new ScoreboardController(_config, Log); _harmony = new Harmony("PeakScoreboard"); try { _harmony.PatchAll(typeof(GuiManagerAttachPatch)); _harmony.PatchAll(typeof(CharacterInputInitPatch)); RebindControlsPatch.Install(_harmony, Log); Log.LogInfo((object)(Name + " v" + Version + " loaded. Press Scoreboard (default Z) to toggle the player list.")); } catch (Exception arg) { Log.LogError((object)$"Failed to patch: {arg}"); } } private void Update() { PlayerStatsTracker.Tick(); _controller?.Tick(); } internal void AttachUi() { _controller?.Attach(); } private void OnDestroy() { _controller?.Dispose(); _controller = null; Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } Instance = null; } } [HarmonyPatch(typeof(GUIManager), "Start")] internal static class GuiManagerAttachPatch { private static void Postfix() { Plugin.Instance?.AttachUi(); } } [HarmonyPatch(typeof(CharacterInput), "Init")] internal static class CharacterInputInitPatch { private static void Prefix() { ScoreboardAction.EnsureRegistered(); } private static void Postfix() { ScoreboardAction.OnGameBindingsLoaded(); } } internal static class RebindControlsPatch { private const string InjectedObjectName = "PeakScoreboard_RebindButton"; private const string InjectedKeyboardName = "PeakScoreboard_RebindButton_KB"; private const string InjectedGamepadName = "PeakScoreboard_RebindButton_GP"; private static ManualLogSource? _logger; private static bool _patched; public static void Install(Harmony harmony, ManualLogSource logger) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown _logger = logger; if (!_patched) { MethodInfo methodInfo = AccessTools.Method(typeof(PauseMenuControlsPage), "InitButtons", (Type[])null, (Type[])null); if (methodInfo == null) { logger.LogWarning((object)"PauseMenuControlsPage.InitButtons not found; Scoreboard will not appear in Rebind controls."); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(RebindControlsPatch), "InitButtonsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patched = true; } } private static void InitButtonsPrefix(PauseMenuControlsPage __instance) { try { ScoreboardAction.EnsureRegistered(); EnsureButtons(__instance); } catch (Exception arg) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)$"Failed to inject Scoreboard rebind control: {arg}"); } } } private static void EnsureButtons(PauseMenuControlsPage page) { Transform controlsMenuButtonsParent = page.controlsMenuButtonsParent; if ((Object)(object)controlsMenuButtonsParent == (Object)null) { return; } PauseMenuRebindButton[] componentsInChildren = ((Component)controlsMenuButtonsParent).GetComponentsInChildren<PauseMenuRebindButton>(true); if (componentsInChildren.Length == 0) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)"No PauseMenuRebindButton template found to clone for Scoreboard."); } return; } PauseMenuRebindButton val = FindTemplate(componentsInChildren, preferKeyboard: true); PauseMenuRebindButton val2 = FindTemplate(componentsInChildren, preferKeyboard: false); DestroyLegacyMisplacedClone(controlsMenuButtonsParent, (val != null) ? ((Component)val).transform.parent : null, (val2 != null) ? ((Component)val2).transform.parent : null); bool flag = false; if ((Object)(object)val != (Object)null) { flag |= EnsureClone(val, "PeakScoreboard_RebindButton_KB"); } if ((Object)(object)val2 != (Object)null && (Object)(object)val != (Object)null && (Object)(object)((Component)val2).transform.parent != (Object)(object)((Component)val).transform.parent) { flag |= EnsureClone(val2, "PeakScoreboard_RebindButton_GP"); } else if ((Object)(object)val == (Object)null && (Object)(object)val2 != (Object)null) { flag |= EnsureClone(val2, "PeakScoreboard_RebindButton_GP"); } if (flag) { AccessTools.Field(typeof(PauseMenuControlsPage), "initializedButtons")?.SetValue(page, false); RectTransform val3 = (RectTransform)(object)((controlsMenuButtonsParent is RectTransform) ? controlsMenuButtonsParent : null); if ((Object)(object)val3 != (Object)null) { LayoutRebuilder.ForceRebuildLayoutImmediate(val3); } ManualLogSource? logger2 = _logger; if (logger2 != null) { logger2.LogInfo((object)"Added Scoreboard to Rebind controls."); } } } private static void DestroyLegacyMisplacedClone(Transform root, Transform? keyboardParent, Transform? gamepadParent) { PauseMenuRebindButton[] componentsInChildren = ((Component)root).GetComponentsInChildren<PauseMenuRebindButton>(true); PauseMenuRebindButton[] array = componentsInChildren; foreach (PauseMenuRebindButton val in array) { if ((Object)(object)val == (Object)null) { continue; } string name = ((Object)((Component)val).gameObject).name; if (name == "PeakScoreboard_RebindButton" || name.StartsWith("PeakScoreboard_RebindButton", StringComparison.Ordinal)) { Transform parent = ((Component)val).transform.parent; if (!((Object)(object)parent != (Object)null) || (!((Object)(object)parent == (Object)(object)keyboardParent) && !((Object)(object)parent == (Object)(object)gamepadParent)) || (!(name == "PeakScoreboard_RebindButton_KB") && !(name == "PeakScoreboard_RebindButton_GP"))) { Object.DestroyImmediate((Object)(object)((Component)val).gameObject); } } } } private static PauseMenuRebindButton? FindTemplate(PauseMenuRebindButton[] templates, bool preferKeyboard) { PauseMenuRebindButton val = null; foreach (PauseMenuRebindButton val2 in templates) { if (!((Object)(object)val2 == (Object)null) && !string.Equals(val2.inputActionName, "Pause", StringComparison.OrdinalIgnoreCase) && !((Object)((Component)val2).gameObject).name.StartsWith("PeakScoreboard_RebindButton", StringComparison.Ordinal)) { if (val == null) { val = val2; } string name = ((Object)((Component)val2).gameObject).name; bool flag = name.IndexOf("KB", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Keyboard", StringComparison.OrdinalIgnoreCase) >= 0; bool flag2 = name.IndexOf("GP", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Gamepad", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Controller", StringComparison.OrdinalIgnoreCase) >= 0; if (preferKeyboard && flag) { return val2; } if (!preferKeyboard && flag2) { return val2; } } } foreach (PauseMenuRebindButton val3 in templates) { if (!((Object)(object)val3 == (Object)null) && !string.Equals(val3.inputActionName, "Pause", StringComparison.OrdinalIgnoreCase) && !((Object)((Component)val3).gameObject).name.StartsWith("PeakScoreboard_RebindButton", StringComparison.Ordinal) && ((Component)val3).gameObject.activeInHierarchy) { return val3; } } return val; } private static bool EnsureClone(PauseMenuRebindButton template, string objectName) { //IL_0089: 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_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00ca: Unknown result type (might be due to invalid IL or missing references) Transform parent = ((Component)template).transform.parent; if ((Object)(object)parent == (Object)null) { return false; } Transform val = parent.Find(objectName); if ((Object)(object)val != (Object)null) { return false; } GameObject val2 = Object.Instantiate<GameObject>(((Component)template).gameObject, parent); ((Object)val2).name = objectName; val2.SetActive(((Component)template).gameObject.activeSelf); val2.transform.SetAsLastSibling(); Transform transform = val2.transform; RectTransform val3 = (RectTransform)(object)((transform is RectTransform) ? transform : null); Transform transform2 = ((Component)template).transform; RectTransform val4 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null); if ((Object)(object)val3 != (Object)null && (Object)(object)val4 != (Object)null) { ((Transform)val3).localScale = ((Transform)val4).localScale; val3.anchorMin = val4.anchorMin; val3.anchorMax = val4.anchorMax; val3.pivot = val4.pivot; val3.sizeDelta = val4.sizeDelta; val3.anchoredPosition = val4.anchoredPosition; } PauseMenuRebindButton component = val2.GetComponent<PauseMenuRebindButton>(); component.inputActionName = "Scoreboard"; AccessTools.Field(typeof(PauseMenuRebindButton), "inputAction")?.SetValue(component, ScoreboardAction.Action); if ((Object)(object)component.inputDescriptionText != (Object)null) { component.inputDescriptionText.index = "SCOREBOARD"; component.inputDescriptionText.autoSet = false; if ((Object)(object)component.inputDescriptionText.tmp != (Object)null) { component.inputDescriptionText.tmp.text = "Scoreboard"; } } else { TextMeshProUGUI componentInChildren = val2.GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)componentInChildren != (Object)null) { ((TMP_Text)componentInChildren).text = "Scoreboard"; } } ReplaceBindingGlyphs(val2); LayoutGroup component2 = ((Component)parent).GetComponent<LayoutGroup>(); if ((Object)(object)component2 != (Object)null) { LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)(object)((parent is RectTransform) ? parent : null)); } return true; } private static void ReplaceBindingGlyphs(GameObject clone) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) InputIcon[] componentsInChildren = clone.GetComponentsInChildren<InputIcon>(true); InputIcon[] array = componentsInChildren; foreach (InputIcon val in array) { if (!((Object)(object)val == (Object)null)) { TMP_Text val2 = val.text; if ((Object)(object)val2 == (Object)null) { val2 = ((Component)val).GetComponent<TMP_Text>(); } Object.Destroy((Object)(object)val); if (!((Object)(object)val2 == (Object)null)) { ScoreboardBindingGlyph scoreboardBindingGlyph = ((Component)val2).gameObject.GetComponent<ScoreboardBindingGlyph>() ?? ((Component)val2).gameObject.AddComponent<ScoreboardBindingGlyph>(); scoreboardBindingGlyph.Bind(val2); scoreboardBindingGlyph.Refresh(InputHandler.GetCurrentUsedInputScheme()); } } } } } internal sealed class RespawnService { private readonly ModConfig _config; private readonly ManualLogSource _logger; public RespawnService(ModConfig config, ManualLogSource logger) { _config = config; _logger = logger; } public bool CanRespawn(out string reason) { if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient) { reason = "Only the host can respawn players."; return false; } reason = string.Empty; return true; } public bool TryRespawn(Character target, out string message) { //IL_0062: 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_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0118: 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_01be: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null) { message = "No target."; return false; } if (!CanRespawn(out string reason)) { message = reason; return false; } if (!((Object)(object)target.data != (Object)null) || (!target.data.dead && !target.IsGhost)) { message = ResolveName(target) + " is not dead."; return false; } Vector3 val = ResolveRespawnPosition(target); bool value = _config.ApplyRevivePenalty.Value; try { if (target.IsLocal) { PhotonView val2 = ((target.refs != null && (Object)(object)target.refs.view != (Object)null) ? target.refs.view : ((MonoBehaviourPun)target).photonView); val2.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { val, value, -1 }); } else if (target.refs != null && (Object)(object)target.refs.view != (Object)null) { target.refs.view.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { val, value, -1 }); } else { if (!((Object)(object)((MonoBehaviourPun)target).photonView != (Object)null)) { message = "No PhotonView for " + ResolveName(target) + "."; return false; } ((MonoBehaviourPun)target).photonView.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { val, value, -1 }); } message = "Respawning " + ResolveName(target) + "…"; _logger.LogInfo((object)$"Requested respawn for '{ResolveName(target)}' at {val} (penalty={value})."); return true; } catch (Exception arg) { _logger.LogError((object)$"Failed to respawn '{ResolveName(target)}': {arg}"); message = "Respawn failed. Check the BepInEx log."; return false; } } private Vector3 ResolveRespawnPosition(Character target) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(0.1f, _config.RespawnVerticalOffset.Value); if (_config.RespawnBesideLocal.Value) { Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter != (Object)null && (Object)(object)localCharacter != (Object)(object)target && (Object)(object)localCharacter.data != (Object)null && !localCharacter.data.dead && !localCharacter.IsGhost) { return localCharacter.Center + Vector3.up * num; } Character val = FindNearestAlive(target); if ((Object)(object)val != (Object)null) { return val.Center + Vector3.up * num; } } return target.Center + Vector3.up * num; } private static Character? FindNearestAlive(Character exclude) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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) Character result = null; float num = float.MaxValue; Vector3 center = exclude.Center; foreach (PlayerStatusRow item in PlayerStatusService.Capture()) { if (!((Object)(object)item.Character == (Object)(object)exclude) && !item.IsDead) { float num2 = Vector3.Distance(center, item.Character.Center); if (num2 < num) { num = num2; result = item.Character; } } } return result; } private static string ResolveName(Character character) { if (!string.IsNullOrWhiteSpace(character.characterName)) { return character.characterName; } return ((Object)character).name; } } internal static class ScoreboardAction { public const string ActionName = "Scoreboard"; public const string LocalizationId = "SCOREBOARD"; public const string DisplayLabel = "Scoreboard"; private static ManualLogSource? _logger; private static ModConfig? _config; private static InputAction? _action; private static bool _registered; private static bool _listeningForConfigChanges; private static bool _gameBindingsLoaded; private static bool _suppressConfigApply; public static InputAction? Action => _action; public static void Initialize(ManualLogSource logger, ModConfig config) { _logger = logger; _config = config; HookConfigChanges(); EnsureRegistered(); } public static void OnGameBindingsLoaded() { _gameBindingsLoaded = true; EnsureRegistered(); SyncConfigFromLiveBindings(); } public static bool EnsureRegistered() { //IL_0051: 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_012b: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) if (_registered && _action != null && _action.actionMap != null) { return true; } InputActionAsset actions = InputSystem.actions; if ((Object)(object)actions == (Object)null) { return false; } InputAction val = actions.FindAction("Scoreboard", false); if (val != null) { _action = val; _registered = true; EnsureLocalizationEntry(); return true; } InputActionMap val2 = ((IEnumerable<InputActionMap>)(object)actions.actionMaps).FirstOrDefault((Func<InputActionMap, bool>)((InputActionMap candidate) => candidate.FindAction("Jump", false) != null)) ?? ((IEnumerable<InputActionMap>)(object)actions.actionMaps).FirstOrDefault(); if (val2 == null) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)"Could not find an InputActionMap to host the Scoreboard action."); } return false; } try { bool enabled = val2.enabled; if (enabled) { val2.Disable(); } string text = NormalizePath(_config?.KeyboardHoldPath.Value, "<Keyboard>/z"); string text2 = NormalizePath(_config?.ControllerHoldPath.Value, "<Gamepad>/select"); InputAction val3 = InputActionSetupExtensions.AddAction(val2, "Scoreboard", (InputActionType)1, (string)null, (string)null, (string)null, (string)null, (string)null); if (text.Length > 0) { InputActionSetupExtensions.AddBinding(val3, text, (string)null, (string)null, "Keyboard&Mouse"); } if (text2.Length > 0) { InputActionSetupExtensions.AddBinding(val3, text2, (string)null, (string)null, "Gamepad"); } if (val3.bindings.Count == 0) { InputActionSetupExtensions.AddBinding(val3, "<Keyboard>/z", (string)null, (string)null, "Keyboard&Mouse"); ManualLogSource? logger2 = _logger; if (logger2 != null) { logger2.LogWarning((object)"Both scoreboard bindings were empty; fell back to <Keyboard>/z."); } } _action = val3; if (enabled) { val2.Enable(); } else { val3.Enable(); } EnsureLocalizationEntry(); _registered = true; ManualLogSource? logger3 = _logger; if (logger3 != null) { logger3.LogInfo((object)("Registered InputAction 'Scoreboard' (default " + DescribeBinding(text, text2) + ").")); } return true; } catch (Exception arg) { ManualLogSource? logger4 = _logger; if (logger4 != null) { logger4.LogError((object)$"Failed to register Scoreboard input action: {arg}"); } return false; } } public static bool WasPressedThisFrame() { EnsureRegistered(); if (_action != null) { return _action.WasPressedThisFrame(); } Keyboard current = Keyboard.current; if (current != null) { return ((ButtonControl)current.zKey).wasPressedThisFrame; } return false; } public static void ApplyConfiguredBindings(bool save) { if (_config == null || !EnsureRegistered() || _action == null) { return; } try { string text = NormalizePath(_config.KeyboardHoldPath.Value, string.Empty); string text2 = NormalizePath(_config.ControllerHoldPath.Value, string.Empty); ApplyOrClearGroupBinding("Keyboard&Mouse", text); ApplyOrClearGroupBinding("Gamepad", text2); if (save && _gameBindingsLoaded) { Rebinding.SaveRebindingsToFile((InputActionAsset)null); } ManualLogSource? logger = _logger; if (logger != null) { logger.LogInfo((object)("Scoreboard toggle binding set from config to " + DescribeBinding(text, text2) + ".")); } } catch (Exception ex) { ManualLogSource? logger2 = _logger; if (logger2 != null) { logger2.LogWarning((object)("Failed to apply scoreboard binding from config: " + ex.Message)); } } } public static string GetEffectiveKeyboardPath() { EnsureRegistered(); return GetEffectivePathForGroup("Keyboard&Mouse"); } public static string GetEffectiveGamepadPath() { EnsureRegistered(); return GetEffectivePathForGroup("Gamepad"); } private static void SyncConfigFromLiveBindings() { if (_config == null || _action == null) { return; } try { string effectivePathForGroup = GetEffectivePathForGroup("Keyboard&Mouse"); string effectivePathForGroup2 = GetEffectivePathForGroup("Gamepad"); _suppressConfigApply = true; if (!string.IsNullOrEmpty(effectivePathForGroup) && _config.KeyboardHoldPath.Value != effectivePathForGroup) { _config.KeyboardHoldPath.Value = effectivePathForGroup; } if (!string.IsNullOrEmpty(effectivePathForGroup2) && _config.ControllerHoldPath.Value != effectivePathForGroup2) { _config.ControllerHoldPath.Value = effectivePathForGroup2; } } catch (Exception ex) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)("Failed to sync config from live scoreboard bindings: " + ex.Message)); } } finally { _suppressConfigApply = false; } } private static string GetEffectivePathForGroup(string group) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_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) if (_action == null) { return string.Empty; } for (int i = 0; i < _action.bindings.Count; i++) { InputBinding val = _action.bindings[i]; if (!string.IsNullOrEmpty(((InputBinding)(ref val)).groups) && ((InputBinding)(ref val)).groups.Contains(group)) { return ((InputBinding)(ref val)).effectivePath ?? string.Empty; } } return string.Empty; } private static void ApplyOrClearGroupBinding(string group, string path) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (_action == null) { return; } int num = FindBindingIndex(group); if (num < 0) { if (path.Length != 0) { InputActionSetupExtensions.AddBinding(_action, path, (string)null, (string)null, group); } } else if (path.Length == 0) { InputActionRebindingExtensions.ApplyBindingOverride(_action, num, string.Empty); } else { InputActionRebindingExtensions.ApplyBindingOverride(_action, num, path); } } private static int FindBindingIndex(string group) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (_action == null) { return -1; } for (int i = 0; i < _action.bindings.Count; i++) { InputBinding val = _action.bindings[i]; if (!string.IsNullOrEmpty(((InputBinding)(ref val)).groups) && ((InputBinding)(ref val)).groups.Contains(group)) { return i; } } return -1; } private static void HookConfigChanges() { if (!_listeningForConfigChanges && _config != null) { _config.KeyboardHoldPath.SettingChanged += OnControlPathChanged; _config.ControllerHoldPath.SettingChanged += OnControlPathChanged; _listeningForConfigChanges = true; } } private static void OnControlPathChanged(object sender, EventArgs e) { if (!_suppressConfigApply && _gameBindingsLoaded) { ApplyConfiguredBindings(save: true); } } private static string NormalizePath(string? value, string fallback) { string text = value?.Trim() ?? string.Empty; if (text.Length <= 0) { return fallback; } return text; } private static string DescribeBinding(string keyboardPath, string controllerPath) { string text = ((keyboardPath.Length > 0) ? keyboardPath : "(keyboard off)"); string text2 = ((controllerPath.Length > 0) ? controllerPath : "(controller off)"); return text + " / " + text2; } private static void EnsureLocalizationEntry() { try { Dictionary<string, List<string>> mainTable = LocalizedText.mainTable; if (!mainTable.ContainsKey("SCOREBOARD")) { List<string> list = new List<string>(14); for (int i = 0; i < 14; i++) { list.Add("Scoreboard"); } mainTable["SCOREBOARD"] = list; } } catch (Exception ex) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)("Could not register Scoreboard localization entry: " + ex.Message)); } } } } } namespace PeakScoreboard.UI { internal static class RuntimeUiFactory { internal static readonly Color Backdrop = new Color(0.035f, 0.043f, 0.047f, 0.55f); internal static readonly Color Panel = new Color(0.1f, 0.115f, 0.12f, 0.96f); internal static readonly Color Surface = new Color(0.16f, 0.175f, 0.18f, 1f); internal static readonly Color SurfaceHover = new Color(0.22f, 0.235f, 0.235f, 1f); internal static readonly Color Accent = new Color(0.3f, 0.78f, 0.58f, 1f); internal static readonly Color TextPrimary = new Color(0.95f, 0.96f, 0.94f, 1f); internal static readonly Color TextMuted = new Color(0.68f, 0.71f, 0.69f, 1f); internal static readonly Color Alive = new Color(0.45f, 0.86f, 0.58f, 1f); internal static readonly Color Down = new Color(0.95f, 0.78f, 0.35f, 1f); internal static readonly Color Dead = new Color(0.94f, 0.45f, 0.42f, 1f); internal static readonly Color Stamina = new Color(0.45f, 0.82f, 0.55f, 1f); internal static readonly Color StaminaBonus = new Color(0.95f, 0.82f, 0.3f, 1f); internal static readonly Color StaminaTrack = new Color(0.08f, 0.09f, 0.095f, 1f); internal static readonly Color HostTag = new Color(0.95f, 0.78f, 0.35f, 1f); private static Sprite? _whiteSprite; private static Sprite? _circleSprite; public static RectTransform CreateRect(string name, Transform parent, params Type[] components) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown Type[] array = new Type[components.Length + 1]; array[0] = typeof(RectTransform); Array.Copy(components, 0, array, 1, components.Length); GameObject val = new GameObject(name, array); val.transform.SetParent(parent, false); return (RectTransform)val.transform; } public static void Stretch(RectTransform rect, float left = 0f, float right = 0f, float bottom = 0f, float top = 0f) { //IL_0001: 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_0019: 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) rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; rect.offsetMin = new Vector2(left, bottom); rect.offsetMax = new Vector2(0f - right, 0f - top); } public static TMP_FontAsset ResolveFont() { if ((Object)(object)FontFallbackSwapper.instance != (Object)null && (Object)(object)FontFallbackSwapper.instance.mainBaseFont != (Object)null) { return FontFallbackSwapper.instance.mainBaseFont; } TMP_FontAsset val = ((IEnumerable<TMP_FontAsset>)Resources.FindObjectsOfTypeAll<TMP_FontAsset>()).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset candidate) => ((Object)candidate).name == "DarumaDropOne-Regular SDF")) ?? Resources.FindObjectsOfTypeAll<TMP_FontAsset>().FirstOrDefault(); if ((Object)(object)val == (Object)null) { throw new InvalidOperationException("No TextMeshPro font asset is available."); } return val; } public static TextMeshProUGUI CreateText(string name, Transform parent, TMP_FontAsset font, float fontSize, Color color, TextAlignmentOptions alignment) { //IL_0031: 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) RectTransform val = CreateRect(name, parent, typeof(TextMeshProUGUI)); TextMeshProUGUI component = ((Component)val).GetComponent<TextMeshProUGUI>(); ((TMP_Text)component).font = font; ((TMP_Text)component).fontSize = fontSize; ((Graphic)component).color = color; ((TMP_Text)component).alignment = alignment; ((TMP_Text)component).textWrappingMode = (TextWrappingModes)0; ((TMP_Text)component).overflowMode = (TextOverflowModes)1; ((Graphic)component).raycastTarget = false; return component; } public static Image CreateImage(string name, Transform parent, Color color, bool raycastTarget = true) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) RectTransform val = CreateRect(name, parent, typeof(Image)); Image component = ((Component)val).GetComponent<Image>(); component.sprite = GetWhiteSprite(); component.type = (Type)1; ((Graphic)component).color = color; ((Graphic)component).raycastTarget = raycastTarget; return component; } public static Button CreateButton(string name, Transform parent, TMP_FontAsset font, string label) { //IL_0042: 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_0071: Unknown result type (might be due to invalid IL or missing references) RectTransform val = CreateRect(name, parent, typeof(Image), typeof(Button)); Image component = ((Component)val).GetComponent<Image>(); component.sprite = GetWhiteSprite(); component.type = (Type)1; ((Graphic)component).color = Surface; Button component2 = ((Component)val).GetComponent<Button>(); ((Selectable)component2).targetGraphic = (Graphic)(object)component; ((Selectable)component2).colors = CreateButtonColors(); TextMeshProUGUI val2 = CreateText("Label", (Transform)(object)val, font, 20f, TextPrimary, (TextAlignmentOptions)514); ((TMP_Text)val2).text = label; Stretch(((TMP_Text)val2).rectTransform, 4f, 4f, 2f, 2f); return component2; } public static ColorBlock CreateButtonColors() { //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_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) ColorBlock defaultColorBlock = ColorBlock.defaultColorBlock; ((ColorBlock)(ref defaultColorBlock)).normalColor = Surface; ((ColorBlock)(ref defaultColorBlock)).highlightedColor = SurfaceHover; ((ColorBlock)(ref defaultColorBlock)).pressedColor = Accent; ((ColorBlock)(ref defaultColorBlock)).selectedColor = SurfaceHover; ((ColorBlock)(ref defaultColorBlock)).disabledColor = new Color(Surface.r, Surface.g, Surface.b, 0.45f); ((ColorBlock)(ref defaultColorBlock)).colorMultiplier = 1f; ((ColorBlock)(ref defaultColorBlock)).fadeDuration = 0.08f; return defaultColorBlock; } public static Color StatusColor(PlayerStatusRow row) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (row.IsDead) { return Dead; } if (row.IsPassedOut) { return Down; } return Alive; } public static Sprite GetWhiteSprite() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_whiteSprite != (Object)null) { return _whiteSprite; } Texture2D whiteTexture = Texture2D.whiteTexture; _whiteSprite = Sprite.Create(whiteTexture, new Rect(0f, 0f, (float)((Texture)whiteTexture).width, (float)((Texture)whiteTexture).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4(1f, 1f, 1f, 1f)); return _whiteSprite; } public static Sprite GetCircleSprite() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_00b1: 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_0075: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_circleSprite != (Object)null) { return _circleSprite; } Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false); float num = 31.5f; float num2 = num; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { float num3 = (float)j - num2; float num4 = (float)i - num2; float num5 = Mathf.Sqrt(num3 * num3 + num4 * num4); float num6 = Mathf.Clamp01(num - num5 + 0.5f); val.SetPixel(j, i, new Color(1f, 1f, 1f, num6)); } } val.Apply(false, true); _circleSprite = Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 100f); return _circleSprite; } public static RawImage CreateRawImage(string name, Transform parent) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) RectTransform val = CreateRect(name, parent, typeof(RawImage)); RawImage component = ((Component)val).GetComponent<RawImage>(); ((Graphic)component).raycastTarget = false; ((Graphic)component).color = Color.white; return component; } } internal sealed class ScoreboardBindingGlyph : MonoBehaviour { private TMP_Text? _text; private bool _subscribed; public void Bind(TMP_Text text) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) _text = text; Refresh(InputHandler.GetCurrentUsedInputScheme()); } private void OnEnable() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) Subscribe(); Refresh(InputHandler.GetCurrentUsedInputScheme()); } private void OnDisable() { Unsubscribe(); } private void OnDestroy() { Unsubscribe(); } private void Subscribe() { if (!_subscribed) { InputHandler instance = RetrievableResourceSingleton<InputHandler>.Instance; if (!((Object)(object)instance == (Object)null)) { instance.InputSchemeChanged = (Action<InputScheme>)Delegate.Combine(instance.InputSchemeChanged, new Action<InputScheme>(OnDeviceChange)); _subscribed = true; } } } private void Unsubscribe() { if (_subscribed) { InputHandler instance = RetrievableResourceSingleton<InputHandler>.Instance; if ((Object)(object)instance != (Object)null) { instance.InputSchemeChanged = (Action<InputScheme>)Delegate.Remove(instance.InputSchemeChanged, new Action<InputScheme>(OnDeviceChange)); } _subscribed = false; } } private void OnDeviceChange(InputScheme scheme) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) Refresh(scheme); } public void Refresh(InputScheme scheme) { //IL_0015: 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: Invalid comparison between Unknown and I4 if ((Object)(object)_text == (Object)null) { return; } try { bool flag = default(bool); string bindingPath = InputSpriteData.GetBindingPath("Scoreboard", scheme, ref flag); InputSpriteData instance = SingletonAsset<InputSpriteData>.Instance; if ((Object)(object)instance == (Object)null) { _text.text = FormatFallback(bindingPath); return; } string text = (((int)scheme == 1) ? instance.GetSpriteTagFromInputPathGamepad(bindingPath) : instance.GetSpriteTagFromInputPathKeyboard(bindingPath)); _text.text = (string.IsNullOrEmpty(text) ? FormatFallback(bindingPath) : text); } catch (Exception) { _text.text = FormatFallback(ScoreboardAction.GetEffectiveKeyboardPath()); } } private static string FormatFallback(string path) { if (string.IsNullOrEmpty(path)) { return "?"; } int num = path.LastIndexOf('/'); string text = ((num >= 0 && num < path.Length - 1) ? path.Substring(num + 1) : path); if (text.Length != 1) { return text; } return text.ToUpperInvariant(); } } internal sealed class ScoreboardController : IDisposable { private readonly ModConfig _config; private readonly ManualLogSource _logger; private readonly RespawnService _respawn; private ScoreboardView? _view; private bool _visible; private float _nextRefreshAt; private string _statusMessage = string.Empty; private bool _statusIsError; public ScoreboardController(ModConfig config, ManualLogSource logger) { _config = config; _logger = logger; _respawn = new RespawnService(config, logger); } public void Attach() { if (_view != null && (Object)(object)_view.Root != (Object)null) { return; } try { _view = null; ScoreboardAction.EnsureRegistered(); _view = ScoreboardView.Create(); _view.OnCloseRequested = delegate { SetVisible(visible: false); }; _logger.LogInfo((object)"Scoreboard UI ready. Press Scoreboard (default Z) to toggle."); } catch (Exception arg) { _logger.LogError((object)$"Failed to create scoreboard UI: {arg}"); } } public void Tick() { if (_view == null || (Object)(object)_view.Root == (Object)null) { if ((Object)(object)GUIManager.instance != (Object)null) { Attach(); } if (_view == null || (Object)(object)_view.Root == (Object)null) { return; } } if (_visible && !_view.Window.IsOpen) { _visible = false; _view.SetChromeVisible(visible: false); } if (ScoreboardAction.WasPressedThisFrame()) { if (_visible) { SetVisible(visible: false); } else if (CanShow()) { SetVisible(visible: true); } } if (_visible) { Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; if (Time.unscaledTime >= _nextRefreshAt) { RefreshRows(); _nextRefreshAt = Time.unscaledTime + 0.25f; } } } public void Dispose() { if (_visible) { _view?.Close(); } _view?.Destroy(); _view = null; _visible = false; } private void SetVisible(bool visible) { _visible = visible; if (_view != null) { if (visible) { _statusMessage = string.Empty; _statusIsError = false; _view.Open(); RefreshRows(); _nextRefreshAt = Time.unscaledTime + 0.25f; } else { _view.Close(); } } } private void RefreshRows() { if (_view == null) { return; } IReadOnlyList<PlayerStatusRow> readOnlyList = PlayerStatusService.Capture(); string reason; bool flag = _respawn.CanRespawn(out reason); string subtitle = (flag ? "Press Scoreboard again or Close · click Respawn on dead scouts" : reason); _view.SetSubtitle(subtitle); _view.BindRows(readOnlyList, OnRespawnClicked, flag); if (string.IsNullOrEmpty(_statusMessage)) { int num = 0; int num2 = 0; foreach (PlayerStatusRow item in readOnlyList) { if (item.IsDead) { num2++; } else { num++; } } string arg = ((PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient) ? " · you are host" : string.Empty); _view.SetStatus($"{num} alive · {num2} dead{arg}", isError: false); } else { _view.SetStatus(_statusMessage, _statusIsError); } } private void OnRespawnClicked(PlayerStatusRow row) { string message; bool flag = _respawn.TryRespawn(row.Character, out message); _statusMessage = message; _statusIsError = !flag; _view?.SetStatus(_statusMessage, _statusIsError); _nextRefreshAt = Time.unscaledTime + 0.1f; } private bool CanShow() { if (Time.timeScale <= 0f) { return false; } GUIManager instance = GUIManager.instance; if ((Object)(object)instance != (Object)null && instance.wheelActive) { return false; } if ((Object)(object)instance != (Object)null && instance.windowBlockingInput && !_visible) { return false; } if (GUIManager.InPauseMenu) { return false; } if (!((Object)(object)Character.localCharacter != (Object)null)) { return PlayerHandler.Exists; } return true; } } internal sealed class ScoreboardExtensionCells { private readonly RectTransform _parent; private readonly TMP_FontAsset _font; private readonly bool _header; private readonly List<TextMeshProUGUI> _columnLabels = new List<TextMeshProUGUI>(); private readonly List<Button> _actionButtons = new List<Button>(); private readonly List<TextMeshProUGUI> _actionLabels = new List<TextMeshProUGUI>(); public ScoreboardExtensionCells(RectTransform parent, TMP_FontAsset font, bool header) { _parent = parent; _font = font; _header = header; } public void SyncStructure(ScoreboardLayout layout) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) EnsureColumnCount(layout.Columns.Count); EnsureActionCount(layout.RowActions.Count); for (int i = 0; i < _columnLabels.Count; i++) { bool flag = i < layout.Columns.Count; ((Component)_columnLabels[i]).gameObject.SetActive(flag); if (flag) { ScoreboardColumn scoreboardColumn = layout.Columns[i]; ScoreboardLayout.Slot slot = layout.ColumnSlots[i]; TextMeshProUGUI val = _columnLabels[i]; ((TMP_Text)val).text = (_header ? scoreboardColumn.Header : string.Empty); ((TMP_Text)val).alignment = ToTmp(scoreboardColumn.Alignment); ApplySlot(((TMP_Text)val).rectTransform, slot, 4f); if (_header) { ((Graphic)val).color = RuntimeUiFactory.TextMuted; } } } for (int j = 0; j < _actionButtons.Count; j++) { bool flag2 = j < layout.RowActions.Count; ((Component)_actionButtons[j]).gameObject.SetActive(flag2); if (flag2) { ScoreboardRowAction scoreboardRowAction = layout.RowActions[j]; ((TMP_Text)_actionLabels[j]).text = (_header ? string.Empty : scoreboardRowAction.Label); PlaceActionButton(((Component)_actionButtons[j]).GetComponent<RectTransform>(), layout, j); } } } public void BindHeader(ScoreboardLayout layout) { SyncStructure(layout); for (int i = 0; i < layout.RowActions.Count && i < _actionButtons.Count; i++) { ((Component)_actionButtons[i]).gameObject.SetActive(false); } } public void BindRow(ScoreboardLayout layout, ScoreboardPlayer player) { //IL_00e1: 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_0231: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Expected O, but got Unknown SyncStructure(layout); for (int i = 0; i < layout.Columns.Count && i < _columnLabels.Count; i++) { ScoreboardColumn scoreboardColumn = layout.Columns[i]; TextMeshProUGUI val = _columnLabels[i]; try { ((TMP_Text)val).text = scoreboardColumn.GetValue(player) ?? string.Empty; } catch (Exception ex) { ((TMP_Text)val).text = "!"; Plugin.Log.LogWarning((object)("Scoreboard column '" + scoreboardColumn.Id + "' failed: " + ex.Message)); } Color? val2 = null; try { val2 = scoreboardColumn.GetColor?.Invoke(player); } catch (Exception ex2) { Plugin.Log.LogWarning((object)("Scoreboard column '" + scoreboardColumn.Id + "' color failed: " + ex2.Message)); } ((Graphic)val).color = (Color)(((??)val2) ?? RuntimeUiFactory.TextPrimary); } for (int j = 0; j < layout.RowActions.Count && j < _actionButtons.Count; j++) { ScoreboardRowAction scoreboardRowAction = layout.RowActions[j]; Button val3 = _actionButtons[j]; bool flag = true; bool interactable = true; try { flag = scoreboardRowAction.IsVisible?.Invoke(player) ?? true; } catch (Exception ex3) { flag = false; Plugin.Log.LogWarning((object)("Scoreboard action '" + scoreboardRowAction.Id + "' IsVisible failed: " + ex3.Message)); } if (flag) { try { interactable = scoreboardRowAction.IsEnabled?.Invoke(player) ?? true; } catch (Exception ex4) { interactable = false; Plugin.Log.LogWarning((object)("Scoreboard action '" + scoreboardRowAction.Id + "' IsEnabled failed: " + ex4.Message)); } } ((Component)val3).gameObject.SetActive(flag); ((Selectable)val3).interactable = interactable; ((TMP_Text)_actionLabels[j]).text = scoreboardRowAction.Label; ((UnityEventBase)val3.onClick).RemoveAllListeners(); if (flag) { ScoreboardPlayer captured = player; ScoreboardRowAction capturedAction = scoreboardRowAction; ((UnityEvent)val3.onClick).AddListener((UnityAction)delegate { try { capturedAction.OnClick(captured); } catch (Exception arg) { Plugin.Log.LogError((object)$"Scoreboard action '{capturedAction.Id}' failed: {arg}"); } }); } PlaceActionButton(((Component)val3).GetComponent<RectTransform>(), layout, j); } } private void EnsureColumnCount(int count) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) while (_columnLabels.Count < count) { TextMeshProUGUI val = RuntimeUiFactory.CreateText("ExtColumn", (Transform)(object)_parent, _font, _header ? 16f : 20f, _header ? RuntimeUiFactory.TextMuted : RuntimeUiFactory.TextPrimary, (TextAlignmentOptions)514); ((TMP_Text)val).text = string.Empty; ((Graphic)val).raycastTarget = false; _columnLabels.Add(val); } } private void EnsureActionCount(int count) { while (_actionButtons.Count < count) { Button val = RuntimeUiFactory.CreateButton("ExtAction", (Transform)(object)_parent, _font, ""); TextMeshProUGUI componentInChildren = ((Component)val).GetComponentInChildren<TextMeshProUGUI>(); _actionButtons.Add(val); _actionLabels.Add(componentInChildren); if (_header) { ((Component)val).gameObject.SetActive(false); } } } private static void PlaceActionButton(RectTransform rect, ScoreboardLayout layout, int index) { //IL_005a: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: 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_00cb: Unknown result type (might be due to invalid IL or missing references) int num = Math.Max(1, layout.RowActions.Count + 1); float num2 = layout.Actions.Max - layout.Actions.Min; float num3 = num2 / (float)num; float num4 = layout.Actions.Min + (float)index * num3; float num5 = num4 + num3; rect.anchorMin = new Vector2(num4, 0.5f); rect.anchorMax = new Vector2(num5, 0.5f); rect.pivot = new Vector2(0.5f, 0.5f); rect.anchoredPosition = Vector2.zero; rect.sizeDelta = new Vector2(0f, 36f); rect.offsetMin = new Vector2(4f, -18f); rect.offsetMax = new Vector2(-4f, 18f); } internal static void PlaceRespawnButton(RectTransform rect, ScoreboardLayout layout) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) int count = layout.RowActions.Count; int num = Math.Max(1, count + 1); float num2 = layout.Actions.Max - layout.Actions.Min; float num3 = num2 / (float)num; float num4 = layout.Actions.Min + (float)count * num3; float max = layout.Actions.Max; rect.anchorMin = new Vector2(num4, 0.5f); rect.anchorMax = new Vector2(max, 0.5f); rect.pivot = new Vector2(0.5f, 0.5f); rect.anchoredPosition = Vector2.zero; rect.sizeDelta = new Vector2(0f, 36f); rect.offsetMin = new Vector2(4f, -18f); rect.offsetMax = new Vector2(-4f, 18f); } private static void ApplySlot(RectTransform rect, ScoreboardLayout.Slot slot, float leftPad) { //IL_000d: 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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) rect.anchorMin = new Vector2(slot.Min, 0f); rect.anchorMax = new Vector2(slot.Max, 1f); rect.offsetMin = new Vector2(leftPad, 4f); rect.offsetMax = new Vector2(-4f, -4f); } private static TextAlignmentOptions ToTmp(ScoreboardTextAlign align) { //IL_000e: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) return (TextAlignmentOptions)(align switch { ScoreboardTextAlign.Left => 4097, ScoreboardTextAlign.Right => 4100, _ => 514, }); } } internal sealed class ScoreboardLayout { public readonly struct Slot { public float Min { get; } public float Max { get; } public float Mid => (Min + Max) * 0.5f; public Slot(float min, float max) { Min = min; Max = max; } } private const float BuiltInTotalWeight = 90f; private const float ActionBaseWeight = 10f; private const float ActionExtraWeight = 8f; private const float ExtensionUnitWeight = 8f; public Slot Scout { get; private set; } public Slot State { get; private set; } public Slot Stamina { get; private set; } public Slot Effects { get; private set; } public Slot Height { get; private set; } public Slot Travel { get; private set; } public Slot Deaths { get; private set; } public Slot Actions { get; private set; } public IReadOnlyList<ScoreboardColumn> Columns { get; private set; } = Array.Empty<ScoreboardColumn>(); public IReadOnlyList<ScoreboardRowAction> RowActions { get; private set; } = Array.Empty<ScoreboardRowAction>(); public IReadOnlyList<Slot> ColumnSlots { get; private set; } = Array.Empty<Slot>(); public int RegistryVersion { get; private set; } = -1; public static ScoreboardLayout Capture() { ScoreboardLayout scoreboardLayout = new ScoreboardLayout(); scoreboardLayout.Rebuild(ScoreboardRegistry.SnapshotColumns(), ScoreboardRegistry.SnapshotActions(), ScoreboardRegistry.Version); return scoreboardLayout; } public bool NeedsRebuild(int registryVersion) { return RegistryVersion != registryVersion; } public void Rebuild(IReadOnlyList<ScoreboardColumn> columns, IReadOnlyList<ScoreboardRowAction> rowActions, int registryVersion) { Columns = columns; RowActions = rowActions; RegistryVersion = registryVersion; float num = 0f; for (int i = 0; i < columns.Count; i++) { num += Mathf.Max(0.25f, columns[i].WidthWeight) * 8f; } float num2 = 10f + (float)rowActions.Count * 8f; float num3 = 90f + num + num2; if (num3 <= 0f) { num3 = 100f; } float cursor = 0f; Scout = Take(ref cursor, 22f / num3); State = Take(ref cursor, 8f / num3); Stamina = Take(ref cursor, 18f / num3); Effects = Take(ref cursor, 18f / num3); Height = Take(ref cursor, 9f / num3); Travel = Take(ref cursor, 9f / num3); Deaths = Take(ref cursor, 6f / num3); Slot[] array = new Slot[columns.Count]; for (int j = 0; j < columns.Count; j++) { float width = Mathf.Max(0.25f, columns[j].WidthWeight) * 8f / num3; array[j] = Take(ref cursor, width); } ColumnSlots = array; Actions = new Slot(cursor, 1f); } private static Slot Take(ref float cursor, float width) { float min = cursor; cursor = Mathf.Min(1f, cursor + width); return new Slot(min, cursor); } } internal sealed class ScoreboardView { private readonly CanvasGroup _canvasGroup; private readonly TMP_FontAsset _font; private readonly TextMeshProUGUI _subtitle; private readonly TextMeshProUGUI _status; private readonly RectTransform _panel; private readonly RectTransform _rowContent; private readonly ScrollRect _scroll; private readonly ScoreboardHeaderView _header; private readonly List<ScoreboardRowView> _rows = new List<ScoreboardRowView>(); private ScoreboardLayout _layout = ScoreboardLayout.Capture(); public GameObject Root { get; } public ScoreboardWindow Window { get; } public Action? OnCloseRequested { get; set; } private ScoreboardView(GameObject root, ScoreboardWindow window, CanvasGroup canvasGroup, TMP_FontAsset font, TextMeshProUGUI subtitle, TextMeshProUGUI status, RectTransform panel, RectTransform rowContent, ScrollRect scroll, ScoreboardHeaderView header) { Root = root; Window = window; _canvasGroup = canvasGroup; _font = font; _subtitle = subtitle; _status = status; _panel = panel; _rowContent = rowContent; _scroll = scroll; _header = header; } public static ScoreboardView Create() { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0136: 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_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_034d: Unknown result type (might be due to invalid IL or missing references) //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_0452: Unknown result type (might be due to invalid IL or missing references) //IL_045e: Unknown result type (might be due to invalid IL or missing references) //IL_0474: Unknown result type (might be due to invalid IL or missing references) //IL_048a: Unknown result type (might be due to invalid IL or missing references) //IL_04f8: Unknown result type (might be due to invalid IL or missing references) //IL_0549: Unknown result type (might be due to invalid IL or missing references) //IL_055f: Unknown result type (might be due to invalid IL or missing references) //IL_0575: Unknown result type (might be due to invalid IL or missing references) //IL_0581: Unknown result type (might be due to invalid IL or missing references) //IL_058d: Unknown result type (might be due to invalid IL or missing references) //IL_05d2: Unknown result type (might be due to invalid IL or missing references) //IL_05dc: Expected O, but got Unknown //IL_068c: Unknown result type (might be due to invalid IL or missing references) //IL_0696: Expected O, but got Unknown GameObject val = new GameObject("PeakScoreboardUI", new Type[5] { typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler), typeof(CanvasGroup), typeof(GraphicRaycaster) }); try { RectTransform component = val.GetComponent<RectTransform>(); RuntimeUiFactory.Stretch(component); Canvas component2 = val.GetComponent<Canvas>(); component2.renderMode = (RenderMode)0; component2.sortingOrder = 240; CanvasScaler component3 = val.GetComponent<CanvasScaler>(); component3.uiScaleMode = (ScaleMode)1; component3.referenceResolution = new Vector2(1920f, 1080f); component3.screenMatchMode = (ScreenMatchMode)0; component3.matchWidthOrHeight = 0.5f; TMP_FontAsset font = RuntimeUiFactory.ResolveFont(); Image val2 = RuntimeUiFactory.CreateImage("Dim", (Transform)(object)component, RuntimeUiFactory.Backdrop); RuntimeUiFactory.Stretch(((Graphic)val2).rectTransform); ((Graphic)val2).raycastTarget = false; Image val3 = RuntimeUiFactory.CreateImage("Panel", (Transform)(object)component, RuntimeUiFactory.Panel); RectTransform rectTransform = ((Graphic)val3).rectTransform; rectTransform.anchorMin = new Vector2(0.5f, 0.5f); rectTransform.anchorMax = new Vector2(0.5f, 0.5f); rectTransform.pivot = new Vector2(0.5f, 0.5f); rectTransform.sizeDelta = new Vector2(1280f, 640f); TextMeshProUGUI val4 = RuntimeUiFactory.CreateText("Title", (Transform)(object)rectTransform, font, 34f, RuntimeUiFactory.TextPrimary, (TextAlignmentOptions)4097); ((TMP_Text)val4).text = "Scoreboard"; ((TMP_Text)val4).rectTransform.anchorMin = new Vector2(0f, 1f); ((TMP_Text)val4).rectTransform.anchorMax = new Vector2(1f, 1f); ((TMP_Text)val4).rectTransform.pivot = new Vector2(0.5f, 1f); ((TMP_Text)val4).rectTransform.anchoredPosition = new Vector2(0f, -18f); ((TMP_Text)val4).rectTransform.sizeDelta = new Vector2(-140f, 44f); Button val5 = RuntimeUiFactory.CreateButton("Close", (Transform)(object)rectTransform, font, "Close"); RectTransform component4 = ((Component)val5).GetComponent<RectTransform>(); component4.anchorMin = new Vector2(1f, 1f); component4.anchorMax = new Vector2(1f, 1f); component4.pivot = new Vector2(1f, 1f); component4.anchoredPosition = new Vector2(-24f, -16f); component4.sizeDelta = new Vector2(96f, 36f); TextMeshProUGUI val6 = RuntimeUiFactory.CreateText("Subtitle", (Transform)(object)rectTransform, font, 18f, RuntimeUiFactory.TextMuted, (TextAlignmentOptions)4097); ((TMP_Text)val6).text = "Press Scoreboard again or Close · click Respawn on dead scouts"; ((TMP_Text)val6).rectTransform.anchorMin = new Vector2(0f, 1f); ((TMP_Text)val6).rectTransform.anchorMax = new Vector2(1f, 1f); ((TMP_Text)val6).rectTransform.pivot = new Vector2(0.5f, 1f); ((TMP_Text)val6).rectTransform.anchoredPosition = new Vector2(0f, -62f); ((TMP_Text)val6).rectTransform.sizeDelta = new Vector2(-48f, 28f); ScoreboardHeaderView header = ScoreboardHeaderView.Create(rectTransform, font); TextMeshProUGUI val7 = RuntimeUiFactory.CreateText("Status", (Transform)(object)rectTransform, font, 17f, RuntimeUiFactory.TextMuted, (TextAlignmentOptions)4097); ((TMP_Text)val7).text = string.Empty; ((TMP_Text)val7).rectTransform.anchorMin = new Vector2(0f, 0f); ((TMP_Text)val7).rectTransform.anchorMax = new Vector2(1f, 0f); ((TMP_Text)val7).rectTransform.pivot = new Vector2(0.5f, 0f); ((TMP_Text)val7).rectTransform.anchoredPosition = new Vector2(0f, 16f); ((TMP_Text)val7).rectTransform.sizeDelta = new Vector2(-48f, 24f); RectTransform val8 = RuntimeUiFactory.CreateRect("Rows", (Transform)(object)rectTransform, typeof(ScrollRect)); val8.anchorMin = Vector2.zero; val8.anchorMax = Vector2.one; val8.offsetMin = new Vector2(24f, 48f); val8.offsetMax = new Vector2(-24f, -132f); RectTransform val9 = RuntimeUiFactory.CreateRect("Viewport", (Transform)(object)val8, typeof(Image), typeof(RectMask2D)); RuntimeUiFactory.Stretch(val9, 0f, 18f); ((Graphic)((Component)val9).GetComponent<Image>()).color = new Color(1f, 1f, 1f, 0.01f); ((Graphic)((Component)val9).GetComponent<Image>()).raycastTarget = true; RectTransform val10 = RuntimeUiFactory.CreateRect("Content", (Transform)(object)val9, typeof(VerticalLayoutGroup), typeof(ContentSizeFitter)); val10.anchorMin = new Vector2(0f, 1f); val10.anchorMax = new Vector2(1f, 1f); val10.pivot = new Vector2(0.5f, 1f); val10.anchoredPosition = Vector2.zero; val10.sizeDelta = Vector2.zero; VerticalLayoutGroup component5 = ((Component)val10).GetComponent<VerticalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)component5).spacing = 8f; ((HorizontalOrVerticalLayoutGroup)component5).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)component5).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)component5).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)component5).childForceExpandWidth = true; ((LayoutGroup)component5).padding = new RectOffset(0, 0, 0, 0); ((Component)val10).GetComponent<ContentSizeFitter>().verticalFit = (FitMode)2; Scrollbar verticalScrollbar = CreateVerticalScrollbar(val8); ScrollRect component6 = ((Component)val8).GetComponent<ScrollRect>(); component6.viewport = val9; component6.content = val10; component6.horizontal = false; component6.vertical = true; component6.movementType = (MovementType)2; component6.scrollSensitivity = 40f; component6.verticalScrollbar = verticalScrollbar; component6.verticalScrollbarVisibility = (ScrollbarVisibility)2; component6.verticalScrollbarSpacing = 4f; ScoreboardWindow window = val.AddComponent<ScoreboardWindow>(); Object.DontDestroyOnLoad((Object)(object)val); ScoreboardView view = new ScoreboardView(val, window, val.GetComponent<CanvasGroup>(), font, val6, val7, rectTransform, val10, component6, header); ((UnityEven