Decompiled source of PEAK RANKED v1.6.0

plugins/RankedPeak.dll

Decompiled 2 days ago
using System;
using System.Buffers.Binary;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.WebSockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Peak;
using Peak.Afflictions;
using Peak.Network;
using Photon.Pun;
using Photon.Realtime;
using Photon.Voice;
using Photon.Voice.PUN;
using Photon.Voice.Unity;
using RankedPeak.Live;
using RankedPeak.Localization;
using RankedPeak.Models;
using RankedPeak.Patches;
using RankedPeak.Replay;
using RankedPeak.Seeds;
using RankedPeak.Services;
using RankedPeak.Timer;
using RankedPeak.Tracking;
using RankedPeak.Ui;
using RankedPeak.Ui.Menu;
using RankedPeak.Ui.Native;
using RankedPeak.Utils;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Zorro.ControllerSupport;
using Zorro.Core;
using Zorro.Core.CLI;
using Zorro.Core.Serizalization;
using Zorro.UI;
using Zorro.UI.Modal;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ThomasAusHH")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("NEW: Chinese, Simplified and Traditional - localization by TFJSN (ETWML). REVIVE in LIVE RACE, REPLAY your failed runs, GHOSTS V2, TRAINING with pause and rewind, ELO ladder, daily cup, 1v1 duels and a speedrun timer.")]
[assembly: AssemblyFileVersion("1.6.0.0")]
[assembly: AssemblyInformationalVersion("1.6.0+d9cc34fa2fac0825ca291601e0319c186985fcbc")]
[assembly: AssemblyProduct("RankedPeak")]
[assembly: AssemblyTitle("RankedPeak")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://discord.gg/nKUHvzdmVp")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.6.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace RankedPeak
{
	public enum RankedLogLevel
	{
		Error,
		Warning,
		Info,
		Debug
	}
	internal static class RankedLog
	{
		public static void Error(string message)
		{
			if (Enabled(RankedLogLevel.Error))
			{
				Plugin.Log.LogError((object)message);
			}
		}

		public static void Warning(string message)
		{
			if (Enabled(RankedLogLevel.Warning))
			{
				Plugin.Log.LogWarning((object)message);
			}
		}

		public static void Info(string message)
		{
			if (Enabled(RankedLogLevel.Info))
			{
				Plugin.Log.LogInfo((object)message);
			}
		}

		public static void Debug(string message)
		{
			if (Enabled(RankedLogLevel.Debug))
			{
				Plugin.Log.LogDebug((object)message);
			}
		}

		private static bool Enabled(RankedLogLevel level)
		{
			return level <= (Plugin.LogLevel?.Value ?? RankedLogLevel.Info);
		}
	}
	[BepInPlugin("com.rankedpeak.mod", "PEAK RANKED", "1.6.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.rankedpeak.mod";

		public const string PluginName = "PEAK RANKED";

		public const string PluginVersion = "1.6.0";

		public const string VersionLabel = "";

		private Harmony _harmony;

		private RunStorageService _storageService;

		private RaceTimer _raceTimer;

		private ClimbStorageService _climbStorageService;

		private SeedService _seedService;

		public static string DisplayVersion
		{
			get
			{
				if (!string.IsNullOrEmpty(""))
				{
					return "1.6.0 ";
				}
				return "1.6.0";
			}
		}

		internal static ManualLogSource Log { get; private set; }

		internal static ConfigEntry<KeyCode> OverlayToggleKey { get; private set; }

		internal static ConfigEntry<float> OverlayPositionX { get; private set; }

		internal static ConfigEntry<float> OverlayPositionY { get; private set; }

		internal static ConfigEntry<KeyCode> RunResetKey { get; private set; }

		internal static ConfigEntry<GameMode> SelectedMode { get; private set; }

		internal static ConfigEntry<bool> DebugSpawnLogging { get; private set; }

		internal static ConfigEntry<RankedLogLevel> LogLevel { get; private set; }

		internal static ConfigEntry<KeyCode> RaceMenuKey { get; private set; }

		internal static ConfigEntry<bool> GhostEnabled { get; private set; }

		internal static ConfigEntry<float> GhostOpacity { get; private set; }

		internal static ConfigEntry<float> GhostItemOpacity { get; private set; }

		internal static ConfigEntry<bool> VoiceReverb { get; private set; }

		internal static ConfigEntry<KeyCode> ReplayPlayPauseKey { get; private set; }

		internal static ConfigEntry<KeyCode> ReplaySeekBackKey { get; private set; }

		internal static ConfigEntry<KeyCode> ReplaySeekForwardKey { get; private set; }

		internal static ConfigEntry<KeyCode> ReplaySlowerKey { get; private set; }

		internal static ConfigEntry<KeyCode> ReplayFasterKey { get; private set; }

		internal static ConfigEntry<KeyCode> ReplayDockKey { get; private set; }

		internal static ConfigEntry<float> ReplaySeekSeconds { get; private set; }

		internal static ConfigEntry<KeyCode> TrainingPauseKey { get; private set; }

		internal static ConfigEntry<int> ReplayKeepDnf { get; private set; }

		internal static ClimbStorageService ClimbStorage { get; private set; }

		internal static ConfigEntry<bool> GhostItemsEnabled { get; private set; }

		internal static ConfigEntry<int> LiveGhostCount { get; private set; }

		internal static ConfigEntry<KeyCode> SpectateKey { get; private set; }

		internal static ConfigEntry<KeyCode> ClockToggleKey { get; private set; }

		internal static ConfigEntry<bool> RaceHudEnabled { get; private set; }

		internal static ConfigEntry<float> RaceHudX { get; private set; }

		internal static ConfigEntry<float> RaceHudY { get; private set; }

		internal static ConfigEntry<bool> ComparisonManual { get; private set; }

		internal static ConfigEntry<bool> GhostPanelEnabled { get; private set; }

		internal static ConfigEntry<float> GhostPanelX { get; private set; }

		internal static ConfigEntry<float> GhostPanelY { get; private set; }

		internal static ConfigEntry<bool> UseNativeTimer { get; private set; }

		internal static ConfigEntry<bool> ShowRunSummary { get; private set; }

		internal static ConfigEntry<bool> TrackVanillaRuns { get; private set; }

		internal static ConfigEntry<bool> SummaryMinimized { get; private set; }

		internal static ConfigEntry<KeyCode> SettingsMenuKey { get; private set; }

		internal static ConfigEntry<bool> ChatEnabled { get; private set; }

		internal static ConfigEntry<bool> ChatOutsideRace { get; private set; }

		internal static ConfigEntry<bool> RacePublic { get; private set; }

		internal static ConfigEntry<KeyCode> ChatFocusKey { get; private set; }

		internal static ConfigEntry<KeyCode> ChatToggleKey { get; private set; }

		internal static ConfigEntry<float> ChatX { get; private set; }

		internal static ConfigEntry<float> ChatY { get; private set; }

		internal static ConfigEntry<float> ChatFadeSeconds { get; private set; }

		internal static ConfigFile ConfigFile { get; private set; }

		internal static RunStorageService StorageService { get; private set; }

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)("PEAK RANKED " + DisplayVersion + " geladen. API: https://followme-peak.ddns.net"));
			InitializeConfig();
			Loc.Initialize();
			InitializeServices();
			ApplyHarmonyPatches();
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void InitializeConfig()
		{
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Expected O, but got Unknown
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Expected O, but got Unknown
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Expected O, but got Unknown
			//IL_0445: Unknown result type (might be due to invalid IL or missing references)
			//IL_044c: Invalid comparison between Unknown and I4
			//IL_055a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0564: Expected O, but got Unknown
			//IL_058d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0597: Expected O, but got Unknown
			//IL_0697: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a1: Expected O, but got Unknown
			ConfigFile = ((BaseUnityPlugin)this).Config;
			OverlayToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Overlay", "ToggleKey", (KeyCode)289, "Hotkey zum Ein-/Ausblenden des Timer-Overlays.");
			OverlayPositionX = ((BaseUnityPlugin)this).Config.Bind<float>("Overlay", "PositionX", 10f, "Overlay X-Position in Pixeln (von links).");
			OverlayPositionY = ((BaseUnityPlugin)this).Config.Bind<float>("Overlay", "PositionY", 10f, "Overlay Y-Position in Pixeln (von oben).");
			UseNativeTimer = ((BaseUnityPlugin)this).Config.Bind<bool>("Overlay", "UseNativeTimer", true, "true = natives uGUI-Timer-Panel (E4.3) statt IMGUI-Overlay. Position (PositionX/Y) und Toggle (F8) gelten fuer beide.");
			RunResetKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "RunResetKey", (KeyCode)0, "Soft-Reset-Hotkey (E1.5): verwirft den laufenden Run und armiert den Timer neu (State -> Armed). KeyCode.None = deaktiviert. Kein hartes Level-Reload - das waere ein Spiel-Logik-Eingriff und bleibt bewusst aussen vor.");
			SelectedMode = ((BaseUnityPlugin)this).Config.Bind<GameMode>("Ranked", "GameMode", GameMode.StaticDaily, "Modus des naechsten Runs. Setzen die Schilder im Hauptmenue - der Wert hier dient nur als Ausgangswert und zur Diagnose.");
			DebugSpawnLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "SpawnLogging", false, "true = loggt jeden Spawn-Vorgang (Spawner, Position, Items) ins BepInEx-Log. Fuer die Seed-Verifikation (docs/seed-spike.md §8): zwei Runs mit gleichem Seed muessen identische Logs liefern. Eigener Schalter, unabhaengig von LogLevel.");
			LogLevel = ((BaseUnityPlugin)this).Config.Bind<RankedLogLevel>("Debug", "LogLevel", RankedLogLevel.Info, "Schwellenwert fuer alle Log-Zeilen des Mods (RankedLog): Error = nur Fehler, Warning = zusaetzlich Warnungen, Info = zusaetzlich normale Ablaufmeldungen (Vorgabe), Debug = zusaetzlich ausfuehrliche Diagnosemeldungen. Wirkt sofort, kein Neustart noetig. Der Start-Banner und das SpawnLogging-Protokoll haengen bewusst nicht an dieser Stufe.");
			RaceMenuKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "RaceMenuKey", (KeyCode)287, "Hotkey fuer das Race-Menue (Code, Teilnehmer, Verlassen) - auch im Flughafen und waehrend eines Rennens. KeyCode.None = deaktiviert.");
			SettingsMenuKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "SettingsMenuKey", (KeyCode)288, "Hotkey fuer das Einstellungsfenster (RankedSettingsModal) - im Hauptmenue wie auf dem Berg. Alle Werte dieser Datei lassen sich dort im Spiel setzen; das Fenster ist die eigentliche Bedienung, diese Datei nur ihr Speicherort. KeyCode.None = deaktiviert (dann bleibt das Schild EINSTELLUNGEN im Hauptmenue der einzige Weg).");
			GhostEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Ranked", "GhostEnabled", true, "true = waehrend eines Runs laeuft der eigene PB-Ghost mit (E5.5): ein durchsichtiger, nicht-kollidierender Marker auf dem Pfad des schnellsten eigenen Completed-Climbs (gleiche Map + Modus, lokale climbs.json).");
			GhostOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("Ranked", "GhostOpacity", 0.6f, new ConfigDescription("Deckkraft des Ghosts: 0 = unsichtbar, 1 = undurchsichtig. Wirkt sofort, auch waehrend ein Ghost laeuft. Das Einstellungsfenster bietet fuenf Stufen an (0.2 / 0.4 / 0.6 / 0.8 / 1.0); hier ist jeder Wert dazwischen erlaubt.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), Array.Empty<object>()));
			GhostItemOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("Ranked", "GhostItemOpacity", 0.6f, new ConfigDescription("Deckkraft der Items der Live-Ghosts: was sie in der Hand halten, ihre Ballons und was sie gesetzt haben (Seile, Ketten, Anker, Haken, Ranken). Getrennt von der Figur einstellbar - ein Seil, das man kaum sieht, ist im Weg, eine Figur, die man kaum sieht, nicht. Wirkt sofort.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), Array.Empty<object>()));
			SpectateKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "SpectateKey", (KeyCode)289, "Nach dem eigenen Zieleinlauf in einem Live Race: als Geist auf der Insel bleiben und den anderen zusehen, statt in den Flughafen zu gehen. Dieselbe Taste beendet das Zuschauen wieder (Escape ebenfalls). KeyCode.None = deaktiviert.");
			ClockToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "ClockToggleKey", (KeyCode)99, "Nach dem eigenen Zieleinlauf im Live Race, waehrend man jemandem zusieht: schaltet die grosse Uhr im Timer-Panel zwischen der eigenen, eingefrorenen Zielzeit und der laufenden Zeit des Beobachteten um. KeyCode.None = deaktiviert (dann bleibt die eigene Zeit stehen).");
			LiveGhostCount = ((BaseUnityPlugin)this).Config.Bind<int>("Ranked", "LiveGhostCount", 4, new ConfigDescription("Wie viele Mitstreiter im Live-Race gleichzeitig als Figur erscheinen. 0 = keine. Nur eine Anzeigeeinstellung: der Host entscheidet, OB es ueberhaupt Figuren gibt (dann verwirft schon der Server Position und Animation) - dieser Wert kann das nur weiter einschraenken, nie aufheben. Gezeichnet werden immer die naechsten in Reichweite.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 8), Array.Empty<object>()));
			GhostItemsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Ranked", "GhostItemsEnabled", true, "true = der Ghost haelt das Item in der Hand, das der Laeufer an dieser Stelle hielt. Aus, wenn das im Rennen zu viel Bewegung im Bild ist - die Aufzeichnung laeuft unabhaengig davon weiter und das Ghost-Panel zeigt das Inventar ohnehin.");
			ComparisonManual = ((BaseUnityPlugin)this).Config.Bind<bool>("Ranked", "ComparisonManual", false, "false = der Vergleich im Timer ist automatisch der schnellste eigene Lauf auf derselben Karte und Strecke. true = es gilt der Lauf, den du in der Rangliste unter MEINE LAEUFE festgenagelt hast; ohne Wahl greift wieder die Automatik.");
			RacePublic = ((BaseUnityPlugin)this).Config.Bind<bool>("Race", "ListInLobbyBrowser", false, "true = ein neu angelegtes Live Race steht im Lobby-Browser. false = nur mit Code zu finden. Merkt sich die letzte Wahl im Renn-Fenster.");
			RaceHudEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Overlay", "RaceHudEnabled", true, "true = waehrend eines Rennens zeigt die Renn-Anzeige den Zwischenstand: Platz, Name, Fortschritt, Leisten und Items je Teilnehmer.");
			RaceHudX = ((BaseUnityPlugin)this).Config.Bind<float>("Overlay", "RaceHudPositionX", 1510f, "X-Position der Renn-Anzeige in Canvas-Einheiten, von links. Bequemer ueber das Einstellungsfenster zu setzen: dort haengt sich die Anzeige an die Maus.");
			RaceHudY = ((BaseUnityPlugin)this).Config.Bind<float>("Overlay", "RaceHudPositionY", 20f, "Y-Position der Renn-Anzeige in Canvas-Einheiten, von oben.");
			GhostPanelEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Ranked", "GhostPanelEnabled", true, "true = waehrend eines Laufs gegen einen fremden Ghost zeigt ein kleines Panel dessen Uhr, Ausdauer, Statuswerte und Inventar (E5.7).");
			GhostPanelX = ((BaseUnityPlugin)this).Config.Bind<float>("Ranked", "GhostPanelPositionX", 10f, "X-Position des Ghost-Panels in Canvas-Einheiten, von links. Bequemer ueber das Einstellungsfenster zu setzen: dort haengt sich das Panel an die Maus.");
			GhostPanelY = ((BaseUnityPlugin)this).Config.Bind<float>("Ranked", "GhostPanelPositionY", 260f, "Y-Position des Ghost-Panels in Canvas-Einheiten, von oben.");
			SummaryMinimized = ((BaseUnityPlugin)this).Config.Bind<bool>("Overlay", "SummaryMinimized", false, "true = der Ergebnis-Screen erscheint zusammengeklappt als schmale Leiste am unteren Bildrand und gibt den Pfadfinderbericht des Spiels frei. Der Knopf in der Titelleiste des Fensters schreibt diesen Wert - wer einmal zuklappt, bekommt es beim naechsten Lauf gleich klein.");
			ShowRunSummary = ((BaseUnityPlugin)this).Config.Bind<bool>("Overlay", "ShowRunSummary", true, "true = nach Run-Ende erscheint der Summary-Screen (E4.4): Ergebnis, Gesamtzeit, Splits, PB-Vergleich, Upload-Status und Daily-Board-Platzierung. Schliesst automatisch beim naechsten Run.");
			TrackVanillaRuns = ((BaseUnityPlugin)this).Config.Bind<bool>("Overlay", "TrackVanillaRuns", false, "true = auch ein Lauf ausserhalb von PEAK RANKED (PLAY OFFLINE, HOST GAME, Beitritt zu einer fremden Lobby) bekommt Timer, Splits und Ergebniskarte. Vorgabe aus: ohne diesen Schalter bleibt ein Vanilla-Lauf unberuehrt - keine Anzeige, keine Aufzeichnung, kein Eintrag in der lokalen Ablage. Gewertet wird ein solcher Lauf so oder so nicht; die Zeit bleibt lokal. Der Schalter gilt ab dem naechsten Lauf, nicht mitten im laufenden.");
			VoiceReverb = ((BaseUnityPlugin)this).Config.Bind<bool>("Chat", "VoiceReverb", false, "true = die Stimmen der Mitstreiter im Live Race klingen wie die einer Spielfigur: Hall in Hoehlen und Echo ab 60 m Entfernung (VoiceObscuranceFilter des Spiels). Vorgabe aus - im Rennen ist man fast immer weit auseinander, und dann liegt auf jeder Stimme ein halbsekuendiges Echo. Richtung, Entfernung und der dumpfe Klang hinter Felsen bleiben in beiden Faellen.");
			ReplayPlayPauseKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Replay", "PlayPauseKey", (KeyCode)112, "Replay: Abspielen/Anhalten. KeyCode.None = deaktiviert. Die Leertaste ist fuer das Hochfliegen der freien Kamera reserviert.");
			if ((int)ReplayPlayPauseKey.Value == 32)
			{
				ReplayPlayPauseKey.Value = (KeyCode)112;
			}
			ReplaySeekBackKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Replay", "SeekBackKey", (KeyCode)276, "Replay: um ReplaySeekSeconds zurueckspulen.");
			ReplaySeekForwardKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Replay", "SeekForwardKey", (KeyCode)275, "Replay: um ReplaySeekSeconds vorspulen.");
			ReplaySlowerKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Replay", "SlowerKey", (KeyCode)274, "Replay: langsamer (0.25x / 0.5x / 1x / 2x / 4x).");
			ReplayFasterKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Replay", "FasterKey", (KeyCode)273, "Replay: schneller.");
			ReplayDockKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Replay", "DockKey", (KeyCode)102, "Replay: Kamera am Ghost andocken oder frei fliegen (WASD, Leertaste/Strg hoch/runter, Shift schnell).");
			TrainingPauseKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Replay", "TrainingPauseKey", (KeyCode)112, "Ghost-Training: alles einfrieren (Timer, Figur, Welt) und dem Ghost auf der Zeitleiste zusehen; dieselbe Taste setzt fort. Ist sie gleich der Play/Pause-Taste, gewinnt in der Pause das Fortsetzen - der Ghost laeuft dann ueber den Knopf in der Leiste.");
			ReplaySeekSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Replay", "SeekSeconds", 10f, new ConfigDescription("Sprungweite beim Spulen in Sekunden.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>()));
			ReplayKeepDnf = ((BaseUnityPlugin)this).Config.Bind<int>("Replay", "KeepDnfRecordings", 10, new ConfigDescription("Wie viele nicht beendete Laeufe (gestorben, abgebrochen) samt Aufzeichnung lokal bleiben - fuer REPLAY unter MEINE LAEUFE. Die aeltesten fallen zuerst. 0 = keine. Getrennt von den beendeten Laeufen, die eigene 100 Plaetze haben.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), Array.Empty<object>()));
			ChatEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Chat", "Enabled", true, "true = im Live Race erscheint der Text-Chat der Teilnehmer (Flughafen und Insel). Details in docs/live-chat.md.");
			ChatOutsideRace = ((BaseUnityPlugin)this).Config.Bind<bool>("Chat", "ShowOutsideRace", false, "true = das Chat-Fenster ist auch ohne laufendes Rennen sichtbar. Vorgabe aus - ohne Rennen gibt es keine Mitspieler zu erreichen.");
			ChatFocusKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "ChatFocusKey", (KeyCode)121, "Holt den Chat in den Schreibmodus: Eingabefeld auf, Tastatur wird abgefangen. Enter sendet, Escape verwirft - beides gibt den Fokus wieder frei. KeyCode.None = deaktiviert.");
			ChatToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "ChatToggleKey", (KeyCode)290, "Blendet das gesamte Chat-Fenster samt Nachrichten ein und aus. KeyCode.None = deaktiviert.");
			ChatX = ((BaseUnityPlugin)this).Config.Bind<float>("Chat", "PositionX", 28f, "X-Position des Chat-Fensters in Canvas-Einheiten, von links. Bequemer ueber das Einstellungsfenster zu setzen: dort haengt sich die Anzeige an die Maus.");
			ChatY = ((BaseUnityPlugin)this).Config.Bind<float>("Chat", "PositionY", 760f, "Y-Position des Chat-Fensters in Canvas-Einheiten, von oben.");
			ChatFadeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Chat", "FadeSeconds", 12f, new ConfigDescription("Wie lange eine Zeile im Lesemodus stehen bleibt, bevor sie ausblendet. Im Schreibmodus altert nichts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 60f), Array.Empty<object>()));
		}

		private void InitializeServices()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//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_0068: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Expected O, but got Unknown
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Expected O, but got Unknown
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Expected O, but got Unknown
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Expected O, but got Unknown
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Expected O, but got Unknown
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Expected O, but got Unknown
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Expected O, but got Unknown
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Expected O, but got Unknown
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Expected O, but got Unknown
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Expected O, but got Unknown
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Expected O, but got Unknown
			//IL_0262: 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_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Expected O, but got Unknown
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Expected O, but got Unknown
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Expected O, but got Unknown
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Expected O, but got Unknown
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Expected O, but got Unknown
			_storageService = new RunStorageService();
			StorageService = _storageService;
			_raceTimer = new RaceTimer(_storageService);
			_raceTimer.Arm();
			GameObject val = new GameObject("RankedPeak_TimerOverlay");
			Object.DontDestroyOnLoad((Object)val);
			val.AddComponent<TimerOverlay>().Initialize(_raceTimer, _storageService);
			GameObject val2 = new GameObject("RankedPeak_NativeTimerPanel");
			Object.DontDestroyOnLoad((Object)val2);
			val2.AddComponent<NativeTimerPanel>().Initialize(_raceTimer, _storageService);
			GameObject val3 = new GameObject("RankedPeak_RunSummary");
			Object.DontDestroyOnLoad((Object)val3);
			val3.AddComponent<RunSummaryPanel>().Initialize(_raceTimer, _storageService);
			GameObject val4 = new GameObject("RankedPeak_Settings");
			Object.DontDestroyOnLoad((Object)val4);
			val4.AddComponent<RankedSettingsModal>();
			GameObject val5 = new GameObject("RankedPeak_Help");
			Object.DontDestroyOnLoad((Object)val5);
			val5.AddComponent<RankedHelpModal>();
			GameObject val6 = new GameObject("RankedPeak_RunUpload");
			Object.DontDestroyOnLoad((Object)val6);
			RunUploadService uploadService = val6.AddComponent<RunUploadService>();
			GameObject val7 = new GameObject("RankedPeak_RunSentinel");
			Object.DontDestroyOnLoad((Object)val7);
			val7.AddComponent<RunSentinel>();
			GameObject val8 = new GameObject("RankedPeak_Spectator");
			Object.DontDestroyOnLoad((Object)val8);
			val8.AddComponent<SpectatorService>();
			_climbStorageService = new ClimbStorageService();
			ClimbStorage = _climbStorageService;
			GameObject val9 = new GameObject("RankedPeak_Replay");
			Object.DontDestroyOnLoad((Object)val9);
			val9.AddComponent<ReplayService>();
			GameObject val10 = new GameObject("RankedPeak_Revive");
			Object.DontDestroyOnLoad((Object)val10);
			val10.AddComponent<ReviveController>();
			GameObject val11 = new GameObject("RankedPeak_ClimbTracking");
			Object.DontDestroyOnLoad((Object)val11);
			val11.AddComponent<ClimbTrackingService>().Initialize(_raceTimer, _climbStorageService, uploadService);
			GameObject val12 = new GameObject("RankedPeak_GhostStatus");
			Object.DontDestroyOnLoad((Object)val12);
			val12.AddComponent<GhostStatusPanel>();
			GameObject val13 = new GameObject("RankedPeak_GhostPlayback");
			Object.DontDestroyOnLoad((Object)val13);
			val13.AddComponent<GhostPlaybackService>().Initialize(_raceTimer, _climbStorageService);
			_seedService = new SeedService();
			GameObject val14 = new GameObject("RankedPeak_DailySeed");
			Object.DontDestroyOnLoad((Object)val14);
			val14.AddComponent<DailySeedService>().RefreshIfStale();
			GameObject val15 = new GameObject("RankedPeak_ModAllowlist");
			Object.DontDestroyOnLoad((Object)val15);
			val15.AddComponent<ModAllowlistService>().RefreshIfStale();
			GameObject val16 = new GameObject("RankedPeak_ItemBlocklist");
			Object.DontDestroyOnLoad((Object)val16);
			val16.AddComponent<ItemBlocklistService>().RefreshIfStale();
			GameObject val17 = new GameObject("RankedPeak_RatingService");
			Object.DontDestroyOnLoad((Object)val17);
			val17.AddComponent<RatingService>();
			GameObject val18 = new GameObject("RankedPeak_DuelService");
			Object.DontDestroyOnLoad((Object)val18);
			val18.AddComponent<DuelService>();
			GameObject val19 = new GameObject("RankedPeak_RaceService");
			Object.DontDestroyOnLoad((Object)val19);
			val19.AddComponent<RaceService>();
			GameObject val20 = new GameObject("RankedPeak_RaceHud");
			Object.DontDestroyOnLoad((Object)val20);
			val20.AddComponent<RaceHudOverlay>();
			val20.AddComponent<RaceCountdownOverlay>();
			GameObject val21 = new GameObject("RankedPeak_RaceLive");
			Object.DontDestroyOnLoad((Object)val21);
			val21.AddComponent<RaceLiveConnection>();
			GameObject val22 = new GameObject("RankedPeak_LiveGhosts");
			Object.DontDestroyOnLoad((Object)val22);
			val22.AddComponent<LiveGhostManager>();
			val22.AddComponent<GhostPlacements>();
			GameObject val23 = new GameObject("RankedPeak_LiveChat");
			Object.DontDestroyOnLoad((Object)val23);
			val23.AddComponent<LiveChatOverlay>();
			GameObject val24 = new GameObject("RankedPeak_RaceVoice");
			Object.DontDestroyOnLoad((Object)val24);
			val24.AddComponent<RaceVoiceService>();
			val24.AddComponent<RaceVoiceMixerPanel>();
			RankedRoomGuard.Install();
			GameObject val25 = new GameObject("RankedPeak_UpdateCheck");
			Object.DontDestroyOnLoad((Object)val25);
			val25.AddComponent<UpdateCheckService>();
			RankedLog.Info("Services initialisiert (RaceTimer, RunStorageService, TimerOverlay, ClimbTrackingService, RunUploadService, SeedService, DailySeedService, ModAllowlistService, GhostPlaybackService, RatingService, DuelService, RaceService).");
		}

		private void ApplyHarmonyPatches()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			_harmony = new Harmony("com.rankedpeak.mod");
			try
			{
				_harmony.PatchAll(typeof(RunLifecyclePatches));
				_harmony.PatchAll(typeof(SpectatorPatches));
				_harmony.PatchAll(typeof(RankedExitPatch));
				RunLifecyclePatches.ApplyEndGamePatches(_harmony);
				_harmony.PatchAll(typeof(SeedScopePatches.TrySpawnItemsPatch));
				_harmony.PatchAll(typeof(SeedScopePatches.SpawnItemsPatch));
				_harmony.PatchAll(typeof(SeedScopePatches.GetSpawnSpotsPatch));
				_harmony.PatchAll(typeof(SeedScopePatches.GroundPlaceSpawnerPatch));
				_harmony.PatchAll(typeof(SeedScopePatches.BerryBushPatch));
				_harmony.PatchAll(typeof(SeedScopePatches.BerryVinePatch));
				_harmony.PatchAll(typeof(SeedScopePatches.TempleSeedPatch));
				_harmony.PatchAll(typeof(MainMenuPatches.PageInjectionPatch));
				_harmony.PatchAll(typeof(MainMenuPatches.SignpostPatch));
				_harmony.PatchAll(typeof(BoardingPassPatch));
				_harmony.PatchAll(typeof(RaceInputLockPatch));
				_harmony.PatchAll(typeof(GhostPlacementPatches.VineBuiltPatch));
				_harmony.PatchAll(typeof(GhostPlacementPatches.PitonHammeredPatch));
				_harmony.PatchAll(typeof(WeatherSyncPatches.ZoneStartPatch));
				_harmony.PatchAll(typeof(WeatherSyncPatches.ZoneTimePatch));
				_harmony.PatchAll(typeof(WeatherSyncPatches.SpawnerPatch));
				_harmony.PatchAll(typeof(WeatherSyncPatches.TornadoStartPatch));
				_harmony.PatchAll(typeof(WeatherSyncPatches.TornadoTargetPatch));
				_harmony.PatchAll(typeof(WeatherSyncPatches.DayTimePatch));
				_harmony.PatchAll(typeof(ReplayCursorPatch));
				_harmony.PatchAll(typeof(ReviveGuardPatches.TryCheckpointPatch));
				_harmony.PatchAll(typeof(ReviveGuardPatches.DieInstantlyPatch));
				_harmony.PatchAll(typeof(ReviveGuardPatches.DieInstantlyLocalPatch));
				_harmony.PatchAll(typeof(ReviveGuardPatches.HandlePassedOutPatch));
				_harmony.PatchAll(typeof(RaceVoicePatches.RoomNamePatch));
				_harmony.PatchAll(typeof(RaceVoicePatches.RegionPatch));
				_harmony.PatchAll(typeof(RaceVoicePatches.SpeakerPatch));
				_harmony.PatchAll(typeof(HotbarKeyWasPressedWhileTypingPatch));
				_harmony.PatchAll(typeof(HotbarKeyIsPressedWhileTypingPatch));
				_harmony.PatchAll(typeof(PauseWhileTypingPatch));
				_harmony.PatchAll(typeof(RunSettingsPatch));
				_harmony.PatchAll(typeof(ItemBlockPatch));
				_harmony.PatchAll(typeof(SteamLobbyCreatedPatch));
				_harmony.PatchAll(typeof(RankedRoomPrivacyPatches.HostRoomOptionsPatch));
				_harmony.PatchAll(typeof(RankedRoomPrivacyPatches.LobbyTypePatch));
				_harmony.PatchAll(typeof(RankedRoomPrivacyPatches.RichPresencePatch));
				SentinelPatches.Apply(_harmony);
				RankedLog.Info("Harmony-Patches angewendet.");
			}
			catch (Exception arg)
			{
				RankedLog.Error($"Harmony-Patching fehlgeschlagen: {arg}");
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			Loc.Refresh();
			try
			{
				if (_raceTimer == null)
				{
					return;
				}
				MapCatalog.LogDiagnostics("Szene '" + ((Scene)(ref scene)).name + "'");
				SentinelPatches.ApplyConsoleGuards(_harmony);
				if (((Scene)(ref scene)).name.StartsWith("Level_"))
				{
					_seedService?.ResetForNewScene();
					if ((Object)(object)DailySeedService.Instance != (Object)null)
					{
						DailySeedService.Instance.RefreshIfStale();
					}
				}
				if ((_raceTimer.State == TimerState.Running || _raceTimer.State == TimerState.WaitingForInput) && !((Scene)(ref scene)).name.StartsWith("Level_"))
				{
					RankedLog.Info("[Plugin] Szenenwechsel nach '" + ((Scene)(ref scene)).name + "' bei aktivem Run - Run abgebrochen.");
					_raceTimer.AbortRun();
				}
				if (!((Scene)(ref scene)).name.StartsWith("Level_"))
				{
					RatingService.Instance?.RefreshRating();
					ModAllowlistService.Instance?.RefreshIfStale();
					ItemBlocklistService.Instance?.RefreshIfStale();
					RankedGameLauncher.ReapplyForcedLevel();
				}
			}
			catch (Exception arg)
			{
				RankedLog.Error($"[Plugin] Fehler in OnSceneLoaded: {arg}");
			}
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class BuildInfo
	{
		public const string Version = "1.6.0";

		public const string Label = "";

		public const string ProductName = "PEAK RANKED";

		public const string LanServerUrl = "http://localhost:3000";
	}
}
namespace RankedPeak.Utils
{
	public static class ClimbDataCrusher
	{
		private static class NanCodes
		{
			internal const byte AbsoluteReposition = 1;

