Decompiled source of GameSaverRevived v1.1.1

plugins/GameSaver.dll

Decompiled a day 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.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using GameSaver.Asset;
using GameSaver.Component;
using GameSaver.Menu;
using GameSaver.Network;
using GameSaver.Patches;
using GameSaver.Util;
using HarmonyLib;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using ModdingUtils.Utils;
using Photon.Pun;
using Photon.Realtime;
using RWF;
using Steamworks;
using TMPro;
using UnboundLib;
using UnboundLib.Extensions;
using UnboundLib.GameModes;
using UnboundLib.Networking;
using UnboundLib.Utils;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("1.1.1")]
[assembly: AssemblyInformationalVersion("1.1.1")]
[assembly: IgnoresAccessChecksTo("RoundsWithFriends")]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace GameSaver
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("ot.dan.rounds.gamesaver", "GameSaver", "1.1.1")]
	[BepInProcess("Rounds.exe")]
	public class GameSaver : BaseUnityPlugin
	{
		private const string ModId = "ot.dan.rounds.gamesaver";

		private const string ModName = "Game Saver";

		public const string Version = "1.1.1";

		public const string ModInitials = "GS";

		private const string CompatibilityModName = "GameSaver";

		public static GameSaver Instance { get; private set; }

		internal static bool AssetsFailed { get; private set; }

		internal void Awake()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			Instance = this;
			ConfigManager.Initialize(((BaseUnityPlugin)this).Config);
			try
			{
				AssetsFailed = !AssetManager.Initialize();
			}
			catch (Exception arg)
			{
				AssetsFailed = true;
				LogError($"asset initialisation threw: {arg}");
			}
			if (AssetsFailed)
			{
				LogError("asset bundle failed to load - GameSaver is disabled for this session.");
				return;
			}
			SaveManager.Initialize();
			OpeningPickPatch.Apply(new Harmony("ot.dan.rounds.gamesaver"));
		}

		internal void Start()
		{
			if (!AssetsFailed)
			{
				GameModeManager.AddHook("GameStart", (Func<IGameModeHandler, IEnumerator>)SaveManager.GameStart, 0);
				GameModeManager.AddHook("GameEnd", (Func<IGameModeHandler, IEnumerator>)SaveManager.GameEnd);
				GameModeManager.AddHook("RoundStart", (Func<IGameModeHandler, IEnumerator>)SaveManager.RoundStart);
				GameModeManager.AddHook("RoundEnd", (Func<IGameModeHandler, IEnumerator>)SaveManager.RoundEnd);
				GameModeManager.AddHook("PickEnd", (Func<IGameModeHandler, IEnumerator>)SaveManager.PickEnd);
				((Component)this).gameObject.AddComponent<LobbyMonitor>();
			}
		}

		public void Log(string debug)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)debug);
		}

		internal static void LogInfo(string message)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)message);
			}
			else
			{
				Debug.Log("[GameSaver] " + message);
			}
		}

		internal static void LogWarning(string message)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)message);
			}
			else
			{
				Debug.LogWarning("[GameSaver] " + message);
			}
		}

		internal static void LogError(string message)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogError((object)message);
			}
			else
			{
				Debug.LogError("[GameSaver] " + message);
			}
		}
	}
}
namespace GameSaver.Util
{
	internal static class ConfigManager
	{
		internal static ConfigEntry<bool> SaveEnabled { get; private set; }

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

		internal static void Initialize(ConfigFile config)
		{
			SaveEnabled = config.Bind<bool>("General", "SaveEnabled", true, "Automatically save the state of the match after every card pick.");
			SaveAsHostOnly = config.Bind<bool>("General", "SaveAsHostOnly", false, "Only write save files when you are the host. Only the host can load a save, so turning this on stops non-hosts filling their disk with saves they can never use.");
		}
	}
	public class SaveManager
	{
		private class Match
		{
			public PlayerData Data;

			public Player Player;
		}

		public class GameInfoData
		{
			public GameData gameData;

			public List<SaveData> gameSaves;

			private int _rounds = -1;

			public string FilePath { get; }

			public int rounds
			{
				get
				{
					if (_rounds == -1)
					{
						_rounds = ((gameSaves.Count != 0) ? gameSaves.OrderByDescending((SaveData save) => save.round).First().round : 0);
					}
					return _rounds;
				}
			}

			internal void InvalidateRounds()
			{
				_rounds = -1;
			}

			public GameInfoData(string filePath, GameData gameData, List<SaveData> gameSaves)
			{
				FilePath = filePath;
				this.gameData = gameData;
				this.gameSaves = gameSaves;
			}
		}

		[Serializable]
		public class GameData
		{
			[NonSerialized]
			public GameObject button;

			public long _serializedStartTime;

			public int playerAmount;

			public string gameMode;

			public GameType gameType;

			public DateTime StartTime => DateTime.FromBinary(_serializedStartTime);

			public GameData(DateTime startTime, int playerAmount, string gameMode, GameType gameType)
			{
				_serializedStartTime = startTime.ToBinary();
				this.playerAmount = playerAmount;
				this.gameMode = gameMode;
				this.gameType = gameType;
			}
		}

		[Serializable]
		public class SaveData
		{
			[NonSerialized]
			public GameObject button;

			[NonSerialized]
			public GameObject display;

			[NonSerialized]
			public TextMeshProUGUI loaded;

			public long _serializedDateTime;

			public SaveType saveType;

			public int round;

			public int pointsToWinRound = 2;

			public int pointsToWin;

			public List<string> seralizedPlayers;

			private List<PlayerData> _players;

			public DateTime Time => DateTime.FromBinary(_serializedDateTime);

			public List<PlayerData> players
			{
				get
				{
					if (_players != null)
					{
						return _players;
					}
					List<PlayerData> list = new List<PlayerData>();
					foreach (string item in seralizedPlayers ?? new List<string>())
					{
						try
						{
							PlayerData playerData = JsonUtility.FromJson<PlayerData>(item);
							if (playerData != null)
							{
								list.Add(playerData);
							}
						}
						catch (Exception ex)
						{
							GameSaver.LogWarning("skipping unreadable player entry in save: " + ex.Message);
						}
					}
					return _players = list;
				}
				set
				{
					_players = value;
				}
			}

			internal void InvalidateCards()
			{
				if (_players == null)
				{
					return;
				}
				foreach (PlayerData player in _players)
				{
					player?.InvalidateCards();
				}
			}

			public SaveData(DateTime time, SaveType saveType, int round, int pointsToWinRound, int pointsToWin, List<string> players)
			{
				_serializedDateTime = time.ToBinary();
				this.saveType = saveType;
				this.round = round;
				this.pointsToWinRound = pointsToWinRound;
				this.pointsToWin = pointsToWin;
				seralizedPlayers = players;
			}
		}

		[Serializable]
		public class PlayerData
		{
			[NonSerialized]
			public GameObject display;

			private List<CardInfo> _cards;

			public int serializedTeamId;

			public string name;

			public int serializedColor;

			public List<string> serializedCards;

			public int rounds;

			public int points;

			public bool host;

			public ulong steamId;

			public List<CardInfo> Cards
			{
				get
				{
					if (_cards != null)
					{
						return _cards;
					}
					List<CardInfo> list = new List<CardInfo>();
					foreach (string item in serializedCards ?? new List<string>())
					{
						list.Add(ResolveCard(item));
					}
					return _cards = list;
				}
			}

			public PlayerSkin Color => PlayerSkinBank.GetPlayerSkinColors(serializedColor);

			public int TeamId => serializedTeamId - 1;

			public bool HasTeamId => serializedTeamId > 0;

			internal void InvalidateCards()
			{
				_cards = null;
			}

