]> git.deb.at Git - rhonda/impostor.git/commitdiff
Demote InnerGameData, promote InnerPlayerInfo
authorminiduikboot <mini@duikbo.at>
Wed, 19 Jun 2024 18:42:18 +0000 (20:42 +0200)
committerminiduikboot <mini@duikbo.at>
Tue, 20 Aug 2024 19:41:38 +0000 (21:41 +0200)
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.

src/Impostor.Api/Net/Inner/Objects/IInnerGameData.cs
src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs
src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.Api.cs
src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs
src/Impostor.Server/Net/State/Game.Data.cs
src/Impostor.Server/Net/State/GameNet.Api.cs
src/Impostor.Server/Net/State/GameNet.cs

index 6e410203ba854f4023e031933232fa8d355b36b7..a535131ff2e82f6e43079136398ff4dcc4ccef03 100644 (file)
@@ -1,6 +1,6 @@
 namespace Impostor.Api.Net.Inner.Objects
 {
-    public interface IInnerGameData : IInnerNetObject
+    public interface IInnerGameData
     {
     }
 }
index 47fe4a0e78277700edef015744db24a977334cc4..26ec23bc94e6823a8d2d0b6a45a61631c9aa9106 100644 (file)
@@ -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<InnerGameData> _logger;
-        private readonly IEventManager _eventManager;
-        private readonly ConcurrentDictionary<byte, InnerPlayerInfo> _allPlayers;
-
-        public InnerGameData(ICustomMessageManager<ICustomRpc> customMessageManager, Game game, ILogger<InnerGameData> logger, IEventManager eventManager, IServiceProvider serviceProvider) : base(customMessageManager, game)
-        {
-            _logger = logger;
-            _eventManager = eventManager;
-            _allPlayers = new ConcurrentDictionary<byte, InnerPlayerInfo>();
-
-            Components.Add(this);
-            Components.Add(ActivatorUtilities.CreateInstance<InnerVoteBanSystem>(serviceProvider, game));
-        }
+        private readonly ConcurrentDictionary<byte, InnerPlayerInfo> _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<bool> 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<bool> 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<byte> 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<TaskInfo>(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 _);
         }
     }
 }
index 512a4f1afcf3adaea611c4715f65efb2ac55d5e9..b8b3cd8b540e4067a1b70c7b7c3d132daf132af1 100644 (file)
@@ -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<ITaskInfo> IInnerPlayerInfo.Tasks => Tasks;
     }
index 320cb5b06d43a34c3dcfdf9e05bf96e6dfffe38c..498f8f6b8f972bc89b616b79ed69e43df502c53e 100644 (file)
@@ -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<InnerPlayerInfo> _logger;
+
+        public InnerPlayerInfo(ICustomMessageManager<ICustomRpc> customMessageManager, Game game, ILogger<InnerPlayerInfo> 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<bool> 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<bool>(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;
         }
     }
 }
index 5f0e56ccd990939e8fa3a510790efbfb6f5ef08f..4e429fa3e89ddf93d3d74bb1715a9272508e0cda 100644 (file)
@@ -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))
                     {
index 68d4c2617c540ed9fe1568a55ce2711de6b2d842..d57ec1dbaa9455283ca3d496e2dea6b04f9e7076 100644 (file)
@@ -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;
 
index 66f69f0fffe1aea528fe97a4592189257488c60a..25efec69bbefce1ce3c39ca6a5c606c4fd1633fe 100644 (file)
@@ -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; }