			internal const byte AsHalfFloats = 2;
		}

		public static void WriteClimbData(MemoryStream dataStream, List<Vector3> points)
		{
			//IL_0014: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			if (points.Count < 2)
			{
				return;
			}
			byte[] array = new byte[14];
			Vector3 val = points[0];
			EncodePointAsFloats(array, val);
			dataStream.Write(array.AsSpan(0, 12));
			for (int i = 1; i < points.Count; i++)
			{
				Vector3 val2 = points[i];
				QuarterFloat quarter = QuarterFloat.FromFloat(val2.x - val.x);
				QuarterFloat quarter2 = QuarterFloat.FromFloat(val2.y - val.y);
				QuarterFloat quarter3 = QuarterFloat.FromFloat(val2.z - val.z);
				if (quarter.IsInfinity() || quarter2.IsInfinity() || quarter3.IsInfinity())
				{
					HalfFloat half = HalfFloat.FromFloat(val2.x - val.x);
					HalfFloat half2 = HalfFloat.FromFloat(val2.y - val.y);
					HalfFloat half3 = HalfFloat.FromFloat(val2.z - val.z);
					if (half.IsInfinity() || half2.IsInfinity() || half3.IsInfinity())
					{
						EncodeQuarterFloat(array.AsSpan(0, 1), QuarterFloat.EncodeNaN(1));
						EncodePointAsFloats(array.AsSpan(1, 12), val2);
						val = val2;
						dataStream.Write(array.AsSpan(0, 13));
						continue;
					}
					EncodeQuarterFloat(array.AsSpan(0, 1), QuarterFloat.EncodeNaN(2));
					EncodeHalfFloat(array.AsSpan(1, 2), half);
					EncodeHalfFloat(array.AsSpan(3, 2), half2);
					EncodeHalfFloat(array.AsSpan(5, 2), half3);
					val.x += half.ToFloat();
					val.y += half2.ToFloat();
					val.z += half3.ToFloat();
					dataStream.Write(array.AsSpan(0, 7));
				}
				else
				{
					if (quarter.IsZero() && quarter2.IsZero())
					{
						quarter3.IsZero();
					}
					EncodeQuarterFloat(array.AsSpan(0, 1), quarter);
					EncodeQuarterFloat(array.AsSpan(1, 1), quarter2);
					EncodeQuarterFloat(array.AsSpan(2, 1), quarter3);
					val.x += quarter.ToFloat();
					val.y += quarter2.ToFloat();
					val.z += quarter3.ToFloat();
					dataStream.Write(array.AsSpan(0, 3));
				}
			}
		}