			private static CardInfo ResolveCard(string objectName)
			{
				if (string.IsNullOrEmpty(objectName))
				{
					return null;
				}
				try
				{
					CardInfo cardWithObjectName = Cards.instance.GetCardWithObjectName(objectName);
					if (Object.op_Implicit((Object)(object)cardWithObjectName))
					{
						return cardWithObjectName;
					}
				}
				catch (Exception ex)
				{
					GameSaver.LogWarning("card lookup for '" + objectName + "' failed: " + ex.GetType().Name + ": " + ex.Message);
				}
				try
				{
					CardInfo cardInfoWithName = CardManager.GetCardInfoWithName(objectName);
					if (Object.op_Implicit((Object)(object)cardInfoWithName))
					{
						return cardInfoWithName;
					}
				}
				catch (Exception ex2)
				{
					GameSaver.LogWarning("card '" + objectName + "' is unresolvable on this client (mod not installed, or a random-card seed that was not generated this session): " + ex2.GetType().Name);
				}
				try
				{
					string b = Regex.Replace(objectName, "\\s+", "");
					ReadOnlyCollection<CardInfo> hiddenCards = Cards.instance.HiddenCards;
					IEnumerable<CardInfo> second;
					if (!((Object)(object)CardChoice.instance != (Object)null))
					{
						IEnumerable<CardInfo> enumerable = (IEnumerable<CardInfo>)(object)new CardInfo[0];
						second = enumerable;
					}
					else
					{
						IEnumerable<CardInfo> enumerable = CardChoice.instance.cards;
						second = enumerable;
					}
					foreach (CardInfo item in hiddenCards.Concat(second))
					{
						if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)((Component)item).gameObject) && string.Equals(Regex.Replace(((Object)((Component)item).gameObject).name, "\\s+", ""), b, StringComparison.OrdinalIgnoreCase))
						{
							return item;
						}
					}
				}
				catch (Exception ex3)
				{
					GameSaver.LogWarning("fuzzy card lookup for '" + objectName + "' failed: " + ex3.GetType().Name + ": " + ex3.Message);
				}
				return null;
			}

			public PlayerData(string name, int color, int teamId, List<CardInfo> cards, int points, int rounds, bool host, ulong steamId)
			{
				this.name = name;
				serializedColor = color;
				serializedTeamId = teamId + 1;
				serializedCards = new List<string>();
				foreach (CardInfo card in cards)
				{
					if (Object.op_Implicit((Object)(object)card) && Object.op_Implicit((Object)(object)((Component)card).gameObject))
					{
						serializedCards.Add(((Object)((Component)card).gameObject).name);
					}
				}
				this.points = points;
				this.rounds = rounds;
				this.host = host;
				this.steamId = steamId;
			}
		}

		public enum SaveType
		{
			PickStart,
			PickEnd,
			CardPicked,
			RoundStart,
			RoundEnd,
			Manual
		}

		public enum GameType
		{
			Local,
			Online
		}

		public static readonly string SavesPath = Path.Combine(Paths.ConfigPath, "Saves");

		private static string _gameSavesPath;

		private static int _round;

		private static Guid _gameGuid;

		public static List<GameInfoData> _games = new List<GameInfoData>();

		public static SaveData _selectedSave;

		private static GameObject _savingObject;

		public static List<GameInfoData> orderedGames => (from game in _games
			where game != null && game.gameData != null
			orderby game.gameData._serializedStartTime descending
			select game).ToList();

		internal static bool SuppressOpeningPick { get; private set; }

		internal static void Initialize()
		{
			Directory.CreateDirectory(SavesPath);
			LoadGames();
		}

		private static IEnumerator RunGuarded(IEnumerator routine, string what)
		{
			while (true)
			{
				object current;
				try
				{
					if (!routine.MoveNext())
					{
						break;
					}
					current = routine.Current;
				}
				catch (Exception arg)
				{
					GameSaver.LogError($"{what} failed: {arg}");
					break;
				}
				yield return current;
			}
		}

		public static void LoadGames()
		{
			string[] directories;
			try
			{
				directories = Directory.GetDirectories(SavesPath);
			}
			catch (Exception ex)
			{
				GameSaver.LogError("could not enumerate saves folder: " + ex.Message);
				return;
			}
			string[] array = directories;
			foreach (string directoryPath in array)
			{
				if (!Path.GetFileName(directoryPath).StartsWith("Game-", StringComparison.Ordinal))
				{
					continue;
				}
				string path = Path.Combine(directoryPath, "game.json");
				if (!File.Exists(path))
				{
					continue;
				}
				GameData gameData;
				try
				{
					gameData = JsonUtility.FromJson<GameData>(File.ReadAllText(path));
				}
				catch (Exception ex2)
				{
					GameSaver.LogWarning("skipping unreadable game.json in '" + Path.GetFileName(directoryPath) + "': " + ex2.Message);
					continue;
				}
				if (gameData == null)
				{
					continue;
				}
				string[] files;
				try
				{
					files = Directory.GetFiles(directoryPath);
				}
				catch (Exception ex3)
				{
					GameSaver.LogWarning("could not read save folder '" + Path.GetFileName(directoryPath) + "': " + ex3.Message);
					continue;
				}
				List<SaveData> list = new List<SaveData>();
				string[] array2 = files;
				foreach (string path2 in array2)
				{
					if (!Path.GetFileName(path2).Contains("save"))
					{
						continue;
					}
					try
					{
						SaveData saveData = JsonUtility.FromJson<SaveData>(File.ReadAllText(path2));
						if (saveData != null)
						{
							list.Add(saveData);
						}
					}
					catch (Exception ex4)
					{
						GameSaver.LogWarning("skipping unreadable save '" + Path.GetFileName(path2) + "': " + ex4.Message);
					}
				}
				GameInfoData gameInfoData = _games.FirstOrDefault((GameInfoData g) => g?.gameData != null && string.Equals(g.FilePath, directoryPath, StringComparison.OrdinalIgnoreCase));
				if (gameInfoData != null)
				{
					HashSet<long> known = new HashSet<long>(from s in gameInfoData.gameSaves
						where s != null
						select s._serializedDateTime);
					int num = 0;
					foreach (SaveData item in list.Where((SaveData save) => !known.Contains(save._serializedDateTime)))
					{
						gameInfoData.gameSaves.Add(item);
						num++;
					}
					if (num > 0)
					{
						gameInfoData.InvalidateRounds();
					}
				}
				else
				{
					_games.Add(new GameInfoData(directoryPath, gameData, list));
				}
			}
		}

		internal static IEnumerator PreSave()
		{
			string savesPath = SavesPath;
			Guid gameGuid = _gameGuid;
			_gameSavesPath = Path.Combine(savesPath, "Game-" + gameGuid);
			Directory.CreateDirectory(_gameSavesPath);
			string currentHandlerID = GameModeManager.CurrentHandlerID;
			GameType gameType = ((!PhotonNetwork.OfflineMode && PhotonNetwork.CurrentRoom != null) ? GameType.Online : GameType.Local);
			GameData gameData = new GameData(DateTime.Now, PlayerManager.instance.players.Count, currentHandlerID, gameType);
			File.WriteAllText(Path.Combine(_gameSavesPath, "game.json"), JsonUtility.ToJson((object)gameData));
			yield return null;
		}

		private static List<Match> MatchPlayers(SaveData save)
		{
			List<Match> list = new List<Match>();
			List<Player> list2 = new List<Player>(PlayerManager.instance.players.Where((Player p) => (Object)(object)p?.data?.view != (Object)null));
			Room room = (PhotonNetwork.OfflineMode ? null : PhotonNetwork.CurrentRoom);
			List<PlayerData> list3 = new List<PlayerData>(save.players.Where((PlayerData p) => p != null));
			foreach (PlayerData data in list3.ToList())
			{
				if (data.steamId > 1)
				{
					ulong value;
					Player val = ((IEnumerable<Player>)list2).FirstOrDefault((Func<Player, bool>)((Player p) => SteamManager.steamIds.TryGetValue(p.data.view.OwnerActorNr, out value) && value == data.steamId));
					if (!((Object)(object)val == (Object)null))
					{
						list.Add(new Match
						{
							Data = data,
							Player = val
						});
						list2.Remove(val);
						list3.Remove(data);
					}
				}
			}
			foreach (PlayerData data2 in list3.ToList())
			{
				if (room == null)
				{
					break;
				}
				Player val2 = ((IEnumerable<Player>)list2).FirstOrDefault((Func<Player, bool>)delegate(Player p)
				{
					Player player = room.GetPlayer(p.data.view.OwnerActorNr);
					return player != null && player.NickName == data2.name;
				});
				if (!((Object)(object)val2 == (Object)null))
				{
					list.Add(new Match
					{
						Data = data2,
						Player = val2
					});
					list2.Remove(val2);
					list3.Remove(data2);
				}
			}
			if (room == null && save.players.Count == PlayerManager.instance.players.Count)
			{
				foreach (PlayerData item in list3.ToList())
				{
					int num = save.players.IndexOf(item);
					if (num >= 0 && num < PlayerManager.instance.players.Count)
					{
						Player val3 = PlayerManager.instance.players[num];
						if (!((Object)(object)val3 == (Object)null) && list2.Contains(val3))
						{
							list.Add(new Match
							{
								Data = item,
								Player = val3
							});
							list2.Remove(val3);
							list3.Remove(item);
							GameSaver.LogInfo($"matched saved player '{item.name}' by position {num} (no steam id or nickname match).");
						}
					}
				}
			}
			foreach (PlayerData item2 in list3)
			{
				GameSaver.LogWarning("saved player '" + item2.name + "' could not be matched to anyone in this lobby - their cards and score were not restored.");
			}
			foreach (Player item3 in list2)
			{
				GameSaver.LogWarning("player '" + PlayerName(item3) + "' is in this lobby but not in the save - they start fresh.");
			}
			return list;
		}

		private static string PlayerName(Player player)
		{
			try
			{
				Room currentRoom = PhotonNetwork.CurrentRoom;
				if (currentRoom == null)
				{
					return $"player {player.playerID}";
				}
				Player player2 = currentRoom.GetPlayer(player.data.view.OwnerActorNr);
				return ((player2 != null) ? player2.NickName : null) ?? $"player {player.playerID}";
			}
			catch
			{
				return $"player {player.playerID}";
			}
		}

		private static void RestorePlayerCards(Match match)
		{
			try
			{
				List<CardInfo> cards = match.Data.Cards;
				CardInfo[] array = cards.Where((CardInfo c) => Object.op_Implicit((Object)(object)c)).ToArray();
				if (array.Length != cards.Count)
				{
					GameSaver.LogWarning($"{match.Data.name}: {cards.Count - array.Length} of {cards.Count} cards could not be resolved on this client and were skipped.");
				}
				if (array.Length != 0)
				{
					Cards.instance.AddCardsToPlayer(match.Player, array, true, (string[])null, (float[])null, (float[])null, true);
				}
			}
			catch (Exception arg)
			{
				GameSaver.LogError($"failed to restore cards for '{match.Data.name}': {arg}");
			}
		}

		private static void ApplyTeamScores(List<Match> matches)
		{
			foreach (IGrouping<int, Match> item in from m in matches
				group m by m.Player.teamID)
			{
				List<Match> source = item.ToList();
				List<int> list = (from m in source
					where m.Data.HasTeamId
					select m.Data.TeamId).Distinct().ToList();
				if (list.Count > 1)
				{
					GameSaver.LogWarning($"team {item.Key} now contains players who were on {list.Count} different teams " + "(" + string.Join(", ", source.Select((Match m) => m.Data.name).ToArray()) + "); applying the highest score of the group.");
				}
				Match match = (from m in source
					orderby m.Data.rounds descending, m.Data.points descending
					select m).First();
				ShareSaveTeamSettings(item.Key, match.Data.points, match.Data.rounds);
			}
		}

		internal static IEnumerator LoadSave()
		{
			if (_selectedSave == null)
			{
				yield break;
			}
			SaveData save = _selectedSave;
			_selectedSave = null;
			_round = save.round;
			ShareSaveGameSettings(save.pointsToWin, save.pointsToWinRound);
			yield return null;
			List<Match> matches = MatchPlayers(save);
			foreach (Match item in matches)
			{
				RestorePlayerCards(item);
				yield return null;
			}
			ApplyTeamScores(matches);
			SuppressOpeningPick = true;
			GameSaver.LogInfo($"restored round {save.round} for {matches.Count} player(s); " + "skipping the opening pick so the match resumes straight into the round.");
		}

		public static void ShareSaveTeamSettings(int teamId, int points, int rounds)
		{
			NetworkingManager.RPC(typeof(SaveManager), "LoadSaveTeamSettings", new object[3] { teamId, points, rounds });
		}

		public static void ShareSaveGameSettings(int pointsToWin, int pointsToWinRound)
		{
			NetworkingManager.RPC(typeof(SaveManager), "LoadSaveGameSettings", new object[3] { pointsToWin, pointsToWinRound, _round });
		}

		[UnboundRPC]
		private static void LoadSaveTeamSettings(int teamId, int points, int rounds)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameModeManager.CurrentHandler.SetTeamScore(teamId, new TeamScore(points, rounds));
				if ((Object)(object)UIHandler.instance != (Object)null)
				{
					if ((Object)(object)UIHandler.instance.roundCounter != (Object)null)
					{
						ExtensionMethods.InvokeMethod((object)UIHandler.instance.roundCounter, "ReDraw", Array.Empty<object>());
					}
					if ((Object)(object)UIHandler.instance.roundCounterSmall != (Object)null)
					{
						ExtensionMethods.InvokeMethod((object)UIHandler.instance.roundCounterSmall, "ReDraw", Array.Empty<object>());
					}
				}
			}
			catch (Exception arg)
			{
				GameSaver.LogError($"could not apply team score for team {teamId}: {arg}");
			}
		}

		[UnboundRPC]
		private static void LoadSaveGameSettings(int pointsToWin, int pointsToWinRound, int currentRound)
		{
			try
			{
				GameModeManager.CurrentHandler.ChangeSetting("roundsToWinGame", (object)pointsToWin);
				GameModeManager.CurrentHandler.ChangeSetting("pointsToWinRound", (object)pointsToWinRound);
				_round = currentRound;
			}
			catch (Exception arg)
			{
				GameSaver.LogError($"could not apply game settings: {arg}");
			}
		}

		private static void EnsureSavingObject()
		{
			if ((Object)(object)_savingObject != (Object)null)
			{
				return;
			}
			try
			{
				if ((Object)(object)AssetManager.Saving != (Object)null)
				{
					_savingObject = Object.Instantiate<GameObject>(AssetManager.Saving);
				}
			}
			catch (Exception ex)
			{
				GameSaver.LogWarning("could not create the saving indicator: " + ex.Message);
			}
		}

		private static void GameStartPrologue()
		{
			try
			{
				if ((Object)(object)SaveLoadMenu.instance != (Object)null)
				{
					SaveLoadMenu.instance.Reset();
				}
				EnsureSavingObject();
			}
			catch (Exception arg)
			{
				GameSaver.LogError($"preparing a new game failed: {arg}");
			}
		}

		internal static IEnumerator GameStart(IGameModeHandler gm)
		{
			GameStartPrologue();
			_round = 1;
			_gameGuid = Guid.NewGuid();
			yield return RunGuarded(LoadSave(), "restoring a save");
			yield return RunGuarded(PreSave(), "creating the save folder");
		}

		internal static IEnumerator GameEnd(IGameModeHandler gm)
		{
			if ((Object)(object)_savingObject != (Object)null)
			{
				Object.Destroy((Object)(object)_savingObject);
				_savingObject = null;
			}
			_selectedSave = null;
			SuppressOpeningPick = false;
			yield return null;
		}

		internal static void SelectSave(GameData gameData, SaveData selectedSave)
		{
			_selectedSave = selectedSave;
			GameModeManager.SetGameMode(gameData.gameMode);
			ExtensionMethods.InvokeMethod((object)PrivateRoomHandler.instance, "UnreadyAllPlayers", Array.Empty<object>());
			ObjectExtensions.ExecuteAfterGameModeInitialized((MonoBehaviour)(object)PrivateRoomHandler.instance, gameData.gameMode, (Action)delegate
			{
				SyncMethodStatic.SyncMethod(typeof(PrivateRoomHandler), "SetGameSettings", (int[])null, new object[2]
				{
					GameModeManager.CurrentHandlerID,
					GameModeManager.CurrentHandler.Settings
				});
				ExtensionMethods.InvokeMethod((object)PrivateRoomHandler.instance, "HandleTeamRules", Array.Empty<object>());
			});
		}

		internal static IEnumerator RoundStart(IGameModeHandler gm)
		{
			if ((Object)(object)_savingObject != (Object)null)
			{
				_savingObject.SetActive(false);
			}
			yield return null;
		}

		internal static IEnumerator RoundEnd(IGameModeHandler gm)
		{
			_round++;
			yield return null;
		}

		internal static IEnumerator PickEnd(IGameModeHandler gm)
		{
			SuppressOpeningPick = false;
			yield return RunGuarded(Save(SaveType.PickEnd), "auto-saving after the pick phase");
		}

		internal static IEnumerator Save(SaveType saveType)
		{
			if ((ConfigManager.SaveEnabled != null && !ConfigManager.SaveEnabled.Value) || (ConfigManager.SaveAsHostOnly != null && ConfigManager.SaveAsHostOnly.Value && !PhotonNetwork.OfflineMode && !PhotonNetwork.IsMasterClient) || string.IsNullOrEmpty(_gameSavesPath))
			{
				yield break;
			}
			EnsureSavingObject();
			if ((Object)(object)_savingObject != (Object)null)
			{
				_savingObject.SetActive(true);
				ExtensionMethods.GetOrAddComponent<AnimationAutoDestroy>(_savingObject, false);
			}
			yield return null;
			List<string> list = new List<string>();
			bool flag = PhotonNetwork.OfflineMode || PhotonNetwork.CurrentRoom == null;
			int num = 1;
			foreach (Player item in PlayerManager.instance.players.Where((Player player) => (Object)(object)player != (Object)null))
			{
				Player val = (flag ? null : PhotonNetwork.CurrentRoom.GetPlayer(item.data.view.OwnerActorNr));
				string name = (flag ? (SteamFriends.GetPersonaName() + "-" + num) : (((val != null) ? val.NickName : null) ?? ("Player " + num)));
				List<CardInfo> cards = new List<CardInfo>(item.data.currentCards);
				TeamScore teamScore = GameModeManager.CurrentHandler.GetTeamScore(item.teamID);
				bool host = (flag ? (num == 1) : (val != null && val.IsMasterClient));
				ulong value;
				ulong steamId = (flag ? 1 : (SteamManager.steamIds.TryGetValue(item.data.view.OwnerActorNr, out value) ? value : 1));
				list.Add(JsonUtility.ToJson((object)new PlayerData(name, PlayerExtensions.colorID(item), item.teamID, cards, teamScore.points, teamScore.rounds, host, steamId)));
				num++;
			}
			int pointsToWinRound = (int)GameModeManager.CurrentHandler.Settings["pointsToWinRound"];
			int pointsToWin = (int)GameModeManager.CurrentHandler.Settings["roundsToWinGame"];
			SaveData saveData = new SaveData(DateTime.Now, saveType, _round, pointsToWinRound, pointsToWin, list);
			try
			{
				File.WriteAllText(Path.Combine(_gameSavesPath, "save" + DateTime.Now.ToBinary() + ".json"), JsonUtility.ToJson((object)saveData, true));
			}
			catch (Exception ex)
			{
				GameSaver.LogError("could not write save file: " + ex.Message);
			}
			yield return null;
		}

		public static void DeleteGameSave(GameInfoData gameInfoData)
		{
			_games.Remove(gameInfoData);
			if ((Object)(object)SaveLoadMenu.instance != (Object)null)
			{
				SaveLoadMenu.instance.RemoveGameSaveButtons(gameInfoData);
			}
			try
			{
				if (Directory.Exists(gameInfoData.FilePath))
				{
					Directory.Delete(gameInfoData.FilePath, recursive: true);
				}
			}
			catch (Exception ex)
			{
				GameSaver.LogError("could not delete save folder: " + ex.Message);
			}
		}
	}
	internal static class ShareCodec
	{
		[Serializable]
		private class Payload
		{
			public SaveManager.GameData game;

			public SaveManager.SaveData save;
		}

		internal static string Encode(SaveManager.GameData game, SaveManager.SaveData save)
		{
			string s = JsonUtility.ToJson((object)new Payload
			{
				game = game,
				save = save
			});
			return TextCodec.Frame(TextCodec.Deflate(Encoding.UTF8.GetBytes(s)));
		}

		internal static bool TryDecode(string code, out SaveManager.GameData game, out SaveManager.SaveData save, out string error)
		{
			game = null;
			save = null;
			if (!TextCodec.TryUnframe(code, out var compressed, out error))
			{
				return false;
			}
			try
			{
				Payload payload = JsonUtility.FromJson<Payload>(Encoding.UTF8.GetString(TextCodec.Inflate(compressed)));
				if (payload?.game == null || payload.save == null)
				{
					error = "CODE UNREADABLE";
					return false;
				}
				game = payload.game;
				save = payload.save;
				return true;
			}
			catch (Exception ex)
			{
				GameSaver.LogWarning("could not decode share code: " + ex.Message);
				error = "CODE UNREADABLE";
				return false;
			}
		}
	}
	internal static class ShareManager
	{
		internal class ExportResult
		{
			public bool Success;

			public string Code;

			public string FilePath;

			public string Error;

			public bool FitsInOneMessage
			{
				get
				{
					if (Code != null)
					{
						return Code.Length <= 2000;
					}
					return false;
				}
			}
		}

		internal class ImportResult
		{
			public bool Success;

			public string Error;

			public int Round;

			public bool AlreadyHad;
		}

		internal const int ChatMessageLimit = 2000;

		internal static string SharedFolder => Path.Combine(SaveManager.SavesPath, "_shared");

		internal static ExportResult Export(SaveManager.GameData game, SaveManager.SaveData save)
		{
			ExportResult exportResult = new ExportResult();
			try
			{
				exportResult.Code = ShareCodec.Encode(game, save);
				try
				{
					GUIUtility.systemCopyBuffer = exportResult.Code;
				}
				catch (Exception ex)
				{
					GameSaver.LogWarning("could not copy the code to the clipboard: " + ex.Message);
				}
				try
				{
					Directory.CreateDirectory(SharedFolder);
					string text = $"round{save.round}-{game.gameMode}-{save.Time:yyyyMMdd-HHmmss}.txt";
					char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
					foreach (char oldChar in invalidFileNameChars)
					{
						text = text.Replace(oldChar, '_');
					}
					exportResult.FilePath = Path.Combine(SharedFolder, text);
					File.WriteAllText(exportResult.FilePath, exportResult.Code);
				}
				catch (Exception ex2)
				{
					exportResult.FilePath = null;
					GameSaver.LogWarning("could not write the share file: " + ex2.Message);
				}
				exportResult.Success = true;
				GameSaver.LogInfo($"exported round {save.round} as a {exportResult.Code.Length} character code" + ((exportResult.FilePath != null) ? (" (also saved to " + exportResult.FilePath + ")") : ""));
			}
			catch (Exception arg)
			{
				exportResult.Error = "EXPORT FAILED";
				GameSaver.LogError($"could not export the save: {arg}");
			}
			return exportResult;
		}

		internal static ImportResult Import(string code)
		{
			ImportResult importResult = new ImportResult();
			if (!ShareCodec.TryDecode(code, out var game, out var save, out var error))
			{
				importResult.Error = error;
				return importResult;
			}
			try
			{
				string text = FindFolderForGame(game) ?? CreateFolderForGame(game);
				string path = "save" + save._serializedDateTime + ".json";
				string path2 = Path.Combine(text, path);
				if (File.Exists(path2))
				{
					importResult.Success = true;
					importResult.AlreadyHad = true;
					importResult.Round = save.round;
					return importResult;
				}
				File.WriteAllText(path2, JsonUtility.ToJson((object)save, true));
				SaveManager.LoadGames();
				importResult.Success = true;
				importResult.Round = save.round;
				GameSaver.LogInfo($"imported round {save.round} ({game.gameMode}) into {text}");
			}
			catch (Exception arg)
			{
				importResult.Error = "IMPORT FAILED";
				GameSaver.LogError($"could not import the save: {arg}");
			}
			return importResult;
		}

		private static string FindFolderForGame(SaveManager.GameData game)
		{
			if (!Directory.Exists(SaveManager.SavesPath))
			{
				return null;
			}
			string[] directories = Directory.GetDirectories(SaveManager.SavesPath);
			foreach (string text in directories)
			{
				if (!Path.GetFileName(text).StartsWith("Game-", StringComparison.Ordinal))
				{
					continue;
				}
				string path = Path.Combine(text, "game.json");
				if (!File.Exists(path))
				{
					continue;
				}
				try
				{
					SaveManager.GameData gameData = JsonUtility.FromJson<SaveManager.GameData>(File.ReadAllText(path));
					if (gameData != null && gameData._serializedStartTime == game._serializedStartTime)
					{
						return text;
					}
				}
				catch (Exception)
				{
				}
			}
			return null;
		}

		private static string CreateFolderForGame(SaveManager.GameData game)
		{
			string text = Path.Combine(SaveManager.SavesPath, "Game-" + Guid.NewGuid());
			Directory.CreateDirectory(text);
			File.WriteAllText(Path.Combine(text, "game.json"), JsonUtility.ToJson((object)game));
			return text;
		}
	}
	internal class SteamManager
	{
		public static Dictionary<int, ulong> steamIds = new Dictionary<int, ulong>();

		public static Player GetPlayerFromSteamId(ulong steamId)
		{
			if (steamId <= 1 || steamIds.Count == 0)
			{
				return null;
			}
			foreach (Player player in PlayerManager.instance.players)
			{
				if (!((Object)(object)player?.data?.view == (Object)null) && steamIds.TryGetValue(player.data.view.OwnerActorNr, out var value) && value == steamId)
				{
					return player;
				}
			}
			return null;
		}
	}
	internal static class TextCodec
	{
		internal const string Prefix = "GS1";

		private static uint[] _crcTable;

		internal static string Frame(byte[] compressed)
		{
			return string.Format("{0}-{1:x8}-{2}", "GS1", Crc32(compressed), ToBase64Url(compressed));
		}

		internal static bool TryUnframe(string code, out byte[] compressed, out string error)
		{
			compressed = null;
			error = null;
			if (string.IsNullOrEmpty(code))
			{
				error = "NO CODE";
				return false;
			}
			string[] array = StripWhitespace(code).Split(new char[1] { '-' }, 3);
			if (array.Length != 3 || array[0] != "GS1")
			{
				error = "NOT A GAMESAVER CODE";
				return false;
			}
			if (!uint.TryParse(array[1], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result))
			{
				error = "NOT A GAMESAVER CODE";
				return false;
			}
			byte[] array2;
			try
			{
				array2 = FromBase64Url(array[2]);
			}
			catch (Exception)
			{
				error = "CODE CORRUPTED";
				return false;
			}
			if (Crc32(array2) != result)
			{
				error = "CODE INCOMPLETE";
				return false;
			}
			compressed = array2;
			return true;
		}

		internal static byte[] Deflate(byte[] data)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Compress, leaveOpen: true))
			{
				deflateStream.Write(data, 0, data.Length);
			}
			return memoryStream.ToArray();
		}

		internal static byte[] Inflate(byte[] data)
		{
			using MemoryStream stream = new MemoryStream(data);
			using DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress);
			using MemoryStream memoryStream = new MemoryStream();
			byte[] array = new byte[8192];
			int count;
			while ((count = deflateStream.Read(array, 0, array.Length)) > 0)
			{
				memoryStream.Write(array, 0, count);
			}
			return memoryStream.ToArray();
		}

		internal static string ToBase64Url(byte[] data)
		{
			return Convert.ToBase64String(data).Replace('+', '-').Replace('/', '_')
				.TrimEnd(new char[1] { '=' });
		}

		internal static byte[] FromBase64Url(string text)
		{
			string text2 = text.Replace('-', '+').Replace('_', '/');
			switch (text2.Length % 4)
			{
			case 2:
				text2 += "==";
				break;
			case 3:
				text2 += "=";
				break;
			case 1:
				throw new FormatException("bad base64url length");
			}
			return Convert.FromBase64String(text2);
		}

		internal static string StripWhitespace(string text)
		{
			StringBuilder stringBuilder = new StringBuilder(text.Length);
			foreach (char c in text)
			{
				if (!char.IsWhiteSpace(c))
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}

		internal static uint Crc32(byte[] data)
		{
			if (_crcTable == null)
			{
				uint[] array = new uint[256];
				for (uint num = 0u; num < 256; num++)
				{
					uint num2 = num;
					for (int i = 0; i < 8; i++)
					{
						num2 = (((num2 & 1) == 1) ? (0xEDB88320u ^ (num2 >> 1)) : (num2 >> 1));
					}
					array[num] = num2;
				}
				_crcTable = array;
			}
			uint num3 = uint.MaxValue;
			foreach (byte b in data)
			{
				num3 = _crcTable[(num3 ^ b) & 0xFF] ^ (num3 >> 8);
			}
			return num3 ^ 0xFFFFFFFFu;
		}
	}
}
namespace GameSaver.Patches
{
	internal static class OpeningPickPatch
	{
		internal static void Apply(Harmony harmony)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method("RWF.PlayerManagerExtensions:GetPickOrder", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				GameSaver.LogWarning("could not find RWF.PlayerManagerExtensions.GetPickOrder - loading a save will still run the opening card pick.");
			}
			else
			{
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(OpeningPickPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void Postfix(int[] winningTeamIDs, ref List<Player> __result)
		{
			if (SaveManager.SuppressOpeningPick && winningTeamIDs == null)
			{
				GameSaver.LogInfo($"skipping the opening card pick for {__result?.Count ?? 0} player(s) - a save is being restored.");
				__result = new List<Player>();
			}
		}
	}
}
namespace GameSaver.Network
{
	public class LobbyMonitor : MonoBehaviourPunCallbacks
	{
		private static GameObject _loadSaveRow;

