Decompiled source of SpectrumB Milsim System v2.20.74

Mods/SpectrumB_Milsim_System.dll

Decompiled 4 hours ago
using System;
using System.Buffers.Binary;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Numerics;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using AudioImportLib;
using BoneLib;
using BoneLib.BoneMenu;
using BoneLib.BoneMenu.UI;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Bonelab;
using Il2CppSLZ.Data;
using Il2CppSLZ.Interaction;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.AI;
using Il2CppSLZ.Marrow.Audio;
using Il2CppSLZ.Marrow.Combat;
using Il2CppSLZ.Marrow.Data;
using Il2CppSLZ.Marrow.Interaction;
using Il2CppSLZ.Marrow.Pool;
using Il2CppSLZ.Marrow.Utilities;
using Il2CppSLZ.Marrow.Warehouse;
using Il2CppSLZ.VFX;
using Il2CppSLZ.VRMK;
using Il2CppSLZ.Vehicle;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using Il2CppTMPro;
using LabFusion.Audio;
using LabFusion.Data;
using LabFusion.Entities;
using LabFusion.Extensions;
using LabFusion.Marrow;
using LabFusion.Marrow.Extenders;
using LabFusion.Marrow.Messages;
using LabFusion.Marrow.Serialization;
using LabFusion.MonoBehaviours;
using LabFusion.Network;
using LabFusion.Network.Serialization;
using LabFusion.Player;
using LabFusion.RPC;
using LabFusion.Representation;
using LabFusion.SDK.Metadata;
using LabFusion.SDK.Modules;
using LabFusion.Scene;
using LabFusion.Senders;
using LabFusion.Utilities;
using LabFusion.Voice;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using Microsoft.Win32.SafeHandles;
using SpectrumB.Content;
using SpectrumB.Handheld;
using SpectrumB.Milsim;
using SpectrumB.UI.Core;
using SpectrumB.UI.Core.Statistics;
using SpectrumB_Modding_Hub;
using SpectrumB_Modding_Hub.Modules;
using SpectrumB_Modding_Hub.Modules.Admin;
using SpectrumB_Modding_Hub.Modules.Ballistics;
using SpectrumB_Modding_Hub.Modules.BulletFX;
using SpectrumB_Modding_Hub.Modules.CloudSync;
using SpectrumB_Modding_Hub.Modules.Combat;
using SpectrumB_Modding_Hub.Modules.Corpses;
using SpectrumB_Modding_Hub.Modules.Developer;
using SpectrumB_Modding_Hub.Modules.Diagnostics;
using SpectrumB_Modding_Hub.Modules.FusionSync;
using SpectrumB_Modding_Hub.Modules.Localization;
using SpectrumB_Modding_Hub.Modules.Medical;
using SpectrumB_Modding_Hub.Modules.Milsim;
using SpectrumB_Modding_Hub.Modules.Milsim.Handheld;
using SpectrumB_Modding_Hub.Modules.Platforms;
using SpectrumB_Modding_Hub.Modules.PlayerLifecycle;
using SpectrumB_Modding_Hub.Modules.Rendering;
using SpectrumB_Modding_Hub.Modules.Slings;
using SpectrumB_Modding_Hub.Modules.SoundFramework;
using SpectrumB_Modding_Hub.Modules.SpectrumBUI;
using SpectrumB_Modding_Hub.Modules.VisualFX;
using Steamworks;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Audio;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityEngine.XR;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "SpectrumB Milsim System", "2.20.74", "SpectrumB", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonOptionalDependencies(new string[] { "AudioImportLib" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("SpectrumB_Milsim_System")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("SpectrumB release notes v1:\nGlobal statistics reset support and old-upload protection.\r\nClears old local match history and replays after reset.\r\nPCVR teams, loadouts, squads, radios and medical play.\r\nHost-synced walls and late-join recovery.\r\nSafer updates, Pack recovery and saved-game refresh.\r\nPairing, controller and quick-menu fixes.\r\nMatching SpectrumB builds required for multiplayer.\r\n")]
[assembly: AssemblyFileVersion("2.20.74.0")]
[assembly: AssemblyInformationalVersion("2.20.74+53c73f65b7b62586c96b19b170c1b025ee8ee329")]
[assembly: AssemblyProduct("SpectrumB_Milsim_System")]
[assembly: AssemblyTitle("SpectrumB_Milsim_System")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.20.74.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace SpectrumB.UI.Core
{
	public enum UiActionId
	{
		None,
		Navigate,
		Back,
		GoHome,
		SetWorkspace,
		OpenLoadoutSelector,
		OpenSetupTemplates,
		OpenWorkflowEditor,
		OpenMedical,
		OpenLanguage,
		OpenMap,
		SelectTeam,
		LeaveTeam,
		SelectLoadout,
		ToggleReady,
		Deploy,
		ReturnToSpawn,
		RequestVehicle,
		OpenMedicalQuickMenu,
		ApproveJoinRequest,
		DenyJoinRequest,
		ApproveVehicleRequest,
		DenyVehicleRequest,
		ToggleTeamLock,
		SetSquadQueueFilter,
		SelectRosterPlayer,
		StartMatch,
		StopMatch,
		CleanupSpawnedItems,
		ClearCorpses,
		ClearWrecks,
		AutoAssignTeams,
		ToggleModEnabled,
		SetLanguage,
		AcceptCloudInvite,
		DeclineCloudInvite,
		SelectBodyRegion,
		CyclePatient,
		SetPageIndex,
		PreviewInject,
		SelectSpawn,
		SelectAutomaticSpawn,
		PlaceRally,
		RemoveRally,
		ChangeInitialVehicleCount,
		CycleInitialVehicleSpawn,
		SpawnFactionFlag,
		DeleteFactionFlag,
		OpenFeedbackDetails,
		TogglePlayersFrozen
	}
	public sealed class UiAction
	{
		public UiActionId Id;

		public UiPageId Page;

		public UiTeam Team;

		public int Number;

		public string Text = "";

		public string PlayerId = "";

		public bool Flag;

		public string ConfirmKey = "";

		public static readonly UiAction None = new UiAction();

		public bool IsNone => Id == UiActionId.None;

		public static UiAction Navigate(UiPageId page)
		{
			return new UiAction
			{
				Id = UiActionId.Navigate,
				Page = page
			};
		}

		public static UiAction Of(UiActionId id)
		{
			return new UiAction
			{
				Id = id
			};
		}

		public UiAction With(UiPageId page)
		{
			Page = page;
			return this;
		}

		public UiAction With(UiTeam team)
		{
			Team = team;
			return this;
		}

		public UiAction WithNumber(int number)
		{
			Number = number;
			return this;
		}

		public UiAction WithText(string text)
		{
			Text = text ?? "";
			return this;
		}

		public UiAction WithFlag(bool flag)
		{
			Flag = flag;
			return this;
		}

		public UiAction Confirm(string key)
		{
			ConfirmKey = key ?? "";
			return this;
		}

		public override string ToString()
		{
			return string.Format(CultureInfo.InvariantCulture, "{0}(page={1}, team={2}, n={3}, text={4})", Id, Page, Team, Number, Text);
		}
	}
	public sealed class UiActionResult
	{
		public bool Handled;

		public bool Success;

		public string Message = "";

		public bool Navigated;

		public UiPageId NavigatedTo;

		public bool AwaitingConfirmation;

		public static UiActionResult Ok(string message = "")
		{
			return new UiActionResult
			{
				Handled = true,
				Success = true,
				Message = (message ?? "")
			};
		}

		public static UiActionResult Failed(string message)
		{
			return new UiActionResult
			{
				Handled = true,
				Success = false,
				Message = (message ?? "")
			};
		}

		public static UiActionResult Unhandled(string message = "")
		{
			return new UiActionResult
			{
				Handled = false,
				Success = false,
				Message = (message ?? "")
			};
		}

		public static UiActionResult Route(UiPageId page, string message = "")
		{
			return new UiActionResult
			{
				Handled = true,
				Success = true,
				Navigated = true,
				NavigatedTo = page,
				Message = (message ?? "")
			};
		}

		public static UiActionResult Arm(string message)
		{
			return new UiActionResult
			{
				Handled = true,
				Success = true,
				AwaitingConfirmation = true,
				Message = (message ?? "")
			};
		}
	}
	public static class UiConfirmation
	{
		public const float WindowSeconds = 4f;

		public const string Instruction = "Press this button again.";

		public static string Label(string action, float remainingSeconds, bool compact = false)
		{
			int num = Math.Max(1, Math.Min(4, (int)Math.Ceiling(remainingSeconds)));
			string text = Regex.Replace(action ?? "", "<[^>]+>", "").Replace("\n", " ").Trim();
			return "CONFIRM" + ((compact || text.Length == 0) ? "" : (" " + text.ToUpperInvariant())) + " · " + num.ToString(CultureInfo.InvariantCulture) + "s";
		}

		public static string ButtonText(string action, float remainingSeconds, bool compact = false)
		{
			return Label(action, remainingSeconds, compact) + (compact ? "" : "\n<size=65%>Press this button again.</size>");
		}
	}
	public static class UiDerive
	{
		public static bool DescribeCondition(UiMedicalSnapshot medical, out string line, out UiColor accent)
		{
			if (medical == null || !medical.Enabled)
			{
				line = "MEDICAL SYSTEM IS OFF";
				accent = UiTheme.TextDim;
				return false;
			}
			switch (medical.State)
			{
			case UiMedicalState.Dead:
				line = "<b>YOU ARE DEAD</b> — waiting to respawn";
				accent = UiTheme.HealthCrit;
				return true;
			case UiMedicalState.Respawning:
				line = "<b>RESPAWNING</b>";
				accent = UiTheme.Orange;
				return true;
			case UiMedicalState.Incapacitated:
				line = "<b>YOU ARE DOWN</b> — someone has to revive you";
				accent = UiTheme.HealthCrit;
				return true;
			case UiMedicalState.Critical:
				line = (medical.Bleeding ? "<b>CRITICAL</b> — bleeding out, treat now" : "<b>CRITICAL</b> — treat now");
				accent = UiTheme.HealthCrit;
				return true;
			case UiMedicalState.Injured:
				line = (medical.Bleeding ? "<b>WOUNDED</b> — you are bleeding" : "<b>WOUNDED</b> — trauma is slowing you down");
				accent = UiTheme.HealthWarn;
				return true;
			default:
				if (medical.Bleeding)
				{
					line = "<b>BLEEDING</b> — bandage it before it gets worse";
					accent = UiTheme.HealthWarn;
					return true;
				}
				line = "<b>UNINJURED</b> — good to go";
				accent = UiTheme.HealthGood;
				return false;
			}
		}

		public static bool MemberHasProblem(UiSnapshot state, UiPlayerSnapshot entry)
		{
			if (entry == null)
			{
				return true;
			}
			if (entry.Team == UiTeam.Unassigned || string.IsNullOrWhiteSpace(entry.LoadoutName))
			{
				return true;
			}
			UiMedicalState medicalState = entry.MedicalState;
			if ((entry.IsReady || state.Session.SessionActive) && medicalState != UiMedicalState.Incapacitated && medicalState != UiMedicalState.Dead && medicalState != UiMedicalState.Respawning)
			{
				return medicalState == UiMedicalState.Critical;
			}
			return true;
		}

		public static string MemberState(UiSnapshot state, UiPlayerSnapshot entry)
		{
			if (entry.Team == UiTeam.Unassigned)
			{
				return "NO TEAM";
			}
			if (string.IsNullOrWhiteSpace(entry.LoadoutName))
			{
				return "NO LOADOUT";
			}
			if (entry.MedicalState != UiMedicalState.Alive)
			{
				return entry.MedicalState.ToString().ToUpperInvariant();
			}
			if (!state.Session.SessionActive)
			{
				if (!entry.IsReady)
				{
					return "NOT READY";
				}
				return "READY";
			}
			return "ACTIVE";
		}

		public static List<UiPlayerSnapshot> LocalSquad(UiSnapshot state)
		{
			UiTeam team = (state.Local.HasPendingDeployment ? state.Local.CurrentTeam : state.Local.Team);
			return (from entry in state.Roster
				where entry.Team == team
				orderby (!MemberHasProblem(state, entry)) ? 1 : 0
				select entry).ThenBy<UiPlayerSnapshot, string>((UiPlayerSnapshot entry) => entry.Name, StringComparer.OrdinalIgnoreCase).ToList();
		}

		public static string LocalRoleSummary(UiSnapshot state)
		{
			string text = (state.Session.IsSquadLeader ? "SL" : "NONE");
			if (!state.Session.CanManage)
			{
				return "COMMAND: " + text;
			}
			return "COMMAND: " + text + "  •  ADMIN: HOST";
		}

		public static UiPageId PrimaryNextPage(UiSnapshot state)
		{
			return UiPageId.PlayerField;
		}

		public static string PrimaryNextTitle(UiPageId page)
		{
			return page switch
			{
				UiPageId.PlayerReadyLobby => "Complete player setup", 
				UiPageId.PlayerReadyLive => "Complete deployment", 
				UiPageId.PlayerField => "GAME", 
				UiPageId.SquadCommand => "Resolve command decisions", 
				UiPageId.HostSetupOverview => "Continue match setup", 
				_ => "Continue", 
			};
		}

		public static string PrimaryNextDetail(UiPageId page)
		{
			return page switch
			{
				UiPageId.PlayerReadyLobby => "Choose team, choose loadout, ready up", 
				UiPageId.PlayerReadyLive => "Team, loadout and deployment", 
				UiPageId.PlayerField => "Team, loadout and deployment", 
				UiPageId.SquadCommand => "Join and vehicle requests are waiting", 
				UiPageId.HostSetupOverview => "Fix setup blockers before preflight", 
				_ => "Open the active workspace", 
			};
		}

		public static string CompactMatchState(UiSnapshot state)
		{
			List<UiTeamSnapshot> activeTeams = state.ActiveTeams;
			if (activeTeams.Count == 0)
			{
				return "MATCH LIVE";
			}
			return (state.Match.RespawnTokensEnabled ? string.Join("  /  ", (from team in activeTeams.Take(2)
				select team.Tag + " " + team.Tokens).ToArray()) : "UNLIMITED LIVES") + "  •  " + state.Match.Objectives.Count + " OBJECTIVES";
		}

		public static UiVehicleRequestSnapshot LocalPendingVehicleRequest(UiSnapshot state)
		{
			return state.VehicleRequests.FirstOrDefault((UiVehicleRequestSnapshot request) => (state.Local.PlatformId != 0L && request.RequesterPlatformId == state.Local.PlatformId) || string.Equals(request.RequesterName, state.Session.LocalPlayerName, StringComparison.OrdinalIgnoreCase));
		}

		public static int IncompleteRosterCount(UiSnapshot state)
		{
			return state.Roster.Count((UiPlayerSnapshot entry) => entry.Team == UiTeam.Unassigned || string.IsNullOrWhiteSpace(entry.LoadoutName));
		}

		public static UiColor HealthColor(float integrity01)
		{
			if (integrity01 >= 0.75f)
			{
				return UiTheme.HealthGood;
			}
			if (integrity01 >= 0.4f)
			{
				return UiTheme.HealthWarn;
			}
			return UiTheme.HealthCrit;
		}
	}
	public static class UiLiveLayout
	{
		public static bool CanRefresh(IReadOnlyList<UiElement> before, IReadOnlyList<UiElement> after)
		{
			if (before.Count != after.Count)
			{
				return false;
			}
			for (int i = 0; i < before.Count; i++)
			{
				UiElement uiElement = before[i];
				UiElement uiElement2 = after[i];
				if (uiElement.Kind != uiElement2.Kind || uiElement.Id != uiElement2.Id || uiElement.Visible != uiElement2.Visible || !uiElement.Position.Equals(uiElement2.Position) || !uiElement.Size.Equals(uiElement2.Size) || !CanRefresh(uiElement.Children, uiElement2.Children))
				{
					return false;
				}
				if (uiElement is UiText uiText && uiElement2 is UiText uiText2)
				{
					if (uiText.FontSize != uiText2.FontSize || uiText.Alignment != uiText2.Alignment || uiText.RichText != uiText2.RichText)
					{
						return false;
					}
					continue;
				}
				if (uiElement is UiButton uiButton && uiElement2 is UiButton uiButton2)
				{
					if (uiButton.FontSize != uiButton2.FontSize || uiButton.Alignment != uiButton2.Alignment || uiButton.Transparent != uiButton2.Transparent || uiButton.Outlined != uiButton2.Outlined)
					{
						return false;
					}
					continue;
				}
				if (uiElement is UiDivider uiDivider && uiElement2 is UiDivider uiDivider2 && (!uiDivider.Color.Equals(uiDivider2.Color) || uiDivider.Alpha != uiDivider2.Alpha))
				{
					return false;
				}
				if (uiElement is UiRectangle uiRectangle && uiElement2 is UiRectangle uiRectangle2 && (!uiRectangle.Color.Equals(uiRectangle2.Color) || uiRectangle.Alpha != uiRectangle2.Alpha || uiRectangle.Rotation != uiRectangle2.Rotation))
				{
					return false;
				}
				if (uiElement is UiPanel uiPanel && uiElement2 is UiPanel uiPanel2 && (!uiPanel.Color.Equals(uiPanel2.Color) || uiPanel.Alpha != uiPanel2.Alpha))
				{
					return false;
				}
				if (uiElement is UiFlagChip uiFlagChip && uiElement2 is UiFlagChip uiFlagChip2 && (uiFlagChip.FlagCode != uiFlagChip2.FlagCode || uiFlagChip.Tag != uiFlagChip2.Tag || !uiFlagChip.Color.Equals(uiFlagChip2.Color)))
				{
					return false;
				}
				if (uiElement is UiToggle uiToggle && uiElement2 is UiToggle uiToggle2 && (uiToggle.On != uiToggle2.On || uiToggle.Text != uiToggle2.Text))
				{
					return false;
				}
				if (uiElement is UiProgressBar uiProgressBar && uiElement2 is UiProgressBar uiProgressBar2 && (uiProgressBar.Value01 != uiProgressBar2.Value01 || !uiProgressBar.FillColor.Equals(uiProgressBar2.FillColor) || !uiProgressBar.TrackColor.Equals(uiProgressBar2.TrackColor) || uiProgressBar.TrackAlpha != uiProgressBar2.TrackAlpha))
				{
					return false;
				}
				if (uiElement is UiIconElement uiIconElement && uiElement2 is UiIconElement uiIconElement2 && (uiIconElement.Icon != uiIconElement2.Icon || !uiIconElement.Color.Equals(uiIconElement2.Color)))
				{
					return false;
				}
			}
			return true;
		}
	}
	public static class UiOverlays
	{
		private static UiVector2 V(float x, float y)
		{
			return new UiVector2(x, y);
		}

		public static void Compose(UiScreen screen, UiSnapshot state)
		{
			UiOverlaySnapshot overlays = state.Overlays;
			if (overlays.CaptureVisible)
			{
				ComposeCapture(screen, overlays);
			}
			if (state.Medical.DownTimerActive)
			{
				ComposeDownTimer(screen, state);
			}
			if (overlays.RuntimeNoticeVisible && !string.IsNullOrWhiteSpace(overlays.RuntimeNotice))
			{
				ComposeRuntimeNotice(screen, overlays);
			}
			if (overlays.GameOverVisible)
			{
				ComposeGameOver(screen, state, overlays);
			}
			if (overlays.VrCursorVisible)
			{
				ComposeCursor(screen, overlays);
			}
		}

		private static void ComposeCapture(UiScreen screen, UiOverlaySnapshot overlay)
		{
			int num = ((overlay.CapturePercent >= 0) ? ((overlay.CapturePercent > 100) ? 100 : overlay.CapturePercent) : 0);
			screen.Overlays.Add(new UiPanel
			{
				Id = "CaptureBackdrop",
				Position = V(0f, 250f),
				Size = V(420f, 78f),
				Color = UiTheme.PanelDark,
				Alpha = 0.86f
			});
			screen.Overlays.Add(new UiText
			{
				Id = "CaptureText",
				Position = V(0f, 268f),
				Size = V(392f, 30f),
				FontSize = 16f,
				Alignment = UiAlignment.Center,
				Text = "<b>" + overlay.CaptureVerb.ToUpperInvariant() + "  •  " + overlay.CaptureLabel.ToUpperInvariant() + "</b>",
				Color = UiTheme.Orange
			});
			screen.Overlays.Add(new UiRectangle
			{
				Id = "CaptureTrack",
				Position = V(0f, 236f),
				Size = V(360f, 10f),
				Color = new UiColor(0f, 0f, 0f),
				Alpha = 0.5f,
				Sharp = true
			});
			screen.Overlays.Add(new UiProgressBar
			{
				Id = "CaptureProgress",
				Position = V(0f, 236f),
				Size = V(360f, 10f),
				Value01 = (float)num / 100f,
				FillColor = ((num >= 100) ? UiTheme.HealthGood : UiTheme.Orange)
			});
			screen.Overlays.Add(new UiText
			{
				Id = "CapturePercent",
				Position = V(0f, 218f),
				Size = V(392f, 22f),
				FontSize = 11f,
				Alignment = UiAlignment.Center,
				Text = num.ToString(CultureInfo.InvariantCulture) + "%",
				Color = UiTheme.TextDim
			});
		}

		private static void ComposeDownTimer(UiScreen screen, UiSnapshot state)
		{
			UiMedicalSnapshot medical = state.Medical;
			float num = ((medical.DownSecondsRemaining < 0f) ? 0f : medical.DownSecondsRemaining);
			UiColor color = ((num <= 5f) ? UiTheme.HealthCrit : ((num <= 20f) ? UiTheme.HealthWarn : UiTheme.Orange));
			screen.Overlays.Add(new UiPanel
			{
				Id = "DownBackdrop",
				Position = V(0f, 0f),
				Size = V(620f, 780f),
				Color = UiTheme.PanelDark,
				Alpha = 0.55f
			});
			screen.Overlays.Add(new UiRectangle
			{
				Id = "DownAccent",
				Position = V(0f, 60f),
				Size = V(460f, 6f),
				Color = color,
				Alpha = 0.95f,
				Sharp = true
			});
			screen.Overlays.Add(new UiText
			{
				Id = "DownState",
				Position = V(0f, 130f),
				Size = V(520f, 44f),
				FontSize = 26f,
				Alignment = UiAlignment.Center,
				Text = "<b>" + medical.State.ToString().ToUpperInvariant() + "</b>",
				Color = color
			});
			screen.Overlays.Add(new UiText
			{
				Id = "DownTimer",
				Position = V(0f, 6f),
				Size = V(520f, 76f),
				FontSize = 54f,
				Alignment = UiAlignment.Center,
				Text = FormatCountdown(num),
				Color = UiTheme.TextWhite
			});
			screen.Overlays.Add(new UiText
			{
				Id = "DownPrompt",
				Position = V(0f, -64f),
				Size = V(520f, 32f),
				FontSize = 15f,
				Alignment = UiAlignment.Center,
				Text = medical.DownPrompt,
				Color = UiTheme.TextDim
			});
			if (!string.IsNullOrWhiteSpace(medical.DownDetail))
			{
				screen.Overlays.Add(new UiText
				{
					Id = "DownDetail",
					Position = V(0f, -102f),
					Size = V(520f, 30f),
					FontSize = 12f,
					Alignment = UiAlignment.Center,
					Text = medical.DownDetail,
					Color = UiTheme.TextDim
				});
			}
		}

		private static void ComposeRuntimeNotice(UiScreen screen, UiOverlaySnapshot overlay)
		{
			screen.Overlays.Add(new UiPanel
			{
				Id = "NoticeBackdrop",
				Position = V(0f, -250f),
				Size = V(540f, 64f),
				Color = UiTheme.PanelDark,
				Alpha = 0.9f
			});
			screen.Overlays.Add(new UiRectangle
			{
				Id = "NoticeRail",
				Position = V(-266f, -250f),
				Size = V(4f, 48f),
				Color = UiTheme.Orange,
				Alpha = 0.96f
			});
			screen.Overlays.Add(new UiText
			{
				Id = "NoticeText",
				Position = V(8f, -250f),
				Size = V(500f, 52f),
				FontSize = 13f,
				Alignment = UiAlignment.Left,
				Text = overlay.RuntimeNotice,
				Color = UiTheme.TextWhite
			});
		}

		private static void ComposeGameOver(UiScreen screen, UiSnapshot state, UiOverlaySnapshot overlay)
		{
			UiTeamSnapshot uiTeamSnapshot = state.Team(overlay.GameOverWinner);
			UiColor color = uiTeamSnapshot?.Color ?? UiTheme.Orange;
			string text = ((!string.IsNullOrWhiteSpace(overlay.GameOverHeadline)) ? overlay.GameOverHeadline : ((uiTeamSnapshot != null) ? (uiTeamSnapshot.DisplayName.ToUpperInvariant() + " WINS") : "MATCH OVER"));
			screen.Overlays.Add(new UiPanel
			{
				Id = "GameOverBackdrop",
				Position = V(0f, 0f),
				Size = V(620f, 780f),
				Color = UiTheme.PanelDark,
				Alpha = 0.88f
			});
			screen.Overlays.Add(new UiFlagChip
			{
				Id = "GameOverFlag",
				Position = V(0f, 120f),
				Size = V(180f, 120f),
				FlagCode = ((uiTeamSnapshot != null) ? uiTeamSnapshot.FlagCode : ""),
				Tag = ((uiTeamSnapshot != null) ? uiTeamSnapshot.Tag : ""),
				Color = color
			});
			screen.Overlays.Add(new UiText
			{
				Id = "GameOverText",
				Position = V(0f, 10f),
				Size = V(540f, 60f),
				FontSize = 32f,
				Alignment = UiAlignment.Center,
				Text = "<b>" + text + "</b>",
				Color = color
			});
			if (!string.IsNullOrWhiteSpace(overlay.GameOverDetail))
			{
				screen.Overlays.Add(new UiText
				{
					Id = "GameOverDetail",
					Position = V(0f, -46f),
					Size = V(540f, 40f),
					FontSize = 14f,
					Alignment = UiAlignment.Center,
					Text = overlay.GameOverDetail,
					Color = UiTheme.TextDim
				});
			}
		}

		private static void ComposeCursor(UiScreen screen, UiOverlaySnapshot overlay)
		{
			screen.Overlays.Add(new UiRectangle
			{
				Id = "VrCursorRing",
				Position = overlay.VrCursorPosition,
				Size = V(26f, 26f),
				Color = UiTheme.Orange,
				Alpha = 0.35f
			});
			screen.Overlays.Add(new UiRectangle
			{
				Id = "VrCursorDot",
				Position = overlay.VrCursorPosition,
				Size = V(8f, 8f),
				Color = UiTheme.Orange,
				Alpha = 1f
			});
		}

		public static string FormatCountdown(float seconds)
		{
			if (seconds < 0f)
			{
				seconds = 0f;
			}
			int num = (int)seconds;
			int num2 = num / 60;
			int num3 = num % 60;
			if (num2 <= 0)
			{
				return num3.ToString(CultureInfo.InvariantCulture);
			}
			return num2.ToString(CultureInfo.InvariantCulture) + ":" + num3.ToString("00", CultureInfo.InvariantCulture);
		}
	}
	public sealed class UiPageBuilder
	{
		private readonly UiScreen _screen;

		private readonly UiSnapshot _state;

		private bool _chrome;

		public UiScreen Screen => _screen;

		public UiSnapshot State => _state;

		public UiPageBuilder(UiPageId page, UiSnapshot state)
		{
			_state = state;
			_screen = new UiScreen
			{
				Page = page,
				Workspace = state.View.ActiveWorkspace,
				Feedback = (state.Feedback ?? "")
			};
		}

		public UiScreen Build()
		{
			ApplyConfirmation(_screen.Elements);
			ApplyConfirmation(_screen.Chrome);
			return _screen;
		}

		private void ApplyConfirmation(List<UiElement> elements)
		{
			foreach (UiElement element in elements)
			{
				ApplyConfirmation(element.Children);
				if (element is UiButton { Enabled: not false } uiButton && !string.IsNullOrEmpty(uiButton.Action.ConfirmKey) && !(uiButton.Action.ConfirmKey != _state.View.ArmedConfirmKey))
				{
					string text = uiButton.Text;
					bool flag = uiButton.Size.X < 120f;
					uiButton.Text = UiConfirmation.ButtonText(text, _state.View.ConfirmationRemainingSeconds, flag);
					uiButton.FontSize = (flag ? 13f : ((uiButton.Size.X < 260f) ? 15f : 19f));
					uiButton.Tint = UiTheme.HealthWarn;
					uiButton.TintAlpha = 1f;
					uiButton.Transparent = false;
					uiButton.TextColor = UiTheme.Coffee;
					if (flag)
					{
						float x = ((uiButton.Position.X > 0f) ? (-190f) : 190f);
						uiButton.Add(new UiPanel
						{
							Id = uiButton.Id + "_ConfirmHint",
							Position = V(x, 0f),
							Size = V(260f, 48f),
							Color = UiTheme.Coffee,
							Alpha = 1f
						});
						uiButton.Add(new UiText
						{
							Id = uiButton.Id + "_ConfirmInstruction",
							Position = V(x, 0f),
							Size = V(252f, 44f),
							FontSize = 12f,
							Alignment = UiAlignment.Center,
							Color = UiTheme.HealthWarn,
							Text = UiConfirmation.ButtonText(text, _state.View.ConfirmationRemainingSeconds)
						});
					}
				}
			}
		}

		public UiPageBuilder MarkPreviewOnly()
		{
			_screen.PreviewOnly = true;
			return this;
		}

		public static UiVector2 V(float x, float y)
		{
			return new UiVector2(x, y);
		}

		private T AddTo<T>(T element, UiElement parent) where T : UiElement
		{
			if (parent != null)
			{
				parent.Add(element);
			}
			else if (_chrome)
			{
				_screen.Chrome.Add(element);
			}
			else
			{
				_screen.Elements.Add(element);
			}
			return element;
		}

		private void AsChrome(Action build)
		{
			bool chrome = _chrome;
			_chrome = true;
			try
			{
				build();
			}
			finally
			{
				_chrome = chrome;
			}
		}

		public UiPanel Panel(string id, UiVector2 pos, UiVector2 size, UiColor color, float alpha, UiElement parent = null)
		{
			return AddTo(new UiPanel
			{
				Id = id,
				Position = pos,
				Size = size,
				Color = color,
				Alpha = alpha
			}, parent);
		}

		public UiRectangle Rect(string id, UiVector2 pos, UiVector2 size, UiColor color, float alpha, float rotation = 0f, UiElement parent = null)
		{
			return AddTo(new UiRectangle
			{
				Id = id,
				Position = pos,
				Size = size,
				Color = color,
				Alpha = alpha,
				Rotation = rotation
			}, parent);
		}

		public UiRectangle SharpRect(string id, UiVector2 pos, UiVector2 size, UiColor color, float alpha, UiElement parent = null)
		{
			return AddTo(new UiRectangle
			{
				Id = id,
				Position = pos,
				Size = size,
				Color = color,
				Alpha = alpha,
				Sharp = true
			}, parent);
		}

		public UiDivider Divider(UiVector2 pos, UiVector2 size, UiColor color, float alpha, UiElement parent = null)
		{
			return AddTo(new UiDivider
			{
				Id = "Divider",
				Position = pos,
				Size = size,
				Color = color,
				Alpha = alpha
			}, parent);
		}

		public UiText Text(string id, UiVector2 pos, UiVector2 size, float fontSize, UiAlignment alignment, string text, UiColor color, UiElement parent = null)
		{
			return AddTo(new UiText
			{
				Id = id,
				Position = pos,
				Size = size,
				FontSize = fontSize,
				Alignment = alignment,
				Text = Localize(text),
				Color = color
			}, parent);
		}

		public UiButton Button(string id, UiVector2 pos, UiVector2 size, string text, float fontSize, UiAction action, UiElement parent = null)
		{
			return AddTo(new UiButton
			{
				Id = id,
				Position = pos,
				Size = size,
				Text = Localize(text),
				FontSize = fontSize,
				Action = (action ?? UiAction.None)
			}, parent);
		}

		public UiButton TransparentButton(string id, UiVector2 pos, UiVector2 size, string text, float fontSize, UiAction action, UiColor? textColor = null, UiElement parent = null)
		{
			UiButton uiButton = Button(id, pos, size, text, fontSize, action, parent);
			uiButton.Transparent = true;
			uiButton.Outlined = false;
			uiButton.TintAlpha = 0f;
			if (textColor.HasValue)
			{
				uiButton.TextColor = textColor.Value;
			}
			return uiButton;
		}

		public UiButton ConfirmButton(string id, UiVector2 pos, UiVector2 size, string text, float fontSize, string confirmKey, UiAction action, UiElement parent = null)
		{
			return Button(id, pos, size, text, fontSize, (action ?? UiAction.None).Confirm(confirmKey), parent);
		}

		public UiIconElement Icon(string id, UiVector2 pos, float size, UiIcon icon, UiColor color, float alpha = 1f, UiElement parent = null)
		{
			return AddTo(new UiIconElement
			{
				Id = id,
				Position = pos,
				Size = V(size, size),
				Icon = icon,
				Color = color,
				Alpha = alpha
			}, parent);
		}

		public UiProgressBar Progress(string id, UiVector2 pos, UiVector2 size, float value01, UiColor fill, UiElement parent = null)
		{
			return AddTo(new UiProgressBar
			{
				Id = id,
				Position = pos,
				Size = size,
				Value01 = Clamp01(value01),
				FillColor = fill
			}, parent);
		}

		public UiToggle Toggle(string id, UiVector2 pos, UiVector2 size, float fontSize, string label, bool on, UiAction action, UiElement parent = null)
		{
			return AddTo(new UiToggle
			{
				Id = id,
				Position = pos,
				Size = size,
				FontSize = fontSize,
				Text = Localize(label),
				On = on,
				Action = (action ?? UiAction.None)
			}, parent);
		}

		public UiFlagChip Flag(string id, UiVector2 pos, UiVector2 size, string flagCode, string tag, UiColor color, UiElement parent = null)
		{
			return AddTo(new UiFlagChip
			{
				Id = id,
				Position = pos,
				Size = size,
				FlagCode = (flagCode ?? ""),
				Tag = (tag ?? ""),
				Color = color
			}, parent);
		}

		public void PageTitle(string title)
		{
			_screen.Title = title;
			bool home = _screen.Page == UiPageId.Home;
			AsChrome(delegate
			{
				Text("PageTitle", home ? V(-62f, 326f) : V(-56f, 326f), home ? V(428f, 44f) : V(368f, 44f), home ? 27f : 24f, UiAlignment.Left, "<b>" + title + "</b>", UiTheme.TextWhite);
			});
		}

		private int WorkspaceActionCount()
		{
			if (_state.View.ActiveWorkspace == UiWorkspace.Squad && _state.Session.IsSquadLeader)
			{
				return _state.JoinRequests.Count + _state.VehicleRequests.Count;
			}
			return _state.Session.HasPendingCloudJoin ? 1 : 0;
		}

		public UiButton ActionRow(string name, UiVector2 pos, UiVector2 size, string title, string detail, string state, UiAction action, bool primary = false, bool warning = false, bool destructive = false)
		{
			detail = detail ?? "";
			state = state ?? "";
			UiColor uiColor = (destructive ? UiTheme.HealthCrit : (warning ? UiTheme.HealthWarn : (primary ? UiTheme.Orange : UiTheme.OutlineGray)));
			UiButton uiButton = Button(name, pos, size, "", 14f, action);
			uiButton.Tint = (primary ? UiTheme.Orange : (destructive ? UiTheme.HealthCrit : UiTheme.ButtonBrown));
			uiButton.TintAlpha = (primary ? 0.88f : (destructive ? 0.2f : 0.72f));
			Rect(name + "_Rail", V((0f - size.X) * 0.5f + 4f, 0f), V(4f, size.Y - 12f), uiColor, 0.96f, 0f, uiButton);
			UiColor color = (primary ? UiTheme.TextBlack : UiTheme.TextWhite);
			UiColor color2 = (primary ? UiTheme.TextBlack.WithAlpha(0.72f) : UiTheme.TextDim);
			bool flag = !string.IsNullOrWhiteSpace(state);
			float num = ((size.X < 220f) ? 44f : ((size.X < 320f) ? 72f : 124f));
			float num2 = (0f - size.X) * 0.5f + 18f;
			float num3 = size.X * 0.5f - 14f - (flag ? (num + 12f) : 0f);
			float x = Math.Max(72f, num3 - num2);
			float x2 = (num2 + num3) * 0.5f;
			Text(name + "_Title", V(x2, (detail.Length > 0) ? 11f : 0f), V(x, 26f), (size.Y >= 68f) ? 17f : ((size.Y >= 58f) ? 16f : 14f), UiAlignment.Left, "<b>" + title + "</b>", color, uiButton);
			if (!string.IsNullOrWhiteSpace(detail))
			{
				Text(name + "_Detail", V(x2, -14f), V(x, 22f), 11.5f, UiAlignment.Left, detail, color2, uiButton);
			}
			if (flag)
			{
				UiVector2 pos2 = V(size.X * 0.5f - 14f - num * 0.5f, 0f);
				Rect(name + "_StatePill", pos2, V(num, 28f), primary ? UiTheme.TextBlack : uiColor, primary ? 0.14f : 0.16f, 0f, uiButton);
				Text(name + "_State", pos2, V(num - 8f, 28f), (size.X < 320f) ? 10.5f : 11f, UiAlignment.Center, state, primary ? UiTheme.TextBlack : ((warning || destructive) ? uiColor : UiTheme.TextDim), uiButton);
			}
			return uiButton;
		}

		public void InfoRow(string name, UiVector2 pos, UiVector2 size, string title, string detail, string state = "", UiColor? accentOverride = null)
		{
			detail = detail ?? "";
			state = state ?? "";
			UiColor color = accentOverride ?? UiTheme.OutlineGray;
			Panel(name, pos, size, UiTheme.Coffee, 0.66f);
			Rect(name + "_Rail", V(pos.X - size.X * 0.5f + 4f, pos.Y), V(4f, size.Y - 12f), color, 0.88f);
			bool flag = !string.IsNullOrWhiteSpace(state);
			float num = ((size.X < 220f) ? 44f : ((size.X < 320f) ? 72f : 124f));
			float num2 = (0f - size.X) * 0.5f + 18f;
			float num3 = size.X * 0.5f - 14f - (flag ? (num + 12f) : 0f);
			float x = Math.Max(72f, num3 - num2);
			float x2 = (num2 + num3) * 0.5f;
			Text(name + "_Title", pos + V(x2, (detail.Length > 0) ? 11f : 0f), V(x, 26f), (size.Y >= 68f) ? 17f : ((size.Y >= 58f) ? 16f : 14f), UiAlignment.Left, "<b>" + title + "</b>", UiTheme.TextWhite);
			if (!string.IsNullOrWhiteSpace(detail))
			{
				Text(name + "_Detail", pos + V(x2, -14f), V(x, 22f), 11.5f, UiAlignment.Left, detail, UiTheme.TextDim);
			}
			if (flag)
			{
				UiVector2 pos2 = pos + V(size.X * 0.5f - 14f - num * 0.5f, 0f);
				Panel(name + "_StatePill", pos2, V(num, 28f), color, 0.14f);
				Text(name + "_State", pos2, V(num - 8f, 28f), (size.X < 320f) ? 10.5f : 11f, UiAlignment.Center, state, accentOverride ?? UiTheme.TextDim);
			}
		}

		public void Pager(string name, int currentPage, int itemCount, int pageSize, float y, UiActionId action)
		{
			int num = ((pageSize <= 0) ? 1 : ((itemCount + pageSize - 1) / pageSize));
			if (num > 1)
			{
				int num2 = ClampPage(currentPage, itemCount, pageSize);
				Button(name + "_Previous", V(-86f, y), V(54f, 36f), "<", 20f, new UiAction
				{
					Id = action,
					Number = Math.Max(0, num2 - 1),
					Text = name
				});
				Text(name + "_Page", V(0f, y), V(100f, 30f), 14f, UiAlignment.Center, (num2 + 1).ToString(CultureInfo.InvariantCulture) + " / " + num.ToString(CultureInfo.InvariantCulture), UiTheme.TextDim);
				Button(name + "_Next", V(86f, y), V(54f, 36f), ">", 20f, new UiAction
				{
					Id = action,
					Number = Math.Min(num - 1, num2 + 1),
					Text = name
				});
			}
		}

		public void FeedbackBar(float y)
		{
			UiGroup uiGroup = AddTo(new UiGroup
			{
				Id = "FeedbackBar",
				Position = V(0f, y),
				Size = V(520f, 34f)
			}, null);
			uiGroup.Add(new UiPanel
			{
				Id = "FeedbackPill",
				Position = V(0f, 0f),
				Size = V(520f, 34f),
				Color = UiTheme.Coffee,
				Alpha = 0.72f
			});
			uiGroup.Add(new UiRectangle
			{
				Id = "FeedbackDot",
				Position = V(-246f, 0f),
				Size = V(6f, 18f),
				Color = UiTheme.Orange,
				Alpha = 0.95f
			});
			uiGroup.Add(new UiText
			{
				Id = "ActionFeedback",
				Position = V(-40f, 0f),
				Size = V(380f, 26f),
				FontSize = 12.5f,
				Alignment = UiAlignment.Left,
				Text = (_state.Feedback ?? ""),
				Color = UiTheme.TextDim,
				Dynamic = true
			});
			Button("FeedbackDetails", V(206f, 0f), V(96f, 30f), "DETAILS", 12f, UiAction.Of(UiActionId.OpenFeedbackDetails), uiGroup);
		}

		public void SectionLabel(UiVector2 pos, string label)
		{
			Text("Section_" + label, pos, V(548f, 24f), 10.5f, UiAlignment.Left, label.ToUpperInvariant(), UiTheme.TextDim);
		}

		public void MetricChip(UiVector2 pos, string label, string value, UiColor accent)
		{
			Panel("Metric_" + label, pos, V(160f, 54f), UiTheme.Coffee, 0.7f);
			Text("MetricLabel_" + label, pos + V(0f, 13f), V(148f, 18f), 9.5f, UiAlignment.Center, label.ToUpperInvariant(), UiTheme.TextDim);
			Text("MetricValue_" + label, pos + V(0f, -11f), V(148f, 24f), 16f, UiAlignment.Center, "<b>" + value + "</b>", accent);
		}

		public void WorkspaceNavigation(UiPageId page)
		{
			AsChrome(delegate
			{
				WorkspaceNavigationBody(page);
			});
		}

		private void WorkspaceNavigationBody(UiPageId page)
		{
			if (!UiPageIds.ShowsWorkspaceNavigation(page))
			{
				return;
			}
			UiWorkspace[] array = UiRouter.AvailableWorkspaces(_state);
			if (array.Length == 1)
			{
				Text("WorkspaceSingle", V(0f, 277f), V(180f, 28f), 10.5f, UiAlignment.Center, "PLAYER", UiTheme.TextDim);
				return;
			}
			float num = ((array.Length == 3) ? 174f : 260f);
			float spacing = num + 8f;
			float[] array2 = SpreadPositions(array.Length, spacing);
			for (int i = 0; i < array.Length; i++)
			{
				UiWorkspace uiWorkspace = array[i];
				bool flag = _state.View.ActiveWorkspace == uiWorkspace;
				int num2 = ((uiWorkspace == UiWorkspace.Squad) ? (_state.JoinRequests.Count + _state.VehicleRequests.Count) : 0);
				string text = uiWorkspace.ToString().ToUpperInvariant() + ((num2 > 0) ? ("  " + num2) : "");
				UiButton uiButton = Button("Workspace_" + uiWorkspace, V(array2[i], 277f), V(num, 34f), text, 10.5f, new UiAction
				{
					Id = UiActionId.SetWorkspace,
					Number = (int)uiWorkspace
				});
				uiButton.Tint = (flag ? UiTheme.Orange : UiTheme.ButtonBrown);
				uiButton.TintAlpha = (flag ? 0.34f : 0.58f);
				if (flag)
				{
					Rect("WorkspaceRail_" + uiWorkspace, V(0f, -15f), V(num - 14f, 3f), UiTheme.Orange, 1f, 0f, uiButton);
				}
			}
		}

		public void TopNavigation(UiPageId page)
		{
			AsChrome(delegate
			{
				TopNavigationBody(page);
			});
		}

		private void TopNavigationBody(UiPageId page)
		{
			UiButton parent = Button("SettingsGear", V(194f, 326f), V(36f, 36f), "", 10f, UiAction.Navigate(UiPageId.Settings));
			Icon("SettingsGearIcon", V(0f, 0f), 22f, UiIcon.Settings, UiTheme.TextDim, 1f, parent);
			int num = UiNavigation.ActionableNotificationCount(_state);
			UiButton parent2 = Button("NotificationBell", V(238f, 326f), V(36f, 36f), "", 10f, UiAction.Navigate(UiPageId.Notifications));
			if (num > 0)
			{
				Text("NotificationCount", V(250f, 338f), V(24f, 18f), 10f, UiAlignment.Center, num.ToString(), UiTheme.Orange);
			}
			Icon("NotificationBellIcon", V(0f, 0f), 20f, UiIcon.Notifications, UiTheme.Orange, 1f, parent2);
			if (page != UiPageId.Home)
			{
				TransparentButton("Back", V(-274f, 326f), V(44f, 44f), "<-", 18f, UiAction.Of(UiActionId.Back), UiTheme.Orange);
			}
		}

		public void FooterNavigation(UiPageId page)
		{
			AsChrome(delegate
			{
				FooterNavigationBody(page);
			});
		}

		private void FooterNavigationBody(UiPageId page)
		{
			UiNavigation.Section[] array = UiNavigation.Sections(_state, page);
			float num = ((array.Length == 4) ? 130f : ((array.Length == 2) ? 264f : 174f));
			float[] array2 = SpreadPositions(array.Length, num + 8f);
			for (int i = 0; i < array.Length; i++)
			{
				Button("Section_" + array[i].Label, V(array2[i], UiPageIds.ShowsWorkspaceNavigation(page) ? 244f : 277f), V(num, 26f), array[i].Label, 10f, UiAction.Navigate(array[i].Page));
			}
			string text = UiNavigation.Breadcrumb(_state, page);
			if (text.Length > 0)
			{
				Text("HostBreadcrumb", V(0f, -246f), V(548f, 18f), 9f, UiAlignment.Left, text, UiTheme.TextDim);
			}
			Divider(V(0f, -320f), V(564f, 2f), UiTheme.OutlineGray, 0.62f);
			if (page != UiPageId.Home)
			{
				TransparentButton("FooterHome", V(-254f, -348f), V(76f, 38f), "HOME", 10f, UiAction.Of(UiActionId.GoHome), UiTheme.TextDim);
			}
			if (UiPageIds.IsMilsimPage(page) && !UiPageIds.ShowsWorkspaceNavigation(page))
			{
				TransparentButton("FooterWorkspace", V(-162f, -348f), V(100f, 38f), _state.View.ActiveWorkspace.ToString().ToUpperInvariant(), 10.5f, new UiAction
				{
					Id = UiActionId.SetWorkspace,
					Number = (int)_state.View.ActiveWorkspace
				}, UiTheme.Orange);
			}
			TransparentButton("FooterUpdates", V(-40f, -348f), V(136f, 38f), "v" + _state.Session.ModVersion + " • UPDATES", 9.5f, UiAction.Navigate(UiPageId.AboutUpdates), (page == UiPageId.AboutUpdates) ? UiTheme.Orange : UiTheme.TextDim);
			string text2 = UiFormat.Short(_state.Session.LocalPlayerName, 10) + "  •  " + (_state.Session.NetworkActive ? "FUSION" : "SOLO");
			Text("FooterIdentity", V(166f, -348f), V(236f, 28f), 10.5f, UiAlignment.Right, text2.ToUpperInvariant(), UiTheme.TextDim);
		}

		public void LanguageButton(UiPageId page)
		{
			AsChrome(delegate
			{
				bool flag = page == UiPageId.Language;
				UiButton uiButton = Button("LanguageGlobe", V(284f, 326f), V(40f, 40f), "", 10f, new UiAction
				{
					Id = UiActionId.OpenLanguage,
					Page = page
				});
				uiButton.Tint = UiTheme.Coffee;
				uiButton.TintAlpha = 0.8f;
				Icon("LanguageGlobe_Icon", V(0f, 0f), 24f, UiIcon.Globe, flag ? UiTheme.Orange : UiTheme.TextWhite, 1f, uiButton);
				Text("LanguageGlobe_Code", V(284f, 299f), V(52f, 16f), 9f, UiAlignment.Center, _state.View.Language.ToUpperInvariant(), UiTheme.TextDim);
			});
		}

		public static float[] SpreadPositions(int count, float spacing)
		{
			float[] array = new float[count];
			float num = (float)(-(count - 1)) * spacing * 0.5f;
			for (int i = 0; i < count; i++)
			{
				array[i] = num + (float)i * spacing;
			}
			return array;
		}

		public static int ClampPage(int page, int itemCount, int pageSize)
		{
			if (pageSize <= 0)
			{
				return 0;
			}
			int num = Math.Max(1, (itemCount + pageSize - 1) / pageSize);
			if (page < 0)
			{
				return 0;
			}
			if (page < num)
			{
				return page;
			}
			return num - 1;
		}

		private static float Clamp01(float value)
		{
			if (!(value < 0f))
			{
				if (!(value > 1f))
				{
					return value;
				}
				return 1f;
			}
			return 0f;
		}

		private string Localize(string text)
		{
			if (text == null)
			{
				return "";
			}
			text = UiTranslation.Translate(text, _state.View.TranslateInComposition ? _state.View.Language : "en");
			if (!_state.View.LocalizationStressTest || text.Length == 0)
			{
				return text;
			}
			return UiStrings.Stretch(text);
		}
	}
	public static class UiFormat
	{
		public static string Literal(string value)
		{
			return (value ?? "").Replace("<", "‹").Replace(">", "›");
		}

		public static string SideName(UiSnapshot state, int side)
		{
			string[] array = (from t in state.ActiveTeams
				where t.Side == side
				select Literal(t.Tag)).ToArray();
			if (array.Length != 0)
			{
				return string.Join(" + ", array);
			}
			return "Side " + ((side == 1) ? "A" : "B");
		}

		public static string SideScore(UiSnapshot state)
		{
			return Score(1) + "  /  " + Score(2);
			string Score(int side)
			{
				UiTeamSnapshot uiTeamSnapshot = state.ActiveTeams.FirstOrDefault((UiTeamSnapshot t) => t.Side == side);
				return SideName(state, side) + " " + ((uiTeamSnapshot == null) ? "—" : uiTeamSnapshot.Tokens.ToString(CultureInfo.InvariantCulture));
			}
		}

		public static string Short(string value, int max)
		{
			if (string.IsNullOrEmpty(value))
			{
				return "";
			}
			return Literal((value.Length <= max) ? value : (value.Substring(0, Math.Max(1, max - 1)) + "…"));
		}

		public static string Plural(int count, string singular, string plural = null)
		{
			if (count == 1)
			{
				return singular;
			}
			return plural ?? (singular + "s");
		}

		public static string Supply(int value)
		{
			if (value >= 0)
			{
				return value.ToString(CultureInfo.InvariantCulture);
			}
			return "∞";
		}

		public static string Number(float value, string format = "0.#")
		{
			return value.ToString(format, CultureInfo.InvariantCulture);
		}

		public static string Strip(string richText)
		{
			if (string.IsNullOrEmpty(richText))
			{
				return "";
			}
			return richText.Replace("<b>", "").Replace("</b>", "").Replace("<i>", "")
				.Replace("</i>", "");
		}

		public static string TeamTag(UiSnapshot state, UiTeam team)
		{
			if (team == UiTeam.Unassigned)
			{
				return "NONE";
			}
			UiTeamSnapshot uiTeamSnapshot = state.Team(team);
			if (uiTeamSnapshot != null && !string.IsNullOrWhiteSpace(uiTeamSnapshot.Tag))
			{
				return Literal(uiTeamSnapshot.Tag);
			}
			return team.ToString().ToUpperInvariant();
		}

		public static string TeamName(UiSnapshot state, UiTeam team)
		{
			if (team == UiTeam.Unassigned)
			{
				return "Unassigned";
			}
			UiTeamSnapshot uiTeamSnapshot = state.Team(team);
			if (uiTeamSnapshot != null && !string.IsNullOrWhiteSpace(uiTeamSnapshot.DisplayName))
			{
				return Literal(uiTeamSnapshot.DisplayName);
			}
			return team.ToString();
		}
	}
	public static class UiPageCatalog
	{
		private sealed class QueueRow
		{
			public bool Join;

			public int Id;

			public string Name = "";

			public string Detail = "";
		}

		private static readonly HashSet<UiPageId> SharedPages = new HashSet<UiPageId>
		{
			UiPageId.PlayerSpawns,
			UiPageId.InitialVehicles,
			UiPageId.FeedbackDetails,
			UiPageId.Home,
			UiPageId.PlayerTeamsLoadout,
			UiPageId.Notifications,
			UiPageId.PlayerReadyLobby,
			UiPageId.PlayerReadyLive,
			UiPageId.PlayerField,
			UiPageId.PlayerBrief,
			UiPageId.PlayerRoster,
			UiPageId.PlayerKitSupplies,
			UiPageId.PlayerVehicleRequest,
			UiPageId.SquadAssembly,
			UiPageId.SquadCommand,
			UiPageId.SquadQueue,
			UiPageId.SquadRoster,
			UiPageId.SquadPolicy,
			UiPageId.HostSetupOverview,
			UiPageId.HostLiveControl,
			UiPageId.HostWorld,
			UiPageId.HostPreflight,
			UiPageId.HostLiveActions
		};

		private static readonly UiVector2 BodyFigureCenter = new UiVector2(0f, 50f);

		public static bool IsSharedWithBonelabRenderer(UiPageId page)
		{
			return SharedPages.Contains(page);
		}

		public static IEnumerable<UiPageId> AllPages()
		{
			return Enum.GetValues(typeof(UiPageId)).Cast<UiPageId>();
		}

		public static UiScreen Compose(UiPageId page, UiSnapshot state)
		{
			if (state == null)
			{
				throw new ArgumentNullException("state");
			}
			UiPageBuilder uiPageBuilder = new UiPageBuilder(page, state);
			if (!SharedPages.Contains(page))
			{
				uiPageBuilder.MarkPreviewOnly();
			}
			uiPageBuilder.TopNavigation(page);
			uiPageBuilder.LanguageButton(page);
			uiPageBuilder.WorkspaceNavigation(page);
			BuildPageBody(uiPageBuilder, page, state);
			uiPageBuilder.FooterNavigation(page);
			UiOverlays.Compose(uiPageBuilder.Screen, state);
			return uiPageBuilder.Build();
		}

		private static void BuildPageBody(UiPageBuilder b, UiPageId page, UiSnapshot state)
		{
			switch (page)
			{
			case UiPageId.FeedbackDetails:
				BuildFeedbackDetails(b, state);
				break;
			case UiPageId.PlayerSpawns:
				BuildPlayerSpawns(b, state);
				break;
			case UiPageId.InitialVehicles:
				BuildInitialVehicles(b, state);
				break;
			case UiPageId.Home:
				BuildHome(b, state);
				break;
			case UiPageId.PlayerReadyLobby:
				BuildPlayerReadyRoom(b, state, live: false);
				break;
			case UiPageId.PlayerReadyLive:
				BuildPlayerReadyRoom(b, state, live: true);
				break;
			case UiPageId.PlayerField:
				BuildPlayerField(b, state);
				break;
			case UiPageId.PlayerBrief:
				BuildPlayerBrief(b, state);
				break;
			case UiPageId.PlayerRoster:
				BuildRoster(b, state, squadOnly: false);
				break;
			case UiPageId.PlayerKitSupplies:
				BuildPlayerKitSupplies(b, state);
				break;
			case UiPageId.PlayerVehicleRequest:
				BuildPlayerVehicleRequest(b, state);
				break;
			case UiPageId.SquadAssembly:
				BuildSquadLanding(b, state, state.Session.SessionActive);
				break;
			case UiPageId.SquadCommand:
				BuildSquadLanding(b, state, state.Session.SessionActive);
				break;
			case UiPageId.SquadQueue:
				BuildSquadCommandQueue(b, state);
				break;
			case UiPageId.SquadRoster:
				BuildSquadRoster(b, state);
				break;
			case UiPageId.SquadPolicy:
				BuildSquadPolicy(b, state);
				break;
			case UiPageId.HostSetupOverview:
				if (state.Session.SessionActive)
				{
					BuildHostLiveControl(b, state);
				}
				else
				{
					BuildHostSetupOverview(b, state);
				}
				break;
			case UiPageId.HostLiveControl:
				if (state.Session.SessionActive)
				{
					BuildHostLiveControl(b, state);
				}
				else
				{
					BuildHostSetupOverview(b, state);
				}
				break;
			case UiPageId.HostWorld:
				BuildHostWorld(b, state);
				break;
			case UiPageId.HostPreflight:
				if (state.Session.SessionActive)
				{
					BuildHostLiveControl(b, state);
				}
				else
				{
					BuildHostPreflight(b, state);
				}
				break;
			case UiPageId.HostLiveActions:
				BuildHostLiveActions(b, state);
				break;
			case UiPageId.Settings:
				BuildSettings(b, state);
				break;
			case UiPageId.SettingsCategory:
				BuildSettingsCategory(b, state);
				break;
			case UiPageId.Notifications:
				BuildNotifications(b, state);
				break;
			case UiPageId.Medical:
				BuildMedical(b, state);
				break;
			case UiPageId.MilsimMap:
				BuildMap(b, state);
				break;
			case UiPageId.PlayerTeamsLoadout:
				BuildTeamSelection(b, state);
				break;
			case UiPageId.Language:
				BuildLanguage(b, state);
				break;
			case UiPageId.AboutUpdates:
				BuildAboutUpdates(b, state);
				break;
			case UiPageId.MilsimLoadoutSelect:
				BuildLoadoutSelect(b, state);
				break;
			case UiPageId.MilsimOverview:
				BuildGameOverview(b, state);
				break;
			case UiPageId.Fusion:
				BuildFusion(b, state);
				break;
			default:
				BuildLegacyPlaceholder(b, page, state);
				break;
			}
		}

		private static void BuildLegacyPlaceholder(UiPageBuilder b, UiPageId page, UiSnapshot state)
		{
			b.PageTitle(SplitPascal(page.ToString()));
			b.Panel("LegacyBox", UiPageBuilder.V(0f, 60f), UiPageBuilder.V(548f, 260f), UiTheme.Coffee, 0.6f);
			b.Text("LegacyTitle", UiPageBuilder.V(0f, 150f), UiPageBuilder.V(500f, 30f), 16f, UiAlignment.Center, "<b>LEGACY UNITY PAGE</b>", UiTheme.HealthWarn);
			b.Text("LegacyBody", UiPageBuilder.V(0f, 70f), UiPageBuilder.V(500f, 120f), 12.5f, UiAlignment.Center, "This page is still drawn by DashboardView's own builder in BONELAB.\nIt has no shared composition yet, so the previewer will not\ninvent one - that is how a second UI starts.\n\nRoute and state below are real and are shared with the game.", UiTheme.TextDim);
			b.InfoRow("LegacyRoute", UiPageBuilder.V(0f, -60f), UiPageBuilder.V(548f, 56f), "Back goes to", SplitPascal(UiRouter.ParentPage(state, page).ToString()), "ROUTE");
			b.InfoRow("LegacyWorkspace", UiPageBuilder.V(0f, -124f), UiPageBuilder.V(548f, 56f), "Workspace", UiRouter.WorkspaceForPage(page, state.View.ActiveWorkspace).ToString(), UiPageIds.IsMilsimPage(page) ? "MILSIM" : "SHELL");
		}

		internal static string SplitPascal(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder(value.Length + 8);
			for (int i = 0; i < value.Length; i++)
			{
				if (i > 0 && char.IsUpper(value[i]) && !char.IsUpper(value[i - 1]))
				{
					stringBuilder.Append(' ');
				}
				stringBuilder.Append(value[i]);
			}
			return stringBuilder.ToString();
		}

		private static void BuildPlayerSpawns(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("Choose spawn");
			b.Text("SelectedSpawn", V(0f, 220f), V(540f, 40f), 13f, UiAlignment.Center, s.SpawnSelectionStatus, UiTheme.TextDim);
			List<UiSpawnSnapshot> list = s.Match.Spawns.Where((UiSpawnSnapshot p) => p.Eligible).ToList();
			int num = UiPageBuilder.ClampPage(s.View.SpawnPage, list.Count, 4);
			float num2 = 150f;
			foreach (UiSpawnSnapshot item in list.Skip(num * 4).Take(4))
			{
				b.ActionRow("ChooseSpawn_" + item.Id, V(0f, num2), V(548f, 64f), UiFormat.Literal(item.Name), (item.IsRally ? "Rally" : UiFormat.TeamTag(s, item.Team)) + (item.Damaged ? " · Damaged — unavailable" : (item.Threatened ? " · Enemy nearby" : "")), item.Damaged ? "DISABLED" : (item.Selected ? (item.Threatened ? "SELECTED !" : "SELECTED") : (item.Threatened ? "THREAT" : "SELECT")), new UiAction
				{
					Id = UiActionId.SelectSpawn,
					Number = item.Id
				}, item.Selected, item.Threatened || item.Damaged).Enabled = !item.Damaged && !item.Threatened;
				num2 -= 74f;
			}
			if (list.Count == 0)
			{
				b.Text("NoSpawnChoices", V(0f, 60f), V(540f, 60f), 16f, UiAlignment.Center, "No respawn points yet", UiTheme.TextDim);
			}
			b.Pager("PlayerSpawns", num, list.Count, 4, -166f, UiActionId.SetPageIndex);
			b.Button("AutomaticSpawn", V(0f, -222f), V(420f, 46f), "AUTOMATIC", 14f, UiAction.Of(UiActionId.SelectAutomaticSpawn));
			b.FeedbackBar(-286f);
		}

		private static void BuildInitialVehicles(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("Initial vehicles");
			if (!s.Session.CanManage)
			{
				b.Text("InitialVehiclesDenied", V(0f, 60f), V(540f, 60f), 16f, UiAlignment.Center, "Host Access required", UiTheme.TextDim);
				return;
			}
			b.Text("InitialVehiclesStatus", V(0f, 218f), V(540f, 42f), 12f, UiAlignment.Center, s.Session.SessionActive ? "Stop the match to edit initial vehicles" : s.InitialVehicleStatus, UiTheme.TextDim);
			List<UiInitialVehicleOption> initialVehicleOptions = s.InitialVehicleOptions;
			int num = UiPageBuilder.ClampPage(s.View.InitialVehiclePage, initialVehicleOptions.Count, 3);
			float num2 = 150f;
			foreach (UiInitialVehicleOption row in initialVehicleOptions.Skip(num * 3).Take(3))
			{
				int team = (int)row.Team;
				string text = "Initial_" + team + "_" + initialVehicleOptions.IndexOf(row);
				UiSpawnSnapshot uiSpawnSnapshot = s.Match.Spawns.FirstOrDefault((UiSpawnSnapshot p) => p.Id == row.SpawnId);
				b.Text(text + "Name", V(-40f, num2), V(450f, 32f), 14f, UiAlignment.Left, UiFormat.TeamTag(s, row.Team) + "  ·  " + UiFormat.Short(row.Name, 28), UiTheme.TextWhite);
				UiButton uiButton = b.Button(text + "Minus", V(152f, num2 - 36f), V(48f, 38f), "−", 18f, new UiAction
				{
					Id = UiActionId.ChangeInitialVehicleCount,
					Team = row.Team,
					Text = row.Barcode,
					Number = -1
				});
				UiButton uiButton2 = b.Button(text + "Plus", V(238f, num2 - 36f), V(48f, 38f), "+", 18f, new UiAction
				{
					Id = UiActionId.ChangeInitialVehicleCount,
					Team = row.Team,
					Text = row.Barcode,
					Number = 1
				});
				uiButton.Enabled = !s.Session.SessionActive && row.Count > 0;
				uiButton2.Enabled = !s.Session.SessionActive && row.Count < 16 && (row.Limit <= 0 || row.Count < row.Limit);
				b.Text(text + "Count", V(195f, num2 - 36f), V(38f, 34f), 15f, UiAlignment.Center, row.Count.ToString(), UiTheme.TextWhite);
				b.Button(text + "Spawn", V(-74f, num2 - 36f), V(376f, 38f), (uiSpawnSnapshot == null) ? "TEAM SPAWN" : UiFormat.Short(uiSpawnSnapshot.Name, 30), 12f, new UiAction
				{
					Id = UiActionId.CycleInitialVehicleSpawn,
					Team = row.Team,
					Text = row.Barcode
				}).Enabled = !s.Session.SessionActive && row.Count > 0;
				num2 -= 106f;
			}
			if (initialVehicleOptions.Count == 0)
			{
				b.Text("InitialVehiclesEmpty", V(0f, 40f), V(540f, 60f), 16f, UiAlignment.Center, "No team vehicles configured", UiTheme.TextDim);
			}
			b.Pager("InitialVehicles", num, initialVehicleOptions.Count, 3, -208f, UiActionId.SetPageIndex);
			b.FeedbackBar(-286f);
		}

		private static void BuildHostSetupOverview(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("SETUP");
			bool startReady = s.Match.StartReady;
			string startReadinessSummary = s.Match.StartReadinessSummary;
			b.Panel("SetupIdentity", V(0f, 202f), V(548f, 44f), UiTheme.Coffee, 0.72f);
			b.Text("SetupTemplate", V(-58f, 202f), V(410f, 26f), 11f, UiAlignment.Left, "ACTIVE  •  " + UiFormat.Short(s.Match.ActiveTemplateName, 30), UiTheme.TextWhite);
			b.Text("SetupState", V(220f, 202f), V(96f, 26f), 10f, UiAlignment.Right, startReady ? "READY" : "INCOMPLETE", startReady ? UiTheme.HealthGood : UiTheme.HealthWarn);
			int activeFactionCount = s.Setup.ActiveFactionCount;
			b.ActionRow("SetupTemplates", V(-138f, 148f), V(264f, 62f), "SAVED SETUPS", "Load or save setup", "", new UiAction
			{
				Id = UiActionId.OpenSetupTemplates,
				Page = UiPageId.HostSetupOverview
			});
			b.ActionRow("SetupTeams", V(138f, 148f), V(264f, 62f), "TEAMS & LOADOUTS", activeFactionCount + " active teams", "", new UiAction
			{
				Id = UiActionId.OpenWorkflowEditor,
				Page = UiPageId.SetupContent
			}, activeFactionCount < 2, activeFactionCount < 2);
			b.ActionRow("SetupWorld", V(-138f, 76f), V(264f, 62f), "World", s.Match.Objectives.Count + " objectives  •  " + s.Match.Spawns.Count + " spawns", "", UiAction.Navigate(UiPageId.HostWorld));
			b.ActionRow("SetupRules", V(138f, 76f), V(264f, 62f), "Rules", "Flow, combat, medical, spawn", "", new UiAction
			{
				Id = UiActionId.OpenWorkflowEditor,
				Page = UiPageId.HostSettings
			});
			int num = UiDerive.IncompleteRosterCount(s);
			b.ActionRow("SetupLobby", V(-138f, 4f), V(264f, 62f), "PLAYERS", s.Roster.Count + " " + UiFormat.Plural(s.Roster.Count, "player") + "  •  " + num + " incomplete", (num > 0) ? "CHECK" : "", new UiAction
			{
				Id = UiActionId.OpenWorkflowEditor,
				Page = UiPageId.MilsimTeams
			}, primary: false, num > 0);
			b.ActionRow("SetupContent", V(138f, 4f), V(264f, 62f), "Loadout Pack", UiFormat.Short(s.Match.ActivePackStatusLine, 42), "", new UiAction
			{
				Id = UiActionId.OpenWorkflowEditor,
				Page = UiPageId.MilsimPacks
			});
			b.ActionRow("SetupPreflight", V(0f, -82f), V(548f, 70f), startReady ? "Ready to start" : "Check match setup", UiFormat.Short(startReadinessSummary, 56), startReady ? "START" : "REVIEW", UiAction.Navigate(UiPageId.HostPreflight), startReady, !startReady);
			b.FeedbackBar(-286f);
		}

		private static void BuildHostLiveControl(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("CONTROL");
			int num = UiDerive.IncompleteRosterCount(s);
			_ = s.ActiveTeams;
			string text = (s.Match.RespawnTokensEnabled ? UiFormat.SideScore(s) : "UNLIMITED LIVES");
			b.Panel("LiveMatchStrip", V(0f, 202f), V(548f, 44f), UiTheme.Coffee, 0.78f);
			b.Text("LiveScore", V(-70f, 202f), V(390f, 26f), 13f, UiAlignment.Left, "<b>" + text + "</b>  •  " + s.Roster.Count + " " + UiFormat.Plural(s.Roster.Count, "PLAYER", "PLAYERS"), UiTheme.TextWhite);
			b.Text("LiveExceptions", V(220f, 202f), V(100f, 26f), 10f, UiAlignment.Right, (num > 0) ? (num + " NEED SETUP") : "HEALTHY", (num > 0) ? UiTheme.HealthWarn : UiTheme.HealthGood);
			int num2 = s.Match.ObjectivesOwnedBySide(1);
			int num3 = s.Match.ObjectivesOwnedBySide(2);
			b.Text("LiveObjectives", V(0f, 164f), V(548f, 24f), 10.5f, UiAlignment.Left, "OBJECTIVES  •  SIDE A " + num2 + "  /  NEUTRAL " + (s.Match.Objectives.Count - num2 - num3) + "  /  SIDE B " + num3, UiTheme.TextDim);
			b.ActionRow("LiveFreeze", V(0f, 108f), V(548f, 60f), s.Session.PlayersFrozen ? "UNFREEZE" : "FREEZE", s.Session.PlayersFrozen ? "Players frozen" : "Players active", "", UiAction.Of(UiActionId.TogglePlayersFrozen));
			b.ConfirmButton("LiveStop", V(0f, 34f), V(548f, 62f), "END MATCH", 16f, "live_stop_match", UiAction.Of(UiActionId.StopMatch));
			b.ActionRow("LiveSetup", V(-138f, -44f), V(264f, 60f), "SETUP", "Teams & loadouts", "", new UiAction
			{
				Id = UiActionId.OpenWorkflowEditor,
				Page = UiPageId.SetupContent
			});
			b.ActionRow("LiveAdvanced", V(138f, -44f), V(264f, 60f), "ADVANCED", "World cleanup", "", UiAction.Navigate(UiPageId.HostLiveActions));
			b.FeedbackBar(-286f);
		}

		private static void BuildHostWorld(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("World");
			b.Text("WorldLevel", V(0f, 220f), V(548f, 28f), 11f, UiAlignment.Left, "LEVEL  •  " + UiFormat.Short(s.Session.SceneName, 42) + (s.Session.SessionActive ? "  •  LIVE EDIT" : ""), UiTheme.TextDim);
			b.ActionRow("WorldObjectives", V(0f, 132f), V(548f, 100f), "Objectives", s.Match.Objectives.Count + " placed  •  capture radius " + UiFormat.Number(s.Match.CaptureRadius) + "m", "EDIT", new UiAction
			{
				Id = UiActionId.OpenWorkflowEditor,
				Page = UiPageId.MilsimPoints
			});
			b.ActionRow("WorldSpawns", V(0f, 20f), V(548f, 100f), "Spawns", s.Match.Spawns.Count + " placed  •  shared and team coverage", "EDIT", new UiAction
			{
				Id = UiActionId.OpenWorkflowEditor,
				Page = UiPageId.MilsimRespawns
			});
			b.ActionRow("WorldVehicles", V(0f, -194f), V(548f, 76f), "VEHICLES", s.Session.SessionActive ? "Team vehicles" : "Starting vehicles by team", "EDIT", UiAction.Navigate(s.Session.SessionActive ? UiPageId.MilsimFactionVehicles : UiPageId.InitialVehicles));
			b.ActionRow("WorldAdvanced", V(0f, -92f), V(548f, 76f), "ADVANCED", "World cleanup", "OPEN", UiAction.Navigate(UiPageId.HostLiveActions));
		}

		private static void BuildHostPreflight(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("Preflight");
			bool startReady = s.Match.StartReady;
			string startReadinessSummary = s.Match.StartReadinessSummary;
			List<string> compatibilityWatchMods = s.Session.CompatibilityWatchMods;
			bool flag = compatibilityWatchMods.Count == 0;
			bool codeModGateClean = s.Session.CodeModGateClean;
			int num = s.Roster.Where((UiPlayerSnapshot entry) => entry.Team != UiTeam.Unassigned).ToList().Count((UiPlayerSnapshot entry) => entry.IsReady && !string.IsNullOrWhiteSpace(entry.LoadoutName));
			int num2 = s.Roster.Count - num;
			b.Text("PreflightState", V(0f, 222f), V(548f, 28f), 13f, UiAlignment.Left, startReady ? "READY TO START" : "CONFIGURATION BLOCKED", startReady ? UiTheme.HealthGood : UiTheme.HealthCrit);
			PreflightRow(b, "PreflightPack", 174f, "Loadout Pack", s.Match.ActivePackLoadoutCount > 0, UiFormat.Short(s.Match.ActivePackStatusLine, 58), UiPageId.MilsimPacks);
			PreflightRow(b, "PreflightTeams", 116f, "TEAMS & LOADOUTS", s.Setup.ActiveFactionCount >= 2, s.Setup.ActiveFactionCount + " ACTIVE TEAMS", UiPageId.SetupContent);
			PreflightRow(b, "PreflightSpawns", 58f, "Team spawns", s.Setup.HasRequiredSpawns, s.Match.Spawns.Count + " PLACED", UiPageId.HostWorld);
			b.InfoRow("PreflightCodeModGate", V(0f, 0f), V(548f, 54f), "Code Mod Gate", UiFormat.Short(s.Session.CodeModGateStatus, 58), codeModGateClean ? "CLEAR" : "NOTICE", codeModGateClean ? UiTheme.HealthGood : UiTheme.HealthWarn);
			b.InfoRow("PreflightCompatibility", V(0f, -58f), V(548f, 54f), flag ? "Compatibility" : "Optional compatibility notice", flag ? "NO WATCH-LIST MODS DETECTED" : string.Join(", ", compatibilityWatchMods.ToArray()), flag ? "CLEAR" : "START ALLOWED", flag ? UiTheme.HealthGood : UiTheme.HealthWarn);
			PreflightRow(b, "PreflightPlayers", -116f, "Players", good: true, num + " DEPLOY NOW  •  " + num2 + " JOIN AFTER START", UiPageId.MilsimTeams);
			b.ActionRow("PreflightStart", V(0f, -190f), V(548f, 50f), startReady ? "Start match" : "Fix blockers before start", UiFormat.Short(startReadinessSummary, 60), startReady ? "START" : "BLOCKED", UiAction.Of(UiActionId.StartMatch), startReady, !startReady);
			b.FeedbackBar(-286f);
		}

		private static void PreflightRow(UiPageBuilder b, string name, float y, string title, bool good, string detail, UiPageId target)
		{
			b.ActionRow(name, V(0f, y), V(548f, 54f), title, detail, good ? "OK" : "FIX", UiAction.Navigate(target), primary: false, !good);
		}

		private static void BuildHostLiveActions(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("ADVANCED");
			b.Text("LiveActionScope", V(0f, 220f), V(548f, 32f), 11f, UiAlignment.Left, s.Session.NetworkActive ? "HOST AUTHORITY  •  ALL PLAYERS" : "SOLO  •  OWNERSHIP-AWARE CLEANUP MAY BE LIMITED", UiTheme.TextDim);
			b.ConfirmButton("LiveCleanup", V(0f, 146f), V(548f, 60f), "CLEAN ALL SPAWNED ITEMS", 14f, "live_cleanup_all", UiAction.Of(UiActionId.CleanupSpawnedItems));
			b.ConfirmButton("LiveCorpses", V(0f, 76f), V(548f, 60f), "CLEAR ALL CORPSES", 14f, "live_clear_corpses", UiAction.Of(UiActionId.ClearCorpses));
			b.ConfirmButton("LiveWrecks", V(0f, 6f), V(548f, 60f), "CLEAR ALL VEHICLE WRECKS", 14f, "live_clear_wrecks", UiAction.Of(UiActionId.ClearWrecks));
			b.Text("LiveStopScope", V(0f, -70f), V(520f, 30f), 10f, UiAlignment.Center, "STOP RETURNS PLAYERS TO THE ORIGINAL MAP SPAWN", UiTheme.TextDim);
			b.ConfirmButton("LiveStop", V(0f, -126f), V(548f, 72f), "END MATCH", 18f, "live_stop_match", UiAction.Of(UiActionId.StopMatch));
			b.FeedbackBar(-286f);
		}

		private static UiVector2 V(float x, float y)
		{
			return new UiVector2(x, y);
		}

		private static void BuildHome(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("Main Menu");
			int playerCount = s.Session.PlayerCount;
			b.Text("HomeConnection", V(0f, 226f), V(548f, 26f), 11f, UiAlignment.Left, (s.Session.SessionActive ? "LIVE" : "LOBBY") + "  •  " + (s.Session.NetworkActive ? "FUSION" : "SOLO") + "  •  " + playerCount + " " + UiFormat.Plural(playerCount, "PLAYER", "PLAYERS"), UiTheme.TextDim);
			b.Text("HomeRole", V(0f, 226f), V(548f, 26f), 11f, UiAlignment.Right, UiDerive.LocalRoleSummary(s), UiTheme.Orange);
			UiPageId page = UiDerive.PrimaryNextPage(s);
			b.ActionRow("HomeContinue", V(0f, 164f), V(548f, 74f), UiDerive.PrimaryNextTitle(page), UiDerive.PrimaryNextDetail(page), "OPEN", UiAction.Navigate(page), primary: true);
			b.ActionRow("HomeAccount", V(0f, 60f), V(548f, 66f), "ACCOUNT / ONLINE", "Pairing and servers", "", UiAction.Navigate(UiPageId.AccountPairing));
			b.ActionRow("HomeServerBrowser", V(0f, -20f), V(548f, 66f), "SPECTRUMB SERVER BROWSER", "Browse and join servers", "OPEN", UiAction.Navigate(UiPageId.ServerBrowser));
		}

		private static void BuildPlayerReadyRoom(UiPageBuilder b, UiSnapshot s, bool live)
		{
			BuildPlayerField(b, s);
		}

		private static void BuildTeamSelection(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("TEAM");
			b.Text("TeamHint", V(0f, 218f), V(548f, 28f), 11f, UiAlignment.Left, s.Session.SessionActive ? "Applies on next deployment" : "Choose team", UiTheme.TextDim);
			TeamPicker(b, s, 140f);
			b.FeedbackBar(-286f);
		}

		private static void TeamPicker(UiPageBuilder b, UiSnapshot s, float y)
		{
			List<UiTeamSnapshot> activeTeams = s.ActiveTeams;
			if (activeTeams.Count == 0)
			{
				b.Text("TeamPickerEmpty", V(0f, y), V(520f, 40f), 14f, UiAlignment.Center, "NO TEAMS CONFIGURED", UiTheme.TextDim);
				return;
			}
			bool flag = activeTeams.Count == 4;
			int num = (flag ? 4 : (activeTeams.Count + (s.Local.HasTeam ? 1 : 0)));
			float num2 = ((num <= 2) ? 264f : ((num == 3) ? 174f : 130f));
			float[] array = UiPageBuilder.SpreadPositions(num, num2 + 8f);
			if (flag)
			{
				num2 = 264f;
			}
			for (int i = 0; i < activeTeams.Count; i++)
			{
				UiTeamSnapshot uiTeamSnapshot = activeTeams[i];
				bool flag2 = s.Local.Team == uiTeamSnapshot.Team;
				bool flag3 = false;
				UiButton uiButton = b.Button("TeamPick_" + uiTeamSnapshot.Team, flag ? V((i % 2 == 0) ? (-138f) : 138f, y + ((i < 2) ? 15f : (-23f))) : V(array[i], y), V(num2, flag ? 32f : 56f), UiFormat.Short(string.IsNullOrWhiteSpace(uiTeamSnapshot.DisplayName) ? uiTeamSnapshot.Tag : uiTeamSnapshot.DisplayName, flag ? 26 : ((num >= 4) ? 14 : 22)) + ((!flag3) ? "" : (flag ? " · REQUEST" : "\nREQUEST")), flag ? 12f : 14f, new UiAction
				{
					Id = UiActionId.SelectTeam,
					Team = uiTeamSnapshot.Team
				}.Confirm(flag2 ? "" : ("team_" + uiTeamSnapshot.Team)));
				uiButton.Tint = (flag2 ? uiTeamSnapshot.Color : UiTheme.ButtonBrown);
				uiButton.TintAlpha = (flag2 ? 0.56f : 0.62f);
				uiButton.TextColor = (flag2 ? UiTheme.TextWhite : UiTheme.TextDim);
				if (flag2)
				{
					b.Rect("TeamPickRail_" + uiTeamSnapshot.Team, V(0f, flag ? (-14f) : (-24f)), V(num2 - 18f, 3f), UiTheme.Orange, 1f, 0f, uiButton);
				}
			}
			if (s.Local.HasTeam)
			{
				UiButton uiButton2 = b.Button("TeamLeave", flag ? V(205f, 184f) : V(array[num - 1], y), flag ? V(130f, 24f) : V(num2, 56f), "LEAVE", (num >= 4) ? 11f : 12f, UiAction.Of(UiActionId.LeaveTeam).Confirm("leave_team"));
				uiButton2.Tint = UiTheme.HealthCrit;
				uiButton2.TintAlpha = 0.22f;
			}
		}

		private static void BuildPlayerField(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("GAME");
			bool sessionActive = s.Session.SessionActive;
			bool flag = s.Medical.State == UiMedicalState.Dead || s.Medical.State == UiMedicalState.Respawning;
			string text = (sessionActive ? (flag ? ("RESPAWN  " + Math.Ceiling(s.Local.RespawnRemaining) + "s") : (s.Local.LateJoinCountdownActive ? "DEPLOYING" : "LIVE")) : (s.Local.Ready ? "READY" : "NOT READY"));
			b.Text("GameStatus", V(0f, 220f), V(548f, 26f), 11f, UiAlignment.Left, text, UiTheme.Orange);
			b.ActionRow("GameTeam", V(0f, 158f), V(548f, 62f), "TEAM", s.Local.HasTeam ? UiFormat.TeamName(s, s.Local.Team) : "Choose Team", "", UiAction.Navigate(UiPageId.PlayerTeamsLoadout), !s.Local.HasTeam);
			b.ActionRow("GameLoadout", V(0f, 86f), V(548f, 62f), "LOADOUT", (!s.Local.HasTeam) ? "Unavailable until team selected" : (s.Local.HasLoadout ? s.Local.LoadoutName : "Choose Loadout"), "", new UiAction
			{
				Id = UiActionId.OpenLoadoutSelector,
				Page = UiPageId.PlayerField
			}, s.Local.HasTeam && !s.Local.HasLoadout, !s.Local.HasTeam).Enabled = s.Local.HasTeam;
			if (sessionActive)
			{
				b.ActionRow("GameSpawn", V(0f, 14f), V(548f, 62f), "SPAWN", s.SpawnSelectionStatus, "", UiAction.Navigate(UiPageId.PlayerSpawns));
			}
			if (sessionActive && s.Local.HasPendingDeployment)
			{
				b.Text("GamePending", V(0f, -56f), V(548f, 48f), 10.5f, UiAlignment.Left, "CURRENT  " + UiFormat.TeamName(s, s.Local.CurrentTeam) + " / " + s.Local.CurrentLoadoutName + "\nNEXT DEPLOYMENT  " + UiFormat.TeamName(s, s.Local.Team) + " / " + s.Local.LoadoutName, UiTheme.TextDim);
			}
			bool flag2 = s.Local.HasTeam && s.Local.HasLoadout;
			bool flag3 = sessionActive && !flag && !s.Local.LateJoinPending;
			bool flag4 = flag2 && s.Local.CanDeploy && !s.Local.LateJoinCountdownActive;
			string title = (sessionActive ? (flag3 ? "REDEPLOY" : (flag ? "DEPLOY WHEN READY" : "DEPLOY")) : (s.Local.Ready ? "NOT READY" : "READY"));
			UiAction uiAction = UiAction.Of(sessionActive ? UiActionId.Deploy : UiActionId.ToggleReady);
			if (flag3)
			{
				uiAction.Confirm("game_redeploy");
			}
			b.ActionRow("GamePrimary", V(0f, -128f), V(548f, 64f), title, (sessionActive && !flag4) ? s.Local.DeployBlockReason : "", "", uiAction, primary: true, sessionActive ? (!flag4) : (!flag2)).Enabled = (sessionActive ? flag4 : flag2);
			b.Button("GameBrief", V(-138f, -192f), V(264f, 38f), "OBJECTIVES", 11f, UiAction.Navigate(UiPageId.PlayerBrief));
			b.Button("GameSupplies", V(138f, -192f), V(264f, 38f), "SUPPLIES", 11f, UiAction.Navigate(UiPageId.PlayerKitSupplies));
			b.Button("GameOverview", V(-138f, -238f), V(264f, 38f), "GAME OVERVIEW", 11f, UiAction.Navigate(UiPageId.MilsimOverview));
			b.Button("GameVehicles", V(138f, -238f), V(264f, 38f), "VEHICLE REQUEST", 11f, UiAction.Navigate(UiPageId.PlayerVehicleRequest));
			b.FeedbackBar(-286f);
		}

		private static void BuildPlayerBrief(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("OBJECTIVES");
			b.Text("ObjectiveScore", V(0f, 220f), V(548f, 26f), 12f, UiAlignment.Left, UiFormat.SideScore(s), UiTheme.Orange);
			int num = UiPageBuilder.ClampPage(s.View.ObjectivePage, s.Match.Objectives.Count, 5);
			float num2 = 166f;
			foreach (UiObjectiveSnapshot item in s.Match.Objectives.Skip(num * 5).Take(5))
			{
				b.InfoRow("Objective_" + item.Id, V(0f, num2), V(548f, 56f), item.Name, (item.Owner == UiTeam.Unassigned) ? "NEUTRAL" : UiFormat.TeamName(s, item.Owner), item.Contested ? "CONTESTED" : "");
				num2 -= 64f;
			}
			if (s.Match.Objectives.Count == 0)
			{
				b.Text("NoObjectives", V(0f, 40f), V(520f, 42f), 14f, UiAlignment.Center, "NO OBJECTIVES", UiTheme.TextDim);
			}
			b.Pager("Objectives", num, s.Match.Objectives.Count, 5, -206f, UiActionId.SetPageIndex);
		}

		private static void BuildRoster(UiPageBuilder b, UiSnapshot s, bool squadOnly)
		{
			b.PageTitle(squadOnly ? "SQUAD" : "TEAM");
			UiTeam localTeam = (s.Local.HasPendingDeployment ? s.Local.CurrentTeam : s.Local.Team);
			List<UiPlayerSnapshot> list = (from entry in s.Roster
				where entry.Team == localTeam && localTeam != UiTeam.Unassigned
				orderby (entry.Team != localTeam) ? 1 : 0, entry.IsSquadLeader descending
				select entry).ThenBy<UiPlayerSnapshot, string>((UiPlayerSnapshot entry) => entry.Name, StringComparer.OrdinalIgnoreCase).ToList();
			int num = UiPageBuilder.ClampPage(s.View.RosterPage, list.Count, 5);
			List<UiPlayerSnapshot> list2 = list.Skip(num * 5).Take(5).ToList();
			UiTeamSnapshot uiTeamSnapshot = s.Team(localTeam);
			string value = ((uiTeamSnapshot != null) ? uiTeamSnapshot.SquadLeaderName : "");
			string text = ((localTeam == UiTeam.Unassigned) ? (list.Count + " " + UiFormat.Plural(list.Count, "PLAYER", "PLAYERS") + "  •  NO SQUAD") : ("SQUAD LEADER: " + (string.IsNullOrWhiteSpace(value) ? "NOT ASSIGNED" : UiFormat.Short(value, 28))));
			b.Text("RosterSummary", V(0f, 222f), V(548f, 26f), 11f, UiAlignment.Left, "<b>" + text + "</b>", UiTheme.Orange);
			float num2 = 170f;
			for (int num3 = 0; num3 < list2.Count; num3++)
			{
				UiPlayerSnapshot uiPlayerSnapshot = list2[num3];
				string text2 = UiDerive.MemberState(s, uiPlayerSnapshot);
				UiColor uiColor = (UiDerive.MemberHasProblem(s, uiPlayerSnapshot) ? UiTheme.HealthWarn : (uiPlayerSnapshot.IsSquadLeader ? UiTheme.Orange : UiTheme.OutlineGray));
				b.Panel("PlayerRoster_" + num3, V(0f, num2), V(548f, 52f), UiTheme.Coffee, 0.68f);
				b.Rect("PlayerRosterRail_" + num3, V(-270f, num2), V(4f, 38f), uiColor, 0.96f);
				b.Text("PlayerRosterName_" + num3, V(-118f, num2 + 8f), V(270f, 22f), 13f, UiAlignment.Left, "<b>" + UiFormat.Short(uiPlayerSnapshot.Name, 22) + "</b>" + (uiPlayerSnapshot.IsSquadLeader ? "  •  SL" : ""), UiTheme.TextWhite);
				b.Text("PlayerRosterKit_" + num3, V(-118f, num2 - 12f), V(300f, 20f), 11f, UiAlignment.Left, UiFormat.TeamTag(s, uiPlayerSnapshot.Team) + "  •  " + UiFormat.Short(uiPlayerSnapshot.LoadoutName, 22), UiTheme.TextDim);
				b.Text("PlayerRosterState_" + num3, V(198f, num2), V(120f, 24f), 10f, UiAlignment.Right, text2, (UiDerive.MemberHasProblem(s, uiPlayerSnapshot) || uiPlayerSnapshot.IsSquadLeader) ? uiColor : UiTheme.TextDim);
				num2 -= 60f;
			}
			if (list2.Count == 0)
			{
				b.Text("RosterEmpty", V(0f, 40f), V(520f, 54f), 16f, UiAlignment.Center, "NO PLAYERS IN THIS VIEW", UiTheme.TextDim);
			}
			b.Pager("WorkspaceRoster", num, list.Count, 5, -158f, UiActionId.SetPageIndex);
			if (!squadOnly)
			{
				b.Button("TeamVehicleRequest", V(0f, -222f), V(420f, 38f), "VEHICLE REQUEST", 11f, UiAction.Navigate(UiPageId.PlayerVehicleRequest));
			}
		}

		private static void BuildPlayerKitSupplies(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("Loadout & Supplies");
			string text = (s.Local.HasPendingDeployment ? s.Local.CurrentLoadoutName : s.Local.LoadoutName);
			b.Panel("KitIdentity", V(0f, 208f), V(548f, 68f), UiTheme.Coffee, 0.82f);
			b.Text("KitName", V(-74f, 221f), V(390f, 28f), 17f, UiAlignment.Left, "<b>" + UiFormat.Short(string.IsNullOrWhiteSpace(text) ? "NO LOADOUT" : text, 30) + "</b>", UiTheme.TextWhite);
			b.Text("KitFaction", V(-74f, 194f), V(390f, 22f), 10f, UiAlignment.Left, s.Local.HasTeam ? UiFormat.TeamName(s, s.Local.HasPendingDeployment ? s.Local.CurrentTeam : s.Local.Team) : "UNASSIGNED", UiTheme.TextDim);
			b.InfoRow("KitItems", V(0f, 122f), V(548f, 62f), "Issued items", s.Local.ItemPreview, s.Local.LoadoutItemCount + " " + UiFormat.Plural(s.Local.LoadoutItemCount, "ITEM", "ITEMS"));
			string detail = (s.Local.AmmoRuleSet ? ("LIGHT " + UiFormat.Supply(s.Local.AmmoLight) + "  •  MED " + UiFormat.Supply(s.Local.AmmoMedium) + "  •  HEAVY " + UiFormat.Supply(s.Local.AmmoHeavy)) : "INHERITED FROM PACK");
			b.InfoRow("KitAmmo", V(0f, 50f), V(548f, 62f), "Ammunition", detail);
			b.InfoRow("KitMedical", V(0f, -22f), V(548f, 62f), "Medical supplies", s.Local.MedicalSupplyLine);
			b.InfoRow("KitWeight", V(0f, -94f), V(548f, 62f), "Carried weight", UiFormat.Number(s.Local.CarriedMassKg, "0.0") + " kg  •  movement " + UiFormat.Number(s.Local.MovementScalar * 100f, "0") + "%", s.Local.WeightTier.ToUpperInvariant());
			b.Text("KitReadOnly", V(0f, -166f), V(520f, 30f), 10f, UiAlignment.Center, "Change loadout on GAME", UiTheme.TextDim);
		}

		private static void BuildPlayerVehicleRequest(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("Vehicle Request");
			UiTeam team = (s.Local.HasPendingDeployment ? s.Local.CurrentTeam : s.Local.Team);
			List<UiVehicleSnapshot> list = ((team != UiTeam.Unassigned) ? s.AvailableVehicles.Where((UiVehicleSnapshot vehicle) => vehicle.Team == team).ToList() : new List<UiVehicleSnapshot>());
			int num = UiPageBuilder.ClampPage(s.View.VehiclePage, list.Count, 5);
			List<UiVehicleSnapshot> list2 = list.Skip(num * 5).Take(5).ToList();
			UiVehicleRequestSnapshot uiVehicleRequestSnapshot = UiDerive.LocalPendingVehicleRequest(s);
			b.Text("VehicleRequestState", V(0f, 222f), V(548f, 28f), 11f, UiAlignment.Left, (uiVehicleRequestSnapshot == null) ? "SELECT A VEHICLE" : ("PENDING  •  " + UiFormat.Short(uiVehicleRequestSnapshot.VehicleName, 28)), (uiVehicleRequestSnapshot == null) ? UiTheme.TextDim : UiTheme.HealthWarn);
			float num2 = 170f;
			for (int num3 = 0; num3 < list2.Count; num3++)
			{
				UiVehicleSnapshot uiVehicleSnapshot = list2[num3];
				string text = ((uiVehicleSnapshot.MaxSpawns <= 0) ? (uiVehicleSnapshot.ActiveSpawns + "/∞") : (uiVehicleSnapshot.ActiveSpawns + "/" + uiVehicleSnapshot.MaxSpawns));
				b.ActionRow("RequestVehicle_" + num3, V(0f, num2), V(548f, 52f), UiFormat.Literal(uiVehicleSnapshot.Name), uiVehicleSnapshot.VehicleClass + "  •  CREW " + uiVehicleSnapshot.CrewRequirement + "  •  ACTIVE " + text, (uiVehicleSnapshot.TicketCost <= 0) ? "FREE" : (uiVehicleSnapshot.TicketCost + ((uiVehicleSnapshot.TicketCost == 1) ? " LIFE" : " LIVES")), new UiAction
				{
					Id = UiActionId.RequestVehicle,
					Text = uiVehicleSnapshot.Name
				});
				num2 -= 58f;
			}
			if (list2.Count == 0)
			{
				b.Text("VehicleEmpty", V(0f, 40f), V(520f, 70f), 16f, UiAlignment.Center, s.Local.HasTeam ? "NO VEHICLES CONFIGURED FOR YOUR TEAM" : "CHOOSE A TEAM BEFORE REQUESTING A VEHICLE", UiTheme.TextDim);
			}
			b.Pager("PlayerVehicles", num, list.Count, 5, -150f, UiActionId.SetPageIndex);
			b.FeedbackBar(-286f);
		}

		private static void BuildSquadLanding(UiPageBuilder b, UiSnapshot s, bool live)
		{
			b.PageTitle(live ? "Squad Command" : "Squad Assembly");
			UiTeam team = (s.Local.HasPendingDeployment ? s.Local.CurrentTeam : s.Local.Team);
			UiTeamSnapshot uiTeamSnapshot = s.Team(team);
			List<UiPlayerSnapshot> list = UiDerive.LocalSquad(s);
			int count = s.JoinRequests.Count;
			int count2 = s.VehicleRequests.Count;
			int num = list.Count((UiPlayerSnapshot entry) => UiDerive.MemberHasProblem(s, entry));
			_ = uiTeamSnapshot?.Locked ?? false;
			b.Panel("SquadStrip", V(0f, 218f), V(548f, 50f), UiTheme.Coffee, 0.78f);
			b.Text("SquadStripText", V(-34f, 218f), V(430f, 28f), 11f, UiAlignment.Left, UiFormat.TeamTag(s, team) + "  •  " + list.Count + " MEMBERS" + ((live && s.Match.RespawnTokensEnabled && uiTeamSnapshot != null) ? ("  •  " + uiTeamSnapshot.Tokens + " LIVES") : ""), UiTheme.TextWhite);
			b.Text("SquadProblemCount", V(220f, 218f), V(86f, 28f), 10f, UiAlignment.Right, (num > 0) ? (num + " " + UiFormat.Plural(num, "ISSUE", "ISSUES")) : "READY", (num > 0) ? UiTheme.HealthWarn : UiTheme.HealthGood);
			int num2 = count + count2;
			b.ActionRow("SquadDecision", V(0f, 146f), V(548f, 66f), (num2 > 0) ? (num2 + " " + UiFormat.Plural(num2, "decision") + " waiting") : "Command queue clear", count + " JOIN  •  " + count2 + " VEHICLE", (num2 > 0) ? "REVIEW" : "CLEAR", UiAction.Navigate(UiPageId.SquadQueue), num2 > 0);
			List<UiPlayerSnapshot> list2 = list.Where((UiPlayerSnapshot entry) => UiDerive.MemberHasProblem(s, entry)).Take(3).ToList();
			float num3 = 72f;
			for (int num4 = 0; num4 < list2.Count; num4++)
			{
				UiPlayerSnapshot uiPlayerSnapshot = list2[num4];
				b.ActionRow("SquadProblem_" + num4, V(0f, num3), V(548f, 52f), UiFormat.Literal(uiPlayerSnapshot.Name), UiFormat.Short(uiPlayerSnapshot.LoadoutName, 22), UiDerive.MemberState(s, uiPlayerSnapshot), new UiAction
				{
					Id = UiActionId.SelectRosterPlayer,
					PlayerId = uiPlayerSnapshot.PlatformId.ToString(CultureInfo.InvariantCulture),
					Flag = uiPlayerSnapshot.IsLocal,
					Text = uiPlayerSnapshot.Name,
					Page = UiPageId.MilsimPlayerEdit
				}, primary: false, warning: true);
				num3 -= 58f;
			}
			if (list2.Count == 0)
			{
				b.Panel("SquadReady", V(0f, 22f), V(548f, 94f), UiTheme.Coffee, 0.5f);
				b.Text("SquadReadyText", V(0f, 22f), V(510f, 48f), 15f, UiAlignment.Center, "SQUAD READY\nNO PLAYERS NEED HELP", UiTheme.HealthGood);
			}
			b.ActionRow("SquadRosterOpen", V(-138f, -142f), V(264f, 58f), live ? "Squad status" : "Squad roster", "Members and loadouts", "", UiAction.Navigate(UiPageId.SquadRoster));
			b.ActionRow("SquadPolicyOpen", V(138f, -142f), V(264f, 58f), "Team policy", "Capacity and requests", "", UiAction.Navigate(UiPageId.SquadPolicy));
			if (live)
			{
				b.Text("RallyStatus", V(0f, -184f), V(540f, 24f), 12f, UiAlignment.Center, s.Local.RallyStatus, UiTheme.TextDim);
				b.Button("PlaceRally", V(-138f, -222f), V(264f, 46f), "PLACE RALLY", 13f, UiAction.Of(UiActionId.PlaceRally)).Enabled = s.Local.CanPlaceRally;
				b.ConfirmButton("RemoveRally", V(138f, -222f), V(264f, 46f), "REMOVE RALLY", 13f, "remove_rally", UiAction.Of(UiActionId.RemoveRally)).Enabled = s.Local.CanRemoveRally;
			}
			b.FeedbackBar(-286f);
		}

		private static void BuildSquadCommandQueue(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("Command Queue");
			List<UiJoinRequestSnapshot> joinRequests = s.JoinRequests;
			List<UiVehicleRequestSnapshot> vehicleRequests = s.VehicleRequests;
			UiSquadQueueFilter squadQueueFilter = s.View.SquadQueueFilter;
			int itemCount = squadQueueFilter switch
			{
				UiSquadQueueFilter.Vehicle => vehicleRequests.Count, 
				UiSquadQueueFilter.Join => joinRequests.Count, 
				_ => joinRequests.Count + vehicleRequests.Count, 
			};
			b.Button("QueueFilter", V(0f, 222f), V(300f, 38f), "FILTER  •  " + squadQueueFilter.ToString().ToUpperInvariant(), 11f, new UiAction
			{
				Id = UiActionId.SetSquadQueueFilter,
				Number = (int)(squadQueueFilter + 1) % 3
			});
			int num = UiPageBuilder.ClampPage(s.View.SquadQueuePage, itemCount, 4);
			int count = num * 4;
			List<QueueRow> list = new List<QueueRow>();
			if (squadQueueFilter != UiSquadQueueFilter.Vehicle)
			{
				list.AddRange(joinRequests.Select((UiJoinRequestSnapshot request) => new QueueRow
				{
					Join = true,
					Id = request.Id,
					Name = request.RequesterName,
					Detail = "JOIN " + UiFormat.TeamTag(s, request.Team)
				}));
			}
			if (squadQueueFilter != UiSquadQueueFilter.Join)
			{
				list.AddRange(vehicleRequests.Select((UiVehicleRequestSnapshot request) => new QueueRow
				{
					Join = false,
					Id = request.Id,
					Name = request.RequesterName,
					Detail = request.VehicleName
				}));
			}
			List<QueueRow> list2 = list.Skip(count).Take(4).ToList();
			float num2 = 164f;
			for (int num3 = 0; num3 < list2.Count; num3++)
			{
				QueueRow queueRow = list2[num3];
				b.Panel("QueueRow_" + num3, V(0f, num2), V(548f, 72f), UiTheme.Coffee, 0.78f);
				b.Rect("QueueRail_" + num3, V(-270f, num2), V(4f, 56f), UiTheme.HealthWarn, 0.96f);
				b.Text("QueueName_" + num3, V(-130f, num2 + 13f), V(260f, 24f), 13f, UiAlignment.Left, "<b>" + UiFormat.Short(queueRow.Name, 20) + "</b>", UiTheme.TextWhite);
				b.Text("QueueDetail_" + num3, V(-130f, num2 - 13f), V(280f, 22f), 12f, UiAlignment.Left, (queueRow.Join ? "JOIN" : "VEHICLE") + "  •  " + UiFormat.Short(queueRow.Detail, 24), UiTheme.TextDim);
				b.Button("QueueApprove_" + num3, V(136f, num2), V(106f, 40f), "APPROVE", 12f, new UiAction
				{
					Id = (queueRow.Join ? UiActionId.ApproveJoinRequest : UiActionId.ApproveVehicleRequest),
					Number = queueRow.Id
				});
				UiButton uiButton = b.Button("QueueDeny_" + num3, V(230f, num2), V(74f, 40f), "DENY", 12f, new UiAction
				{
					Id = (queueRow.Join ? UiActionId.DenyJoinRequest : UiActionId.DenyVehicleRequest),
					Number = queueRow.Id
				});
				uiButton.Tint = UiTheme.HealthCrit;
				uiButton.TintAlpha = 0.2f;
				num2 -= 80f;
			}
			if (list2.Count == 0)
			{
				b.Text("QueueEmpty", V(0f, 40f), V(520f, 72f), 16f, UiAlignment.Center, "NO COMMAND DECISIONS WAITING", UiTheme.HealthGood);
			}
			b.Pager("SquadQueue", num, itemCount, 4, -174f, UiActionId.SetPageIndex);
			b.FeedbackBar(-286f);
		}

		private static void BuildSquadRoster(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("Squad Status");
			List<UiPlayerSnapshot> list = UiDerive.LocalSquad(s);
			int num = UiPageBuilder.ClampPage(s.View.RosterPage, list.Count, 5);
			List<UiPlayerSnapshot> list2 = list.Skip(num * 5).Take(5).ToList();
			int num2 = list.Count((UiPlayerSnapshot entry) => UiDerive.MemberHasProblem(s, entry));
			b.Text("SquadRosterSummary", V(0f, 222f), V(548f, 28f), 11f, UiAlignment.Left, list.Count + " " + UiFormat.Plural(list.Count, "MEMBER", "MEMBERS") + "  •  " + num2 + " " + UiFormat.Plural(num2, "PLAYER NEEDS SETUP", "PLAYERS NEED SETUP"), (num2 > 0) ? UiTheme.HealthWarn : UiTheme.HealthGood);
			float num3 = 170f;
			for (int num4 = 0; num4 < list2.Count; num4++)
			{
				UiPlayerSnapshot uiPlayerSnapshot = list2[num4];
				b.ActionRow("SquadRoster_" + num4, V(0f, num3), V(548f, 52f), UiFormat.Literal(uiPlayerSnapshot.Name), UiFormat.Short(uiPlayerSnapshot.LoadoutName, 24), UiDerive.MemberState(s, uiPlayerSnapshot), new UiAction
				{
					Id = UiActionId.SelectRosterPlayer,
					PlayerId = uiPlayerSnapshot.PlatformId.ToString(CultureInfo.InvariantCulture),
					Flag = uiPlayerSnapshot.IsLocal,
					Text = uiPlayerSnapshot.Name,
					Page = UiPageId.MilsimPlayerEdit
				}, primary: false, UiDerive.MemberHasProblem(s, uiPlayerSnapshot));
				num3 -= 60f;
			}
			b.Pager("SquadRoster", num, list.Count, 5, -158f, UiActionId.SetPageIndex);
			b.FeedbackBar(-286f);
		}

		private static void BuildSquadPolicy(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("Team Policy");
			UiTeam team = (s.Local.HasPendingDeployment ? s.Local.CurrentTeam : s.Local.Team);
			UiTeamSnapshot uiTeamSnapshot = s.Team(team);
			_ = uiTeamSnapshot?.Locked ?? false;
			List<UiPlayerSnapshot> list = UiDerive.LocalSquad(s);
			int num = uiTeamSnapshot?.MemberLimit ?? 0;
			b.Panel("PolicyState", V(0f, 190f), V(548f, 92f), UiTheme.Coffee, 0.78f);
			b.Text("PolicyName", V(0f, 207f), V(510f, 28f), 17f, UiAlignment.Center, "<b>" + UiFormat.TeamName(s, team) + "</b>", UiTheme.TextWhite);
			b.Text("PolicyCapacity", V(0f, 174f), V(510f, 22f), 10.5f, UiAlignment.Center, list.Count + "/" + ((num <= 0) ? "∞" : num.ToString()) + " MEMBERS  •  DIRECT JOIN", UiTheme.TextDim);
			b.InfoRow("PolicyJoin", V(0f, 72f), V(500f, 68f), "TEAM", "Players choose their team directly");
			int count = s.JoinRequests.Count;
			b.ActionRow("PolicyRequests", V(0f, -76f), V(500f, 62f), "Pending join requests", "Review membership decisions", count.ToString(), new UiAction
			{
				Id = UiActionId.SetSquadQueueFilter,
				Number = 1,
				Flag = true
			}, count > 0);
			b.FeedbackBar(-286f);
		}

		private static void BuildSettings(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("Settings");
			b.ActionRow("SettingsMaster", V(0f, 200f), V(548f, 72f), s.Session.ModEnabled ? "SpectrumB is on" : "SpectrumB is off", s.Session.ModEnabled ? "Turning it off stops Milsim, Medical and Fusion sync" : "Everything else stays locked until this is back on", s.Session.ModEnabled ? "ON" : "OFF", UiAction.Of(UiActionId.ToggleModEnabled), !s.Session.ModEnabled, warning: false, s.Session.ModEnabled);
			b.ActionRow("SettingsGameplay", V(-138f, 108f), V(264f, 62f), "Gameplay", "Movement, recoil, stamina", "", new UiAction
			{
				Id = UiActionId.Navigate,
				Page = UiPageId.SettingsCategory,
				Number = 0
			});
			b.ActionRow("SettingsAudio", V(138f, 108f), V(264f, 62f), "Audio & haptics", "Feedback volume and rumble", "", new UiAction
			{
				Id = UiActionId.Navigate,
				Page = UiPageId.SettingsCategory,
				Number = 1
			});
			b.ActionRow("SettingsInterface", V(-138f, 36f), V(264f, 62f), "Interface", "Cursor, overlays, motion", "", new UiAction
			{
				Id = UiActionId.Navigate,
				Page = UiPageId.SettingsCategory,
				Number = 2
			});
			b.ActionRow("SettingsGeneral", V(138f, 36f), V(264f, 62f), "General", "Medical menu button and diagnostics", "", new UiAction
			{
				Id = UiActionId.Navigate,
				Page = UiPageId.SettingsCategory,
				Number = 3
			});
			b.ActionRow("SettingsLanguage", V(0f, -46f), V(548f, 58f), "Language", UiStrings.Language(s.View.Language).NativeName, "CHANGE", new UiAction
			{
				Id = UiActionId.OpenLanguage,
				Page = UiPageId.Settings
			});
			if (s.Session.DeveloperToolsAvailable)
			{
				b.ActionRow("SettingsDeveloper", V(0f, -114f), V(548f, 58f), "Developer Board", "Simulation and diagnostics", "DEV", UiAction.Navigate(UiPageId.DeveloperBoard), primary: false, warning: true);
			}
			else
			{
				b.InfoRow("SettingsDeveloperLocked", V(0f, -114f), V(548f, 58f), "Developer Board", "Restricted to dev builds and developer accounts", "LOCKED");
			}
			b.FeedbackBar(-286f);
		}

		private static void BuildSettingsCategory(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("Settings");
			b.Text("CategoryHint", V(0f, 222f), V(548f, 26f), 11f, UiAlignment.Left, "CATEGORY DETAIL IS STILL DRAWN BY THE LEGACY BUILDER IN GAME", UiTheme.TextDim);
			b.ActionRow("HandheldFlag", V(0f, 150f), V(548f, 58f), "Handheld Flag", s.HandheldFlag.Status, s.HandheldFlag.Button, s.HandheldFlag.Action);
			b.InfoRow("CategoryToggleSample", V(0f, 84f), V(548f, 58f), "Realistic recoil", "Per-weapon recoil curve", "ON");
			b.InfoRow("CategoryStepperSample", V(0f, 18f), V(548f, 58f), "Recoil strength", "0.85", "STEP");
			b.InfoRow("CategoryCycleSample", V(0f, -48f), V(548f, 58f), "Arms stamina", "Moderate", "CYCLE");
			b.FeedbackBar(-286f);
		}

		private static void BuildNotifications(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("NOTIFICATIONS");
			b.Text("InboxScope", V(0f, 222f), V(548f, 28f), 11f, UiAlignment.Left, "INVITES AND SYSTEM NOTICES", UiTheme.TextDim);
			float num = 154f;
			if (s.Session.HasPendingCloudJoin)
			{
				b.ActionRow("InboxInvite", V(0f, num), V(548f, 76f), UiFormat.Short(s.Session.PendingJoinServerName, 30), "Website lobby invitation", "INVITE", UiAction.None, primary: true);
				num -= 84f;
				b.Button("InboxAccept", V(-88f, num), V(156f, 42f), "ACCEPT", 12f, UiAction.Of(UiActionId.AcceptCloudInvite));
				UiButton uiButton = b.Button("InboxDecline", V(88f, num), V(156f, 42f), "DECLINE", 12f, UiAction.Of(UiActionId.DeclineCloudInvite));
				uiButton.Tint = UiTheme.HealthCrit;
				uiButton.TintAlpha = 0.2f;
				num -= 66f;
			}
			int num2 = (s.Session.HasPendingCloudJoin ? 3 : 5);
			int num3 = UiPageBuilder.ClampPage(s.View.NotificationPage, s.Notifications.Count, num2);
			List<UiNotificationSnapshot> list = s.Notifications.Skip(num3 * num2).Take(num2).ToList();
			for (int i = 0; i < list.Count; i++)
			{
				UiNotificationSnapshot uiNotificationSnapshot = list[i];
				UiColor value = ((uiNotificationSnapshot.Kind == "VEHICLE") ? UiTheme.Orange : ((uiNotificationSnapshot.Kind == "JOIN") ? UiTheme.HealthWarn : UiTheme.OutlineGray));
				if (!uiNotificationSnapshot.Action.IsNone)
				{
					b.ActionRow("InboxNotice_" + i, V(0f, num), V(548f, 60f), uiNotificationSnapshot.Title, uiNotificationSnapshot.Detail, uiNotificationSnapshot.Kind, uiNotificationSnapshot.Action);
				}
				else
				{
					b.InfoRow("InboxNotice_" + i, V(0f, num), V(548f, 60f), uiNotificationSnapshot.Title, uiNotificationSnapshot.Detail, uiNotificationSnapshot.Kind, value);
				}
				num -= 64f;
			}
			b.Pager("Notifications", num3, s.Notifications.Count, num2, -224f, UiActionId.SetPageIndex);
			if (!s.Session.HasPendingCloudJoin && list.Count == 0)
			{
				b.Text("InboxEmpty", V(0f, 40f), V(520f, 60f), 16f, UiAlignment.Center, "NOTHING WAITING", UiTheme.TextDim);
			}
			b.FeedbackBar(-286f);
		}

		private static void BuildMedical(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("Medical");
			b.ActionRow("PatientSelect", V(-150f, 224f), V(214f, 48f), "patient", s.Medical.PatientLabel, "", UiAction.Of(UiActionId.CyclePatient));
			b.ActionRow("OpenQuickMenu", V(150f, 224f), V(214f, 48f), "quick menu", s.Medical.QuickMenuBinding, "OPEN", UiAction.Of(UiActionId.OpenMedicalQuickMenu));
			BuildBodyDiagram(b, s);
			UiDerive.DescribeCondition(s.Medical, out var line, out var accent);
			b.ActionRow("RegionSelect", V(-150f, -96f), V(214f, 54f), "region", SplitPascal(s.Medical.SelectedRegion.ToString()), "", new UiAction
			{
				Id = UiActionId.SelectBodyRegion,
				Number = (int)(s.Medical.SelectedRegion + 1) % 7
			});
			b.InfoRow("MedicalStatus", V(140f, -96f), V(300f, 54f), UiFormat.Strip(line), UiFormat.Number(s.Medical.Overall01 * 100f, "0") + "% INTEGRITY", s.Medical.Bleeding ? "BLEED" : "", accent);
			b.Panel("TreatmentBox", V(0f, -228f), V(556f, 184f), UiTheme.Coffee, 0.38f);
			b.Text("TreatmentBoxLabel", V(0f, -150f), V(500f, 22f), 15f, UiAlignment.Center, "<b>treatments moved to the medical quick menu</b>", UiTheme.Orange);
			string text = string.Join("   |   ", s.Medical.Supplies.Select((UiSupplySnapshot supply) => supply.Label + " <b>" + supply.Display + "</b>").ToArray());
			b.Text("TreatmentBoxHint", V(0f, -198f), V(516f, 70f), 14f, UiAlignment.Center, (text.Length == 0) ? "NO SUPPLY DATA" : text, UiTheme.TextDim);
			b.Text("QuickMenuBinding", V(0f, -284f), V(460f, 48f), 14f, UiAlignment.Center, "open with <b>" + s.Medical.QuickMenuBinding + "</b>", UiTheme.TextDim);
		}

		private static void BuildBodyDiagram(UiPageBuilder b, UiSnapshot s)
		{
			b.Panel("BodyDiagramBg", V(0f, 66f), V(556f, 244f), UiTheme.PanelDark, 0.3f);
			UiBodyRegion[] array = new UiBodyRegion[7]
			{
				UiBodyRegion.Head,
				UiBodyRegion.Chest,
				UiBodyRegion.Abdomen,
				UiBodyRegion.RightArm,
				UiBodyRegion.LeftArm,
				UiBodyRegion.RightLeg,
				UiBodyRegion.LeftLeg
			};
			for (int i = 0; i < array.Length; i++)
			{
				UiBodyRegion uiBodyRegion = array[i];
				GetPartLayout(uiBodyRegion, out var partOffset, out var partSize, out var rot, out var tagPos);
				UiBodyRegionSnapshot uiBodyRegionSnapshot = s.Medical.Region(uiBodyRegion);
				float num = uiBodyRegionSnapshot?.Integrity01 ?? 1f;
				bool flag = uiBodyRegionSnapshot?.Bleeding ?? false;
				UiColor uiColor = ((uiBodyRegionSnapshot == null) ? UiTheme.HealthUnknown : (flag ? UiTheme.HealthBleed : UiDerive.HealthColor(num)));
				UiVector2 pos = BodyFigureCenter + partOffset;
				if (s.Medical.SelectedRegion == uiBodyRegion)
				{
					b.Rect("PartSel_" + uiBodyRegion, pos, partSize + new UiVector2(10f, 10f), UiTheme.Orange, 0.55f, rot);
				}
				b.Rect("Part_" + uiBodyRegion, pos, partSize, uiColor, 0.5f, rot);
				UiButton parent = b.Button("MedTag_" + uiBodyRegion, tagPos, V(132f, 30f), "", 12f, new UiAction
				{
					Id = UiActionId.SelectBodyRegion,
					Number = (int)uiBodyRegion
				});
				b.Text("TagName_" + uiBodyRegion, V(6f, 7f), V(118f, 16f), 12f, UiAlignment.Left, ShortRegion(uiBodyRegion), UiTheme.TextWhite, parent);
				b.Text("TagVal_" + uiBodyRegion, V(-6f, 7f), V(118f, 16f), 12f, UiAlignment.Right, (uiBodyRegionSnapshot == null) ? "--" : UiFormat.Number(num * 100f, "0"), UiTheme.TextDim, parent);
				b.SharpRect("TagTrack_" + uiBodyRegion, V(0f, -8f), V(112f, 7f), new UiColor(0f, 0f, 0f), 0.4f, parent);
				b.Progress("TagFill_" + uiBodyRegion, V(0f, -8f), V(112f, 7f), num, uiColor, parent);
			}
		}

		private static void GetPartLayout(UiBodyRegion region, out UiVector2 partOffset, out UiVector2 partSize, out float rot, out UiVector2 tagPos)
		{
			switch (region)
			{
			case UiBodyRegion.Head:
				partOffset = V(0f, 94f);
				partSize = V(40f, 36f);
				rot = 0f;
				tagPos = V(0f, 180f);
				break;
			case UiBodyRegion.Chest:
				partOffset = V(0f, 50f);
				partSize = V(58f, 50f);
				rot = 0f;
				tagPos = V(-180f, 120f);
				break;
			case UiBodyRegion.Abdomen:
				partOffset = V(0f, 6f);
				partSize = V(48f, 42f);
				rot = 0f;
				tagPos = V(180f, 120f);
				break;
			case UiBodyRegion.RightArm:
				partOffset = V(-45f, 50f);
				partSize = V(17f, 68f);
				rot = -10f;
				tagPos = V(-186f, 58f);
				break;
			case UiBodyRegion.LeftArm:
				partOffset = V(45f, 50f);
				partSize = V(17f, 68f);
				rot = 10f;
				tagPos = V(186f, 58f);
				break;
			case UiBodyRegion.RightLeg:
				partOffset = V(-15f, -58f);
				partSize = V(19f, 82f);
				rot = 0f;
				tagPos = V(-162f, -6f);
				break;
			case UiBodyRegion.LeftLeg:
				partOffset = V(15f, -58f);
				partSize = V(19f, 82f);
				rot = 0f;
				tagPos = V(162f, -6f);
				break;
			default:
				partOffset = UiVector2.Zero;
				partSize = V(20f, 20f);
				rot = 0f;
				tagPos = UiVector2.Zero;
				break;
			}
		}

		private static string ShortRegion(UiBodyRegion region)
		{
			return region switch
			{
				UiBodyRegion.Head => "HEAD", 
				UiBodyRegion.Chest => "CHEST", 
				UiBodyRegion.Abdomen => "ABDOMEN", 
				UiBodyRegion.LeftArm => "L ARM", 
				UiBodyRegion.RightArm => "R ARM", 
				UiBodyRegion.LeftLeg => "L LEG", 
				UiBodyRegion.RightLeg => "R LEG", 
				_ => "?", 
			};
		}

		private static void BuildMap(UiPageBuilder b, UiSnapshot s)
		{
			b.PageTitle("Map & Score");
			UiVector2 uiVector = V(0f, 40f);
			b.Panel("MapBg", uiVector, V(500f, 500f), UiTheme.PanelDark, 0.92f);
			if (s.Map.BackgroundKind == "grid")
			{
				float num = 62.5f;
				for (int i = 1; i < 8; i++)
				{
					float num2 = -250f + (float)i * num;
					b.SharpRect("MapGridV_" + i, uiVector + V(num2, 0f), V(1f, 500f), UiTheme.OutlineGray, 0.35f);
					b.SharpRect("MapGridH_" + i, uiVector + V(0f, num2), V(500f, 1f), UiTheme.OutlineGray, 0.35f);
				}
			}
			b.Rect("MapFrame", uiVector, V(500f, 500f), UiTheme.OutlineGray, 0.9f);
			foreach (UiMapUnitSnapshot unit in s.Map.Units)
			{
				UiVector2 uiVector2 = uiVector + V(unit.Position.X * 500f, unit.Position.Y * 500f);
				UiColor uiColor = ((unit.Kind == UiMapMarkerKind.Explosion) ? UiTheme.HealthCrit : ((unit.Kind == UiMapMarkerKind.Objective) ? UiTheme.Orange : ((unit.Kind == UiMapMarkerKind.Spawn) ? UiTheme.TextDim : ((unit.Team != UiTeam.Unassigned) ? UiTheme.TeamColor(unit.Team) : UiTheme.TextDim))));
				switch (unit.Kind)
				{
				case UiMapMarkerKind.Objective:
					b.Rect("MapObj_" + unit.Label, uiVector2, V(22f, 22f), uiColor, 0.9f, 45f);
					if (unit.Progress01 >= 0f)
					{
						b.Progress("MapObjProgress_" + unit.Label, uiVector2 + V(0f, -20f), V(40f, 5f), unit.Progress01, UiTheme.Orange);
					}
					break;
				case UiMapMarkerKind.Spawn:
					b.Rect("MapSpawn_" + unit.Label, uiVector2, V(16f, 16f), uiColor, 0.75f);
					break;
				case UiMapMarkerKind.Vehicle:
					b.Rect("MapVeh_" + unit.Label, uiVector2, V(20f, 12f), uiColor, 0.9f, unit.HeadingDegrees);
					break;
				case UiMapMarkerKind.Explosion:
					b.Rect("MapBoom_" + unit.Label, uiVector2, V(26f, 26f), uiColor, 0.55f, 45f);
					break;
				case UiMapMarkerKind.Wounded:
					b.SharpRect("MapWoundH_" + unit.Label, uiVector2, V(18f, 5f), UiTheme.HealthCrit, 1f);
					b.SharpRect("MapWoundV_" + unit.Label, uiVector2, V(5f, 18f), UiTheme.HealthCrit, 1f);
					break;
				default:
					if (s.Map.VisionConesEnabled && !unit.Wounded)
					{
						b.Rect("MapCone_" + unit.Label, uiVector2, V(10f, 34f), uiColor, 0.16f, unit.HeadingDegrees);
					}
					b.Rect("MapUnit_" + unit.Label, uiVector2, V(unit.IsLocal ? 16f : 12f, unit.IsLocal ? 16f : 12f), unit.IsLocal ? UiTheme.Orange : uiColor, 0.95f);
					break;
				}
				if (!string.IsNullOrEmpty(unit.Label) && unit.Kind != UiMapMarkerKind.Player)
				{
					b.Text("MapLabel_" + unit.Label, uiVector2 + V(0f, 18f), V(90f, 16f), 8.5f, UiAlignment.Center, unit.Label.ToUpperInvariant(), UiTheme.TextDim);
				}
			}
			b.Text("MapLevel", V(0f, 288f), V(548f, 24f), 10.5f, UiAlignment.Left, "LEVEL  •  " + UiFormat.Short(s.Map.LevelName, 40), UiTheme.TextDim);
			List<UiTeamSnapsho