From be5a876113d8ff4af066e3874417af85ebf97b9c Mon Sep 17 00:00:00 2001 From: AeonLucid Date: Fri, 23 Oct 2020 05:38:32 +0200 Subject: [PATCH] Implement deserialization for most GameData objects --- .../Extensions/SpanReaderExtensions.cs | 2 +- src/Impostor.Api/Games/IGame.cs | 2 + src/Impostor.Api/Innersloth/Data/GameNet.cs | 29 +++++++ src/Impostor.Api/Innersloth/Data/MapId.cs | 10 +++ .../Innersloth/GameOptionsData.cs | 3 +- .../Innersloth/Net}/GameObject.cs | 6 +- .../Innersloth/Net}/InnerNetObject.cs | 6 +- .../Components/InnerCustomNetworkTransform.cs | 3 +- .../Objects/Components/InnerPlayerPhysics.cs | 2 +- .../Objects/Components/InnerVoteBanSystem.cs | 16 ++-- .../Net}/Objects/InnerGameData.PlayerInfo.cs | 2 +- .../Net}/Objects/InnerGameData.TaskInfo.cs | 2 +- .../Innersloth/Net}/Objects/InnerGameData.cs | 10 ++- .../Net}/Objects/InnerLobbyBehaviour.cs | 2 +- .../Objects/InnerMeetingHud.PlayerVoteArea.cs | 49 +++++++++++ .../Innersloth/Net/Objects/InnerMeetingHud.cs | 78 ++++++++++++++++++ .../Net}/Objects/InnerPlayerControl.cs | 4 +- .../Innersloth/Net/Objects/InnerShipStatus.cs | 81 +++++++++++++++++++ .../Net/Objects/Systems/IActivatable.cs | 7 ++ .../Net/Objects/Systems/ISystemType.cs | 11 +++ .../Systems/ShipStatus/DoorsSystemType.cs | 61 ++++++++++++++ .../ShipStatus/HudOverrideSystemType.cs | 19 +++++ .../Systems/ShipStatus/LifeSuppSystemType.cs | 44 ++++++++++ .../Systems/ShipStatus/MedScanSystem.cs | 32 ++++++++ .../Systems/ShipStatus/ReactorSystemType.cs | 39 +++++++++ .../Systems/ShipStatus/SabotageSystemType.cs | 26 ++++++ .../ShipStatus/SecurityCameraSystemType.cs | 19 +++++ .../Systems/ShipStatus/SwitchSystem.cs | 27 +++++++ .../Net/Objects/Systems/SystemTypeHelpers.cs | 28 +++++++ .../Net/Objects/Systems/SystemTypes.cs | 31 +++++++ .../Innersloth/Net}/SpawnFlags.cs | 2 +- .../Net/Messages/C2S/Message01JoinGameC2S.cs | 1 - .../Net/Messages/C2S/Message10AlterGameC2S.cs | 3 +- src/Impostor.Api/Properties/AssemblyInfo.cs | 3 + .../GameData/Objects/InnerMeetingHud.cs | 32 -------- .../GameData/Objects/InnerShipStatus.cs | 32 -------- src/Impostor.Server/Net/State/Game.Data.cs | 35 +++++--- src/Impostor.Server/Net/State/Game.cs | 3 + src/Impostor.Tools.ServerReplay/Program.cs | 3 +- 39 files changed, 658 insertions(+), 107 deletions(-) create mode 100644 src/Impostor.Api/Innersloth/Data/GameNet.cs create mode 100644 src/Impostor.Api/Innersloth/Data/MapId.cs rename src/{Impostor.Server/GameData => Impostor.Api/Innersloth/Net}/GameObject.cs (76%) rename src/{Impostor.Server/GameData => Impostor.Api/Innersloth/Net}/InnerNetObject.cs (74%) rename src/{Impostor.Server/GameData => Impostor.Api/Innersloth/Net}/Objects/Components/InnerCustomNetworkTransform.cs (97%) rename src/{Impostor.Server/GameData => Impostor.Api/Innersloth/Net}/Objects/Components/InnerPlayerPhysics.cs (90%) rename src/{Impostor.Server/GameData => Impostor.Api/Innersloth/Net}/Objects/Components/InnerVoteBanSystem.cs (73%) rename src/{Impostor.Server/GameData => Impostor.Api/Innersloth/Net}/Objects/InnerGameData.PlayerInfo.cs (97%) rename src/{Impostor.Server/GameData => Impostor.Api/Innersloth/Net}/Objects/InnerGameData.TaskInfo.cs (92%) rename src/{Impostor.Server/GameData => Impostor.Api/Innersloth/Net}/Objects/InnerGameData.cs (89%) rename src/{Impostor.Server/GameData => Impostor.Api/Innersloth/Net}/Objects/InnerLobbyBehaviour.cs (94%) create mode 100644 src/Impostor.Api/Innersloth/Net/Objects/InnerMeetingHud.PlayerVoteArea.cs create mode 100644 src/Impostor.Api/Innersloth/Net/Objects/InnerMeetingHud.cs rename src/{Impostor.Server/GameData => Impostor.Api/Innersloth/Net}/Objects/InnerPlayerControl.cs (92%) create mode 100644 src/Impostor.Api/Innersloth/Net/Objects/InnerShipStatus.cs create mode 100644 src/Impostor.Api/Innersloth/Net/Objects/Systems/IActivatable.cs create mode 100644 src/Impostor.Api/Innersloth/Net/Objects/Systems/ISystemType.cs create mode 100644 src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/DoorsSystemType.cs create mode 100644 src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/HudOverrideSystemType.cs create mode 100644 src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/LifeSuppSystemType.cs create mode 100644 src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/MedScanSystem.cs create mode 100644 src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/ReactorSystemType.cs create mode 100644 src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/SabotageSystemType.cs create mode 100644 src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/SecurityCameraSystemType.cs create mode 100644 src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/SwitchSystem.cs create mode 100644 src/Impostor.Api/Innersloth/Net/Objects/Systems/SystemTypeHelpers.cs create mode 100644 src/Impostor.Api/Innersloth/Net/Objects/Systems/SystemTypes.cs rename src/{Impostor.Server/GameData => Impostor.Api/Innersloth/Net}/SpawnFlags.cs (76%) create mode 100644 src/Impostor.Api/Properties/AssemblyInfo.cs delete mode 100644 src/Impostor.Server/GameData/Objects/InnerMeetingHud.cs delete mode 100644 src/Impostor.Server/GameData/Objects/InnerShipStatus.cs diff --git a/src/Impostor.Api/Extensions/SpanReaderExtensions.cs b/src/Impostor.Api/Extensions/SpanReaderExtensions.cs index 97365ac..c103ee7 100644 --- a/src/Impostor.Api/Extensions/SpanReaderExtensions.cs +++ b/src/Impostor.Api/Extensions/SpanReaderExtensions.cs @@ -2,7 +2,7 @@ using System.Buffers.Binary; using System.Runtime.CompilerServices; -namespace Impostor.Api.Extensions +namespace Impostor.Api { /// /// Priovides a StreamReader-like api throught extensions diff --git a/src/Impostor.Api/Games/IGame.cs b/src/Impostor.Api/Games/IGame.cs index 17fa2b8..5dbec19 100644 --- a/src/Impostor.Api/Games/IGame.cs +++ b/src/Impostor.Api/Games/IGame.cs @@ -16,6 +16,8 @@ namespace Impostor.Api.Games GameStates GameState { get; } + GameNet GameNet { get; } + IEnumerable 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 index 0000000..2d37879 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Data/GameNet.cs @@ -0,0 +1,29 @@ +using Impostor.Api.Innersloth.Net; +using Impostor.Api.Innersloth.Net.Objects; + +namespace Impostor.Api.Innersloth.Data +{ + /// + /// Holds all data that is serialized over the network through GameData packets. + /// + 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 index 0000000..97d79d4 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Data/MapId.cs @@ -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 diff --git a/src/Impostor.Api/Innersloth/GameOptionsData.cs b/src/Impostor.Api/Innersloth/GameOptionsData.cs index e420e53..41bebff 100644 --- a/src/Impostor.Api/Innersloth/GameOptionsData.cs +++ b/src/Impostor.Api/Innersloth/GameOptionsData.cs @@ -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.Server/GameData/GameObject.cs b/src/Impostor.Api/Innersloth/Net/GameObject.cs similarity index 76% rename from src/Impostor.Server/GameData/GameObject.cs rename to src/Impostor.Api/Innersloth/Net/GameObject.cs index c78dee0..c58e4fb 100644 --- a/src/Impostor.Server/GameData/GameObject.cs +++ b/src/Impostor.Api/Innersloth/Net/GameObject.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Impostor.Server.GameData +namespace Impostor.Api.Innersloth.Net { public class GameObject { @@ -17,9 +17,9 @@ namespace Impostor.Server.GameData foreach (var component in Components) { - if (component.GetType().IsAssignableTo(typeof(T))) + if (component is T c) { - result.Add((T) component); + result.Add(c); } } diff --git a/src/Impostor.Server/GameData/InnerNetObject.cs b/src/Impostor.Api/Innersloth/Net/InnerNetObject.cs similarity index 74% rename from src/Impostor.Server/GameData/InnerNetObject.cs rename to src/Impostor.Api/Innersloth/Net/InnerNetObject.cs index d1a09e0..6e112f3 100644 --- a/src/Impostor.Server/GameData/InnerNetObject.cs +++ b/src/Impostor.Api/Innersloth/Net/InnerNetObject.cs @@ -1,12 +1,12 @@ using Impostor.Api.Net.Messages; -namespace Impostor.Server.GameData +namespace Impostor.Api.Innersloth.Net { public abstract class InnerNetObject : GameObject { - public uint NetId { get; set; } + public uint NetId { get; internal set; } - public int OwnerId { get; set; } + public int OwnerId { get; internal set; } public SpawnFlags SpawnFlags { get; internal set; } diff --git a/src/Impostor.Server/GameData/Objects/Components/InnerCustomNetworkTransform.cs b/src/Impostor.Api/Innersloth/Net/Objects/Components/InnerCustomNetworkTransform.cs similarity index 97% rename from src/Impostor.Server/GameData/Objects/Components/InnerCustomNetworkTransform.cs rename to src/Impostor.Api/Innersloth/Net/Objects/Components/InnerCustomNetworkTransform.cs index c6804ed..a8c4915 100644 --- a/src/Impostor.Server/GameData/Objects/Components/InnerCustomNetworkTransform.cs +++ b/src/Impostor.Api/Innersloth/Net/Objects/Components/InnerCustomNetworkTransform.cs @@ -1,9 +1,8 @@ using System.Numerics; -using Impostor.Api.Innersloth; using Impostor.Api.Net.Messages; using Microsoft.Extensions.Logging; -namespace Impostor.Server.GameData.Objects.Components +namespace Impostor.Api.Innersloth.Net.Objects.Components { public class InnerCustomNetworkTransform : InnerNetObject { diff --git a/src/Impostor.Server/GameData/Objects/Components/InnerPlayerPhysics.cs b/src/Impostor.Api/Innersloth/Net/Objects/Components/InnerPlayerPhysics.cs similarity index 90% rename from src/Impostor.Server/GameData/Objects/Components/InnerPlayerPhysics.cs rename to src/Impostor.Api/Innersloth/Net/Objects/Components/InnerPlayerPhysics.cs index 698f97e..7c74aaf 100644 --- a/src/Impostor.Server/GameData/Objects/Components/InnerPlayerPhysics.cs +++ b/src/Impostor.Api/Innersloth/Net/Objects/Components/InnerPlayerPhysics.cs @@ -1,6 +1,6 @@ using Impostor.Api.Net.Messages; -namespace Impostor.Server.GameData.Objects.Components +namespace Impostor.Api.Innersloth.Net.Objects.Components { public class InnerPlayerPhysics : InnerNetObject { diff --git a/src/Impostor.Server/GameData/Objects/Components/InnerVoteBanSystem.cs b/src/Impostor.Api/Innersloth/Net/Objects/Components/InnerVoteBanSystem.cs similarity index 73% rename from src/Impostor.Server/GameData/Objects/Components/InnerVoteBanSystem.cs rename to src/Impostor.Api/Innersloth/Net/Objects/Components/InnerVoteBanSystem.cs index 72253ba..ed5f29a 100644 --- a/src/Impostor.Server/GameData/Objects/Components/InnerVoteBanSystem.cs +++ b/src/Impostor.Api/Innersloth/Net/Objects/Components/InnerVoteBanSystem.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using Impostor.Api.Net.Messages; -namespace Impostor.Server.GameData.Objects.Components +namespace Impostor.Api.Innersloth.Net.Objects.Components { public class InnerVoteBanSystem : InnerNetObject { @@ -26,12 +26,16 @@ namespace Impostor.Server.GameData.Objects.Components public override void Deserialize(IMessageReader reader, bool initialState) { var votes = _votes; - var unknown = reader.ReadBoolean(); - if (unknown) + var unknown = reader.ReadByte(); + if (unknown != 0) { - while (true) + for (var i = 0; i < unknown; i++) { var v4 = reader.ReadInt32(); + if (v4 == 0) + { + break; + } if (!votes.TryGetValue(v4, out var v12)) { @@ -39,9 +43,9 @@ namespace Impostor.Server.GameData.Objects.Components votes[v4] = v12; } - for (var i = 0; i < 3; i++) + for (var j = 0; j < 3; j++) { - v12[i] = reader.ReadPackedInt32(); + v12[j] = reader.ReadPackedInt32(); } } } diff --git a/src/Impostor.Server/GameData/Objects/InnerGameData.PlayerInfo.cs b/src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.PlayerInfo.cs similarity index 97% rename from src/Impostor.Server/GameData/Objects/InnerGameData.PlayerInfo.cs rename to src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.PlayerInfo.cs index dfcdfab..b076d9e 100644 --- a/src/Impostor.Server/GameData/Objects/InnerGameData.PlayerInfo.cs +++ b/src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.PlayerInfo.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using Impostor.Api.Net.Messages; -namespace Impostor.Server.GameData.Objects +namespace Impostor.Api.Innersloth.Net.Objects { public partial class InnerGameData { diff --git a/src/Impostor.Server/GameData/Objects/InnerGameData.TaskInfo.cs b/src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.TaskInfo.cs similarity index 92% rename from src/Impostor.Server/GameData/Objects/InnerGameData.TaskInfo.cs rename to src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.TaskInfo.cs index 516a7a9..d1ef9f2 100644 --- a/src/Impostor.Server/GameData/Objects/InnerGameData.TaskInfo.cs +++ b/src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.TaskInfo.cs @@ -1,6 +1,6 @@ using Impostor.Api.Net.Messages; -namespace Impostor.Server.GameData.Objects +namespace Impostor.Api.Innersloth.Net.Objects { public partial class InnerGameData { diff --git a/src/Impostor.Server/GameData/Objects/InnerGameData.cs b/src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.cs similarity index 89% rename from src/Impostor.Server/GameData/Objects/InnerGameData.cs rename to src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.cs index 3b27000..5d07e10 100644 --- a/src/Impostor.Server/GameData/Objects/InnerGameData.cs +++ b/src/Impostor.Api/Innersloth/Net/Objects/InnerGameData.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; using Impostor.Api.Games; +using Impostor.Api.Innersloth.Net.Objects.Components; using Impostor.Api.Net.Messages; -using Impostor.Server.GameData.Objects.Components; -namespace Impostor.Server.GameData.Objects +namespace Impostor.Api.Innersloth.Net.Objects { public partial class InnerGameData : InnerNetObject { @@ -20,6 +20,10 @@ namespace Impostor.Server.GameData.Objects Components.Add(new InnerVoteBanSystem()); } + public int PlayerCount => _allPlayers.Count; + + public IReadOnlyList Players => _allPlayers; + public PlayerInfo GetPlayerById(byte id) { foreach (var player in _allPlayers) @@ -58,7 +62,7 @@ namespace Impostor.Server.GameData.Objects } else { - throw new NotImplementedException("This shouldn't happen, according to Among Us assembly.."); + throw new NotImplementedException("This shouldn't happen, according to Among Us disassembly.."); // var num = reader.ReadByte(); // diff --git a/src/Impostor.Server/GameData/Objects/InnerLobbyBehaviour.cs b/src/Impostor.Api/Innersloth/Net/Objects/InnerLobbyBehaviour.cs similarity index 94% rename from src/Impostor.Server/GameData/Objects/InnerLobbyBehaviour.cs rename to src/Impostor.Api/Innersloth/Net/Objects/InnerLobbyBehaviour.cs index c9f96c0..7b73ed2 100644 --- a/src/Impostor.Server/GameData/Objects/InnerLobbyBehaviour.cs +++ b/src/Impostor.Api/Innersloth/Net/Objects/InnerLobbyBehaviour.cs @@ -1,7 +1,7 @@ using Impostor.Api.Games; using Impostor.Api.Net.Messages; -namespace Impostor.Server.GameData.Objects +namespace Impostor.Api.Innersloth.Net.Objects { public class InnerLobbyBehaviour : InnerNetObject { 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 index 0000000..82f0ef6 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Net/Objects/InnerMeetingHud.PlayerVoteArea.cs @@ -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 index 0000000..816fe6f --- /dev/null +++ b/src/Impostor.Api/Innersloth/Net/Objects/InnerMeetingHud.cs @@ -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.Server/GameData/Objects/InnerPlayerControl.cs b/src/Impostor.Api/Innersloth/Net/Objects/InnerPlayerControl.cs similarity index 92% rename from src/Impostor.Server/GameData/Objects/InnerPlayerControl.cs rename to src/Impostor.Api/Innersloth/Net/Objects/InnerPlayerControl.cs index 965f8c7..fd9a609 100644 --- a/src/Impostor.Server/GameData/Objects/InnerPlayerControl.cs +++ b/src/Impostor.Api/Innersloth/Net/Objects/InnerPlayerControl.cs @@ -1,10 +1,10 @@ using System; using Impostor.Api.Games; +using Impostor.Api.Innersloth.Net.Objects.Components; using Impostor.Api.Net.Messages; -using Impostor.Server.GameData.Objects.Components; using Microsoft.Extensions.DependencyInjection; -namespace Impostor.Server.GameData.Objects +namespace Impostor.Api.Innersloth.Net.Objects { public class InnerPlayerControl : InnerNetObject { diff --git a/src/Impostor.Api/Innersloth/Net/Objects/InnerShipStatus.cs b/src/Impostor.Api/Innersloth/Net/Objects/InnerShipStatus.cs new file mode 100644 index 0000000..d16eaf5 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Net/Objects/InnerShipStatus.cs @@ -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 _systems; + + public InnerShipStatus(IGame game) + { + _game = game; + + _systems = new Dictionary + { + [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 index 0000000..eaae0a2 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Net/Objects/Systems/IActivatable.cs @@ -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 index 0000000..0b25e94 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ISystemType.cs @@ -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 index 0000000..05a2916 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/DoorsSystemType.cs @@ -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 _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(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 index 0000000..fe29bb0 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/HudOverrideSystemType.cs @@ -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 index 0000000..fd8b01a --- /dev/null +++ b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/LifeSuppSystemType.cs @@ -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(); + } + + public float Countdown { get; private set; } + + public HashSet 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 index 0000000..f93fb8e --- /dev/null +++ b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/MedScanSystem.cs @@ -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(); + } + + public List 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 index 0000000..d3f1973 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/ReactorSystemType.cs @@ -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>(); + } + + public float Countdown { get; private set; } + + public HashSet> 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(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 index 0000000..f442b91 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/SabotageSystemType.cs @@ -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 index 0000000..4e16b31 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/SecurityCameraSystemType.cs @@ -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 index 0000000..6d46d01 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Net/Objects/Systems/ShipStatus/SwitchSystem.cs @@ -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 index 0000000..46e68ff --- /dev/null +++ b/src/Impostor.Api/Innersloth/Net/Objects/Systems/SystemTypeHelpers.cs @@ -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().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 index 0000000..0ff4220 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Net/Objects/Systems/SystemTypes.cs @@ -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.Server/GameData/SpawnFlags.cs b/src/Impostor.Api/Innersloth/Net/SpawnFlags.cs similarity index 76% rename from src/Impostor.Server/GameData/SpawnFlags.cs rename to src/Impostor.Api/Innersloth/Net/SpawnFlags.cs index f91b378..0372196 100644 --- a/src/Impostor.Server/GameData/SpawnFlags.cs +++ b/src/Impostor.Api/Innersloth/Net/SpawnFlags.cs @@ -1,6 +1,6 @@ using System; -namespace Impostor.Server.GameData +namespace Impostor.Api.Innersloth.Net { [Flags] public enum SpawnFlags : byte diff --git a/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs index c713790..f121b97 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs @@ -1,5 +1,4 @@ using System; -using Impostor.Api.Extensions; namespace Impostor.Api.Net.Messages.C2S { diff --git a/src/Impostor.Api/Net/Messages/C2S/Message10AlterGameC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message10AlterGameC2S.cs index e9ad8e8..dd143c0 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message10AlterGameC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message10AlterGameC2S.cs @@ -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 index 0000000..c02e44a --- /dev/null +++ b/src/Impostor.Api/Properties/AssemblyInfo.cs @@ -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/Objects/InnerMeetingHud.cs b/src/Impostor.Server/GameData/Objects/InnerMeetingHud.cs deleted file mode 100644 index 7088526..0000000 --- a/src/Impostor.Server/GameData/Objects/InnerMeetingHud.cs +++ /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/InnerShipStatus.cs b/src/Impostor.Server/GameData/Objects/InnerShipStatus.cs deleted file mode 100644 index 00d38c4..0000000 --- a/src/Impostor.Server/GameData/Objects/InnerShipStatus.cs +++ /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/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index 4b6565a..e59e90e 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -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; diff --git a/src/Impostor.Server/Net/State/Game.cs b/src/Impostor.Server/Net/State/Game.cs index c3283df..0826ce8 100644 --- a/src/Impostor.Server/Net/State/Game.cs +++ b/src/Impostor.Server/Net/State/Game.cs @@ -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 Items { get; } diff --git a/src/Impostor.Tools.ServerReplay/Program.cs b/src/Impostor.Tools.ServerReplay/Program.cs index ebae6bf..c904081 100644 --- a/src/Impostor.Tools.ServerReplay/Program.cs +++ b/src/Impostor.Tools.ServerReplay/Program.cs @@ -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(); -- 2.39.5