		private static SaveLoadMenu _menu;

		private static TMP_FontAsset _menuFont;

		public static LobbyMonitor Instance { get; private set; }

		public static TMP_FontAsset MenuFont
		{
			get
			{
				if (Object.op_Implicit((Object)(object)_menuFont) || !Object.op_Implicit((Object)(object)MainMenuHandler.instance))
				{
					return _menuFont;
				}
				Transform val = ((Component)MainMenuHandler.instance).transform.Find("Canvas/ListSelector/Main/Group/Local");
				if ((Object)(object)val == (Object)null)
				{
					return _menuFont;
				}
				TextMeshProUGUI componentInChildren = ((Component)val).GetComponentInChildren<TextMeshProUGUI>();
				_menuFont = ((componentInChildren != null) ? ((TMP_Text)componentInChildren).font : null);
				return _menuFont;
			}
		}

		private void Awake()
		{
			Instance = this;
		}

		public override void OnCreatedRoom()
		{
		}

		public override void OnJoinedRoom()
		{
			if (PhotonNetwork.OfflineMode)
			{
				return;
			}
			SteamManager.steamIds.Clear();
			ExtensionMethods.ExecuteAfterFrames((MonoBehaviour)(object)Unbound.Instance, 1, (Action)LoadSaveButton);
			ExtensionMethods.ExecuteAfterSeconds((MonoBehaviour)(object)Unbound.Instance, 2f, (Action)delegate
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					SendSteamId(PhotonNetwork.LocalPlayer.ActorNumber, SteamUser.GetSteamID().m_SteamID);
				}
				catch (Exception ex)
				{
					GameSaver.LogWarning("could not broadcast steam id: " + ex.Message);
				}
			});
		}