		public static List<Vector3> ReadClimbData(byte[] data)
		{
			//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)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: 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_0072: 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_00ee: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3>();
			if (data == null || data.Length < 12)
			{
				return list;
			}
			Vector3 item = DecodePointFromFloats(data.AsSpan(0, 12));
			list.Add(item);
			int num = 12;
			while (num < data.Length)
			{
				QuarterFloat quarterFloat = DecodeQuarterFloat(data.AsSpan(num, 1));
				if (quarterFloat.IsNaN())
				{
					switch (quarterFloat.DecodeNaN())
					{
					case 1:
						item = DecodePointFromFloats(data.AsSpan(num + 1, 12));
						list.Add(item);
						num += 13;
						break;
					case 2:
						item.x += DecodeHalfFloat(data.AsSpan(num + 1, 2)).ToFloat();
						item.y += DecodeHalfFloat(data.AsSpan(num + 3, 2)).ToFloat();
						item.z += DecodeHalfFloat(data.AsSpan(num + 5, 2)).ToFloat();
						list.Add(item);
						num += 7;
						break;
					default:
						throw new InvalidOperationException($"Unexpected NaN code in climb data: {quarterFloat.DecodeNaN()}");
					}
				}
				else
				{
					item.x += quarterFloat.ToFloat();
					item.y += DecodeQuarterFloat(data.AsSpan(num + 1, 1)).ToFloat();
					item.z += DecodeQuarterFloat(data.AsSpan(num + 2, 1)).ToFloat();
					list.Add(item);
					num += 3;
				}
			}
			return list;
		}

