]> git.deb.at Git - rhonda/impostor.git/commitdiff
Implement deserialization for most GameData objects
authorAeonLucid <aeonlucid@outlook.com>
Fri, 23 Oct 2020 03:38:32 +0000 (05:38 +0200)
committerAeonLucid <aeonlucid@outlook.com>
Fri, 23 Oct 2020 03:38:32 +0000 (05:38 +0200)
50 files changed:
src/Impostor.Api/Extensions/SpanReaderExtensions.cs
src/Impostor.Api/Games/IGame.cs
src/Impostor.Api/Innersloth/Data/GameNet.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Data/MapId.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/GameOptionsData.cs
src/Impostor.Api/Innersloth/Net/GameObject.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/InnerNetObject.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/Components/InnerCustomNetworkTransform.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/Components/InnerPlayerPhysics.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/Components/InnerVoteBanSystem.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.PlayerInfo.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.TaskInfo.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/InnerLobbyBehaviour.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/InnerMeetingHud.PlayerVoteArea.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/InnerMeetingHud.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/InnerPlayerControl.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/InnerShipStatus.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/Systems/IActivatable.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/Systems/ISystemType.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/DoorsSystemType.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/HudOverrideSystemType.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/LifeSuppSystemType.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/MedScanSystem.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/ReactorSystemType.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/SabotageSystemType.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/SecurityCameraSystemType.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/SwitchSystem.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/Systems/SystemTypeHelpers.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/Objects/Systems/SystemTypes.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/Net/SpawnFlags.cs [new file with mode: 0644]
src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs
src/Impostor.Api/Net/Messages/C2S/Message10AlterGameC2S.cs
src/Impostor.Api/Properties/AssemblyInfo.cs [new file with mode: 0644]
src/Impostor.Server/GameData/GameObject.cs [deleted file]
src/Impostor.Server/GameData/InnerNetObject.cs [deleted file]
src/Impostor.Server/GameData/Objects/Components/InnerCustomNetworkTransform.cs [deleted file]
src/Impostor.Server/GameData/Objects/Components/InnerPlayerPhysics.cs [deleted file]
src/Impostor.Server/GameData/Objects/Components/InnerVoteBanSystem.cs [deleted file]
src/Impostor.Server/GameData/Objects/InnerGameData.PlayerInfo.cs [deleted file]
src/Impostor.Server/GameData/Objects/InnerGameData.TaskInfo.cs [deleted file]
src/Impostor.Server/GameData/Objects/InnerGameData.cs [deleted file]
src/Impostor.Server/GameData/Objects/InnerLobbyBehaviour.cs [deleted file]
src/Impostor.Server/GameData/Objects/InnerMeetingHud.cs [deleted file]
src/Impostor.Server/GameData/Objects/InnerPlayerControl.cs [deleted file]
src/Impostor.Server/GameData/Objects/InnerShipStatus.cs [deleted file]
src/Impostor.Server/GameData/SpawnFlags.cs [deleted file]
src/Impostor.Server/Net/State/Game.Data.cs
src/Impostor.Server/Net/State/Game.cs
src/Impostor.Tools.ServerReplay/Program.cs

index 97365ac3a4e4635ffadff1b85c650e457a02f3aa..c103ee7bc261b684ce46d4e09f8abc3e72c85bea 100644 (file)
@@ -2,7 +2,7 @@
 using System.Buffers.Binary;
 using System.Runtime.CompilerServices;
 
