using System; using System.Collections.Generic; using System.Linq; using Assets.CoreScripts; using Hazel; using InnerNet; using UnityEngine; //c 单局游戏数据,同步频率比较小 public class GameData : InnerNetObject, IDisconnectHandler { public int PlayerCount { get { return this.AllPlayers.Count; } } public static GameData Instance; // 所有角色数据,包括外观、装饰、是否是imposter、是否死亡 public List AllPlayers = new List(); public int TotalTasks; public int CompletedTasks; public const byte InvalidPlayerId = 255; public const byte DisconnectedPlayerId = 254; public class TaskInfo { public uint Id; public bool Complete; public void Serialize(MessageWriter writer) { writer.WritePacked(this.Id); writer.Write(this.Complete); } public void Deserialize(MessageReader reader) { this.Id = reader.ReadPackedUInt32(); this.Complete = reader.ReadBoolean(); } } //c 角色数据,包括外观、装饰、是否是imposter、是否死亡 public class PlayerInfo { public PlayerControl Object { get { if (!this._object) { this._object = PlayerControl.AllPlayerControls.FirstOrDefault((PlayerControl p) => p.PlayerId == this.PlayerId); } return this._object; } } // 单局游戏内会给每一个玩家分配一个playerId public readonly byte PlayerId; public string PlayerName = string.Empty; public byte ColorId; public uint HatId; public uint PetId; public uint SkinId; public bool Disconnected; public List Tasks; public bool IsImpostor; public bool IsDead; private PlayerControl _object; public PlayerInfo(byte playerId) { this.PlayerId = playerId; } public PlayerInfo(PlayerControl pc) : this(pc.PlayerId) { this._object = pc; } public void Serialize(MessageWriter writer) { writer.Write(this.PlayerName); writer.Write(this.ColorId); writer.WritePacked(this.HatId); writer.WritePacked(this.PetId); writer.WritePacked(this.SkinId); byte b = 0; if (this.Disconnected) { b |= 1; } if (this.IsImpostor) { b |= 2; } if (this.IsDead) { b |= 4; } writer.Write(b); if (this.Tasks != null) { writer.Write((byte)this.Tasks.Count); for (int i = 0; i < this.Tasks.Count; i++) { this.Tasks[i].Serialize(writer); } return; } writer.Write(0); } public void Deserialize(MessageReader reader) { this.PlayerName = reader.ReadString(); this.ColorId = reader.ReadByte(); this.HatId = reader.ReadPackedUInt32(); this.PetId = reader.ReadPackedUInt32(); this.SkinId = reader.ReadPackedUInt32(); byte b = reader.ReadByte(); this.Disconnected = ((b & 1) > 0); this.IsImpostor = ((b & 2) > 0); this.IsDead = ((b & 4) > 0); byte b2 = reader.ReadByte(); this.Tasks = new List((int)b2); for (int i = 0; i < (int)b2; i++) { this.Tasks.Add(new GameData.TaskInfo()); this.Tasks[i].Deserialize(reader); } } public GameData.TaskInfo FindTaskById(uint taskId) { for (int i = 0; i < this.Tasks.Count; i++) { if (this.Tasks[i].Id == taskId) { return this.Tasks[i]; } } return null; } } private enum RpcCalls { SetTasks } public void Awake() { if (GameData.Instance && GameData.Instance != this) { UnityEngine.Object.Destroy(base.gameObject); return; } GameData.Instance = this; if (AmongUsClient.Instance) { AmongUsClient.Instance.DisconnectHandlers.AddUnique(this); } } internal void SetDirty() { base.SetDirtyBit(uint.MaxValue); } public GameData.PlayerInfo GetHost() { ClientData host = AmongUsClient.Instance.GetHost(); if (host != null && host.Character) { return host.Character.Data; } return null; } public sbyte GetAvailableId() { sbyte i; sbyte j; for (i = 0; i < 10; i = j + 1) { if (!this.AllPlayers.Any((GameData.PlayerInfo p) => p.PlayerId == (byte)i)) { return i; } j = i; } return -1; } public GameData.PlayerInfo GetPlayerById(byte id) { if (id == 255) { return null; } for (int i = 0; i < this.AllPlayers.Count; i++) { if (this.AllPlayers[i].PlayerId == id) { return this.AllPlayers[i]; } } return null; } public void UpdateName(byte playerId, string name) { GameData.PlayerInfo playerById = this.GetPlayerById(playerId); if (playerById != null) { playerById.PlayerName = name; } base.SetDirtyBit(1U << (int)playerId); } public void UpdateColor(byte playerId, byte color) { GameData.PlayerInfo playerById = this.GetPlayerById(playerId); if (playerById != null) { playerById.ColorId = color; } base.SetDirtyBit(1U << (int)playerId); } public void UpdateHat(byte playerId, uint hat) { GameData.PlayerInfo playerById = this.GetPlayerById(playerId); if (playerById != null) { playerById.HatId = hat; } base.SetDirtyBit(1U << (int)playerId); } public void UpdatePet(byte playerId, uint petId) { GameData.PlayerInfo playerById = this.GetPlayerById(playerId); if (playerById != null) { playerById.PetId = petId; } base.SetDirtyBit(1U << (int)playerId); } public void UpdateSkin(byte playerId, uint skin) { GameData.PlayerInfo playerById = this.GetPlayerById(playerId); if (playerById != null) { playerById.SkinId = skin; } base.SetDirtyBit(1U << (int)playerId); } public void AddPlayer(PlayerControl pc) { GameData.PlayerInfo item = new GameData.PlayerInfo(pc); this.AllPlayers.Add(item); base.SetDirtyBit(1U << (int)pc.PlayerId); } public bool RemovePlayer(byte playerId) { for (int i = 0; i < this.AllPlayers.Count; i++) { if (this.AllPlayers[i].PlayerId == playerId) { this.SetDirty(); this.AllPlayers.RemoveAt(i); return true; } } return false; } public void RecomputeTaskCounts() { this.TotalTasks = 0; this.CompletedTasks = 0; for (int i = 0; i < this.AllPlayers.Count; i++) { GameData.PlayerInfo playerInfo = this.AllPlayers[i]; if (!playerInfo.Disconnected && playerInfo.Tasks != null && playerInfo.Object && (PlayerControl.GameOptions.GhostsDoTasks || !playerInfo.IsDead) && !playerInfo.IsImpostor) { for (int j = 0; j < playerInfo.Tasks.Count; j++) { this.TotalTasks++; if (playerInfo.Tasks[j].Complete) { this.CompletedTasks++; } } } } } public void TutOnlyRemoveTask(byte playerId, uint taskId) { GameData.PlayerInfo playerById = this.GetPlayerById(playerId); GameData.TaskInfo item = playerById.FindTaskById(taskId); playerById.Tasks.Remove(item); this.RecomputeTaskCounts(); } public void TutOnlyAddTask(byte playerId, uint taskId) { this.GetPlayerById(playerId).Tasks.Add(new GameData.TaskInfo { Id = taskId }); this.TotalTasks++; } private void SetTasks(byte playerId, byte[] taskTypeIds) { GameData.PlayerInfo playerById = this.GetPlayerById(playerId); if (playerById == null) { Debug.Log("Could not set tasks for player id: " + playerId); return; } if (playerById.Disconnected) { return; } if (!playerById.Object) { Debug.Log(string.Concat(new object[] { "Could not set tasks for player (", playerById.PlayerName, "): ", playerId })); return; } playerById.Tasks = new List(taskTypeIds.Length); for (int i = 0; i < taskTypeIds.Length; i++) { playerById.Tasks.Add(new GameData.TaskInfo()); playerById.Tasks[i].Id = (uint)i; } playerById.Object.SetTasks(taskTypeIds); base.SetDirtyBit(1U << (int)playerById.PlayerId); } public void CompleteTask(PlayerControl pc, uint taskId) { GameData.TaskInfo taskInfo = pc.Data.FindTaskById(taskId); if (taskInfo == null) { Debug.LogWarning("Couldn't find task: " + taskId); return; } if (!taskInfo.Complete) { taskInfo.Complete = true; this.CompletedTasks++; return; } Debug.LogWarning("Double complete task: " + taskId); } public void HandleDisconnect(PlayerControl player, DisconnectReasons reason) { if (!player) { return; } GameData.PlayerInfo playerById = this.GetPlayerById(player.PlayerId); if (playerById == null) { return; } if (AmongUsClient.Instance.IsGameStarted) { if (!playerById.Disconnected) { playerById.Disconnected = true; TempData.LastDeathReason = DeathReason.Disconnect; this.ShowNotification(playerById.PlayerName, reason); } } else if (this.RemovePlayer(player.PlayerId)) { this.ShowNotification(playerById.PlayerName, reason); } this.RecomputeTaskCounts(); } private void ShowNotification(string playerName, DisconnectReasons reason) { if (string.IsNullOrEmpty(playerName)) { return; } if (reason <= DisconnectReasons.Banned) { if (reason == DisconnectReasons.ExitGame) { DestroyableSingleton.Instance.Notifier.AddItem(playerName + " left the game."); return; } if (reason == DisconnectReasons.Banned) { GameData.PlayerInfo data = AmongUsClient.Instance.GetHost().Character.Data; DestroyableSingleton.Instance.Notifier.AddItem(playerName + " was banned by " + data.PlayerName + "."); return; } } else if (reason == DisconnectReasons.Kicked) { GameData.PlayerInfo data2 = AmongUsClient.Instance.GetHost().Character.Data; DestroyableSingleton.Instance.Notifier.AddItem(playerName + " was kicked by " + data2.PlayerName + "."); return; } DestroyableSingleton.Instance.Notifier.AddItem(playerName + " left the game due to error."); } public void HandleDisconnect() { if (!AmongUsClient.Instance.IsGameStarted) { for (int i = this.AllPlayers.Count - 1; i >= 0; i--) { if (!this.AllPlayers[i].Object) { this.AllPlayers.RemoveAt(i); } } } } public override bool Serialize(MessageWriter writer, bool initialState) { if (initialState) { if (!DestroyableSingleton.Instance.IsInitialized) { DestroyableSingleton.Instance.Initialize(); } writer.WriteBytesAndSize(DestroyableSingleton.Instance.CurrentGuid.ToByteArray()); writer.WritePacked(this.AllPlayers.Count); for (int i = 0; i < this.AllPlayers.Count; i++) { GameData.PlayerInfo playerInfo = this.AllPlayers[i]; writer.Write(playerInfo.PlayerId); playerInfo.Serialize(writer); } } else { int position = writer.Position; byte b = 0; writer.Write(b); for (int j = 0; j < this.AllPlayers.Count; j++) { GameData.PlayerInfo playerInfo2 = this.AllPlayers[j]; if ((this.DirtyBits & 1U << (int)playerInfo2.PlayerId) != 0U) { writer.Write(playerInfo2.PlayerId); playerInfo2.Serialize(writer); b += 1; } } writer.Position = position; writer.Write(b); writer.Position = writer.Length; this.DirtyBits = 0U; } return true; } public override void Deserialize(MessageReader reader, bool initialState) { if (initialState) { Guid gameGuid = new Guid(reader.ReadBytesAndSize()); if (!DestroyableSingleton.Instance.IsInitialized) { DestroyableSingleton.Instance.Initialize(gameGuid); } int num = reader.ReadPackedInt32(); for (int i = 0; i < num; i++) { GameData.PlayerInfo playerInfo = new GameData.PlayerInfo(reader.ReadByte()); playerInfo.Deserialize(reader); this.AllPlayers.Add(playerInfo); } } else { byte b = reader.ReadByte(); for (int j = 0; j < (int)b; j++) { byte b2 = reader.ReadByte(); GameData.PlayerInfo playerInfo2 = this.GetPlayerById(b2); if (playerInfo2 != null) { playerInfo2.Deserialize(reader); } else { playerInfo2 = new GameData.PlayerInfo(b2); playerInfo2.Deserialize(reader); this.AllPlayers.Add(playerInfo2); } } } this.RecomputeTaskCounts(); } public void RpcSetTasks(byte playerId, byte[] taskTypeIds) { if (AmongUsClient.Instance.AmClient) { this.SetTasks(playerId, taskTypeIds); } MessageWriter messageWriter = AmongUsClient.Instance.StartRpc(this.NetId, 0, SendOption.Reliable); messageWriter.Write(playerId); messageWriter.WriteBytesAndSize(taskTypeIds); messageWriter.EndMessage(); } public override void HandleRpc(byte callId, MessageReader reader) { if (callId == 0) { this.SetTasks(reader.ReadByte(), reader.ReadBytesAndSize()); } } }