From 0f6bfb3597c570d804c76ff493069db5b75385e0 Mon Sep 17 00:00:00 2001 From: js6pak Date: Wed, 24 Mar 2021 16:38:23 +0100 Subject: [PATCH] Fix warnings --- .../Events/IManualEventListener.cs | 6 +- .../Exceptions/ImpostorConfigException.cs | 6 +- .../Exceptions/ImpostorException.cs | 8 +- .../Exceptions/ImpostorProtocolException.cs | 6 +- src/Impostor.Api/Games/IGame.cs | 2 +- src/Impostor.Api/Impostor.Api.csproj | 4 +- .../Innersloth/DisconnectReason.cs | 40 ++- src/Impostor.Api/Innersloth/GameCodeParser.cs | 105 +++----- src/Impostor.Api/Innersloth/GameOverReason.cs | 4 +- src/Impostor.Api/Innersloth/RegionInfo.cs | 30 +-- src/Impostor.Api/Innersloth/ServerInfo.cs | 30 +-- src/Impostor.Api/Innersloth/SystemTypes.cs | 33 ++- src/Impostor.Api/Innersloth/TaskBarUpdate.cs | 4 +- src/Impostor.Api/Net/IConnection.cs | 3 +- src/Impostor.Api/Net/Inner/IGameNet.cs | 10 +- .../Net/Inner/Objects/IInnerShipStatus.cs | 3 +- .../Net/Inner/Objects/IInnerVoteBanSystem.cs | 3 +- src/Impostor.Api/Net/Inner/RpcCalls.cs | 4 +- src/Impostor.Api/ProjectRules.ruleset | 18 -- src/Impostor.Benchmarks/Data/MessageWriter.cs | 2 - .../Impostor.Client.App.csproj | 20 +- src/Impostor.Client/Impostor.Client.csproj | 14 +- src/Impostor.Hazel/Impostor.Hazel.csproj | 24 +- src/Impostor.Hazel/NetworkConnection.cs | 14 +- src/Impostor.Hazel/Udp/UdpServerConnection.cs | 2 +- .../Impostor.Patcher.Cli.csproj | 26 +- .../Impostor.Patcher.Shared.csproj | 14 +- .../Impostor.Patcher.WinForms.csproj | 38 +-- .../Impostor.Plugins.Debugger.csproj | 22 +- .../Impostor.Plugins.Example.csproj | 2 +- .../Config/AnnouncementsServerConfig.cs | 19 +- src/Impostor.Server/Config/DebugConfig.cs | 17 +- src/Impostor.Server/Config/ServerConfig.cs | 4 +- .../Config/ServerRedirectorConfig.cs | 31 ++- .../Config/ServerRedirectorNode.cs | 17 +- src/Impostor.Server/Events/EventHandler.cs | 8 +- src/Impostor.Server/Events/EventManager.cs | 2 +- .../Events/Game/GameEndedEvent.cs | 2 +- .../Register/IRegisteredEventListener.cs | 4 +- .../InvokedRegisteredEventListener.cs | 4 +- .../Register/ManualRegisteredEventListener.cs | 6 +- .../Register/RegisteredEventListener.cs | 88 +++---- .../WrappedRegisteredEventListener.cs | 4 +- src/Impostor.Server/Impostor.Server.csproj | 10 +- .../Net/AnnouncementsService.cs | 10 +- src/Impostor.Server/Net/Client.cs | 12 +- src/Impostor.Server/Net/ClientBase.cs | 1 - .../Net/Hazel/HazelConnection.cs | 4 +- .../Net/Inner/InnerNetObject.cs | 3 +- .../InnerCustomNetworkTransform.Api.cs | 2 +- .../Components/InnerCustomNetworkTransform.cs | 22 +- .../Net/Inner/Objects/InnerMeetingHud.Api.cs | 3 +- .../Objects/InnerMeetingHud.PlayerVoteArea.cs | 14 +- .../Net/Inner/Objects/InnerMeetingHud.cs | 31 +-- .../Inner/Objects/InnerPlayerControl.Api.cs | 4 +- .../Net/Inner/Objects/InnerPlayerControl.cs | 26 +- .../Net/Inner/Objects/InnerPlayerInfo.cs | 6 +- .../Systems/ShipStatus/DoorsSystemType.cs | 4 +- .../Net/Manager/ClientManager.cs | 4 +- .../Net/Manager/GameManager.cs | 78 +++--- src/Impostor.Server/Net/Matchmaker.cs | 15 +- .../Net/Redirector/INodeLocator.cs | 4 +- .../Net/Redirector/NodeLocatorNoOp.cs | 4 +- .../Net/Redirector/NodeLocatorRedis.cs | 4 +- .../Net/Redirector/NodeLocatorUDP.cs | 32 +-- .../Net/Redirector/NodeLocatorUDPService.cs | 2 +- src/Impostor.Server/Net/State/ClientPlayer.cs | 4 +- src/Impostor.Server/Net/State/Game.Api.cs | 2 +- src/Impostor.Server/Net/State/Game.Data.cs | 236 +++++++++--------- .../Net/State/Game.Incoming.cs | 186 +++++++------- src/Impostor.Server/Net/State/Game.State.cs | 2 +- src/Impostor.Server/Net/State/Game.cs | 21 +- src/Impostor.Server/Net/State/GameNet.Api.cs | 10 +- src/Impostor.Server/Net/State/GameNet.cs | 10 +- .../Plugins/AssemblyInformation.cs | 4 +- .../Plugins/PluginInformation.cs | 10 +- src/Impostor.Server/Plugins/PluginLoader.cs | 10 +- .../Plugins/PluginLoaderException.cs | 8 +- .../Plugins/PluginLoaderService.cs | 19 +- src/Impostor.Server/Program.cs | 4 +- src/Impostor.Server/ProjectRules.ruleset | 22 -- .../Recorder/PacketRecorder.cs | 76 +++--- .../Recorder/PacketSerializationContext.cs | 25 +- .../Recorder/RecordedPacketType.cs | 4 +- src/Impostor.Tests/Impostor.Tests.csproj | 31 +-- .../Impostor.Tools.Proxy.csproj | 26 +- .../Impostor.Tools.ServerReplay.csproj | 4 +- .../Mocks/MockHazelConnection.cs | 4 +- src/ProjectRules.ruleset | 23 ++ 89 files changed, 895 insertions(+), 844 deletions(-) delete mode 100644 src/Impostor.Api/ProjectRules.ruleset delete mode 100644 src/Impostor.Server/ProjectRules.ruleset create mode 100644 src/ProjectRules.ruleset diff --git a/src/Impostor.Api/Events/IManualEventListener.cs b/src/Impostor.Api/Events/IManualEventListener.cs index b5c140e..1b054f7 100644 --- a/src/Impostor.Api/Events/IManualEventListener.cs +++ b/src/Impostor.Api/Events/IManualEventListener.cs @@ -4,10 +4,10 @@ namespace Impostor.Api.Events { public interface IManualEventListener : IEventListener { + EventPriority Priority { get; set; } + public bool CanExecute(); public ValueTask Execute(IEvent @event); - - EventPriority Priority { get; set; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Exceptions/ImpostorConfigException.cs b/src/Impostor.Api/Exceptions/ImpostorConfigException.cs index 1e59a9b..01b20d4 100644 --- a/src/Impostor.Api/Exceptions/ImpostorConfigException.cs +++ b/src/Impostor.Api/Exceptions/ImpostorConfigException.cs @@ -9,15 +9,15 @@ namespace Impostor.Api { } - protected ImpostorConfigException(SerializationInfo info, StreamingContext context) : base(info, context) + public ImpostorConfigException(string? message) : base(message) { } - public ImpostorConfigException(string? message) : base(message) + public ImpostorConfigException(string? message, Exception? innerException) : base(message, innerException) { } - public ImpostorConfigException(string? message, Exception? innerException) : base(message, innerException) + protected ImpostorConfigException(SerializationInfo info, StreamingContext context) : base(info, context) { } } diff --git a/src/Impostor.Api/Exceptions/ImpostorException.cs b/src/Impostor.Api/Exceptions/ImpostorException.cs index 188c50e..0389194 100644 --- a/src/Impostor.Api/Exceptions/ImpostorException.cs +++ b/src/Impostor.Api/Exceptions/ImpostorException.cs @@ -9,16 +9,16 @@ namespace Impostor.Api { } - protected ImpostorException(SerializationInfo info, StreamingContext context) : base(info, context) + public ImpostorException(string? message) : base(message) { } - public ImpostorException(string? message) : base(message) + public ImpostorException(string? message, Exception? innerException) : base(message, innerException) { } - public ImpostorException(string? message, Exception? innerException) : base(message, innerException) + protected ImpostorException(SerializationInfo info, StreamingContext context) : base(info, context) { } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Exceptions/ImpostorProtocolException.cs b/src/Impostor.Api/Exceptions/ImpostorProtocolException.cs index 864602d..513e590 100644 --- a/src/Impostor.Api/Exceptions/ImpostorProtocolException.cs +++ b/src/Impostor.Api/Exceptions/ImpostorProtocolException.cs @@ -9,15 +9,15 @@ namespace Impostor.Api { } - protected ImpostorProtocolException(SerializationInfo info, StreamingContext context) : base(info, context) + public ImpostorProtocolException(string? message) : base(message) { } - public ImpostorProtocolException(string? message) : base(message) + public ImpostorProtocolException(string? message, Exception? innerException) : base(message, innerException) { } - public ImpostorProtocolException(string? message, Exception? innerException) : base(message, innerException) + protected ImpostorProtocolException(SerializationInfo info, StreamingContext context) : base(info, context) { } } diff --git a/src/Impostor.Api/Games/IGame.cs b/src/Impostor.Api/Games/IGame.cs index 57c3fcd..58e9208 100644 --- a/src/Impostor.Api/Games/IGame.cs +++ b/src/Impostor.Api/Games/IGame.cs @@ -37,7 +37,7 @@ namespace Impostor.Api.Games int HostId { get; } - IClientPlayer GetClientPlayer(int clientId); + IClientPlayer? GetClientPlayer(int clientId); T? FindObjectByNetId(uint netId) where T : IInnerNetObject; diff --git a/src/Impostor.Api/Impostor.Api.csproj b/src/Impostor.Api/Impostor.Api.csproj index 188f2a6..33c2ea0 100644 --- a/src/Impostor.Api/Impostor.Api.csproj +++ b/src/Impostor.Api/Impostor.Api.csproj @@ -2,7 +2,7 @@ netstandard2.1 - ProjectRules.ruleset + ../ProjectRules.ruleset 9 true enable @@ -33,4 +33,4 @@ - \ No newline at end of file + diff --git a/src/Impostor.Api/Innersloth/DisconnectReason.cs b/src/Impostor.Api/Innersloth/DisconnectReason.cs index 9526f58..21cdc94 100644 --- a/src/Impostor.Api/Innersloth/DisconnectReason.cs +++ b/src/Impostor.Api/Innersloth/DisconnectReason.cs @@ -3,52 +3,66 @@ public enum DisconnectReason { ExitGame = 0, + Destroy = 16, + // The game you tried to join is full. // Check with the host to see if you can join next round. GameFull = 1, + // The game you tried to join already started. // Check with the host to see if you can join next round. GameStarted = 2, - // Could not find the game you're looking for. + + // Could not find the game you're looking for.. GameMissing = 3, IncorrectGame = 18, - // For these a message can be given, specifying an empty message shows + + // For this a message can be given, specifying an empty message shows // "An unknown error disconnected you from the server." - CustomMessage1 = 4, + // 4, 12, 13, 14, 15 also count as Custom Custom = 8, - // CustomMessage3 = 11, - // CustomMessage4 = 12, - // CustomMessage5 = 13, - // CustomMessage6 = 14, - // CustomMessage7 = 15, + // You are running an older version of the game. // Please update to play with others. IncorrectVersion = 5, + + // You were banned from { GameCode ?? "the room" } // You cannot rejoin that room. - // You were banned Banned = 6, - // You can rejoin if the room hasn't started - // You were kicked + + // You were kicked from { GameCode ?? "the room" } + // You can rejoin if the room hasn't started. Kicked = 7, + // You were banned for hacking. // Please stop. Hacking = 10, - Destroy = 16, + + // GameModes.LocalGame: // You disconnected from the host. // If this happens often, check your WiFi strength. // + // GameModes.OnlineGame: // You disconnected from the server. // If this happens often, check your network strength. // This may also be a server issue. Error = 17, + // The server stopped this game. Possibly due to inactivity. ServerRequest = 19, + // The Among Us servers are overloaded. // Sorry! Please try again later! ServerFull = 20, + FocusLostBackground = 207, + + // You may not join another game for another { BanMinutesLeft } minutes after intentionally disconnecting. IntentionalLeaving = 208, + + // You were disconnected because Among Us was suspended by another app. FocusLost = 209, + NewConnection = 210, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/GameCodeParser.cs b/src/Impostor.Api/Innersloth/GameCodeParser.cs index 9717cff..f4743c5 100644 --- a/src/Impostor.Api/Innersloth/GameCodeParser.cs +++ b/src/Impostor.Api/Innersloth/GameCodeParser.cs @@ -9,36 +9,11 @@ namespace Impostor.Api.Innersloth public static class GameCodeParser { private const string V2 = "QWXRTYLPESDFGHUJKZOCVBINMA"; - private static readonly int[] V2Map = { - 25, - 21, - 19, - 10, - 8, - 11, - 12, - 13, - 22, - 15, - 16, - 6, - 24, - 23, - 18, - 7, - 0, - 3, - 9, - 4, - 14, - 20, - 1, - 2, - 5, - 17 - }; + + private static readonly int[] V2Map = Enumerable.Range(65, 26).Select(v => V2.IndexOf((char)v)).ToArray(); + private static readonly RNGCryptoServiceProvider Random = new RNGCryptoServiceProvider(); - + public static string IntToGameName(int input) { // V2. @@ -57,22 +32,6 @@ namespace Impostor.Api.Innersloth #endif } - private static string IntToGameNameV2(int input) - { - var a = input & 0x3FF; - var b = (input >> 10) & 0xFFFFF; - - return new string(new [] - { - V2[a % 26], - V2[a / 26], - V2[b % 26], - V2[b / 26 % 26], - V2[b / (26 * 26) % 26], - V2[b / (26 * 26 * 26) % 26] - }); - } - public static int GameNameToInt(string code) { var upper = code.ToUpperInvariant(); @@ -80,7 +39,7 @@ namespace Impostor.Api.Innersloth { return -1; } - + var len = code.Length; if (len == 6) { @@ -91,23 +50,8 @@ namespace Impostor.Api.Innersloth { return code[0] | ((code[1] | ((code[2] | (code[3] << 8)) << 8)) << 8); } - - return -1; - } - - private static int GameNameToIntV2(string code) - { - var a = V2Map[code[0] - 65]; - var b = V2Map[code[1] - 65]; - var c = V2Map[code[2] - 65]; - var d = V2Map[code[3] - 65]; - var e = V2Map[code[4] - 65]; - var f = V2Map[code[5] - 65]; - - var one = (a + 26 * b) & 0x3FF; - var two = (c + 26 * (d + 26 * (e + 26 * f))); - return (int) (one | ((two << 10) & 0x3FFFFC00) | 0x80000000); + return -1; } public static int GenerateCode(int len) @@ -116,7 +60,7 @@ namespace Impostor.Api.Innersloth { throw new ArgumentException("should be 4 or 6", nameof(len)); } - + // Generate random bytes. #if NETSTANDARD2_0 var data = new byte[len]; @@ -124,7 +68,7 @@ namespace Impostor.Api.Innersloth Span data = stackalloc byte[len]; #endif Random.GetBytes(data); - + // Convert to their char representation. Span dataChar = stackalloc char[len]; for (var i = 0; i < len; i++) @@ -138,5 +82,36 @@ namespace Impostor.Api.Innersloth return GameNameToInt(new string(dataChar)); #endif } + + private static string IntToGameNameV2(int input) + { + var a = input & 0x3FF; + var b = (input >> 10) & 0xFFFFF; + + return new string(new[] + { + V2[a % 26], + V2[a / 26], + V2[b % 26], + V2[(b / 26) % 26], + V2[(b / (26 * 26)) % 26], + V2[(b / (26 * 26 * 26)) % 26], + }); + } + + private static int GameNameToIntV2(string code) + { + var a = V2Map[code[0] - 65]; + var b = V2Map[code[1] - 65]; + var c = V2Map[code[2] - 65]; + var d = V2Map[code[3] - 65]; + var e = V2Map[code[4] - 65]; + var f = V2Map[code[5] - 65]; + + var one = (a + (26 * b)) & 0x3FF; + var two = c + (26 * (d + (26 * (e + (26 * f))))); + + return (int)(one | ((two << 10) & 0x3FFFFC00) | 0x80000000); + } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/GameOverReason.cs b/src/Impostor.Api/Innersloth/GameOverReason.cs index 6a95d37..5c30036 100644 --- a/src/Impostor.Api/Innersloth/GameOverReason.cs +++ b/src/Impostor.Api/Innersloth/GameOverReason.cs @@ -7,9 +7,7 @@ ImpostorByVote = 2, ImpostorByKill = 3, ImpostorBySabotage = 4, - - // Unused (?) ImpostorDisconnect = 5, HumansDisconnect = 6, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/RegionInfo.cs b/src/Impostor.Api/Innersloth/RegionInfo.cs index c78978b..51580db 100644 --- a/src/Impostor.Api/Innersloth/RegionInfo.cs +++ b/src/Impostor.Api/Innersloth/RegionInfo.cs @@ -13,21 +13,10 @@ namespace Impostor.Api.Innersloth } public string Name { get; } - public string Ping { get; } - public IReadOnlyList Servers { get; } - public void Serialize(BinaryWriter writer) - { - writer.Write(0); - writer.Write(Name); - writer.Write(Ping); - writer.Write(Servers.Count); + public string Ping { get; } - foreach (var server in Servers) - { - server.Serialize(writer); - } - } + public IReadOnlyList Servers { get; } public static RegionInfo Deserialize(BinaryReader reader) { @@ -44,5 +33,18 @@ namespace Impostor.Api.Innersloth return new RegionInfo(name, ping, servers); } + + public void Serialize(BinaryWriter writer) + { + writer.Write(0); + writer.Write(Name); + writer.Write(Ping); + writer.Write(Servers.Count); + + foreach (var server in Servers) + { + server.Serialize(writer); + } + } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/ServerInfo.cs b/src/Impostor.Api/Innersloth/ServerInfo.cs index 7785823..21ba1ea 100644 --- a/src/Impostor.Api/Innersloth/ServerInfo.cs +++ b/src/Impostor.Api/Innersloth/ServerInfo.cs @@ -5,24 +5,18 @@ namespace Impostor.Api.Innersloth { public class ServerInfo { - public string Name { get; } - public string Ip { get; } - public ushort Port { get; } - public ServerInfo(string name, string ip, ushort port) { Name = name; Ip = ip; Port = port; } - - public void Serialize(BinaryWriter writer) - { - writer.Write(Name); - writer.Write(IPAddress.Parse(Ip).GetAddressBytes()); - writer.Write(Port); - writer.Write(0); - } + + public string Name { get; } + + public string Ip { get; } + + public ushort Port { get; } public static ServerInfo Deserialize(BinaryReader reader) { @@ -30,8 +24,16 @@ namespace Impostor.Api.Innersloth var ip = new IPAddress(reader.ReadBytes(4)).ToString(); var port = reader.ReadUInt16(); var unknown = reader.ReadInt32(); - + return new ServerInfo(name, ip, port); } + + public void Serialize(BinaryWriter writer) + { + writer.Write(Name); + writer.Write(IPAddress.Parse(Ip).GetAddressBytes()); + writer.Write(Port); + writer.Write(0); + } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/SystemTypes.cs b/src/Impostor.Api/Innersloth/SystemTypes.cs index 7f91718..5de8bc9 100644 --- a/src/Impostor.Api/Innersloth/SystemTypes.cs +++ b/src/Impostor.Api/Innersloth/SystemTypes.cs @@ -3,40 +3,69 @@ public enum SystemTypes : byte { Hallway = 0, + Storage = 1, + Cafeteria = 2, + Reactor = 3, + UpperEngine = 4, + Nav = 5, + Admin = 6, + Electrical = 7, + LifeSupp = 8, + Shields = 9, + MedBay = 10, + Security = 11, + Weapons = 12, + LowerEngine = 13, + Comms = 14, + ShipTasks = 15, + Doors = 16, + Sabotage = 17, + /// /// Decontam on Mira and bottom decontam on Polus /// Decontamination = 18, + Launchpad = 19, + LockerRoom = 20, + Laboratory = 21, + Balcony = 22, + Office = 23, + Greenhouse = 24, + Dropship = 25, + /// /// Top decontam on Polus /// Decontamination2 = 26, + Outside = 27, + Specimens = 28, - BoilerRoom = 29 + + BoilerRoom = 29, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/TaskBarUpdate.cs b/src/Impostor.Api/Innersloth/TaskBarUpdate.cs index f4d7c1f..ea9a5fc 100644 --- a/src/Impostor.Api/Innersloth/TaskBarUpdate.cs +++ b/src/Impostor.Api/Innersloth/TaskBarUpdate.cs @@ -4,6 +4,6 @@ { Always = 0, Meetings = 1, - Never = 2 + Never = 2, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/IConnection.cs b/src/Impostor.Api/Net/IConnection.cs index 94f9b8b..fa99841 100644 --- a/src/Impostor.Api/Net/IConnection.cs +++ b/src/Impostor.Api/Net/IConnection.cs @@ -2,6 +2,5 @@ { public interface IConnection { - } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Inner/IGameNet.cs b/src/Impostor.Api/Net/Inner/IGameNet.cs index 933a4de..9cac0f2 100644 --- a/src/Impostor.Api/Net/Inner/IGameNet.cs +++ b/src/Impostor.Api/Net/Inner/IGameNet.cs @@ -7,12 +7,12 @@ namespace Impostor.Api.Net.Inner /// public interface IGameNet { - IInnerLobbyBehaviour LobbyBehaviour { get; } + IInnerLobbyBehaviour? LobbyBehaviour { get; } - IInnerGameData GameData { get; } + IInnerGameData? GameData { get; } - IInnerVoteBanSystem VoteBan { get; } + IInnerVoteBanSystem? VoteBan { get; } - IInnerShipStatus ShipStatus { get; } + IInnerShipStatus? ShipStatus { get; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Inner/Objects/IInnerShipStatus.cs b/src/Impostor.Api/Net/Inner/Objects/IInnerShipStatus.cs index c0a05ae..79b9f96 100644 --- a/src/Impostor.Api/Net/Inner/Objects/IInnerShipStatus.cs +++ b/src/Impostor.Api/Net/Inner/Objects/IInnerShipStatus.cs @@ -2,6 +2,5 @@ { public interface IInnerShipStatus : IInnerNetObject { - } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Inner/Objects/IInnerVoteBanSystem.cs b/src/Impostor.Api/Net/Inner/Objects/IInnerVoteBanSystem.cs index d0a816d..8d8b4ac 100644 --- a/src/Impostor.Api/Net/Inner/Objects/IInnerVoteBanSystem.cs +++ b/src/Impostor.Api/Net/Inner/Objects/IInnerVoteBanSystem.cs @@ -2,6 +2,5 @@ { public interface IInnerVoteBanSystem : IInnerNetObject { - } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Inner/RpcCalls.cs b/src/Impostor.Api/Net/Inner/RpcCalls.cs index f82d2e8..e75f80e 100644 --- a/src/Impostor.Api/Net/Inner/RpcCalls.cs +++ b/src/Impostor.Api/Net/Inner/RpcCalls.cs @@ -33,6 +33,6 @@ RepairSystem = 28, SetTasks = 29, UpdateGameData = 30, - CustomRpc = byte.MaxValue + CustomRpc = byte.MaxValue, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/ProjectRules.ruleset b/src/Impostor.Api/ProjectRules.ruleset deleted file mode 100644 index 51021f5..0000000 --- a/src/Impostor.Api/ProjectRules.ruleset +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Impostor.Benchmarks/Data/MessageWriter.cs b/src/Impostor.Benchmarks/Data/MessageWriter.cs index 94ff441..42f452a 100644 --- a/src/Impostor.Benchmarks/Data/MessageWriter.cs +++ b/src/Impostor.Benchmarks/Data/MessageWriter.cs @@ -9,8 +9,6 @@ namespace Impostor.Benchmarks.Data { public class MessageWriter { - private static int BufferSize = 64000; - public MessageType SendOption { get; private set; } private Stack messageStarts = new Stack(); diff --git a/src/Impostor.Client.App/Impostor.Client.App.csproj b/src/Impostor.Client.App/Impostor.Client.App.csproj index 886e26e..3e5adc8 100644 --- a/src/Impostor.Client.App/Impostor.Client.App.csproj +++ b/src/Impostor.Client.App/Impostor.Client.App.csproj @@ -1,16 +1,16 @@ - - Exe - net5.0 - + + Exe + net5.0 + - - - + + + - - - + + + diff --git a/src/Impostor.Client/Impostor.Client.csproj b/src/Impostor.Client/Impostor.Client.csproj index 28b6ed3..cbde5b6 100644 --- a/src/Impostor.Client/Impostor.Client.csproj +++ b/src/Impostor.Client/Impostor.Client.csproj @@ -1,12 +1,12 @@ - - net5.0 - + + net5.0 + - - - - + + + + diff --git a/src/Impostor.Hazel/Impostor.Hazel.csproj b/src/Impostor.Hazel/Impostor.Hazel.csproj index 0099769..7ab52af 100644 --- a/src/Impostor.Hazel/Impostor.Hazel.csproj +++ b/src/Impostor.Hazel/Impostor.Hazel.csproj @@ -1,18 +1,18 @@ - - true - net5.0 - HAZEL_BAG - + + true + net5.0 + HAZEL_BAG + - - - - + + + + - - - + + + diff --git a/src/Impostor.Hazel/NetworkConnection.cs b/src/Impostor.Hazel/NetworkConnection.cs index 282fe10..9e81c5c 100644 --- a/src/Impostor.Hazel/NetworkConnection.cs +++ b/src/Impostor.Hazel/NetworkConnection.cs @@ -37,15 +37,11 @@ namespace Impostor.Hazel public long GetIP4Address() { - if (IPMode == IPMode.IPv4) - { - return ((IPEndPoint)this.RemoteEndPoint).Address.Address; - } - else - { - var bytes = ((IPEndPoint)this.RemoteEndPoint).Address.GetAddressBytes(); - return BitConverter.ToInt64(bytes, bytes.Length - 8); - } + var bytes = this.RemoteEndPoint.Address.GetAddressBytes(); + + return IPMode == IPMode.IPv4 + ? (uint)((bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0]) & 0x0FFFFFFFF) + : BitConverter.ToInt64(bytes, bytes.Length - 8); } /// diff --git a/src/Impostor.Hazel/Udp/UdpServerConnection.cs b/src/Impostor.Hazel/Udp/UdpServerConnection.cs index 22eed98..8d3426e 100644 --- a/src/Impostor.Hazel/Udp/UdpServerConnection.cs +++ b/src/Impostor.Hazel/Udp/UdpServerConnection.cs @@ -88,7 +88,7 @@ namespace Impostor.Hazel.Udp if (disposing) { - SendDisconnect(); + _ = SendDisconnect(); } base.Dispose(disposing); diff --git a/src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj b/src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj index c59fa87..7835c4f 100644 --- a/src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj +++ b/src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj @@ -1,19 +1,19 @@ - - Impostor.Cli - net5.0 - win-x64;linux-x64;linux-arm;linux-arm64;osx-x64 - Exe - true - + + Impostor.Cli + net5.0 + win-x64;linux-x64;linux-arm;linux-arm64;osx-x64 + Exe + true + - - - + + + - - - + + + diff --git a/src/Impostor.Patcher/Impostor.Patcher.Shared/Impostor.Patcher.Shared.csproj b/src/Impostor.Patcher/Impostor.Patcher.Shared/Impostor.Patcher.Shared.csproj index 8d71e56..3039810 100644 --- a/src/Impostor.Patcher/Impostor.Patcher.Shared/Impostor.Patcher.Shared.csproj +++ b/src/Impostor.Patcher/Impostor.Patcher.Shared/Impostor.Patcher.Shared.csproj @@ -1,11 +1,11 @@ - - netstandard2.0;netstandard2.1 - + + netstandard2.0;netstandard2.1 + + + + + - - - - diff --git a/src/Impostor.Patcher/Impostor.Patcher.WinForms/Impostor.Patcher.WinForms.csproj b/src/Impostor.Patcher/Impostor.Patcher.WinForms/Impostor.Patcher.WinForms.csproj index 7149436..83f6e26 100644 --- a/src/Impostor.Patcher/Impostor.Patcher.WinForms/Impostor.Patcher.WinForms.csproj +++ b/src/Impostor.Patcher/Impostor.Patcher.WinForms/Impostor.Patcher.WinForms.csproj @@ -1,22 +1,22 @@  - - - Impostor - {804CF172-0C87-4423-9688-BD97D549891E} - WinExe - net472 - true - Copyright © AeonLucid 2020 - icon.ico - true - true - - - - - - - + + Impostor + {804CF172-0C87-4423-9688-BD97D549891E} + WinExe + net472 + true + Copyright © AeonLucid 2020 + icon.ico + true + true + - \ No newline at end of file + + + + + + + + diff --git a/src/Impostor.Plugins.Debugger/Impostor.Plugins.Debugger.csproj b/src/Impostor.Plugins.Debugger/Impostor.Plugins.Debugger.csproj index 9518e48..8fce4f8 100644 --- a/src/Impostor.Plugins.Debugger/Impostor.Plugins.Debugger.csproj +++ b/src/Impostor.Plugins.Debugger/Impostor.Plugins.Debugger.csproj @@ -1,16 +1,16 @@  - - net5.0 - Library - + + net5.0 + Library + - - - + + + - - - + + + - \ No newline at end of file + diff --git a/src/Impostor.Plugins.Example/Impostor.Plugins.Example.csproj b/src/Impostor.Plugins.Example/Impostor.Plugins.Example.csproj index dd4724d..f0ebef3 100644 --- a/src/Impostor.Plugins.Example/Impostor.Plugins.Example.csproj +++ b/src/Impostor.Plugins.Example/Impostor.Plugins.Example.csproj @@ -3,7 +3,7 @@ netstandard2.1 - + diff --git a/src/Impostor.Server/Config/AnnouncementsServerConfig.cs b/src/Impostor.Server/Config/AnnouncementsServerConfig.cs index 5d61ac0..3ea3eb3 100644 --- a/src/Impostor.Server/Config/AnnouncementsServerConfig.cs +++ b/src/Impostor.Server/Config/AnnouncementsServerConfig.cs @@ -1,18 +1,27 @@ -using Impostor.Server.Utils; +using System.Text.Json.Serialization; +using Impostor.Server.Utils; namespace Impostor.Server.Config { internal class AnnouncementsServerConfig { + public const string Section = "AnnouncementsServer"; + private string? _resolvedListenIp; - public const string Section = "AnnouncementsServer"; + [JsonConstructor] + public AnnouncementsServerConfig(bool enabled = true, string listenIp = "0.0.0.0", ushort listenPort = 22024) + { + Enabled = enabled; + ListenIp = listenIp; + ListenPort = listenPort; + } - public bool Enabled { get; set; } = true; + public bool Enabled { get; } - public string ListenIp { get; set; } = "0.0.0.0"; + public string ListenIp { get; } - public ushort ListenPort { get; set; } = 22024; + public ushort ListenPort { get; } public string ResolveListenIp() { diff --git a/src/Impostor.Server/Config/DebugConfig.cs b/src/Impostor.Server/Config/DebugConfig.cs index 630d1b4..ef37d39 100644 --- a/src/Impostor.Server/Config/DebugConfig.cs +++ b/src/Impostor.Server/Config/DebugConfig.cs @@ -1,11 +1,20 @@ -namespace Impostor.Server.Config +using System.Text.Json.Serialization; + +namespace Impostor.Server.Config { public class DebugConfig { public const string Section = "Debug"; - public bool GameRecorderEnabled { get; set; } + [JsonConstructor] + public DebugConfig(bool gameRecorderEnabled = false, string? gameRecorderPath = null) + { + GameRecorderEnabled = gameRecorderEnabled; + GameRecorderPath = gameRecorderPath; + } + + public bool GameRecorderEnabled { get; } - public string GameRecorderPath { get; set; } + public string? GameRecorderPath { get; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Config/ServerConfig.cs b/src/Impostor.Server/Config/ServerConfig.cs index 1c58433..7ed3ae6 100644 --- a/src/Impostor.Server/Config/ServerConfig.cs +++ b/src/Impostor.Server/Config/ServerConfig.cs @@ -4,11 +4,11 @@ namespace Impostor.Server.Config { internal class ServerConfig { + public const string Section = "Server"; + private string? _resolvedPublicIp; private string? _resolvedListenIp; - public const string Section = "Server"; - public string PublicIp { get; set; } = "127.0.0.1"; public ushort PublicPort { get; set; } = 22023; diff --git a/src/Impostor.Server/Config/ServerRedirectorConfig.cs b/src/Impostor.Server/Config/ServerRedirectorConfig.cs index 0ccfa0d..63285ad 100644 --- a/src/Impostor.Server/Config/ServerRedirectorConfig.cs +++ b/src/Impostor.Server/Config/ServerRedirectorConfig.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Text.Json.Serialization; namespace Impostor.Server.Config { @@ -6,19 +7,35 @@ namespace Impostor.Server.Config { public const string Section = "ServerRedirector"; - public bool Enabled { get; set; } + [JsonConstructor] + public ServerRedirectorConfig(bool enabled = false, bool master = false, NodeLocator? locator = null, List? nodes = null) + { + Enabled = enabled; + Master = master; + Locator = locator; + Nodes = nodes; + } - public bool Master { get; set; } + public bool Enabled { get; } - public NodeLocator Locator { get; set; } + public bool Master { get; } - public List Nodes { get; set; } + public NodeLocator? Locator { get; } + + public List? Nodes { get; } public class NodeLocator { - public string Redis { get; set; } + [JsonConstructor] + public NodeLocator(string redis, string udpMasterEndpoint) + { + Redis = redis; + UdpMasterEndpoint = udpMasterEndpoint; + } + + public string Redis { get; } - public string UdpMasterEndpoint { get; set; } + public string UdpMasterEndpoint { get; } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Config/ServerRedirectorNode.cs b/src/Impostor.Server/Config/ServerRedirectorNode.cs index d11b60f..c5752bf 100644 --- a/src/Impostor.Server/Config/ServerRedirectorNode.cs +++ b/src/Impostor.Server/Config/ServerRedirectorNode.cs @@ -1,9 +1,18 @@ -namespace Impostor.Server.Config +using System.Text.Json.Serialization; + +namespace Impostor.Server.Config { public class ServerRedirectorNode { - public string Ip { get; set; } + [JsonConstructor] + public ServerRedirectorNode(string ip, ushort port) + { + Ip = ip; + Port = port; + } + + public string Ip { get; } - public ushort Port { get; set; } + public ushort Port { get; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Events/EventHandler.cs b/src/Impostor.Server/Events/EventHandler.cs index 190f7f3..e185c9a 100644 --- a/src/Impostor.Server/Events/EventHandler.cs +++ b/src/Impostor.Server/Events/EventHandler.cs @@ -5,20 +5,20 @@ namespace Impostor.Server.Events { internal readonly struct EventHandler { - public EventHandler(IEventListener o, IRegisteredEventListener listener) + public EventHandler(IEventListener? o, IRegisteredEventListener listener) { Object = o; Listener = listener; } - public IEventListener Object { get; } + public IEventListener? Object { get; } public IRegisteredEventListener Listener { get; } - public void Deconstruct(out IEventListener o, out IRegisteredEventListener listener) + public void Deconstruct(out IEventListener? o, out IRegisteredEventListener listener) { o = Object; listener = Listener; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Events/EventManager.cs b/src/Impostor.Server/Events/EventManager.cs index 0cc6e54..4ab2d15 100644 --- a/src/Impostor.Server/Events/EventManager.cs +++ b/src/Impostor.Server/Events/EventManager.cs @@ -27,7 +27,7 @@ namespace Impostor.Server.Events } /// - public IDisposable RegisterListener(TListener listener, Func, Task> invoker = null) + public IDisposable RegisterListener(TListener listener, Func, Task>? invoker = null) where TListener : IEventListener { if (listener == null) diff --git a/src/Impostor.Server/Events/Game/GameEndedEvent.cs b/src/Impostor.Server/Events/Game/GameEndedEvent.cs index 4ec4dcf..b0704cf 100644 --- a/src/Impostor.Server/Events/Game/GameEndedEvent.cs +++ b/src/Impostor.Server/Events/Game/GameEndedEvent.cs @@ -13,7 +13,7 @@ namespace Impostor.Server.Events } public IGame Game { get; } - + public GameOverReason GameOverReason { get; } } } diff --git a/src/Impostor.Server/Events/Register/IRegisteredEventListener.cs b/src/Impostor.Server/Events/Register/IRegisteredEventListener.cs index 479a3f6..3b39bc9 100644 --- a/src/Impostor.Server/Events/Register/IRegisteredEventListener.cs +++ b/src/Impostor.Server/Events/Register/IRegisteredEventListener.cs @@ -10,6 +10,6 @@ namespace Impostor.Server.Events.Register EventPriority Priority { get; } - ValueTask InvokeAsync(object eventHandler, object @event, IServiceProvider provider); + ValueTask InvokeAsync(object? eventHandler, object @event, IServiceProvider provider); } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Events/Register/InvokedRegisteredEventListener.cs b/src/Impostor.Server/Events/Register/InvokedRegisteredEventListener.cs index a21c3b1..adec183 100644 --- a/src/Impostor.Server/Events/Register/InvokedRegisteredEventListener.cs +++ b/src/Impostor.Server/Events/Register/InvokedRegisteredEventListener.cs @@ -19,9 +19,9 @@ namespace Impostor.Server.Events.Register public EventPriority Priority => _innerObject.Priority; - public ValueTask InvokeAsync(object eventHandler, object @event, IServiceProvider provider) + public ValueTask InvokeAsync(object? eventHandler, object @event, IServiceProvider provider) { return new ValueTask(_invoker(() => _innerObject.InvokeAsync(eventHandler, @event, provider).AsTask())); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Events/Register/ManualRegisteredEventListener.cs b/src/Impostor.Server/Events/Register/ManualRegisteredEventListener.cs index e81e8f8..394f47d 100644 --- a/src/Impostor.Server/Events/Register/ManualRegisteredEventListener.cs +++ b/src/Impostor.Server/Events/Register/ManualRegisteredEventListener.cs @@ -6,8 +6,6 @@ namespace Impostor.Server.Events.Register { internal class ManualRegisteredEventListener : IRegisteredEventListener { - public Type EventType { get; } = typeof(object); - private readonly IManualEventListener _manualEventListener; public ManualRegisteredEventListener(IManualEventListener manualEventListener) @@ -15,9 +13,11 @@ namespace Impostor.Server.Events.Register _manualEventListener = manualEventListener; } + public Type EventType { get; } = typeof(object); + public EventPriority Priority => _manualEventListener.Priority; - public ValueTask InvokeAsync(object eventHandler, object @event, IServiceProvider provider) + public ValueTask InvokeAsync(object? eventHandler, object @event, IServiceProvider provider) { if (@event is IEvent typedEvent) { diff --git a/src/Impostor.Server/Events/Register/RegisteredEventListener.cs b/src/Impostor.Server/Events/Register/RegisteredEventListener.cs index 120a45e..6517aac 100644 --- a/src/Impostor.Server/Events/Register/RegisteredEventListener.cs +++ b/src/Impostor.Server/Events/Register/RegisteredEventListener.cs @@ -15,7 +15,7 @@ namespace Impostor.Server.Events.Register private static readonly PropertyInfo IsCancelledProperty = typeof(IEventCancelable).GetProperty(nameof(IEventCancelable.IsCancelled))!; private static readonly ConcurrentDictionary Instances = new ConcurrentDictionary(); - private readonly Func _invoker; + private readonly Func _invoker; private readonly Type _eventListenerType; public RegisteredEventListener(Type eventType, MethodInfo method, EventListenerAttribute attribute, Type eventListenerType) @@ -38,12 +38,52 @@ namespace Impostor.Server.Events.Register public string Method { get; } - public ValueTask InvokeAsync(object eventHandler, object @event, IServiceProvider provider) + public static IReadOnlyList FromType(Type type) + { + return Instances.GetOrAdd(type, t => + { + return t.GetMethods() + .Where(m => !m.IsStatic && m.GetCustomAttributes(typeof(EventListenerAttribute), false).Any()) + .SelectMany(m => FromMethod(t, m)) + .ToArray(); + }); + } + + public static IEnumerable FromMethod(Type listenerType, MethodInfo methodType) + { + // Get the return type. + var returnType = methodType.ReturnType; + + if (returnType != typeof(void) && returnType != typeof(ValueTask)) + { + throw new InvalidOperationException($"The method {methodType.GetFriendlyName()} does not return void or ValueTask."); + } + + // Register the event. + foreach (var attribute in methodType.GetCustomAttributes(false)) + { + var eventType = attribute.Event; + + if (eventType == null) + { + if (methodType.GetParameters().Length == 0 || !typeof(IEvent).IsAssignableFrom(methodType.GetParameters()[0].ParameterType)) + { + throw new InvalidOperationException($"The first parameter of the method {methodType.GetFriendlyName()} should be the type {nameof(IEvent)}."); + } + + eventType = methodType.GetParameters()[0].ParameterType; + } + + yield return new RegisteredEventListener(eventType, methodType, attribute, listenerType); + } + } + + public ValueTask InvokeAsync(object? eventHandler, object @event, IServiceProvider provider) { return _invoker(eventHandler, @event, provider); } - private Func CreateInvoker(MethodInfo method, bool ignoreCancelled) + private Func CreateInvoker(MethodInfo method, bool ignoreCancelled) { var instance = Expression.Parameter(typeof(object), "instance"); var eventParameter = Expression.Parameter(typeof(object), "event"); @@ -119,48 +159,8 @@ namespace Impostor.Server.Events.Register throw new InvalidOperationException($"The method {method.GetFriendlyName()} must return void or ValueTask."); } - return Expression.Lambda>(invoke, instance, eventParameter, provider) + return Expression.Lambda>(invoke, instance, eventParameter, provider) .Compile(); } - - public static IReadOnlyList FromType(Type type) - { - return Instances.GetOrAdd(type, t => - { - return t.GetMethods() - .Where(m => !m.IsStatic && m.GetCustomAttributes(typeof(EventListenerAttribute), false).Any()) - .SelectMany(m => FromMethod(t, m)) - .ToArray(); - }); - } - - public static IEnumerable FromMethod(Type listenerType, MethodInfo methodType) - { - // Get the return type. - var returnType = methodType.ReturnType; - - if (returnType != typeof(void) && returnType != typeof(ValueTask)) - { - throw new InvalidOperationException($"The method {methodType.GetFriendlyName()} does not return void or ValueTask."); - } - - // Register the event. - foreach (var attribute in methodType.GetCustomAttributes(false)) - { - var eventType = attribute.Event; - - if (eventType == null) - { - if (methodType.GetParameters().Length == 0 || !typeof(IEvent).IsAssignableFrom(methodType.GetParameters()[0].ParameterType)) - { - throw new InvalidOperationException($"The first parameter of the method {methodType.GetFriendlyName()} should be the type {nameof(IEvent)}."); - } - - eventType = methodType.GetParameters()[0].ParameterType; - } - - yield return new RegisteredEventListener(eventType, methodType, attribute, listenerType); - } - } } } diff --git a/src/Impostor.Server/Events/Register/WrappedRegisteredEventListener.cs b/src/Impostor.Server/Events/Register/WrappedRegisteredEventListener.cs index dd668c5..d1a66ee 100644 --- a/src/Impostor.Server/Events/Register/WrappedRegisteredEventListener.cs +++ b/src/Impostor.Server/Events/Register/WrappedRegisteredEventListener.cs @@ -19,9 +19,9 @@ namespace Impostor.Server.Events.Register public EventPriority Priority => _innerObject.Priority; - public ValueTask InvokeAsync(object eventHandler, object @event, IServiceProvider provider) + public ValueTask InvokeAsync(object? eventHandler, object @event, IServiceProvider provider) { return _innerObject.InvokeAsync(_object, @event, provider); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Impostor.Server.csproj b/src/Impostor.Server/Impostor.Server.csproj index 663f7af..5cad72d 100644 --- a/src/Impostor.Server/Impostor.Server.csproj +++ b/src/Impostor.Server/Impostor.Server.csproj @@ -6,7 +6,7 @@ win-x64;linux-x64;linux-arm;linux-arm64;osx-x64 true icon.ico - ProjectRules.ruleset + ../ProjectRules.ruleset enable false @@ -24,13 +24,13 @@ - + - - + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Impostor.Server/Net/AnnouncementsService.cs b/src/Impostor.Server/Net/AnnouncementsService.cs index a58abf2..6ca0bb9 100644 --- a/src/Impostor.Server/Net/AnnouncementsService.cs +++ b/src/Impostor.Server/Net/AnnouncementsService.cs @@ -24,7 +24,7 @@ namespace Impostor.Server.Net private readonly AnnouncementsServerConfig _config; private readonly ObjectPool _readerPool; private readonly IEventManager _eventManager; - private UdpConnectionListener _connection; + private UdpConnectionListener? _connection; public AnnouncementsService(ILogger logger, IOptions config, ObjectPool readerPool, IEventManager eventManager) { @@ -42,7 +42,7 @@ namespace Impostor.Server.Net { AddressFamily.InterNetwork => IPMode.IPv4, AddressFamily.InterNetworkV6 => IPMode.IPv6, - _ => throw new InvalidOperationException() + _ => throw new InvalidOperationException(), }; _connection = new UdpConnectionListener(endpoint, _readerPool, mode) @@ -58,7 +58,11 @@ namespace Impostor.Server.Net public async Task StopAsync(CancellationToken cancellationToken) { _logger.LogWarning("Announcements server is shutting down!"); - await _connection.DisposeAsync(); + + if (_connection != null) + { + await _connection.DisposeAsync(); + } } private async ValueTask OnNewConnection(NewConnectionEventArgs e) diff --git a/src/Impostor.Server/Net/Client.cs b/src/Impostor.Server/Net/Client.cs index f26de40..45718e5 100644 --- a/src/Impostor.Server/Net/Client.cs +++ b/src/Impostor.Server/Net/Client.cs @@ -131,7 +131,7 @@ namespace Impostor.Server.Net return; } - await Player.Game.HandleStartGame(reader); + await Player!.Game.HandleStartGame(reader); break; } @@ -151,7 +151,7 @@ namespace Impostor.Server.Net out var playerId, out var reason); - await Player.Game.HandleRemovePlayer(playerId, (DisconnectReason)reason); + await Player!.Game.HandleRemovePlayer(playerId, (DisconnectReason)reason); break; } @@ -168,7 +168,7 @@ namespace Impostor.Server.Net // Handle packet. using var readerCopy = reader.Copy(); - var verified = await Player.Game.HandleGameDataAsync(readerCopy, Player, toPlayer); + var verified = await Player!.Game.HandleGameDataAsync(readerCopy, Player, toPlayer); if (verified) { // Broadcast packet to all other players. @@ -202,7 +202,7 @@ namespace Impostor.Server.Net reader, out var gameOverReason); - await Player.Game.HandleEndGame(reader, gameOverReason); + await Player!.Game.HandleEndGame(reader, gameOverReason); break; } @@ -223,7 +223,7 @@ namespace Impostor.Server.Net return; } - await Player.Game.HandleAlterGame(reader, Player, value); + await Player!.Game.HandleAlterGame(reader, Player, value); break; } @@ -239,7 +239,7 @@ namespace Impostor.Server.Net out var playerId, out var isBan); - await Player.Game.HandleKickPlayer(playerId, isBan); + await Player!.Game.HandleKickPlayer(playerId, isBan); break; } diff --git a/src/Impostor.Server/Net/ClientBase.cs b/src/Impostor.Server/Net/ClientBase.cs index 7bff06e..78bcb9e 100644 --- a/src/Impostor.Server/Net/ClientBase.cs +++ b/src/Impostor.Server/Net/ClientBase.cs @@ -64,7 +64,6 @@ namespace Impostor.Server.Net public abstract ValueTask HandleDisconnectAsync(string reason); - public async ValueTask DisconnectAsync(DisconnectReason reason, string? message = null) { if (!Connection.IsConnected) diff --git a/src/Impostor.Server/Net/Hazel/HazelConnection.cs b/src/Impostor.Server/Net/Hazel/HazelConnection.cs index 45d2be8..e663dec 100644 --- a/src/Impostor.Server/Net/Hazel/HazelConnection.cs +++ b/src/Impostor.Server/Net/Hazel/HazelConnection.cs @@ -25,14 +25,14 @@ namespace Impostor.Server.Net.Hazel public bool IsConnected => InnerConnection.State == ConnectionState.Connected; - public IClient Client { get; set; } + public IClient? Client { get; set; } public ValueTask SendAsync(IMessageWriter writer) { return InnerConnection.SendAsync(writer); } - public ValueTask DisconnectAsync(string reason) + public ValueTask DisconnectAsync(string? reason) { return InnerConnection.Disconnect(reason); } diff --git a/src/Impostor.Server/Net/Inner/InnerNetObject.cs b/src/Impostor.Server/Net/Inner/InnerNetObject.cs index 9579fe0..5b65f46 100644 --- a/src/Impostor.Server/Net/Inner/InnerNetObject.cs +++ b/src/Impostor.Server/Net/Inner/InnerNetObject.cs @@ -29,6 +29,7 @@ namespace Impostor.Server.Net.Inner public abstract ValueTask HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader); + // TODO move to Reactor.Impostor plugin protected ValueTask HandleCustomRpc(IMessageReader reader, Game game) { var lengthOrShortId = reader.ReadPackedInt32(); @@ -39,8 +40,6 @@ namespace Impostor.Server.Net.Inner var id = reader.ReadPackedInt32(); - // TODO handle custom rpcs - return ValueTask.FromResult(true); } } diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.Api.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.Api.cs index 56ff96e..0e70bd6 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.Api.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.Api.cs @@ -11,7 +11,7 @@ namespace Impostor.Server.Net.Inner.Objects.Components var minSid = (ushort)(_lastSequenceId + 5U); // Snap in the server. - await SnapToAsync(_game.GetClientPlayer(OwnerId), position, minSid); + await SnapToAsync(_game.GetClientPlayer(OwnerId)!, position, minSid); // Broadcast to all clients. using (var writer = _game.StartRpc(NetId, RpcCalls.SnapTo)) diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs index 80dd6ad..0e475b8 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs @@ -23,10 +23,6 @@ namespace Impostor.Server.Net.Inner.Objects.Components private ushort _lastSequenceId; - public Vector2 Position { get; private set; } - - public Vector2 Velocity { get; private set; } - public InnerCustomNetworkTransform(ILogger logger, InnerPlayerControl playerControl, Game game, IEventManager eventManager, ObjectPool pool) { _logger = logger; @@ -37,14 +33,9 @@ namespace Impostor.Server.Net.Inner.Objects.Components _pool = pool; } - private static bool SidGreaterThan(ushort newSid, ushort prevSid) - { - var num = (ushort)(prevSid + (uint)short.MaxValue); + public Vector2 Position { get; private set; } - return (int)prevSid < (int)num - ? newSid > prevSid && newSid <= num - : newSid > prevSid || newSid <= num; - } + public Vector2 Velocity { get; private set; } public override ValueTask SerializeAsync(IMessageWriter writer, bool initialState) { @@ -120,6 +111,15 @@ namespace Impostor.Server.Net.Inner.Objects.Components _pool.Return(playerMovementEvent); } + 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 ValueTask SnapToAsync(IClientPlayer sender, Vector2 position, ushort minSid) { if (!SidGreaterThan(minSid, _lastSequenceId)) diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.Api.cs b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.Api.cs index 5d120c5..0219fba 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.Api.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.Api.cs @@ -4,6 +4,5 @@ namespace Impostor.Server.Net.Inner.Objects { internal partial class InnerMeetingHud : IInnerMeetingHud { - } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.PlayerVoteArea.cs b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.PlayerVoteArea.cs index fbf2510..48f551b 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.PlayerVoteArea.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.PlayerVoteArea.cs @@ -29,12 +29,6 @@ namespace Impostor.Server.Net.Inner.Objects 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(); @@ -44,6 +38,12 @@ namespace Impostor.Server.Net.Inner.Objects DidVote = (num & VotedBit) > 0; DidReport = (num & ReportedBit) > 0; } + + internal void SetDead(bool didReport, bool isDead) + { + DidReport = didReport; + IsDead = isDead; + } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs index 96d829f..8f9c8f5 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading.Tasks; using Impostor.Api; @@ -21,6 +22,8 @@ namespace Impostor.Server.Net.Inner.Objects private readonly IEventManager _eventManager; private readonly Game _game; private readonly GameNet _gameNet; + + [AllowNull] private PlayerVoteArea[] _playerStates; public InnerMeetingHud(ILogger logger, IEventManager eventManager, Game game) @@ -36,18 +39,6 @@ namespace Impostor.Server.Net.Inner.Objects public byte ReporterId { get; private set; } - private void PopulateButtons(byte reporter) - { - _playerStates = _gameNet.GameData.Players - .Select(x => - { - var area = new PlayerVoteArea(this, x.Key); - area.SetDead(x.Value.PlayerId == reporter, x.Value.Disconnected || x.Value.IsDead); - return area; - }) - .ToArray(); - } - public override ValueTask SerializeAsync(IMessageWriter writer, bool initialState) { throw new NotImplementedException(); @@ -142,12 +133,24 @@ namespace Impostor.Server.Net.Inner.Objects return true; } + private void PopulateButtons(byte reporter) + { + _playerStates = _gameNet.GameData!.Players + .Select(x => + { + var area = new PlayerVoteArea(this, x.Key); + area.SetDead(x.Value.PlayerId == reporter, x.Value.Disconnected || x.Value.IsDead); + return area; + }) + .ToArray(); + } + private async ValueTask HandleVotingComplete(ClientPlayer sender, ReadOnlyMemory states, byte playerId, bool tie) { if (playerId != byte.MaxValue) { - var player = _game.GameNet.GameData.GetPlayerById(playerId); - if (player != null) + var player = _game.GameNet.GameData!.GetPlayerById(playerId); + if (player?.Controller != null) { player.Controller.Die(DeathReason.Exile); await _eventManager.CallAsync(new PlayerExileEvent(_game, sender, player.Controller)); diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs index e55f079..604c6e6 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs @@ -104,7 +104,7 @@ namespace Impostor.Server.Net.Inner.Objects Rpc12MurderPlayer.Serialize(writer, target); await _game.FinishRpcAsync(writer); - await _eventManager.CallAsync(new PlayerMurderEvent(_game, _game.GetClientPlayer(OwnerId), this, target)); + await _eventManager.CallAsync(new PlayerMurderEvent(_game, _game.GetClientPlayer(OwnerId)!, this, target)); } public async ValueTask ExileAsync() @@ -123,7 +123,7 @@ namespace Impostor.Server.Net.Inner.Objects await _game.FinishRpcAsync(writer); // Notify plugins. - await _eventManager.CallAsync(new PlayerExileEvent(_game, _game.GetClientPlayer(OwnerId), this)); + await _eventManager.CallAsync(new PlayerExileEvent(_game, _game.GetClientPlayer(OwnerId)!, this)); } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs index 8391ed0..8cd808d 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading.Tasks; using Impostor.Api; @@ -20,6 +21,8 @@ namespace Impostor.Server.Net.Inner.Objects { internal partial class InnerPlayerControl : InnerNetObject { + private static readonly byte ColorsCount = (byte)Enum.GetValues().Length; + private readonly ILogger _logger; private readonly IEventManager _eventManager; private readonly Game _game; @@ -50,6 +53,7 @@ namespace Impostor.Server.Net.Inner.Objects public InnerCustomNetworkTransform NetworkTransform { get; } + [AllowNull] public InnerPlayerInfo PlayerInfo { get; internal set; } internal Queue RequestedPlayerName { get; } = new Queue(); @@ -76,12 +80,6 @@ namespace Impostor.Server.Net.Inner.Objects PlayerId = reader.ReadByte(); } - internal void Die(DeathReason reason) - { - PlayerInfo.IsDead = true; - PlayerInfo.LastDeathReason = reason; - } - public override async ValueTask HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) { switch (call) @@ -297,6 +295,12 @@ namespace Impostor.Server.Net.Inner.Objects return true; } + internal void Die(DeathReason reason) + { + PlayerInfo.IsDead = true; + PlayerInfo.LastDeathReason = reason; + } + private async ValueTask HandleCompleteTask(ClientPlayer sender, uint taskId) { var task = PlayerInfo.Tasks.ElementAtOrDefault((int)taskId); @@ -316,7 +320,7 @@ namespace Impostor.Server.Net.Inner.Objects { for (var i = 0; i < infectedIds.Length; i++) { - var player = _game.GameNet.GameData.GetPlayerById(infectedIds.Span[i]); + var player = _game.GameNet.GameData!.GetPlayerById(infectedIds.Span[i]); if (player != null) { player.IsImpostor = true; @@ -428,8 +432,6 @@ namespace Impostor.Server.Net.Inner.Objects return true; } - private static readonly byte ColorsCount = (byte)Enum.GetValues().Length; - private async ValueTask HandleCheckColor(ClientPlayer sender, ColorType color) { if ((byte)color > ColorsCount) @@ -537,7 +539,7 @@ namespace Impostor.Server.Net.Inner.Objects PlayerInfo.LastMurder = _dateTimeProvider.UtcNow; - if (!target.PlayerInfo.IsDead) + if (target != null && !target.PlayerInfo.IsDead) { ((InnerPlayerControl)target).Die(DeathReason.Kill); await _eventManager.CallAsync(new PlayerMurderEvent(_game, sender, this, target)); @@ -556,8 +558,8 @@ namespace Impostor.Server.Net.Inner.Objects private async ValueTask HandleStartMeeting(byte targetId) { - var deadPlayer = _game.GameNet.GameData.GetPlayerById(targetId)?.Controller; - await _eventManager.CallAsync(new PlayerStartMeetingEvent(_game, _game.GetClientPlayer(this.OwnerId), this, deadPlayer)); + var deadPlayer = _game.GameNet.GameData!.GetPlayerById(targetId)?.Controller; + await _eventManager.CallAsync(new PlayerStartMeetingEvent(_game, _game.GetClientPlayer(this.OwnerId)!, this, deadPlayer)); } private async ValueTask HandleSetPet(ClientPlayer sender, PetType pet) diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs index 301fc08..1d488fb 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs @@ -15,11 +15,11 @@ namespace Impostor.Server.Net.Inner.Objects PlayerId = playerId; } - public InnerPlayerControl Controller { get; internal set; } + public InnerPlayerControl? Controller { get; internal set; } public byte PlayerId { get; } - public string PlayerName { get; internal set; } + public string PlayerName { get; internal set; } = string.Empty; public ColorType Color { get; internal set; } @@ -37,7 +37,7 @@ namespace Impostor.Server.Net.Inner.Objects public DeathReason LastDeathReason { get; internal set; } - public List Tasks { get; internal set; } + public List Tasks { get; internal set; } = new List(0); public DateTimeOffset LastMurder { get; set; } diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/DoorsSystemType.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/DoorsSystemType.cs index 64b1f5f..df374bf 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/DoorsSystemType.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/DoorsSystemType.cs @@ -18,7 +18,7 @@ namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus MapTypes.Skeld => 13, MapTypes.MiraHQ => 2, MapTypes.Polus => 12, - _ => throw new ArgumentOutOfRangeException() + _ => throw new ArgumentOutOfRangeException(), }; _doors = new Dictionary(doorCount); @@ -57,4 +57,4 @@ namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Manager/ClientManager.cs b/src/Impostor.Server/Net/Manager/ClientManager.cs index 32359f8..6ee4515 100644 --- a/src/Impostor.Server/Net/Manager/ClientManager.cs +++ b/src/Impostor.Server/Net/Manager/ClientManager.cs @@ -18,12 +18,12 @@ namespace Impostor.Server.Net.Manager { internal partial class ClientManager { - private static HashSet SupportedVersions { get; } = new HashSet + private static readonly HashSet SupportedVersions = new HashSet { GameVersion.GetVersion(2021, 3, 5), // 2021.3.5 }; - private static string ServerBrand { get; } = $"Impostor {DotnetUtils.GetVersion()}"; + private static readonly string ServerBrand = $"Impostor {DotnetUtils.GetVersion()}"; private readonly ILogger _logger; private readonly ConcurrentDictionary _clients; diff --git a/src/Impostor.Server/Net/Manager/GameManager.cs b/src/Impostor.Server/Net/Manager/GameManager.cs index 8d883a4..eef5d53 100644 --- a/src/Impostor.Server/Net/Manager/GameManager.cs +++ b/src/Impostor.Server/Net/Manager/GameManager.cs @@ -42,46 +42,9 @@ namespace Impostor.Server.Net.Manager IEnumerable IGameManager.Games => _games.Select(kv => kv.Value); - IGame IGameManager.Find(GameCode code) => Find(code); + IGame? IGameManager.Find(GameCode code) => Find(code); - public async ValueTask CreateAsync(GameOptionsData options) - { - // TODO: Prevent duplicates when using server redirector using INodeProvider. - var (success, game) = await TryCreateAsync(options); - - for (int i = 0; i < 10 && !success; i++) - { - (success, game) = await TryCreateAsync(options); - } - - if (!success) - { - throw new ImpostorException("Could not create new game"); // TODO: Fix generic exception. - } - - return game; - } - - private async ValueTask<(bool success, Game game)> TryCreateAsync(GameOptionsData options) - { - var gameCode = _gameCodeFactory.Create(); - var gameCodeStr = gameCode.Code; - var game = ActivatorUtilities.CreateInstance(_serviceProvider, _publicIp, gameCode, options); - - if (await _nodeLocator.ExistsAsync(gameCodeStr) || !_games.TryAdd(gameCode, game)) - { - return (false, null); - } - - await _nodeLocator.SaveAsync(gameCodeStr, _publicIp); - _logger.LogDebug("Created game with code {0}.", game.Code); - - await _eventManager.CallAsync(new GameCreatedEvent(game)); - - return (true, game); - } - - public Game Find(GameCode code) + public Game? Find(GameCode code) { _games.TryGetValue(code, out var game); return game; @@ -146,5 +109,42 @@ namespace Impostor.Server.Net.Manager await _eventManager.CallAsync(new GameDestroyedEvent(game)); } + + public async ValueTask CreateAsync(GameOptionsData options) + { + // TODO: Prevent duplicates when using server redirector using INodeProvider. + var (success, game) = await TryCreateAsync(options); + + for (int i = 0; i < 10 && !success; i++) + { + (success, game) = await TryCreateAsync(options); + } + + if (!success || game == null) + { + throw new ImpostorException("Could not create new game"); // TODO: Fix generic exception. + } + + return game; + } + + private async ValueTask<(bool Success, Game? Game)> TryCreateAsync(GameOptionsData options) + { + var gameCode = _gameCodeFactory.Create(); + var gameCodeStr = gameCode.Code; + var game = ActivatorUtilities.CreateInstance(_serviceProvider, _publicIp, gameCode, options); + + if (await _nodeLocator.ExistsAsync(gameCodeStr) || !_games.TryAdd(gameCode, game)) + { + return (false, null); + } + + await _nodeLocator.SaveAsync(gameCodeStr, _publicIp); + _logger.LogDebug("Created game with code {0}.", game.Code); + + await _eventManager.CallAsync(new GameCreatedEvent(game)); + + return (true, game); + } } } diff --git a/src/Impostor.Server/Net/Matchmaker.cs b/src/Impostor.Server/Net/Matchmaker.cs index e700703..a5518dc 100644 --- a/src/Impostor.Server/Net/Matchmaker.cs +++ b/src/Impostor.Server/Net/Matchmaker.cs @@ -18,7 +18,7 @@ namespace Impostor.Server.Net private readonly ObjectPool _readerPool; private readonly ILogger _logger; private readonly ILogger _connectionLogger; - private UdpConnectionListener _connection; + private UdpConnectionListener? _connection; public Matchmaker( ILogger logger, @@ -38,18 +38,23 @@ namespace Impostor.Server.Net { AddressFamily.InterNetwork => IPMode.IPv4, AddressFamily.InterNetworkV6 => IPMode.IPv6, - _ => throw new InvalidOperationException() + _ => throw new InvalidOperationException(), }; - _connection = new UdpConnectionListener(ipEndPoint, _readerPool, mode); - _connection.NewConnection = OnNewConnection; + _connection = new UdpConnectionListener(ipEndPoint, _readerPool, mode) + { + NewConnection = OnNewConnection, + }; await _connection.StartAsync(); } public async ValueTask StopAsync() { - await _connection.DisposeAsync(); + if (_connection != null) + { + await _connection.DisposeAsync(); + } } private async ValueTask OnNewConnection(NewConnectionEventArgs e) diff --git a/src/Impostor.Server/Net/Redirector/INodeLocator.cs b/src/Impostor.Server/Net/Redirector/INodeLocator.cs index 12563b9..1c3391a 100644 --- a/src/Impostor.Server/Net/Redirector/INodeLocator.cs +++ b/src/Impostor.Server/Net/Redirector/INodeLocator.cs @@ -5,10 +5,10 @@ namespace Impostor.Server.Net.Redirector { public interface INodeLocator { - ValueTask FindAsync(string gameCode); + ValueTask FindAsync(string gameCode); ValueTask SaveAsync(string gameCode, IPEndPoint endPoint); ValueTask RemoveAsync(string gameCode); } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Redirector/NodeLocatorNoOp.cs b/src/Impostor.Server/Net/Redirector/NodeLocatorNoOp.cs index fd4cd56..baef6db 100644 --- a/src/Impostor.Server/Net/Redirector/NodeLocatorNoOp.cs +++ b/src/Impostor.Server/Net/Redirector/NodeLocatorNoOp.cs @@ -5,10 +5,10 @@ namespace Impostor.Server.Net.Redirector { public class NodeLocatorNoOp : INodeLocator { - public ValueTask FindAsync(string gameCode) => ValueTask.FromResult(default(IPEndPoint)); + public ValueTask FindAsync(string gameCode) => ValueTask.FromResult(default(IPEndPoint)); public ValueTask SaveAsync(string gameCode, IPEndPoint endPoint) => ValueTask.CompletedTask; public ValueTask RemoveAsync(string gameCode) => ValueTask.CompletedTask; } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Redirector/NodeLocatorRedis.cs b/src/Impostor.Server/Net/Redirector/NodeLocatorRedis.cs index 0b6fdff..f4595e3 100644 --- a/src/Impostor.Server/Net/Redirector/NodeLocatorRedis.cs +++ b/src/Impostor.Server/Net/Redirector/NodeLocatorRedis.cs @@ -16,7 +16,7 @@ namespace Impostor.Server.Net.Redirector _cache = cache; } - public async ValueTask FindAsync(string gameCode) + public async ValueTask FindAsync(string gameCode) { var entry = await _cache.GetStringAsync(gameCode); if (entry == null) @@ -40,4 +40,4 @@ namespace Impostor.Server.Net.Redirector await _cache.RemoveAsync(gameCode); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Redirector/NodeLocatorUDP.cs b/src/Impostor.Server/Net/Redirector/NodeLocatorUDP.cs index 2539a8f..c75392a 100644 --- a/src/Impostor.Server/Net/Redirector/NodeLocatorUDP.cs +++ b/src/Impostor.Server/Net/Redirector/NodeLocatorUDP.cs @@ -14,9 +14,9 @@ namespace Impostor.Server.Net.Redirector { private readonly ILogger _logger; private readonly bool _isMaster; - private readonly IPEndPoint _server; - private readonly UdpClient _client; - private readonly ConcurrentDictionary _availableNodes; + private readonly IPEndPoint? _server; + private readonly UdpClient? _client; + private readonly ConcurrentDictionary? _availableNodes; public NodeLocatorUdp(ILogger logger, IOptions config) { @@ -31,7 +31,7 @@ namespace Impostor.Server.Net.Redirector { _isMaster = false; - if (!IPEndPoint.TryParse(config.Value.Locator.UdpMasterEndpoint, out var endpoint)) + if (!IPEndPoint.TryParse(config.Value.Locator!.UdpMasterEndpoint, out var endpoint)) { throw new ArgumentException("UdpMasterEndpoint should be in the ip:port format."); } @@ -54,13 +54,9 @@ namespace Impostor.Server.Net.Redirector { _logger.LogDebug("Received update {0} -> {1}", gameCode, ip); - _availableNodes.AddOrUpdate( + _availableNodes!.AddOrUpdate( gameCode, - s => new AvailableNode - { - Endpoint = ip, - LastUpdated = DateTimeOffset.UtcNow, - }, + s => new AvailableNode(ip, DateTimeOffset.UtcNow), (s, node) => { node.Endpoint = ip; @@ -78,14 +74,14 @@ namespace Impostor.Server.Net.Redirector } } - public ValueTask FindAsync(string gameCode) + public ValueTask FindAsync(string gameCode) { if (!_isMaster) { return ValueTask.FromResult(default(IPEndPoint)); } - if (_availableNodes.TryGetValue(gameCode, out var node)) + if (_availableNodes!.TryGetValue(gameCode, out var node)) { if (node.Expired) { @@ -93,7 +89,7 @@ namespace Impostor.Server.Net.Redirector return ValueTask.FromResult(default(IPEndPoint)); } - return ValueTask.FromResult(node.Endpoint); + return ValueTask.FromResult(node.Endpoint)!; } return ValueTask.FromResult(default(IPEndPoint)); @@ -106,14 +102,14 @@ namespace Impostor.Server.Net.Redirector return ValueTask.CompletedTask; } - _availableNodes.TryRemove(gameCode, out _); + _availableNodes!.TryRemove(gameCode, out _); return ValueTask.CompletedTask; } public ValueTask SaveAsync(string gameCode, IPEndPoint endPoint) { var data = Encoding.UTF8.GetBytes($"{gameCode},{endPoint}"); - _client.Send(data, data.Length, _server); + _client!.Send(data, data.Length, _server); return ValueTask.CompletedTask; } @@ -124,6 +120,12 @@ namespace Impostor.Server.Net.Redirector private class AvailableNode { + public AvailableNode(IPEndPoint endpoint, DateTimeOffset lastUpdated) + { + Endpoint = endpoint; + LastUpdated = lastUpdated; + } + public IPEndPoint Endpoint { get; set; } public DateTimeOffset LastUpdated { get; set; } diff --git a/src/Impostor.Server/Net/Redirector/NodeLocatorUDPService.cs b/src/Impostor.Server/Net/Redirector/NodeLocatorUDPService.cs index 3706bb4..781e91f 100644 --- a/src/Impostor.Server/Net/Redirector/NodeLocatorUDPService.cs +++ b/src/Impostor.Server/Net/Redirector/NodeLocatorUDPService.cs @@ -25,7 +25,7 @@ namespace Impostor.Server.Net.Redirector _nodeLocator = (NodeLocatorUdp)nodeLocator; _logger = logger; - if (!IPEndPoint.TryParse(options.Value.Locator.UdpMasterEndpoint, out var endpoint)) + if (!IPEndPoint.TryParse(options.Value.Locator!.UdpMasterEndpoint, out var endpoint)) { throw new ArgumentException("UdpMasterEndpoint should be in the ip:port format."); } diff --git a/src/Impostor.Server/Net/State/ClientPlayer.cs b/src/Impostor.Server/Net/State/ClientPlayer.cs index ceb73b4..b615c06 100644 --- a/src/Impostor.Server/Net/State/ClientPlayer.cs +++ b/src/Impostor.Server/Net/State/ClientPlayer.cs @@ -17,7 +17,7 @@ namespace Impostor.Server.Net.State public ClientPlayer(ILogger logger, ClientBase client, Game game) { _logger = logger; - _spawnTimeout = new Timer(RunSpawnTimeout, null, -1, -1); + _spawnTimeout = new Timer(RunSpawnTimeout!, null, -1, -1); Game = game; Client = client; @@ -35,7 +35,7 @@ namespace Impostor.Server.Net.State public bool IsHost => Game?.Host == this; - public string Scene { get; internal set; } + public string? Scene { get; internal set; } public RuntimePlatform? Platform { get; internal set; } diff --git a/src/Impostor.Server/Net/State/Game.Api.cs b/src/Impostor.Server/Net/State/Game.Api.cs index a299691..44257e7 100644 --- a/src/Impostor.Server/Net/State/Game.Api.cs +++ b/src/Impostor.Server/Net/State/Game.Api.cs @@ -25,7 +25,7 @@ namespace Impostor.Server.Net.State public async ValueTask SyncSettingsAsync() { - if (Host.Character == null) + if (Host?.Character == null) { throw new ImpostorException("Attempted to set infected when the host was not spawned."); } diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index a2eaa09..b928a3c 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -47,124 +47,24 @@ namespace Impostor.Server.Net.State }; private readonly List _allObjects = new List(); - private readonly Dictionary _allObjectsFast = new Dictionary(); - private int _gamedataInitialized; + private readonly Dictionary _allObjectsFast = new Dictionary(); - private async ValueTask OnSpawnAsync(InnerNetObject netObj) + public T? FindObjectByNetId(uint netId) + where T : IInnerNetObject { - switch (netObj) + if (_allObjectsFast.TryGetValue(netId, out var obj)) { - case InnerLobbyBehaviour lobby: - { - GameNet.LobbyBehaviour = lobby; - break; - } - - case InnerGameData data: - { - GameNet.GameData = data; - break; - } - - case InnerVoteBanSystem voteBan: - { - GameNet.VoteBan = voteBan; - break; - } - - case InnerShipStatus shipStatus: - { - GameNet.ShipStatus = shipStatus; - break; - } - - case InnerPlayerControl control: - { - // Hook up InnerPlayerControl <-> IClientPlayer. - if (!TryGetPlayer(control.OwnerId, out var player)) - { - throw new ImpostorException("Failed to find player that spawned the InnerPlayerControl"); - } - - player.Character = control; - player.DisableSpawnTimeout(); - - // Hook up InnerPlayerControl <-> InnerPlayerControl.PlayerInfo. - control.PlayerInfo = GameNet.GameData.GetPlayerById(control.PlayerId)!; - - if (control.PlayerInfo == null) - { - GameNet.GameData.AddPlayer(control); - } - - if (control.PlayerInfo != null) - { - control.PlayerInfo!.Controller = control; - } - - await _eventManager.CallAsync(new PlayerSpawnedEvent(this, player, control)); - - break; - } - - case InnerMeetingHud meetingHud: - { - await _eventManager.CallAsync(new MeetingStartedEvent(this, meetingHud)); - break; - } + return (T)(IInnerNetObject)obj; } - } - - private async ValueTask OnDestroyAsync(InnerNetObject netObj) - { - switch (netObj) - { - case InnerLobbyBehaviour: - { - GameNet.LobbyBehaviour = null; - break; - } - - case InnerGameData: - { - GameNet.GameData = null; - break; - } - - case InnerVoteBanSystem: - { - GameNet.VoteBan = null; - break; - } - - case InnerShipStatus: - { - GameNet.ShipStatus = null; - break; - } - case InnerPlayerControl control: - { - // Remove InnerPlayerControl <-> IClientPlayer. - if (TryGetPlayer(control.OwnerId, out var player)) - { - player.Character = null; - } - - await _eventManager.CallAsync(new PlayerDestroyedEvent(this, player, control)); - - break; - } - - - } + return default; } public async ValueTask HandleGameDataAsync(IMessageReader parent, ClientPlayer sender, bool toPlayer) { // Find target player. - ClientPlayer target = null; + ClientPlayer? target = null; if (toPlayer) { @@ -232,7 +132,7 @@ namespace Impostor.Server.Net.State var objectId = reader.ReadPackedUInt32(); if (objectId < SpawnableObjects.Length) { - var innerNetObject = (InnerNetObject) ActivatorUtilities.CreateInstance(_serviceProvider, SpawnableObjects[objectId], this); + var innerNetObject = (InnerNetObject)ActivatorUtilities.CreateInstance(_serviceProvider, SpawnableObjects[objectId], this); var ownerClientId = reader.ReadPackedInt32(); // Prevent fake client from being broadcasted. @@ -242,7 +142,7 @@ namespace Impostor.Server.Net.State return false; } - innerNetObject.SpawnFlags = (SpawnFlags) reader.ReadByte(); + innerNetObject.SpawnFlags = (SpawnFlags)reader.ReadByte(); var components = innerNetObject.GetComponentsInChildren(); var componentsCount = reader.ReadPackedInt32(); @@ -393,6 +293,113 @@ namespace Impostor.Server.Net.State return true; } + private async ValueTask OnSpawnAsync(InnerNetObject netObj) + { + switch (netObj) + { + case InnerLobbyBehaviour lobby: + { + GameNet.LobbyBehaviour = lobby; + break; + } + + case InnerGameData data: + { + GameNet.GameData = data; + break; + } + + case InnerVoteBanSystem voteBan: + { + GameNet.VoteBan = voteBan; + break; + } + + case InnerShipStatus shipStatus: + { + GameNet.ShipStatus = shipStatus; + break; + } + + case InnerPlayerControl control: + { + // Hook up InnerPlayerControl <-> IClientPlayer. + if (!TryGetPlayer(control.OwnerId, out var player)) + { + throw new ImpostorException("Failed to find player that spawned the InnerPlayerControl"); + } + + player.Character = control; + player.DisableSpawnTimeout(); + + // Hook up InnerPlayerControl <-> InnerPlayerControl.PlayerInfo. + var playerInfo = GameNet.GameData!.GetPlayerById(control.PlayerId); + + if (playerInfo != null) + { + playerInfo.Controller = control; + control.PlayerInfo = playerInfo; + } + else + { + GameNet.GameData.AddPlayer(control); + } + + await _eventManager.CallAsync(new PlayerSpawnedEvent(this, player, control)); + + break; + } + + case InnerMeetingHud meetingHud: + { + await _eventManager.CallAsync(new MeetingStartedEvent(this, meetingHud)); + break; + } + } + } + + private async ValueTask OnDestroyAsync(InnerNetObject netObj) + { + switch (netObj) + { + case InnerLobbyBehaviour: + { + GameNet.LobbyBehaviour = null; + break; + } + + case InnerGameData: + { + GameNet.GameData = null; + break; + } + + case InnerVoteBanSystem: + { + GameNet.VoteBan = null; + break; + } + + case InnerShipStatus: + { + GameNet.ShipStatus = null; + break; + } + + case InnerPlayerControl control: + { + // Remove InnerPlayerControl <-> IClientPlayer. + if (TryGetPlayer(control.OwnerId, out var player)) + { + player.Character = null; + await _eventManager.CallAsync(new PlayerDestroyedEvent(this, player, control)); + } + + break; + } + } + } + private bool AddNetObject(InnerNetObject obj) { if (_allObjectsFast.ContainsKey(obj.NetId)) @@ -417,16 +424,5 @@ namespace Impostor.Server.Net.State obj.NetId = uint.MaxValue; } - - public T? FindObjectByNetId(uint netId) - where T : IInnerNetObject - { - if (_allObjectsFast.TryGetValue(netId, out var obj)) - { - return (T)(IInnerNetObject)obj; - } - - return default; - } } } diff --git a/src/Impostor.Server/Net/State/Game.Incoming.cs b/src/Impostor.Server/Net/State/Game.Incoming.cs index 547224d..8f9df62 100644 --- a/src/Impostor.Server/Net/State/Game.Incoming.cs +++ b/src/Impostor.Server/Net/State/Game.Incoming.cs @@ -29,6 +29,74 @@ namespace Impostor.Server.Net.State await _eventManager.CallAsync(new GameStartingEvent(this)); } + public async ValueTask HandleEndGame(IMessageReader message, GameOverReason gameOverReason) + { + GameState = GameStates.Ended; + + // Broadcast end of the game. + using (var packet = MessageWriter.Get(MessageType.Reliable)) + { + message.CopyTo(packet); + await SendToAllAsync(packet); + } + + // Put all players in the correct limbo state. + foreach (var player in _players) + { + player.Value.Limbo = LimboStates.PreSpawn; + } + + await _eventManager.CallAsync(new GameEndedEvent(this, gameOverReason)); + } + + public async ValueTask HandleAlterGame(IMessageReader message, IClientPlayer sender, bool isPublic) + { + IsPublic = isPublic; + + using var packet = MessageWriter.Get(MessageType.Reliable); + message.CopyTo(packet); + await SendToAllExceptAsync(packet, sender.Client.Id); + + await _eventManager.CallAsync(new GameAlterEvent(this, isPublic)); + } + + public async ValueTask HandleRemovePlayer(int playerId, DisconnectReason reason) + { + await PlayerRemove(playerId); + + // It's possible that the last player was removed, so check if the game is still around. + if (GameState == GameStates.Destroyed) + { + return; + } + + using var packet = MessageWriter.Get(MessageType.Reliable); + WriteRemovePlayerMessage(packet, false, playerId, reason); + await SendToAllExceptAsync(packet, playerId); + } + + public async ValueTask HandleKickPlayer(int playerId, bool isBan) + { + _logger.LogInformation("{0} - Player {1} has left.", Code, playerId); + + using var message = MessageWriter.Get(MessageType.Reliable); + + // Send message to everyone that this player was kicked. + WriteKickPlayerMessage(message, false, playerId, isBan); + + await SendToAllAsync(message); + await PlayerRemove(playerId, isBan); + + // Remove the player from everyone's game. + WriteRemovePlayerMessage( + message, + true, + playerId, + isBan ? DisconnectReason.Banned : DisconnectReason.Kicked); + + await SendToAllExceptAsync(message, playerId); + } + public async ValueTask AddClientAsync(ClientBase client) { var hasLock = false; @@ -53,10 +121,34 @@ namespace Impostor.Server.Net.State return GameJoinResult.FromError(GameJoinError.InvalidClient); } + private async ValueTask HandleJoinGameNew(ClientPlayer sender, bool isNew) + { + _logger.LogInformation("{0} - Player {1} ({2}) is joining.", Code, sender.Client.Name, sender.Client.Id); + + // Add player to the game. + if (isNew) + { + await PlayerAdd(sender); + } + + sender.InitializeSpawnTimeout(); + + using (var message = MessageWriter.Get(MessageType.Reliable)) + { + WriteJoinedGameMessage(message, false, sender); + WriteAlterGameMessage(message, false, IsPublic); + + sender.Limbo = LimboStates.NotLimbo; + + await SendToAsync(message, sender.Client.Id); + await BroadcastJoinMessage(message, true, sender); + } + } + private async ValueTask AddClientSafeAsync(ClientBase client) { // Check if the IP of the player is banned. - if (client.Connection != null && _bannedIps.Contains(client.Connection.EndPoint.Address)) + if (_bannedIps.Contains(client.Connection.EndPoint.Address)) { return GameJoinResult.FromError(GameJoinError.Banned); } @@ -132,98 +224,6 @@ namespace Impostor.Server.Net.State return GameJoinResult.CreateSuccess(player); } - public async ValueTask HandleEndGame(IMessageReader message, GameOverReason gameOverReason) - { - GameState = GameStates.Ended; - - // Broadcast end of the game. - using (var packet = MessageWriter.Get(MessageType.Reliable)) - { - message.CopyTo(packet); - await SendToAllAsync(packet); - } - - // Put all players in the correct limbo state. - foreach (var player in _players) - { - player.Value.Limbo = LimboStates.PreSpawn; - } - - await _eventManager.CallAsync(new GameEndedEvent(this, gameOverReason)); - } - - public async ValueTask HandleAlterGame(IMessageReader message, IClientPlayer sender, bool isPublic) - { - IsPublic = isPublic; - - using var packet = MessageWriter.Get(MessageType.Reliable); - message.CopyTo(packet); - await SendToAllExceptAsync(packet, sender.Client.Id); - - await _eventManager.CallAsync(new GameAlterEvent(this, isPublic)); - } - - public async ValueTask HandleRemovePlayer(int playerId, DisconnectReason reason) - { - await PlayerRemove(playerId); - - // It's possible that the last player was removed, so check if the game is still around. - if (GameState == GameStates.Destroyed) - { - return; - } - - using var packet = MessageWriter.Get(MessageType.Reliable); - WriteRemovePlayerMessage(packet, false, playerId, reason); - await SendToAllExceptAsync(packet, playerId); - } - - public async ValueTask HandleKickPlayer(int playerId, bool isBan) - { - _logger.LogInformation("{0} - Player {1} has left.", Code, playerId); - - using var message = MessageWriter.Get(MessageType.Reliable); - - // Send message to everyone that this player was kicked. - WriteKickPlayerMessage(message, false, playerId, isBan); - - await SendToAllAsync(message); - await PlayerRemove(playerId, isBan); - - // Remove the player from everyone's game. - WriteRemovePlayerMessage( - message, - true, - playerId, - isBan ? DisconnectReason.Banned : DisconnectReason.Kicked); - - await SendToAllExceptAsync(message, playerId); - } - - private async ValueTask HandleJoinGameNew(ClientPlayer sender, bool isNew) - { - _logger.LogInformation("{0} - Player {1} ({2}) is joining.", Code, sender.Client.Name, sender.Client.Id); - - // Add player to the game. - if (isNew) - { - await PlayerAdd(sender); - } - - sender.InitializeSpawnTimeout(); - - using (var message = MessageWriter.Get(MessageType.Reliable)) - { - WriteJoinedGameMessage(message, false, sender); - WriteAlterGameMessage(message, false, IsPublic); - - sender.Limbo = LimboStates.NotLimbo; - - await SendToAsync(message, sender.Client.Id); - await BroadcastJoinMessage(message, true, sender); - } - } - private async ValueTask HandleJoinGameNext(ClientPlayer sender, bool isNew) { _logger.LogInformation("{0} - Player {1} ({2}) is rejoining.", Code, sender.Client.Name, sender.Client.Id); diff --git a/src/Impostor.Server/Net/State/Game.State.cs b/src/Impostor.Server/Net/State/Game.State.cs index 927548e..9f9d904 100644 --- a/src/Impostor.Server/Net/State/Game.State.cs +++ b/src/Impostor.Server/Net/State/Game.State.cs @@ -66,7 +66,7 @@ namespace Impostor.Server.Net.State await MigrateHost(); } - if (isBan && player.Client.Connection != null) + if (isBan) { BanIp(player.Client.Connection.EndPoint.Address); } diff --git a/src/Impostor.Server/Net/State/Game.cs b/src/Impostor.Server/Net/State/Game.cs index 6ca2fd6..823c049 100644 --- a/src/Impostor.Server/Net/State/Game.cs +++ b/src/Impostor.Server/Net/State/Game.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net; using System.Numerics; @@ -66,8 +67,6 @@ namespace Impostor.Server.Net.State public GameStates GameState { get; private set; } - internal GameNet GameNet { get; } - public GameOptionsData Options { get; } public IDictionary Items { get; } @@ -78,7 +77,9 @@ namespace Impostor.Server.Net.State public IEnumerable Players => _players.Select(p => p.Value); - public bool TryGetPlayer(int id, out ClientPlayer player) + internal GameNet GameNet { get; } + + public bool TryGetPlayer(int id, [MaybeNullWhen(false)] out ClientPlayer player) { if (_players.TryGetValue(id, out var result)) { @@ -90,11 +91,16 @@ namespace Impostor.Server.Net.State return false; } - public IClientPlayer GetClientPlayer(int clientId) + public IClientPlayer? GetClientPlayer(int clientId) { return _players.TryGetValue(clientId, out var clientPlayer) ? clientPlayer : null; } + public ValueTask EndAsync() + { + return _gameManager.RemoveAsync(Code); + } + internal async ValueTask StartedAsync() { if (GameState == GameStates.Starting) @@ -111,11 +117,6 @@ namespace Impostor.Server.Net.State } } - public ValueTask EndAsync() - { - return _gameManager.RemoveAsync(Code); - } - private ValueTask BroadcastJoinMessage(IMessageWriter message, bool clear, ClientPlayer player) { Message01JoinGameS2C.SerializeJoin(message, clear, Code, player.Client.Id, HostId); @@ -127,7 +128,7 @@ namespace Impostor.Server.Net.State { return Players .Where(filter) - .Select(p => p.Client.Connection); + .Select(p => p.Client.Connection)!; } } } diff --git a/src/Impostor.Server/Net/State/GameNet.Api.cs b/src/Impostor.Server/Net/State/GameNet.Api.cs index 34ea0fe..4fed527 100644 --- a/src/Impostor.Server/Net/State/GameNet.Api.cs +++ b/src/Impostor.Server/Net/State/GameNet.Api.cs @@ -6,12 +6,12 @@ namespace Impostor.Server.Net.State /// internal partial class GameNet : IGameNet { - IInnerLobbyBehaviour IGameNet.LobbyBehaviour => LobbyBehaviour; + IInnerLobbyBehaviour? IGameNet.LobbyBehaviour => LobbyBehaviour; - IInnerGameData IGameNet.GameData => GameData; + IInnerGameData? IGameNet.GameData => GameData; - IInnerVoteBanSystem IGameNet.VoteBan => VoteBan; + IInnerVoteBanSystem? IGameNet.VoteBan => VoteBan; - IInnerShipStatus IGameNet.ShipStatus => ShipStatus; + IInnerShipStatus? IGameNet.ShipStatus => ShipStatus; } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/State/GameNet.cs b/src/Impostor.Server/Net/State/GameNet.cs index c5542f9..37e0cbd 100644 --- a/src/Impostor.Server/Net/State/GameNet.cs +++ b/src/Impostor.Server/Net/State/GameNet.cs @@ -5,12 +5,12 @@ namespace Impostor.Server.Net.State { internal partial class GameNet { - public InnerLobbyBehaviour LobbyBehaviour { get; internal set; } + public InnerLobbyBehaviour? LobbyBehaviour { get; internal set; } - public InnerGameData GameData { get; internal set; } + public InnerGameData? GameData { get; internal set; } - public InnerVoteBanSystem VoteBan { get; internal set; } + public InnerVoteBanSystem? VoteBan { get; internal set; } - public InnerShipStatus ShipStatus { get; internal set; } + public InnerShipStatus? ShipStatus { get; internal set; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Plugins/AssemblyInformation.cs b/src/Impostor.Server/Plugins/AssemblyInformation.cs index 5f6aee1..df1bf84 100644 --- a/src/Impostor.Server/Plugins/AssemblyInformation.cs +++ b/src/Impostor.Server/Plugins/AssemblyInformation.cs @@ -6,7 +6,7 @@ namespace Impostor.Server.Plugins { public class AssemblyInformation : IAssemblyInformation { - private Assembly _assembly; + private Assembly? _assembly; public AssemblyInformation(AssemblyName assemblyName, string path, bool isPlugin) { @@ -35,4 +35,4 @@ namespace Impostor.Server.Plugins return _assembly; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Plugins/PluginInformation.cs b/src/Impostor.Server/Plugins/PluginInformation.cs index e6a5b6c..f9f61a1 100644 --- a/src/Impostor.Server/Plugins/PluginInformation.cs +++ b/src/Impostor.Server/Plugins/PluginInformation.cs @@ -8,9 +8,9 @@ namespace Impostor.Server.Plugins { private readonly ImpostorPluginAttribute _attribute; - public PluginInformation(IPluginStartup startup, Type pluginType) + public PluginInformation(IPluginStartup? startup, Type pluginType) { - _attribute = pluginType.GetCustomAttribute(); + _attribute = pluginType.GetCustomAttribute()!; Startup = startup; PluginType = pluginType; @@ -24,15 +24,15 @@ namespace Impostor.Server.Plugins public string Version => _attribute.Version; - public IPluginStartup Startup { get; } + public IPluginStartup? Startup { get; } public Type PluginType { get; } - public IPlugin Instance { get; set; } + public IPlugin? Instance { get; set; } public override string ToString() { return $"{Package} {Name} ({Version}) by {Author}"; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Plugins/PluginLoader.cs b/src/Impostor.Server/Plugins/PluginLoader.cs index 4b5d07a..90b9caf 100644 --- a/src/Impostor.Server/Plugins/PluginLoader.cs +++ b/src/Impostor.Server/Plugins/PluginLoader.cs @@ -47,7 +47,7 @@ namespace Impostor.Server.Plugins // Some plugins may be referencing another Impostor.Api version and try to load it. // We want to only use the one shipped with the server. - if (name.Name.Equals("Impostor.Api")) + if (name.Name == "Impostor.Api") { return typeof(IPlugin).Assembly; } @@ -104,18 +104,18 @@ namespace Impostor.Server.Plugins plugin.First())); } - foreach (var plugin in plugins.Where(plugin => plugin.Startup != null)) + foreach (var plugin in plugins) { - plugin.Startup.ConfigureHost(builder); + plugin.Startup?.ConfigureHost(builder); } builder.ConfigureServices(services => { services.AddHostedService(provider => ActivatorUtilities.CreateInstance(provider, plugins)); - foreach (var plugin in plugins.Where(plugin => plugin.Startup != null)) + foreach (var plugin in plugins) { - plugin.Startup.ConfigureServices(services); + plugin.Startup?.ConfigureServices(services); } }); diff --git a/src/Impostor.Server/Plugins/PluginLoaderException.cs b/src/Impostor.Server/Plugins/PluginLoaderException.cs index 64424a1..740cc46 100644 --- a/src/Impostor.Server/Plugins/PluginLoaderException.cs +++ b/src/Impostor.Server/Plugins/PluginLoaderException.cs @@ -10,16 +10,16 @@ namespace Impostor.Server.Plugins { } - protected PluginLoaderException(SerializationInfo info, StreamingContext context) : base(info, context) + public PluginLoaderException(string? message) : base(message) { } - public PluginLoaderException(string? message) : base(message) + public PluginLoaderException(string? message, Exception? innerException) : base(message, innerException) { } - public PluginLoaderException(string? message, Exception? innerException) : base(message, innerException) + protected PluginLoaderException(SerializationInfo info, StreamingContext context) : base(info, context) { } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Plugins/PluginLoaderService.cs b/src/Impostor.Server/Plugins/PluginLoaderService.cs index 0afbc22..84238f7 100644 --- a/src/Impostor.Server/Plugins/PluginLoaderService.cs +++ b/src/Impostor.Server/Plugins/PluginLoaderService.cs @@ -32,7 +32,7 @@ namespace Impostor.Server.Plugins _logger.LogInformation("Enabling plugin {0}.", plugin); // Create instance and inject services. - plugin.Instance = (IPlugin) ActivatorUtilities.CreateInstance(_serviceProvider, plugin.PluginType); + plugin.Instance = (IPlugin)ActivatorUtilities.CreateInstance(_serviceProvider, plugin.PluginType); // Enable plugin. await plugin.Instance.EnableAsync(); @@ -41,20 +41,25 @@ namespace Impostor.Server.Plugins _logger.LogInformation( _plugins.Count == 1 ? "Loaded {0} plugin." - : "Loaded {0} plugins.", _plugins.Count); + : "Loaded {0} plugins.", + _plugins.Count + ); } public async Task StopAsync(CancellationToken cancellationToken) { // Disable all plugins with a valid instance set. // In the case of a failed startup, some can be null. - foreach (var plugin in _plugins.Where(plugin => plugin.Instance != null)) + foreach (var plugin in _plugins) { - _logger.LogInformation("Disabling plugin {0}.", plugin); + if (plugin.Instance != null) + { + _logger.LogInformation("Disabling plugin {0}.", plugin); - // Disable plugin. - await plugin.Instance.DisableAsync(); + // Disable plugin. + await plugin.Instance.DisableAsync(); + } } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Program.cs b/src/Impostor.Server/Program.cs index 109c6be..ab582ca 100644 --- a/src/Impostor.Server/Program.cs +++ b/src/Impostor.Server/Program.cs @@ -128,7 +128,7 @@ namespace Impostor.Server if (redirector.Enabled) { - if (!string.IsNullOrEmpty(redirector.Locator.Redis)) + if (!string.IsNullOrEmpty(redirector.Locator?.Redis)) { // When joining a game, it retrieves the game server ip from redis. // When a game has been created on this node, it stores the game code with its ip in redis. @@ -141,7 +141,7 @@ namespace Impostor.Server options.InstanceName = "ImpostorRedis"; }); } - else if (!string.IsNullOrEmpty(redirector.Locator.UdpMasterEndpoint)) + else if (!string.IsNullOrEmpty(redirector.Locator?.UdpMasterEndpoint)) { services.AddSingleton(); diff --git a/src/Impostor.Server/ProjectRules.ruleset b/src/Impostor.Server/ProjectRules.ruleset deleted file mode 100644 index fd6daac..0000000 --- a/src/Impostor.Server/ProjectRules.ruleset +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Impostor.Server/Recorder/PacketRecorder.cs b/src/Impostor.Server/Recorder/PacketRecorder.cs index c8efdb3..c6531b4 100644 --- a/src/Impostor.Server/Recorder/PacketRecorder.cs +++ b/src/Impostor.Server/Recorder/PacketRecorder.cs @@ -31,7 +31,7 @@ namespace Impostor.Server.Recorder { var name = $"session_{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}.dat"; - _path = Path.Combine(options.Value.GameRecorderPath, name); + _path = Path.Combine(options.Value.GameRecorderPath!, name); _logger = logger; _pool = pool; @@ -42,34 +42,6 @@ namespace Impostor.Server.Recorder }); } - protected override async Task ExecuteAsync(CancellationToken stoppingToken) - { - _startTime = DateTimeOffset.UtcNow; - _logger.LogInformation("PacketRecorder is enabled, writing packets to {0}.", _path); - - var writer = File.Open(_path, FileMode.CreateNew, FileAccess.Write, FileShare.Read); - - await WriteFileHeaderAsync(); - - // Handle messages. - try - { - while (!stoppingToken.IsCancellationRequested) - { - var result = await _channel.Reader.ReadAsync(stoppingToken); - - await writer.WriteAsync(result, stoppingToken); - await writer.FlushAsync(stoppingToken); - } - } - catch (TaskCanceledException) - { - } - - // Clean up. - await writer.DisposeAsync(); - } - public async Task WriteConnectAsync(ClientRecorder client) { _logger.LogTrace("Writing Connect."); @@ -82,7 +54,7 @@ namespace Impostor.Server.Recorder WriteClient(context, client, true); WriteLength(context); - await WriteAsync(context.Stream); + await WriteAsync(context.Stream!); } finally { @@ -103,7 +75,7 @@ namespace Impostor.Server.Recorder context.Writer.Write(reason); WriteLength(context); - await WriteAsync(context.Stream); + await WriteAsync(context.Stream!); } finally { @@ -124,7 +96,7 @@ namespace Impostor.Server.Recorder WritePacket(context, reader, messageType); WriteLength(context); - await WriteAsync(context.Stream); + await WriteAsync(context.Stream!); } finally { @@ -145,7 +117,7 @@ namespace Impostor.Server.Recorder WriteGameCode(context, gameCode); WriteLength(context); - await WriteAsync(context.Stream); + await WriteAsync(context.Stream!); } finally { @@ -153,6 +125,34 @@ namespace Impostor.Server.Recorder } } + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + _startTime = DateTimeOffset.UtcNow; + _logger.LogInformation("PacketRecorder is enabled, writing packets to {0}.", _path); + + var writer = File.Open(_path, FileMode.CreateNew, FileAccess.Write, FileShare.Read); + + await WriteFileHeaderAsync(); + + // Handle messages. + try + { + while (!stoppingToken.IsCancellationRequested) + { + var result = await _channel.Reader.ReadAsync(stoppingToken); + + await writer.WriteAsync(result, stoppingToken); + await writer.FlushAsync(stoppingToken); + } + } + catch (TaskCanceledException) + { + } + + // Clean up. + await writer.DisposeAsync(); + } + private async Task WriteFileHeaderAsync() { var context = _pool.Get(); @@ -163,7 +163,7 @@ namespace Impostor.Server.Recorder context.Writer.Write(_startTime.ToUnixTimeMilliseconds()); context.Writer.Write(DotnetUtils.GetVersion()); - await WriteAsync(context.Stream); + await WriteAsync(context.Stream!); } finally { @@ -182,7 +182,7 @@ namespace Impostor.Server.Recorder context.Writer.Write((byte)type); } - private static void WriteClient(PacketSerializationContext context, ClientBase client, bool full) + private void WriteClient(PacketSerializationContext context, ClientBase client, bool full) { var address = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345); var addressBytes = address.Address.GetAddressBytes(); @@ -199,7 +199,7 @@ namespace Impostor.Server.Recorder } } - private static void WritePacket(PacketSerializationContext context, IMessageReader reader, MessageType messageType) + private void WritePacket(PacketSerializationContext context, IMessageReader reader, MessageType messageType) { context.Writer.Write((byte)messageType); context.Writer.Write((byte)reader.Tag); @@ -207,12 +207,12 @@ namespace Impostor.Server.Recorder context.Writer.Write(reader.Buffer, reader.Offset, reader.Length); } - private static void WriteGameCode(PacketSerializationContext context, in GameCode gameCode) + private void WriteGameCode(PacketSerializationContext context, in GameCode gameCode) { context.Writer.Write(gameCode.Code); } - private static void WriteLength(PacketSerializationContext context) + private void WriteLength(PacketSerializationContext context) { var length = context.Stream.Position; diff --git a/src/Impostor.Server/Recorder/PacketSerializationContext.cs b/src/Impostor.Server/Recorder/PacketSerializationContext.cs index 07755f6..2290bcb 100644 --- a/src/Impostor.Server/Recorder/PacketSerializationContext.cs +++ b/src/Impostor.Server/Recorder/PacketSerializationContext.cs @@ -1,4 +1,5 @@ -using System.IO; +using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Text; namespace Impostor.Server.Recorder @@ -8,33 +9,25 @@ namespace Impostor.Server.Recorder private const int InitialStreamSize = 0x100; private const int MaximumStreamSize = 0x100000; - private MemoryStream _memory; - private BinaryWriter _writer; + private MemoryStream? _memory; + private BinaryWriter? _writer; + [AllowNull] public MemoryStream Stream { get { - if (_memory == null) - { - _memory = new MemoryStream(InitialStreamSize); - } - - return _memory; + return _memory ??= new MemoryStream(InitialStreamSize); } private set => _memory = value; } + [AllowNull] public BinaryWriter Writer { get { - if (_writer == null) - { - _writer = new BinaryWriter(Stream, Encoding.UTF8, true); - } - - return _writer; + return _writer ??= new BinaryWriter(Stream, Encoding.UTF8, true); } private set => _writer = value; } @@ -53,4 +46,4 @@ namespace Impostor.Server.Recorder } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Recorder/RecordedPacketType.cs b/src/Impostor.Server/Recorder/RecordedPacketType.cs index a8a20bc..336cd57 100644 --- a/src/Impostor.Server/Recorder/RecordedPacketType.cs +++ b/src/Impostor.Server/Recorder/RecordedPacketType.cs @@ -5,6 +5,6 @@ Connect = 1, Disconnect = 2, Message = 3, - GameCreated = 4 + GameCreated = 4, } -} \ No newline at end of file +} diff --git a/src/Impostor.Tests/Impostor.Tests.csproj b/src/Impostor.Tests/Impostor.Tests.csproj index 3f96bf6..a4ccd6b 100644 --- a/src/Impostor.Tests/Impostor.Tests.csproj +++ b/src/Impostor.Tests/Impostor.Tests.csproj @@ -1,20 +1,23 @@ - - net5.0 - false - + + net5.0 + false + - - - - - - - + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + - - - + + + diff --git a/src/Impostor.Tools.Proxy/Impostor.Tools.Proxy.csproj b/src/Impostor.Tools.Proxy/Impostor.Tools.Proxy.csproj index 8f523dc..571d7b9 100644 --- a/src/Impostor.Tools.Proxy/Impostor.Tools.Proxy.csproj +++ b/src/Impostor.Tools.Proxy/Impostor.Tools.Proxy.csproj @@ -1,17 +1,19 @@ - - Exe - net5.0 - + + Exe + net5.0 + - - - - + + + + NU1701 + + + + + + - - - - diff --git a/src/Impostor.Tools.ServerReplay/Impostor.Tools.ServerReplay.csproj b/src/Impostor.Tools.ServerReplay/Impostor.Tools.ServerReplay.csproj index 98fa689..3b46f3f 100644 --- a/src/Impostor.Tools.ServerReplay/Impostor.Tools.ServerReplay.csproj +++ b/src/Impostor.Tools.ServerReplay/Impostor.Tools.ServerReplay.csproj @@ -6,11 +6,11 @@ - + - + diff --git a/src/Impostor.Tools.ServerReplay/Mocks/MockHazelConnection.cs b/src/Impostor.Tools.ServerReplay/Mocks/MockHazelConnection.cs index 43f0257..327296f 100644 --- a/src/Impostor.Tools.ServerReplay/Mocks/MockHazelConnection.cs +++ b/src/Impostor.Tools.ServerReplay/Mocks/MockHazelConnection.cs @@ -16,7 +16,7 @@ namespace Impostor.Tools.ServerReplay.Mocks public IPEndPoint EndPoint { get; } public bool IsConnected { get; } - public IClient? Client { get; set; } + public IClient Client { get; set; } public ValueTask SendAsync(IMessageWriter writer) { @@ -28,4 +28,4 @@ namespace Impostor.Tools.ServerReplay.Mocks return ValueTask.CompletedTask; } } -} \ No newline at end of file +} diff --git a/src/ProjectRules.ruleset b/src/ProjectRules.ruleset new file mode 100644 index 0000000..5102b80 --- /dev/null +++ b/src/ProjectRules.ruleset @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + -- 2.39.5