-namespace Impostor.Api.Extensions
+namespace Impostor.Api
 {
     /// <summary>
     /// Priovides a StreamReader-like api throught extensions
index 17fa2b87ed624e6a7ce33c4edb9ccc16e08cb9d9..5dbec197cea60c744b63222f7060a8cd86c505f4 100644 (file)
@@ -16,6 +16,8 @@ namespace Impostor.Api.Games
 
         GameStates GameState { get; }
 
+        GameNet GameNet { get; }
+
         IEnumerable<IClientPlayer> Players { get; }
 
         IPEndPoint PublicIp { get; }
diff --git a/src/Impostor.Api/Innersloth/Data/GameNet.cs b/src/Impostor.Api/Innersloth/Data/GameNet.cs
new file mode 100644 (file)
index 0000000..2d37879
--- /dev/null
@@ -0,0 +1,29 @@
+using Impostor.Api.Innersloth.Net;
+using Impostor.Api.Innersloth.Net.Objects;
+
+namespace Impostor.Api.Innersloth.Data
+{
+    /// <summary>
+    ///     Holds all data that is serialized over the network through GameData packets.
+    /// </summary>
+    public class GameNet
+    {
+        public InnerGameData GameData { get; internal set; }
+
+        internal void OnSpawn(InnerNetObject netObj)
+        {
+            if (netObj is InnerGameData data)
+            {
+                GameData = data;
+            }
+        }
+
+        internal void OnDestroy(InnerNetObject netObj)
+        {
+            if (netObj is InnerGameData)
+            {
+                GameData = null;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Data/MapId.cs b/src/Impostor.Api/Innersloth/Data/MapId.cs
new file mode 100644 (file)
index 0000000..97d79d4
--- /dev/null
@@ -0,0 +1,10 @@
+namespace Impostor.Api.Innersloth.Data
+{
+    public static class MapId
+    {
+        // TODO: Not sure if correct, check
+        public const int Skeld = 0;
+        public const int MiraHQ = 1;
+        public const int Polus = 2;
+    }
+}
\ No newline at end of file
index e420e53f64fa2796bf417057c8871a8dc7412713..41bebff27a6d25a7e67e47b182b990329e4ac38d 100644 (file)
@@ -1,5 +1,4 @@
-using Impostor.Api.Extensions;
-using Impostor.Api.Innersloth.Data;
+using Impostor.Api.Innersloth.Data;
 
 using System;
 using System.IO;
diff --git a/src/Impostor.Api/Innersloth/Net/GameObject.cs b/src/Impostor.Api/Innersloth/Net/GameObject.cs
new file mode 100644 (file)
index 0000000..c58e4fb
--- /dev/null
@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+
+namespace Impostor.Api.Innersloth.Net
+{
+    public class GameObject
+    {
+        public GameObject()
+        {
+            Components = new List<object>();
+        }
+
+        protected List<object> Components { get; }
+
+        public List<T> GetComponentsInChildren<T>()
+        {
+            var result = new List<T>();
+
+            foreach (var component in Components)
+            {
+                if (component is T c)
+                {
+                    result.Add(c);
+                }
+            }
+
+            return result;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/InnerNetObject.cs b/src/Impostor.Api/Innersloth/Net/InnerNetObject.cs
new file mode 100644 (file)
index 0000000..6e112f3
--- /dev/null
@@ -0,0 +1,19 @@
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net
+{
+    public abstract class InnerNetObject : GameObject
+    {
+        public uint NetId { get; internal set; }
+
+        public int OwnerId { get; internal set; }
+
+        public SpawnFlags SpawnFlags { get; internal set; }
+
+        public abstract void HandleRpc(byte callId, IMessageReader reader);
+
+        public abstract bool Serialize(IMessageWriter writer, bool initialState);
+
+        public abstract void Deserialize(IMessageReader reader, bool initialState);
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/Components/InnerCustomNetworkTransform.cs b/src/Impostor.Api/Innersloth/Net/Objects/Components/InnerCustomNetworkTransform.cs
new file mode 100644 (file)
index 0000000..a8c4915
--- /dev/null
@@ -0,0 +1,112 @@
+using System.Numerics;
+using Impostor.Api.Net.Messages;
+using Microsoft.Extensions.Logging;
+
+namespace Impostor.Api.Innersloth.Net.Objects.Components
+{
+    public class InnerCustomNetworkTransform : InnerNetObject
+    {
+        private static readonly FloatRange XRange = new FloatRange(-40f, 40f);
+        private static readonly FloatRange YRange = new FloatRange(-40f, 40f);
+
+        private readonly ILogger<InnerCustomNetworkTransform> _logger;
+
+        private ushort _lastSequenceId;
+        private Vector2 _targetSyncPosition;
+        private Vector2 _targetSyncVelocity;
+
+        public InnerCustomNetworkTransform(ILogger<InnerCustomNetworkTransform> logger)
+        {
+            _logger = logger;
+        }
+
+        private static bool SidGreaterThan(ushort newSid, ushort prevSid)
+        {
+            var num = (ushort)(prevSid + (uint) short.MaxValue);
+
+            return (int) prevSid < (int) num
+                ? newSid > prevSid && newSid <= num
+                : newSid > prevSid || newSid <= num;
+        }
+
+        private static void WriteVector2(IMessageWriter writer, Vector2 vec)
+        {
+            writer.Write((ushort)(XRange.ReverseLerp(vec.X) * (double) ushort.MaxValue));
+            writer.Write((ushort)(YRange.ReverseLerp(vec.Y) * (double) ushort.MaxValue));
+        }
+
+        private static Vector2 ReadVector2(IMessageReader reader)
+        {
+            var v1 = reader.ReadUInt16() / (float) ushort.MaxValue;
+            var v2 = reader.ReadUInt16() / (float) ushort.MaxValue;
+
+            return new Vector2(XRange.Lerp(v1), YRange.Lerp(v2));
+        }
+
+        public override void HandleRpc(byte callId, IMessageReader reader)
+        {
+            if (callId == 0)
+            {
+                SnapTo(ReadVector2(reader), reader.ReadUInt16());
+            }
+            else
+            {
+                _logger.LogWarning("InnerCustomNetworkTransform: Unknown rpc call {0}", callId);
+            }
+        }
+
+        public override bool Serialize(IMessageWriter writer, bool initialState)
+        {
+            if (initialState)
+            {
+                writer.Write(_lastSequenceId);
+                WriteVector2(writer, _targetSyncPosition);
+                WriteVector2(writer, _targetSyncVelocity);
+                return true;
+            }
+
+            // TODO: DirtyBits == 0 return false.
+            _lastSequenceId++;
+
+            writer.Write(_lastSequenceId);
+            WriteVector2(writer, _targetSyncPosition);
+            WriteVector2(writer, _targetSyncVelocity);
+            return true;
+        }
+
+        public override void Deserialize(IMessageReader reader, bool initialState)
+        {
+            var sequenceId = reader.ReadUInt16();
+
+            if (initialState)
+            {
+                _lastSequenceId = sequenceId;
+                _targetSyncPosition = ReadVector2(reader);
+                _targetSyncVelocity = ReadVector2(reader);
+            }
+            else
+            {
+                if (!SidGreaterThan(sequenceId, _lastSequenceId))
+                {
+                    return;
+                }
+
+                _lastSequenceId = sequenceId;
+                _targetSyncPosition = ReadVector2(reader);
+                _targetSyncVelocity = ReadVector2(reader);
+            }
+        }
+
+        private void SnapTo(Vector2 position, ushort minSid)
+        {
+            if (SidGreaterThan(minSid, _lastSequenceId))
+            {
+                return;
+            }
+
+            _lastSequenceId = minSid;
+            _targetSyncPosition = position;
+            _targetSyncVelocity = Vector2.Zero;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/Components/InnerPlayerPhysics.cs b/src/Impostor.Api/Innersloth/Net/Objects/Components/InnerPlayerPhysics.cs
new file mode 100644 (file)
index 0000000..7c74aaf
--- /dev/null
@@ -0,0 +1,22 @@
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects.Components
+{
+    public class InnerPlayerPhysics : InnerNetObject
+    {
+        public override void HandleRpc(byte callId, IMessageReader reader)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public override bool Serialize(IMessageWriter writer, bool initialState)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public override void Deserialize(IMessageReader reader, bool initialState)
+        {
+            throw new System.NotImplementedException();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/Components/InnerVoteBanSystem.cs b/src/Impostor.Api/Innersloth/Net/Objects/Components/InnerVoteBanSystem.cs
new file mode 100644 (file)
index 0000000..ed5f29a
--- /dev/null
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects.Components
+{
+    public class InnerVoteBanSystem : InnerNetObject
+    {
+        private readonly Dictionary<int, int[]> _votes;
+
+        public InnerVoteBanSystem()
+        {
+            _votes = new Dictionary<int, int[]>();
+        }
+
+        public override void HandleRpc(byte callId, IMessageReader reader)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override bool Serialize(IMessageWriter writer, bool initialState)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override void Deserialize(IMessageReader reader, bool initialState)
+        {
+            var votes = _votes;
+            var unknown = reader.ReadByte();
+            if (unknown != 0)
+            {
+                for (var i = 0; i < unknown; i++)
+                {
+                    var v4 = reader.ReadInt32();
+                    if (v4 == 0)
+                    {
+                        break;
+                    }
+
+                    if (!votes.TryGetValue(v4, out var v12))
+                    {
+                        v12 = new int[3];
+                        votes[v4] = v12;
+                    }
+
+                    for (var j = 0; j < 3; j++)
+                    {
+                        v12[j] = reader.ReadPackedInt32();
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.PlayerInfo.cs b/src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.PlayerInfo.cs
new file mode 100644 (file)
index 0000000..b076d9e
--- /dev/null
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects
+{
+    public partial class InnerGameData
+    {
+        public class PlayerInfo
+        {
+            public PlayerInfo(byte playerId)
+            {
+                PlayerId = playerId;
+            }
+
+            public byte PlayerId { get; }
+
+            public string PlayerName { get; private set; }
+
+            public byte ColorId { get; private set; }
+
+            public uint HatId { get; private set; }
+
+            public uint PetId { get; private set; }
+
+            public uint SkinId { get; private set; }
+
+            public bool Disconnected { get; private set; }
+
+            public bool IsImpostor { get; private set; }
+
+            public bool IsDead { get; private set; }
+
+            public List<TaskInfo> Tasks { get; private set; }
+
+            public void Serialize(IMessageWriter writer)
+            {
+                throw new NotImplementedException();
+            }
+
+            public void Deserialize(IMessageReader reader)
+            {
+                PlayerName = reader.ReadString();
+                ColorId = reader.ReadByte();
+                HatId = reader.ReadPackedUInt32();
+                PetId = reader.ReadPackedUInt32();
+                SkinId = reader.ReadPackedUInt32();
+                var flag = reader.ReadByte();
+                Disconnected = (flag & 1) > 0;
+                IsImpostor = (flag & 2) > 0;
+                IsDead = (flag & 4) > 0;
+                var taskCount = reader.ReadByte();
+                Tasks = new List<TaskInfo>();
+                for (var i = 0; i < taskCount; i++)
+                {
+                    Tasks.Add(new TaskInfo());
+                    Tasks[i].Deserialize(reader);
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.TaskInfo.cs b/src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.TaskInfo.cs
new file mode 100644 (file)
index 0000000..d1ef9f2
--- /dev/null
@@ -0,0 +1,26 @@
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects
+{
+    public partial class InnerGameData
+    {
+        public class TaskInfo
+        {
+            public uint Id { get; private set; }
+
+            public bool Complete { get; private set; }
+
+            public void Serialize(IMessageWriter writer)
+            {
+                writer.WritePacked(Id);
+                writer.Write(Complete);
+            }
+
+            public void Deserialize(IMessageReader reader)
+            {
+                this.Id = reader.ReadPackedUInt32();
+                this.Complete = reader.ReadBoolean();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.cs b/src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.cs
new file mode 100644 (file)
index 0000000..5d07e10
--- /dev/null
@@ -0,0 +1,87 @@
+using System;
+using System.Collections.Generic;
+using Impostor.Api.Games;
+using Impostor.Api.Innersloth.Net.Objects.Components;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects
+{
+    public partial class InnerGameData : InnerNetObject
+    {
+        private readonly IGame _game;
+        private readonly List<PlayerInfo> _allPlayers;
+
+        public InnerGameData(IGame game)
+        {
+            _game = game;
+            _allPlayers = new List<PlayerInfo>();
+
+            Components.Add(this);
+            Components.Add(new InnerVoteBanSystem());
+        }
+
+        public int PlayerCount => _allPlayers.Count;
+
+        public IReadOnlyList<PlayerInfo> Players => _allPlayers;
+
+        public PlayerInfo GetPlayerById(byte id)
+        {
+            foreach (var player in _allPlayers)
+            {
+                if (player.PlayerId == id)
+                {
+                    return player;
+                }
+            }
+
+            return null;
+        }
+
+        public override void HandleRpc(byte callId, IMessageReader reader)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override bool Serialize(IMessageWriter writer, bool initialState)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override void Deserialize(IMessageReader reader, bool initialState)
+        {
+            if (initialState)
+            {
+                var num = reader.ReadPackedInt32();
+
+                for (var i = 0; i < num; i++)
+                {
+                    var playerInfo = new PlayerInfo(reader.ReadByte());
+                    playerInfo.Deserialize(reader);
+                    _allPlayers.Add(playerInfo);
+                }
+            }
+            else
+            {
+                throw new NotImplementedException("This shouldn't happen, according to Among Us disassembly..");
+
+                // var num = reader.ReadByte();
+                //
+                // for (var i = 0; i < num; i++)
+                // {
+                //     var id = reader.ReadByte();
+                //     var player = GetPlayerById(id);
+                //     if (player != null)
+                //     {
+                //         player.Deserialize(reader);
+                //     }
+                //     else
+                //     {
+                //         var playerInfo = new PlayerInfo(id);
+                //         playerInfo.Deserialize(reader);
+                //         _allPlayers.Add(playerInfo);
+                //     }
+                // }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/InnerLobbyBehaviour.cs b/src/Impostor.Api/Innersloth/Net/Objects/InnerLobbyBehaviour.cs
new file mode 100644 (file)
index 0000000..7b73ed2
--- /dev/null
@@ -0,0 +1,32 @@
+using Impostor.Api.Games;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects
+{
+    public class InnerLobbyBehaviour : InnerNetObject
+    {
+        private readonly IGame _game;
+
+        public InnerLobbyBehaviour(IGame game)
+        {
+            _game = game;
+
+            Components.Add(this);
+        }
+
+        public override void HandleRpc(byte callId, IMessageReader reader)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public override bool Serialize(IMessageWriter writer, bool initialState)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public override void Deserialize(IMessageReader reader, bool initialState)
+        {
+            throw new System.NotImplementedException();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/InnerMeetingHud.PlayerVoteArea.cs b/src/Impostor.Api/Innersloth/Net/Objects/InnerMeetingHud.PlayerVoteArea.cs
new file mode 100644 (file)
index 0000000..82f0ef6
--- /dev/null
@@ -0,0 +1,49 @@
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects
+{
+    public partial class InnerMeetingHud
+    {
+        public class PlayerVoteArea
+        {
+            private const byte VoteMask = 15;
+            private const byte ReportedBit = 32;
+            private const byte VotedBit = 64;
+            private const byte DeadBit = 128;
+
+            public PlayerVoteArea(InnerMeetingHud parent, byte targetPlayerId)
+            {
+                Parent = parent;
+                TargetPlayerId = targetPlayerId;
+            }
+
+            public InnerMeetingHud Parent { get; }
+
+            public byte TargetPlayerId { get; }
+
+            public bool IsDead { get; private set; }
+
+            public bool DidVote { get; private set; }
+
+            public bool DidReport { get; private set; }
+
+            public sbyte VotedFor { get; private set; }
+
+            internal void SetDead(bool didReport, bool isDead)
+            {
+                DidReport = didReport;
+                IsDead = isDead;
+            }
+
+            public void Deserialize(IMessageReader reader)
+            {
+                var num = reader.ReadByte();
+
+                VotedFor = (sbyte)((num & VoteMask) - 1);
+                IsDead = (num & DeadBit) > 0;
+                DidVote = (num & VotedBit) > 0;
+                DidReport = (num & ReportedBit) > 0;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/InnerMeetingHud.cs b/src/Impostor.Api/Innersloth/Net/Objects/InnerMeetingHud.cs
new file mode 100644 (file)
index 0000000..816fe6f
--- /dev/null
@@ -0,0 +1,78 @@
+using System;
+using Impostor.Api.Games;
+using Impostor.Api.Innersloth.Data;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects
+{
+    public partial class InnerMeetingHud : InnerNetObject
+    {
+        private readonly IGame _game;
+        private readonly GameNet _gameNet;
+        private PlayerVoteArea[] _playerStates;
+
+        public InnerMeetingHud(IGame game)
+        {
+            _game = game;
+            _gameNet = game.GameNet;
+            _playerStates = null;
+
+            Components.Add(this);
+        }
+
+        public byte ReporterId { get; private set; }
+
+        private void PopulateButtons(byte reporter)
+        {
+            _playerStates = new PlayerVoteArea[_gameNet.GameData.PlayerCount];
+
+            for (var i = 0; i < _playerStates.Length; i++)
+            {
+                var player = _gameNet.GameData.Players[i];
+                var playerVoteArea = _playerStates[i] = new PlayerVoteArea(this, player.PlayerId);
+
+                playerVoteArea.SetDead(player.PlayerId == reporter, player.Disconnected || player.IsDead);
+            }
+        }
+
+        public override void HandleRpc(byte callId, IMessageReader reader)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override bool Serialize(IMessageWriter writer, bool initialState)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override void Deserialize(IMessageReader reader, bool initialState)
+        {
+            if (initialState)
+            {
+                PopulateButtons(0);
+
+                foreach (var playerState in _playerStates)
+                {
+                    playerState.Deserialize(reader);
+
+                    if (playerState.DidReport)
+                    {
+                        ReporterId = playerState.TargetPlayerId;
+                    }
+                }
+            }
+            else
+            {
+                var num = reader.ReadPackedUInt32();
+
+                for (var i = 0; i < _playerStates.Length; i++)
+                {
+                    if ((num & 1 << i) != 0)
+                    {
+                        _playerStates[i].Deserialize(reader);
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/InnerPlayerControl.cs b/src/Impostor.Api/Innersloth/Net/Objects/InnerPlayerControl.cs
new file mode 100644 (file)
index 0000000..fd9a609
--- /dev/null
@@ -0,0 +1,48 @@
+using System;
+using Impostor.Api.Games;
+using Impostor.Api.Innersloth.Net.Objects.Components;
+using Impostor.Api.Net.Messages;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Impostor.Api.Innersloth.Net.Objects
+{
+    public class InnerPlayerControl : InnerNetObject
+    {
+        private readonly IGame _game;
+
+        public InnerPlayerControl(IGame game, IServiceProvider serviceProvider)
+        {
+            _game = game;
+
+            Components.Add(this);
+            Components.Add(ActivatorUtilities.CreateInstance<InnerPlayerPhysics>(serviceProvider));
+            Components.Add(ActivatorUtilities.CreateInstance<InnerCustomNetworkTransform>(serviceProvider));
+
+            PlayerId = byte.MaxValue;
+        }
+
+        public bool IsNew { get; private set; }
+
+        public byte PlayerId { get; private set; }
+
+        public override void HandleRpc(byte callId, IMessageReader reader)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override bool Serialize(IMessageWriter writer, bool initialState)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override void Deserialize(IMessageReader reader, bool initialState)
+        {
+            if (initialState)
+            {
+                IsNew = reader.ReadBoolean();
+            }
+
+            PlayerId = reader.ReadByte();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/InnerShipStatus.cs b/src/Impostor.Api/Innersloth/Net/Objects/InnerShipStatus.cs
new file mode 100644 (file)
index 0000000..d16eaf5
--- /dev/null
@@ -0,0 +1,81 @@
+using System.Collections.Generic;
+using Impostor.Api.Games;
+using Impostor.Api.Innersloth.Net.Objects.Systems;
+using Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects
+{
+    public class InnerShipStatus : InnerNetObject
+    {
+        private readonly IGame _game;
+        private readonly Dictionary<SystemTypes, ISystemType> _systems;
+
+        public InnerShipStatus(IGame game)
+        {
+            _game = game;
+
+            _systems = new Dictionary<SystemTypes, ISystemType>
+            {
+                [SystemTypes.Electrical] = new SwitchSystem(),
+                [SystemTypes.MedBay] = new MedScanSystem(),
+                [SystemTypes.Reactor] = new ReactorSystemType(),
+                [SystemTypes.LifeSupp] = new LifeSuppSystemType(),
+                [SystemTypes.Security] = new SecurityCameraSystemType(),
+                [SystemTypes.Comms] = new HudOverrideSystemType(),
+                [SystemTypes.Doors] = new DoorsSystemType(_game),
+            };
+
+            _systems.Add(SystemTypes.Sabotage, new SabotageSystemType(new[]
+            {
+                (IActivatable) _systems[SystemTypes.Comms],
+                (IActivatable) _systems[SystemTypes.Reactor],
+                (IActivatable) _systems[SystemTypes.LifeSupp],
+                (IActivatable) _systems[SystemTypes.Electrical],
+            }));
+
+            Components.Add(this);
+        }
+
+        public override void HandleRpc(byte callId, IMessageReader reader)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public override bool Serialize(IMessageWriter writer, bool initialState)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public override void Deserialize(IMessageReader reader, bool initialState)
+        {
+            if (initialState)
+            {
+                // TODO: (_systems[SystemTypes.Doors] as DoorsSystemType).SetDoors();
+                foreach (var systemType in SystemTypeHelpers.AllTypes)
+                {
+                    if (_systems.TryGetValue(systemType, out var system))
+                    {
+                        system.Deserialize(reader, true);
+                    }
+                }
+            }
+            else
+            {
+                var count = reader.ReadPackedUInt32();
+
+                foreach (var systemType in SystemTypeHelpers.AllTypes)
+                {
+                    // TODO: Not sure what is going on here, check.
+                    if ((count & 1 << (int) (systemType & (SystemTypes.ShipTasks | SystemTypes.Doors))) != 0L)
+                    {
+                        if (_systems.TryGetValue(systemType, out var system))
+                        {
+                            system.Deserialize(reader, false);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/Systems/IActivatable.cs b/src/Impostor.Api/Innersloth/Net/Objects/Systems/IActivatable.cs
new file mode 100644 (file)
index 0000000..eaae0a2
--- /dev/null
@@ -0,0 +1,7 @@
+namespace Impostor.Api.Innersloth.Net.Objects.Systems
+{
+    public interface IActivatable
+    {
+        bool IsActive { get; }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/Systems/ISystemType.cs b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ISystemType.cs
new file mode 100644 (file)
index 0000000..0b25e94
--- /dev/null
@@ -0,0 +1,11 @@
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects.Systems
+{
+    public interface ISystemType
+    {
+        void Serialize(IMessageWriter writer, bool initialState);
+
+        void Deserialize(IMessageReader reader, bool initialState);
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/DoorsSystemType.cs b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/DoorsSystemType.cs
new file mode 100644 (file)
index 0000000..05a2916
--- /dev/null
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using Impostor.Api.Games;
+using Impostor.Api.Innersloth.Data;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
+{
+    public class DoorsSystemType : ISystemType
+    {
+        // TODO: AutoDoors
+        private readonly Dictionary<int, bool> _doors;
+
+        public DoorsSystemType(IGame game)
+        {
+            // TODO: Check
+            var doorCount = game.Options.MapId switch
+            {
+                MapId.Skeld => 13,
+                MapId.MiraHQ => 2,
+                MapId.Polus => 12,
+                _ => throw new ArgumentOutOfRangeException()
+            };
+
+            _doors = new Dictionary<int, bool>(doorCount);
+
+            for (var i = 0; i < doorCount; i++)
+            {
+                _doors.Add(i, false);
+            }
+        }
+
+        public void Serialize(IMessageWriter writer, bool initialState)
+        {
+            throw new NotImplementedException();
+        }
+
+        public void Deserialize(IMessageReader reader, bool initialState)
+        {
+            if (initialState)
+            {
+                for (var i = 0; i < _doors.Count; i++)
+                {
+                    _doors[i] = reader.ReadBoolean();
+                }
+            }
+            else
+            {
+                var num = reader.ReadPackedUInt32();
+
+                for (var i = 0; i < _doors.Count; i++)
+                {
+                    if ((num & 1 << i) != 0)
+                    {
+                        _doors[i] = reader.ReadBoolean();
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/HudOverrideSystemType.cs b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/HudOverrideSystemType.cs
new file mode 100644 (file)
index 0000000..fe29bb0
--- /dev/null
@@ -0,0 +1,19 @@
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
+{
+    public class HudOverrideSystemType : ISystemType, IActivatable
+    {
+        public bool IsActive { get; private set; }
+
+        public void Serialize(IMessageWriter writer, bool initialState)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public void Deserialize(IMessageReader reader, bool initialState)
+        {
+            IsActive = reader.ReadBoolean();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/LifeSuppSystemType.cs b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/LifeSuppSystemType.cs
new file mode 100644 (file)
index 0000000..fd8b01a
--- /dev/null
@@ -0,0 +1,44 @@
+using System.Collections.Generic;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
+{
+    public class LifeSuppSystemType : ISystemType, IActivatable
+    {
+        public LifeSuppSystemType()
+        {
+            Countdown = 10000f;
+            CompletedConsoles = new HashSet<int>();
+        }
+
+        public float Countdown { get; private set; }
+
+        public HashSet<int> CompletedConsoles { get; }
+
+        public bool IsActive => Countdown < 10000.0;
+
+        public void Serialize(IMessageWriter writer, bool initialState)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public void Deserialize(IMessageReader reader, bool initialState)
+        {
+            Countdown = reader.ReadSingle();
+
+            if (reader.Position >= reader.Length)
+            {
+                return;
+            }
+
+            CompletedConsoles.Clear(); // TODO: Thread safety
+
+            var num = reader.ReadPackedInt32();
+
+            for (var i = 0; i < num; i++)
+            {
+                CompletedConsoles.Add(reader.ReadPackedInt32());
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/MedScanSystem.cs b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/MedScanSystem.cs
new file mode 100644 (file)
index 0000000..f93fb8e
--- /dev/null
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
+{
+    public class MedScanSystem : ISystemType
+    {
+        public MedScanSystem()
+        {
+            UsersList = new List<byte>();
+        }
+
+        public List<byte> UsersList { get; }
+
+        public void Serialize(IMessageWriter writer, bool initialState)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public void Deserialize(IMessageReader reader, bool initialState)
+        {
+            UsersList.Clear();
+
+            var num = reader.ReadPackedInt32();
+
+            for (var i = 0; i < num; i++)
+            {
+                UsersList.Add(reader.ReadByte());
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/ReactorSystemType.cs b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/ReactorSystemType.cs
new file mode 100644 (file)
index 0000000..d3f1973
--- /dev/null
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
+{
+    public class ReactorSystemType : ISystemType, IActivatable
+    {
+        public ReactorSystemType()
+        {
+            Countdown = 10000f;
+            UserConsolePairs = new HashSet<Tuple<byte, byte>>();
+        }
+
+        public float Countdown { get; private set; }
+
+        public HashSet<Tuple<byte, byte>> UserConsolePairs { get; }
+
+        public bool IsActive => Countdown < 10000.0;
+
+        public void Serialize(IMessageWriter writer, bool initialState)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public void Deserialize(IMessageReader reader, bool initialState)
+        {
+            Countdown = reader.ReadSingle();
+            UserConsolePairs.Clear(); // TODO: Thread safety
+
+            var count = reader.ReadPackedInt32();
+
+            for (var i = 0; i < count; i++)
+            {
+                UserConsolePairs.Add(new Tuple<byte, byte>(reader.ReadByte(), reader.ReadByte()));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/SabotageSystemType.cs b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/SabotageSystemType.cs
new file mode 100644 (file)
index 0000000..f442b91
--- /dev/null
@@ -0,0 +1,26 @@
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
+{
+    public class SabotageSystemType : ISystemType
+    {
+        private readonly IActivatable[] _specials;
+
+        public SabotageSystemType(IActivatable[] specials)
+        {
+            _specials = specials;
+        }
+
+        public float Timer { get; set; }
+
+        public void Serialize(IMessageWriter writer, bool initialState)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public void Deserialize(IMessageReader reader, bool initialState)
+        {
+            Timer = reader.ReadSingle();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/SecurityCameraSystemType.cs b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/SecurityCameraSystemType.cs
new file mode 100644 (file)
index 0000000..4e16b31
--- /dev/null
@@ -0,0 +1,19 @@
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
+{
+    public class SecurityCameraSystemType : ISystemType
+    {
+        public byte InUse { get; internal set; }
+
+        public void Serialize(IMessageWriter writer, bool initialState)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public void Deserialize(IMessageReader reader, bool initialState)
+        {
+            InUse = reader.ReadByte();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/SwitchSystem.cs b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/SwitchSystem.cs
new file mode 100644 (file)
index 0000000..6d46d01
--- /dev/null
@@ -0,0 +1,27 @@
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
+{
+    public class SwitchSystem : ISystemType, IActivatable
+    {
+        public byte ExpectedSwitches { get; set; }
+
+        public byte ActualSwitches { get; set; }
+
+        public byte Value { get; set; } = byte.MaxValue;
+
+        public bool IsActive { get; }
+
+        public void Serialize(IMessageWriter writer, bool initialState)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public void Deserialize(IMessageReader reader, bool initialState)
+        {
+            ExpectedSwitches = reader.ReadByte();
+            ActualSwitches = reader.ReadByte();
+            Value = reader.ReadByte();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/Systems/SystemTypeHelpers.cs b/src/Impostor.Api/Innersloth/Net/Objects/Systems/SystemTypeHelpers.cs
new file mode 100644 (file)
index 0000000..46e68ff
--- /dev/null
@@ -0,0 +1,28 @@
+using System;
+using System.Linq;
+
+namespace Impostor.Api.Innersloth.Net.Objects.Systems
+{
+    internal class SystemTypeHelpers
+    {
+        public static readonly SystemTypes[] AllTypes;
+        public static readonly string[] Names;
+
+        static SystemTypeHelpers()
+        {
+            AllTypes = Enum.GetValues(typeof(SystemTypes)).Cast<SystemTypes>().ToArray();
+            Names = AllTypes.Select(x =>
+            {
+                return x switch
+                {
+                    SystemTypes.UpperEngine => "Upper Engine",
+                    SystemTypes.Nav => "Navigations",
+                    SystemTypes.LifeSupp => "O2",
+                    SystemTypes.LowerEngine => "Lower Engine",
+                    SystemTypes.LockerRoom => "Locker Room",
+                    _ => x.ToString()
+                };
+            }).ToArray();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/Objects/Systems/SystemTypes.cs b/src/Impostor.Api/Innersloth/Net/Objects/Systems/SystemTypes.cs
new file mode 100644 (file)
index 0000000..0ff4220
--- /dev/null
@@ -0,0 +1,31 @@
+namespace Impostor.Api.Innersloth.Net.Objects.Systems
+{
+    public enum SystemTypes : byte
+    {
+        Hallway,
+        Storage,
+        Cafeteria,
+        Reactor,
+        UpperEngine,
+        Nav,
+        Admin,
+        Electrical,
+        LifeSupp,
+        Shields,
+        MedBay,
+        Security,
+        Weapons,
+        LowerEngine,
+        Comms,
+        ShipTasks,
+        Doors,
+        Sabotage,
+        Decontamination,
+        Launchpad,
+        LockerRoom,
+        Laboratory,
+        Balcony,
+        Office,
+        Greenhouse,
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Innersloth/Net/SpawnFlags.cs b/src/Impostor.Api/Innersloth/Net/SpawnFlags.cs
new file mode 100644 (file)
index 0000000..0372196
--- /dev/null
@@ -0,0 +1,11 @@
+using System;
+
+namespace Impostor.Api.Innersloth.Net
+{
+    [Flags]
+    public enum SpawnFlags : byte
+    {
+        None = 0,
+        IsClientCharacter = 1,
+    }
+}
\ No newline at end of file
index c713790e39d0cdebcf9c6866f6ffe30a724da614..f121b97ea35c8590bd2e63e2198586562c3e8b39 100644 (file)
@@ -1,5 +1,4 @@
 using System;
-using Impostor.Api.Extensions;
 
 namespace Impostor.Api.Net.Messages.C2S
 {
index e9ad8e8af1b1a4f50925f49fa85b28ce61217ba6..dd143c062acd77b4299b9eac3673e893be4037ea 100644 (file)
@@ -1,5 +1,4 @@
-using Impostor.Api.Extensions;
-using Impostor.Api.Innersloth.Data;
+using Impostor.Api.Innersloth.Data;
 
 namespace Impostor.Api.Net.Messages.C2S
 {
diff --git a/src/Impostor.Api/Properties/AssemblyInfo.cs b/src/Impostor.Api/Properties/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..c02e44a
--- /dev/null
@@ -0,0 +1,3 @@
+using System.Runtime.CompilerServices;
+
+[assembly:InternalsVisibleTo("Impostor.Server")]
\ No newline at end of file
diff --git a/src/Impostor.Server/GameData/GameObject.cs b/src/Impostor.Server/GameData/GameObject.cs
deleted file mode 100644 (file)
index c78dee0..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-using System.Collections.Generic;
-
-namespace Impostor.Server.GameData
-{
-    public class GameObject
-    {
-        public GameObject()
-        {
-            Components = new List<object>();
-        }
-
-        protected List<object> Components { get; }
-
-        public List<T> GetComponentsInChildren<T>()
-        {
-            var result = new List<T>();
-
-            foreach (var component in Components)
-            {
-                if (component.GetType().IsAssignableTo(typeof(T)))
-                {
-                    result.Add((T) component);
-                }
-            }
-
-            return result;
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/Impostor.Server/GameData/InnerNetObject.cs b/src/Impostor.Server/GameData/InnerNetObject.cs
deleted file mode 100644 (file)
index d1a09e0..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Server.GameData
-{
-    public abstract class InnerNetObject : GameObject
-    {
-        public uint NetId { get; set; }
-
-        public int OwnerId { get; set; }
-
-        public SpawnFlags SpawnFlags { get; internal set; }
-
-        public abstract void HandleRpc(byte callId, IMessageReader reader);
-
-        public abstract bool Serialize(IMessageWriter writer, bool initialState);
-
-        public abstract void Deserialize(IMessageReader reader, bool initialState);
-    }
-}
\ No newline at end of file
diff --git a/src/Impostor.Server/GameData/Objects/Components/InnerCustomNetworkTransform.cs b/src/Impostor.Server/GameData/Objects/Components/InnerCustomNetworkTransform.cs
deleted file mode 100644 (file)
index c6804ed..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-using System.Numerics;
-using Impostor.Api.Innersloth;
-using Impostor.Api.Net.Messages;
-using Microsoft.Extensions.Logging;
-
-namespace Impostor.Server.GameData.Objects.Components
-{
-    public class InnerCustomNetworkTransform : InnerNetObject
-    {
-        private static readonly FloatRange XRange = new FloatRange(-40f, 40f);
-        private static readonly FloatRange YRange = new FloatRange(-40f, 40f);
-
-        private readonly ILogger<InnerCustomNetworkTransform> _logger;
-
-        private ushort _lastSequenceId;
-        private Vector2 _targetSyncPosition;
-        private Vector2 _targetSyncVelocity;
-
-        public InnerCustomNetworkTransform(ILogger<InnerCustomNetworkTransform> logger)
-        {
-            _logger = logger;
-        }
-
-        private static bool SidGreaterThan(ushort newSid, ushort prevSid)
-        {
-            var num = (ushort)(prevSid + (uint) short.MaxValue);
-
-            return (int) prevSid < (int) num
-                ? newSid > prevSid && newSid <= num
-                : newSid > prevSid || newSid <= num;
-        }
-
-        private static void WriteVector2(IMessageWriter writer, Vector2 vec)
-        {
-            writer.Write((ushort)(XRange.ReverseLerp(vec.X) * (double) ushort.MaxValue));
-            writer.Write((ushort)(YRange.ReverseLerp(vec.Y) * (double) ushort.MaxValue));
-        }
-
-        private static Vector2 ReadVector2(IMessageReader reader)
-        {
-            var v1 = reader.ReadUInt16() / (float) ushort.MaxValue;
-            var v2 = reader.ReadUInt16() / (float) ushort.MaxValue;
-
-            return new Vector2(XRange.Lerp(v1), YRange.Lerp(v2));
-        }
-
-        public override void HandleRpc(byte callId, IMessageReader reader)
-        {
-            if (callId == 0)
-            {
-                SnapTo(ReadVector2(reader), reader.ReadUInt16());
-            }
-            else
-            {
-                _logger.LogWarning("InnerCustomNetworkTransform: Unknown rpc call {0}", callId);
-            }
-        }
-
-        public override bool Serialize(IMessageWriter writer, bool initialState)
-        {
-            if (initialState)
-            {
-                writer.Write(_lastSequenceId);
-                WriteVector2(writer, _targetSyncPosition);
-                WriteVector2(writer, _targetSyncVelocity);
-                return true;
-            }
-
-            // TODO: DirtyBits == 0 return false.
-            _lastSequenceId++;
-
-            writer.Write(_lastSequenceId);
-            WriteVector2(writer, _targetSyncPosition);
-            WriteVector2(writer, _targetSyncVelocity);
-            return true;
-        }
-
-        public override void Deserialize(IMessageReader reader, bool initialState)
-        {
-            var sequenceId = reader.ReadUInt16();
-
-            if (initialState)
-            {
-                _lastSequenceId = sequenceId;
-                _targetSyncPosition = ReadVector2(reader);
-                _targetSyncVelocity = ReadVector2(reader);
-            }
-            else
-            {
-                if (!SidGreaterThan(sequenceId, _lastSequenceId))
-                {
-                    return;
-                }
-
-                _lastSequenceId = sequenceId;
-                _targetSyncPosition = ReadVector2(reader);
-                _targetSyncVelocity = ReadVector2(reader);
-            }
-        }
-
-        private void SnapTo(Vector2 position, ushort minSid)
-        {
-            if (SidGreaterThan(minSid, _lastSequenceId))
-            {
-                return;
-            }
-
-            _lastSequenceId = minSid;
-            _targetSyncPosition = position;
-            _targetSyncVelocity = Vector2.Zero;
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/Impostor.Server/GameData/Objects/Components/InnerPlayerPhysics.cs b/src/Impostor.Server/GameData/Objects/Components/InnerPlayerPhysics.cs
deleted file mode 100644 (file)
index 698f97e..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Server.GameData.Objects.Components
-{
-    public class InnerPlayerPhysics : InnerNetObject
-    {
-        public override void HandleRpc(byte callId, IMessageReader reader)
-        {
-            throw new System.NotImplementedException();
-        }
-
-        public override bool Serialize(IMessageWriter writer, bool initialState)
-        {
-            throw new System.NotImplementedException();
-        }
-
-        public override void Deserialize(IMessageReader reader, bool initialState)
-        {
-            throw new System.NotImplementedException();
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/Impostor.Server/GameData/Objects/Components/InnerVoteBanSystem.cs b/src/Impostor.Server/GameData/Objects/Components/InnerVoteBanSystem.cs
deleted file mode 100644 (file)
index 72253ba..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Server.GameData.Objects.Components
-{
-    public class InnerVoteBanSystem : InnerNetObject
-    {
-        private readonly Dictionary<int, int[]> _votes;
-
-        public InnerVoteBanSystem()
-        {
-            _votes = new Dictionary<int, int[]>();
-        }
-
-        public override void HandleRpc(byte callId, IMessageReader reader)
-        {
-            throw new NotImplementedException();
-        }
-
-        public override bool Serialize(IMessageWriter writer, bool initialState)
-        {
-            throw new NotImplementedException();
-        }
-
-        public override void Deserialize(IMessageReader reader, bool initialState)
-        {
-            var votes = _votes;
-            var unknown = reader.ReadBoolean();
-            if (unknown)
-            {
-                while (true)
-                {
-                    var v4 = reader.ReadInt32();
-
-                    if (!votes.TryGetValue(v4, out var v12))
-                    {
-                        v12 = new int[3];
-                        votes[v4] = v12;
-                    }
-
-                    for (var i = 0; i < 3; i++)
-                    {
-                        v12[i] = reader.ReadPackedInt32();
-                    }
-                }
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/Impostor.Server/GameData/Objects/InnerGameData.PlayerInfo.cs b/src/Impostor.Server/GameData/Objects/InnerGameData.PlayerInfo.cs
deleted file mode 100644 (file)
index dfcdfab..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Server.GameData.Objects
-{
-    public partial class InnerGameData
-    {
-        public class PlayerInfo
-        {
-            public PlayerInfo(byte playerId)
-            {
-                PlayerId = playerId;
-            }
-
-            public byte PlayerId { get; }
-
-            public string PlayerName { get; private set; }
-
-            public byte ColorId { get; private set; }
-
-            public uint HatId { get; private set; }
-
-            public uint PetId { get; private set; }
-
-            public uint SkinId { get; private set; }
-
-            public bool Disconnected { get; private set; }
-
-            public bool IsImpostor { get; private set; }
-
-            public bool IsDead { get; private set; }
-
-            public List<TaskInfo> Tasks { get; private set; }
-
-            public void Serialize(IMessageWriter writer)
-            {
-                throw new NotImplementedException();
-            }
-
-            public void Deserialize(IMessageReader reader)
-            {
-                PlayerName = reader.ReadString();
-                ColorId = reader.ReadByte();
-                HatId = reader.ReadPackedUInt32();
-                PetId = reader.ReadPackedUInt32();
-                SkinId = reader.ReadPackedUInt32();
-                var flag = reader.ReadByte();
-                Disconnected = (flag & 1) > 0;
-                IsImpostor = (flag & 2) > 0;
-                IsDead = (flag & 4) > 0;
-                var taskCount = reader.ReadByte();
-                Tasks = new List<TaskInfo>();
-                for (var i = 0; i < taskCount; i++)
-                {
-                    Tasks.Add(new TaskInfo());
-                    Tasks[i].Deserialize(reader);
-                }
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/Impostor.Server/GameData/Objects/InnerGameData.TaskInfo.cs b/src/Impostor.Server/GameData/Objects/InnerGameData.TaskInfo.cs
deleted file mode 100644 (file)
index 516a7a9..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Server.GameData.Objects
-{
-    public partial class InnerGameData
-    {
-        public class TaskInfo
-        {
-            public uint Id { get; private set; }
-
-            public bool Complete { get; private set; }
-
-            public void Serialize(IMessageWriter writer)
-            {
-                writer.WritePacked(Id);
-                writer.Write(Complete);
-            }
-
-            public void Deserialize(IMessageReader reader)
-            {
-                this.Id = reader.ReadPackedUInt32();
-                this.Complete = reader.ReadBoolean();
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/Impostor.Server/GameData/Objects/InnerGameData.cs b/src/Impostor.Server/GameData/Objects/InnerGameData.cs
deleted file mode 100644 (file)
index 3b27000..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Impostor.Api.Games;
-using Impostor.Api.Net.Messages;
-using Impostor.Server.GameData.Objects.Components;
-
-namespace Impostor.Server.GameData.Objects
-{
-    public partial class InnerGameData : InnerNetObject
-    {
-        private readonly IGame _game;
-        private readonly List<PlayerInfo> _allPlayers;
-
-        public InnerGameData(IGame game)
-        {
-            _game = game;
-            _allPlayers = new List<PlayerInfo>();
-
-            Components.Add(this);
-            Components.Add(new InnerVoteBanSystem());
-        }
-
-        public PlayerInfo GetPlayerById(byte id)
-        {
-            foreach (var player in _allPlayers)
-            {
-                if (player.PlayerId == id)
-                {
-                    return player;
-                }
-            }
-
-            return null;
-        }
-
-        public override void HandleRpc(byte callId, IMessageReader reader)
-        {
-            throw new NotImplementedException();
-        }
-
-        public override bool Serialize(IMessageWriter writer, bool initialState)
-        {
-            throw new NotImplementedException();
-        }
-
-        public override void Deserialize(IMessageReader reader, bool initialState)
-        {
-            if (initialState)
-            {
-                var num = reader.ReadPackedInt32();
-
-                for (var i = 0; i < num; i++)
-                {
-                    var playerInfo = new PlayerInfo(reader.ReadByte());
-                    playerInfo.Deserialize(reader);
-                    _allPlayers.Add(playerInfo);
-                }
-            }
-            else
-            {
-                throw new NotImplementedException("This shouldn't happen, according to Among Us assembly..");
-
-                // var num = reader.ReadByte();
-                //
-                // for (var i = 0; i < num; i++)
-                // {
-                //     var id = reader.ReadByte();
-                //     var player = GetPlayerById(id);
-                //     if (player != null)
-                //     {
-                //         player.Deserialize(reader);
-                //     }
-                //     else
-                //     {
-                //         var playerInfo = new PlayerInfo(id);
-                //         playerInfo.Deserialize(reader);
-                //         _allPlayers.Add(playerInfo);
-                //     }
-                // }
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/Impostor.Server/GameData/Objects/InnerLobbyBehaviour.cs b/src/Impostor.Server/GameData/Objects/InnerLobbyBehaviour.cs
deleted file mode 100644 (file)
index c9f96c0..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-using Impostor.Api.Games;
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Server.GameData.Objects
-{
-    public class InnerLobbyBehaviour : InnerNetObject
-    {
-        private readonly IGame _game;
-
-        public InnerLobbyBehaviour(IGame game)
-        {
-            _game = game;
-
-            Components.Add(this);
-        }
-
-        public override void HandleRpc(byte callId, IMessageReader reader)
-        {
-            throw new System.NotImplementedException();
-        }
-
-        public override bool Serialize(IMessageWriter writer, bool initialState)
-        {
-            throw new System.NotImplementedException();
-        }
-
-        public override void Deserialize(IMessageReader reader, bool initialState)
-        {
-            throw new System.NotImplementedException();
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/Impostor.Server/GameData/Objects/InnerMeetingHud.cs b/src/Impostor.Server/GameData/Objects/InnerMeetingHud.cs
deleted file mode 100644 (file)
index 7088526..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-using Impostor.Api.Games;
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Server.GameData.Objects
-{
-    public class InnerMeetingHud : InnerNetObject
-    {
-        private readonly IGame _game;
-
-        public InnerMeetingHud(IGame game)
-        {
-            _game = game;
-
-            Components.Add(this);
-        }
-
-        public override void HandleRpc(byte callId, IMessageReader reader)
-        {
-            throw new System.NotImplementedException();
-        }
-
-        public override bool Serialize(IMessageWriter writer, bool initialState)
-        {
-            throw new System.NotImplementedException();
-        }
-
-        public override void Deserialize(IMessageReader reader, bool initialState)
-        {
-            throw new System.NotImplementedException();
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/Impostor.Server/GameData/Objects/InnerPlayerControl.cs b/src/Impostor.Server/GameData/Objects/InnerPlayerControl.cs
deleted file mode 100644 (file)
index 965f8c7..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-using System;
-using Impostor.Api.Games;
-using Impostor.Api.Net.Messages;
-using Impostor.Server.GameData.Objects.Components;
-using Microsoft.Extensions.DependencyInjection;
-
-namespace Impostor.Server.GameData.Objects
-{
-    public class InnerPlayerControl : InnerNetObject
-    {
-        private readonly IGame _game;
-
-        public InnerPlayerControl(IGame game, IServiceProvider serviceProvider)
-        {
-            _game = game;
-
-            Components.Add(this);
-            Components.Add(ActivatorUtilities.CreateInstance<InnerPlayerPhysics>(serviceProvider));
-            Components.Add(ActivatorUtilities.CreateInstance<InnerCustomNetworkTransform>(serviceProvider));
-
-            PlayerId = byte.MaxValue;
-        }
-
-        public bool IsNew { get; private set; }
-
-        public byte PlayerId { get; private set; }
-
-        public override void HandleRpc(byte callId, IMessageReader reader)
-        {
-            throw new NotImplementedException();
-        }
-
-        public override bool Serialize(IMessageWriter writer, bool initialState)
-        {
-            throw new NotImplementedException();
-        }
-
-        public override void Deserialize(IMessageReader reader, bool initialState)
-        {
-            if (initialState)
-            {
-                IsNew = reader.ReadBoolean();
-            }
-
-            PlayerId = reader.ReadByte();
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/Impostor.Server/GameData/Objects/InnerShipStatus.cs b/src/Impostor.Server/GameData/Objects/InnerShipStatus.cs
deleted file mode 100644 (file)
index 00d38c4..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-using Impostor.Api.Games;
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Server.GameData.Objects
-{
-    public class InnerShipStatus : InnerNetObject
-    {
-        private readonly IGame _game;
-
-        public InnerShipStatus(IGame game)
-        {
-            _game = game;
-
-            Components.Add(this);
-        }
-
-        public override void HandleRpc(byte callId, IMessageReader reader)
-        {
-            throw new System.NotImplementedException();
-        }
-
-        public override bool Serialize(IMessageWriter writer, bool initialState)
-        {
-            throw new System.NotImplementedException();
-        }
-
-        public override void Deserialize(IMessageReader reader, bool initialState)
-        {
-            throw new System.NotImplementedException();
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/Impostor.Server/GameData/SpawnFlags.cs b/src/Impostor.Server/GameData/SpawnFlags.cs
deleted file mode 100644 (file)
index f91b378..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-
-namespace Impostor.Server.GameData
-{
-    [Flags]
-    public enum SpawnFlags : byte
-    {
-        None = 0,
-        IsClientCharacter = 1,
-    }
-}
\ No newline at end of file
index 4b6565a8875ee74cf1e840bf0f3586f5fef06b15..e59e90e65330b3dec9d97242fb3044ef4cb15950 100644 (file)
@@ -6,12 +6,12 @@ using System.Threading.Tasks;
 using Impostor.Api;
 using Impostor.Api.Innersloth.Data;
 using Impostor.Api.Innersloth.GameData;
+using Impostor.Api.Innersloth.Net;
+using Impostor.Api.Innersloth.Net.Objects;
 using Impostor.Api.Net.Messages;
 using Impostor.Api.Net.Messages.C2S;
 using Impostor.Api.Net.Messages.S2C;
 using Impostor.Hazel;
-using Impostor.Server.GameData;
-using Impostor.Server.GameData.Objects;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
 
@@ -180,7 +180,7 @@ namespace Impostor.Server.Net.State
                                 continue;
                             }
 
-                            _logger.LogTrace(
+                            _logger.LogDebug(
                                 "Spawning {0} components, SpawnFlags {1}",
                                 innerNetObject.GetType().Name,
                                 innerNetObject.SpawnFlags);
@@ -192,7 +192,7 @@ namespace Impostor.Server.Net.State
                                 obj.NetId = reader.ReadPackedUInt32();
                                 obj.OwnerId = ownerClientId;
 
-                                _logger.LogTrace(
+                                _logger.LogDebug(
                                     "- {0}, NetId {1}, OwnerId {2}",
                                     obj.GetType().Name,
                                     obj.NetId,
@@ -211,6 +211,8 @@ namespace Impostor.Server.Net.State
                                 {
                                     obj.Deserialize(readerSub, true);
                                 }
+
+                                GameNet.OnSpawn(obj);
                             }
 
                             if ((innerNetObject.SpawnFlags & SpawnFlags.IsClientCharacter) != SpawnFlags.None)
@@ -235,21 +237,30 @@ namespace Impostor.Server.Net.State
                     case GameDataTag.DespawnFlag:
                     {
                         // Only the host is allowed to despawn objects.
-                        if (!sender.IsHost)
-                        {
-                            _logger.LogWarning("Player {0} ({1}) tried to send DespawnFlag as non-host.", sender.Client.Name, sender.Client.Id);
-                            return false;
-                        }
-
                         var netId = reader.ReadPackedUInt32();
                         if (_allObjectsFast.TryGetValue(netId, out var obj))
                         {
+                            if (sender.Client.Id != obj.OwnerId && !sender.IsHost)
+                            {
+                                _logger.LogWarning(
+                                    "Player {0} ({1}) tried to send DespawnFlag for {2} but was denied.",
+                                    sender.Client.Name,
+                                    sender.Client.Id,
+                                    netId);
+                                return false;
+                            }
+
                             RemoveNetObject(obj);
-                            _logger.LogTrace("Destroyed InnerNetObject {0} ({1})", obj.GetType().Name, netId);
+                            GameNet.OnSpawn(obj);
+                            _logger.LogDebug("Destroyed InnerNetObject {0} ({1}), OwnerId {2}", obj.GetType().Name, netId, obj.OwnerId);
                         }
                         else
                         {
-                            _logger.LogWarning("Received DespawnFlag for unregistered NetId {0}.", netId);
+                            _logger.LogWarning(
+                                "Player {0} ({1}) sent DespawnFlag for unregistered NetId {2}.",
+                                sender.Client.Name,
+                                sender.Client.Id,
+                                netId);
                         }
 
                         break;
index c3283df3813fcdf77ce856904d2ad5cf1867b56a..0826ce872b810705eefbef0fcb7235933033003b 100644 (file)
@@ -51,6 +51,7 @@ namespace Impostor.Server.Net.State
             Code = code;
             HostId = -1;
             GameState = GameStates.NotStarted;
+            GameNet = new GameNet();
             Options = options;
             _clientManager = clientManager;
             _eventManager = eventManager;
@@ -67,6 +68,8 @@ namespace Impostor.Server.Net.State
 
         public GameStates GameState { get; private set; }
 
+        public GameNet GameNet { get; }
+
         public GameOptionsData Options { get; }
 
         public IDictionary<object, object> Items { get; }
index ebae6bf6cc55d8bc2f62bd8d41fd0956e50f3004..c904081610fb0f0782e10c57b47a6c3566d1f108 100644 (file)
@@ -43,7 +43,8 @@ namespace Impostor.Tools.ServerReplay
         private static async Task Main(string[] args)
         {
             Log.Logger = new LoggerConfiguration()
-                .MinimumLevel.Verbose()
+                // .MinimumLevel.Verbose()
+                .MinimumLevel.Debug()
                 .WriteTo.Console()
                 .CreateLogger();