		public override void OnPlayerEnteredRoom(Player newPlayer)
		{
			if (!PhotonNetwork.IsMasterClient)
			{
				return;
			}
			ExtensionMethods.ExecuteAfterSeconds((MonoBehaviour)(object)Unbound.Instance, 2.5f, (Action)delegate
			{
				foreach (KeyValuePair<int, ulong> steamId in SteamManager.steamIds)
				{
					SendSteamId(steamId.Key, steamId.Value);
				}
			});
		}

		public override void OnLeftRoom()
		{
			SaveManagerResetSelection();
			if (!((Object)(object)SaveLoadMenu.instance == (Object)null))
			{
				SaveLoadMenu.instance.Reset();
			}
		}

		private static void SaveManagerResetSelection()
		{
			SaveManager._selectedSave = null;
		}

		public static void SendSteamId(int player, ulong steamId)
		{
			NetworkingManager.RPC(typeof(LobbyMonitor), "SyncSteamId", new object[2]
			{
				player,
				steamId.ToString()
			});
		}

		[UnboundRPC]
		private static void SyncSteamId(int player, string serializedSteamId)
		{
			try
			{
				SteamManager.steamIds[player] = ulong.Parse(serializedSteamId);
			}
			catch (Exception ex)
			{
				GameSaver.LogWarning($"could not record steam id for actor {player}: {ex.Message}");
			}
		}