		private static void EncodePointAsFloats(Span<byte> span, Vector3 firstPoint)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			EncodeFloat(span.Slice(0, 4), firstPoint.x);
			EncodeFloat(span.Slice(4, 4), firstPoint.y);
			EncodeFloat(span.Slice(8, 4), firstPoint.z);
		}

		private static Vector3 DecodePointFromFloats(Span<byte> data)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(DecodeFloat(data.Slice(0, 4)), DecodeFloat(data.Slice(4, 4)), DecodeFloat(data.Slice(8, 4)));
		}

		private static void EncodeFloat(Span<byte> span, float value)
		{
			BinaryPrimitives.WriteInt32LittleEndian(span, BitConverter.SingleToInt32Bits(value));
		}

		private static float DecodeFloat(Span<byte> span)
		{
			return BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(span));
		}

		private static void EncodeHalfFloat(Span<byte> span, HalfFloat half)
		{
			BinaryPrimitives.WriteUInt16LittleEndian(span, half.RawValue);
		}

		private static HalfFloat DecodeHalfFloat(Span<byte> span)
		{
			return new HalfFloat
			{
				RawValue = BinaryPrimitives.ReadUInt16LittleEndian(span)
			};
		}

		private static void EncodeQuarterFloat(Span<byte> span, QuarterFloat quarter)
		{
			span[0] = quarter.RawValue;
		}

		private static QuarterFloat DecodeQuarterFloat(Span<byte> span)
		{
			return new QuarterFloat
			{
				RawValue = span[0]
			};
		}
	}
	public struct HalfFloat
	{
		public const byte TotalNumBits = 16;

		public const byte NumExponentBits = 4;

		public const byte NumMantissaBits = 11;

		public const byte SignBitPos = 15;

		private const ushort SignBit = 32768;

		private const ushort ExponentMask = 30720;

		private const ushort MantissaMask = 2047;

		private const ushort ExponentInfinity = 15;

		private const int ExponentBias = 7;

		private const int SingleExponentBias = 127;

		private const byte SingleNumExponentBits = 8;

		private const byte SingleNumMantissaBits = 23;

		private const byte SingleSignBitPos = 31;

		private const uint SingleExponentMask = 2139095040u;

		private const uint SingleMantissaMask = 8388607u;

		private const uint SingleExponentInfinity = 255u;

		public ushort RawValue;

		public static HalfFloat NaN => new HalfFloat
		{
			RawValue = 30721
		};

		public ushort ExponentBits => (ushort)((uint)(RawValue & 0x7800) >> 11);

		public ushort MantissaBits => (ushort)(RawValue & 0x7FF);

		public static HalfFloat FromFloat(float value)
		{
			int num = BitConverter.SingleToInt32Bits(value);
			uint num2 = (uint)num >> 31;
			uint num3 = (uint)(num & 0x7F800000) >> 23;
			uint num4 = (uint)(num & 0x7FFFFF);
			int num5 = (int)(num3 - 127 + 7);
			if (num5 == -11)
			{
				num4 = 0u;
				num5++;
			}
			else if (num5 > -11)
			{
				uint num6 = (uint)(1 << 11 + Math.Max(0, 1 - num5));
				if ((num4 & num6) != 0)
				{
					num4 += num6;
					if ((num4 & 0xFF800000u) != 0)
					{
						num4 = 0u;
						num5++;
					}
				}
			}
			if (num5 >= 15)
			{
				if (num4 != 0 && num3 == 255)
				{
					return NaN;
				}
				num5 = 15;
				num4 = 0u;
			}
			else if (num5 <= 0)
			{
				if (num5 > -11)
				{
					num4 |= 0x800000;
					int num7 = 1 - num5;
					num4 >>= num7;
					num5 = 0;
				}
				else
				{
					num5 = 0;
					num4 = 0u;
				}
			}
			ushort num8 = (ushort)(num2 << 15);
			ushort num9 = (ushort)(num5 << 11);
			ushort num10 = (ushort)(num4 >> 12);
			return new HalfFloat
			{
				RawValue = (ushort)(num8 | num9 | num10)
			};
		}

		public float ToFloat()
		{
			uint num = (uint)((RawValue & 0x8000) << 16);
			uint exponentBits = ExponentBits;
			uint num2 = MantissaBits;
			if (exponentBits == 0 && num2 == 0)
			{
				return BitConverter.Int32BitsToSingle((int)num);
			}
			uint num3 = exponentBits + 127 - 7;
			if (exponentBits == 15)
			{
				num3 = 255u;
			}
			else if (exponentBits == 0)
			{
				while ((num2 & 0x800) == 0)
				{
					num2 <<= 1;
					num3--;
				}
				num2 &= 0x7FF;
				num3++;
			}
			return BitConverter.Int32BitsToSingle((int)(num | (num3 << 23) | (num2 << 12)));
		}

		public static HalfFloat EncodeNaN(ushort value)
		{
			value++;
			ushort num = (ushort)((uint)value >> 11);
			if (num > 1)
			{
				throw new ArgumentOutOfRangeException("value", "Value too large to encode as NaN");
			}
			ushort num2 = (ushort)(value & 0x7FF);
			return new HalfFloat
			{
				RawValue = (ushort)((num << 15) | 0x7800 | num2)
			};
		}

		public ushort DecodeNaN()
		{
			if (!IsNaN())
			{
				throw new InvalidOperationException("Not a NaN value");
			}
			ushort num = (ushort)((RawValue & 0x8000) >>> 15);
			ushort num2 = (ushort)(RawValue & 0x7FF);
			return (ushort)(((num << 11) | num2) - 1);
		}

		public bool IsNaN()
		{
			if (ExponentBits == 15)
			{
				return MantissaBits != 0;
			}
			return false;
		}

		public bool IsInfinity()
		{
			if (ExponentBits == 15)
			{
				return MantissaBits == 0;
			}
			return false;
		}

		public bool IsPositiveInfinity()
		{
			if (IsInfinity())
			{
				return (RawValue & 0x8000) == 0;
			}
			return false;
		}

		public bool IsNegativeInfinity()
		{
			if (IsInfinity())
			{
				return (RawValue & 0x8000) != 0;
			}
			return false;
		}

		public bool IsZero()
		{
			return (RawValue & -32769) == 0;
		}

		public bool IsPositiveZero()
		{
			return RawValue == 0;
		}

		public bool IsNegativeZero()
		{
			return RawValue == 32768;
		}

		public bool IsDenormalized()
		{
			if (ExponentBits == 0)
			{
				return MantissaBits != 0;
			}
			return false;
		}

		public override string ToString()
		{
			return ToFloat().ToString(CultureInfo.InvariantCulture);
		}
	}
	public struct QuarterFloat
	{
		public const byte TotalNumBits = 8;

		public const byte NumExponentBits = 2;

		public const byte NumMantissaBits = 5;

		public const byte SignBitPos = 7;

		private const byte SignBit = 128;

		private const byte ExponentMask = 96;

		private const byte MantissaMask = 31;

		private const byte ExponentInfinity = 3;

		private const int ExponentBias = 1;

		private const int SingleExponentBias = 127;

		private const byte SingleNumExponentBits = 8;

		private const byte SingleNumMantissaBits = 23;

		private const byte SingleSignBitPos = 31;

		private const uint SingleExponentMask = 2139095040u;

		private const uint SingleMantissaMask = 8388607u;

		private const uint SingleExponentInfinity = 255u;

		public byte RawValue;

		public static QuarterFloat NaN => new QuarterFloat
		{
			RawValue = 97
		};

		public byte ExponentBits => (byte)((uint)(RawValue & 0x60) >> 5);

		public byte MantissaBits => (byte)(RawValue & 0x1F);

		public static QuarterFloat FromFloat(float value)
		{
			int num = BitConverter.SingleToInt32Bits(value);
			uint num2 = (uint)num >> 31;
			uint num3 = (uint)(num & 0x7F800000) >> 23;
			uint num4 = (uint)(num & 0x7FFFFF);
			int num5 = (int)(num3 - 127 + 1);
			if (num5 == -5)
			{
				num4 = 0u;
				num5++;
			}
			else if (num5 > -5)
			{
				uint num6 = (uint)(1 << 17 + Math.Max(0, 1 - num5));
				if ((num4 & num6) != 0)
				{
					num4 += num6;
					if ((num4 & 0xFF800000u) != 0)
					{
						num4 = 0u;
						num5++;
					}
				}
			}
			if (num5 >= 3)
			{
				if (num4 != 0 && num3 == 255)
				{
					return NaN;
				}
				num5 = 3;
				num4 = 0u;
			}
			else if (num5 <= 0)
			{
				if (num5 > -5)
				{
					num4 |= 0x800000;
					int num7 = 1 - num5;
					num4 >>= num7;
					num5 = 0;
				}
				else
				{
					num5 = 0;
					num4 = 0u;
				}
			}
			byte b = (byte)(num2 << 7);
			byte b2 = (byte)(num5 << 5);
			byte b3 = (byte)(num4 >> 18);
			return new QuarterFloat
			{
				RawValue = (byte)(b | b2 | b3)
			};
		}

		public float ToFloat()
		{
			uint num = (uint)((RawValue & 0x80) << 24);
			uint exponentBits = ExponentBits;
			uint num2 = MantissaBits;
			if (exponentBits == 0 && num2 == 0)
			{
				return BitConverter.Int32BitsToSingle((int)num);
			}
			uint num3 = exponentBits + 127 - 1;
			if (exponentBits == 3)
			{
				num3 = 255u;
			}
			else if (exponentBits == 0)
			{
				while ((num2 & 0x20) == 0)
				{
					num2 <<= 1;
					num3--;
				}
				num2 &= 0x1F;
				num3++;
			}
			return BitConverter.Int32BitsToSingle((int)(num | (num3 << 23) | (num2 << 18)));
		}

		public static QuarterFloat EncodeNaN(byte value)
		{
			value++;
			byte b = (byte)((uint)value >> 5);
			if (b > 1)
			{
				throw new ArgumentOutOfRangeException("value", "Value too large to encode as NaN");
			}
			byte b2 = (byte)(value & 0x1F);
			return new QuarterFloat
			{
				RawValue = (byte)((b << 7) | 0x60 | b2)
			};
		}

		public byte DecodeNaN()
		{
			if (!IsNaN())
			{
				throw new InvalidOperationException("Not a NaN value");
			}
			byte num = (byte)((RawValue & 0x80) >>> 7);
			byte b = (byte)(RawValue & 0x1F);
			return (byte)(((num << 5) | b) - 1);
		}

		public bool IsNaN()
		{
			if (ExponentBits == 3)
			{
				return MantissaBits != 0;
			}
			return false;
		}

		public bool IsInfinity()
		{
			if (ExponentBits == 3)
			{
				return MantissaBits == 0;
			}
			return false;
		}

		public bool IsPositiveInfinity()
		{
			if (IsInfinity())
			{
				return (RawValue & 0x80) == 0;
			}
			return false;
		}

		public bool IsNegativeInfinity()
		{
			if (IsInfinity())
			{
				return (RawValue & 0x80) != 0;
			}
			return false;
		}

		public bool IsZero()
		{
			return (RawValue & -129) == 0;
		}

		public bool IsPositiveZero()
		{
			return RawValue == 0;
		}

		public bool IsNegativeZero()
		{
			return RawValue == 128;
		}

		public bool IsDenormalized()
		{
			if (ExponentBits == 0)
			{
				return MantissaBits != 0;
			}
			return false;
		}

		public override string ToString()
		{
			return ToFloat().ToString(CultureInfo.InvariantCulture);
		}
	}
	public static class MenuHierarchyDump
	{
		public static void Dump(MainMenuMainPage page)
		{
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("[MenuDump] === Title-Menue-Hierarchie ===");
				stringBuilder.AppendLine($"[MenuDump] MainPage '{((Object)page).name}' {RectInfo(((Component)page).transform)} children={((Component)page).transform.childCount}:");
				DumpChildren(stringBuilder, ((Component)page).transform, 1, 1);
				TMP_SpriteAsset[] array = Resources.FindObjectsOfTypeAll<TMP_SpriteAsset>();
				if (array != null && array.Length != 0)
				{
					TMP_SpriteAsset[] array2 = array;
					foreach (TMP_SpriteAsset val in array2)
					{
						string text = ((val.spriteCharacterTable != null) ? string.Join(", ", val.spriteCharacterTable.Select((TMP_SpriteCharacter c) => c.name)) : "keine");
						stringBuilder.AppendLine("[MenuDump] SpriteAsset '" + ((Object)val).name + "': " + text);
					}
				}
				DumpLogoDetail(stringBuilder, ((Component)page).transform.Find("Logo"), "Logo");
				DumpLogoDetail(stringBuilder, ((Component)page).transform.Find("LogoBlack"), "LogoBlack");
				Transform val2 = (((Object)(object)page.m_playButton != (Object)null) ? ((Component)page.m_playButton).transform.parent : null);
				if ((Object)(object)val2 != (Object)null)
				{
					stringBuilder.AppendLine("[MenuDump] Linker Original-Mast (Sign-Container): '" + ((Object)val2).name + "' " + RectInfo(val2));
					DumpChildren(stringBuilder, val2, 1, 4);
					if ((Object)(object)val2.parent != (Object)null && (Object)(object)val2.parent != (Object)(object)((Component)page).transform)
					{
						stringBuilder.AppendLine("[MenuDump] Linker Mast-Parent: '" + ((Object)val2.parent).name + "' " + RectInfo(val2.parent));
						DumpChildren(stringBuilder, val2.parent, 1, 2);
					}
				}
				Transform val3 = ((Component)page).transform.Find("RankedSignpostContainer") ?? (((Object)(object)((val2 != null) ? val2.parent : null) != (Object)null) ? val2.parent.Find("RankedSignpostContainer") : null);
				if ((Object)(object)val3 != (Object)null)
				{
					stringBuilder.AppendLine("[MenuDump] Rechter Ranked-Mast: '" + ((Object)val3).name + "' " + RectInfo(val3));
					DumpChildren(stringBuilder, val3, 1, 2);
				}
				else
				{
					stringBuilder.AppendLine("[MenuDump] Rechter Ranked-Mast: noch nicht gefunden.");
				}
				RankedLog.Debug(stringBuilder.ToString());
			}
			catch (Exception ex)
			{
				RankedLog.Warning("[MenuDump] Fehler beim Hierarchie-Dump: " + ex.Message);
			}
		}

		private static void DumpLogoDetail(StringBuilder sb, Transform root, string label)
		{
			if ((Object)(object)root == (Object)null)
			{
				sb.AppendLine("[MenuDump] " + label + ": nicht gefunden.");
				return;
			}
			sb.AppendLine("[MenuDump] === " + label + " im Detail ===");
			DumpLogoNode(sb, root, 0);
		}

		private static void DumpLogoNode(StringBuilder sb, Transform node, int indent)
		{
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			string text = new string(' ', indent * 2);
			sb.AppendLine($"{text}'{((Object)node).name}' {RectInfo(node)} active={((Component)node).gameObject.activeSelf} ({Components(node)})");
			Graphic component = ((Component)node).GetComponent<Graphic>();
			if ((Object)(object)component != (Object)null)
			{
				Material materialForRendering = component.materialForRendering;
				string text2 = (((Object)(object)materialForRendering != (Object)null && (Object)(object)materialForRendering.shader != (Object)null) ? ((Object)materialForRendering.shader).name : "-");
				string text3 = (((Object)(object)materialForRendering != (Object)null) ? ((Object)materialForRendering).name : "-");
				sb.AppendLine($"{text}  -> Graphic {((object)component).GetType().Name}: color={component.color} material='{text3}' shader='{text2}'");
				Image val = (Image)(object)((component is Image) ? component : null);
				if (val != null)
				{
					string text4 = (((Object)(object)val.sprite != (Object)null) ? ((Object)val.sprite).name : "-");
					string text5 = (((Object)(object)val.sprite != (Object)null && (Object)(object)val.sprite.texture != (Object)null) ? ((Object)val.sprite.texture).name : "-");
					sb.AppendLine($"{text}  -> Image: sprite='{text4}' texture='{text5}' type={val.type} fill={val.fillAmount}");
				}
				if ((Object)(object)materialForRendering != (Object)null)
				{
					string[] texturePropertyNames = materialForRendering.GetTexturePropertyNames();
					if (texturePropertyNames != null && texturePropertyNames.Length != 0)
					{
						sb.AppendLine(text + "  -> Textur-Slots: " + string.Join(", ", texturePropertyNames));
					}
				}
			}
			Mask component2 = ((Component)node).GetComponent<Mask>();
			if ((Object)(object)component2 != (Object)null)
			{
				sb.AppendLine($"{text}  -> Mask: showMaskGraphic={component2.showMaskGraphic}");
			}
			Animator component3 = ((Component)node).GetComponent<Animator>();
			if ((Object)(object)component3 != (Object)null)
			{
				RuntimeAnimatorController runtimeAnimatorController = component3.runtimeAnimatorController;
				string text6 = (((Object)(object)runtimeAnimatorController != (Object)null && runtimeAnimatorController.animationClips != null) ? string.Join(", ", runtimeAnimatorController.animationClips.Select((AnimationClip c) => (!((Object)(object)c != (Object)null)) ? "?" : $"{((Object)c).name} ({c.length:0.##}s, loop={((Motion)c).isLooping})")) : "keine");
				sb.AppendLine(string.Format("{0}  -> Animator: controller='{1}' clips=[{2}] enabled={3} speed={4}", text, ((Object)(object)runtimeAnimatorController != (Object)null) ? ((Object)runtimeAnimatorController).name : "-", text6, ((Behaviour)component3).enabled, component3.speed));
			}
			for (int num = 0; num < node.childCount; num++)
			{
				DumpLogoNode(sb, node.GetChild(num), indent + 1);
			}
		}

		private static void DumpChildren(StringBuilder sb, Transform parent, int indent, int maxDepth)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			string text = new string(' ', indent * 2);
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform child = parent.GetChild(i);
				TextMeshProUGUI componentInChildren = ((Component)child).GetComponentInChildren<TextMeshProUGUI>(true);
				string text2 = (((Object)(object)componentInChildren != (Object)null) ? (" text='" + ((TMP_Text)componentInChildren).text + "'") : string.Empty);
				Image component = ((Component)child).GetComponent<Image>();
				string text3 = (((Object)(object)component != (Object)null && (Object)(object)component.sprite != (Object)null) ? $" sprite='{((Object)component.sprite).name}' type={component.type}" : string.Empty);
				sb.AppendLine($"{text}[{i}] '{((Object)child).name}' {RectInfo(child)} active={((Component)child).gameObject.activeSelf}{text2}{text3} ({Components(child)})");
				if (indent < maxDepth)
				{
					DumpChildren(sb, child, indent + 1, maxDepth);
				}
			}
		}

		private static string RectInfo(Transform t)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = (RectTransform)(object)((t is RectTransform) ? t : null);
			if (val != null)
			{
				return $"pos={val.anchoredPosition} size={val.sizeDelta} scale={((Transform)val).localScale} pivot={val.pivot} anchorMin={val.anchorMin} anchorMax={val.anchorMax}";
			}
			return $"localPos={t.localPosition} scale={t.localScale}";
		}

		private static string Components(Transform t)
		{
			Component[] components = ((Component)t).GetComponents<Component>();
			string[] array = new string[components.Length];
			for (int i = 0; i < components.Length; i++)
			{
				array[i] = (((Object)(object)components[i] != (Object)null) ? ((object)components[i]).GetType().Name : "?");
			}
			return string.Join(",", array);
		}
	}
}
namespace RankedPeak.Ui
{
	public class CustomRunModal : MenuWindow
	{
		private enum RaceView
		{
			RoleSelect,
			HostSetup,
			JoinEntry,
			Board
		}

