using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Assets.CoreScripts;
using InnerNet;
using UnityEngine;
using UnityEngine.SceneManagement;

public class AmongUsClient : InnerNetClient
{
	public static AmongUsClient Instance;

	public GameModes GameMode;

	public string OnlineScene;

	public string MainMenuScene;

	public GameData GameDataPrefab;

	public PlayerControl PlayerPrefab;

	public List<ShipStatus> ShipPrefabs;

	public float SpawnRadius = 1.75f;

	public DiscoveryState discoverState;

	public List<IDisconnectHandler> DisconnectHandlers = new List<IDisconnectHandler>();

	public List<IGameListHandler> GameListHandlers = new List<IGameListHandler>();

	public void Awake()
	{
		if (AmongUsClient.Instance)
		{
			if (AmongUsClient.Instance != this)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
			return;
		}
		AmongUsClient.Instance = this;
		UnityEngine.Object.DontDestroyOnLoad(base.gameObject);
		Application.targetFrameRate = 30;
	}

	protected override byte[] GetConnectionData()
	{
		byte[] result;
		using (MemoryStream memoryStream = new MemoryStream())
		{
			using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream))
			{
				binaryWriter.Write(Constants.GetBroadcastVersion());
				binaryWriter.Write(SaveManager.PlayerName);
				binaryWriter.Flush();
				result = memoryStream.ToArray();
			}
		}
		return result;
	}

	public void StartGame()
	{
		base.SendStartGame();
		this.discoverState = DiscoveryState.Off;
	}

	public void ExitGame(DisconnectReasons reason = DisconnectReasons.ExitGame)
	{
		if (DestroyableSingleton<WaitForHostPopup>.InstanceExists)
		{
			DestroyableSingleton<WaitForHostPopup>.Instance.Hide();
		}
		SoundManager.Instance.StopAllSound();
		this.discoverState = DiscoveryState.Off;
		this.DisconnectHandlers.Clear();
		base.DisconnectInternal(reason, null);
		SceneManager.LoadScene(this.MainMenuScene);
	}

	protected override void OnGetGameList(int totalGames, List<GameListing> availableGames)
	{
		for (int i = 0; i < this.GameListHandlers.Count; i++)
		{
			try
			{
				this.GameListHandlers[i].HandleList(totalGames, availableGames);
			}
			catch
			{
			}
		}
	}

	protected override void OnGameCreated(string gameIdString)
	{
	}

	protected override void OnWaitForHost(string gameIdString)
	{
		if (this.GameState != InnerNetClient.GameStates.Joined)
		{
			Debug.Log("Waiting for host: " + gameIdString);
			if (DestroyableSingleton<WaitForHostPopup>.InstanceExists)
			{
				DestroyableSingleton<WaitForHostPopup>.Instance.Show();
			}
		}
	}

	protected override void OnStartGame()
	{
		Debug.Log("Received game start: " + base.AmHost.ToString());
		base.StartCoroutine(this.CoStartGame());
	}

    // 收到开始游戏的消息后开始游戏
	private IEnumerator CoStartGame()
	{
		yield return null;
		while (!DestroyableSingleton<HudManager>.InstanceExists)
		{
			yield return null;
		}
		while (!PlayerControl.LocalPlayer)
		{
			yield return null;
		}
		PlayerControl.LocalPlayer.moveable = false;
		CustomPlayerMenu customPlayerMenu = UnityEngine.Object.FindObjectOfType<CustomPlayerMenu>();
		if (customPlayerMenu)
		{
			customPlayerMenu.Close(false);
		}
		if (DestroyableSingleton<GameStartManager>.InstanceExists)
		{
			this.DisconnectHandlers.Remove(DestroyableSingleton<GameStartManager>.Instance);
			UnityEngine.Object.Destroy(DestroyableSingleton<GameStartManager>.Instance.gameObject);
		}
		if (DestroyableSingleton<DiscordManager>.InstanceExists)
		{
			DestroyableSingleton<DiscordManager>.Instance.SetPlayingGame();
		}
		yield return DestroyableSingleton<HudManager>.Instance.CoFadeFullScreen(Color.clear, Color.black, 0.2f);
		while (!GameData.Instance)
		{
			yield return null;
		}
		while (!base.AmHost)
		{
			while (PlayerControl.LocalPlayer.Data == null && !base.AmHost)
			{
				yield return null;
			}
			if (!base.AmHost)
			{
				base.SendClientReady();
				while (!ShipStatus.Instance && !base.AmHost)
				{
					yield return null;
				}
				if (!base.AmHost)
				{
					IL_324:
					for (int i = 0; i < GameData.Instance.PlayerCount; i++)
					{
						PlayerControl @object = GameData.Instance.AllPlayers[i].Object;
						if (@object)
						{
							@object.moveable = true;
							@object.NetTransform.enabled = true;
							@object.MyPhysics.enabled = true;
							@object.MyPhysics.Awake();
							@object.MyPhysics.ResetAnim(true);
							@object.Collider.enabled = true;
							Vector2 spawnLocation = ShipStatus.Instance.GetSpawnLocation(i, GameData.Instance.PlayerCount);
							@object.NetTransform.SnapTo(spawnLocation);
						}
					}
					yield break;
				}
			}
		}
		GameData.Instance.SetDirty();
		base.SendClientReady();
		float timer = 0f;
		for (;;)
		{
			bool stopWaiting = true;
			List<ClientData> allClients = this.allClients;
			lock (allClients)
			{
				for (int j = 0; j < this.allClients.Count; j++)
				{
					ClientData clientData = this.allClients[j];
					if (!clientData.IsReady)
					{
						if (timer < 5f)
						{
							stopWaiting = false;
						}
						else
						{
							base.SendLateRejection(clientData.Id, DisconnectReasons.Error);
							clientData.IsReady = true;
							this.OnPlayerLeft(clientData, DisconnectReasons.Error);
						}
					}
				}
			}
			yield return null;
			if (stopWaiting)
			{
				break;
			}
			timer += Time.deltaTime;
		}
		if (LobbyBehaviour.Instance)
		{
			LobbyBehaviour.Instance.Despawn();
		}
		if (!ShipStatus.Instance)
		{
			int index = Mathf.Clamp((int)PlayerControl.GameOptions.MapId, 0, this.ShipPrefabs.Count - 1);
			ShipStatus.Instance = UnityEngine.Object.Instantiate<ShipStatus>(this.ShipPrefabs[index]);
		}
		base.Spawn(ShipStatus.Instance, -2, SpawnFlags.None);
		ShipStatus.Instance.SelectInfected();
		ShipStatus.Instance.Begin();
		goto IL_324;
	}

	protected override void OnBecomeHost()
	{
		ClientData clientData = base.FindClientById(this.ClientId);
		if (!clientData.Character)
		{
			this.OnGameJoined(null, clientData);
		}
		Debug.Log("Became Host");
		base.RemoveUnownedObjects();
	}

	protected override void OnGameEnd(GameOverReason gameOverReason, bool showAd)
	{
		StatsManager.Instance.BanPoints -= 1.5f;
		StatsManager.Instance.LastGameStarted = DateTime.MinValue;
		this.DisconnectHandlers.Clear();
		if (Minigame.Instance)
		{
			Minigame.Instance.Close();
			Minigame.Instance.Close();
		}
		try
		{
			if (SaveManager.SendTelemetry)
			{
				DestroyableSingleton<Telemetry>.Instance.EndGame(gameOverReason);
			}
		}
		catch
		{
		}
		TempData.EndReason = gameOverReason;
		TempData.showAd = showAd;
		bool flag = TempData.DidHumansWin(gameOverReason);
		TempData.winners = new List<WinningPlayerData>();
		for (int i = 0; i < GameData.Instance.PlayerCount; i++)
		{
			GameData.PlayerInfo playerInfo = GameData.Instance.AllPlayers[i];
			if (gameOverReason == GameOverReason.HumansDisconnect || gameOverReason == GameOverReason.ImpostorDisconnect || flag != playerInfo.IsImpostor)
			{
				TempData.winners.Add(new WinningPlayerData(playerInfo));
			}
		}
		base.StartCoroutine(this.CoEndGame());
	}

	public IEnumerator CoEndGame()
	{
		yield return DestroyableSingleton<HudManager>.Instance.CoFadeFullScreen(Color.clear, Color.black, 0.5f);
		SceneManager.LoadScene("EndGame");
		yield break;
	}

    // 加入游戏回调
	protected override void OnPlayerJoined(ClientData data)
	{
		if (DestroyableSingleton<GameStartManager>.InstanceExists)
		{
			DestroyableSingleton<GameStartManager>.Instance.ResetStartState();
		}
		if (base.AmHost && data.InScene) // 如果本机是Local host
		{
			this.CreatePlayer(data);
		}
	}

	protected override void OnGameJoined(string gameIdString, ClientData data)
	{
		if (DestroyableSingleton<WaitForHostPopup>.InstanceExists)
		{
			DestroyableSingleton<WaitForHostPopup>.Instance.Hide();
		}
		if (!string.IsNullOrWhiteSpace(this.OnlineScene))
		{
			SceneManager.LoadScene(this.OnlineScene);
		}
	}

	// 删除某个角色对象gameobject
	protected override void OnPlayerLeft(ClientData data, DisconnectReasons reason)
	{
		if (DestroyableSingleton<GameStartManager>.InstanceExists)
		{
			DestroyableSingleton<GameStartManager>.Instance.ResetStartState();
		}
		PlayerControl character = data.Character;
		if (character)
		{
			for (int i = this.DisconnectHandlers.Count - 1; i > -1; i--)
			{
				try
				{
					this.DisconnectHandlers[i].HandleDisconnect(character, reason);
				}
				catch (Exception exception)
				{
					Debug.LogException(exception);
					this.DisconnectHandlers.RemoveAt(i);
				}
			}
			UnityEngine.Object.Destroy(character.gameObject);
		}
		else
		{
			Debug.LogWarning(string.Format("A player without a character disconnected: {0}: {1}", data.Id, data.InScene));
			for (int j = this.DisconnectHandlers.Count - 1; j > -1; j--)
			{
				try
				{
					this.DisconnectHandlers[j].HandleDisconnect();
				}
				catch (Exception exception2)
				{
					Debug.LogException(exception2);
					this.DisconnectHandlers.RemoveAt(j);
				}
			}
		}
		if (base.AmHost)
		{
			GameOptionsData gameOptions = PlayerControl.GameOptions;
			if (gameOptions != null && gameOptions.isDefaults)
			{
				PlayerControl.GameOptions.SetRecommendations(GameData.Instance.PlayerCount, AmongUsClient.Instance.GameMode);
				PlayerControl localPlayer = PlayerControl.LocalPlayer;
				if (localPlayer != null)
				{
					localPlayer.RpcSyncSettings(PlayerControl.GameOptions);
				}
			}
		}
		base.RemoveUnownedObjects();
	}

	protected override void OnDisconnected()
	{
		SceneManager.LoadScene(this.MainMenuScene);
	}

    //c 场景加载完成的回调
	protected override void OnPlayerChangedScene(ClientData client, string currentScene)
	{
		client.InScene = true;
		if (!base.AmHost)
		{
			return;
		}
		if (currentScene.Equals("Tutorial"))
		{
			GameData.Instance = UnityEngine.Object.Instantiate<GameData>(this.GameDataPrefab);
			base.Spawn(GameData.Instance, -2, SpawnFlags.None);
			base.Spawn(UnityEngine.Object.Instantiate<ShipStatus>(this.ShipPrefabs.Last<ShipStatus>()), -2, SpawnFlags.None);
			this.CreatePlayer(client);
			return;
		}
		if (currentScene.Equals("OnlineGame"))
		{
			if (client.Id != this.ClientId)
			{
				base.SendInitialData(client.Id);
			}
			else
			{
				if (this.GameMode == GameModes.LocalGame)
				{
					base.StartCoroutine(this.CoBroadcastManager());
				}
				if (!GameData.Instance)
				{
					GameData.Instance = UnityEngine.Object.Instantiate<GameData>(this.GameDataPrefab);
					base.Spawn(GameData.Instance, -2, SpawnFlags.None);
				}
			}
			this.CreatePlayer(client);
		}
	}

	[ContextMenu("Spawn Tester")]
	private void SpawnTester()
	{
		sbyte availableId = GameData.Instance.GetAvailableId();
		Vector2 v = Vector2.up.Rotate((float)availableId * (360f / (float)Palette.PlayerColors.Length)) * this.SpawnRadius;
		PlayerControl playerControl = UnityEngine.Object.Instantiate<PlayerControl>(this.PlayerPrefab, v, Quaternion.identity);
		playerControl.PlayerId = (byte)availableId;
		GameData.Instance.AddPlayer(playerControl);
		base.Spawn(playerControl, -2, SpawnFlags.None);
		playerControl.CmdCheckName("Test");
		playerControl.CmdCheckColor(0);
		if (DestroyableSingleton<HatManager>.InstanceExists)
		{
			playerControl.RpcSetHat((uint)((int)availableId % DestroyableSingleton<HatManager>.Instance.AllHats.Count));
			playerControl.RpcSetSkin((uint)((int)availableId % DestroyableSingleton<HatManager>.Instance.AllSkins.Count));
			playerControl.RpcSetPet((uint)availableId);
		}
	}

	private void CreatePlayer(ClientData clientData)
	{
		if (clientData.Character)
		{
			return;
		}
		if (!base.AmHost)
		{
			Debug.Log("Waiting for host to make my player");
			return;
		}
		if (!GameData.Instance)
		{
			GameData.Instance = UnityEngine.Object.Instantiate<GameData>(this.GameDataPrefab);
			base.Spawn(GameData.Instance, -2, SpawnFlags.None);
		}
		sbyte availableId = GameData.Instance.GetAvailableId();
		if (availableId == -1)
		{
			base.SendLateRejection(clientData.Id, DisconnectReasons.GameFull);
			Debug.Log("Overfilled room.");
			return;
		}
		Vector2 v = Vector2.zero;
		if (ShipStatus.Instance)
		{
			v = ShipStatus.Instance.GetSpawnLocation((int)availableId, Palette.PlayerColors.Length);
		}
		else if (DestroyableSingleton<TutorialManager>.InstanceExists)
		{
			v = new Vector2(-1.9f, 3.25f);
		}
        // 新建player gameobject
		Debug.Log(string.Format("Spawned player {0} for client {1}", availableId, clientData.Id));
		PlayerControl playerControl = UnityEngine.Object.Instantiate<PlayerControl>(this.PlayerPrefab, v, Quaternion.identity);
		playerControl.PlayerId = (byte)availableId;
		clientData.Character = playerControl;
		base.Spawn(playerControl, clientData.Id, SpawnFlags.IsClientCharacter);
		GameData.Instance.AddPlayer(playerControl);
		if (PlayerControl.GameOptions.isDefaults)
		{
			PlayerControl.GameOptions.SetRecommendations(GameData.Instance.PlayerCount, AmongUsClient.Instance.GameMode);
		}
        // 同步这个新玩家的单局配置,调用它的设置函数
		playerControl.RpcSyncSettings(PlayerControl.GameOptions);
	}

	private IEnumerator CoBroadcastManager()
	{
		while (!GameData.Instance)
		{
			yield return null;
		}
		int lastPlayerCount = 0;
		this.discoverState = DiscoveryState.Broadcast;
		while (this.discoverState == DiscoveryState.Broadcast)
		{
			if (lastPlayerCount != GameData.Instance.PlayerCount)
			{
				lastPlayerCount = GameData.Instance.PlayerCount;
				string data = string.Format("{0}~Open~{1}~", SaveManager.PlayerName, GameData.Instance.PlayerCount);
				DestroyableSingleton<InnerDiscover>.Instance.Interval = 1f;
				DestroyableSingleton<InnerDiscover>.Instance.StartAsServer(data);
			}
			yield return null;
		}
		DestroyableSingleton<InnerDiscover>.Instance.StopServer();
		yield break;
	}
}