		public void LoadSaveButton()
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Expected O, but got Unknown
			if (!PhotonNetwork.IsMasterClient || GameSaver.AssetsFailed)
			{
				return;
			}
			GameObject val = GameObject.Find("PrivateRoom/Main/Group");
			if ((Object)(object)val == (Object)null)
			{
				GameSaver.LogWarning("private room UI not found - the LOAD button was not added.");
				return;
			}
			if ((Object)(object)_loadSaveRow != (Object)null)
			{
				Object.Destroy((Object)(object)_loadSaveRow);
			}
			if ((Object)(object)_menu != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_menu).gameObject);
			}
			Transform val2 = val.transform.Find("LOAD_SAVE");
			if ((Object)(object)val2 != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val2).gameObject);
			}
			GameObject val3 = new GameObject("LOAD_SAVE");
			val3.transform.SetParent(val.transform);
			val3.transform.localScale = Vector3.one;
			val3.transform.SetSiblingIndex(val3.transform.GetSiblingIndex() - 1);
			GameObject text = GetText("LOAD");
			text.transform.SetParent(val3.transform);
			text.transform.localScale = Vector3.one;
			val3.AddComponent<RectTransform>();
			val3.AddComponent<CanvasRenderer>();
			val3.AddComponent<LayoutElement>().minHeight = 92f;
			ListMenuButton val4 = val3.AddComponent<ListMenuButton>();
			val4.setBarHeight = 92f;
			GameObject val5 = Object.Instantiate<GameObject>(AssetManager.ElementSection);
			SaveLoadMenu saveLoadMenu = val5.AddComponent<SaveLoadMenu>();
			saveLoadMenu.lobbyUi = val;
			saveLoadMenu.listMenuButton = val4;
			((UnityEvent)val3.AddComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				saveLoadMenu.Open();
			});
			_loadSaveRow = val3;
			_menu = saveLoadMenu;
		}

		public GameObject GetText(string str)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			GameObject val = new GameObject("Text");
			val.AddComponent<CanvasRenderer>();
			TextMeshProUGUI obj = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj).text = str;
			((Graphic)obj).color = Color32.op_Implicit(new Color32((byte)230, (byte)230, (byte)230, byte.MaxValue));
			((TMP_Text)obj).font = MenuFont;
			((TMP_Text)obj).fontSize = 60f;
			((TMP_Text)obj).fontWeight = (FontWeight)400;
			((TMP_Text)obj).alignment = (TextAlignmentOptions)514;
			((TMP_Text)obj).rectTransform.sizeDelta = new Vector2(2050f, 92f);
			return val;
		}
	}
}
namespace GameSaver.Menu
{
	internal class SaveLoadMenu : MonoBehaviour
	{
		public static SaveLoadMenu instance;

		public Camera gameCamera;

		private Canvas canvas;

		private CanvasGroup canvasGroup;

		public GameObject lobbyUi;

		public ListMenuButton listMenuButton;

		private bool open;

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

		private TextMeshProUGUI _selectedText;

		private SaveManager.GameInfoData _selectedGame;

		private SaveManager.SaveData _selectedSave;

		private Coroutine _loadButtonsRoutine;

		private Coroutine _gameRoutine;

		private Coroutine _saveRoutine;

		private Coroutine _swoopRoutine;

		private Vector2 _lobbyRest;

		private bool _lobbyRestCaptured;

		private TextMeshProUGUI savedGamesText;

		private TextMeshProUGUI _loadText;

		private int lastGameCount = -1;

		private Transform _gameButtonContainer;

		private Transform _roundButtonContainer;

		private Transform _roundDisplayContainer;

		private Transform _playerContainer;