		private const float WindowWidth = 1180f;

		private const float TitleBarHeight = 82f;

		private const float WindowPadding = 26f;

		private const float BoxPadding = 24f;

		private const float BoxGap = 14f;

		private const float BodyBottomPadding = 18f;

		private const int MinSeed = 100000000;

		private const int MaxSeed = 999999999;

		private const int MaxParticipantRows = 32;

		private const int ParticipantColumns = 4;

		private const float ParticipantRowHeight = 22f;

		private static readonly int[] PlayerSteps = new int[9] { 2, 3, 4, 6, 8, 12, 16, 24, 32 };

		private static readonly int[] AutoEndStepsMs = new int[7] { 0, 30000, 60000, 120000, 180000, 300000, 600000 };

		private const float ModeRowY = 8f;

		private const float ModeRowHeight = 44f;

		private const float MountainBoxHeight = 194f;

		private const float RandomBoxHeight = 96f;

		private const float AscentBoxHeight = 128f;

		private const float RouteBoxHeight = 146f;

		private const float RaceBoxHeight = 300f;

		private const float RoleBoxHeight = 170f;

		private const float FooterHeight = 52f;

		private const float JoinBoxHeight = 170f;

		private const float BrowserHeight = 540f;

		private const float LobbyRefreshSeconds = 5f;

		private const float SeedRowY = 50f;

		private const float MapRowY = 112f;

		private const float MapHintY = 160f;

		private const float RaceRow1Y = 50f;

		private const float RaceRow2Y = 104f;

		private const float RaceRow3Y = 160f;

		private static CustomRunModal _speedrunInstance;

		private static CustomRunModal _raceInstance;

		private RaceView _view;

		private RectTransform _root;

		private PeakWindowStyle.WindowParts _window;

		private TMP_InputField _seedInput;

		private TMP_InputField _codeInput;

		private TextMeshProUGUI _ascentDescriptionLabel;

		private TextMeshProUGUI _routeDescriptionLabel;

		private TextMeshProUGUI _summaryLabel;

		private TextMeshProUGUI _levelLabel;

		private TextMeshProUGUI _levelDescriptionLabel;

		private TextMeshProUGUI _playersLabel;

		private TextMeshProUGUI _codeLabel;

		private TextMeshProUGUI _modeHintLabel;

		private TextMeshProUGUI _joinHintLabel;

		private RectTransform _mountainBox;

		private RectTransform _randomBox;

		private RectTransform _ascentBox;

		private RectTransform _routeBox;

		private RectTransform _raceBox;

		private RectTransform _roleBox;

		private Button _staticModeButton;

		private Button _randomModeButton;

		private Button _dailyButton;

		private Button _rollSeedButton;

		private Button _copySeedButton;

		private Button _levelPrevButton;

		private Button _levelNextButton;

		private Button _todayButton;

		private Button _playersPrevButton;

		private Button _playersNextButton;

		private Button _autoStartButton;

		private Button _rivalsButton;

		private Button _startButton;

		private Button _cancelButton;

		private Button _backButton;

		private Button _createButton;

		private Button _hostStartButton;

		private Button _leaveButton;

		private Button _copyCodeButton;

		private Button _joinButton;

		private Button _spectateButton;

		private Button _spectatorsButton;

		private Button _autoEndButton;

		private Button _voiceButton;

		private Button _rulesButton;

		private Button _visibilityButton;

		private RaceLobbyBrowser _browser;

		private bool _browserVisible;

		private bool _lobbyFetchInFlight;

		private float _nextLobbyFetch;

		private readonly List<Button> _ascentPills = new List<Button>();

		private readonly List<Button> _routePills = new List<Button>();

		private readonly List<TextMeshProUGUI> _participantRows = new List<TextMeshProUGUI>();

		private readonly List<RaceParticipant> _standings = new List<RaceParticipant>();

		private PeakWindowStyle.ScrollArea _participantArea;

