Decompiled source of RoundsTracker v1.0.6

rounds-tracker.dll

Decompiled 7 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using ModdingUtils.Utils;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnboundLib;
using UnboundLib.GameModes;
using UnboundLib.Networking;
using UnboundLib.Utils.UI;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("rounds-tracker")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+013720f88a4117bc5cc81421d963ae6bf92ff28a")]
[assembly: AssemblyProduct("rounds-tracker")]
[assembly: AssemblyTitle("rounds-tracker")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace RoundsTracker
{
	internal static class Api
	{
		[CompilerGenerated]
		private sealed class <SendCoroutine>d__2 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public RoundReport report;

			public int retry;

			private string <json>5__1;

			private string <url>5__2;

			private UnityWebRequest <req>5__3;

			private string <responseText>5__4;

			private int <eloIdx>5__5;

			private float <before>5__6;

			private float <change>5__7;

			private float <after>5__8;

			private int <displayBefore>5__9;

			private int <displayChange>5__10;

			private int <displayAfter>5__11;

			private string <sign>5__12;

			private GameMessageType <msgType>5__13;

			private List<EloPlayerData> <allElo>5__14;

			private Exception <ex>5__15;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <SendCoroutine>d__2(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || (uint)(num - 1) <= 1u)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<json>5__1 = null;
				<url>5__2 = null;
				<req>5__3 = null;
				<responseText>5__4 = null;
				<sign>5__12 = null;
				<allElo>5__14 = null;
				<ex>5__15 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_008e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0098: Expected O, but got Unknown
				//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c1: Expected O, but got Unknown
				//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d2: Expected O, but got Unknown
				//IL_0187: Unknown result type (might be due to invalid IL or missing references)
				//IL_0191: Expected O, but got Unknown
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<json>5__1 = Json.Serialize(report);
						<url>5__2 = RT.ApiUrlValue + "/api/rounds";
						RT.LogDebug($"Sending {<json>5__1.Length} bytes to {<url>5__2}");
						<req>5__3 = new UnityWebRequest(<url>5__2, "POST");
						<>1__state = -3;
						<req>5__3.uploadHandler = (UploadHandler)new UploadHandlerRaw(Encoding.UTF8.GetBytes(<json>5__1));
						<req>5__3.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
						<req>5__3.SetRequestHeader("Content-Type", "application/json");
						<req>5__3.timeout = 15;
						<>2__current = <req>5__3.SendWebRequest();
						<>1__state = 1;
						return true;
					case 1:
						<>1__state = -3;
						if (<req>5__3.isNetworkError || <req>5__3.isHttpError)
						{
							RT.LogError($"Send error: {<req>5__3.error} (attempt {retry + 1})");
							if (retry < 3)
							{
								<>2__current = (object)new WaitForSeconds(2f * (float)(retry + 1));
								<>1__state = 2;
								return true;
							}
							break;
						}
						<responseText>5__4 = <req>5__3.downloadHandler.text;
						RT.Log("Send OK: " + <responseText>5__4.Substring(0, Math.Min(<responseText>5__4.Length, 500)));
						if (<responseText>5__4 != null && <responseText>5__4.Contains("\"elo\""))
						{
							try
							{
								<eloIdx>5__5 = <responseText>5__4.IndexOf("\"elo\"");
								if (<eloIdx>5__5 >= 0)
								{
									<before>5__6 = ExtractFloat(<responseText>5__4, "before", <eloIdx>5__5);
									<change>5__7 = ExtractFloat(<responseText>5__4, "change", <eloIdx>5__5);
									<after>5__8 = ExtractFloat(<responseText>5__4, "after", <eloIdx>5__5);
									if (<change>5__7 != 0f && RT.ShowEloNotifications.Value && !RT._eloShownThisGame)
									{
										RT._eloShownThisGame = true;
										<displayBefore>5__9 = (int)Math.Round(<before>5__6);
										<displayChange>5__10 = (int)Math.Round(<change>5__7);
										<displayAfter>5__11 = (int)Math.Round(<after>5__8);
										<sign>5__12 = ((<displayChange>5__10 > 0) ? "+" : "");
										<msgType>5__13 = ((<displayChange>5__10 > 0) ? GameMessageType.Success : GameMessageType.Warning);
										GameMessage.Show($"ELO {<displayBefore>5__9} → {<sign>5__12}{<displayChange>5__10} → {<displayAfter>5__11}", <msgType>5__13, 5f);
										RT.Log($"ELO change (server): {<before>5__6:F1} -> {<sign>5__12}{<change>5__7:F1} -> {<after>5__8:F1}");
										<sign>5__12 = null;
									}
								}
								if (<responseText>5__4.Contains("\"all_elo\""))
								{
									<allElo>5__14 = ParseAllElo(<responseText>5__4);
									if (<allElo>5__14.Count > 0)
									{
										Networking.BroadcastEloResults(<allElo>5__14);
									}
									<allElo>5__14 = null;
								}
							}
							catch (Exception ex)
							{
								<ex>5__15 = ex;
								RT.LogError("ELO parse error: " + <ex>5__15.Message);
							}
						}
						<responseText>5__4 = null;
						break;
					case 2:
						<>1__state = -3;
						((MonoBehaviour)RT.Instance).StartCoroutine(SendCoroutine(report, retry + 1));
						break;
					}
					<>m__Finally1();
					<req>5__3 = null;
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<req>5__3 != null)
				{
					((IDisposable)<req>5__3).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private const int MaxRetries = 3;

		public static void Send(RoundReport report)
		{
			if (RT.EnableTracking.Value && !string.IsNullOrEmpty(report.steam_id))
			{
				((MonoBehaviour)RT.Instance).StartCoroutine(SendCoroutine(report, 0));
			}
		}

		[IteratorStateMachine(typeof(<SendCoroutine>d__2))]
		private static IEnumerator SendCoroutine(RoundReport report, int retry)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SendCoroutine>d__2(0)
			{
				report = report,
				retry = retry
			};
		}

		private static int ExtractInt(string text, string field, int startIdx = 0)
		{
			string text2 = "\"" + field + "\":";
			int num = text.IndexOf(text2, startIdx);
			if (num < 0)
			{
				return 0;
			}
			int i;
			for (i = num + text2.Length; i < text.Length && text[i] == ' '; i++)
			{
			}
			int j = i;
			if (j < text.Length && text[j] == '-')
			{
				j++;
			}
			for (; j < text.Length && char.IsDigit(text[j]); j++)
			{
			}
			if (j == i)
			{
				return 0;
			}
			string s = text.Substring(i, j - i);
			if (int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			return 0;
		}

		private static float ExtractFloat(string text, string field, int startIdx = 0)
		{
			string text2 = "\"" + field + "\":";
			int num = text.IndexOf(text2, startIdx);
			if (num < 0)
			{
				return 0f;
			}
			int i;
			for (i = num + text2.Length; i < text.Length && text[i] == ' '; i++)
			{
			}
			int j = i;
			if (j < text.Length && text[j] == '-')
			{
				j++;
			}
			for (; j < text.Length && char.IsDigit(text[j]); j++)
			{
			}
			if (j < text.Length && text[j] == '.')
			{
				for (j++; j < text.Length && char.IsDigit(text[j]); j++)
				{
				}
			}
			if (j == i)
			{
				return 0f;
			}
			string s = text.Substring(i, j - i);
			if (float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			return 0f;
		}

		private static List<EloPlayerData> ParseAllElo(string text)
		{
			List<EloPlayerData> list = new List<EloPlayerData>();
			int num = text.IndexOf("\"all_elo\"");
			if (num < 0)
			{
				return list;
			}
			int num2 = text.IndexOf('[', num);
			if (num2 < 0)
			{
				return list;
			}
			int num3 = text.IndexOf(']', num2);
			if (num3 < 0)
			{
				return list;
			}
			string text2 = text.Substring(num2, num3 - num2 + 1);
			int num4 = 0;
			while (num4 < text2.Length)
			{
				int num5 = text2.IndexOf('{', num4);
				if (num5 < 0)
				{
					break;
				}
				int num6 = text2.IndexOf('}', num5);
				if (num6 < 0)
				{
					break;
				}
				string text3 = text2.Substring(num5, num6 - num5 + 1);
				num4 = num6 + 1;
				try
				{
					string text4 = ExtractString(text3, "steam_id");
					if (!string.IsNullOrEmpty(text4))
					{
						float before = ExtractFloat(text3, "before");
						float after = ExtractFloat(text3, "after");
						float change = ExtractFloat(text3, "change");
						list.Add(new EloPlayerData
						{
							steam_id = text4,
							before = before,
							after = after,
							change = change
						});
					}
				}
				catch
				{
				}
			}
			RT.Log($"ParseAllElo: parsed {list.Count} entries");
			return list;
		}

		private static string ExtractString(string obj, string field)
		{
			string text = "\"" + field + "\":\"";
			int num = obj.IndexOf(text);
			if (num < 0)
			{
				return null;
			}
			int num2 = num + text.Length;
			int num3 = obj.IndexOf('"', num2);
			if (num3 < 0)
			{
				return null;
			}
			return obj.Substring(num2, num3 - num2);
		}
	}
	internal static class Json
	{
		public static string Serialize(RoundReport r)
		{
			StringBuilder stringBuilder = new StringBuilder(8192);
			stringBuilder.Append("{");
			stringBuilder.Append("\"report_id\":\"");
			stringBuilder.Append(E(r.report_id));
			stringBuilder.Append("\",");
			stringBuilder.Append("\"session_id\":\"");
			stringBuilder.Append(E(r.session_id));
			stringBuilder.Append("\",");
			stringBuilder.Append("\"round_number\":");
			stringBuilder.Append(r.round_number);
			stringBuilder.Append(",");
			stringBuilder.Append("\"steam_id\":\"");
			stringBuilder.Append(E(r.steam_id));
			stringBuilder.Append("\",");
			stringBuilder.Append("\"nickname\":");
			stringBuilder.Append(N(r.nickname));
			stringBuilder.Append(",");
			stringBuilder.Append("\"player_color\":");
			stringBuilder.Append(N(r.player_color));
			stringBuilder.Append(",");
			stringBuilder.Append("\"is_round_winner\":");
			stringBuilder.Append(B(r.is_round_winner));
			stringBuilder.Append(",");
			stringBuilder.Append("\"points_won\":");
			stringBuilder.Append(r.points_won);
			stringBuilder.Append(",");
			stringBuilder.Append("\"points_played\":");
			stringBuilder.Append(r.points_played);
			stringBuilder.Append(",");
			stringBuilder.Append("\"current_cards\":[");
			for (int i = 0; i < r.current_cards.Count; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append(",");
				}
				AppendCard(stringBuilder, r.current_cards[i]);
			}
			stringBuilder.Append("],");
			stringBuilder.Append("\"picks\":[");
			for (int j = 0; j < r.picks.Count; j++)
			{
				if (j > 0)
				{
					stringBuilder.Append(",");
				}
				AppendPick(stringBuilder, r.picks[j]);
			}
			stringBuilder.Append("],");
			stringBuilder.Append("\"offered_cards\":[");
			for (int k = 0; k < r.offered_cards.Count; k++)
			{
				if (k > 0)
				{
					stringBuilder.Append(",");
				}
				AppendCard(stringBuilder, r.offered_cards[k]);
			}
			stringBuilder.Append("],");
			stringBuilder.Append("\"added\":[");
			for (int l = 0; l < r.added.Count; l++)
			{
				if (l > 0)
				{
					stringBuilder.Append(",");
				}
				AppendCard(stringBuilder, r.added[l]);
			}
			stringBuilder.Append("],");
			stringBuilder.Append("\"removed\":[");
			for (int m = 0; m < r.removed.Count; m++)
			{
				if (m > 0)
				{
					stringBuilder.Append(",");
				}
				AppendCard(stringBuilder, r.removed[m]);
			}
			stringBuilder.Append("],");
			stringBuilder.Append("\"game_mode\":");
			stringBuilder.Append(N(r.game_mode));
			stringBuilder.Append(",");
			stringBuilder.Append("\"player_count\":");
			stringBuilder.Append(r.player_count);
			stringBuilder.Append(",");
			stringBuilder.Append("\"players\":[");
			for (int n = 0; n < r.players.Count; n++)
			{
				if (n > 0)
				{
					stringBuilder.Append(",");
				}
				PlayerInfo playerInfo = r.players[n];
				stringBuilder.Append("{\"player_id\":");
				stringBuilder.Append(playerInfo.player_id);
				stringBuilder.Append(",\"steam_id\":");
				stringBuilder.Append(N(playerInfo.steam_id));
				stringBuilder.Append(",\"nickname\":");
				stringBuilder.Append(N(playerInfo.nickname));
				stringBuilder.Append(",\"player_color\":");
				stringBuilder.Append(N(playerInfo.player_color));
				stringBuilder.Append("}");
			}
			stringBuilder.Append("],");
			stringBuilder.Append("\"points_to_win_round\":");
			stringBuilder.Append(NI(r.points_to_win_round));
			stringBuilder.Append(",");
			stringBuilder.Append("\"rounds_to_win_game\":");
			stringBuilder.Append(NI(r.rounds_to_win_game));
			stringBuilder.Append(",");
			stringBuilder.Append("\"game_continued_count\":");
			stringBuilder.Append(r.game_continued_count);
			stringBuilder.Append(",");
			stringBuilder.Append("\"picks_to_choose\":");
			stringBuilder.Append(r.picks_to_choose);
			stringBuilder.Append(",");
			stringBuilder.Append("\"draws_per_pick_phase\":");
			stringBuilder.Append(r.draws_per_pick_phase);
			stringBuilder.Append(",");
			stringBuilder.Append("\"is_game_over\":");
			stringBuilder.Append(B(r.is_game_over));
			stringBuilder.Append(",");
			stringBuilder.Append("\"is_legitimate_game_over\":");
			stringBuilder.Append(B(r.is_legitimate_game_over));
			stringBuilder.Append(",");
			stringBuilder.Append("\"tracker_version\":\"");
			stringBuilder.Append(E(r.tracker_version));
			stringBuilder.Append("\"");
			stringBuilder.Append("}");
			return stringBuilder.ToString();
		}

		private static void AppendCard(StringBuilder sb, CardData c)
		{
			sb.Append("{\"card_name\":\"");
			sb.Append(E(c.card_name));
			sb.Append("\",\"mod_name\":");
			sb.Append(N(c.mod_name));
			sb.Append(",\"rarity\":");
			sb.Append(N(c.rarity));
			sb.Append(",\"description\":");
			sb.Append(N(c.description));
			sb.Append(",\"color_theme\":");
			sb.Append(N(c.color_theme));
			sb.Append(",\"card_color\":");
			sb.Append(N(c.card_color));
			sb.Append(",\"card_color_bg\":");
			sb.Append(N(c.card_color_bg));
			sb.Append(",\"stats\":[");
			if (c.stats != null)
			{
				for (int i = 0; i < c.stats.Count; i++)
				{
					if (i > 0)
					{
						sb.Append(",");
					}
					Stat stat = c.stats[i];
					sb.Append("{\"stat\":\"");
					sb.Append(E(stat.stat));
					sb.Append("\",\"amount\":\"");
					sb.Append(E(stat.amount));
					sb.Append("\",\"positive\":");
					sb.Append(B(stat.positive));
					sb.Append("}");
				}
			}
			sb.Append("]}");
		}

		private static void AppendPick(StringBuilder sb, PickEvent p)
		{
			sb.Append("{\"card_name\":\"");
			sb.Append(E(p.card_name));
			sb.Append("\",\"mod_name\":");
			sb.Append(N(p.mod_name));
			sb.Append(",\"rarity\":");
			sb.Append(N(p.rarity));
			sb.Append(",\"description\":");
			sb.Append(N(p.description));
			sb.Append(",\"color_theme\":");
			sb.Append(N(p.color_theme));
			sb.Append(",\"card_color\":");
			sb.Append(N(p.card_color));
			sb.Append(",\"card_color_bg\":");
			sb.Append(N(p.card_color_bg));
			sb.Append(",\"stats\":[");
			if (p.stats != null)
			{
				for (int i = 0; i < p.stats.Count; i++)
				{
					if (i > 0)
					{
						sb.Append(",");
					}
					Stat stat = p.stats[i];
					sb.Append("{\"stat\":\"");
					sb.Append(E(stat.stat));
					sb.Append("\",\"amount\":\"");
					sb.Append(E(stat.amount));
					sb.Append("\",\"positive\":");
					sb.Append(B(stat.positive));
					sb.Append("}");
				}
			}
			sb.Append("],\"position\":");
			sb.Append(p.position);
			sb.Append(",\"pick_number\":");
			sb.Append(p.pick_number);
			sb.Append(",\"offered_cards\":[");
			if (p.offered_cards != null)
			{
				for (int j = 0; j < p.offered_cards.Count; j++)
				{
					if (j > 0)
					{
						sb.Append(",");
					}
					AppendCard(sb, p.offered_cards[j]);
				}
			}
			sb.Append("]}");
		}

		private static string N(string v)
		{
			return string.IsNullOrEmpty(v) ? "null" : ("\"" + E(v) + "\"");
		}

		private static string B(bool v)
		{
			return v ? "true" : "false";
		}

		private static string E(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return "";
			}
			return s.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n")
				.Replace("\r", "\\r")
				.Replace("\t", "\\t");
		}

		private static string NI(int? v)
		{
			return v.HasValue ? v.Value.ToString() : "null";
		}
	}
	internal static class WinRateCache
	{
		[CompilerGenerated]
		private sealed class <LoadCoroutine>d__14 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private float <waited>5__1;

			private int <lastCardCount>5__2;

			private float <stableTime>5__3;

			private float <stabilizeWaited>5__4;

			private string <modsParam>5__5;

			private string <url>5__6;

			private bool <serverSuccess>5__7;

			private int <currentCount>5__8;

			private HashSet<string> <modSet>5__9;

			private List<CardInfo> <allCards>5__10;

			private List<CardInfo>.Enumerator <>s__11;

			private CardInfo <card>5__12;

			private string <modName>5__13;

			private CardInfo[] <>s__14;

			private int <>s__15;

			private CardInfo <card>5__16;

			private string <modName>5__17;

			private ReadOnlyCollection<CardInfo> <hidden>5__18;

			private IEnumerator<CardInfo> <>s__19;

			private CardInfo <card>5__20;

			private string <modName>5__21;

			private List<string> <parts>5__22;

			private HashSet<string>.Enumerator <>s__23;

			private string <mod>5__24;

			private Exception <ex>5__25;

			private UnityWebRequest <req>5__26;

			private string <rawText>5__27;

			private Exception <ex>5__28;

			private string <cached>5__29;

			private Exception <ex>5__30;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadCoroutine>d__14(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 3)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<modsParam>5__5 = null;
				<url>5__6 = null;
				<modSet>5__9 = null;
				<allCards>5__10 = null;
				<>s__11 = default(List<CardInfo>.Enumerator);
				<card>5__12 = null;
				<modName>5__13 = null;
				<>s__14 = null;
				<card>5__16 = null;
				<modName>5__17 = null;
				<hidden>5__18 = null;
				<>s__19 = null;
				<card>5__20 = null;
				<modName>5__21 = null;
				<parts>5__22 = null;
				<>s__23 = default(HashSet<string>.Enumerator);
				<mod>5__24 = null;
				<ex>5__25 = null;
				<req>5__26 = null;
				<rawText>5__27 = null;
				<ex>5__28 = null;
				<cached>5__29 = null;
				<ex>5__30 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0094: Unknown result type (might be due to invalid IL or missing references)
				//IL_009e: Expected O, but got Unknown
				//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ff: Expected O, but got Unknown
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						_loading = true;
						<waited>5__1 = 0f;
						goto IL_00c6;
					case 1:
						<>1__state = -1;
						<waited>5__1 += 1f;
						goto IL_00c6;
					case 2:
						<>1__state = -1;
						<stabilizeWaited>5__4 += 1f;
						goto IL_0227;
					case 3:
						{
							<>1__state = -3;
							if (<req>5__26.isNetworkError || <req>5__26.isHttpError)
							{
								RT.LogError("WinRateCache load error: " + <req>5__26.error);
							}
							else
							{
								try
								{
									<rawText>5__27 = <req>5__26.downloadHandler.text;
									RT.Log("WinRateCache: HTTP=" + <req>5__26.responseCode + " length=" + <rawText>5__27.Length + " bytes");
									ParseResponse(<rawText>5__27);
									if (_cache.Count > 0)
									{
										_loaded = true;
										<serverSuccess>5__7 = true;
										SaveToFile(<rawText>5__27);
										RT.Log("WinRateCache: updated from server, " + _cache.Count + " cards");
										if (RT.ShowCardUpdateNotifications.Value)
										{
											GameMessage.Success("Card data updated (" + _cache.Count + " cards)");
										}
									}
									<rawText>5__27 = null;
								}
								catch (Exception ex)
								{
									<ex>5__28 = ex;
									RT.LogError("WinRateCache parse error: " + <ex>5__28.Message);
								}
							}
							<>m__Finally1();
							<req>5__26 = null;
							if (!<serverSuccess>5__7)
							{
								<cached>5__29 = LoadFromFile();
								if (<cached>5__29 != null)
								{
									try
									{
										ParseResponse(<cached>5__29);
										if (_cache.Count > 0)
										{
											_loaded = true;
											RT.Log("WinRateCache: loaded from local cache, " + _cache.Count + " cards");
											if (RT.ShowCardUpdateNotifications.Value)
											{
												GameMessage.Warn("Card data: using cached version (" + _cache.Count + " cards)");
											}
										}
									}
									catch (Exception ex)
									{
										<ex>5__30 = ex;
										RT.LogError("WinRateCache cached parse error: " + <ex>5__30.Message);
									}
								}
								else
								{
									RT.Log("WinRateCache: no local cache available");
									if (RT.ShowCardUpdateNotifications.Value)
									{
										GameMessage.Error("Card data unavailable");
									}
								}
								<cached>5__29 = null;
							}
							_loading = false;
							return false;
						}
						IL_00c6:
						if (<waited>5__1 < 45f)
						{
							try
							{
								if ((Object)(object)CardChoice.instance != (Object)null && CardChoice.instance.cards != null && CardChoice.instance.cards.Length > 10)
								{
									goto IL_00da;
								}
							}
							catch
							{
							}
							<>2__current = (object)new WaitForSeconds(1f);
							<>1__state = 1;
							return true;
						}
						goto IL_00da;
						IL_023d:
						<modsParam>5__5 = "";
						try
						{
							<modSet>5__9 = new HashSet<string>();
							<modSet>5__9.Add("Vanilla");
							try
							{
								<allCards>5__10 = Cards.all;
								if (<allCards>5__10 != null)
								{
									<>s__11 = <allCards>5__10.GetEnumerator();
									try
									{
										while (<>s__11.MoveNext())
										{
											<card>5__12 = <>s__11.Current;
											if (!((Object)(object)<card>5__12 == (Object)null) && !((Object)(object)((Component)<card>5__12).gameObject == (Object)null))
											{
												<modName>5__13 = DC.ExtractModName(((Object)((Component)<card>5__12).gameObject).name);
												<modSet>5__9.Add(<modName>5__13);
												<modName>5__13 = null;
												<card>5__12 = null;
											}
										}
									}
									finally
									{
										((IDisposable)<>s__11).Dispose();
									}
									<>s__11 = default(List<CardInfo>.Enumerator);
								}
								<allCards>5__10 = null;
							}
							catch
							{
								if ((Object)(object)CardChoice.instance != (Object)null && CardChoice.instance.cards != null)
								{
									<>s__14 = CardChoice.instance.cards;
									for (<>s__15 = 0; <>s__15 < <>s__14.Length; <>s__15++)
									{
										<card>5__16 = <>s__14[<>s__15];
										if (!((Object)(object)<card>5__16 == (Object)null))
										{
											<modName>5__17 = DC.ExtractModName(((Object)((Component)<card>5__16).gameObject).name);
											<modSet>5__9.Add(<modName>5__17);
											<modName>5__17 = null;
											<card>5__16 = null;
										}
									}
									<>s__14 = null;
								}
							}
							try
							{
								<hidden>5__18 = Cards.instance.HiddenCards;
								if (<hidden>5__18 != null)
								{
									<>s__19 = <hidden>5__18.GetEnumerator();
									try
									{
										while (<>s__19.MoveNext())
										{
											<card>5__20 = <>s__19.Current;
											if (!((Object)(object)<card>5__20 == (Object)null) && !((Object)(object)((Component)<card>5__20).gameObject == (Object)null))
											{
												<modName>5__21 = DC.ExtractModName(((Object)((Component)<card>5__20).gameObject).name);
												<modSet>5__9.Add(<modName>5__21);
												<modName>5__21 = null;
												<card>5__20 = null;
											}
										}
									}
									finally
									{
										if (<>s__19 != null)
										{
											<>s__19.Dispose();
										}
									}
									<>s__19 = null;
								}
								<hidden>5__18 = null;
							}
							catch
							{
							}
							RT.Log("WinRateCache: detected " + <modSet>5__9.Count + " installed mods");
							if (<modSet>5__9.Count > 0)
							{
								<parts>5__22 = new List<string>();
								<>s__23 = <modSet>5__9.GetEnumerator();
								try
								{
									while (<>s__23.MoveNext())
									{
										<mod>5__24 = <>s__23.Current;
										<parts>5__22.Add(Uri.EscapeDataString(<mod>5__24));
										<mod>5__24 = null;
									}
								}
								finally
								{
									((IDisposable)<>s__23).Dispose();
								}
								<>s__23 = default(HashSet<string>.Enumerator);
								<modsParam>5__5 = "?mods=" + string.Join(",", <parts>5__22.ToArray());
								<parts>5__22 = null;
							}
							<modSet>5__9 = null;
						}
						catch (Exception ex)
						{
							<ex>5__25 = ex;
							RT.LogError("WinRateCache: mod detection error: " + <ex>5__25.Message);
						}
						<url>5__6 = RT.ApiUrlValue + "/api/cards/winrates" + <modsParam>5__5;
						RT.Log("WinRateCache: loading from " + <url>5__6);
						<serverSuccess>5__7 = false;
						<req>5__26 = UnityWebRequest.Get(<url>5__6);
						<>1__state = -3;
						<req>5__26.timeout = 15;
						<>2__current = <req>5__26.SendWebRequest();
						<>1__state = 3;
						return true;
						IL_00da:
						<lastCardCount>5__2 = 0;
						<stableTime>5__3 = 0f;
						<stabilizeWaited>5__4 = 0f;
						goto IL_0227;
						IL_0227:
						if (<stabilizeWaited>5__4 < 45f)
						{
							<currentCount>5__8 = 0;
							try
							{
								if ((Object)(object)CardChoice.instance != (Object)null && CardChoice.instance.cards != null)
								{
									<currentCount>5__8 = CardChoice.instance.cards.Length;
								}
							}
							catch
							{
							}
							if (<currentCount>5__8 > 0 && <currentCount>5__8 == <lastCardCount>5__2)
							{
								<stableTime>5__3 += 1f;
								if (<stableTime>5__3 >= 15f)
								{
									RT.LogDebug("WinRateCache: card count stabilized at " + <currentCount>5__8 + " after " + <stabilizeWaited>5__4 + "s");
									goto IL_023d;
								}
							}
							else
							{
								<stableTime>5__3 = 0f;
								<lastCardCount>5__2 = <currentCount>5__8;
							}
							<>2__current = (object)new WaitForSeconds(1f);
							<>1__state = 2;
							return true;
						}
						goto IL_023d;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<req>5__26 != null)
				{
					((IDisposable)<req>5__26).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static Dictionary<string, WinRateEntry> _cache = new Dictionary<string, WinRateEntry>();

		private static bool _loaded = false;

		private static bool _loading = false;

		public static bool IsLoaded => _loaded;

		private static string CacheFilePath
		{
			get
			{
				string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)RT.Instance).Info.Location);
				return Path.Combine(directoryName, "winrate_cache.json");
			}
		}

		public static string MakeKey(string cardName, string modName, string rarity)
		{
			return cardName + "|" + (modName ?? "Vanilla") + "|" + (rarity ?? "Common");
		}

		public static WinRateEntry Get(string key)
		{
			if (_cache.TryGetValue(key, out var value))
			{
				return value;
			}
			return null;
		}

		public static List<string> FindSimilar(string cardName, int max)
		{
			List<string> list = new List<string>();
			if (string.IsNullOrEmpty(cardName))
			{
				return list;
			}
			string value = cardName.ToLowerInvariant();
			foreach (KeyValuePair<string, WinRateEntry> item in _cache)
			{
				if (list.Count >= max)
				{
					break;
				}
				if (item.Key.ToLowerInvariant().Contains(value))
				{
					list.Add(item.Key + "(wr=" + item.Value.round_win_rate + ")");
				}
			}
			return list;
		}

		public static void Clear()
		{
			_cache.Clear();
			_loaded = false;
		}

		public static void Load()
		{
			if (!_loading)
			{
				((MonoBehaviour)RT.Instance).StartCoroutine(LoadCoroutine());
			}
		}

		private static void SaveToFile(string rawJson)
		{
			try
			{
				File.WriteAllText(CacheFilePath, rawJson, Encoding.UTF8);
				RT.LogDebug("WinRateCache: saved to " + CacheFilePath);
			}
			catch (Exception ex)
			{
				RT.LogError("WinRateCache save error: " + ex.Message);
			}
		}

		private static string LoadFromFile()
		{
			try
			{
				if (File.Exists(CacheFilePath))
				{
					string text = File.ReadAllText(CacheFilePath, Encoding.UTF8);
					if (!string.IsNullOrEmpty(text) && text.Length > 10)
					{
						RT.LogDebug("WinRateCache: loaded from file, length=" + text.Length);
						return text;
					}
				}
			}
			catch (Exception ex)
			{
				RT.LogError("WinRateCache file read error: " + ex.Message);
			}
			return null;
		}

		[IteratorStateMachine(typeof(<LoadCoroutine>d__14))]
		private static IEnumerator LoadCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadCoroutine>d__14(0);
		}

		private static void ParseResponse(string json)
		{
			_cache.Clear();
			if (string.IsNullOrEmpty(json) || json.Length < 3)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			while (num < json.Length)
			{
				int num4 = json.IndexOf('{', num);
				if (num4 < 0)
				{
					break;
				}
				int num5 = json.IndexOf('}', num4);
				if (num5 < 0)
				{
					break;
				}
				string text = json.Substring(num4 + 1, num5 - num4 - 1);
				num = num5 + 1;
				num2++;
				try
				{
					string text2 = ExtractString(text, "cn");
					string text3 = ExtractString(text, "mn");
					string text4 = ExtractString(text, "r");
					float pick_rate = ExtractFloat(text, "pr");
					float round_win_rate = ExtractFloat(text, "wr");
					if (num2 <= 3)
					{
						RT.Log("WinRateCache PARSE[" + num2 + "] raw: {" + ((text.Length > 200) ? text.Substring(0, 200) : text) + "}");
						RT.Log("WinRateCache PARSE[" + num2 + "] => cn=\"" + (text2 ?? "NULL") + "\" mn=\"" + (text3 ?? "NULL") + "\" r=\"" + (text4 ?? "NULL") + "\" pr=" + pick_rate + " wr=" + round_win_rate);
					}
					if (!string.IsNullOrEmpty(text2))
					{
						string key = MakeKey(text2, text3, text4);
						_cache[key] = new WinRateEntry
						{
							pick_rate = pick_rate,
							round_win_rate = round_win_rate
						};
					}
					else
					{
						num3++;
					}
				}
				catch (Exception ex)
				{
					num3++;
					if (num3 <= 3)
					{
						RT.LogError("WinRateCache PARSE error #" + num2 + ": " + ex.Message);
					}
				}
			}
			RT.Log("WinRateCache ParseResponse done: " + num2 + " objects, " + _cache.Count + " cached, " + num3 + " errors");
		}

		private static string ExtractString(string obj, string field)
		{
			string text = "\"" + field + "\":\"";
			int num = obj.IndexOf(text);
			if (num < 0)
			{
				return null;
			}
			int num2 = num + text.Length;
			int num3 = obj.IndexOf('"', num2);
			if (num3 < 0)
			{
				return null;
			}
			return obj.Substring(num2, num3 - num2);
		}

		private static float ExtractFloat(string obj, string field)
		{
			string text = "\"" + field + "\":";
			int num = obj.IndexOf(text);
			if (num < 0)
			{
				return 0f;
			}
			int i;
			for (i = num + text.Length; i < obj.Length && obj[i] == ' '; i++)
			{
			}
			if (i < obj.Length && obj[i] == '"')
			{
				i++;
			}
			int j;
			for (j = i; j < obj.Length && (char.IsDigit(obj[j]) || obj[j] == '.' || obj[j] == '-'); j++)
			{
			}
			if (j == i)
			{
				return 0f;
			}
			string s = obj.Substring(i, j - i);
			if (float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			return 0f;
		}
	}
	public class RoundCollector
	{
		public List<PickEvent> Picks = new List<PickEvent>();

		public List<CardData> Added = new List<CardData>();

		public List<CardData> Removed = new List<CardData>();

		public int PointsWon;

		public int PointsPlayed;

		public void Reset()
		{
			Picks.Clear();
			Added.Clear();
			Removed.Clear();
			PointsWon = 0;
			PointsPlayed = 0;
		}

		public void AddPick(PickEvent pick)
		{
			Picks.Add(pick);
			RT.LogDebug($"Collector: Added pick {pick.card_name}, total picks: {Picks.Count}");
		}

		public void AddAdded(CardData card)
		{
			Added.Add(card);
			RT.LogDebug($"Collector: Added card {card.card_name}, total added: {Added.Count}");
		}

		public void AddRemoved(CardData card)
		{
			Removed.Add(card);
			RT.LogDebug($"Collector: Removed card {card.card_name}, total removed: {Removed.Count}");
		}
	}
	[HarmonyPatch(typeof(CardChoice), "Pick")]
	internal class CardChoicePatch
	{
		private static FieldInfo SpawnedCardsField = AccessTools.Field(typeof(CardChoice), "spawnedCards");

		private static FieldInfo PickerTypeField = AccessTools.Field(typeof(CardChoice), "pickerType");

		private static void Postfix(CardChoice __instance, GameObject pickedCard, int ___pickrID)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Invalid comparison between Unknown and I4
			if (!RT.EnableTracking.Value || (Object)(object)pickedCard == (Object)null || PhotonNetwork.OfflineMode)
			{
				return;
			}
			try
			{
				PickerType val = (PickerType)(PickerTypeField?.GetValue(__instance));
				Player val2 = null;
				if ((int)val == 0)
				{
					Player[] playersInTeam = PlayerManager.instance.GetPlayersInTeam(___pickrID);
					val2 = ((playersInTeam != null && playersInTeam.Length != 0) ? playersInTeam[0] : null);
				}
				else if (___pickrID < PlayerManager.instance.players.Count)
				{
					val2 = PlayerManager.instance.players[___pickrID];
				}
				if ((Object)(object)val2 == (Object)null || !val2.data.view.IsMine)
				{
					return;
				}
				CardData cardData = DC.FromGO(pickedCard);
				if (cardData == null || string.IsNullOrEmpty(cardData.card_name))
				{
					return;
				}
				List<GameObject> list = SpawnedCardsField?.GetValue(__instance) as List<GameObject>;
				List<CardData> list2 = new List<CardData>();
				int num = 0;
				if (list != null)
				{
					for (int i = 0; i < list.Count; i++)
					{
						GameObject val3 = list[i];
						if ((Object)(object)val3 == (Object)null)
						{
							continue;
						}
						CardData cardData2 = DC.FromGO(val3);
						if (cardData2 != null && !string.IsNullOrEmpty(cardData2.card_name))
						{
							list2.Add(cardData2);
							if ((Object)(object)val3 == (Object)(object)pickedCard)
							{
								num = list2.Count - 1;
							}
						}
					}
				}
				PickEvent pick = new PickEvent
				{
					card_name = cardData.card_name,
					mod_name = cardData.mod_name,
					rarity = cardData.rarity,
					description = cardData.description,
					color_theme = cardData.color_theme,
					stats = cardData.stats,
					position = num,
					pick_number = RT.NextPickNumber(),
					offered_cards = list2
				};
				RT.Collector.AddPick(pick);
				if (RT._picksToChoose == 0 && list2.Count > 0)
				{
					RT._picksToChoose = list2.Count;
					RT.LogDebug($"Detected picks_to_choose={RT._picksToChoose}");
				}
				RT.Log($"Pick: {cardData.card_name} (pos {num + 1} of {list2.Count})");
			}
			catch (Exception ex)
			{
				RT.LogError("CardChoice.Pick error: " + ex.Message);
			}
		}
	}
	[HarmonyPatch(typeof(CardChoice), "StartPick")]
	internal class StartPickPatch
	{
		private static void Prefix(int picksToSet)
		{
			if (!RT.EnableTracking.Value || PhotonNetwork.OfflineMode)
			{
				return;
			}
			try
			{
				if (RT._drawsPerPickPhase == 0 && picksToSet > 0)
				{
					RT._drawsPerPickPhase = picksToSet;
					RT.LogDebug($"Detected draws_per_pick_phase={picksToSet}");
				}
			}
			catch (Exception ex)
			{
				RT.LogError("StartPick patch error: " + ex.Message);
			}
		}
	}
	[HarmonyPatch]
	internal class AssignCardPatch
	{
		private static MethodBase TargetMethod()
		{
			Type typeFromHandle = typeof(Cards);
			MethodInfo methodInfo = AccessTools.Method(typeFromHandle, "RPCA_AssignCard", new Type[7]
			{
				typeof(string),
				typeof(int),
				typeof(bool),
				typeof(string),
				typeof(float),
				typeof(float),
				typeof(bool)
			}, (Type[])null);
			if (methodInfo == null)
			{
				methodInfo = AccessTools.Method(typeFromHandle, "RPCA_AssignCard", new Type[6]
				{
					typeof(string),
					typeof(int),
					typeof(bool),
					typeof(string),
					typeof(float),
					typeof(float)
				}, (Type[])null);
			}
			return methodInfo;
		}

		private static void Postfix(string cardObjectName, int playerID, bool reassign)
		{
			if (!RT.EnableTracking.Value || reassign || PhotonNetwork.OfflineMode)
			{
				return;
			}
			try
			{
				Player val = PlayerManager.instance.players.Find((Player p) => p.playerID == playerID);
				if (!((Object)(object)val == (Object)null) && val.data.view.IsMine)
				{
					CardData cardData = DC.FromObjectName(cardObjectName);
					if (cardData != null && !string.IsNullOrEmpty(cardData.card_name))
					{
						RT.Collector.AddAdded(cardData);
						RT.Log("Added: " + cardData.card_name);
					}
				}
			}
			catch (Exception ex)
			{
				RT.LogError("RPCA_AssignCard error: " + ex.Message);
			}
		}
	}
	internal static class CardTracker
	{
		private static Dictionary<string, List<CardInfo>> _savedCardsById = new Dictionary<string, List<CardInfo>>();

		private static int _callCounter = 0;

		private static Stack<string> _callIdStack = new Stack<string>();

		public static void ClearAll()
		{
			_savedCardsById.Clear();
			_callCounter = 0;
			_callIdStack.Clear();
		}

		public static void RemoveAllCardsPrefix(Player player, bool clearBar)
		{
			if ((Object)(object)player == (Object)null || !((Object)(object)player.data?.view != (Object)null) || !player.data.view.IsMine || !RT.EnableTracking.Value || PhotonNetwork.OfflineMode)
			{
				return;
			}
			try
			{
				_callCounter++;
				string text = $"{player.playerID}_{_callCounter}_{Time.frameCount}";
				_callIdStack.Push(text);
				List<CardInfo> list = new List<CardInfo>();
				List<string> list2 = new List<string>();
				if (player.data?.currentCards != null)
				{
					foreach (CardInfo currentCard in player.data.currentCards)
					{
						if ((Object)(object)currentCard != (Object)null)
						{
							list.Add(currentCard);
							list2.Add(currentCard.cardName);
						}
					}
				}
				_savedCardsById[text] = list;
				if (_savedCardsById.Count > 100)
				{
					List<string> list3 = _savedCardsById.Keys.Take(_savedCardsById.Count - 50).ToList();
					foreach (string item in list3)
					{
						_savedCardsById.Remove(item);
					}
				}
				RT.LogDebug(string.Format("RemoveAllCardsPrefix: callId={0}, stack={1}, cards=[{2}]", text, _callIdStack.Count, string.Join(", ", list2)));
			}
			catch (Exception ex)
			{
				RT.LogError("RemoveAllCardsPrefix error: " + ex.Message);
			}
		}

		public static void AddCardsPostfix(Player player, CardInfo[] cards, bool[] reassigns, string[] twoLetterCodes, float[] forceDisplays, float[] forceDisplayDelays, bool addToCardBar)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			string text = null;
			if (_callIdStack.Count > 0)
			{
				text = _callIdStack.Pop();
			}
			if (!((Object)(object)player.data?.view != (Object)null) || !player.data.view.IsMine)
			{
				return;
			}
			List<CardInfo> value = null;
			if (!string.IsNullOrEmpty(text) && _savedCardsById.TryGetValue(text, out value))
			{
				_savedCardsById.Remove(text);
			}
			List<string> list = new List<string>();
			if (cards != null)
			{
				for (int i = 0; i < cards.Length; i++)
				{
					if ((Object)(object)cards[i] != (Object)null)
					{
						bool flag = reassigns != null && i < reassigns.Length && reassigns[i];
						list.Add(cards[i].cardName + "(" + (flag ? "R" : "N") + ")");
					}
				}
			}
			List<string> values = value?.Select((CardInfo c) => c.cardName).ToList() ?? new List<string>();
			RT.LogDebug(string.Format("AddCardsPostfix: callId={0}, stack={1}, saved=[{2}], new=[{3}]", text, _callIdStack.Count, string.Join(", ", values), string.Join(", ", list)));
			if (!RT.EnableTracking.Value)
			{
				return;
			}
			if (cards == null || value == null || value.Count == 0)
			{
				RT.LogDebug("AddCardsPostfix: No data to process");
			}
			else
			{
				if (PhotonNetwork.OfflineMode)
				{
					return;
				}
				try
				{
					Dictionary<string, int> dictionary = new Dictionary<string, int>();
					for (int j = 0; j < cards.Length; j++)
					{
						if ((Object)(object)cards[j] != (Object)null && reassigns != null && j < reassigns.Length && reassigns[j])
						{
							string name = ((Object)cards[j]).name;
							if (!dictionary.ContainsKey(name))
							{
								dictionary[name] = 0;
							}
							dictionary[name]++;
						}
					}
					foreach (CardInfo item in value)
					{
						string name2 = ((Object)item).name;
						if (dictionary.ContainsKey(name2) && dictionary[name2] > 0)
						{
							dictionary[name2]--;
							continue;
						}
						RT.LogDebug("AddCardsPostfix: REMOVED " + item.cardName + " (name=" + name2 + ")");
						GameObject gameObject = ((Component)item).gameObject;
						CardData cardData = DC.FromInfo(item, (gameObject != null) ? ((Object)gameObject).name : null);
						if (cardData != null && !string.IsNullOrEmpty(cardData.card_name))
						{
							RT.Collector.AddRemoved(cardData);
							RT.Log("Removed: " + cardData.card_name);
						}
					}
				}
				catch (Exception ex)
				{
					RT.LogError("AddCardsPostfix error: " + ex.Message);
				}
			}
		}
	}
	internal static class DC
	{
		public static CardData FromGO(GameObject obj)
		{
			if ((Object)(object)obj == (Object)null)
			{
				return null;
			}
			CardInfo component = obj.GetComponent<CardInfo>();
			return ((Object)(object)component != (Object)null) ? FromInfo(component, ((Object)obj).name) : null;
		}

		public static CardData FromObjectName(string objectName)
		{
			if (string.IsNullOrEmpty(objectName))
			{
				return null;
			}
			try
			{
				CardInfo cardWithObjectName = Cards.instance.GetCardWithObjectName(objectName);
				if ((Object)(object)cardWithObjectName != (Object)null)
				{
					return FromInfo(cardWithObjectName, objectName);
				}
			}
			catch
			{
			}
			return ParseObjectName(objectName);
		}

		public static CardData ParseObjectName(string objectName)
		{
			string mod_name = ExtractModName(objectName);
			string card_name = objectName;
			if (objectName.StartsWith("__"))
			{
				string[] array = objectName.Split(new string[1] { "__" }, StringSplitOptions.RemoveEmptyEntries);
				if (array.Length >= 2)
				{
					card_name = array[1];
				}
			}
			return new CardData
			{
				card_name = card_name,
				mod_name = mod_name,
				rarity = "Common",
				description = null,
				color_theme = null,
				card_color = null,
				stats = new List<Stat>()
			};
		}

		public static string ExtractModName(string objectName)
		{
			if (string.IsNullOrEmpty(objectName))
			{
				return "Vanilla";
			}
			string text = objectName;
			int num = text.IndexOf("(Clone)");
			if (num >= 0)
			{
				text = text.Substring(0, num).Trim();
			}
			if (text.StartsWith("__"))
			{
				string[] array = text.Split(new string[1] { "__" }, StringSplitOptions.RemoveEmptyEntries);
				if (array.Length >= 1)
				{
					return array[0];
				}
			}
			return "Vanilla";
		}

		public static CardData FromInfo(CardInfo info, string objectName = null)
		{
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)info == (Object)null)
			{
				return null;
			}
			string mod_name = "Vanilla";
			object obj = objectName;
			if (obj == null)
			{
				GameObject gameObject = ((Component)info).gameObject;
				obj = ((gameObject != null) ? ((Object)gameObject).name : null) ?? "";
			}
			string text = (string)obj;
			if (text.StartsWith("__"))
			{
				string[] array = text.Split(new string[1] { "__" }, StringSplitOptions.RemoveEmptyEntries);
				if (array.Length >= 1)
				{
					mod_name = array[0];
				}
			}
			List<Stat> list = new List<Stat>();
			try
			{
				if (info.cardStats != null)
				{
					CardInfoStat[] cardStats = info.cardStats;
					foreach (CardInfoStat val in cardStats)
					{
						list.Add(new Stat
						{
							stat = (val.stat ?? ""),
							amount = (val.amount ?? ""),
							positive = val.positive
						});
					}
				}
			}
			catch
			{
			}
			string description = null;
			try
			{
				description = info.cardDestription;
			}
			catch
			{
			}
			string rarity = "Common";
			try
			{
				rarity = ((object)(Rarity)(ref info.rarity)).ToString();
			}
			catch
			{
			}
			string color_theme = null;
			try
			{
				color_theme = ((object)(CardThemeColorType)(ref info.colorTheme)).ToString();
			}
			catch
			{
			}
			string card_color = null;
			try
			{
				card_color = "#" + ColorUtility.ToHtmlStringRGB(info.cardColor);
			}
			catch
			{
			}
			string card_color_bg = null;
			try
			{
				if ((Object)(object)CardChoice.instance != (Object)null)
				{
					Color cardColor = CardChoice.instance.GetCardColor2(info.colorTheme);
					card_color_bg = "#" + ColorUtility.ToHtmlStringRGB(cardColor);
				}
			}
			catch
			{
			}
			return new CardData
			{
				card_name = (info.cardName ?? ""),
				mod_name = mod_name,
				rarity = rarity,
				description = description,
				color_theme = color_theme,
				card_color = card_color,
				card_color_bg = card_color_bg,
				stats = list
			};
		}
	}
	public class CardData
	{
		public string card_name;

		public string mod_name;

		public string rarity;

		public string description;

		public string color_theme;

		public string card_color;

		public string card_color_bg;

		public List<Stat> stats = new List<Stat>();
	}
	public class PickEvent : CardData
	{
		public int position;

		public int pick_number;

		public List<CardData> offered_cards = new List<CardData>();
	}
	public class Stat
	{
		public string stat;

		public string amount;

		public bool positive;
	}
	public class RoundReport
	{
		public string report_id;

		public string session_id;

		public int round_number;

		public string steam_id;

		public string nickname;

		public string player_color;

		public bool is_round_winner;

		public int points_won;

		public int points_played;

		public List<CardData> current_cards = new List<CardData>();

		public List<PickEvent> picks = new List<PickEvent>();

		public List<CardData> offered_cards = new List<CardData>();

		public List<CardData> added = new List<CardData>();

		public List<CardData> removed = new List<CardData>();

		public List<PlayerInfo> players = new List<PlayerInfo>();

		public string game_mode;

		public int player_count;

		public int? points_to_win_round;

		public int? rounds_to_win_game;

		public int game_continued_count;

		public int picks_to_choose;

		public int draws_per_pick_phase;

		public bool is_game_over;

		public bool is_legitimate_game_over;

		public string tracker_version;
	}
	public class PlayerInfo
	{
		public int player_id;

		public string steam_id;

		public string nickname;

		public string player_color;
	}
	public class WinRateEntry
	{
		public float pick_rate;

		public float round_win_rate;
	}
	public class EloPlayerData
	{
		public string steam_id;

		public float before;

		public float after;

		public float change;
	}
	internal static class Networking
	{
		[CompilerGenerated]
		private sealed class <FetchLocalEloCoroutine>d__12 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string steamId;

			private string <url>5__1;

			private UnityWebRequest <req>5__2;

			private string <text>5__3;

			private float <elo>5__4;

			private int <games>5__5;

			private int <displayElo>5__6;

			private Exception <ex>5__7;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <FetchLocalEloCoroutine>d__12(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<url>5__1 = null;
				<req>5__2 = null;
				<text>5__3 = null;
				<ex>5__7 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				bool result;
				try
				{
					switch (<>1__state)
					{
					default:
						result = false;
						break;
					case 0:
						<>1__state = -1;
						<url>5__1 = RT.ApiUrlValue + "/api/elo/me?steam_id=" + steamId;
						<req>5__2 = UnityWebRequest.Get(<url>5__1);
						<>1__state = -3;
						<req>5__2.timeout = 10;
						<>2__current = <req>5__2.SendWebRequest();
						<>1__state = 1;
						result = true;
						break;
					case 1:
						<>1__state = -3;
						if (<req>5__2.isNetworkError || <req>5__2.isHttpError)
						{
							RT.LogDebug("FetchLocalElo error: " + <req>5__2.error);
							result = false;
						}
						else
						{
							<text>5__3 = <req>5__2.downloadHandler.text;
							if (!string.IsNullOrEmpty(<text>5__3))
							{
								try
								{
									<elo>5__4 = ExtractFloat(<text>5__3, "elo");
									<games>5__5 = ExtractInt(<text>5__3, "elo_games");
									if (<elo>5__4 > 0f)
									{
										<displayElo>5__6 = (int)Math.Round(<elo>5__4);
										GameMessage.Show($"ELO: {<displayElo>5__6}  ({<games>5__5} games)", GameMessageType.Info, 4f);
										RT.Log($"Current ELO: {<elo>5__4:F1} ({<games>5__5} games)");
									}
								}
								catch (Exception ex)
								{
									<ex>5__7 = ex;
									RT.LogError("FetchLocalElo parse: " + <ex>5__7.Message);
								}
								<text>5__3 = null;
								<>m__Finally1();
								<req>5__2 = null;
								result = false;
								break;
							}
							result = false;
						}
						<>m__Finally1();
						break;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<req>5__2 != null)
				{
					((IDisposable)<req>5__2).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <PollEloFromRoomProperties>d__5 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private string <mySteamId>5__1;

			private string <myKey>5__2;

			private float <elapsed>5__3;

			private Hashtable <roomProps>5__4;

			private string <value>5__5;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <PollEloFromRoomProperties>d__5(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<mySteamId>5__1 = null;
				<myKey>5__2 = null;
				<roomProps>5__4 = null;
				<value>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_012c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0136: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<mySteamId>5__1 = RT.GetSteamId();
					if (string.IsNullOrEmpty(<mySteamId>5__1))
					{
						return false;
					}
					<myKey>5__2 = "rt_elo_" + <mySteamId>5__1;
					<elapsed>5__3 = 0f;
					RT.LogDebug("ELO poll: waiting for room prop '" + <myKey>5__2 + "'");
					break;
				case 1:
					<>1__state = -1;
					<elapsed>5__3 += 0.5f;
					<roomProps>5__4 = null;
					break;
				}
				if (<elapsed>5__3 < 10f)
				{
					if (RT._eloShownThisGame)
					{
						return false;
					}
					if (PhotonNetwork.CurrentRoom == null)
					{
						RT.LogDebug("ELO poll: room is null, stopping");
						return false;
					}
					<roomProps>5__4 = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties;
					if (<roomProps>5__4 != null && ((Dictionary<object, object>)(object)<roomProps>5__4).ContainsKey((object)<myKey>5__2))
					{
						<value>5__5 = <roomProps>5__4[(object)<myKey>5__2] as string;
						if (!string.IsNullOrEmpty(<value>5__5))
						{
							ProcessEloPropertyValue(<value>5__5, <mySteamId>5__1);
							return false;
						}
						<value>5__5 = null;
					}
					<>2__current = (object)new WaitForSeconds(0.5f);
					<>1__state = 1;
					return true;
				}
				RT.LogDebug("ELO poll: timeout, falling back to HTTP check");
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private const string ELO_PROP_PREFIX = "rt_elo_";

		private const float ELO_POLL_INTERVAL = 0.5f;

		private const float ELO_POLL_TIMEOUT = 10f;

		public static void BroadcastEloResults(List<EloPlayerData> allElo)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			if (PhotonNetwork.OfflineMode || allElo == null || allElo.Count == 0)
			{
				return;
			}
			if (PhotonNetwork.CurrentRoom == null)
			{
				RT.LogError("BroadcastEloResults: no current room");
				return;
			}
			Hashtable val = new Hashtable();
			int num = 0;
			foreach (EloPlayerData item in allElo)
			{
				if (!string.IsNullOrEmpty(item.steam_id))
				{
					string text = "rt_elo_" + item.steam_id;
					string text3 = (string)(val[(object)text] = string.Format(CultureInfo.InvariantCulture, "{0}|{1}|{2}", item.before, item.after, item.change));
					num++;
					RT.Log("BroadcastElo prop: ****" + item.steam_id.Substring(Math.Max(0, item.steam_id.Length - 4)) + " = " + text3);
				}
			}
			if (num > 0)
			{
				PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
				RT.Log($"BroadcastElo: set {num} room properties");
			}
		}

		public static void StartEloPropertyPoll()
		{
			if (!PhotonNetwork.OfflineMode && RT.EnableTracking.Value && RT.ShowEloNotifications.Value && !RT._eloShownThisGame)
			{
				((MonoBehaviour)RT.Instance).StartCoroutine(PollEloFromRoomProperties());
			}
		}

		[IteratorStateMachine(typeof(<PollEloFromRoomProperties>d__5))]
		private static IEnumerator PollEloFromRoomProperties()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <PollEloFromRoomProperties>d__5(0);
		}

		private static void ProcessEloPropertyValue(string value, string mySteamId)
		{
			try
			{
				string[] array = value.Split(new char[1] { '|' });
				if (array.Length < 3)
				{
					return;
				}
				float num = float.Parse(array[0], CultureInfo.InvariantCulture);
				float num2 = float.Parse(array[1], CultureInfo.InvariantCulture);
				float num3 = float.Parse(array[2], CultureInfo.InvariantCulture);
				RT.Log($"ELO from room prop for ****{mySteamId.Substring(Math.Max(0, mySteamId.Length - 4))}: {num:F1} -> {num2:F1} ({num3:F1})");
				if (!RT._eloShownThisGame)
				{
					RT._eloShownThisGame = true;
					if (num3 != 0f && RT.ShowEloNotifications.Value)
					{
						int num4 = (int)Math.Round(num);
						int num5 = (int)Math.Round(num3);
						int num6 = (int)Math.Round(num2);
						string text = ((num5 > 0) ? "+" : "");
						GameMessageType type = ((num5 > 0) ? GameMessageType.Success : GameMessageType.Warning);
						GameMessage.Show($"ELO {num4} > {text}{num5} > {num6}", type, 5f);
						RT.Log($"ELO change (room prop): {num:F1} > {text}{num3:F1} > {num2:F1}");
					}
				}
			}
			catch (Exception ex)
			{
				RT.LogError("ELO prop parse error: " + ex.Message);
			}
		}

		[UnboundRPC]
		public static void RPCA_CardRemoved(int playerID, string cardName, string cardObjectName)
		{
			RT.LogDebug($"RPCA_CardRemoved (ignored): player={playerID}, card={cardName}");
		}

		[UnboundRPC]
		public static void RPCA_ShareSteamId(int playerID, string steamId)
		{
			if (!string.IsNullOrEmpty(steamId))
			{
				RT.PlayerSteamIds[playerID] = steamId;
				RT.LogDebug($"Received Steam ID for player {playerID}: {steamId.Substring(0, Math.Min(4, steamId.Length))}****");
			}
		}

		[UnboundRPC]
		public static void RPCA_ShareEloResult(string data)
		{
		}

		public static void BroadcastSteamId()
		{
			if (!PhotonNetwork.OfflineMode)
			{
				Player localPlayer = RT.GetLocalPlayer();
				string steamId = RT.GetSteamId();
				if ((Object)(object)localPlayer != (Object)null && !string.IsNullOrEmpty(steamId))
				{
					NetworkingManager.RPC(typeof(Networking), "RPCA_ShareSteamId", new object[2] { localPlayer.playerID, steamId });
				}
			}
		}

		public static void FetchLocalElo()
		{
			string steamId = RT.GetSteamId();
			if (!string.IsNullOrEmpty(steamId) && RT.EnableTracking.Value && RT.ShowEloNotifications.Value)
			{
				((MonoBehaviour)RT.Instance).StartCoroutine(FetchLocalEloCoroutine(steamId));
			}
		}

		[IteratorStateMachine(typeof(<FetchLocalEloCoroutine>d__12))]
		private static IEnumerator FetchLocalEloCoroutine(string steamId)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <FetchLocalEloCoroutine>d__12(0)
			{
				steamId = steamId
			};
		}

		private static float ExtractFloat(string text, string field)
		{
			string text2 = "\"" + field + "\":";
			int num = text.IndexOf(text2);
			if (num < 0)
			{
				return 0f;
			}
			int i;
			for (i = num + text2.Length; i < text.Length && text[i] == ' '; i++)
			{
			}
			int j = i;
			if (j < text.Length && text[j] == '-')
			{
				j++;
			}
			for (; j < text.Length && char.IsDigit(text[j]); j++)
			{
			}
			if (j < text.Length && text[j] == '.')
			{
				for (j++; j < text.Length && char.IsDigit(text[j]); j++)
				{
				}
			}
			if (j == i)
			{
				return 0f;
			}
			string s = text.Substring(i, j - i);
			if (float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			return 0f;
		}

		private static int ExtractInt(string text, string field)
		{
			string text2 = "\"" + field + "\":";
			int num = text.IndexOf(text2);
			if (num < 0)
			{
				return 0;
			}
			int i;
			for (i = num + text2.Length; i < text.Length && text[i] == ' '; i++)
			{
			}
			int j = i;
			if (j < text.Length && text[j] == '-')
			{
				j++;
			}
			for (; j < text.Length && char.IsDigit(text[j]); j++)
			{
			}
			if (j == i)
			{
				return 0;
			}
			string s = text.Substring(i, j - i);
			if (int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			return 0;
		}

		public static void EnsureSteamInfo()
		{
			if (RT._steamInfoTried)
			{
				return;
			}
			RT._steamInfoTried = true;
			try
			{
				Type type = Type.GetType("SteamManager, Assembly-CSharp");
				if (type == null)
				{
					return;
				}
				PropertyInfo property = type.GetProperty("Initialized", BindingFlags.Static | BindingFlags.Public);
				if (property == null || !(bool)property.GetValue(null))
				{
					return;
				}
				Type type2 = Type.GetType("Steamworks.SteamUser, Assembly-CSharp-firstpass") ?? Type.GetType("Steamworks.SteamUser, com.rlabrecque.steamworks.net");
				if (type2 != null)
				{
					MethodInfo method = type2.GetMethod("GetSteamID", BindingFlags.Static | BindingFlags.Public);
					if (method != null)
					{
						object obj = method.Invoke(null, null);
						if (obj != null)
						{
							RT._steamId = obj.ToString();
						}
					}
				}
				Type type3 = Type.GetType("Steamworks.SteamFriends, Assembly-CSharp-firstpass") ?? Type.GetType("Steamworks.SteamFriends, com.rlabrecque.steamworks.net");
				if (!(type3 != null))
				{
					return;
				}
				MethodInfo method2 = type3.GetMethod("GetPersonaName", BindingFlags.Static | BindingFlags.Public);
				if (method2 != null)
				{
					object obj2 = method2.Invoke(null, null);
					if (obj2 != null)
					{
						RT._steamNickname = obj2.ToString();
					}
				}
			}
			catch (Exception ex)
			{
				RT.LogError("Steam info error: " + ex.Message);
			}
		}

		public static void CollectSessionPlayers()
		{
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			RT.SessionPlayers.Clear();
			foreach (Player player in PlayerManager.instance.players)
			{
				if ((Object)(object)player == (Object)null || (Object)(object)player.data == (Object)null)
				{
					continue;
				}
				string value = null;
				if ((Object)(object)player.data.view != (Object)null && player.data.view.IsMine)
				{
					value = RT.GetSteamId();
				}
				else
				{
					RT.PlayerSteamIds.TryGetValue(player.playerID, out value);
				}
				string nickname = null;
				try
				{
					if ((Object)(object)player.data.view != (Object)null && player.data.view.Owner != null)
					{
						nickname = player.data.view.Owner.NickName;
					}
				}
				catch
				{
				}
				string player_color = null;
				try
				{
					PlayerSkin playerSkinColors = PlayerSkinBank.GetPlayerSkinColors(player.playerID);
					player_color = "#" + ColorUtility.ToHtmlStringRGB(playerSkinColors.color);
				}
				catch
				{
				}
				RT.SessionPlayers.Add(new PlayerInfo
				{
					player_id = player.playerID,
					steam_id = value,
					nickname = nickname,
					player_color = player_color
				});
			}
			RT.LogDebug($"Collected {RT.SessionPlayers.Count} session players, " + $"{RT.SessionPlayers.Count((PlayerInfo p) => p.steam_id != null)} with Steam ID");
		}

		public static void RefreshSessionPlayers()
		{
			if (RT.SessionPlayers.Count == 0)
			{
				CollectSessionPlayers();
				return;
			}
			bool flag = false;
			foreach (PlayerInfo sessionPlayer in RT.SessionPlayers)
			{
				if (sessionPlayer.steam_id == null && RT.PlayerSteamIds.TryGetValue(sessionPlayer.player_id, out var value) && !string.IsNullOrEmpty(value))
				{
					sessionPlayer.steam_id = value;
					flag = true;
					RT.LogDebug($"RefreshSessionPlayers: player {sessionPlayer.player_id} got steam_id");
				}
			}
			if (flag)
			{
				RT.LogDebug($"RefreshSessionPlayers: now {RT.SessionPlayers.Count((PlayerInfo p) => p.steam_id != null)}/{RT.SessionPlayers.Count} with Steam ID");
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.rounds.tracker", "Rounds Tracker", "1.0.6")]
	[BepInProcess("Rounds.exe")]
	public class RT : BaseUnityPlugin
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__32_0;

			public static UnityAction<bool> <>9__33_0;

			public static UnityAction<bool> <>9__33_1;

			public static UnityAction<bool> <>9__33_2;

			public static UnityAction<bool> <>9__33_3;

			internal void <Start>b__32_0()
			{
			}

			internal void <BuildMenu>b__33_0(bool val)
			{
				ShowWinRates.Value = val;
			}

			internal void <BuildMenu>b__33_1(bool val)
			{
				EnableTracking.Value = val;
			}

			internal void <BuildMenu>b__33_2(bool val)
			{
				ShowCardUpdateNotifications.Value = val;
			}

			internal void <BuildMenu>b__33_3(bool val)
			{
				ShowEloNotifications.Value = val;
			}
		}

		[CompilerGenerated]
		private sealed class <OnGameEnd>d__40 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public IGameModeHandler gm;

			public RT <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <OnGameEnd>d__40(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				if (<>1__state != 0)
				{
					return false;
				}
				<>1__state = -1;
				if (!EnableTracking.Value || PhotonNetwork.OfflineMode)
				{
					return false;
				}
				if (_gameOverSent)
				{
					LogDebug("GameEnd: already sent from PointEnd-GameOver, skip");
					return false;
				}
				if (_lastRoundSent < _roundNumber + 1)
				{
					_roundNumber++;
					<>4__this.SendRoundReport("GameEnd");
					_collector.Reset();
					Networking.StartEloPropertyPoll();
				}
				else
				{
					LogDebug("GameEnd: round already sent, skip");
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <OnGameStart>d__35 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public IGameModeHandler gm;

			public RT <>4__this;

			private Room <room>5__1;

			private Exception <ex>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <OnGameStart>d__35(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<room>5__1 = null;
				<ex>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0117: Unknown result type (might be due to invalid IL or missing references)
				//IL_0121: Expected O, but got Unknown
				//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fb: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					try
					{
						<room>5__1 = PhotonNetwork.CurrentRoom;
						Room obj = <room>5__1;
						Log(string.Format("[RT-DEBUG] Room={0}, IsOffline={1}", ((obj != null) ? obj.Name : null) ?? "null", PhotonNetwork.OfflineMode));
						<room>5__1 = null;
					}
					catch (Exception ex)
					{
						<ex>5__2 = ex;
						LogError("[RT-DEBUG] Room error: " + <ex>5__2.Message);
					}
					ResetSession();
					CardTracker.ClearAll();
					_collector.Reset();
					LogDebug("Game started, session reset");
					if (!EnableTracking.Value || PhotonNetwork.OfflineMode)
					{
						return false;
					}
					Networking.BroadcastSteamId();
					Networking.FetchLocalElo();
					<>2__current = (object)new WaitForSeconds(2f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					Networking.BroadcastSteamId();
					<>2__current = (object)new WaitForSeconds(1f);
					<>1__state = 2;
					return true;
				case 2:
					<>1__state = -1;
					Networking.CollectSessionPlayers();
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <OnPickEnd>d__37 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public IGameModeHandler gm;

			public RT <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <OnPickEnd>d__37(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				if (<>1__state != 0)
				{
					return false;
				}
				<>1__state = -1;
				LogDebug($"PickEnd: picks={_collector.Picks.Count}, added={_collector.Added.Count}, removed={_collector.Removed.Count}");
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <OnPickStart>d__36 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public IGameModeHandler gm;

			public RT <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <OnPickStart>d__36(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				if (<>1__state != 0)
				{
					return false;
				}
				<>1__state = -1;
				if (_gameOverSent)
				{
					_gameContinuedCount++;
					_eloShownThisGame = false;
					LogDebug($"PickStart: game continued (count={_gameContinuedCount})");
					_gameOverSent = false;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <OnPointEnd>d__38 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public IGameModeHandler gm;

			public RT <>4__this;

			private Player <winner>5__1;

			private Player <local>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <OnPointEnd>d__38(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<winner>5__1 = null;
				<local>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				if (<>1__state != 0)
				{
					return false;
				}
				<>1__state = -1;
				if (!EnableTracking.Value || PhotonNetwork.OfflineMode)
				{
					return false;
				}
				<winner>5__1 = PlayerManager.instance.GetLastPlayerAlive();
				<local>5__2 = GetLocalPlayer();
				if ((Object)(object)<local>5__2 != (Object)null)
				{
					_collector.PointsPlayed++;
					if ((Object)(object)<winner>5__1 != (Object)null && <winner>5__1.data.view.IsMine)
					{
						_collector.PointsWon++;
					}
				}
				LogDebug($"PointEnd: {_collector.PointsWon}/{_collector.PointsPlayed}");
				if (<>4__this.IsGameOver(gm))
				{
					_roundNumber++;
					<>4__this.SendRoundReport("PointEnd-GameOver");
					_collector.Reset();
					_gameOverSent = true;
					Networking.StartEloPropertyPoll();
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <OnRoundEnd>d__39 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public IGameModeHandler gm;

			public RT <>4__this;

			private bool <gameOver>5__1;

			private string <source>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <OnRoundEnd>d__39(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<source>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				if (<>1__state != 0)
				{
					return false;
				}
				<>1__state = -1;
				if (!EnableTracking.Value || PhotonNetwork.OfflineMode)
				{
					return false;
				}
				if (_gameOverSent)
				{
					LogDebug("RoundEnd: already sent from PointEnd-GameOver, skip");
					return false;
				}
				_roundNumber++;
				<gameOver>5__1 = <>4__this.IsGameOver(gm);
				<source>5__2 = (<gameOver>5__1 ? "RoundEnd-GameOver" : "RoundEnd");
				<>4__this.SendRoundReport(<source>5__2);
				_collector.Reset();
				if (<gameOver>5__1)
				{
					_gameOverSent = true;
					Networking.StartEloPropertyPoll();
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public const string ModId = "com.rounds.tracker";

		public const string ModName = "Rounds Tracker";

		public const string Version = "1.0.6";

		public const bool ENABLE_LOGS = false;

		public static ConfigEntry<bool> EnableTracking;

		public static ConfigEntry<bool> ShowWinRates;

		public static ConfigEntry<bool> ShowCardUpdateNotifications;

		public static ConfigEntry<bool> ShowEloNotifications;

		public static ConfigEntry<bool> DebugLogging;

		private static string _sessionId;

		private static int _pickNumber;

		private static int _roundNumber;

		private static string _currentRoomName;

		private static int _gameIndexInRoom;

		internal static string _steamId;

		internal static string _steamNickname;

		internal static bool _steamInfoTried;

		private static RoundCollector _collector = new RoundCollector();

		private static int _lastRoundSent = 0;

		private static bool _gameOverSent = false;

		private static int _gameContinuedCount = 0;

		internal static int _picksToChoose = 0;

		internal static int _drawsPerPickPhase = 0;

		internal static bool _eloShownThisGame = false;

		internal static Dictionary<int, string> PlayerSteamIds = new Dictionary<int, string>();

		internal static List<PlayerInfo> SessionPlayers = new List<PlayerInfo>();

		public static string ApiUrlValue = "http://77.246.107.74:8000";

		public static RT Instance { get; private set; }

		public static RoundCollector Collector => _collector;

		private void Awake()
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			EnableTracking = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableTracking", true, "Enable tracking");
			ShowWinRates = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowWinRates", true, "Show card win rates during pick phase");
			ShowCardUpdateNotifications = ((BaseUnityPlugin)this).Config.Bind<bool>("Notifications", "ShowCardUpdateNotifications", true, "Show notification when card data is updated");
			ShowEloNotifications = ((BaseUnityPlugin)this).Config.Bind<bool>("Notifications", "ShowEloNotifications", true, "Show notification when ELO rating changes");
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogging", true, "Debug logging");
			new Harmony("com.rounds.tracker").PatchAll();
		}

		private void Start()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			ResetSession();
			Unbound.RegisterClientSideMod("com.rounds.tracker");
			object obj = <>c.<>9__32_0;
			if (obj == null)
			{
				UnityAction val = delegate
				{
				};
				<>c.<>9__32_0 = val;
				obj = (object)val;
			}
			Unbound.RegisterMenu("Rounds Tracker", (UnityAction)obj, (Action<GameObject>)BuildMenu, (GameObject)null, false);
			GameModeManager.AddHook("GameStart", (Func<IGameModeHandler, IEnumerator>)OnGameStart);
			GameModeManager.AddHook("PointEnd", (Func<IGameModeHandler, IEnumerator>)OnPointEnd);
			GameModeManager.AddHook("RoundEnd", (Func<IGameModeHandler, IEnumerator>)OnRoundEnd);
			GameModeManager.AddHook("GameEnd", (Func<IGameModeHandler, IEnumerator>)OnGameEnd);
			GameModeManager.AddHook("PickStart", (Func<IGameModeHandler, IEnumerator>)OnPickStart);
			GameModeManager.AddHook("PickEnd", (Func<IGameModeHandler, IEnumerator>)OnPickEnd);
			ApplyPatches();
			if (ShowWinRates.Value)
			{
				WinRateCache.Load();
			}
			Log("Rounds Tracker v1.0.6 initialized");
		}

		private static void BuildMenu(GameObject menu)
		{
			try
			{
				TextMeshProUGUI val2 = null;
				MenuHandler.CreateText("Rounds Tracker Settings", menu, ref val2, 60, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateToggle(ShowWinRates.Value, "Show Win Rates on Cards", menu, (UnityAction<bool>)delegate(bool val)
				{
					ShowWinRates.Value = val;
				}, 50, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateToggle(EnableTracking.Value, "Enable Tracking", menu, (UnityAction<bool>)delegate(bool val)
				{
					EnableTracking.Value = val;
				}, 50, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateToggle(ShowCardUpdateNotifications.Value, "Card Update Notifications", menu, (UnityAction<bool>)delegate(bool val)
				{
					ShowCardUpdateNotifications.Value = val;
				}, 50, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateToggle(ShowEloNotifications.Value, "ELO Change Notifications", menu, (UnityAction<bool>)delegate(bool val)
				{
					ShowEloNotifications.Value = val;
				}, 50, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
			}
			catch (Exception ex)
			{
				LogError("BuildMenu error: " + ex.Message);
			}
		}

		private void ApplyPatches()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected O, but got Unknown
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Expected O, but got Unknown
			try
			{
				Harmony val = new Harmony("com.rounds.tracker.cardpatches");
				Type typeFromHandle = typeof(Cards);
				MethodInfo methodInfo = AccessTools.Method(typeFromHandle, "RemoveAllCardsFromPlayer", new Type[2]
				{
					typeof(Player),
					typeof(bool)
				}, (Type[])null);
				if (methodInfo != null)
				{
					val.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(CardTracker), "RemoveAllCardsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					LogDebug("Patched RemoveAllCardsFromPlayer");
				}
				MethodInfo methodInfo2 = AccessTools.Method(typeFromHandle, "AddCardsToPlayer", new Type[7]
				{
					typeof(Player),
					typeof(CardInfo[]),
					typeof(bool[]),
					typeof(string[]),
					typeof(float[]),
					typeof(float[]),
					typeof(bool)
				}, (Type[])null);
				if (methodInfo2 != null)
				{
					val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(CardTracker), "AddCardsPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					LogDebug("Patched AddCardsToPlayer");
				}
				MethodInfo methodInfo3 = AccessTools.Method(typeof(CardVisuals), "Start", (Type[])null, (Type[])null);
				if (methodInfo3 != null)
				{
					val.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(CardVisualsStartPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Log("Patched CardVisuals.Start for WinRate overlay (all clients)");
				}
				else
				{
					LogError("CardVisuals.Start method not found!");
				}
			}
			catch (Exception ex)
			{
				LogError("Patch error: " + ex.Message);
			}
		}

		[IteratorStateMachine(typeof(<OnGameStart>d__35))]
		private IEnumerator OnGameStart(IGameModeHandler gm)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <OnGameStart>d__35(0)
			{
				<>4__this = this,
				gm = gm
			};
		}

		[IteratorStateMachine(typeof(<OnPickStart>d__36))]
		private IEnumerator OnPickStart(IGameModeHandler gm)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <OnPickStart>d__36(0)
			{
				<>4__this = this,
				gm = gm
			};
		}

		[IteratorStateMachine(typeof(<OnPickEnd>d__37))]
		private IEnumerator OnPickEnd(IGameModeHandler gm)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <OnPickEnd>d__37(0)
			{
				<>4__this = this,
				gm = gm
			};
		}

		[IteratorStateMachine(typeof(<OnPointEnd>d__38))]
		private IEnumerator OnPointEnd(IGameModeHandler gm)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <OnPointEnd>d__38(0)
			{
				<>4__this = this,
				gm = gm
			};
		}

		[IteratorStateMachine(typeof(<OnRoundEnd>d__39))]
		private IEnumerator OnRoundEnd(IGameModeHandler gm)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <OnRoundEnd>d__39(0)
			{
				<>4__this = this,
				gm = gm
			};
		}

		[IteratorStateMachine(typeof(<OnGameEnd>d__40))]
		private IEnumerator OnGameEnd(IGameModeHandler gm)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <OnGameEnd>d__40(0)
			{
				<>4__this = this,
				gm = gm
			};
		}

		private bool IsGameOver(IGameModeHandler gm)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: 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)
			try
			{
				if (gm == null)
				{
					return false;
				}
				GameSettings settings = gm.Settings;
				if (settings == null || !settings.ContainsKey("roundsToWinGame"))
				{
					return false;
				}
				int num = (int)settings["roundsToWinGame"];
				HashSet<int> hashSet = new HashSet<int>();
				foreach (Player player in PlayerManager.instance.players)
				{
					if ((Object)(object)player == (Object)null || hashSet.Contains(player.teamID))
					{
						continue;
					}
					hashSet.Add(player.teamID);
					try
					{
						TeamScore teamScore = gm.GetTeamScore(player.teamID);
						if (teamScore.rounds >= num)
						{
							LogDebug($"IsGameOver: team {player.teamID} rounds {teamScore.rounds}/{num}");
							return true;
						}
					}
					catch
					{
					}
				}
			}
			catch (Exception ex)
			{
				LogError("IsGameOver error: " + ex.Message);
			}
			return false;
		}

		internal static bool IsLegitimateGameOver()
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				IGameModeHandler currentHandler = GameModeManager.CurrentHandler;
				if (currentHandler == null)
				{
					return false;
				}
				GameSettings settings = currentHandler.Settings;
				if (settings == null || !settings.ContainsKey("roundsToWinGame"))
				{
					return false;
				}
				int num = (int)settings["roundsToWinGame"];
				bool flag = false;
				HashSet<int> hashSet = new HashSet<int>();
				foreach (Player player in PlayerManager.instance.players)
				{
					if ((Object)(object)player == (Object)null || hashSet.Contains(player.teamID))
					{
						continue;
					}
					hashSet.Add(player.teamID);
					try
					{
						TeamScore teamScore = currentHandler.GetTeamScore(player.teamID);
						if (teamScore.rounds >= num)
						{
							flag = true;
							break;
						}
					}
					catch
					{
					}
				}
				if (!flag)
				{
					LogDebug("IsLegitimateGameOver: no team reached roundsToWin, likely disconnect");
					return false;
				}
				int count = PlayerManager.instance.players.Count;
				if (SessionPlayers.Count > 0 && count < SessionPlayers.Count)
				{
					LogDebug($"IsLegitimateGameOver: player count dropped ({count} < {SessionPlayers.Count}), likely disconnect");
					return false;
				}
				return true;
			}
			catch (Exception ex)
			{
				LogError("IsLegitimateGameOver error: " + ex.Message);
				return false;
			}
		}

		private void SendRoundReport(string source)
		{
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			if (_lastRoundSent >= _roundNumber)
			{
				LogDebug($"{source}: round {_roundNumber} already sent, skip");
				return;
			}
			try
			{
				Player localPlayer = GetLocalPlayer();
				if ((Object)(object)localPlayer == (Object)null)
				{
					LogDebug(source + ": no local player");
					return;
				}
				Player lastPlayerAlive = PlayerManager.instance.GetLastPlayerAlive();
				bool flag = (Object)(object)lastPlayerAlive != (Object)null && lastPlayerAlive.data.view.IsMine;
				Networking.BroadcastSteamId();
				Networking.RefreshSessionPlayers();
				List<CardData> list = new List<CardData>();
				if (localPlayer.data?.currentCards != null)
				{
					foreach (CardInfo currentCard in localPlayer.data.currentCards)
					{
						if ((Object)(object)currentCard != (Object)null)
						{
							list.Add(DC.FromInfo(currentCard));
						}
					}
				}
				PlayerSkin playerSkinColors = PlayerSkinBank.GetPlayerSkinColors(localPlayer.playerID);
				string player_color = "#" + ColorUtility.ToHtmlStringRGB(playerSkinColors.color);
				List<CardData> list2 = new List<CardData>();
				HashSet<string> hashSet = new HashSet<string>();
				foreach (PickEvent pick in _collector.Picks)
				{
					foreach (CardData offered_card in pick.offered_cards)
					{
						string item = offered_card.card_name + "|" + offered_card.mod_name + "|" + offered_card.rarity;
						if (!hashSet.Contains(item))
						{
							hashSet.Add(item);
							list2.Add(offered_card);
						}
					}
				}
				RoundReport report = new RoundReport
				{
					report_id = Guid.NewGuid().ToString(),
					session_id = GetSessionId(),
					round_number = _roundNumber,
					steam_id = GetSteamId(),
					nickname = GetSteamNickname(),
					player_color = player_color,
					is_round_winner = flag,
					points_won = _collector.PointsWon,
					points_played = _collector.PointsPlayed,
					current_cards = list,
					picks = new List<PickEvent>(_collector.Picks),
					offered_cards = list2,
					added = new List<CardData>(_collector.Added),
					removed = new List<CardData>(_collector.Removed),
					players = new List<PlayerInfo>(SessionPlayers),
					game_mode = GameModeManager.CurrentHandlerID,
					player_count = PlayerManager.instance.players.Count,
					points_to_win_round = GetPointsToWinRound(),
					rounds_to_win_game = GetRoundsToWinGame(),
					game_continued_count = _gameContinuedCount,
					picks_to_choose = _picksToChoose,
					draws_per_pick_phase = _drawsPerPickPhase,
					is_game_over = (source.Contains("GameOver") || source == "GameEnd"),
					is_legitimate_game_over = IsLegitimateGameOver(),
					tracker_version = "1.0.6"
				};
				Api.Send(report);
				_lastRoundSent = _roundNumber;
				Log(string.Format("[{0}] R{1} {2} pts:{3}/{4} ", source, _roundNumber, flag ? "WIN" : "LOSS", _collector.PointsWon, _collector.PointsPlayed) + $"cards:{list.Count} picks:{_collector.Picks.Count} offered:{list2.Count} " + $"add:{_collector.Added.Count} rem:{_collector.Removed.Count}");
			}
			catch (Exception ex)
			{
				LogError(source + " error: " + ex.Message + "\n" + ex.StackTrace);
			}
		}

		public static Player GetLocalPlayer()
		{
			foreach (Player player in PlayerManager.instance.players)
			{
				if (player.data.view.IsMine)
				{
					return player;
				}
			}
			return null;
		}

		public static void ResetSession()
		{
			string text = null;
			try
			{
				if (!PhotonNetwork.OfflineMode && PhotonNetwork.CurrentRoom != null)
				{
					text = PhotonNetwork.CurrentRoom.Name;
				}
			}
			catch
			{
			}
			if (!string.IsNullOrEmpty(text))
			{
				if (text == _currentRoomName)
				{
					_gameIndexInRoom++;
				}
				else
				{
					_currentRoomName = text;
					_gameIndexInRoom = 0;
				}
				_sessionId = $"R_{text}_{_gameIndexInRoom}";
			}
			else
			{
				_sessionId = Guid.NewGuid().ToString();
			}
			_pickNumber = 0;
			_roundNumber = 0;
			_lastRoundSent = 0;
			_gameOverSent = false;
			_gameContinuedCount = 0;
			_picksToChoose = 0;
			_drawsPerPickPhase = 0;
			_eloShownThisGame = false;
			_collector.Reset();
			PlayerSteamIds.Clear();
			SessionPlayers.Clear();
			LogDebug("ResetSession: id=" + _sessionId);
		}

		public static string GetSessionId()
		{
			return _sessionId;
		}

		public static int NextPickNumber()
		{
			return ++_pickNumber;
		}

		public static string GetSteamId()
		{
			Networking.EnsureSteamInfo();
			return _steamId;
		}

		public static string GetSteamNickname()
		{
			Networking.EnsureSteamInfo();
			return _steamNickname;
		}

		public static int? GetPointsToWinRound()
		{
			try
			{
				IGameModeHandler currentHandler = GameModeManager.CurrentHandler;
				if (currentHandler == null)
				{
					return null;
				}
				GameSettings settings = currentHandler.Settings;
				if (settings != null && settings.ContainsKey("pointsToWinRound"))
				{
					return (int)settings["pointsToWinRound"];
				}
			}
			catch
			{
			}
			return null;
		}

		public static int? GetRoundsToWinGame()
		{
			try
			{
				IGameModeHandler currentHandler = GameModeManager.CurrentHandler;
				if (currentHandler == null)
				{
					return null;
				}
				GameSettings settings = currentHandler.Settings;
				if (settings != null && settings.ContainsKey("roundsToWinGame"))
				{
					return (int)settings["roundsToWinGame"];
				}
			}
			catch
			{
			}
			return null;
		}

		public static void Log(string msg)
		{
			bool flag = true;
		}

		public static void LogError(string msg)
		{
			bool flag = true;
		}

		public static void LogDebug(string msg)
		{
			bool flag = true;
		}
	}
	internal class WinRateLabel : MonoBehaviour
	{
		private bool _setup = false;

		private float _waitTime = 0f;

		private const float MaxWait = 15f;

		private void LateUpdate()
		{
			if (_setup)
			{
				return;
			}
			if (!WinRateCache.IsLoaded)
			{
				_waitTime += Time.unscaledDeltaTime;
				if (!(_waitTime < 15f))
				{
					Object.Destroy((Object)(object)this);
				}
				return;
			}
			_setup = true;
			try
			{
				Setup();
			}
			catch (Exception ex)
			{
				RT.LogError("WinRateLabel error: " + ex.Message + "\n" + ex.StackTrace);
			}
			Object.Destroy((Object)(object)this);
		}

		private void Setup()
		{
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Expected O, but got Unknown
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			if (!RT.ShowWinRates.Value)
			{
				return;
			}
			CardInfo component = ((Component)this).GetComponent<CardInfo>();
			if ((Object)(object)component == (Object)null || string.IsNullOrEmpty(component.cardName) || component.cardName.Trim().Length == 0)
			{
				return;
			}
			string text = DC.ExtractModName(((Object)((Component)this).gameObject).name);
			string text2 = "Common";
			try
			{
				text2 = ((object)(Rarity)(ref component.rarity)).ToString();
			}
			catch
			{
			}
			string text3 = WinRateCache.MakeKey(component.cardName, text, text2);
			WinRateEntry winRateEntry = WinRateCache.Get(text3);
			RT.Log("WinRateLabel LOOKUP: card=\"" + component.cardName + "\" obj=\"" + ((Object)((Component)this).gameObject).name + "\" mod=\"" + text + "\" rarity=\"" + text2 + "\" key=\"" + text3 + "\" found=" + (winRateEntry != null) + ((winRateEntry != null) ? (" wr=" + winRateEntry.round_win_rate + " pr=" + winRateEntry.pick_rate) : ""));
			if (winRateEntry == null)
			{
				List<string> list = WinRateCache.FindSimilar(component.cardName, 3);
				if (list.Count > 0)
				{
					RT.Log("WinRateLabel SIMILAR: " + string.Join(" | ", list));
				}
				return;
			}
			string text4 = $"WR: {winRateEntry.round_win_rate:F1}%";
			Transform val = null;
			if ((Object)(object)component.cardBase != (Object)null)
			{
				val = component.cardBase.transform.Find("Canvas");
			}
			if ((Object)(object)val == (Object)null)
			{
				CardVisuals componentInChildren = ((Component)this).GetComponentInChildren<CardVisuals>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					val = ((Component)componentInChildren).transform.Find("Canvas");
					if ((Object)(object)val == (Object)null)
					{
						val = ((Component)componentInChildren).transform;
					}
				}
			}
			if (!((Object)(object)val == (Object)null))
			{
				GameObject val2 = new GameObject("RT_WinRate");
				val2.transform.SetParent(val, false);
				RectTransform val3 = val2.AddComponent<RectTransform>();
				val3.anchorMin = new Vector2(0.5f, 0f);
				val3.anchorMax = new Vector2(0.5f, 0f);
				val3.pivot = new Vector2(0.5f, 1f);
				val3.anchoredPosition = new Vector2(0f, -15f);
				val3.sizeDelta = new Vector2(400f, 80f);
				TextMeshProUGUI val4 = val2.AddComponent<TextMeshProUGUI>();
				((TMP_Text)val4).text = text4;
				((Graphic)val4).color = new Color(1f, 1f, 1f, 0f);
				((TMP_Text)val4).fontSize = 72f;
				((TMP_Text)val4).alignment = (TextAlignmentOptions)514;
				((TMP_Text)val4).enableWordWrapping = false;
				((TMP_Text)val4).overflowMode = (TextOverflowModes)0;
				((Graphic)val4).raycastTarget = false;
				((TMP_Text)val4).fontStyle = (FontStyles)1;
				WinRateFlicker winRateFlicker = val2.AddComponent<WinRateFlicker>();
				winRateFlicker.cardRoot = ((Component)this).gameObject;
				RT.Log("WinRateLabel CREATED: " + component.cardName + " => " + text4);
			}
		}
	}
	internal class WinRateFlicker : MonoBehaviour
	{
		public GameObject cardRoot;

		private TextMeshProUGUI _text;

		private float _time;

		private bool _revealed = false;

		private float _revealProgress = 0f;

		private const float RevealDuration = 0.3f;

		private const float DimAlpha = 0.1f;

		private const float BrightAlphaMin = 0.6f;

		private const float BrightAlphaMax = 1f;

		private const float TransitionSpeed = 3.5f;

		private float _brightnessLerp = 0f;

		private CardVisuals _cardVisuals;

		private bool _cvSearched = false;

		public bool IsRevealed => _revealed;

		public float RevealProgress => _revealProgress;

		private void Awake()
		{
			_text = ((Component)this).GetComponent<TextMeshProUGUI>();
		}

		private void Update()
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_text == (Object)null)
			{
				return;
			}
			if (!_cvSearched && (Object)(object)cardRoot != (Object)null)
			{
				_cardVisuals = cardRoot.GetComponentInChildren<CardVisuals>();
				_cvSearched = true;
			}
			if (!_revealed)
			{
				if ((Object)(object)_cardVisuals == (Object)null || !_cardVisuals.isSelected)
				{
					((Graphic)_text).color = new Color(1f, 1f, 1f, 0f);
					return;
				}
				_revealed = true;
				_revealProgress = 0f;
				_brightnessLerp = 1f;
			}
			if (_revealProgress < 1f)
			{
				_revealProgress += Time.unscaledDeltaTime / 0.3f;
				if (_revealProgress > 1f)
				{
					_revealProgress = 1f;
				}
			}
			_time += Time.unscaledDeltaTime;
			float num = (((Object)(object)_cardVisuals != (Object)null && _cardVisuals.isSelected) ? 1f : 0f);
			_brightnessLerp = Mathf.MoveTowards(_brightnessLerp, num, 3.5f * Time.unscaledDeltaTime);
			float num6;
			float num7;
			if (_brightnessLerp > 0.01f)
			{
				float num2 = Mathf.Sin(_time * 3.7f) * 0.5f + 0.5f;
				float num3 = Mathf.Sin(_time * 5.3f) * 0.5f + 0.5f;
				float num4 = num2 * 0.6f + num3 * 0.4f;
				float num5 = 0.6f + num4 * 0.39999998f;
				num6 = Mathf.Lerp(0.1f, num5, _brightnessLerp) * _revealProgress;
				num7 = num4 * 0.15f * _brightnessLerp;
			}
			else
			{
				num6 = 0.1f * _revealProgress;
				num7 = 0f;
			}
			((Graphic)_text).color = new Color(1f - num7 * 0.5f, 1f - num7 * 0.3f, 1f, num6);
		}
	}
	internal class WinRateParticleCtrl : MonoBehaviour
	{
		public WinRateFlicker flicker;

		public GeneralParticleSystem ps;

		private bool _started = false;

		private void Update()
		{
			if (!_started && !((Object)(object)flicker == (Object)null) && !((Object)(object)ps == (Object)null) && flicker.IsRevealed)
			{
				_started = true;
				ps.StartLooping();
			}
		}
	}
	internal static class CardVisualsStartPatch
	{
		public static void Postfix(CardVisuals __instance)
		{
			if (PhotonNetwork.OfflineMode || !RT.ShowWinRates.Value)
			{
				return;
			}
			try
			{
				GameObject gameObject = ((Component)((Component)__instance).transform.root).gameObject;
				PhotonView component = gameObject.GetComponent<PhotonView>();
				if (!((Object)(object)component == (Object)null))
				{
					CardInfo component2 = gameObject.GetComponent<CardInfo>();
					if (!((Object)(object)component2 == (Object)null) && !((Object)(object)gameObjec