Decompiled source of LethalCasinoTracker v1.1.0

LethalCasinoTracker.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalCasinoTracker.Patches;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace LethalCasinoTracker
{
	public enum CasinoGameType
	{
		Unknown,
		Blackjack,
		Roulette,
		Slots,
		Wheel
	}
	public static class CasinoGameNames
	{
		public static string Display(CasinoGameType t)
		{
			return t switch
			{
				CasinoGameType.Blackjack => "Blackjack", 
				CasinoGameType.Roulette => "Roulette", 
				CasinoGameType.Slots => "Slots", 
				CasinoGameType.Wheel => "The Wheel", 
				_ => "Casino", 
			};
		}

		public static CasinoGameType FromTypeName(string typeName)
		{
			return typeName switch
			{
				"Blackjack" => CasinoGameType.Blackjack, 
				"Roulette" => CasinoGameType.Roulette, 
				"SlotMachine" => CasinoGameType.Slots, 
				"TheWheel" => CasinoGameType.Wheel, 
				_ => CasinoGameType.Unknown, 
			};
		}
	}
	public static class CasinoHooks
	{
		public struct ScrapCapture
		{
			public bool valid;

			public GrabbableObject grab;

			public int before;
		}

		public static readonly string[] GameTypeNames = new string[4] { "Blackjack", "Roulette", "SlotMachine", "TheWheel" };

		private static readonly Dictionary<string, FieldInfo> _fieldCache = new Dictionary<string, FieldInfo>();

		private static readonly Dictionary<GrabbableObject, int> _lastValue = new Dictionary<GrabbableObject, int>();

		public static void ResetValueTracking()
		{
			_lastValue.Clear();
		}

		public static void ScrapPrefix(NetworkBehaviourReference item, out ScrapCapture __state)
		{
			__state = default(ScrapCapture);
			try
			{
				GrabbableObject val = default(GrabbableObject);
				if (((NetworkBehaviourReference)(ref item)).TryGet<GrabbableObject>(ref val, (NetworkManager)null) && (Object)(object)val != (Object)null)
				{
					__state.valid = true;
					__state.grab = val;
					__state.before = val.scrapValue;
				}
			}
			catch
			{
			}
		}

		public static void ScrapPostfix(object __instance, int newValue, ScrapCapture __state)
		{
			if (!__state.valid || (Object)(object)__state.grab == (Object)null || !TrackerManager.IsServer())
			{
				return;
			}
			try
			{
				GrabbableObject grab = __state.grab;
				int scrapValue = grab.scrapValue;
				if (!_lastValue.TryGetValue(grab, out var value))
				{
					value = __state.before;
				}
				int num = scrapValue - value;
				_lastValue[grab] = scrapValue;
				string name = __instance.GetType().Name;
				if (Plugin.VerboseLogging)
				{
					Plugin.Log.LogInfo((object)("[bet] " + name + " baseline=" + value + " after=" + scrapValue + " newArg=" + newValue + " orig=" + ReadOriginal(grab) + " delta=" + num));
				}
				if (num == 0)
				{
					return;
				}
				CasinoGameType game = CasinoGameNames.FromTypeName(name);
				PlayerControllerB val = ResolveOwner(__instance, name, grab);
				if ((Object)(object)val == (Object)null)
				{
					if (Plugin.VerboseLogging)
					{
						Plugin.Log.LogWarning((object)("Could not resolve owner for a " + name + " payout of " + num));
					}
					return;
				}
				int num2 = 0;
				Object val2 = (Object)((__instance is Object) ? __instance : null);
				if (val2 != (Object)null)
				{
					num2 = val2.GetInstanceID();
				}
				ulong playerClientId = val.playerClientId;
				string playerUsername = val.playerUsername;
				if ((Object)(object)TrackerManager.Instance != (Object)null)
				{
					TrackerManager.Instance.RecordResolution(playerClientId, playerUsername, num, game, num2);
				}
				NetworkSync.BroadcastDelta(playerClientId, playerUsername, num, game, num2);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Casino capture error: " + ex.Message));
			}
		}

		private static PlayerControllerB ResolveOwner(object inst, string typeName, GrabbableObject grab)
		{
			Type type = inst.GetType();
			switch (typeName)
			{
			case "Blackjack":
			{
				List<GrabbableObject>[] array = GetField(type, "gambledScrap").GetValue(inst) as List<GrabbableObject>[];
				PlayerControllerB[] array2 = GetField(type, "gamblingPlayers").GetValue(inst) as PlayerControllerB[];
				if (array == null || array2 == null)
				{
					return null;
				}
				int num = Math.Min(array.Length, array2.Length);
				for (int i = 0; i < num; i++)
				{
					if (array[i] != null && array[i].Contains(grab))
					{
						return array2[i];
					}
				}
				return null;
			}
			case "Roulette":
			{
				if (GetField(type, "gambledScrapOwners").GetValue(inst) is Dictionary<GrabbableObject, PlayerControllerB> dictionary && dictionary.TryGetValue(grab, out var value2))
				{
					return value2;
				}
				return null;
			}
			case "SlotMachine":
			case "TheWheel":
			{
				FieldInfo field = GetField(type, "gamblingPlayer");
				if (!(field == null))
				{
					object? value = field.GetValue(inst);
					return (PlayerControllerB)((value is PlayerControllerB) ? value : null);
				}
				return null;
			}
			default:
				return null;
			}
		}

		private static int ReadOriginal(GrabbableObject grab)
		{
			try
			{
				Type type = AccessTools.TypeByName("LethalCasino.Custom.CustomScrapController");
				if (type == null)
				{
					return -1;
				}
				Component component = ((Component)grab).GetComponent(type);
				if ((Object)(object)component == (Object)null)
				{
					return -1;
				}
				FieldInfo field = GetField(type, "originalScrapValue");
				if (field == null)
				{
					return -1;
				}
				object value = field.GetValue(component);
				return (value is int) ? ((int)value) : (-1);
			}
			catch
			{
				return -1;
			}
		}

		private static FieldInfo GetField(Type t, string name)
		{
			string key = t.FullName + "." + name;
			if (!_fieldCache.TryGetValue(key, out var value))
			{
				value = AccessTools.Field(t, name);
				_fieldCache[key] = value;
			}
			return value;
		}

		public static void ApplyPatches(Harmony h)
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			//IL_00bb: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(CasinoHooks), "ScrapPrefix", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(CasinoHooks), "ScrapPostfix", (Type[])null, (Type[])null);
			for (int i = 0; i < GameTypeNames.Length; i++)
			{
				string text = "LethalCasino.Custom." + GameTypeNames[i];
				Type type = AccessTools.TypeByName(text);
				if (type == null)
				{
					Plugin.Log.LogWarning((object)("Casino type not found: " + text));
					continue;
				}
				MethodInfo methodInfo3 = AccessTools.Method(type, "UpdateScrapValueClientRpc", (Type[])null, (Type[])null);
				if (methodInfo3 == null)
				{
					Plugin.Log.LogWarning((object)("UpdateScrapValueClientRpc not found on " + text));
					continue;
				}
				try
				{
					h.Patch((MethodBase)methodInfo3, new HarmonyMethod(methodInfo), new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Plugin.Log.LogInfo((object)("Patched " + GameTypeNames[i] + ".UpdateScrapValueClientRpc"));
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("Failed to patch " + text + ": " + ex.Message));
				}
			}
		}
	}
	public class ChalkboardController : MonoBehaviour
	{
		private Type _buildingType;

		private Component _building;

		private float _nextSearch;

		private GameObject _board;

		private TextMeshProUGUI _text;

		private bool _dirty = true;

		private void Start()
		{
			_buildingType = AccessTools.TypeByName("LethalCasino.Custom.CasinoBuilding");
			if (_buildingType == null)
			{
				Plugin.Log.LogWarning((object)"CasinoBuilding type not found; chalkboard disabled.");
			}
		}

		private void Update()
		{
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ChalkboardEnabled() || _buildingType == null)
			{
				return;
			}
			if ((Object)(object)_building == (Object)null && Time.realtimeSinceStartup >= _nextSearch)
			{
				_nextSearch = Time.realtimeSinceStartup + 1.5f;
				ref Component building = ref _building;
				Object obj = Object.FindObjectOfType(_buildingType);
				building = (Component)(object)((obj is Component) ? obj : null);
				if ((Object)(object)_building != (Object)null && (Object)(object)_board == (Object)null)
				{
					BuildBoard();
				}
			}
			if ((Object)(object)_building == (Object)null)
			{
				if ((Object)(object)_board != (Object)null)
				{
					Object.Destroy((Object)(object)_board);
					_board = null;
				}
			}
			else if (!((Object)(object)_board == (Object)null))
			{
				Transform transform = _building.transform;
				_board.transform.position = transform.position + transform.right * Plugin.ChalkOffsetX() + Vector3.up * Plugin.ChalkOffsetY() + transform.forward * Plugin.ChalkOffsetZ();
				Vector3 forward = transform.forward;
				forward.y = 0f;
				if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f)
				{
					forward = Vector3.forward;
				}
				_board.transform.rotation = Quaternion.AngleAxis(Plugin.ChalkYaw(), Vector3.up) * Quaternion.LookRotation(((Vector3)(ref forward)).normalized, Vector3.up);
				TrackerManager instance = TrackerManager.Instance;
				if ((Object)(object)instance != (Object)null && (instance.RecordsDirty || _dirty))
				{
					RefreshText(instance);
					instance.RecordsDirty = false;
					_dirty = false;
				}
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_board != (Object)null)
			{
				Object.Destroy((Object)(object)_board);
			}
		}

		private void BuildBoard()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			_board = new GameObject("LCCasinoChalkboard");
			_board.transform.localScale = Vector3.one * Plugin.ChalkScale();
			Canvas val = _board.AddComponent<Canvas>();
			val.renderMode = (RenderMode)2;
			RectTransform component = ((Component)val).GetComponent<RectTransform>();
			component.sizeDelta = new Vector2(520f, 360f);
			Image val2 = LCStyle.Panel(_board.transform, new Color(0.05f, 0.08f, 0.06f, 0.96f));
			LCStyle.Stretch(((Graphic)val2).rectTransform, 0f, 0f);
			Image val3 = LCStyle.Panel(((Component)val2).transform, new Color(0.4f, 0.52f, 0.36f, 0.5f));
			RectTransform rectTransform = ((Graphic)val3).rectTransform;
			rectTransform.anchorMin = new Vector2(0f, 1f);
			rectTransform.anchorMax = new Vector2(1f, 1f);
			rectTransform.pivot = new Vector2(0.5f, 1f);
			rectTransform.sizeDelta = new Vector2(0f, 3f);
			rectTransform.anchoredPosition = Vector2.zero;
			_text = LCStyle.Text(_board.transform, "Text", 22f, (TextAlignmentOptions)257, nativeGlow: false);
			((Graphic)_text).color = new Color(0.88f, 0.93f, 0.83f);
			LCStyle.Stretch(((TMP_Text)_text).rectTransform, 26f, 22f);
			_dirty = true;
			ManualLogSource log = Plugin.Log;
			Vector3 position = _building.transform.position;
			log.LogInfo((object)("Chalkboard spawned at casino " + ((Vector3)(ref position)).ToString("F1")));
		}

		private void RefreshText(TrackerManager tm)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_text == (Object)null))
			{
				List<PlayerRunRecord> recordsSorted = tm.GetRecordsSorted();
				string value = LCStyle.Tag("------------------------------", LCStyle.Rule);
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.Append(LCStyle.Tag("ALL-TIME CASINO RECORDS", LCStyle.Header)).Append('\n');
				stringBuilder.Append(value).Append('\n');
				Color c = default(Color);
				((Color)(ref c))..ctor(0.88f, 0.93f, 0.83f);
				FindExtremes(recordsSorted, out var biggestWin, out var biggestLoss);
				stringBuilder.Append(LCStyle.Tag("BIGGEST WIN", LCStyle.Dim)).Append("<pos=38%>");
				if (biggestWin != null && biggestWin.biggestSingleWin > 0)
				{
					stringBuilder.Append(LCStyle.Tag(Trunc(biggestWin.username, 11), c)).Append("<pos=70%>").Append(LCStyle.Tag("+" + biggestWin.biggestSingleWin.ToString("N0"), LCStyle.Up));
				}
				else
				{
					stringBuilder.Append(LCStyle.Tag("-", LCStyle.Dim));
				}
				stringBuilder.Append('\n');
				stringBuilder.Append(LCStyle.Tag("BIGGEST LOSS", LCStyle.Dim)).Append("<pos=38%>");
				if (biggestLoss != null && biggestLoss.biggestSingleLoss > 0)
				{
					stringBuilder.Append(LCStyle.Tag(Trunc(biggestLoss.username, 11), c)).Append("<pos=70%>").Append(LCStyle.Tag("-" + biggestLoss.biggestSingleLoss.ToString("N0"), LCStyle.Down));
				}
				else
				{
					stringBuilder.Append(LCStyle.Tag("-", LCStyle.Dim));
				}
				stringBuilder.Append('\n');
				stringBuilder.Append(value).Append('\n');
				stringBuilder.Append(LCStyle.Tag("TOTAL GAMES", LCStyle.Dim)).Append("<pos=38%>").Append(tm.TotalGames());
				((TMP_Text)_text).text = stringBuilder.ToString();
			}
		}

		private static void FindExtremes(List<PlayerRunRecord> recs, out PlayerRunRecord biggestWin, out PlayerRunRecord biggestLoss)
		{
			biggestWin = null;
			biggestLoss = null;
			for (int i = 0; i < recs.Count; i++)
			{
				PlayerRunRecord playerRunRecord = recs[i];
				if (biggestWin == null || playerRunRecord.biggestSingleWin > biggestWin.biggestSingleWin)
				{
					biggestWin = playerRunRecord;
				}
				if (biggestLoss == null || playerRunRecord.biggestSingleLoss > biggestLoss.biggestSingleLoss)
				{
					biggestLoss = playerRunRecord;
				}
			}
		}

		private static string Trunc(string s, int max)
		{
			if (string.IsNullOrEmpty(s))
			{
				return "";
			}
			if (s.Length > max)
			{
				return s.Substring(0, max);
			}
			return s;
		}
	}
	public class HUDController : MonoBehaviour
	{
		private GameObject _root;

		private RectTransform _panel;

		private RawImage _scan;

		private TextMeshProUGUI _text;

		private bool _built;

		private void Build()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			if (LCStyle.Ready)
			{
				Canvas val = LCStyle.OverlayCanvas("LCCT_HUD", 800);
				_root = ((Component)val).gameObject;
				Image val2 = LCStyle.SoftPanel(_root.transform, new Color(0.02f, 0.04f, 0.03f, 0.5f));
				_panel = ((Graphic)val2).rectTransform;
				_panel.anchorMin = new Vector2(1f, 1f);
				_panel.anchorMax = new Vector2(1f, 1f);
				_panel.pivot = new Vector2(1f, 1f);
				_scan = LCStyle.Scanlines(((Component)val2).transform, new Color(0f, 0f, 0f, 0.18f));
				LCStyle.Stretch(((Graphic)_scan).rectTransform, 3f, 3f);
				_text = LCStyle.Text(((Component)val2).transform, "Text", Plugin.HudFontSize(), (TextAlignmentOptions)257, nativeGlow: true);
				LCStyle.Stretch(((TMP_Text)_text).rectTransform, 16f, 12f);
				_built = true;
			}
		}

		private void Update()
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			if (!_built)
			{
				Build();
				if (!_built)
				{
					return;
				}
			}
			TrackerManager instance = TrackerManager.Instance;
			StartOfRound instance2 = StartOfRound.Instance;
			bool flag = Plugin.HudEnabled() && (Object)(object)instance != (Object)null && (Object)(object)instance2 != (Object)null && instance2.shipHasLanded && !instance2.shipIsLeaving && IsGordion(instance2);
			if (_root.activeSelf != flag)
			{
				_root.SetActive(flag);
			}
			if (flag)
			{
				List<PlayerControllerB> crew = GetCrew(instance2);
				float num = (float)Plugin.HudFontSize() * 1.34f;
				float num2 = (float)(crew.Count + 4) * num + 22f;
				_panel.sizeDelta = new Vector2((float)Plugin.HudWidth(), num2);
				_panel.anchoredPosition = new Vector2((float)(-Plugin.HudMarginX()), (float)(-Plugin.HudMarginY()));
				if ((Object)(object)_scan != (Object)null)
				{
					_scan.uvRect = new Rect(0f, 0f, 1f, num2 / 3f);
				}
				((TMP_Text)_text).text = BuildText(instance, crew);
			}
		}

		private static string BuildText(TrackerManager tm, List<PlayerControllerB> crew)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			string value = LCStyle.Tag("------------------------", LCStyle.Rule);
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(LCStyle.Tag("SESSION", LCStyle.Header)).Append('\n');
			stringBuilder.Append(value).Append('\n');
			for (int i = 0; i < crew.Count; i++)
			{
				PlayerControllerB val = crew[i];
				string s = (string.IsNullOrEmpty(val.playerUsername) ? ("Player " + val.playerClientId) : val.playerUsername);
				stringBuilder.Append(LCStyle.Tag(Trunc(s, 12), LCStyle.Ink));
				if (tm.TryGetSessionDelta(val.playerClientId, out var delta) && delta != 0)
				{
					Color c = ((delta > 0) ? LCStyle.Up : LCStyle.Down);
					stringBuilder.Append("<pos=60%>").Append(LCStyle.Tag(LCStyle.Signed(delta), c));
				}
				stringBuilder.Append('\n');
			}
			stringBuilder.Append(value).Append('\n');
			int num = tm.CrewNet();
			Color c2 = ((num > 0) ? LCStyle.Up : ((num < 0) ? LCStyle.Down : LCStyle.Ink));
			stringBuilder.Append(LCStyle.Tag("CREW", LCStyle.Dim)).Append("<pos=60%>").Append(LCStyle.Tag((num == 0) ? "0" : LCStyle.Signed(num), c2));
			return stringBuilder.ToString();
		}

		private static bool IsGordion(StartOfRound sor)
		{
			SelectableLevel currentLevel = sor.currentLevel;
			if ((Object)(object)currentLevel == (Object)null || string.IsNullOrEmpty(currentLevel.PlanetName))
			{
				return false;
			}
			return currentLevel.PlanetName.IndexOf("Gordion", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static List<PlayerControllerB> GetCrew(StartOfRound sor)
		{
			List<PlayerControllerB> list = new List<PlayerControllerB>();
			PlayerControllerB[] allPlayerScripts = sor.allPlayerScripts;
			if (allPlayerScripts == null)
			{
				return list;
			}
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!((Object)(object)val == (Object)null) && (val.isPlayerControlled || val.isPlayerDead))
				{
					list.Add(val);
				}
			}
			return list;
		}

		private static string Trunc(string s, int max)
		{
			if (string.IsNullOrEmpty(s))
			{
				return "";
			}
			if (s.Length > max)
			{
				return s.Substring(0, max);
			}
			return s;
		}

		private void OnDestroy()
		{
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
		}
	}
	public static class LCStyle
	{
		public static readonly Color Ink = new Color(0.74f, 0.85f, 0.7f);

		public static readonly Color Dim = new Color(0.46f, 0.55f, 0.44f);

		public static readonly Color Up = new Color(0.56f, 0.96f, 0.52f);

		public static readonly Color Down = new Color(0.95f, 0.46f, 0.36f);

		public static readonly Color Header = new Color(0.72f, 0.88f, 0.6f);

		public static readonly Color Rule = new Color(0.55f, 0.66f, 0.45f, 0.5f);

		private static TMP_FontAsset _font;

		private static Material _mat;

		private static Sprite _softPanel;

		private static Texture2D _scan;

		private static Sprite _outline;

		public static bool Ready
		{
			get
			{
				EnsureRef();
				if ((Object)(object)_font != (Object)null)
				{
					return (Object)(object)_mat != (Object)null;
				}
				return false;
			}
		}

		public static string Hex(Color c)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return ColorUtility.ToHtmlStringRGB(c);
		}

		public static string Tag(string s, Color c)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return "<color=#" + Hex(c) + ">" + s + "</color>";
		}

		public static string Signed(int v)
		{
			return ((v > 0) ? "+" : "") + v.ToString("N0");
		}

		private static void EnsureRef()
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_font != (Object)null && (Object)(object)_mat != (Object)null)
			{
				return;
			}
			try
			{
				HUDManager instance = HUDManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return;
				}
				TextMeshProUGUI val = null;
				if ((Object)(object)instance.weightCounter != (Object)null)
				{
					val = instance.weightCounter;
				}
				else if (instance.controlTipLines != null && instance.controlTipLines.Length > 0)
				{
					val = instance.controlTipLines[0];
				}
				else if ((Object)(object)instance.clockNumber != (Object)null)
				{
					val = instance.clockNumber;
				}
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				if ((Object)(object)((TMP_Text)val).font != (Object)null)
				{
					_font = ((TMP_Text)val).font;
				}
				if (!((Object)(object)((TMP_Text)val).fontSharedMaterial != (Object)null))
				{
					return;
				}
				_mat = new Material(((TMP_Text)val).fontSharedMaterial);
				try
				{
					_mat.SetColor("_FaceColor", Color.white);
					_mat.EnableKeyword("GLOW_ON");
					_mat.SetColor("_GlowColor", new Color(0.4f, 1f, 0.55f, 1f));
					_mat.SetFloat("_GlowPower", 0.35f);
					_mat.SetFloat("_GlowOuter", 0.45f);
					_mat.SetFloat("_GlowInner", 0.05f);
					_mat.EnableKeyword("OUTLINE_ON");
					_mat.SetColor("_OutlineColor", new Color(0f, 0.08f, 0.03f, 1f));
					_mat.SetFloat("_OutlineWidth", 0.18f);
				}
				catch
				{
				}
			}
			catch
			{
			}
		}

		public static TMP_FontAsset Font()
		{
			EnsureRef();
			if ((Object)(object)_font == (Object)null)
			{
				try
				{
					_font = TMP_Settings.defaultFontAsset;
				}
				catch
				{
				}
			}
			return _font;
		}

		public static Canvas OverlayCanvas(string name, int sortingOrder)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			Object.DontDestroyOnLoad((Object)(object)val);
			Canvas val2 = val.AddComponent<Canvas>();
			val2.renderMode = (RenderMode)0;
			val2.sortingOrder = sortingOrder;
			CanvasScaler val3 = val.AddComponent<CanvasScaler>();
			val3.uiScaleMode = (ScaleMode)1;
			val3.referenceResolution = new Vector2(1920f, 1080f);
			val3.screenMatchMode = (ScreenMatchMode)0;
			val3.matchWidthOrHeight = 0.5f;
			return val2;
		}

		public static Image Panel(Transform parent, Color color)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Panel");
			val.transform.SetParent(parent, false);
			Image val2 = val.AddComponent<Image>();
			((Graphic)val2).color = color;
			((Graphic)val2).raycastTarget = false;
			return val2;
		}

		public static Image SoftPanel(Transform parent, Color color)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Panel");
			val.transform.SetParent(parent, false);
			Image val2 = val.AddComponent<Image>();
			val2.sprite = SoftSprite();
			val2.type = (Type)1;
			((Graphic)val2).color = color;
			((Graphic)val2).raycastTarget = false;
			return val2;
		}

		public static Image Box(Transform parent, Color color)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Box");
			val.transform.SetParent(parent, false);
			Image val2 = val.AddComponent<Image>();
			val2.sprite = OutlineSprite();
			val2.type = (Type)1;
			((Graphic)val2).color = color;
			((Graphic)val2).raycastTarget = false;
			return val2;
		}

		private static Sprite OutlineSprite()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_outline != (Object)null)
			{
				return _outline;
			}
			int num = 16;
			int num2 = 4;
			int num3 = 2;
			Texture2D val = new Texture2D(num, num, (TextureFormat)4, false);
			((Texture)val).wrapMode = (TextureWrapMode)1;
			for (int i = 0; i < num; i++)
			{
				for (int j = 0; j < num; j++)
				{
					bool flag = j < num3 || j >= num - num3 || i < num3 || i >= num - num3;
					val.SetPixel(j, i, new Color(1f, 1f, 1f, flag ? 1f : 0f));
				}
			}
			val.Apply();
			((Object)val).hideFlags = (HideFlags)61;
			_outline = Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4((float)num2, (float)num2, (float)num2, (float)num2));
			return _outline;
		}

		public static RawImage Scanlines(Transform parent, Color color)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Scanlines");
			val.transform.SetParent(parent, false);
			RawImage val2 = val.AddComponent<RawImage>();
			val2.texture = (Texture)(object)ScanTex();
			((Graphic)val2).color = color;
			((Graphic)val2).raycastTarget = false;
			return val2;
		}

		public static TextMeshProUGUI Text(Transform parent, string name, float size, TextAlignmentOptions align, bool nativeGlow)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val2).font = Font();
			if (nativeGlow && (Object)(object)_mat != (Object)null)
			{
				((TMP_Text)val2).fontSharedMaterial = _mat;
			}
			((TMP_Text)val2).fontSize = size;
			((Graphic)val2).color = Ink;
			((TMP_Text)val2).alignment = align;
			((TMP_Text)val2).richText = true;
			((TMP_Text)val2).enableWordWrapping = false;
			((TMP_Text)val2).overflowMode = (TextOverflowModes)0;
			((Graphic)val2).raycastTarget = false;
			return val2;
		}

		public static void Stretch(RectTransform rt, float padX, float padY)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			rt.anchorMin = Vector2.zero;
			rt.anchorMax = Vector2.one;
			rt.offsetMin = new Vector2(padX, padY);
			rt.offsetMax = new Vector2(0f - padX, 0f - padY);
		}

		private static Sprite SoftSprite()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_softPanel != (Object)null)
			{
				return _softPanel;
			}
			int num = 32;
			int num2 = 12;
			Texture2D val = new Texture2D(num, num, (TextureFormat)4, false);
			((Texture)val).wrapMode = (TextureWrapMode)1;
			for (int i = 0; i < num; i++)
			{
				for (int j = 0; j < num; j++)
				{
					int num3 = Mathf.Min(Mathf.Min(j, num - 1 - j), Mathf.Min(i, num - 1 - i));
					float num4 = Mathf.Clamp01((float)num3 / (float)num2);
					num4 = num4 * num4 * (3f - 2f * num4);
					val.SetPixel(j, i, new Color(1f, 1f, 1f, num4));
				}
			}
			val.Apply();
			((Object)val).hideFlags = (HideFlags)61;
			_softPanel = Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4((float)num2, (float)num2, (float)num2, (float)num2));
			return _softPanel;
		}

		private static Texture2D ScanTex()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_scan != (Object)null)
			{
				return _scan;
			}
			_scan = new Texture2D(1, 3, (TextureFormat)4, false);
			((Texture)_scan).wrapMode = (TextureWrapMode)0;
			((Texture)_scan).filterMode = (FilterMode)0;
			_scan.SetPixel(0, 0, new Color(0f, 0f, 0f, 0f));
			_scan.SetPixel(0, 1, new Color(0f, 0f, 0f, 0f));
			_scan.SetPixel(0, 2, new Color(0f, 0f, 0f, 1f));
			_scan.Apply();
			((Object)_scan).hideFlags = (HideFlags)61;
			return _scan;
		}
	}
	[Serializable]
	public class DeltaMsg
	{
		public long id;

		public int delta;

		public int game;

		public int inst;

		public string name = "";
	}
	public static class NetworkSync
	{
		private const string MsgDelta = "LCCT_Delta";

		private const string MsgRequest = "LCCT_Req";

		private const string MsgState = "LCCT_State";

		private static bool _registered;

		private static NetworkManager _registeredOn;

		private static bool _requested;

		public static void Tick()
		{
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if ((Object)(object)singleton == (Object)null || !singleton.IsListening)
				{
					_registered = false;
					_registeredOn = null;
					_requested = false;
					return;
				}
				if (!_registered || (Object)(object)_registeredOn != (Object)(object)singleton)
				{
					Register(singleton);
				}
				if (!singleton.IsServer && singleton.IsConnectedClient && !_requested)
				{
					Send("LCCT_Req", 0uL, "1");
					_requested = true;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("NetworkSync.Tick: " + ex.Message));
			}
		}

		public static void RequestResync()
		{
			_requested = false;
		}

		private static void Register(NetworkManager nm)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			CustomMessagingManager customMessagingManager = nm.CustomMessagingManager;
			if (customMessagingManager != null)
			{
				customMessagingManager.RegisterNamedMessageHandler("LCCT_Delta", new HandleNamedMessageDelegate(OnDelta));
				customMessagingManager.RegisterNamedMessageHandler("LCCT_Req", new HandleNamedMessageDelegate(OnRequest));
				customMessagingManager.RegisterNamedMessageHandler("LCCT_State", new HandleNamedMessageDelegate(OnState));
				_registered = true;
				_registeredOn = nm;
				Plugin.Log.LogInfo((object)("NetworkSync handlers registered (server=" + nm.IsServer + ")."));
			}
		}

		public static void BroadcastDelta(ulong id, string username, int delta, CasinoGameType game, int instId)
		{
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if ((Object)(object)singleton == (Object)null || !singleton.IsServer || singleton.CustomMessagingManager == null)
				{
					return;
				}
				DeltaMsg deltaMsg = new DeltaMsg();
				deltaMsg.id = (long)id;
				deltaMsg.delta = delta;
				deltaMsg.game = (int)game;
				deltaMsg.inst = instId;
				deltaMsg.name = ((username == null) ? "" : username);
				string payload = JsonUtility.ToJson((object)deltaMsg);
				foreach (ulong connectedClientsId in singleton.ConnectedClientsIds)
				{
					if (connectedClientsId != 0)
					{
						Send("LCCT_Delta", connectedClientsId, payload);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("BroadcastDelta: " + ex.Message));
			}
		}

		private static void Send(string msg, ulong clientId, string payload)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(Encoding.UTF8.GetByteCount(payload) + 64, (Allocator)2, 524288);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe(payload, false);
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(msg, clientId, val, (NetworkDelivery)2);
			}
			finally
			{
				((FastBufferWriter)(ref val)).Dispose();
			}
		}

		private static void OnDelta(ulong sender, FastBufferReader reader)
		{
			try
			{
				if (!TrackerManager.IsServer())
				{
					string text = default(string);
					((FastBufferReader)(ref reader)).ReadValueSafe(ref text, false);
					DeltaMsg deltaMsg = JsonUtility.FromJson<DeltaMsg>(text);
					if (deltaMsg != null && (Object)(object)TrackerManager.Instance != (Object)null)
					{
						TrackerManager.Instance.RecordResolution((ulong)deltaMsg.id, deltaMsg.name, deltaMsg.delta, (CasinoGameType)deltaMsg.game, deltaMsg.inst);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("OnDelta: " + ex.Message));
			}
		}

		private static void OnRequest(ulong sender, FastBufferReader reader)
		{
			try
			{
				if (TrackerManager.IsServer() && !((Object)(object)TrackerManager.Instance == (Object)null))
				{
					SyncBlob syncBlob = TrackerManager.Instance.BuildSyncBlob();
					Send("LCCT_State", sender, JsonUtility.ToJson((object)syncBlob));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("OnRequest: " + ex.Message));
			}
		}

		private static void OnState(ulong sender, FastBufferReader reader)
		{
			try
			{
				if (!TrackerManager.IsServer())
				{
					string text = default(string);
					((FastBufferReader)(ref reader)).ReadValueSafe(ref text, false);
					SyncBlob b = JsonUtility.FromJson<SyncBlob>(text);
					if ((Object)(object)TrackerManager.Instance != (Object)null)
					{
						TrackerManager.Instance.ApplySyncBlob(b);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("OnState: " + ex.Message));
			}
		}
	}
	[Serializable]
	public class PlayerRunRecord
	{
		public long clientId;

		public string username = "";

		public int totalWon;

		public int totalLost;

		public int biggestSingleWin;

		public int biggestSingleLoss;

		public string biggestWinGame = "";

		public string biggestLossGame = "";

		public int gamesPlayed;

		public int Net => totalWon - totalLost;
	}
	[Serializable]
	public class RunSaveBlob
	{
		public List<PlayerRunRecord> records = new List<PlayerRunRecord>();
	}
	[Serializable]
	public class SessionEntry
	{
		public long clientId;

		public string username = "";

		public int delta;
	}
	[Serializable]
	public class SyncBlob
	{
		public List<PlayerRunRecord> records = new List<PlayerRunRecord>();

		public List<SessionEntry> session = new List<SessionEntry>();
	}
	[BepInPlugin("jaredfreedman.LethalCasinoTracker", "LethalCasinoTracker", "1.1.0")]
	[BepInDependency("mrgrm7.LethalCasino", "1.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "jaredfreedman.LethalCasinoTracker";

		public static ManualLogSource Log;

		public static bool VerboseLogging;

		private static bool _initialized;

		private static ConfigEntry<bool> _verbose;

		private static ConfigEntry<bool> _hudEnabled;

		private static ConfigEntry<int> _hudMarginX;

		private static ConfigEntry<int> _hudMarginY;

		private static ConfigEntry<int> _hudWidth;

		private static ConfigEntry<int> _hudFont;

		private static ConfigEntry<bool> _summaryEnabled;

		private static ConfigEntry<float> _summaryDuration;

		private static ConfigEntry<bool> _sfxEnabled;

		private static ConfigEntry<float> _sfxVolume;

		private static ConfigEntry<bool> _chalkEnabled;

		private static ConfigEntry<float> _chalkX;

		private static ConfigEntry<float> _chalkY;

		private static ConfigEntry<float> _chalkZ;

		private static ConfigEntry<float> _chalkScale;

		private static ConfigEntry<float> _chalkYaw;

		private void Awake()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			BindConfig();
			if (!_initialized)
			{
				_initialized = true;
				try
				{
					Harmony h = new Harmony("jaredfreedman.LethalCasinoTracker");
					GameOverPatch.ApplyPatches(h);
					CasinoHooks.ApplyPatches(h);
				}
				catch (Exception ex)
				{
					Log.LogError((object)("Failed to apply Harmony patches: " + ex.Message));
				}
				((Component)this).gameObject.AddComponent<TrackerManager>();
				((Component)this).gameObject.AddComponent<SummaryScreenController>();
				((Component)this).gameObject.AddComponent<HUDController>();
				((Component)this).gameObject.AddComponent<ChalkboardController>();
				Log.LogInfo((object)"LethalCasinoTracker 1.1.0 loaded.");
			}
		}

		private void BindConfig()
		{
			_verbose = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "VerboseLogging", false, "Log every tracked bet result (debugging).");
			_hudEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "Enabled", true, "Show the top-right session scoreboard while on a moon.");
			_hudMarginX = ((BaseUnityPlugin)this).Config.Bind<int>("HUD", "MarginX", 12, "Distance from the right edge of the screen, in pixels.");
			_hudMarginY = ((BaseUnityPlugin)this).Config.Bind<int>("HUD", "MarginY", 70, "Distance from the top edge of the screen, in pixels.");
			_hudWidth = ((BaseUnityPlugin)this).Config.Bind<int>("HUD", "Width", 270, "Panel width (reference px at 1080p).");
			_hudFont = ((BaseUnityPlugin)this).Config.Bind<int>("HUD", "FontSize", 19, "Font size for HUD rows.");
			_summaryEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Summary", "Enabled", true, "Show the centered session recap on takeoff.");
			_summaryDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Summary", "HoldSeconds", 7f, "How long the recap stays fully visible (matches the vanilla performance report).");
			_sfxEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Summary", "Sound", true, "Play a win/loss jingle with the recap.");
			_sfxVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Summary", "Volume", 0.5f, "Recap jingle volume (0-1).");
			_chalkEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Chalkboard", "Enabled", true, "Spawn the physical casino records board near the casino.");
			_chalkX = ((BaseUnityPlugin)this).Config.Bind<float>("Chalkboard", "OffsetRight", 0f, "Board placement offset along the casino's right axis (m).");
			_chalkY = ((BaseUnityPlugin)this).Config.Bind<float>("Chalkboard", "OffsetUp", 2.6f, "Board placement offset upward from the casino (m).");
			_chalkZ = ((BaseUnityPlugin)this).Config.Bind<float>("Chalkboard", "OffsetForward", 4.5f, "Board placement offset in front of the casino (m).");
			_chalkScale = ((BaseUnityPlugin)this).Config.Bind<float>("Chalkboard", "Scale", 0.0075f, "World scale of the board.");
			_chalkYaw = ((BaseUnityPlugin)this).Config.Bind<float>("Chalkboard", "Yaw", 180f, "Rotate the board to face the right way (degrees: try 0/90/180/270).");
			VerboseLogging = _verbose.Value;
		}

		public static bool HudEnabled()
		{
			if (_hudEnabled != null)
			{
				return _hudEnabled.Value;
			}
			return true;
		}

		public static int HudMarginX()
		{
			if (_hudMarginX != null)
			{
				return _hudMarginX.Value;
			}
			return 12;
		}

		public static int HudMarginY()
		{
			if (_hudMarginY != null)
			{
				return _hudMarginY.Value;
			}
			return 70;
		}

		public static int HudWidth()
		{
			if (_hudWidth != null)
			{
				return _hudWidth.Value;
			}
			return 270;
		}

		public static int HudFontSize()
		{
			if (_hudFont != null)
			{
				return _hudFont.Value;
			}
			return 19;
		}

		public static bool SummaryEnabled()
		{
			if (_summaryEnabled != null)
			{
				return _summaryEnabled.Value;
			}
			return true;
		}

		public static float SummaryDuration()
		{
			if (_summaryDuration != null)
			{
				return _summaryDuration.Value;
			}
			return 7f;
		}

		public static bool SfxEnabled()
		{
			if (_sfxEnabled != null)
			{
				return _sfxEnabled.Value;
			}
			return true;
		}

		public static float SfxVolume()
		{
			if (_sfxVolume != null)
			{
				return _sfxVolume.Value;
			}
			return 0.5f;
		}

		public static bool ChalkboardEnabled()
		{
			if (_chalkEnabled != null)
			{
				return _chalkEnabled.Value;
			}
			return true;
		}

		public static float ChalkOffsetX()
		{
			if (_chalkX != null)
			{
				return _chalkX.Value;
			}
			return 0f;
		}

		public static float ChalkOffsetY()
		{
			if (_chalkY != null)
			{
				return _chalkY.Value;
			}
			return 2.6f;
		}

		public static float ChalkOffsetZ()
		{
			if (_chalkZ != null)
			{
				return _chalkZ.Value;
			}
			return 4.5f;
		}

		public static float ChalkScale()
		{
			if (_chalkScale != null)
			{
				return _chalkScale.Value;
			}
			return 0.0075f;
		}

		public static float ChalkYaw()
		{
			if (_chalkYaw != null)
			{
				return _chalkYaw.Value;
			}
			return 180f;
		}
	}
	public class SummaryScreenController : MonoBehaviour
	{
		private class Row
		{
			public string name;

			public bool has;

			public int delta;
		}

		private const float W = 700f;

		private const float Pad = 26f;

		private const float RowH = 40f;

		private static readonly Color RInk = new Color(0.95f, 0.5f, 0.36f);

		private static readonly Color RHead = new Color(1f, 0.36f, 0.24f);

		private static readonly Color RDim = new Color(0.74f, 0.34f, 0.27f);

		private static readonly Color RBg = new Color(0.11f, 0.015f, 0.015f, 0.94f);

		private static readonly Color RBorder = new Color(0.92f, 0.26f, 0.17f, 0.95f);

		private static readonly Color Up = new Color(0.55f, 0.95f, 0.5f);

		private static readonly Color Down = new Color(1f, 0.42f, 0.35f);

		private GameObject _root;

		private CanvasGroup _group;

		private RectTransform _panel;

		private RectTransform _inner;

		private TextMeshProUGUI _title;

		private TextMeshProUGUI _notes;

		private TextMeshProUGUI _collected;

		private TextMeshProUGUI _grade;

		private readonly List<GameObject> _rowBoxes = new List<GameObject>();

		private bool _built;

		private Coroutine _co;

		private AudioSource _audio;

		private AudioClip _winClip;

		private AudioClip _loseClip;

		private AudioClip _neutralClip;

		public static SummaryScreenController Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			_audio = ((Component)this).gameObject.AddComponent<AudioSource>();
			_audio.playOnAwake = false;
			_audio.spatialBlend = 0f;
			_audio.ignoreListenerPause = true;
			try
			{
				_winClip = MakeJingle("win", new float[4] { 523.25f, 659.25f, 783.99f, 1046.5f }, 0.13f, 0f);
				_loseClip = MakeJingle("lose", new float[4] { 440f, 392f, 349.23f, 293.66f }, 0.2f, -28f);
				_neutralClip = MakeJingle("neutral", new float[1] { 660f }, 0.09f, 0f);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not build recap audio: " + ex.Message));
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
		}

		private static string Tag(string s, Color c)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return "<color=#" + ColorUtility.ToHtmlStringRGB(c) + ">" + s + "</color>";
		}

		private static string Signed(int v)
		{
			return ((v > 0) ? "+" : "") + v.ToString("N0");
		}

		private TextMeshProUGUI Label(string name, float x, float y, float w, float h, float size, TextAlignmentOptions align, Color col)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI val = LCStyle.Text(((Component)_inner).transform, name, size, align, nativeGlow: false);
			RectTransform rectTransform = ((TMP_Text)val).rectTransform;
			rectTransform.anchorMin = new Vector2(0f, 1f);
			rectTransform.anchorMax = new Vector2(0f, 1f);
			rectTransform.pivot = new Vector2(0f, 1f);
			rectTransform.anchoredPosition = new Vector2(x, 0f - y);
			rectTransform.sizeDelta = new Vector2(w, h);
			((Graphic)val).color = col;
			return val;
		}

		private void BuildUI()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			//IL_0417: Unknown result type (might be due to invalid IL or missing references)
			//IL_0438: Unknown result type (might be due to invalid IL or missing references)
			//IL_044e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			//IL_047a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0493: Unknown result type (might be due to invalid IL or missing references)
			//IL_04dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0508: Unknown result type (might be due to invalid IL or missing references)
			//IL_051e: Unknown result type (might be due to invalid IL or missing references)
			//IL_053d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0586: Unknown result type (might be due to invalid IL or missing references)
			//IL_059c: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05de: Unknown result type (might be due to invalid IL or missing references)
			Canvas val = LCStyle.OverlayCanvas("LCCT_Recap", 950);
			_root = ((Component)val).gameObject;
			_group = _root.AddComponent<CanvasGroup>();
			_group.alpha = 0f;
			Image val2 = LCStyle.Panel(_root.transform, new Color(0f, 0f, 0f, 0.6f));
			LCStyle.Stretch(((Graphic)val2).rectTransform, 0f, 0f);
			Image val3 = LCStyle.Panel(_root.transform, RBorder);
			_panel = ((Graphic)val3).rectTransform;
			RectTransform panel = _panel;
			Vector2 anchorMin = (_panel.anchorMax = new Vector2(0.5f, 0.5f));
			panel.anchorMin = anchorMin;
			_panel.pivot = new Vector2(0.5f, 0.5f);
			Image val5 = LCStyle.Panel(((Component)val3).transform, RBg);
			_inner = ((Graphic)val5).rectTransform;
			LCStyle.Stretch(_inner, 4f, 4f);
			RawImage val6 = LCStyle.Scanlines(((Component)_inner).transform, new Color(0.3f, 0f, 0f, 0.22f));
			LCStyle.Stretch(((Graphic)val6).rectTransform, 0f, 0f);
			_title = Label("Title", 26f, 14f, 648f, 40f, 30f, (TextAlignmentOptions)258, RHead);
			((TMP_Text)_title).fontStyle = (FontStyles)1;
			((TMP_Text)_title).text = "CASINO PERFORMANCE REPORT";
			Image val7 = LCStyle.Panel(((Component)_inner).transform, RBorder);
			RectTransform rectTransform = ((Graphic)val7).rectTransform;
			rectTransform.anchorMin = new Vector2(0f, 1f);
			rectTransform.anchorMax = new Vector2(0f, 1f);
			rectTransform.pivot = new Vector2(0f, 1f);
			rectTransform.anchoredPosition = new Vector2(26f, -58f);
			rectTransform.sizeDelta = new Vector2(648f, 3f);
			float num = 406f;
			((TMP_Text)Label("EmpHead", 26f, 70f, num - 26f, 24f, 18f, (TextAlignmentOptions)257, RDim)).text = "EMPLOYEE";
			((TMP_Text)Label("NotesHead", num + 6f, 70f, 674f - num - 6f, 24f, 18f, (TextAlignmentOptions)257, RDim)).text = "NOTES";
			float num2 = num + 6f;
			float num3 = 674f - num2;
			Image val8 = LCStyle.Box(((Component)_inner).transform, RBorder);
			RectTransform rectTransform2 = ((Graphic)val8).rectTransform;
			rectTransform2.anchorMin = new Vector2(0f, 1f);
			rectTransform2.anchorMax = new Vector2(0f, 1f);
			rectTransform2.pivot = new Vector2(0f, 1f);
			rectTransform2.anchoredPosition = new Vector2(num2, -98f);
			rectTransform2.sizeDelta = new Vector2(num3, 160f);
			_notes = LCStyle.Text(((Component)_inner).transform, "Notes", 17f, (TextAlignmentOptions)257, nativeGlow: false);
			RectTransform rectTransform3 = ((TMP_Text)_notes).rectTransform;
			rectTransform3.anchorMin = new Vector2(0f, 1f);
			rectTransform3.anchorMax = new Vector2(0f, 1f);
			rectTransform3.pivot = new Vector2(0f, 1f);
			rectTransform3.anchoredPosition = new Vector2(num2 + 12f, -110f);
			rectTransform3.sizeDelta = new Vector2(num3 - 24f, 160f);
			((Graphic)_notes).color = RInk;
			Image val9 = LCStyle.Box(((Component)_inner).transform, RBorder);
			RectTransform rectTransform4 = ((Graphic)val9).rectTransform;
			rectTransform4.anchorMin = new Vector2(0f, 0f);
			rectTransform4.anchorMax = new Vector2(0f, 0f);
			rectTransform4.pivot = new Vector2(0f, 0f);
			rectTransform4.anchoredPosition = new Vector2(26f, 16f);
			rectTransform4.sizeDelta = new Vector2(num - 26f, 44f);
			_collected = LCStyle.Text(((Component)_inner).transform, "Collected", 20f, (TextAlignmentOptions)513, nativeGlow: false);
			RectTransform rectTransform5 = ((TMP_Text)_collected).rectTransform;
			rectTransform5.anchorMin = new Vector2(0f, 0f);
			rectTransform5.anchorMax = new Vector2(0f, 0f);
			rectTransform5.pivot = new Vector2(0f, 0f);
			rectTransform5.anchoredPosition = new Vector2(40f, 16f);
			rectTransform5.sizeDelta = new Vector2(num - 26f - 20f, 44f);
			_grade = LCStyle.Text(((Component)_inner).transform, "Grade", 30f, (TextAlignmentOptions)516, nativeGlow: false);
			RectTransform rectTransform6 = ((TMP_Text)_grade).rectTransform;
			rectTransform6.anchorMin = new Vector2(1f, 0f);
			rectTransform6.anchorMax = new Vector2(1f, 0f);
			rectTransform6.pivot = new Vector2(1f, 0f);
			rectTransform6.anchoredPosition = new Vector2(-26f, 16f);
			rectTransform6.sizeDelta = new Vector2(294f, 44f);
			((TMP_Text)_grade).fontStyle = (FontStyles)1;
			_built = true;
		}

		public void Show(Dictionary<ulong, int> sessionSnapshot, int crewNet)
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.SummaryEnabled())
			{
				if ((Object)(object)TrackerManager.Instance != (Object)null)
				{
					TrackerManager.Instance.EndSessionWipe();
				}
				return;
			}
			if (!_built)
			{
				BuildUI();
			}
			List<Row> list = BuildRows(sessionSnapshot);
			for (int i = 0; i < _rowBoxes.Count; i++)
			{
				if ((Object)(object)_rowBoxes[i] != (Object)null)
				{
					Object.Destroy((Object)(object)_rowBoxes[i]);
				}
			}
			_rowBoxes.Clear();
			float num = 406f;
			float num2 = num - 26f;
			int num3 = Mathf.Min(list.Count, 6);
			for (int j = 0; j < num3; j++)
			{
				Row row = list[j];
				Image val = LCStyle.Box(((Component)_inner).transform, RBorder);
				RectTransform rectTransform = ((Graphic)val).rectTransform;
				rectTransform.anchorMin = new Vector2(0f, 1f);
				rectTransform.anchorMax = new Vector2(0f, 1f);
				rectTransform.pivot = new Vector2(0f, 1f);
				rectTransform.anchoredPosition = new Vector2(26f, 0f - (98f + (float)j * 40f));
				rectTransform.sizeDelta = new Vector2(num2, 34f);
				TextMeshProUGUI val2 = LCStyle.Text(((Component)val).transform, "Row", 19f, (TextAlignmentOptions)513, nativeGlow: false);
				LCStyle.Stretch(((TMP_Text)val2).rectTransform, 12f, 0f);
				string text = (row.has ? Tag(Signed(row.delta), (row.delta > 0) ? Up : Down) : Tag("--", RDim));
				((TMP_Text)val2).text = Tag(Trunc(row.name, 12), RInk) + "<pos=72%>" + text;
				_rowBoxes.Add(((Component)val).gameObject);
			}
			((TMP_Text)_notes).text = BuildNotes();
			Color c = ((crewNet > 0) ? Up : ((crewNet < 0) ? Down : RInk));
			((TMP_Text)_collected).text = Tag("COLLECTED: ", RDim) + Tag((crewNet == 0) ? "0" : Signed(crewNet), c);
			((TMP_Text)_grade).text = Tag("GRADE ", RDim) + Tag(Grade(crewNet), RHead);
			float num4 = 98f + (float)Mathf.Max(num3, 3) * 40f + 76f;
			_panel.sizeDelta = new Vector2(700f, num4);
			PlayResultSound(crewNet);
			_root.SetActive(true);
			if (_co != null)
			{
				((MonoBehaviour)this).StopCoroutine(_co);
			}
			_co = ((MonoBehaviour)this).StartCoroutine(Run());
		}

		private static string BuildNotes()
		{
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			TrackerManager instance = TrackerManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return "";
			}
			List<PlayerRunRecord> recordsSorted = instance.GetRecordsSorted();
			PlayerRunRecord playerRunRecord = null;
			PlayerRunRecord playerRunRecord2 = null;
			for (int i = 0; i < recordsSorted.Count; i++)
			{
				if (playerRunRecord == null || recordsSorted[i].biggestSingleWin > playerRunRecord.biggestSingleWin)
				{
					playerRunRecord = recordsSorted[i];
				}
				if (playerRunRecord2 == null || recordsSorted[i].biggestSingleLoss > playerRunRecord2.biggestSingleLoss)
				{
					playerRunRecord2 = recordsSorted[i];
				}
			}
			StringBuilder stringBuilder = new StringBuilder();
			if (playerRunRecord != null && playerRunRecord.biggestSingleWin > 0)
			{
				stringBuilder.Append(Tag("Top win: ", RDim)).Append(Tag(Trunc(playerRunRecord.username, 9) + " " + Signed(playerRunRecord.biggestSingleWin), Up)).Append('\n');
			}
			else
			{
				stringBuilder.Append(Tag("Top win: --", RDim)).Append('\n');
			}
			if (playerRunRecord2 != null && playerRunRecord2.biggestSingleLoss > 0)
			{
				stringBuilder.Append(Tag("Top loss: ", RDim)).Append(Tag(Trunc(playerRunRecord2.username, 9) + " -" + playerRunRecord2.biggestSingleLoss.ToString("N0"), Down)).Append('\n');
			}
			else
			{
				stringBuilder.Append(Tag("Top loss: --", RDim)).Append('\n');
			}
			stringBuilder.Append(Tag("Games: " + instance.TotalGames(), RDim));
			return stringBuilder.ToString();
		}

		private static string Grade(int crewNet)
		{
			if (crewNet >= 1500)
			{
				return "S";
			}
			if (crewNet >= 400)
			{
				return "A";
			}
			if (crewNet > 0)
			{
				return "B";
			}
			if (crewNet == 0)
			{
				return "C";
			}
			if (crewNet > -400)
			{
				return "D";
			}
			return "F";
		}

		private static List<Row> BuildRows(Dictionary<ulong, int> snap)
		{
			List<Row> list = new List<Row>();
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance != (Object)null && instance.allPlayerScripts != null)
			{
				PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts;
				foreach (PlayerControllerB val in allPlayerScripts)
				{
					if (!((Object)(object)val == (Object)null) && (val.isPlayerControlled || val.isPlayerDead))
					{
						Row row = new Row();
						row.name = (string.IsNullOrEmpty(val.playerUsername) ? ("Player " + val.playerClientId) : val.playerUsername);
						row.has = snap != null && snap.TryGetValue(val.playerClientId, out var value) && value != 0;
						row.delta = (row.has ? snap[val.playerClientId] : 0);
						list.Add(row);
					}
				}
			}
			return list;
		}

		private IEnumerator Run()
		{
			float fadeIn = 0.45f;
			float hold = Plugin.SummaryDuration();
			float fadeOut = 0.8f;
			float t = 0f;
			while (t < fadeIn)
			{
				t += Time.unscaledDeltaTime;
				_group.alpha = Mathf.Clamp01(t / fadeIn);
				yield return null;
			}
			_group.alpha = 1f;
			yield return (object)new WaitForSecondsRealtime(hold);
			t = 0f;
			while (t < fadeOut)
			{
				t += Time.unscaledDeltaTime;
				_group.alpha = 1f - Mathf.Clamp01(t / fadeOut);
				yield return null;
			}
			_group.alpha = 0f;
			_root.SetActive(false);
			_co = null;
			if ((Object)(object)TrackerManager.Instance != (Object)null)
			{
				TrackerManager.Instance.EndSessionWipe();
			}
		}

		private void PlayResultSound(int crewNet)
		{
			if (Plugin.SfxEnabled() && !((Object)(object)_audio == (Object)null))
			{
				AudioClip val = ((crewNet > 0) ? _winClip : ((crewNet < 0) ? _loseClip : _neutralClip));
				if ((Object)(object)val != (Object)null)
				{
					_audio.PlayOneShot(val, Plugin.SfxVolume());
				}
			}
		}

		private static string Trunc(string s, int max)
		{
			if (string.IsNullOrEmpty(s))
			{
				return "";
			}
			if (s.Length > max)
			{
				return s.Substring(0, max);
			}
			return s;
		}

		private static AudioClip MakeJingle(string name, float[] freqs, float noteDur, float noteGlideHz)
		{
			int num = 44100;
			int num2 = Mathf.Max(1, (int)(noteDur * (float)num));
			int num3 = num2 * freqs.Length;
			float[] array = new float[num3];
			for (int i = 0; i < freqs.Length; i++)
			{
				float num4 = freqs[i];
				for (int j = 0; j < num2; j++)
				{
					float num5 = (float)j / (float)num;
					float num6 = (float)j / (float)num2;
					float num7 = num4 + noteGlideHz * num6;
					float num8 = Mathf.Exp(-4f * num6);
					float num9 = Mathf.Clamp01(num6 * 40f);
					array[i * num2 + j] = Mathf.Sin((float)Math.PI * 2f * num7 * num5) * num8 * num9 * 0.28f;
				}
			}
			AudioClip val = AudioClip.Create("LCCT_" + name, num3, 1, num, false);
			val.SetData(array, 0);
			return val;
		}
	}
	public class TrackerManager : MonoBehaviour
	{
		private class Pending
		{
			public ulong id;

			public string name;

			public int delta;

			public CasinoGameType game;

			public float lastTouch;
		}

		public const string Es3File = "LethalCasinoTracker.es3";

		private const string Es3KeyPrefix = "CasinoTracker_RunRecords_";

		private const float FlushDelay = 0.85f;

		private readonly Dictionary<ulong, int> _sessionDeltas = new Dictionary<ulong, int>();

		private readonly Dictionary<ulong, PlayerRunRecord> _runRecords = new Dictionary<ulong, PlayerRunRecord>();

		private readonly Dictionary<string, Pending> _pending = new Dictionary<string, Pending>();

		private bool _recordsLoaded;

		private bool _wasLanded;

		private bool _wasListening;

		public static TrackerManager Instance { get; private set; }

		public bool SessionActive { get; private set; }

		public bool RecordsDirty { get; set; }

		private void Awake()
		{
			Instance = this;
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		public void RecordResolution(ulong id, string username, int delta, CasinoGameType game, int gameInstanceId)
		{
			if (delta != 0)
			{
				string text = (string.IsNullOrEmpty(username) ? ("Player " + id) : username);
				_sessionDeltas.TryGetValue(id, out var value);
				_sessionDeltas[id] = value + delta;
				string key = gameInstanceId + ":" + id;
				if (!_pending.TryGetValue(key, out var value2))
				{
					value2 = new Pending();
					value2.id = id;
					value2.name = text;
					value2.game = game;
					_pending[key] = value2;
				}
				value2.delta += delta;
				value2.game = game;
				value2.name = text;
				value2.lastTouch = Time.realtimeSinceStartup;
				if (Plugin.VerboseLogging)
				{
					Plugin.Log.LogInfo((object)("Delta " + delta + " -> " + text + " (" + CasinoGameNames.Display(game) + "), session net now " + _sessionDeltas[id]));
				}
			}
		}

		private void Update()
		{
			bool flag = (Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsListening;
			if (_wasListening && !flag)
			{
				SoftResetForMenu();
			}
			_wasListening = flag;
			StartOfRound instance = StartOfRound.Instance;
			bool flag2 = (Object)(object)instance != (Object)null && instance.shipHasLanded && !instance.shipIsLeaving;
			if (flag2 && !_wasLanded)
			{
				OnShipLanded();
			}
			else if (!flag2 && _wasLanded)
			{
				OnShipLeaving();
			}
			_wasLanded = flag2;
			if (_pending.Count > 0)
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				List<string> list = null;
				foreach (KeyValuePair<string, Pending> item in _pending)
				{
					if (realtimeSinceStartup - item.Value.lastTouch >= 0.85f)
					{
						if (list == null)
						{
							list = new List<string>();
						}
						list.Add(item.Key);
					}
				}
				if (list != null)
				{
					for (int i = 0; i < list.Count; i++)
					{
						Pending p = _pending[list[i]];
						_pending.Remove(list[i]);
						FinalizeRound(p);
					}
				}
			}
			NetworkSync.Tick();
		}

		private void FinalizeRound(Pending p)
		{
			PlayerRunRecord orCreateRecord = GetOrCreateRecord(p.id, p.name);
			orCreateRecord.gamesPlayed++;
			if (p.delta > 0)
			{
				orCreateRecord.totalWon += p.delta;
				if (p.delta > orCreateRecord.biggestSingleWin)
				{
					orCreateRecord.biggestSingleWin = p.delta;
					orCreateRecord.biggestWinGame = CasinoGameNames.Display(p.game);
				}
			}
			else if (p.delta < 0)
			{
				int num = -p.delta;
				orCreateRecord.totalLost += num;
				if (num > orCreateRecord.biggestSingleLoss)
				{
					orCreateRecord.biggestSingleLoss = num;
					orCreateRecord.biggestLossGame = CasinoGameNames.Display(p.game);
				}
			}
			RecordsDirty = true;
		}

		private void FlushAllPendingNow()
		{
			if (_pending.Count != 0)
			{
				List<Pending> list = new List<Pending>(_pending.Values);
				_pending.Clear();
				for (int i = 0; i < list.Count; i++)
				{
					FinalizeRound(list[i]);
				}
			}
		}

		private PlayerRunRecord GetOrCreateRecord(ulong id, string name)
		{
			if (!_runRecords.TryGetValue(id, out var value))
			{
				value = new PlayerRunRecord();
				value.clientId = (long)id;
				value.username = name;
				_runRecords[id] = value;
			}
			else if (!string.IsNullOrEmpty(name))
			{
				value.username = name;
			}
			return value;
		}

		public void OnShipLanded()
		{
			SessionActive = true;
			if (IsServer())
			{
				if (!_recordsLoaded)
				{
					LoadRecords();
				}
				_recordsLoaded = true;
			}
			else
			{
				NetworkSync.RequestResync();
			}
			RecordsDirty = true;
		}

		public void OnShipLeaving()
		{
			FlushAllPendingNow();
			if (IsServer())
			{
				SaveRecords();
			}
			bool flag = IsGordion();
			Dictionary<ulong, int> sessionSnapshot = new Dictionary<ulong, int>(_sessionDeltas);
			SessionActive = false;
			SummaryScreenController instance = SummaryScreenController.Instance;
			if (flag && (Object)(object)instance != (Object)null)
			{
				instance.Show(sessionSnapshot, CrewNet());
			}
			else
			{
				EndSessionWipe();
			}
		}

		public static bool IsGordion()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.currentLevel == (Object)null || string.IsNullOrEmpty(instance.currentLevel.PlanetName))
			{
				return false;
			}
			return instance.currentLevel.PlanetName.IndexOf("Gordion", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		public void EndSessionWipe()
		{
			_sessionDeltas.Clear();
			CasinoHooks.ResetValueTracking();
			RecordsDirty = true;
		}

		private void SoftResetForMenu()
		{
			_sessionDeltas.Clear();
			_runRecords.Clear();
			_pending.Clear();
			SessionActive = false;
			_wasLanded = false;
			_recordsLoaded = false;
			RecordsDirty = true;
		}

		public void EliminateRun()
		{
			_sessionDeltas.Clear();
			_runRecords.Clear();
			_pending.Clear();
			CasinoHooks.ResetValueTracking();
			SessionActive = false;
			RecordsDirty = true;
			if (IsServer())
			{
				DeleteRecordsForSlot(SlotId());
			}
			Plugin.Log.LogInfo((object)"Casino records wiped (crew eliminated).");
		}

		public void OnSaveFileDeleted(string filePath)
		{
			string text = "default";
			try
			{
				if (!string.IsNullOrEmpty(filePath))
				{
					text = Path.GetFileNameWithoutExtension(filePath);
				}
			}
			catch
			{
			}
			DeleteRecordsForSlot(text);
			if (text == SlotId())
			{
				_sessionDeltas.Clear();
				_runRecords.Clear();
				_pending.Clear();
				CasinoHooks.ResetValueTracking();
				_recordsLoaded = false;
				RecordsDirty = true;
			}
			Plugin.Log.LogInfo((object)("Casino records wiped for deleted save '" + text + "'."));
		}

		private static string SlotId()
		{
			try
			{
				if ((Object)(object)GameNetworkManager.Instance != (Object)null && !string.IsNullOrEmpty(GameNetworkManager.Instance.currentSaveFileName))
				{
					return Path.GetFileNameWithoutExtension(GameNetworkManager.Instance.currentSaveFileName);
				}
			}
			catch
			{
			}
			return "default";
		}

		private static string KeyFor(string slot)
		{
			return "CasinoTracker_RunRecords_" + slot;
		}

		private void DeleteRecordsForSlot(string slot)
		{
			try
			{
				string text = KeyFor(slot);
				if (ES3.KeyExists(text, "LethalCasinoTracker.es3"))
				{
					ES3.DeleteKey(text, "LethalCasinoTracker.es3");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("ES3 delete failed: " + ex.Message));
			}
		}

		public void SaveRecords()
		{
			try
			{
				RunSaveBlob runSaveBlob = new RunSaveBlob();
				foreach (PlayerRunRecord value in _runRecords.Values)
				{
					runSaveBlob.records.Add(value);
				}
				string text = JsonUtility.ToJson((object)runSaveBlob);
				ES3.Save<string>(KeyFor(SlotId()), text, "LethalCasinoTracker.es3");
				if (Plugin.VerboseLogging)
				{
					Plugin.Log.LogInfo((object)("Saved " + runSaveBlob.records.Count + " run records for slot '" + SlotId() + "'."));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Failed to save run records: " + ex.Message));
			}
		}

		public void LoadRecords()
		{
			try
			{
				_runRecords.Clear();
				string text = KeyFor(SlotId());
				if (!ES3.KeyExists(text, "LethalCasinoTracker.es3"))
				{
					Plugin.Log.LogInfo((object)("No casino records for slot '" + SlotId() + "'."));
					RecordsDirty = true;
					return;
				}
				string text2 = ES3.Load<string>(text, "LethalCasinoTracker.es3", "");
				if (string.IsNullOrEmpty(text2))
				{
					RecordsDirty = true;
					return;
				}
				RunSaveBlob runSaveBlob = JsonUtility.FromJson<RunSaveBlob>(text2);
				if (runSaveBlob != null && runSaveBlob.records != null)
				{
					for (int i = 0; i < runSaveBlob.records.Count; i++)
					{
						PlayerRunRecord playerRunRecord = runSaveBlob.records[i];
						if (playerRunRecord != null)
						{
							_runRecords[(ulong)playerRunRecord.clientId] = playerRunRecord;
						}
					}
				}
				Plugin.Log.LogInfo((object)("Loaded " + _runRecords.Count + " run records for slot '" + SlotId() + "'."));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Failed to load run records: " + ex.Message));
			}
			RecordsDirty = true;
		}

		public SyncBlob BuildSyncBlob()
		{
			SyncBlob syncBlob = new SyncBlob();
			foreach (PlayerRunRecord value2 in _runRecords.Values)
			{
				syncBlob.records.Add(value2);
			}
			foreach (KeyValuePair<ulong, int> sessionDelta in _sessionDeltas)
			{
				SessionEntry sessionEntry = new SessionEntry();
				sessionEntry.clientId = (long)sessionDelta.Key;
				sessionEntry.delta = sessionDelta.Value;
				sessionEntry.username = (_runRecords.TryGetValue(sessionDelta.Key, out var value) ? value.username : "");
				syncBlob.session.Add(sessionEntry);
			}
			return syncBlob;
		}

		public void ApplySyncBlob(SyncBlob b)
		{
			if (b == null)
			{
				return;
			}
			_runRecords.Clear();
			if (b.records != null)
			{
				for (int i = 0; i < b.records.Count; i++)
				{
					PlayerRunRecord playerRunRecord = b.records[i];
					if (playerRunRecord != null)
					{
						_runRecords[(ulong)playerRunRecord.clientId] = playerRunRecord;
					}
				}
			}
			_sessionDeltas.Clear();
			if (b.session != null)
			{
				for (int j = 0; j < b.session.Count; j++)
				{
					SessionEntry sessionEntry = b.session[j];
					if (sessionEntry != null)
					{
						_sessionDeltas[(ulong)sessionEntry.clientId] = sessionEntry.delta;
					}
				}
			}
			_recordsLoaded = true;
			RecordsDirty = true;
			Plugin.Log.LogInfo((object)("Applied tracker state from host (" + _runRecords.Count + " records)."));
		}

		public bool TryGetSessionDelta(ulong id, out int delta)
		{
			return _sessionDeltas.TryGetValue(id, out delta);
		}

		public int CrewNet()
		{
			int num = 0;
			foreach (int value in _sessionDeltas.Values)
			{
				num += value;
			}
			return num;
		}

		public List<PlayerRunRecord> GetRecordsSorted()
		{
			List<PlayerRunRecord> list = new List<PlayerRunRecord>(_runRecords.Values);
			list.Sort((PlayerRunRecord a, PlayerRunRecord b) => b.Net.CompareTo(a.Net));
			return list;
		}

		public int TotalGames()
		{
			int num = 0;
			foreach (PlayerRunRecord value in _runRecords.Values)
			{
				num += value.gamesPlayed;
			}
			return num;
		}

		public static bool IsServer()
		{
			if ((Object)(object)NetworkManager.Singleton != (Object)null)
			{
				return NetworkManager.Singleton.IsServer;
			}
			return false;
		}
	}
}
namespace LethalCasinoTracker.Patches
{
	public static class GameOverPatch
	{
		public static void OnPlayersFired()
		{
			if ((Object)(object)TrackerManager.Instance != (Object)null)
			{
				Plugin.Log.LogInfo((object)"Crew eliminated by the company — wiping casino records.");
				TrackerManager.Instance.EliminateRun();
			}
		}

		public static void OnSaveFileDeleted(string filePath)
		{
			if ((Object)(object)TrackerManager.Instance != (Object)null)
			{
				TrackerManager.Instance.OnSaveFileDeleted(filePath);
			}
		}

		public static void ApplyPatches(Harmony h)
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			Patch(h, AccessTools.Method(typeof(StartOfRound), "FirePlayersAfterDeadlineClientRpc", (Type[])null, (Type[])null), AccessTools.Method(typeof(GameOverPatch), "OnPlayersFired", (Type[])null, (Type[])null), "StartOfRound.FirePlayersAfterDeadlineClientRpc");
			MethodInfo methodInfo = AccessTools.Method(typeof(GameOverPatch), "OnSaveFileDeleted", (Type[])null, (Type[])null);
			try
			{
				MethodInfo[] methods = typeof(ES3).GetMethods(BindingFlags.Static | BindingFlags.Public);
				int num = 0;
				for (int i = 0; i < methods.Length; i++)
				{
					if (methods[i].Name != "DeleteFile")
					{
						continue;
					}
					ParameterInfo[] parameters = methods[i].GetParameters();
					if (parameters.Length >= 1 && parameters[0].ParameterType == typeof(string))
					{
						try
						{
							h.Patch((MethodBase)methods[i], (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
							num++;
						}
						catch (Exception ex)
						{
							Plugin.Log.LogWarning((object)("ES3.DeleteFile patch failed: " + ex.Message));
						}
					}
				}
				Plugin.Log.LogInfo((object)("Patched ES3.DeleteFile (" + num + " overloads)."));
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogError((object)("Could not patch ES3.DeleteFile: " + ex2.Message));
			}
		}

		private static void Patch(Harmony h, MethodInfo orig, MethodInfo postfix, string label)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			try
			{
				if (orig == null)
				{
					Plugin.Log.LogWarning((object)("Patch target not found: " + label));
					return;
				}
				h.Patch((MethodBase)orig, (HarmonyMethod)null, new HarmonyMethod(postfix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log.LogInfo((object)("Patched " + label));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Failed to patch " + label + ": " + ex.Message));
			}
		}
	}
}