		private RaceBoardPanel _boardPanel;

		private bool _built;

		private bool _raceMode;

		private bool _randomMode;

		private int _seed = 100000000;

		private int _ascent;

		private int _routeIndex;

		private int _levelSlot;

		private int _maxPlayers = 4;

		private bool _autoStart = true;

		private bool _showRivals = true;

		private bool _spectatorsAllowed = true;

		private int _autoEndMs;

		private bool _voiceChat;

		private bool _isPublic;

		private readonly RaceRules _rules = new RaceRules();

		private GameObject _panelPlaceholder;

		private int _openedFrame = -1;

		public override bool openOnStart => false;

		public override bool selectOnOpen => false;

		public override GameObject panel
		{
			get
			{
				if (!((Object)(object)_root != (Object)null))
				{
					return _panelPlaceholder;
				}
				return ((Component)_root).gameObject;
			}
		}

		private void Awake()
		{
			_seed = Random.Range(100000000, 999999999);
		}

		public override void Start()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			_panelPlaceholder = new GameObject("PanelPlaceholder");
			_panelPlaceholder.transform.SetParent(((Component)this).transform, false);
			_panelPlaceholder.SetActive(false);
		}

		public static void OpenSpeedrun()
		{
			OpenModal(raceMode: false);
		}

		public static void OpenRace()
		{
			OpenModal(raceMode: true);
		}

		private static void OpenModal(bool raceMode)
		{
			//IL_0044: 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)
			if (RaceService.Instance?.CurrentRace != null)
			{
				raceMode = true;
			}
			CustomRunModal customRunModal = (raceMode ? _raceInstance : _speedrunInstance);
			if ((Object)(object)customRunModal == (Object)null)
			{
				Canvas canvas = NativeUiFactory.GetCanvas();
				GameObject val = new GameObject(raceMode ? "RankedPeak_RaceModal" : "RankedPeak_SpeedrunModal");
				val.transform.SetParent(((Component)canvas).transform, false);
				customRunModal = val.AddComponent<CustomRunModal>();
				customRunModal._raceMode = raceMode;
				if (raceMode)
				{
					_raceInstance = customRunModal;
				}
				else
				{
					_speedrunInstance = customRunModal;
				}
			}
			CustomRunModal customRunModal2 = (raceMode ? _speedrunInstance : _raceInstance);
			if ((Object)(object)customRunModal2 != (Object)null && (Object)(object)customRunModal2 != (Object)(object)customRunModal)
			{
				customRunModal2.CloseModal();
			}
			customRunModal.ShowModal();
		}

		public void ShowModal()
		{
			_openedFrame = Time.frameCount;
			if (!_built || (Object)(object)_root == (Object)null)
			{
				BuildUi();
			}
			if (_raceMode && RaceService.Instance?.CurrentRace == null)
			{
				_view = RaceView.RoleSelect;
				_isPublic = Plugin.RacePublic.Value;
			}
			else if (_raceMode && (ForcedBoardView() || _view != RaceView.HostSetup))
			{
				_view = RaceView.Board;
			}
			_levelSlot = MapCatalog.SlotOf(MapCatalog.CurrentLevelIndex);
			RefreshDisplay();
			((MenuWindow)this).Open();
			NativeUiFactory.EnsureTopMost();
		}

		public void CloseModal()
		{
			((MenuWindow)this).Close();
		}

		public static void CloseAll()
		{
			if ((Object)(object)_raceInstance != (Object)null && ((MenuWindow)_raceInstance).isOpen)
			{
				_raceInstance.CloseModal();
			}
			if ((Object)(object)_speedrunInstance != (Object)null && ((MenuWindow)_speedrunInstance).isOpen)
			{
				_speedrunInstance.CloseModal();
			}
		}

		private void OnEnable()
		{
			RaceService.RaceUpdated += OnRaceUpdated;
			Loc.LanguageChanged += OnLanguageChanged;
		}

		private void OnDisable()
		{
			RaceService.RaceUpdated -= OnRaceUpdated;
			Loc.LanguageChanged -= OnLanguageChanged;
		}

		private void OnLanguageChanged()
		{
			if (_built)
			{
				bool isOpen = ((MenuWindow)this).isOpen;
				if (isOpen)
				{
					CloseModal();
				}
				if ((Object)(object)_root != (Object)null)
				{
					((Component)_root).gameObject.SetActive(false);
					Object.Destroy((Object)(object)((Component)_root).gameObject);
					_root = null;
				}
				_built = false;
				_ascentPills.Clear();
				_routePills.Clear();
				_participantRows.Clear();
				_boardPanel = null;
				_browser = null;
				if (isOpen)
				{
					ShowModal();
				}
			}
		}

		private void OnRaceUpdated(RaceInfo race)
		{
			if (_raceMode)
			{
				RefreshDisplay();
				if (race != null && (race.Status == "loading" || race.Status == "countdown"))
				{
					CloseModal();
				}
			}
		}

		private static bool ForcedBoardView()
		{
			RaceInfo raceInfo = RaceService.Instance?.CurrentRace;
			if (raceInfo != null)
			{
				return raceInfo.Status != "lobby";
			}
			return false;
		}

		public override void Update()
		{
			if (!((MenuWindow)this).isOpen)
			{
				return;
			}
			if ((Object)(object)_root == (Object)null)
			{
				RankedLog.Warning("[Custom] Fenster offen, aber ohne Anzeige - wird geschlossen.");
				((MenuWindow)this).Close();
				return;
			}
			bool flag = ((Object)(object)_seedInput != (Object)null && _seedInput.isFocused) || ((Object)(object)_codeInput != (Object)null && _codeInput.isFocused);
			if (Input.GetKeyDown((KeyCode)27) && !flag && Time.frameCount > _openedFrame && !RaceRulesModal.IsAnyOpen && !RacePlayersModal.IsAnyOpen)
			{
				CloseModal();
			}
			if (_browserVisible && !_lobbyFetchInFlight && Time.unscaledTime >= _nextLobbyFetch)
			{
				FetchLobbies();
			}
			RaceInfo raceInfo = RaceService.Instance?.CurrentRace;
			if (_view == RaceView.HostSetup && ForcedBoardView())
			{
				_view = RaceView.Board;
				RefreshDisplay();
			}
			if (_boardPanel != null && raceInfo != null && _view != RaceView.HostSetup)
			{
				_boardPanel.Refresh(raceInfo, RaceService.Instance?.IsHost ?? false);
			}
		}

		private void BuildUi()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Expected O, but got Unknown
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			_built = true;
			Canvas canvas = NativeUiFactory.GetCanvas();
			GameObject val = new GameObject("CustomModalRoot", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(((Component)canvas).transform, false);
			_root = (RectTransform)val.transform;
			_root.anchorMin = Vector2.zero;
			_root.anchorMax = Vector2.one;
			_root.offsetMin = Vector2.zero;
			_root.offsetMax = Vector2.zero;
			PeakWindowStyle.CreateBackdrop((Transform)(object)_root, "Backdrop");
			_window = PeakWindowStyle.CreateWindow((Transform)(object)_root, "CustomWindow", 1180f, 900f, 82f, Loc.T(_raceMode ? "mode.liveRace" : "mode.speedrun"), Loc.T(_raceMode ? "run.race.subtitle" : "run.speedrun.subtitle"));
			Button obj = PeakWindowStyle.CreatePill((Transform)(object)_window.TitleBar, "BtnClose", "X", 1094f, 20f, 48f, 42f, 24f);
			Image component = ((Component)obj).GetComponent<Image>();
			if ((Object)(object)component != (Object)null)
			{
				((Graphic)component).color = new Color(1f, 1f, 1f, 0.22f);
			}
			((UnityEvent)obj.onClick).AddListener(new UnityAction(CloseModal));
			RectTransform body = _window.Body;
			float innerWidth = 1128f;
			if (_raceMode)
			{
				BuildRoleBox(body, innerWidth);
			}
			BuildModeRow(body, innerWidth);
			BuildMountainBox(body, innerWidth);
			BuildRandomBox(body, innerWidth);
			BuildAscentBox(body, innerWidth);
			BuildRouteBox(body, innerWidth);
			if (_raceMode)
			{
				BuildRaceBox(body, innerWidth);
				BuildBrowser(body, innerWidth);
				BuildBoard(body, innerWidth);
			}
			BuildFooter(body, innerWidth);
		}

		private void BuildBrowser(RectTransform body, float innerWidth)
		{
			_browser = RaceLobbyBrowser.Create((Transform)(object)body, "BoxBrowser", 26f, 0f, innerWidth, 540f);
			_browser.RefreshRequested = delegate
			{
				_nextLobbyFetch = 0f;
			};
			_browser.Join = delegate(RaceLobbyEntry entry)
			{
				_codeInput.text = entry.InviteCode;
				JoinRace();
			};
			_browser.Spectate = delegate(RaceLobbyEntry entry)
			{
				_codeInput.text = entry.InviteCode;
				SpectateRace();
			};
			_browser.SetActive(active: false);
		}