		private void Start()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Expected O, but got Unknown
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Expected O, but got Unknown
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Expected O, but got Unknown
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Expected O, but got Unknown
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Expected O, but got Unknown
			instance = this;
			gameCamera = Camera.main;
			((Transform)((Component)this).gameObject.GetComponent<RectTransform>()).localScale = Vector3.one;
			canvas = ((Component)this).gameObject.GetComponent<Canvas>();
			canvas.worldCamera = gameCamera;
			canvasGroup = ((Component)this).gameObject.GetComponent<CanvasGroup>();
			Transform child = ((Component)this).transform.GetChild(1);
			_gameButtonContainer = child.GetChild(0).GetChild(0).GetChild(0);
			Transform child2 = child.GetChild(1).GetChild(0);
			_roundButtonContainer = child2.GetChild(0).GetChild(0).GetChild(0);
			Transform child3 = child2.GetChild(1);
			_roundDisplayContainer = child3.GetChild(0);
			_playerContainer = child3.GetChild(0).GetChild(0).GetChild(0);
			GameObject gameObject = ((Component)((Component)this).gameObject.transform.Find("Buttons/LoadButton")).gameObject;
			_loadText = ((Component)gameObject.transform).GetComponentInChildren<TextMeshProUGUI>();
			((UnityEvent)gameObject.GetComponent<Button>().onClick).AddListener(new UnityAction(OnLoadClicked));
			((UnityEvent)((Component)((Component)this).gameObject.transform.Find("Buttons/BackButton")).gameObject.GetComponent<Button>().onClick).AddListener(new UnityAction(Close));
			Transform child4 = ((Component)this).transform.GetChild(4);
			Canvas uiExportImportCanvas = ((Component)child4).GetComponent<Canvas>();
			((Component)child4.GetChild(4)).gameObject.SetActive(false);
			Transform child5 = child4.GetChild(2);
			Canvas uiExportCanvas = ((Component)child5).GetComponent<Canvas>();
			TMP_InputField uiExportText = ((Component)child5).GetComponentInChildren<TMP_InputField>();
			((UnityEvent)((Component)child5).GetComponentInChildren<Button>().onClick).AddListener((UnityAction)delegate
			{
				OnExportClicked(uiExportText);
			});
			Transform child6 = child4.GetChild(3);
			Canvas uiImportCanvas = ((Component)child6).GetComponent<Canvas>();
			TMP_InputField uiImportText = ((Component)child6).GetComponentInChildren<TMP_InputField>();
			((UnityEvent)((Component)child6).GetComponentInChildren<Button>().onClick).AddListener((UnityAction)delegate
			{
				OnImportClicked(uiImportText, uiExportImportCanvas);
			});
			Transform child7 = ((Component)this).transform.GetChild(0);
			((UnityEvent)((Component)child7.GetChild(0)).GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				((Behaviour)uiExportImportCanvas).enabled = true;
				((Behaviour)uiImportCanvas).enabled = false;
				((Behaviour)uiExportCanvas).enabled = true;
			});
			((UnityEvent)((Component)child7.GetChild(1)).GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				((Behaviour)uiExportImportCanvas).enabled = true;
				((Behaviour)uiExportCanvas).enabled = false;
				((Behaviour)uiImportCanvas).enabled = true;
			});
			savedGamesText = ((Component)((Component)this).transform.GetChild(3).GetChild(0)).GetComponentInChildren<TextMeshProUGUI>();
			Active(active: false);
		}

		private void OnExportClicked(TMP_InputField field)
		{
			if (_selectedSave == null || _selectedGame?.gameData == null)
			{
				ShowFieldMessage(field, "SELECT A SAVE FIRST");
				return;
			}
			ShareManager.ExportResult exportResult = ShareManager.Export(_selectedGame.gameData, _selectedSave);
			if (!exportResult.Success)
			{
				ShowFieldMessage(field, exportResult.Error ?? "EXPORT FAILED");
			}
			else
			{
				ShowFieldMessage(field, exportResult.FitsInOneMessage ? $"COPIED - {exportResult.Code.Length} CHARS" : $"COPIED - {exportResult.Code.Length} CHARS, TOO LONG TO CHAT, SEND THE FILE IN {ShareManager.SharedFolder}");
			}
		}

		private void OnImportClicked(TMP_InputField field, Canvas panel)
		{
			TextMeshProUGUI placeholder = (Object.op_Implicit((Object)(object)field.placeholder) ? ((Component)field.placeholder).GetComponent<TextMeshProUGUI>() : null);
			string text = field.text;
			if (string.IsNullOrEmpty(text) || text.Trim().Length == 0)
			{
				try
				{
					text = GUIUtility.systemCopyBuffer;
				}
				catch (Exception ex)
				{
					GameSaver.LogWarning("could not read the clipboard: " + ex.Message);
				}
			}
			field.text = "";
			ShareManager.ImportResult importResult = ShareManager.Import(text);
			if (!importResult.Success)
			{
				FlashPlaceholder(placeholder, importResult.Error ?? "IMPORT FAILED");
				return;
			}
			RefreshAfterImport();
			FlashPlaceholder(placeholder, importResult.AlreadyHad ? $"ALREADY HAD ROUND {importResult.Round}" : $"IMPORTED ROUND {importResult.Round}");
			if (!importResult.AlreadyHad && Object.op_Implicit((Object)(object)panel))
			{
				((Behaviour)panel).enabled = false;
			}
		}

		private void ShowFieldMessage(TMP_InputField field, string message)
		{
			if (Object.op_Implicit((Object)(object)field))
			{
				field.text = message;
			}
		}

		private void FlashPlaceholder(TextMeshProUGUI placeholder, string message)
		{
			if (!Object.op_Implicit((Object)(object)placeholder))
			{
				return;
			}
			string original = ((TMP_Text)placeholder).text;
			((TMP_Text)placeholder).text = message;
			ExtensionMethods.ExecuteAfterSeconds((MonoBehaviour)(object)Unbound.Instance, 2f, (Action)delegate
			{
				if (Object.op_Implicit((Object)(object)placeholder))
				{
					((TMP_Text)placeholder).text = original;
				}
			});
		}

		private void OnLoadClicked()
		{
			try
			{
				if (_selectedSave == null)
				{
					Flash("SAVE NOT SELECTED");
					return;
				}
				if (SaveManager._selectedSave == _selectedSave)
				{
					SaveManager._selectedSave = null;
					if (Object.op_Implicit((Object)(object)_selectedText))
					{
						((TMP_Text)_selectedText).text = "";
					}
					_selectedText = null;
					Flash("UNLOADED");
					return;
				}
				if (_selectedGame?.gameData == null)
				{
					Flash("SAVE NOT SELECTED");
					return;
				}
				SaveManager.GameData gameData = _selectedGame.gameData;
				if (!GameModeManager.GameModes.ContainsKey(gameData.gameMode))
				{
					Flash("UNKNOWN GAMEMODE");
					return;
				}
				SaveManager.SelectSave(gameData, _selectedSave);
				if (Object.op_Implicit((Object)(object)_selectedText))
				{
					((TMP_Text)_selectedText).text = "";
				}
				if (Object.op_Implicit((Object)(object)_selectedSave.loaded))
				{
					_selectedText = _selectedSave.loaded;
					((TMP_Text)_selectedSave.loaded).text = "LOADED";
				}
				Close();
			}
			catch (Exception arg)
			{
				GameSaver.LogError($"loading the selected save failed: {arg}");
				Flash("LOAD FAILED");
			}
		}

		private void RefreshLoadButtonLabel()
		{
			if (Object.op_Implicit((Object)(object)_loadText))
			{
				((TMP_Text)_loadText).text = ((SaveManager._selectedSave != null) ? ("UNLOAD SAVE: " + SaveManager._selectedSave.Time) : "LOAD");
			}
		}

		private void Flash(string message)
		{
			if (Object.op_Implicit((Object)(object)_loadText))
			{
				((TMP_Text)_loadText).text = message;
				ExtensionMethods.ExecuteAfterSeconds((MonoBehaviour)(object)Unbound.Instance, 1f, (Action)RefreshLoadButtonLabel);
			}
		}

		private void Hide(string objectName)
		{
			GameObject val = GameObject.Find(objectName);
			if (!((Object)(object)val == (Object)null) && val.activeSelf)
			{
				val.SetActive(false);
				_hidden.Add(val);
			}
		}

		public void Open()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			if (!open)
			{
				open = true;
				CaptureLobbyRest();
				Hide("Links(Clone)");
				Hide("UIHolder");
				Hide("LobbyImprovementsBG");
				Hide("TimerLobbyUI(Clone)");
				Hide("RoundCounterSmall");
				_swoopRoutine = Restart(_swoopRoutine, Swoop(lobbyUi, _lobbyRest + new Vector2(0f, (float)(Screen.height * 2))));
				if ((Object)(object)listMenuButton != (Object)null)
				{
					listMenuButton.OnPointerEnter((PointerEventData)null);
				}
				Active(active: true);
				SaveManager.LoadGames();
				UpdateGamesCount(SaveManager._games.Count);
				RefreshLoadButtonLabel();
				_loadButtonsRoutine = Restart(_loadButtonsRoutine, LoadGameButtons());
			}
		}

		private void CaptureLobbyRest()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (!_lobbyRestCaptured && Object.op_Implicit((Object)(object)lobbyUi))
			{
				RectTransform component = lobbyUi.GetComponent<RectTransform>();
				if (Object.op_Implicit((Object)(object)component))
				{
					_lobbyRest = component.anchoredPosition;
					_lobbyRestCaptured = true;
				}
			}
		}

		private void RestoreLobby()
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			foreach (GameObject item in _hidden.Where((GameObject hidden) => Object.op_Implicit((Object)(object)hidden)))
			{
				item.SetActive(true);
			}
			_hidden.Clear();
			if (Object.op_Implicit((Object)(object)lobbyUi) && _lobbyRestCaptured)
			{
				_swoopRoutine = Restart(_swoopRoutine, Swoop(lobbyUi, _lobbyRest));
			}
			Active(active: false);
		}

		public void Close()
		{
			if (!open)
			{
				return;
			}
			open = false;
			try
			{
				RestoreLobby();
			}
			finally
			{
				_selectedGame = null;
				_selectedSave = null;
				StopMenuCoroutines();
			}
		}

		private void StopMenuCoroutines()
		{
			Stop(ref _loadButtonsRoutine);
			Stop(ref _gameRoutine);
			Stop(ref _saveRoutine);
		}

		private void OnDestroy()
		{
			StopMenuCoroutines();
			Stop(ref _swoopRoutine);
			if ((Object)(object)instance == (Object)(object)this)
			{
				instance = null;
			}
		}

		private static void Stop(ref Coroutine routine)
		{
			Coroutine val = routine;
			routine = null;
			if (val != null && (Object)(object)GameSaver.Instance != (Object)null)
			{
				((MonoBehaviour)GameSaver.Instance).StopCoroutine(val);
			}
		}

		private static Coroutine Restart(Coroutine existing, IEnumerator routine)
		{
			if (existing != null && (Object)(object)GameSaver.Instance != (Object)null)
			{
				((MonoBehaviour)GameSaver.Instance).StopCoroutine(existing);
			}
			if (!((Object)(object)GameSaver.Instance != (Object)null))
			{
				return null;
			}
			return ((MonoBehaviour)GameSaver.Instance).StartCoroutine(routine);
		}

		public void Reset()
		{
			if (open)
			{
				RestoreLobby();
			}
			open = false;
			StopMenuCoroutines();
			foreach (SaveManager.GameInfoData orderedGame in SaveManager.orderedGames)
			{
				RemoveGameSaveButtons(orderedGame);
			}
			_selectedGame = null;
			_selectedSave = null;
			_selectedText = null;
			lastGameCount = -1;
		}

		internal void RefreshAfterImport()
		{
			if (!open)
			{
				return;
			}
			_selectedGame = null;
			_selectedSave = null;
			HideAllRoundButtons();
			HideAllPlayerAssets();
			foreach (SaveManager.GameInfoData orderedGame in SaveManager.orderedGames)
			{
				RemoveGameSaveButtons(orderedGame);
			}
			UpdateGamesCount(SaveManager._games.Count);
			_loadButtonsRoutine = Restart(_loadButtonsRoutine, LoadGameButtons());
		}

		public void RemoveGameSaveButtons(SaveManager.GameInfoData gameInfoData)
		{
			if (gameInfoData?.gameData == null)
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)gameInfoData.gameData.button))
			{
				Object.Destroy((Object)(object)gameInfoData.gameData.button);
				gameInfoData.gameData.button = null;
			}
			foreach (SaveManager.SaveData item in gameInfoData.gameSaves.Where((SaveManager.SaveData saveData) => saveData != null))
			{
				if (Object.op_Implicit((Object)(object)item.button))
				{
					Object.Destroy((Object)(object)item.button);
					item.button = null;
				}
				if (Object.op_Implicit((Object)(object)item.display))
				{
					Object.Destroy((Object)(object)item.display);
					item.display = null;
				}
				item.loaded = null;
				foreach (SaveManager.PlayerData item2 in item.players.Where((SaveManager.PlayerData playerData) => playerData != null))
				{
					if (Object.op_Implicit((Object)(object)item2.display))
					{
						Object.Destroy((Object)(object)item2.display);
						item2.display = null;
					}
				}
				item.InvalidateCards();
			}
		}

		private void Update()
		{
			if (SaveManager._games.Count != lastGameCount)
			{
				UpdateGamesCount(SaveManager._games.Count);
			}
		}

		public void UpdateGamesCount(int amount)
		{
			if (Object.op_Implicit((Object)(object)savedGamesText))
			{
				((TMP_Text)savedGamesText).text = $"SAVED GAMES: {amount}";
			}
			lastGameCount = amount;
		}

		private void BuildPlayerRow(SaveManager.SaveData saveData, SaveManager.PlayerData playerData, Transform playerContainer)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = (playerData.display = Object.Instantiate<GameObject>(AssetManager.Player, playerContainer));
			try
			{
				((Component)val.transform.GetChild(0).GetChild(0).GetChild(0)).gameObject.SetActive(playerData.host);
				((TMP_Text)((Component)val.transform.GetChild(0).GetChild(1)).GetComponent<TextMeshProUGUI>()).text = playerData.name;
				TextMeshProUGUI component = ((Component)val.transform.GetChild(2)).GetComponent<TextMeshProUGUI>();
				((TMP_Text)component).text = ExtraPlayerSkins.GetTeamColorName(playerData.serializedColor).ToUpper();
				((Graphic)component).color = playerData.Color.color;
				Transform child = ((Component)val.transform.GetChild(1).GetChild(0)).gameObject.transform.GetChild(0).GetChild(0);
				foreach (CardInfo card in playerData.Cards)
				{
					GameObject obj = Object.Instantiate<GameObject>(AssetManager.Card, child);
					((TMP_Text)((Component)obj.transform).GetComponentInChildren<TextMeshProUGUI>()).text = (Object.op_Implicit((Object)(object)card) ? CardInitials(card) : "???");
					((Graphic)((Component)obj.transform).GetComponent<Image>()).color = playerData.Color.color;
					CardDisplayMono orAddComponent = ExtensionMethods.GetOrAddComponent<CardDisplayMono>(obj, false);
					orAddComponent.container = val.transform;
					orAddComponent.card = card;
					orAddComponent.color = playerData.Color.color;
				}
				Transform child2 = val.transform.GetChild(3);
				for (int i = 0; i < saveData.pointsToWin; i++)
				{
					Image componentInChildren = Object.Instantiate<GameObject>(AssetManager.Point, child2).GetComponentInChildren<Image>();
					((Graphic)componentInChildren).color = playerData.Color.color;
					if (i == playerData.rounds)
					{
						float num = ((playerData.points == 0 || saveData.pointsToWinRound == 0) ? 0f : ((float)playerData.points / (float)saveData.pointsToWinRound));
						if (num <= 0f)
						{
							((Component)componentInChildren).gameObject.GetComponent<RectTransform>().sizeDelta = new Vector2(5f, 5f);
							((Graphic)componentInChildren).color = Color.gray;
						}
						else
						{
							componentInChildren.fillAmount = num;
						}
					}
					else if (i > playerData.rounds)
					{
						((Component)componentInChildren).gameObject.GetComponent<RectTransform>().sizeDelta = new Vector2(5f, 5f);
						((Graphic)componentInChildren).color = Color.gray;
					}
				}
			}
			catch (Exception arg)
			{
				GameSaver.LogError($"could not build the row for '{playerData.name}': {arg}");
				Object.Destroy((Object)(object)val);
				playerData.display = null;
			}
		}

		private void BuildRoundButton(SaveManager.GameInfoData gameInfoData, SaveManager.SaveData saveData)
		{
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Expected O, but got Unknown
			GameObject val = Object.Instantiate<GameObject>(AssetManager.SaveInfo, _roundDisplayContainer);
			saveData.display = val;
			try
			{
				((TMP_Text)((Component)val.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).text = $"ROUND {saveData.round}";
				((TMP_Text)((Component)val.transform.GetChild(1).GetChild(1)).GetComponent<TextMeshProUGUI>()).text = $"{saveData.players.Count}/32";
				((TMP_Text)((Component)val.transform.GetChild(2)).GetComponent<TextMeshProUGUI>()).text = gameInfoData.gameData.gameMode.ToUpper();
				saveData.loaded = ((Component)val.transform.GetChild(3)).GetComponent<TextMeshProUGUI>();
				((TMP_Text)saveData.loaded).text = "";
				val.SetActive(false);
			}
			catch (Exception arg)
			{
				GameSaver.LogError($"could not build the round header for round {saveData.round}: {arg}");
				Object.Destroy((Object)(object)val);
				saveData.display = null;
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(AssetManager.RoundButton, _roundButtonContainer);
			saveData.button = val2;
			try
			{
				string[] array = $"{saveData.Time}".Split(new char[1] { ' ' });
				((TMP_Text)((Component)val2.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).text = ((array.Length > 1) ? (array[1] + "\n" + array[0]) : $"{saveData.Time}");
				((TMP_Text)((Component)val2.transform.GetChild(1).GetChild(0)).GetComponent<TextMeshProUGUI>()).text = $"ROUND {saveData.round}";
				((TMP_Text)((Component)val2.transform.GetChild(3)).GetComponent<TextMeshProUGUI>()).text = Regex.Replace(saveData.saveType.ToString(), "([a-z])_?([A-Z])", "$1\n$2").ToUpper();
				((UnityEvent)val2.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
				{
					OnRoundClicked(saveData);
				});
				val2.SetActive(false);
			}
			catch (Exception arg2)
			{
				GameSaver.LogError($"could not build the round button for round {saveData.round}: {arg2}");
				Object.Destroy((Object)(object)val2);
				saveData.button = null;
			}
		}

		private void OnRoundClicked(SaveManager.SaveData saveData)
		{
			if (_selectedSave != saveData)
			{
				_selectedSave = saveData;
				HideAllPlayerAssets();
				_saveRoutine = Restart(_saveRoutine, ShowSaveRoutine(saveData));
			}
		}

		private IEnumerator ShowSaveRoutine(SaveManager.SaveData saveData)
		{
			if (Object.op_Implicit((Object)(object)saveData.display))
			{
				saveData.display.SetActive(true);
			}
			foreach (SaveManager.PlayerData item in saveData.players.Where((SaveManager.PlayerData playerData) => playerData != null))
			{
				if (!Object.op_Implicit((Object)(object)item.display))
				{
					BuildPlayerRow(saveData, item, _playerContainer);
				}
				if (Object.op_Implicit((Object)(object)item.display))
				{
					item.display.SetActive(true);
				}
				yield return null;
			}
		}

		private void OnGameClicked(SaveManager.GameInfoData gameInfoData)
		{
			if (_selectedGame != gameInfoData)
			{
				_selectedGame = gameInfoData;
				_selectedSave = null;
				HideAllRoundButtons();
				HideAllPlayerAssets();
				Stop(ref _saveRoutine);
				_gameRoutine = Restart(_gameRoutine, ShowGameRoutine(gameInfoData));
			}
		}

		private IEnumerator ShowGameRoutine(SaveManager.GameInfoData gameInfoData)
		{
			foreach (SaveManager.SaveData item in from saveData in gameInfoData.gameSaves
				where saveData != null
				orderby saveData._serializedDateTime descending
				select saveData)
			{
				if (!Object.op_Implicit((Object)(object)item.button))
				{
					BuildRoundButton(gameInfoData, item);
				}
				if (Object.op_Implicit((Object)(object)item.button))
				{
					item.button.SetActive(true);
				}
				yield return null;
			}
		}

		private IEnumerator LoadGameButtons()
		{
			foreach (SaveManager.GameInfoData orderedGame in SaveManager.orderedGames)
			{
				if (orderedGame.rounds == 0)
				{
					continue;
				}
				if (Object.op_Implicit((Object)(object)orderedGame.gameData.button))
				{
					orderedGame.gameData.button.SetActive(true);
					continue;
				}
				GameObject val = Object.Instantiate<GameObject>(AssetManager.GameButton, _gameButtonContainer);
				orderedGame.gameData.button = val;
				try
				{
					Transform transform = val.transform;
					string[] array = $"{orderedGame.gameData.StartTime}".Split(new char[1] { ' ' });
					((TMP_Text)((Component)transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).text = ((array.Length > 1) ? (array[1] + " " + array[0]) : $"{orderedGame.gameData.StartTime}");
					((TMP_Text)((Component)transform.GetChild(1).GetChild(1)).GetComponent<TextMeshProUGUI>()).text = orderedGame.rounds.ToString();
					((TMP_Text)((Component)transform.GetChild(2).GetChild(1)).GetComponent<TextMeshProUGUI>()).text = $"{orderedGame.gameData.playerAmount}/32";
					((TMP_Text)((Component)transform.GetChild(3)).GetComponent<TextMeshProUGUI>()).text = orderedGame.gameData.gameMode.ToUpper();
					SaveManager.GameInfoData captured = orderedGame;
					((UnityEvent)val.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
					{
						OnGameClicked(captured);
					});
				}
				catch (Exception arg)
				{
					GameSaver.LogError($"could not build the game button: {arg}");
					Object.Destroy((Object)(object)val);
					orderedGame.gameData.button = null;
				}
				yield return null;
			}
		}

		internal string CardInitials(CardInfo card)
		{
			string cardName = card.cardName;
			if (string.IsNullOrEmpty(cardName))
			{
				return "??";
			}
			cardName = ((cardName.Length >= 2) ? cardName.Substring(0, 2) : cardName.Substring(0, 1));
			string text = cardName[0].ToString().ToUpper();
			if (cardName.Length <= 1)
			{
				return text;
			}
			return text + cardName[1].ToString().ToLower();
		}

		private static void HideAllRoundButtons()
		{
			foreach (SaveManager.GameInfoData orderedGame in SaveManager.orderedGames)
			{
				foreach (SaveManager.SaveData item in orderedGame.gameSaves.Where((SaveManager.SaveData saveData) => saveData != null))
				{
					if (Object.op_Implicit((Object)(object)item.button))
					{
						item.button.SetActive(false);
					}
					if (Object.op_Implicit((Object)(object)item.display))
					{
						item.display.SetActive(false);
					}
				}
			}
		}

		private static void HideAllPlayerAssets()
		{
			foreach (SaveManager.GameInfoData orderedGame in SaveManager.orderedGames)
			{
				foreach (SaveManager.SaveData item in orderedGame.gameSaves.Where((SaveManager.SaveData saveData) => saveData != null))
				{
					if (Object.op_Implicit((Object)(object)item.display))
					{
						item.display.SetActive(false);
					}
					if (!Object.op_Implicit((Object)(object)item.button))
					{
						continue;
					}
					foreach (SaveManager.PlayerData item2 in item.players.Where((SaveManager.PlayerData playerData) => playerData != null))
					{
						if (Object.op_Implicit((Object)(object)item2.display))
						{
							item2.display.SetActive(false);
						}
					}
				}
			}
		}

		private static IEnumerator Swoop(GameObject obj, Vector2 target)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)obj))
			{
				yield break;
			}
			RectTransform rect = obj.GetComponent<RectTransform>();
			if (!Object.op_Implicit((Object)(object)rect))
			{
				yield break;
			}
			float t = 0f;
			Vector2 startPos = rect.anchoredPosition;
			while (t < 0.25f)
			{
				t += Time.deltaTime;
				if (!Object.op_Implicit((Object)(object)rect))
				{
					yield break;
				}
				rect.anchoredPosition = Vector2.Lerp(startPos, target, t * 4f);
				yield return null;
			}
			if (Object.op_Implicit((Object)(object)rect))
			{
				rect.anchoredPosition = target;
			}
		}

		private void Active(bool active)
		{
			if (Object.op_Implicit((Object)(object)canvas))
			{
				((Behaviour)canvas).enabled = active;
			}
			if (Object.op_Implicit((Object)(object)canvasGroup))
			{
				canvasGroup.blocksRaycasts = active;
			}
		}
	}
}
namespace GameSaver.Component
{
	public class AnimationAutoDestroy : MonoBehaviour
	{
		private Animator _animator;

