From: miniduikboot Date: Wed, 19 Jun 2024 18:42:18 +0000 (+0200) Subject: Demote InnerGameData, promote InnerPlayerInfo X-Git-Tag: v1.10.0~7^2~13 X-Git-Url: https://git.deb.at/?a=commitdiff_plain;h=c43fdd2a69f60227a6f860bfa194b397d82da773;p=rhonda%2Fimpostor.git Demote InnerGameData, promote InnerPlayerInfo In 2024.6.18 Innersloth promoted PlayerInfo to its own network object, and gave it to the server. InnerGameData is now a container that holds these players. This commit implements the changes necessary to handle these separate PlayerInfo network objects. --- diff --git a/src/Impostor.Api/Net/Inner/Objects/IInnerGameData.cs b/src/Impostor.Api/Net/Inner/Objects/IInnerGameData.cs index 6e41020..a535131 100644 --- a/src/Impostor.Api/Net/Inner/Objects/IInnerGameData.cs +++ b/src/Impostor.Api/Net/Inner/Objects/IInnerGameData.cs @@ -1,6 +1,6 @@ namespace Impostor.Api.Net.Inner.Objects { - public interface IInnerGameData : IInnerNetObject + public interface IInnerGameData { } } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs index 47fe4a0..26ec23b 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs @@ -1,36 +1,12 @@ -using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Threading.Tasks; -using Impostor.Api; -using Impostor.Api.Events.Managers; -using Impostor.Api.Net; -using Impostor.Api.Net.Custom; -using Impostor.Api.Net.Inner; using Impostor.Api.Net.Inner.Objects; -using Impostor.Api.Net.Messages.Rpcs; -using Impostor.Server.Net.Inner.Objects.Components; -using Impostor.Server.Net.State; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; namespace Impostor.Server.Net.Inner.Objects { - internal partial class InnerGameData : InnerNetObject, IInnerGameData + internal partial class InnerGameData : IInnerGameData { - private readonly ILogger _logger; - private readonly IEventManager _eventManager; - private readonly ConcurrentDictionary _allPlayers; - - public InnerGameData(ICustomMessageManager customMessageManager, Game game, ILogger logger, IEventManager eventManager, IServiceProvider serviceProvider) : base(customMessageManager, game) - { - _logger = logger; - _eventManager = eventManager; - _allPlayers = new ConcurrentDictionary(); - - Components.Add(this); - Components.Add(ActivatorUtilities.CreateInstance(serviceProvider, game)); - } + private readonly ConcurrentDictionary _allPlayers = new(); public int PlayerCount => _allPlayers.Count; @@ -46,103 +22,14 @@ namespace Impostor.Server.Net.Inner.Objects return _allPlayers.TryGetValue(id, out var player) ? player : null; } - public override ValueTask SerializeAsync(IMessageWriter writer, bool initialState) - { - throw new NotImplementedException(); - } - - public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) - { - if (!await ValidateHost(CheatContext.Deserialize, sender)) - { - return; - } - - while (reader.Position < reader.Length) - { - var inner = reader.ReadMessage(); - var playerInfo = this.GetPlayerById(inner.Tag); - if (playerInfo != null) - { - playerInfo.Deserialize(inner); - } - else - { - playerInfo = new InnerPlayerInfo(inner.Tag); - playerInfo.Deserialize(inner); - - if (!_allPlayers.TryAdd(playerInfo.PlayerId, playerInfo)) - { - throw new ImpostorException("Failed to add player to InnerGameData."); - } - } - } - } - - public override async ValueTask HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) - { - if (!await ValidateHost(call, sender)) - { - return false; - } - - switch (call) - { - case RpcCalls.SetTasks: - { - Rpc29SetTasks.Deserialize(reader, out var playerId, out var taskTypeIds); - SetTasks(playerId, taskTypeIds); - break; - } - - default: - return await base.HandleRpcAsync(sender, target, call, reader); - } - - return true; - } - - internal InnerPlayerInfo? AddPlayer(InnerPlayerControl control) + internal bool AddPlayer(InnerPlayerInfo playerInfo) { - var playerId = control.PlayerId; - var playerInfo = new InnerPlayerInfo(control.PlayerId); - - if (_allPlayers.TryAdd(playerId, playerInfo)) - { - return playerInfo; - } - - return null; + return _allPlayers.TryAdd(playerInfo.PlayerId, playerInfo); } - internal void RemovePlayer(InnerPlayerControl control) + internal void RemovePlayer(byte playerId) { - _allPlayers.TryRemove(control.PlayerInfo.PlayerId, out _); - } - - private void SetTasks(byte playerId, ReadOnlyMemory taskTypeIds) - { - var player = GetPlayerById(playerId); - if (player == null) - { - _logger.LogTrace("Could not set tasks for playerId {0}.", playerId); - return; - } - - if (player.Disconnected) - { - return; - } - - player.Tasks = new List(taskTypeIds.Length); - - var taskId = 0u; - foreach (var taskTypeId in taskTypeIds.Span) - { - var mapTasks = Game.GameNet!.ShipStatus?.Data.Tasks; - var taskType = (mapTasks != null && mapTasks.ContainsKey(taskTypeId)) ? mapTasks[taskTypeId] : null; - player.Tasks.Add(new TaskInfo(player, _eventManager, taskId++, taskType)); - } + _allPlayers.TryRemove(playerId, out _); } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.Api.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.Api.cs index 512a4f1..b8b3cd8 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.Api.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.Api.cs @@ -3,7 +3,7 @@ using Impostor.Api.Net.Inner.Objects; namespace Impostor.Server.Net.Inner.Objects { - internal partial class InnerPlayerInfo : IInnerPlayerInfo + internal partial class InnerPlayerInfo : InnerNetObject, IInnerPlayerInfo { IEnumerable IInnerPlayerInfo.Tasks => Tasks; } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs index 320cb5b..498f8f6 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs @@ -1,23 +1,33 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Impostor.Api.Games; using Impostor.Api.Innersloth; using Impostor.Api.Innersloth.Customization; using Impostor.Api.Innersloth.GameOptions; +using Impostor.Api.Net; +using Impostor.Api.Net.Custom; using Impostor.Api.Utils; +using Impostor.Server.Net.State; +using Microsoft.Extensions.Logging; namespace Impostor.Server.Net.Inner.Objects { internal partial class InnerPlayerInfo { - public InnerPlayerInfo(byte playerId) + private readonly ILogger _logger; + + public InnerPlayerInfo(ICustomMessageManager customMessageManager, Game game, ILogger logger) : base(customMessageManager, game) { - PlayerId = playerId; + Components.Add(this); + _logger = logger; } public InnerPlayerControl? Controller { get; internal set; } - public byte PlayerId { get; } + public byte PlayerId { get; internal set; } + + public int ClientId { get; internal set; } public string PlayerName { get; internal set; } = string.Empty; @@ -32,6 +42,8 @@ namespace Impostor.Server.Net.Inner.Objects public RoleTypes? RoleType { get; internal set; } + public RoleTypes? RoleWhenAlive { get; internal set; } + public bool Disconnected { get; internal set; } public bool IsImpostor => RoleType is RoleTypes.Impostor or RoleTypes.Shapeshifter or RoleTypes.ImpostorGhost; @@ -71,13 +83,56 @@ namespace Impostor.Server.Net.Inner.Objects } } - public void Serialize(IMessageWriter writer) + public override ValueTask SerializeAsync(IMessageWriter writer, bool initialState) { - throw new NotImplementedException(); + writer.Write(PlayerId); + writer.WritePacked(ClientId); + + writer.Write((byte)Outfits.Count); + foreach (var outfit in Outfits) + { + writer.Write((byte)outfit.Key); + outfit.Value.Serialize(writer); + } + + writer.WritePacked(PlayerLevel); + + var flag = 0; + if (Disconnected) + { + flag = (byte)(flag | 1u); + } + + if (IsDead) + { + flag = (byte)(flag | 4u); + } + + writer.Write((byte)flag); + + writer.Write((ushort)(RoleType ?? 0)); + writer.Write(RoleWhenAlive.HasValue); + if (RoleWhenAlive.HasValue) + { + writer.Write((ushort)RoleWhenAlive.Value); + } + + writer.Write((byte)Tasks.Count); + for (var i = 0; i < Tasks.Count; i++) + { + Tasks[i].Serialize(writer); + } + + writer.Write(string.Empty); // FriendCode + writer.Write(string.Empty); // PUID + return new ValueTask(true); } - public void Deserialize(IMessageReader reader) + public override ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) { + PlayerId = reader.ReadByte(); + ClientId = reader.ReadPackedInt32(); + Outfits.Clear(); var b = reader.ReadByte(); for (var i = 0; i < b; i++) @@ -93,7 +148,15 @@ namespace Impostor.Server.Net.Inner.Objects Disconnected = (flag & 1) != 0; IsDead = (flag & 4) != 0; - _ = (RoleTypes)reader.ReadUInt16(); // ignore the RoleType here and only trust the SetRole rpc + // Ignore the RoleType here and only trust the SetRole RPC, as + // RoleType is not nullable in vanilla, while Impostor checks game + // starts based on assigned roles. + _ = (RoleTypes)reader.ReadUInt16(); + + if (reader.ReadBoolean()) + { + RoleWhenAlive = (RoleTypes)reader.ReadUInt16(); + } var taskCount = reader.ReadByte(); @@ -106,6 +169,12 @@ namespace Impostor.Server.Net.Inner.Objects { Tasks[i].Deserialize(reader); } + + // Impostor doesn't expose fields that aren't properly validated + reader.ReadString(); // FriendCode + reader.ReadString(); // PUID + + return ValueTask.CompletedTask; } } } diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index 5f0e56c..4e429fa 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -35,7 +35,6 @@ namespace Impostor.Server.Net.State [0] = typeof(InnerSkeldShipStatus), [1] = typeof(InnerMeetingHud), [2] = typeof(InnerLobbyBehaviour), - [3] = typeof(InnerGameData), [4] = typeof(InnerPlayerControl), [5] = typeof(InnerMiraShipStatus), [6] = typeof(InnerPolusShipStatus), @@ -43,6 +42,8 @@ namespace Impostor.Server.Net.State [8] = typeof(InnerAirshipStatus), [9] = typeof(InnerHideAndSeekManager), [10] = typeof(InnerNormalGameManager), + [11] = typeof(InnerPlayerInfo), + [12] = typeof(InnerVoteBanSystem), [13] = typeof(InnerFungleShipStatus), }; @@ -326,9 +327,17 @@ namespace Impostor.Server.Net.State break; } - case InnerGameData data: + case InnerPlayerInfo playerInfo: { - GameNet.GameData = data; + if (!GameNet.GameData.AddPlayer(playerInfo)) + { + _logger.LogWarning( + "Could not add PlayerInfo for playerId {PlayerId} with NetId {newId}, already have NetId {oldNetId}", + playerInfo.PlayerId, + playerInfo.NetId, + GameNet.GameData.GetPlayerById(playerInfo.PlayerId)?.NetId); + } + break; } @@ -358,7 +367,7 @@ namespace Impostor.Server.Net.State } // Hook up InnerPlayerControl <-> InnerPlayerControl.PlayerInfo. - var playerInfo = GameNet.GameData!.GetPlayerById(control.PlayerId) ?? GameNet.GameData.AddPlayer(control); + var playerInfo = GameNet.GameData.GetPlayerById(control.PlayerId); if (playerInfo != null) { @@ -402,12 +411,6 @@ namespace Impostor.Server.Net.State break; } - case InnerGameData: - { - GameNet.GameData = null; - break; - } - case InnerVoteBanSystem: { GameNet.VoteBan = null; @@ -420,13 +423,18 @@ namespace Impostor.Server.Net.State break; } - case InnerPlayerControl control: + case InnerPlayerInfo playerInfo: { if (GameState != GameStates.Started && GameState != GameStates.Starting) { - GameNet.GameData?.RemovePlayer(control); + GameNet.GameData.RemovePlayer(playerInfo.PlayerId); } + break; + } + + case InnerPlayerControl control: + { // Remove InnerPlayerControl <-> IClientPlayer. if (TryGetPlayer(control.OwnerId, out var player)) { diff --git a/src/Impostor.Server/Net/State/GameNet.Api.cs b/src/Impostor.Server/Net/State/GameNet.Api.cs index 68d4c26..d57ec1d 100644 --- a/src/Impostor.Server/Net/State/GameNet.Api.cs +++ b/src/Impostor.Server/Net/State/GameNet.Api.cs @@ -12,7 +12,7 @@ namespace Impostor.Server.Net.State IInnerLobbyBehaviour? IGameNet.LobbyBehaviour => LobbyBehaviour; - IInnerGameData? IGameNet.GameData => GameData; + IInnerGameData IGameNet.GameData => GameData; IInnerVoteBanSystem? IGameNet.VoteBan => VoteBan; diff --git a/src/Impostor.Server/Net/State/GameNet.cs b/src/Impostor.Server/Net/State/GameNet.cs index 66f69f0..25efec6 100644 --- a/src/Impostor.Server/Net/State/GameNet.cs +++ b/src/Impostor.Server/Net/State/GameNet.cs @@ -11,7 +11,7 @@ namespace Impostor.Server.Net.State public InnerLobbyBehaviour? LobbyBehaviour { get; internal set; } - public InnerGameData? GameData { get; internal set; } + public InnerGameData GameData { get; internal set; } = new(); public InnerVoteBanSystem? VoteBan { get; internal set; }