		private void FetchLobbies()
		{
			RaceService instance = RaceService.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				_lobbyFetchInFlight = true;
				instance.FetchLobbies(delegate(List<RaceLobbyEntry> entries, int total)
				{
					_lobbyFetchInFlight = false;
					_nextLobbyFetch = Time.unscaledTime + 5f;
					_browser?.SetEntries(entries, total);
				}, delegate(string error)
				{
					_lobbyFetchInFlight = false;
					_nextLobbyFetch = Time.unscaledTime + 5f;
					_browser?.SetError(error);
				});
			}
		}

		private void BuildRoleBox(RectTransform body, float innerWidth)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Expected O, but got Unknown
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Expected O, but got Unknown
			_roleBox = PeakWindowStyle.CreateBox((Transform)(object)body, "BoxRole", Loc.T("race.role.box"), 26f, 0f, innerWidth, 170f);
			float num = innerWidth - 48f;
			((UnityEvent)PeakWindowStyle.CreatePill((Transform)(object)_roleBox, "BtnRoleHost", Loc.T("race.role.host"), 24f, 52f, num / 2f - 7f, 56f, 21f).onClick).AddListener((UnityAction)delegate
			{
				_view = RaceView.HostSetup;
				_isPublic = Plugin.RacePublic.Value;
				RefreshDisplay();
			});
			Button obj = PeakWindowStyle.CreatePill((Transform)(object)_roleBox, "BtnRoleJoin", Loc.T("race.role.join"), 24f + num / 2f + 7f, 52f, num / 2f - 7f, 56f, 21f);
			PeakWindowStyle.SetPillSelected(obj, selected: false);
			((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
			{
				_view = RaceView.JoinEntry;
				RefreshDisplay();
			});
			NativeUiFactory.Place((RectTransform)((TMP_Text)PeakWindowStyle.CreateText((Transform)(object)_roleBox, "RoleHint", Loc.T("race.role.hint"), 19f, PeakWindowStyle.TextMuted, (TextAlignmentOptions)513)).transform, 24f, 120f, num, 34f);
		}

		private void BuildModeRow(RectTransform body, float innerWidth)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			//IL_00b6: 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)
			//IL_00fb: Expected O, but got Unknown
			_staticModeButton = PeakWindowStyle.CreatePill((Transform)(object)body, "ModeStatic", Loc.T("run.mode.static"), 26f, 8f, 220f, 44f);
			((UnityEvent)_staticModeButton.onClick).AddListener((UnityAction)delegate
			{
				SetRandomMode(randomMode: false);
			});
			_randomModeButton = PeakWindowStyle.CreatePill((Transform)(object)body, "ModeRandom", Loc.T("run.mode.random"), 254f, 8f, 220f, 44f);
			((UnityEvent)_randomModeButton.onClick).AddListener((UnityAction)delegate
			{
				SetRandomMode(randomMode: true);
			});
			_modeHintLabel = PeakWindowStyle.CreateText((Transform)(object)body, "ModeHint", Loc.T("run.mode.hint"), 19f, PeakWindowStyle.TextMuted, (TextAlignmentOptions)513);
			NativeUiFactory.Place((RectTransform)((TMP_Text)_modeHintLabel).transform, 494f, 8f, innerWidth - 468f, 44f);
		}

		private void BuildMountainBox(RectTransform body, float innerWidth)
		{
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Expected O, but got Unknown
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Expected O, but got Unknown
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Expected O, but got Unknown
			//IL_01cb: 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_0205: Expected O, but got Unknown
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Expected O, but got Unknown
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Expected O, but got Unknown
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Expected O, but got Unknown
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Expected O, but got Unknown
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a8: Expected O, but got Unknown
			_mountainBox = PeakWindowStyle.CreateBox((Transform)(object)body, "BoxMountain", Loc.T("run.box.mountain"), 26f, 0f, innerWidth, 194f);
			float num = innerWidth - 48f;
			_seedInput = PeakWindowStyle.CreateInputField((Transform)(object)_mountainBox, "SeedInput", _seed.ToString(), 24f, 50f, 300f, 52f, 30f);
			_seedInput.characterLimit = 9;
			((UnityEvent<string>)(object)_seedInput.onValueChanged).AddListener((UnityAction<string>)OnSeedTyped);
			((UnityEvent<string>)(object)_seedInput.onEndEdit).AddListener((UnityAction<string>)delegate
			{
				PushRaceConfig();
			});
			_dailyButton = PeakWindowStyle.CreatePill((Transform)(object)_mountainBox, "BtnDailySeed", Loc.T("run.btn.daily"), 336f, 50f, 130f, 52f, 19f);
			((UnityEvent)_dailyButton.onClick).AddListener(new UnityAction(UseDailySeed));
			_rollSeedButton = PeakWindowStyle.CreatePill((Transform)(object)_mountainBox, "BtnRollSeed", Loc.T("run.btn.rollSeed"), 476f, 50f, 150f, 52f, 19f);
			((UnityEvent)_rollSeedButton.onClick).AddListener(new UnityAction(RollSeed));
			_copySeedButton = PeakWindowStyle.CreatePill((Transform)(object)_mountainBox, "BtnCopySeed", Loc.T("run.btn.copySeed"), 636f, 50f, 150f, 52f, 19f);
			((UnityEvent)_copySeedButton.onClick).AddListener(new UnityAction(CopySeed));
			NativeUiFactory.Place((RectTransform)((TMP_Text)PeakWindowStyle.CreateText((Transform)(object)_mountainBox, "SeedHint", Loc.T("run.seed.hint"), 16f, PeakWindowStyle.TextMuted, (TextAlignmentOptions)513)).transform, 800f, 50f, num - 776f, 52f);
			_levelPrevButton = PeakWindowStyle.CreatePill((Transform)(object)_mountainBox, "BtnLevelPrev", "<", 24f, 112f, 52f, 42f);
			((UnityEvent)_levelPrevButton.onClick).AddListener((UnityAction)delegate
			{
				StepLevel(-1);
			});
			_levelLabel = PeakWindowStyle.CreateText((Transform)(object)_mountainBox, "LevelLabel", string.Empty, 20f, PeakWindowStyle.TextPrimary, (TextAlignmentOptions)514);
			NativeUiFactory.Place((RectTransform)((TMP_Text)_levelLabel).transform, 82f, 112f, 200f, 42f);
			_levelNextButton = PeakWindowStyle.CreatePill((Transform)(object)_mountainBox, "BtnLevelNext", ">", 288f, 112f, 52f, 42f);
			((UnityEvent)_levelNextButton.onClick).AddListener((UnityAction)delegate
			{
				StepLevel(1);
			});
			_todayButton = PeakWindowStyle.CreatePill((Transform)(object)_mountainBox, "BtnLevelToday", Loc.T("run.btn.today"), 348f, 112f, 120f, 42f, 18f);
			((UnityEvent)_todayButton.onClick).AddListener((UnityAction)delegate
			{
				_levelSlot = MapCatalog.SlotOf(MapCatalog.CurrentLevelIndex);
				PushRaceConfig();
				RefreshDisplay();
			});
			_levelDescriptionLabel = PeakWindowStyle.CreateText((Transform)(object)_mountainBox, "LevelDescription", string.Empty, 19f, PeakWindowStyle.TextMuted, (TextAlignmentOptions)513);
			NativeUiFactory.Place((RectTransform)((TMP_Text)_levelDescriptionLabel).transform, 24f, 160f, num, 24f);
		}

		private void BuildRandomBox(RectTransform body, float innerWidth)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			_randomBox = PeakWindowStyle.CreateBox((Transform)(object)body, "BoxRandom", Loc.T("run.box.random"), 26f, 0f, innerWidth, 96f);
			float width = innerWidth - 48f;
			NativeUiFactory.Place((RectTransform)((TMP_Text)PeakWindowStyle.CreateText((Transform)(object)_randomBox, "RandomHint", Loc.T(_raceMode ? "run.random.hint.race" : "run.random.hint.solo"), 21f, PeakWindowStyle.TextPrimary, (TextAlignmentOptions)513)).transform, 24f, 52f, width, 34f);
		}

		private void BuildAscentBox(RectTransform body, float innerWidth)
		{
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Expected O, but got Unknown
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			_ascentBox = PeakWindowStyle.CreateBox((Transform)(object)body, "BoxAscent", Loc.T("run.box.ascent"), 26f, 0f, innerWidth, 128f);
			float num = innerWidth - 48f;
			int num2 = Mathf.Max(1, RunConfigService.MaxAscent);
			int num3 = num2 + 2;
			float num4 = Mathf.Clamp((num - 140f - 110f - 8f * (float)(num3 - 1)) / (float)num2, 44f, 110f);
			float num5 = 24f;
			for (int i = -1; i <= RunConfigService.MaxAscent; i++)
			{
				float num6 = i switch
				{
					0 => 110f, 
					-1 => 140f, 
					_ => num4, 
				};
				int value = i;
				Button val = PeakWindowStyle.CreatePill((Transform)(object)_ascentBox, $"Ascent{i}", RunConfigService.GetAscentShortName(i), num5, 46f, num6, 44f, 19f);
				((UnityEvent)val.onClick).AddListener((UnityAction)delegate
				{
					_ascent = value;
					PushRaceConfig();
					RefreshDisplay();
				});
				_ascentPills.Add(val);
				num5 += num6 + 8f;
			}
			_ascentDescriptionLabel = PeakWindowStyle.CreateText((Transform)(object)_ascentBox, "AscentDescription", string.Empty, 20f, PeakWindowStyle.TextMuted, (TextAlignmentOptions)513);
			NativeUiFactory.Place((RectTransform)((TMP_Text)_ascentDescriptionLabel).transform, 24f, 96f, num, 28f);
		}

		private void BuildRouteBox(RectTransform body, float innerWidth)
		{
			//IL_00ef: 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_012e: Expected O, but got Unknown
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			_routeBox = PeakWindowStyle.CreateBox((Transform)(object)body, "BoxRoute", Loc.T("run.box.route"), 26f, 0f, innerWidth, 146f);
			float width = innerWidth - 48f;
			float num = 24f;
			for (int i = 0; i < RunConfigService.RouteCount; i++)
			{
				float num2 = ((i == 0) ? 220f : 145f);
				int value = i;
				Button val = PeakWindowStyle.CreatePill((Transform)(object)_routeBox, $"Route{i}", RunConfigService.GetRouteName(i), num, 46f, num2, 44f, 19f);
				((UnityEvent)val.onClick).AddListener((UnityAction)delegate
				{
					_routeIndex = value;
					PushRaceConfig();
					RefreshDisplay();
				});
				_routePills.Add(val);
				num += num2 + 8f;
			}
			_routeDescriptionLabel = PeakWindowStyle.CreateText((Transform)(object)_routeBox, "RouteDescription", string.Empty, 20f, PeakWindowStyle.TextMuted, (TextAlignmentOptions)513);
			NativeUiFactory.Place((RectTransform)((TMP_Text)_routeDescriptionLabel).transform, 24f, 94f, width, 26f);
			NativeUiFactory.Place((RectTransform)((TMP_Text)PeakWindowStyle.CreateText((Transform)(object)_routeBox, "RouteLimitHint", Loc.T("run.route.limitHint", RunConfigService.MiniRunBiomeCount), 18f, PeakWindowStyle.TextMuted, (TextAlignmentOptions)513)).transform, 24f, 118f, width, 24f);
		}

		private void BuildRaceBox(RectTransform body, float innerWidth)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Expected O, but got Unknown
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Expected O, but got Unknown
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Expected O, but got Unknown
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Expected O, but got Unknown
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Expected O, but got Unknown
			//IL_031b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Expected O, but got Unknown
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Expected O, but got Unknown
			//IL_03d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03de: Expected O, but got Unknown
			//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_041e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0438: Expected O, but got Unknown
			//IL_04cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d9: Expected O, but got Unknown
			//IL_0524: Unknown result type (might be due to invalid IL or missing references)
			//IL_052e: Expected O, but got Unknown
			//IL_0581: Unknown result type (might be due to invalid IL or missing references)
			//IL_058b: Expected O, but got Unknown
			//IL_05d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e0: Expected O, but got Unknown
			//IL_062b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0635: Expected O, but got Unknown
			//IL_0696: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a0: Expected O, but got Unknown
			//IL_071a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0738: Unknown result type (might be due to invalid IL or missing references)
			//IL_075a: Expected O, but got Unknown
			_raceBox = PeakWindowStyle.CreateBox((Transform)(object)body, "BoxRace", Loc.T("run.box.race"), 26f, 0f, innerWidth, 300f);
			float num = innerWidth - 48f;
			_playersPrevButton = PeakWindowStyle.CreatePill((Transform)(object)_raceBox, "BtnPlayersPrev", "-", 24f, 50f, 52f, 42f);
			((UnityEvent)_playersPrevButton.onClick).AddListener((UnityAction)delegate
			{
				_maxPlayers = StepPlayers(_maxPlayers, -1);
				PushRaceConfig();
				RefreshDisplay();
			});
			_playersLabel = PeakWindowStyle.CreateText((Transform)(object)_raceBox, "PlayersLabel", string.Empty, 20f, PeakWindowStyle.TextPrimary, (TextAlignmentOptions)514);
			NativeUiFactory.Place((RectTransform)((TMP_Text)_playersLabel).transform, 82f, 50f, 150f, 42f);
			_playersNextButton = PeakWindowStyle.CreatePill((Transform)(object)_raceBox, "BtnPlayersNext", "+", 238f, 50f, 52f, 42f);
			((UnityEvent)_playersNextButton.onClick).AddListener((UnityAction)delegate
			{
				_maxPlayers = StepPlayers(_maxPlayers, 1);
				PushRaceConfig();
				RefreshDisplay();
			});
			_autoStartButton = PeakWindowStyle.CreatePill((Transform)(object)_raceBox, "BtnAutoStart", Loc.T("run.btn.autoStart"), 314f, 50f, 180f, 42f, 18f);
			((UnityEvent)_autoStartButton.onClick).AddListener((UnityAction)delegate
			{
				_autoStart = !_autoStart;
				PushRaceConfig();
				RefreshDisplay();
			});
			_rivalsButton = PeakWindowStyle.CreatePill((Transform)(object)_raceBox, "BtnRivals", Loc.T("run.btn.rivals"), 504f, 50f, 240f, 42f, 16f);
			((UnityEvent)_rivalsButton.onClick).AddListener((UnityAction)delegate
			{
				_showRivals = !_showRivals;
				PushRaceConfig();
				RefreshDisplay();
			});
			_voiceButton = PeakWindowStyle.CreatePill((Transform)(object)_raceBox, "BtnVoice", Loc.T("run.btn.voice"), 754f, 50f, 140f, 42f, 16f);
			((UnityEvent)_voiceButton.onClick).AddListener((UnityAction)delegate
			{
				_voiceChat = !_voiceChat;
				PushRaceConfig();
				RefreshDisplay();
			});
			_spectatorsButton = PeakWindowStyle.CreatePill((Transform)(object)_raceBox, "BtnSpectators", Loc.T("run.btn.spectators"), 24f, 104f, 260f, 46f, 16f);
			((UnityEvent)_spectatorsButton.onClick).AddListener((UnityAction)delegate
			{
				_spectatorsAllowed = !_spectatorsAllowed;
				PushRaceConfig();
				RefreshDisplay();
			});
			_autoEndButton = PeakWindowStyle.CreatePill((Transform)(object)_raceBox, "BtnAutoEnd", string.Empty, 296f, 104f, 230f, 46f, 16f);
			((UnityEvent)_autoEndButton.onClick).AddListener((UnityAction)delegate
			{
				_autoEndMs = NextAutoEnd(_autoEndMs);
				PushRaceConfig();
				RefreshDisplay();
			});
			_rulesButton = PeakWindowStyle.CreatePill((Transform)(object)_raceBox, "BtnRules", Loc.T("run.btn.rules"), 538f, 104f, 200f, 46f, 16f);
			((UnityEvent)_rulesButton.onClick).AddListener(new UnityAction(OpenRulesWindow));
			_codeLabel = PeakWindowStyle.CreateText((Transform)(object)_raceBox, "CodeLabel", string.Empty, 30f, PeakWindowStyle.Heading, (TextAlignmentOptions)516, display: false, 8f);
			NativeUiFactory.Place((RectTransform)((TMP_Text)_codeLabel).transform, 24f + num - 200f, 50f, 200f, 42f);
			_visibilityButton = PeakWindowStyle.CreatePill((Transform)(object)_raceBox, "BtnVisibility", string.Empty, 24f + num - 200f, 50f, 200f, 42f, 16f);
			((UnityEvent)_visibilityButton.onClick).AddListener((UnityAction)delegate
			{
				_isPublic = !_isPublic;
				Plugin.RacePublic.Value = _isPublic;
				RefreshDisplay();
			});
			_joinHintLabel = PeakWindowStyle.CreateText((Transform)(object)_raceBox, "JoinHint", Loc.T("race.join.hint"), 19f, PeakWindowStyle.TextMuted, (TextAlignmentOptions)513);
			NativeUiFactory.Place((RectTransform)((TMP_Text)_joinHintLabel).transform, 24f, 50f, num, 42f);
			_codeInput = PeakWindowStyle.CreateInputField((Transform)(object)_raceBox, "CodeInput", string.Empty, 24f, 104f, 200f, 46f, 24f);
			_codeInput.characterLimit = 6;
			_codeInput.contentType = (ContentType)4;
			_joinButton = PeakWindowStyle.CreatePill((Transform)(object)_raceBox, "BtnJoin", Loc.T("run.btn.join"), 236f, 104f, 190f, 46f, 19f);
			((UnityEvent)_joinButton.onClick).AddListener(new UnityAction(JoinRace));
			_spectateButton = PeakWindowStyle.CreatePill((Transform)(object)_raceBox, "BtnSpectate", Loc.T("run.btn.spectate"), 438f, 104f, 190f, 46f, 19f);
			((UnityEvent)_spectateButton.onClick).AddListener(new UnityAction(SpectateRace));
			_createButton = PeakWindowStyle.CreatePill((Transform)(object)_raceBox, "BtnCreateRace", Loc.T("run.btn.create"), 24f + num - 300f, 104f, 300f, 46f, 19f);
			((UnityEvent)_createButton.onClick).AddListener(new UnityAction(CreateRace));
			_copyCodeButton = PeakWindowStyle.CreatePill((Transform)(object)_raceBox, "BtnCopyCode", Loc.T("run.btn.copyCode"), 24f, 104f, 190f, 46f, 16f);
			((UnityEvent)_copyCodeButton.onClick).AddListener(new UnityAction(CopyInviteCode));
			_hostStartButton = PeakWindowStyle.CreatePill((Transform)(object)_raceBox, "BtnHostStart", Loc.T("run.btn.startRace"), 224f, 104f, 230f, 46f, 18f);
			((UnityEvent)_hostStartButton.onClick).AddListener((UnityAction)delegate
			{
				RaceService.Instance?.StartRace(delegate(string err)
				{
					SetSummary(Loc.T("run.msg.startFailed", err));
				});
			});
			_leaveButton = PeakWindowStyle.CreatePill((Transform)(object)_raceBox, "BtnLeaveRace", Loc.T("run.btn.leave"), 914f, 104f, 190f, 46f, 18f);
			PeakWindowStyle.SetPillSelected(_leaveButton, selected: false);
			((UnityEvent)_leaveButton.onClick).AddListener((UnityAction)delegate
			{
				RaceService.Instance?.LeaveRace();
				SetSummary(Loc.T("run.msg.left"));
				LeaveMountain();
			});
			float height = 128f;
			float contentHeight = Mathf.Ceil(8f) * 22f;
			_participantArea = PeakWindowStyle.CreateScrollArea((Transform)(object)_raceBox, "Participants", 24f, 160f, num, height, contentHeight);
			float num2 = _participantArea.ContentWidth / 4f;
			for (int num3 = 0; num3 < 32; num3++)
			{
				TextMeshProUGUI val = PeakWindowStyle.CreateText((Transform)(object)_participantArea.Content, $"Participant{num3}", string.Empty, 18f, PeakWindowStyle.TextPrimary, (TextAlignmentOptions)513);
				NativeUiFactory.Place((RectTransform)((TMP_Text)val).transform, (float)(num3 % 4) * num2, (float)(num3 / 4) * 22f, num2, 22f);
				((TMP_Text)val).textWrappingMode = (TextWrappingModes)0;
				((Component)val).gameObject.SetActive(false);
				_participantRows.Add(val);
			}
		}

		private static int StepPlayers(int current, int direction)
		{
			int num = 0;
			for (int i = 1; i < PlayerSteps.Length; i++)
			{
				if (Mathf.Abs(PlayerSteps[i] - current) < Mathf.Abs(PlayerSteps[num] - current))
				{
					num = i;
				}
			}
			if (PlayerSteps[num] == current)
			{
				num = Mathf.Clamp(num + direction, 0, PlayerSteps.Length - 1);
			}
			else if (direction > 0 && PlayerSteps[num] < current)
			{
				num = Mathf.Min(num + 1, PlayerSteps.Length - 1);
			}
			else if (direction < 0 && PlayerSteps[num] > current)
			{
				num = Mathf.Max(num - 1, 0);
			}
			return PlayerSteps[num];
		}

		private static int NextAutoEnd(int current)
		{
			int num = Array.IndexOf(AutoEndStepsMs, current);
			if (num < 0)
			{
				for (int i = 0; i < AutoEndStepsMs.Length; i++)
				{
					if (AutoEndStepsMs[i] > current)
					{
						return AutoEndStepsMs[i];
					}
				}
				return 0;
			}
			return AutoEndStepsMs[(num + 1) % AutoEndStepsMs.Length];
		}

		private void OpenRulesWindow()
		{
			RaceService instance = RaceService.Instance;
			RaceInfo raceInfo = instance?.CurrentRace;
			bool editable = ((raceInfo == null) ? (_view == RaceView.HostSetup) : (instance.IsHost && raceInfo.Status == "lobby"));
			RaceRulesModal.OpenWindow(_rules, editable, () => _ascent, delegate
			{
				PushRaceConfig();
				RefreshDisplay();
			});
		}

		private void StepLevel(int direction)
		{
			int slotCount = MapCatalog.SlotCount;
			if (slotCount > 0)
			{
				_levelSlot = ((_levelSlot + direction) % slotCount + slotCount) % slotCount;
				PushRaceConfig();
				RefreshDisplay();
			}
		}

		private void BuildBoard(RectTransform body, float innerWidth)
		{
			_boardPanel = RaceBoardPanel.Create((Transform)(object)body, "BoxBoard", 26f, 0f, innerWidth);
			_boardPanel.CopyCode = CopyInviteCode;
			_boardPanel.HostStart = delegate
			{
				RaceService.Instance?.StartRace(delegate(string err)
				{
					SetSummary(Loc.T("run.msg.startFailed", err));
				});
			};
			_boardPanel.EditSettings = delegate
			{
				_view = RaceView.HostSetup;
				RefreshDisplay();
			};
			_boardPanel.Leave = delegate
			{
				SpectatorService instance = SpectatorService.Instance;
				RaceService instance2 = RaceService.Instance;
				if (instance2 != null && instance2.IsSpectator)
				{
					CloseModal();
					RaceService.Instance.LeaveRace();
					instance?.LeaveToMainMenu("Zuschauer verlaesst das Rennen");
				}
				else if ((Object)(object)instance != (Object)null && instance.WorldHeld)
				{
					CloseModal();
					instance.LeaveToMainMenu("Knopf im Board");
				}
				else
				{
					RaceService.Instance?.LeaveRace();
					SetSummary(Loc.T("run.msg.left"));
					LeaveMountain();
				}
			};
			_boardPanel.FollowParticipant = delegate(string steamId)
			{
				SpectatorService.Instance?.JumpTo(steamId);
				CloseModal();
			};
			_boardPanel.SetVisibility = delegate(bool isPublic)
			{
				Plugin.RacePublic.Value = isPublic;
				RaceService.Instance?.SetPublic(isPublic, delegate(string err)
				{
					SetSummary(Loc.T("run.msg.configFailed", err));
				});
			};
			_boardPanel.ManagePlayers = RacePlayersModal.OpenWindow;
			_boardPanel.Spectate = delegate
			{
				CloseModal();
				SpectatorService.Instance?.Begin();
			};
			_boardPanel.Forfeit = delegate
			{
				RaceService.Instance?.Forfeit();
				SetSummary(Loc.T("board.msg.forfeited"));
			};
		}

		private void LeaveMountain()
		{
			//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)
			Scene activeScene = SceneManager.GetActiveScene();
			if (!((Scene)(ref activeScene)).name.StartsWith("Level_"))
			{
				return;
			}
			CloseModal();
			try
			{
				RankedLog.Info("[Custom] Rennen verlassen - zurueck ins Hauptmenue.");
				Player.LeaveCurrentGame();
			}
			catch (Exception ex)
			{
				RankedLog.Error("[Custom] Rueckweg ins Hauptmenue fehlgeschlagen: " + ex.Message);
			}
		}

		private void BuildFooter(RectTransform body, float innerWidth)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Expected O, but got Unknown
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Expected O, but got Unknown
			_summaryLabel = PeakWindowStyle.CreateText((Transform)(object)body, "Summary", string.Empty, 21f, PeakWindowStyle.TextPrimary, (TextAlignmentOptions)513);
			_backButton = PeakWindowStyle.CreatePill((Transform)(object)body, "BtnBack", Loc.T("run.btn.back"), 26f, 0f, 200f, 52f);
			PeakWindowStyle.SetPillSelected(_backButton, selected: false);
			((UnityEvent)_backButton.onClick).AddListener((UnityAction)delegate
			{
				_view = ((RaceService.Instance?.CurrentRace != null) ? RaceView.Board : RaceView.RoleSelect);
				RefreshDisplay();
			});
			_cancelButton = PeakWindowStyle.CreatePill((Transform)(object)body, "BtnCancel", Loc.T("run.btn.cancel"), 26f, 0f, 220f, 52f);
			PeakWindowStyle.SetPillSelected(_cancelButton, selected: false);
			((UnityEvent)_cancelButton.onClick).AddListener(new UnityAction(CloseModal));
			_startButton = PeakWindowStyle.CreatePill((Transform)(object)body, "BtnStart", Loc.T("run.btn.start"), 26f, 0f, 270f, 52f, 22f);
			((UnityEvent)_startButton.onClick).AddListener(new UnityAction(StartSoloRun));
		}

		private void SetRandomMode(bool randomMode)
		{
			_randomMode = randomMode;
			RaceInfo raceInfo = RaceService.Instance?.CurrentRace;
			if (randomMode && raceInfo != null)
			{
				RaceService instance = RaceService.Instance;
				if (instance != null && instance.IsHost && raceInfo.Status == "lobby")
				{
					RollRandomIfNeeded();
				}
			}
			PushRaceConfig();
			RefreshDisplay();
		}

		private void OnSeedTyped(string value)
		{
			if (int.TryParse(value, out var result))
			{
				_seed = result;
				RefreshSummary();
			}
		}

		private void SetSeed(int seed)
		{
			_seed = seed;
			if ((Object)(object)_seedInput != (Object)null)
			{
				_seedInput.SetTextWithoutNotify(_seed.ToString());
			}
			RefreshSummary();
		}

		private void UseDailySeed()
		{
			if ((Object)(object)DailySeedService.Instance != (Object)null && DailySeedService.Instance.HasValidServerSeed)
			{
				SetSeed(DailySeedService.Instance.ServerSeed);
				PushRaceConfig();
			}
			else
			{
				SetSummary(Loc.T("run.msg.noDailySeed"));
			}
		}

		private void RollSeed()
		{
			SetSeed(Random.Range(1000000