		private int _nextUpdate = 1;

		private int _play;

		private void Start()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			_animator = ((Component)this).GetComponentInChildren<Animator>(true);
			if ((Object)(object)_animator == (Object)null)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			AnimatorStateInfo currentAnimatorStateInfo = _animator.GetCurrentAnimatorStateInfo(0);
			_play = (int)((AnimatorStateInfo)(ref currentAnimatorStateInfo)).length;
		}

		private void Update()
		{
			if (Time.time >= (float)_nextUpdate)
			{
				_nextUpdate = Mathf.FloorToInt(Time.time) + 1;
				UpdateSecond();
			}
		}

		private void UpdateSecond()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_animator == (Object)null)
			{
				return;
			}
			AnimatorStateInfo currentAnimatorStateInfo = _animator.GetCurrentAnimatorStateInfo(0);
			if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime > 1f && !_animator.IsInTransition(0))
			{
				if (_play > 0)
				{
					_play--;
					return;
				}
				((Component)this).gameObject.SetActive(false);
				Object.Destroy((Object)(object)this);
			}
		}
	}
	internal class CardDisplayMono : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler
	{
		private static Canvas cardPreviewCanvas;

		private static GameObject cardPreview;

		private static Image cardPreviewImage;

		private static Image cardPreviewBackgroundImage;

		private static GameObject cardObject;

		private static TextMeshProUGUI noCardText;

		private static Rect cardPreviewRect;

		public Transform container;

		public CardInfo card;

		public Color color;

		private void Start()
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cardPreview == (Object)null || (Object)(object)cardPreviewCanvas == (Object)null)
			{
				if ((Object)(object)AssetManager.CardPreview == (Object)null)
				{
					return;
				}
				GameObject val = Object.Instantiate<GameObject>(AssetManager.CardPreview);
				Object.DontDestroyOnLoad((Object)(object)val);
				cardPreviewCanvas = val.GetComponent<Canvas>();
				if ((Object)(object)cardPreviewCanvas == (Object)null)
				{
					Object.Destroy((Object)(object)val);
					return;
				}
				if ((Object)(object)SaveLoadMenu.instance != (Object)null)
				{
					cardPreviewCanvas.worldCamera = SaveLoadMenu.instance.gameCamera;
				}
				cardPreview = ((Component)((Component)cardPreviewCanvas).transform.GetChild(0)).gameObject;
				cardPreviewRect = cardPreview.GetComponent<RectTransform>().rect;
				cardPreviewBackgroundImage = cardPreview.GetComponent<Image>();
				cardPreviewImage = ((Component)cardPreview.transform.GetChild(0)).GetComponent<Image>();
				noCardText = cardPreview.GetComponentInChildren<TextMeshProUGUI>();
			}
			((Behaviour)cardPreviewCanvas).enabled = false;
		}

		public void OnPointerEnter(PointerEventData eventData)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cardPreviewCanvas == (Object)null || (Object)(object)cardPreview == (Object)null)
			{
				return;
			}
			((Behaviour)cardPreviewCanvas).enabled = true;
			((Graphic)cardPreviewImage).color = color;
			((Graphic)cardPreviewBackgroundImage).color = new Color(color.r * 0.45f, color.g * 0.45f, color.b * 0.45f);
			cardPreview.transform.position = ((Component)this).transform.position;
			if ((Object)(object)cardObject != (Object)null)
			{
				Object.Destroy((Object)(object)cardObject);
			}
			if ((Object)(object)card == (Object)null)
			{
				((Behaviour)noCardText).enabled = true;
				return;
			}
			((Behaviour)noCardText).enabled = false;
			cardObject = Object.Instantiate<GameObject>(((Component)card).gameObject, cardPreview.transform);
			RectTransform orAddComponent = ExtensionMethods.GetOrAddComponent<RectTransform>(cardObject, false);
			orAddComponent.anchorMin = new Vector2(0f, 0f);
			orAddComponent.anchorMax = new Vector2(0f, 0f);
			cardObject.transform.localPosition = new Vector3(((Rect)(ref cardPreviewRect)).width / 2f, 0f - ((Rect)(ref cardPreviewRect)).height / 2f - 8f, 0f);
			CardVisuals componentInChildren = cardObject.GetComponentInChildren<CardVisuals>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.firstValueToSet = true;
			}
			ScaleShake setScaleToZero = cardObject.GetComponentInChildren<ScaleShake>();
			if ((Object)(object)setScaleToZero == (Object)null)
			{
				return;
			}
			ExtensionMethods.ExecuteAfterFrames((MonoBehaviour)(object)Unbound.Instance, 1, (Action)delegate
			{
				if ((Object)(object)setScaleToZero != (Object)null)
				{
					setScaleToZero.targetScale = 15f;
				}
			});
		}

		public void OnPointerExit(PointerEventData eventData)
		{
			if ((Object)(object)cardPreviewCanvas != (Object)null)
			{
				((Behaviour)cardPreviewCanvas).enabled = false;
			}
		}

		private void OnDisable()
		{
			if ((Object)(object)cardPreviewCanvas != (Object)null)
			{
				((Behaviour)cardPreviewCanvas).enabled = false;
			}
		}
	}
}
namespace GameSaver.Asset
{
	public static class AssetManager
	{
		private static AssetBundle _bundle;

