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 ShipPrefabs; public float SpawnRadius = 1.75f; public DiscoveryState discoverState; public List DisconnectHandlers = new List(); public List GameListHandlers = new List(); 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.InstanceExists) { DestroyableSingleton.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 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.InstanceExists) { DestroyableSingleton.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.InstanceExists) { yield return null; } while (!PlayerControl.LocalPlayer) { yield return null; } PlayerControl.LocalPlayer.moveable = false; CustomPlayerMenu customPlayerMenu = UnityEngine.Object.FindObjectOfType(); if (customPlayerMenu) { customPlayerMenu.Close(false); } if (DestroyableSingleton.InstanceExists) { this.DisconnectHandlers.Remove(DestroyableSingleton.Instance); UnityEngine.Object.Destroy(DestroyableSingleton.Instance.gameObject); } if (DestroyableSingleton.InstanceExists) { DestroyableSingleton.Instance.SetPlayingGame(); } yield return DestroyableSingleton.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 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(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.Instance.EndGame(gameOverReason); } } catch { } TempData.EndReason = gameOverReason; TempData.showAd = showAd; bool flag = TempData.DidHumansWin(gameOverReason); TempData.winners = new List(); 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.Instance.CoFadeFullScreen(Color.clear, Color.black, 0.5f); SceneManager.LoadScene("EndGame"); yield break; } // 一个玩家加入游戏后,会创建gameObject并将它的数据加入GameData.AllPlayers列表 protected override void OnPlayerJoined(ClientData data) { if (DestroyableSingleton.InstanceExists) { DestroyableSingleton.Instance.ResetStartState(); } if (base.AmHost && data.InScene) // 如果本机是host,才会创建player { this.CreatePlayer(data); // } } protected override void OnGameJoined(string gameIdString, ClientData data) { if (DestroyableSingleton.InstanceExists) { DestroyableSingleton.Instance.Hide(); } if (!string.IsNullOrWhiteSpace(this.OnlineScene)) { // 切换场景 SceneManager.LoadScene(this.OnlineScene); } } // 删除某个角色对象gameobject protected override void OnPlayerLeft(ClientData data, DisconnectReasons reason) { if (DestroyableSingleton.InstanceExists) { DestroyableSingleton.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(this.GameDataPrefab); base.Spawn(GameData.Instance, -2, SpawnFlags.None); base.Spawn(UnityEngine.Object.Instantiate(this.ShipPrefabs.Last()), -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(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(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.InstanceExists) { playerControl.RpcSetHat((uint)((int)availableId % DestroyableSingleton.Instance.AllHats.Count)); playerControl.RpcSetSkin((uint)((int)availableId % DestroyableSingleton.Instance.AllSkins.Count)); playerControl.RpcSetPet((uint)availableId); } } // 创建角色gameObject,并加入GameData.AllPlayers列表 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(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.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(this.PlayerPrefab, v, Quaternion.identity); playerControl.PlayerId = (byte)availableId; clientData.Character = playerControl; base.Spawn(playerControl, clientData.Id, SpawnFlags.IsClientCharacter); GameData.Instance.AddPlayer(playerControl); // 添加到GameData的AllPlayers里 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.Instance.Interval = 1f; DestroyableSingleton.Instance.StartAsServer(data); } yield return null; } DestroyableSingleton.Instance.StopServer(); yield break; } }