		public static GameObject Saving { get; private set; }

		public static GameObject ElementSection { get; private set; }

		public static GameObject Section { get; private set; }

		public static GameObject SaveInfo { get; private set; }

		public static GameObject GameButton { get; private set; }

		public static GameObject RoundButton { get; private set; }

		public static GameObject Player { get; private set; }

		public static GameObject Card { get; private set; }

		public static GameObject Point { get; private set; }

		public static GameObject CardPreview { get; private set; }

		public static GameObject Delete { get; private set; }

		public static Image Trash { get; private set; }

		public static Image TrashOpen { get; private set; }

		internal static bool Initialize()
		{
			try
			{
				_bundle = AssetUtils.LoadAssetBundleFromResources("gamesaver_assets", typeof(GameSaver).Assembly);
			}
			catch (Exception ex)
			{
				GameSaver.LogError("could not load asset bundle 'gamesaver_assets': " + ex.GetType().Name + ": " + ex.Message);
				return false;
			}
			if ((Object)(object)_bundle == (Object)null)
			{
				GameSaver.LogError("asset bundle 'gamesaver_assets' resolved to null.");
				return false;
			}
			Saving = Load<GameObject>("Saving");
			ElementSection = Load<GameObject>("ElementSection");
			Section = Load<GameObject>("Section");
			SaveInfo = Load<GameObject>("SaveInfo");
			GameButton = Load<GameObject>("GameButton");
			RoundButton = Load<GameObject>("RoundButton");
			Player = Load<GameObject>("Player");
			Card = Load<GameObject>("Card");
			Point = Load<GameObject>("Point");
			CardPreview = Load<GameObject>("CardPreview");
			Delete = Load<GameObject>("Delete");
			Trash = Load<Image>("Trash");
			TrashOpen = Load<Image>("TrashOpen");
			if (Object.op_Implicit((Object)(object)ElementSection) && Object.op_Implicit((Object)(object)SaveInfo) && Object.op_Implicit((Object)(object)GameButton) && Object.op_Implicit((Object)(object)RoundButton) && Object.op_Implicit((Object)(object)Player) && Object.op_Implicit((Object)(object)Card))
			{
				return Object.op_Implicit((Object)(object)Point);
			}
			return false;
		}

		private static T Load<T>(string name) where T : Object
		{
			T val = _bundle.LoadAsset<T>(name);
			if ((Object)(object)val == (Object)null)
			{
				GameSaver.LogError("asset '" + name + "' missing from bundle.");
			}
			return val;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}