From 87a062c1b3f5fecf6686bd6be4fe64047a583902 Mon Sep 17 00:00:00 2001 From: js6pak Date: Wed, 3 Mar 2021 08:53:53 +0000 Subject: [PATCH 01/72] Sync Impostor with 6pak fork (#327) Co-authored-by: DatGuy1 Co-authored-by: miniduikboot <5243971+miniduikboot@users.noreply.github.com> --- .github/stale.yml | 17 - appveyor.yml | 5 +- build.cake | 92 +-- src/.editorconfig | 4 +- src/.gitignore | 149 ---- src/Directory.Build.props | 7 + src/Impostor.Api/CheatContext.cs | 20 + .../IAnnouncementRequestEvent.cs | 43 ++ .../Game/Player/IPlayerMovementEvent.cs | 6 + .../Exceptions/ImpostorCheatException.cs | 24 - src/Impostor.Api/Games/IGame.cs | 11 +- src/Impostor.Api/Impostor.Api.csproj | 4 +- src/Impostor.Api/Innersloth/Announcement.cs | 14 + .../Innersloth/Customization/HatType.cs | 11 +- .../Innersloth/Customization/PetType.cs | 2 +- .../Innersloth/Customization/SkinType.cs | 2 +- src/Impostor.Api/Innersloth/FloatRange.cs | 22 - .../Innersloth/FreeWeekendState.cs | 12 + .../Innersloth/GameOptionsData.cs | 10 +- src/Impostor.Api/Innersloth/Language.cs | 11 + src/Impostor.Api/Innersloth/MapSpawn.cs | 45 ++ src/Impostor.Api/Net/IClient.cs | 8 + .../IInnerCustomNetworkTransform.cs | 10 + .../Net/Inner/Objects/IInnerPlayerControl.cs | 34 +- .../Net/Inner/Objects/IInnerPlayerInfo.cs | 9 +- .../Net/Inner/RpcCalls.cs | 1 + .../Announcements/Message00UseCache.cs | 15 + .../Messages/Announcements/Message01Update.cs | 19 + .../Announcements/Message02SetFreeWeekend.cs | 19 + .../Messages/Announcements/MessageHello.cs | 15 + .../Net/Messages/AnnouncementsMessageFlags.cs | 9 + .../Net/Messages/C2S/Message00HostGameC2S.cs | 14 +- .../Net/Messages/IMessageReader.cs | 10 + .../Net/Messages/IMessageWriter.cs | 8 +- .../Net/Messages/Rpcs/Rpc00PlayAnimation.cs | 17 + .../Net/Messages/Rpcs/Rpc01CompleteTask.cs | 15 + .../Net/Messages/Rpcs/Rpc02SyncSettings.cs | 17 + .../Net/Messages/Rpcs/Rpc03SetInfected.cs | 17 + .../Net/Messages/Rpcs/Rpc04Exiled.cs | 13 + .../Net/Messages/Rpcs/Rpc05CheckName.cs | 15 + .../Net/Messages/Rpcs/Rpc06SetName.cs | 15 + .../Net/Messages/Rpcs/Rpc07CheckColor.cs | 17 + .../Net/Messages/Rpcs/Rpc08SetColor.cs | 17 + .../Net/Messages/Rpcs/Rpc09SetHat.cs | 17 + .../Net/Messages/Rpcs/Rpc10SetSkin.cs | 17 + .../Net/Messages/Rpcs/Rpc11ReportDeadBody.cs | 15 + .../Net/Messages/Rpcs/Rpc12MurderPlayer.cs | 18 + .../Net/Messages/Rpcs/Rpc13SendChat.cs | 15 + .../Net/Messages/Rpcs/Rpc14StartMeeting.cs | 15 + .../Net/Messages/Rpcs/Rpc15SetScanner.cs | 17 + .../Net/Messages/Rpcs/Rpc16SendChatNote.cs | 19 + .../Net/Messages/Rpcs/Rpc17SetPet.cs | 17 + .../Net/Messages/Rpcs/Rpc18SetStartCounter.cs | 17 + .../Net/Messages/Rpcs/Rpc19EnterVent.cs | 15 + .../Net/Messages/Rpcs/Rpc20ExitVent.cs | 15 + .../Net/Messages/Rpcs/Rpc21SnapTo.cs | 19 + .../Net/Messages/Rpcs/Rpc22Close.cs | 13 + .../Net/Messages/Rpcs/Rpc23VotingComplete.cs | 21 + .../Net/Messages/Rpcs/Rpc24CastVote.cs | 17 + .../Net/Messages/Rpcs/Rpc25ClearVote.cs | 13 + .../Net/Messages/Rpcs/Rpc26AddVote.cs | 17 + .../Messages/Rpcs/Rpc27CloseDoorsOfType.cs | 17 + .../Net/Messages/Rpcs/Rpc28RepairSystem.cs | 23 + .../Net/Messages/Rpcs/Rpc29SetTasks.cs | 19 + .../Net/Messages/Rpcs/Rpc30UpdateGameData.cs | 18 + src/Impostor.Api/ProjectRules.ruleset | 3 +- src/Impostor.Api/Reactor/Mod.cs | 21 + src/Impostor.Api/Reactor/ModList.cs | 24 + .../Reactor/ModdedHandshakeC2S.cs | 23 + .../Reactor/ModdedHandshakeS2C.cs | 14 + src/Impostor.Api/Reactor/PluginSide.cs | 23 + src/Impostor.Api/Unity/Mathf.cs | 7 +- src/Impostor.Hazel/Impostor.Hazel.csproj | 1 - src/Impostor.Hazel/MessageReader.cs | 29 +- src/Impostor.Hazel/MessageWriter.cs | 21 + .../Udp/UdpConnection.Reliable.cs | 12 +- .../AmongUsModifier.cs | 6 +- .../Impostor.Patcher.Shared.csproj | 1 - .../ExamplePluginStartup.cs | 1 + .../Handlers/AnnouncementsListener.cs | 26 + .../Config/AnnouncementsServerConfig.cs | 22 + src/Impostor.Server/Config/AntiCheatConfig.cs | 4 +- .../Announcements/AnnouncementRequestEvent.cs | 29 + src/Impostor.Server/Events/EventManager.cs | 5 - .../Events/Game/Player/PlayerChatEvent.cs | 7 +- .../Game/Player/PlayerCompletedTaskEvent.cs | 1 - .../Events/Game/Player/PlayerMovementEvent.cs | 35 +- .../Extensions/MessageReaderExtensions.cs | 15 - .../Extensions/ServiceProviderExtensions.cs | 22 + src/Impostor.Server/Impostor.Server.csproj | 5 +- .../Net/AnnouncementsService.cs | 98 +++ src/Impostor.Server/Net/Client.cs | 66 +- src/Impostor.Server/Net/ClientBase.cs | 27 +- .../Net/Factories/ClientFactory.cs | 6 +- .../Net/Factories/IClientFactory.cs | 6 +- .../Net/Inner/InnerNetObject.Anticheat.cs | 98 +++ .../Net/Inner/InnerNetObject.cs | 34 +- .../InnerCustomNetworkTransform.Api.cs | 4 +- .../Components/InnerCustomNetworkTransform.cs | 138 ++-- .../Objects/Components/InnerPlayerPhysics.cs | 57 +- .../Objects/Components/InnerVoteBanSystem.cs | 62 +- .../Net/Inner/Objects/InnerGameData.cs | 107 ++- .../Net/Inner/Objects/InnerLobbyBehaviour.cs | 8 +- .../Net/Inner/Objects/InnerMeetingHud.cs | 160 ++-- .../Inner/Objects/InnerPlayerControl.Api.cs | 76 +- .../Net/Inner/Objects/InnerPlayerControl.cs | 706 +++++++++--------- .../Net/Inner/Objects/InnerPlayerInfo.cs | 21 +- .../Net/Inner/Objects/InnerShipStatus.cs | 115 ++- .../Net/Manager/ClientManager.cs | 12 +- src/Impostor.Server/Net/Matchmaker.cs | 6 +- .../Net/Redirector/ClientRedirector.cs | 7 +- src/Impostor.Server/Net/State/Game.Api.cs | 24 +- src/Impostor.Server/Net/State/Game.Data.cs | 23 +- .../Net/State/Game.Incoming.cs | 21 + src/Impostor.Server/Net/State/Game.State.cs | 8 +- src/Impostor.Server/Net/State/Game.cs | 15 +- src/Impostor.Server/Plugins/PluginLoader.cs | 1 - src/Impostor.Server/Program.cs | 13 + src/Impostor.Server/ProjectRules.ruleset | 1 + .../Recorder/ClientRecorder.cs | 8 +- .../Utils/ServerEnvironment.cs | 7 + src/Impostor.Server/config-full.json | 10 +- src/Impostor.Tools.ServerReplay/Program.cs | 12 +- 123 files changed, 2290 insertions(+), 1223 deletions(-) delete mode 100644 .github/stale.yml create mode 100644 src/Directory.Build.props create mode 100644 src/Impostor.Api/CheatContext.cs create mode 100644 src/Impostor.Api/Events/Announcements/IAnnouncementRequestEvent.cs create mode 100644 src/Impostor.Api/Events/Game/Player/IPlayerMovementEvent.cs delete mode 100644 src/Impostor.Api/Exceptions/ImpostorCheatException.cs create mode 100644 src/Impostor.Api/Innersloth/Announcement.cs delete mode 100644 src/Impostor.Api/Innersloth/FloatRange.cs create mode 100644 src/Impostor.Api/Innersloth/FreeWeekendState.cs create mode 100644 src/Impostor.Api/Innersloth/Language.cs create mode 100644 src/Impostor.Api/Innersloth/MapSpawn.cs rename src/{Impostor.Server => Impostor.Api}/Net/Inner/RpcCalls.cs (96%) create mode 100644 src/Impostor.Api/Net/Messages/Announcements/Message00UseCache.cs create mode 100644 src/Impostor.Api/Net/Messages/Announcements/Message01Update.cs create mode 100644 src/Impostor.Api/Net/Messages/Announcements/Message02SetFreeWeekend.cs create mode 100644 src/Impostor.Api/Net/Messages/Announcements/MessageHello.cs create mode 100644 src/Impostor.Api/Net/Messages/AnnouncementsMessageFlags.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc00PlayAnimation.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc01CompleteTask.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc02SyncSettings.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc03SetInfected.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc04Exiled.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc05CheckName.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc06SetName.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc07CheckColor.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc08SetColor.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc09SetHat.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc10SetSkin.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc11ReportDeadBody.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc12MurderPlayer.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc13SendChat.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc14StartMeeting.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc15SetScanner.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc16SendChatNote.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc17SetPet.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc18SetStartCounter.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc19EnterVent.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc20ExitVent.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc21SnapTo.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc22Close.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc23VotingComplete.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc24CastVote.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc25ClearVote.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc26AddVote.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc27CloseDoorsOfType.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc28RepairSystem.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc29SetTasks.cs create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc30UpdateGameData.cs create mode 100644 src/Impostor.Api/Reactor/Mod.cs create mode 100644 src/Impostor.Api/Reactor/ModList.cs create mode 100644 src/Impostor.Api/Reactor/ModdedHandshakeC2S.cs create mode 100644 src/Impostor.Api/Reactor/ModdedHandshakeS2C.cs create mode 100644 src/Impostor.Api/Reactor/PluginSide.cs create mode 100644 src/Impostor.Plugins.Example/Handlers/AnnouncementsListener.cs create mode 100644 src/Impostor.Server/Config/AnnouncementsServerConfig.cs create mode 100644 src/Impostor.Server/Events/Announcements/AnnouncementRequestEvent.cs delete mode 100644 src/Impostor.Server/Extensions/MessageReaderExtensions.cs create mode 100644 src/Impostor.Server/Extensions/ServiceProviderExtensions.cs create mode 100644 src/Impostor.Server/Net/AnnouncementsService.cs create mode 100644 src/Impostor.Server/Net/Inner/InnerNetObject.Anticheat.cs create mode 100644 src/Impostor.Server/Utils/ServerEnvironment.cs diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index e556fa985..000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 60 -# Number of days of inactivity before a stale issue is closed -daysUntilClose: 7 -# Issues with these labels will never be considered stale -exemptLabels: - - pinned - - security -# Label to use when marking an issue as stale -staleLabel: stale -# Comment to post when marking an issue as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false diff --git a/appveyor.yml b/appveyor.yml index e0c82f688..ce3b999ae 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,12 +1,11 @@ version: '{build}' environment: - IMPOSTOR_VERSION: '1.2.2' DOTNET_CLI_TELEMETRY_OPTOUT: 1 branches: except: - - gh-pages + - gh-pages pull_requests: do_not_increment_build_number: true @@ -17,7 +16,7 @@ assembly_info: dotnet_csproj: patch: false -image: Visual Studio 2019 Preview +image: Ubuntu2004 install: - git submodule update --init --recursive diff --git a/build.cake b/build.cake index 7b2869857..e8d9519d9 100644 --- a/build.cake +++ b/build.cake @@ -2,19 +2,19 @@ #addin "nuget:?package=Cake.Compression&Version=0.2.4" #addin "nuget:?package=Cake.FileHelpers&Version=3.3.0" - -var buildId = EnvironmentVariable("APPVEYOR_BUILD_VERSION") ?? "0"; -var buildVersion = EnvironmentVariable("IMPOSTOR_VERSION") ?? "1.0.0"; -var buildBranch = EnvironmentVariable("APPVEYOR_REPO_BRANCH") ?? "dev"; +var buildId = EnvironmentVariable("GITHUB_RUN_NUMBER") ?? EnvironmentVariable("APPVEYOR_BUILD_VERSION"); +var buildRelease = EnvironmentVariable("APPVEYOR_REPO_TAG") == "true"; +var buildVersion = FindRegexMatchGroupInFile("./src/Directory.Build.props", @"\(.*?)\<\/VersionPrefix\>", 1, System.Text.RegularExpressions.RegexOptions.None).Value; var buildDir = MakeAbsolute(Directory("./build")); -var prNumber = EnvironmentVariable("APPVEYOR_PULL_REQUEST_NUMBER"); var target = Argument("target", "Deploy"); var configuration = Argument("configuration", "Release"); -// On any branch that is not master, we need to tag the version as prerelease. -if (buildBranch != "master") { - buildVersion = buildVersion + "-ci." + buildId; +var msbuildSettings = new DotNetCoreMSBuildSettings(); + +if (!buildRelease && buildId != null) { + msbuildSettings.Properties["VersionSuffix"] = new[] { "ci." + buildId }; + buildVersion += "-ci." + buildId; } ////////////////////////////////////////////////////////////////////// @@ -34,7 +34,8 @@ private void ImpostorPublish(string name, string project, string runtime, bool i SelfContained = false, PublishSingleFile = true, PublishTrimmed = false, - OutputDirectory = projBuildDir + OutputDirectory = projBuildDir, + MSBuildSettings = msbuildSettings }); if (isServer) { @@ -46,11 +47,7 @@ private void ImpostorPublish(string name, string project, string runtime, bool i } } - if (runtime == "win-x64") { - Zip(projBuildDir, buildDir.CombineWithFilePath(projBuildName + ".zip")); - } else { - GZipCompress(projBuildDir, buildDir.CombineWithFilePath(projBuildName + ".tar.gz")); - } + Zip(projBuildDir, buildDir.CombineWithFilePath(projBuildName + ".zip")); } private void ImpostorPublishNF(string name, string project) { @@ -62,7 +59,8 @@ private void ImpostorPublishNF(string name, string project) { Configuration = configuration, NoRestore = true, Framework = "net472", - OutputDirectory = projBuildDir + OutputDirectory = projBuildDir, + MSBuildSettings = msbuildSettings }); Zip(projBuildDir, projBuildZip); @@ -86,13 +84,6 @@ Task("Restore") DotNetCoreRestore("./src/Impostor.sln"); }); -Task("Patch") - .WithCriteria(BuildSystem.AppVeyor.IsRunningOnAppVeyor) - .Does(() => { - ReplaceRegexInFiles("./src/**/*.csproj", @".*?<\/Version>", "" + buildVersion + ""); - ReplaceRegexInFiles("./src/**/*.props", @".*?<\/Version>", "" + buildVersion + ""); - }); - Task("Replay") .Does(() => { // D:\Projects\GitHub\Impostor\Impostor\src\Impostor.Tools.ServerReplay\sessions @@ -107,7 +98,6 @@ Task("Replay") Task("Build") .IsDependentOn("Clean") - .IsDependentOn("Patch") .IsDependentOn("Restore") .IsDependentOn("Replay") .Does(() => { @@ -116,44 +106,28 @@ Task("Build") Configuration = configuration, }); - // Only build artifacts if; - // - buildBranch is master/dev - // - it is not a pull request - if ((buildBranch == "master" || buildBranch == "dev") && string.IsNullOrEmpty(prNumber)) { - // Client. - ImpostorPublishNF("Impostor-Patcher", "./src/Impostor.Patcher/Impostor.Patcher.WinForms/Impostor.Patcher.WinForms.csproj"); + // Client. + ImpostorPublishNF("Impostor-Patcher", "./src/Impostor.Patcher/Impostor.Patcher.WinForms/Impostor.Patcher.WinForms.csproj"); - ImpostorPublish("Impostor-Patcher-Cli", "./src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj", "win-x64"); - ImpostorPublish("Impostor-Patcher-Cli", "./src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj", "osx-x64"); - ImpostorPublish("Impostor-Patcher-Cli", "./src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj", "linux-x64"); + ImpostorPublish("Impostor-Patcher-Cli", "./src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj", "win-x64"); + ImpostorPublish("Impostor-Patcher-Cli", "./src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj", "osx-x64"); + ImpostorPublish("Impostor-Patcher-Cli", "./src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj", "linux-x64"); - // Server. - ImpostorPublish("Impostor-Server", "./src/Impostor.Server/Impostor.Server.csproj", "win-x64", true); - ImpostorPublish("Impostor-Server", "./src/Impostor.Server/Impostor.Server.csproj", "osx-x64", true); - ImpostorPublish("Impostor-Server", "./src/Impostor.Server/Impostor.Server.csproj", "linux-x64", true); - ImpostorPublish("Impostor-Server", "./src/Impostor.Server/Impostor.Server.csproj", "linux-arm", true); - ImpostorPublish("Impostor-Server", "./src/Impostor.Server/Impostor.Server.csproj", "linux-arm64", true); - - // API. - DotNetCorePack("./src/Impostor.Api/Impostor.Api.csproj", new DotNetCorePackSettings { - Configuration = configuration, - OutputDirectory = buildDir, - IncludeSource = true, - IncludeSymbols = true - }); - } else { - DotNetCoreBuild("./src/Impostor.Patcher/Impostor.Patcher.WinForms/Impostor.Patcher.WinForms.csproj", new DotNetCoreBuildSettings { - Configuration = configuration, - NoRestore = true, - Framework = "net472" - }); - - DotNetCoreBuild("./src/Impostor.Server/Impostor.Server.csproj", new DotNetCoreBuildSettings { - Configuration = configuration, - NoRestore = true, - Framework = "net5.0" - }); - } + // Server. + ImpostorPublish("Impostor-Server", "./src/Impostor.Server/Impostor.Server.csproj", "win-x64", true); + ImpostorPublish("Impostor-Server", "./src/Impostor.Server/Impostor.Server.csproj", "osx-x64", true); + ImpostorPublish("Impostor-Server", "./src/Impostor.Server/Impostor.Server.csproj", "linux-x64", true); + ImpostorPublish("Impostor-Server", "./src/Impostor.Server/Impostor.Server.csproj", "linux-arm", true); + ImpostorPublish("Impostor-Server", "./src/Impostor.Server/Impostor.Server.csproj", "linux-arm64", true); + + // API. + DotNetCorePack("./src/Impostor.Api/Impostor.Api.csproj", new DotNetCorePackSettings { + Configuration = configuration, + OutputDirectory = buildDir, + IncludeSource = true, + IncludeSymbols = true, + MSBuildSettings = msbuildSettings + }); }); Task("Test") diff --git a/src/.editorconfig b/src/.editorconfig index ef7041d32..af97d16c2 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -4,8 +4,8 @@ root = true # Don't use tabs for indentation. [*] charset = utf-8 -end_of_line = crlf -insert_final_newline = false +end_of_line = lf +insert_final_newline = true indent_style = space # Code files diff --git a/src/.gitignore b/src/.gitignore index e0838bae9..1810abe12 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -26,21 +26,6 @@ bld/ # Visual Studio 2015 cache/options directory .vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c # DNX project.lock.json @@ -72,32 +57,12 @@ artifacts/ *.svclog *.scc -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - # Visual Studio profiler *.psess *.vsp *.vspx *.sap -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper @@ -112,72 +77,11 @@ _TeamCity* # DotCover is a Code Coverage Tool *.dotCover -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - # Click-Once directory publish/ -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -#*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - # NuGet Packages *.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt # Visual Studio cache files # files ending in .cache can be ignored @@ -197,13 +101,6 @@ ClientBin/ node_modules/ orleans.codegen.cs -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) @@ -212,52 +109,6 @@ Backup*/ UpgradeLog*.XML UpgradeLog*.htm -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - # JetBrains Rider .idea/ *.sln.iml - -# CodeRush -.cr/ - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 000000000..58fd8ce9a --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,7 @@ + + + 1.2.2 + dev + + + diff --git a/src/Impostor.Api/CheatContext.cs b/src/Impostor.Api/CheatContext.cs new file mode 100644 index 000000000..45a9956e6 --- /dev/null +++ b/src/Impostor.Api/CheatContext.cs @@ -0,0 +1,20 @@ +using Impostor.Server.Net.Inner; + +namespace Impostor.Api +{ + public class CheatContext + { + public CheatContext(string name) + { + Name = name; + } + + public static CheatContext Deserialize { get; } = new CheatContext(nameof(Deserialize)); + + public static CheatContext Serialize { get; } = new CheatContext(nameof(Serialize)); + + public string Name { get; } + + public static implicit operator CheatContext(RpcCalls rpcCalls) => new CheatContext(rpcCalls.ToString()); + } +} diff --git a/src/Impostor.Api/Events/Announcements/IAnnouncementRequestEvent.cs b/src/Impostor.Api/Events/Announcements/IAnnouncementRequestEvent.cs new file mode 100644 index 000000000..b4eaa0152 --- /dev/null +++ b/src/Impostor.Api/Events/Announcements/IAnnouncementRequestEvent.cs @@ -0,0 +1,43 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Events.Announcements +{ + /// + /// Event fired after client requests a announcement. + /// + public interface IAnnouncementRequestEvent : IEvent + { + public interface IResponse + { + /// + /// Gets or sets FreeWeekendState, currently unused by the client. + /// + public FreeWeekendState FreeWeekendState { get; set; } + + /// + /// Gets or sets a value indicating whether announcement should be loaded from client's cache, can save some bytes. + /// + public bool UseCached { get; set; } + + /// + /// Gets or sets announcement, should be null when is set to true. + /// + public Announcement? Announcement { get; set; } + } + + /// + /// Gets client's last announcement id. + /// + public int Id { get; } + + /// + /// Gets client's language. + /// + public Language Language { get; } + + /// + /// Gets or sets plugin made response. + /// + public IResponse Response { get; set; } + } +} diff --git a/src/Impostor.Api/Events/Game/Player/IPlayerMovementEvent.cs b/src/Impostor.Api/Events/Game/Player/IPlayerMovementEvent.cs new file mode 100644 index 000000000..816684d91 --- /dev/null +++ b/src/Impostor.Api/Events/Game/Player/IPlayerMovementEvent.cs @@ -0,0 +1,6 @@ +namespace Impostor.Api.Events.Player +{ + public interface IPlayerMovementEvent : IPlayerEvent + { + } +} diff --git a/src/Impostor.Api/Exceptions/ImpostorCheatException.cs b/src/Impostor.Api/Exceptions/ImpostorCheatException.cs deleted file mode 100644 index 8eb72f8b6..000000000 --- a/src/Impostor.Api/Exceptions/ImpostorCheatException.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace Impostor.Api -{ - public class ImpostorCheatException : ImpostorException - { - public ImpostorCheatException() - { - } - - protected ImpostorCheatException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - public ImpostorCheatException(string? message) : base(message) - { - } - - public ImpostorCheatException(string? message, Exception? innerException) : base(message, innerException) - { - } - } -} \ No newline at end of file diff --git a/src/Impostor.Api/Games/IGame.cs b/src/Impostor.Api/Games/IGame.cs index ad719867e..7c6140c09 100644 --- a/src/Impostor.Api/Games/IGame.cs +++ b/src/Impostor.Api/Games/IGame.cs @@ -4,7 +4,6 @@ using Impostor.Api.Innersloth; using Impostor.Api.Net; using Impostor.Api.Net.Inner; -using Impostor.Api.Net.Inner.Objects; using Impostor.Api.Net.Messages; namespace Impostor.Api.Games @@ -35,6 +34,9 @@ public interface IGame IClientPlayer GetClientPlayer(int clientId); + T? FindObjectByNetId(uint netId) + where T : IInnerNetObject; + /// /// Adds an to the ban list of this game. /// Prevents all future joins from this . @@ -53,13 +55,6 @@ public interface IGame /// A representing the asynchronous operation. ValueTask SyncSettingsAsync(); - /// - /// Sets the specified list as Impostor on all connected players. - /// - /// List of players to be Impostor. - /// A representing the asynchronous operation. - ValueTask SetInfectedAsync(IEnumerable players); - /// /// Send the message to all players. /// diff --git a/src/Impostor.Api/Impostor.Api.csproj b/src/Impostor.Api/Impostor.Api.csproj index 8ad258288..188f2a677 100644 --- a/src/Impostor.Api/Impostor.Api.csproj +++ b/src/Impostor.Api/Impostor.Api.csproj @@ -1,12 +1,11 @@ - netstandard2.0 + netstandard2.1 ProjectRules.ruleset 9 true enable - 1.0.0 true snupkg Impostor.Api @@ -22,7 +21,6 @@ - diff --git a/src/Impostor.Api/Innersloth/Announcement.cs b/src/Impostor.Api/Innersloth/Announcement.cs new file mode 100644 index 000000000..fca060191 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Announcement.cs @@ -0,0 +1,14 @@ +namespace Impostor.Api.Innersloth +{ + public readonly struct Announcement + { + public readonly int Id; + public readonly string Message; + + public Announcement(int id, string message) + { + Id = id; + Message = message; + } + } +} diff --git a/src/Impostor.Api/Innersloth/Customization/HatType.cs b/src/Impostor.Api/Innersloth/Customization/HatType.cs index 5e0a3efe0..c4af44c98 100644 --- a/src/Impostor.Api/Innersloth/Customization/HatType.cs +++ b/src/Impostor.Api/Innersloth/Customization/HatType.cs @@ -1,6 +1,6 @@ namespace Impostor.Api.Innersloth.Customization { - public enum HatType + public enum HatType : uint { NoHat = 0, Astronaut = 1, @@ -45,8 +45,8 @@ public enum HatType ThirdEyeHat = 40, ToiletPaperHat = 41, Toppat = 42, - Fedora = 43, - Goggles2 = 44, + BlackFedora = 43, + SkiGoggles = 44, Headphones = 45, MaskHat = 46, PaperMask = 47, @@ -58,7 +58,7 @@ public enum HatType Cheese = 53, Cherry = 54, Egg = 55, - Fedora2 = 56, + GreenFedora = 56, Flamingo = 57, FlowerPin = 58, Helmet = 59, @@ -95,6 +95,7 @@ public enum HatType MiniCrewmate = 90, NinjaMask = 91, RamHorns = 92, - Snowman2 = 93, + SnowCrewmate = 93, + GeoffHat = 94, } } diff --git a/src/Impostor.Api/Innersloth/Customization/PetType.cs b/src/Impostor.Api/Innersloth/Customization/PetType.cs index 456e3274f..f8753f273 100644 --- a/src/Impostor.Api/Innersloth/Customization/PetType.cs +++ b/src/Impostor.Api/Innersloth/Customization/PetType.cs @@ -1,6 +1,6 @@ namespace Impostor.Api.Innersloth.Customization { - public enum PetType + public enum PetType : uint { NoPet = 0, Alien = 1, diff --git a/src/Impostor.Api/Innersloth/Customization/SkinType.cs b/src/Impostor.Api/Innersloth/Customization/SkinType.cs index 35da31209..9f0aa2297 100644 --- a/src/Impostor.Api/Innersloth/Customization/SkinType.cs +++ b/src/Impostor.Api/Innersloth/Customization/SkinType.cs @@ -1,6 +1,6 @@ namespace Impostor.Api.Innersloth.Customization { - public enum SkinType : byte + public enum SkinType : uint { None = 0, Astro = 1, diff --git a/src/Impostor.Api/Innersloth/FloatRange.cs b/src/Impostor.Api/Innersloth/FloatRange.cs deleted file mode 100644 index c8a0824df..000000000 --- a/src/Impostor.Api/Innersloth/FloatRange.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Impostor.Api.Unity; - -namespace Impostor.Api.Innersloth -{ - public class FloatRange - { - private readonly float _min; - private readonly float _max; - - public FloatRange(float min, float max) - { - _min = min; - _max = max; - } - - public float Width => _max - _min; - - public float Lerp(float v) => Mathf.Lerp(_min, _max, v); - - public float ReverseLerp(float t) => Mathf.Clamp((t - _min) / Width, 0.0f, 1f); - } -} \ No newline at end of file diff --git a/src/Impostor.Api/Innersloth/FreeWeekendState.cs b/src/Impostor.Api/Innersloth/FreeWeekendState.cs new file mode 100644 index 000000000..2effda854 --- /dev/null +++ b/src/Impostor.Api/Innersloth/FreeWeekendState.cs @@ -0,0 +1,12 @@ +using System; + +namespace Impostor.Api.Innersloth +{ + [Flags] + public enum FreeWeekendState : byte + { + NotFree, + FreeMIRA, + FreePolus, + } +} diff --git a/src/Impostor.Api/Innersloth/GameOptionsData.cs b/src/Impostor.Api/Innersloth/GameOptionsData.cs index d18efd8c5..7f7e0c5ef 100644 --- a/src/Impostor.Api/Innersloth/GameOptionsData.cs +++ b/src/Impostor.Api/Innersloth/GameOptionsData.cs @@ -161,7 +161,7 @@ public static GameOptionsData DeserializeCreate(IMessageReader reader) /// /// The stream to write the message to. /// The version of the game. - public void Serialize(BinaryWriter writer, byte version) + public void Serialize(BinaryWriter writer, byte version = LatestVersion) { writer.Write((byte)version); writer.Write((byte)MaxPlayers); @@ -204,6 +204,14 @@ public void Serialize(BinaryWriter writer, byte version) } } + public void Serialize(IMessageWriter writer) + { + using var memory = new MemoryStream(); + using var writerBin = new BinaryWriter(memory); + Serialize(writerBin); + writer.WriteBytesAndSize(memory.ToArray()); + } + /// /// Deserialize a ReadOnlyMemory object to this instance of the GameOptionsData object. /// diff --git a/src/Impostor.Api/Innersloth/Language.cs b/src/Impostor.Api/Innersloth/Language.cs new file mode 100644 index 000000000..b17e5ad8c --- /dev/null +++ b/src/Impostor.Api/Innersloth/Language.cs @@ -0,0 +1,11 @@ +namespace Impostor.Api.Innersloth +{ + public enum Language + { + English, + Spanish, + Portuguese, + Korean, + Russian, + } +} diff --git a/src/Impostor.Api/Innersloth/MapSpawn.cs b/src/Impostor.Api/Innersloth/MapSpawn.cs new file mode 100644 index 000000000..61dea0f6d --- /dev/null +++ b/src/Impostor.Api/Innersloth/MapSpawn.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Numerics; + +namespace Impostor.Api.Innersloth +{ + public class MapSpawn + { + private MapSpawn(float spawnRadius, Vector2 initialSpawnCenter, Vector2 meetingSpawnCenter) + { + SpawnRadius = spawnRadius; + InitialSpawnCenter = initialSpawnCenter; + MeetingSpawnCenter = meetingSpawnCenter; + } + + public static Dictionary Maps { get; } = new Dictionary + { + [MapTypes.Skeld] = new MapSpawn(1.6f, new Vector2(-0.72f, 0.62f), new Vector2(-0.72f, 0.62f)), + [MapTypes.MiraHQ] = new MapSpawn(1.55f, new Vector2(-4.4f, 2.2f), new Vector2(24.043f, 1.72f)), + [MapTypes.Polus] = new MapSpawn(1f, new Vector2(16.64f, -2.46f), new Vector2(17.726f, -16.286f)), + }; + + public float SpawnRadius { get; } + + public Vector2 InitialSpawnCenter { get; } + + public Vector2 MeetingSpawnCenter { get; } + + public Vector2 GetSpawnLocation(int playerId, int numPlayer, bool initialSpawn) + { + var vector = new Vector2(0, 1); + vector = Rotate(vector, (playerId - 1) * (360f / numPlayer)); + vector *= this.SpawnRadius; + return (initialSpawn ? this.InitialSpawnCenter : this.MeetingSpawnCenter) + vector + new Vector2(0f, 0.3636f); + } + + private static Vector2 Rotate(Vector2 self, float degrees) + { + var f = 0.017453292f * degrees; + var num = (float)Math.Cos(f); + var num2 = (float)Math.Sin(f); + return new Vector2((self.X * num) - (num2 * self.Y), (self.X * num2) + (num * self.Y)); + } + } +} diff --git a/src/Impostor.Api/Net/IClient.cs b/src/Impostor.Api/Net/IClient.cs index 48efeda42..1ba594470 100644 --- a/src/Impostor.Api/Net/IClient.cs +++ b/src/Impostor.Api/Net/IClient.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Impostor.Api.Innersloth; using Impostor.Api.Net.Messages; +using Impostor.Api.Reactor; namespace Impostor.Api.Net { @@ -27,6 +28,11 @@ public interface IClient /// string Name { get; } + /// + /// Gets mods sent by client in modded handshake. + /// + ISet Mods { get; } + /// /// Gets the connection of the client. /// @@ -55,6 +61,8 @@ public interface IClient /// IClientPlayer? Player { get; } + ValueTask ReportCheatAsync(CheatContext context, string message); + ValueTask HandleMessageAsync(IMessageReader message, MessageType messageType); ValueTask HandleDisconnectAsync(string reason); diff --git a/src/Impostor.Api/Net/Inner/Objects/Components/IInnerCustomNetworkTransform.cs b/src/Impostor.Api/Net/Inner/Objects/Components/IInnerCustomNetworkTransform.cs index 6d867e793..2dd470947 100644 --- a/src/Impostor.Api/Net/Inner/Objects/Components/IInnerCustomNetworkTransform.cs +++ b/src/Impostor.Api/Net/Inner/Objects/Components/IInnerCustomNetworkTransform.cs @@ -5,6 +5,16 @@ namespace Impostor.Api.Net.Inner.Objects.Components { public interface IInnerCustomNetworkTransform : IInnerNetObject { + /// + /// Gets position where the object thinks it is (not interpolated). + /// + Vector2 Position { get; } + + /// + /// Gets current object's velocity. + /// + Vector2 Velocity { get; } + /// /// Snaps the current to the given position . /// diff --git a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs index 04558b96e..c0ecf855d 100644 --- a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs +++ b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs @@ -41,48 +41,32 @@ public interface IInnerPlayerControl : IInnerNetObject /// Sets the color of the current . /// Visible to all players. /// - /// A color for the player. - /// Task that must be awaited. - ValueTask SetColorAsync(byte colorId); - /// A color for the player. - /// + /// Task that must be awaited. ValueTask SetColorAsync(ColorType colorType); /// /// Sets the hat of the current . /// Visible to all players. /// - /// An hat for the player. - /// Task that must be awaited. - ValueTask SetHatAsync(uint hatId); - /// An hat for the player. - /// + /// Task that must be awaited. ValueTask SetHatAsync(HatType hatType); /// /// Sets the pet of the current . /// Visible to all players. /// - /// A pet for the player. - /// Task that must be awaited. - ValueTask SetPetAsync(uint petId); - /// A pet for the player. - /// + /// Task that must be awaited. ValueTask SetPetAsync(PetType petType); /// /// Sets the skin of the current . /// Visible to all players. /// - /// A skin for the player. - /// Task that must be awaited. - ValueTask SetSkinAsync(uint skinId); - /// A skin for the player. - /// + /// Task that must be awaited. ValueTask SetSkinAsync(SkinType skinType); /// @@ -106,11 +90,13 @@ public interface IInnerPlayerControl : IInnerNetObject ValueTask SendChatToPlayerAsync(string text, IInnerPlayerControl? player = null); /// - /// Sets the current to be murdered by an impostor . - /// Visible to all players. + /// Murder player. /// - /// /// The Impostor who kill. + /// Target player to murder. + /// Thrown when player is not the impostor. + /// Thrown when player is dead. + /// Thrown when target is dead. /// Task that must be awaited. - ValueTask SetMurderedByAsync(IClientPlayer impostor); + ValueTask MurderPlayerAsync(IInnerPlayerControl target); } } diff --git a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs index 6cb33024a..310755ed2 100644 --- a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs +++ b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Impostor.Api.Innersloth; +using Impostor.Api.Innersloth.Customization; namespace Impostor.Api.Net.Inner.Objects { @@ -14,22 +15,22 @@ public interface IInnerPlayerInfo /// /// Gets the color of the player. /// - byte ColorId { get; } + ColorType Color { get; } /// /// Gets the hat of the player. /// - uint HatId { get; } + HatType Hat { get; } /// /// Gets the pet of the player. /// - uint PetId { get; } + PetType Pet { get; } /// /// Gets the skin of the player. /// - uint SkinId { get; } + SkinType Skin { get; } /// /// Gets a value indicating whether the player is an impostor. diff --git a/src/Impostor.Server/Net/Inner/RpcCalls.cs b/src/Impostor.Api/Net/Inner/RpcCalls.cs similarity index 96% rename from src/Impostor.Server/Net/Inner/RpcCalls.cs rename to src/Impostor.Api/Net/Inner/RpcCalls.cs index ce4896537..f82d2e89e 100644 --- a/src/Impostor.Server/Net/Inner/RpcCalls.cs +++ b/src/Impostor.Api/Net/Inner/RpcCalls.cs @@ -33,5 +33,6 @@ public enum RpcCalls : byte RepairSystem = 28, SetTasks = 29, UpdateGameData = 30, + CustomRpc = byte.MaxValue } } \ No newline at end of file diff --git a/src/Impostor.Api/Net/Messages/Announcements/Message00UseCache.cs b/src/Impostor.Api/Net/Messages/Announcements/Message00UseCache.cs new file mode 100644 index 000000000..3787ef63c --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Announcements/Message00UseCache.cs @@ -0,0 +1,15 @@ +namespace Impostor.Api.Net.Messages.Announcements +{ + public static class Message00UseCache + { + public static void Serialize(IMessageWriter writer) + { + writer.StartMessage(AnnouncementsMessageFlags.UseCache); + writer.EndMessage(); + } + + public static void Deserialize(IMessageReader reader) + { + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Announcements/Message01Update.cs b/src/Impostor.Api/Net/Messages/Announcements/Message01Update.cs new file mode 100644 index 000000000..b8bc28439 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Announcements/Message01Update.cs @@ -0,0 +1,19 @@ +namespace Impostor.Api.Net.Messages.Announcements +{ + public static class Message01Update + { + public static void Serialize(IMessageWriter writer, int id, string message) + { + writer.StartMessage(AnnouncementsMessageFlags.SetUpdate); + writer.WritePacked(id); + writer.Write(message); + writer.EndMessage(); + } + + public static void Deserialize(IMessageReader reader, out int id, out string message) + { + id = reader.ReadPackedInt32(); + message = reader.ReadString(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Announcements/Message02SetFreeWeekend.cs b/src/Impostor.Api/Net/Messages/Announcements/Message02SetFreeWeekend.cs new file mode 100644 index 000000000..054f313e5 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Announcements/Message02SetFreeWeekend.cs @@ -0,0 +1,19 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.Announcements +{ + public static class Message02SetFreeWeekend + { + public static void Serialize(IMessageWriter writer, FreeWeekendState state) + { + writer.StartMessage(AnnouncementsMessageFlags.SetFreeWeekend); + writer.Write((byte)state); + writer.EndMessage(); + } + + public static void Deserialize(IMessageReader reader, out FreeWeekendState state) + { + state = (FreeWeekendState)reader.ReadByte(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Announcements/MessageHello.cs b/src/Impostor.Api/Net/Messages/Announcements/MessageHello.cs new file mode 100644 index 000000000..c695037ec --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Announcements/MessageHello.cs @@ -0,0 +1,15 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.Announcements +{ + public class MessageHello + { + public static void Deserialize(IMessageReader reader, out int announcementVersion, out int id, out Language language) + { + reader.ReadByte(); // SendOption header, probably added by accident + announcementVersion = reader.ReadPackedInt32(); + id = reader.ReadPackedInt32(); + language = (Language)reader.ReadPackedInt32(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/AnnouncementsMessageFlags.cs b/src/Impostor.Api/Net/Messages/AnnouncementsMessageFlags.cs new file mode 100644 index 000000000..498d3e412 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/AnnouncementsMessageFlags.cs @@ -0,0 +1,9 @@ +namespace Impostor.Api.Net.Messages +{ + public class AnnouncementsMessageFlags + { + public const byte UseCache = 0; + public const byte SetUpdate = 1; + public const byte SetFreeWeekend = 2; + } +} diff --git a/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs index 4f5b39ce7..f90d7f53f 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs @@ -1,5 +1,4 @@ -using System.IO; -using Impostor.Api.Innersloth; +using Impostor.Api.Innersloth; namespace Impostor.Api.Net.Messages.C2S { @@ -8,14 +7,7 @@ public static class Message00HostGameC2S public static void Serialize(IMessageWriter writer, GameOptionsData gameOptionsData) { writer.StartMessage(MessageFlags.HostGame); - - using (var memory = new MemoryStream()) - using (var writerBin = new BinaryWriter(memory)) - { - gameOptionsData.Serialize(writerBin, GameOptionsData.LatestVersion); - writer.WriteBytesAndSize(memory.ToArray()); - } - + gameOptionsData.Serialize(writer); writer.EndMessage(); } @@ -24,4 +16,4 @@ public static GameOptionsData Deserialize(IMessageReader reader) return GameOptionsData.DeserializeCreate(reader); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/IMessageReader.cs b/src/Impostor.Api/Net/Messages/IMessageReader.cs index 87c06c448..1eb82d1f3 100644 --- a/src/Impostor.Api/Net/Messages/IMessageReader.cs +++ b/src/Impostor.Api/Net/Messages/IMessageReader.cs @@ -1,4 +1,7 @@ using System; +using System.Numerics; +using Impostor.Api.Games; +using Impostor.Api.Net.Inner; namespace Impostor.Api.Net.Messages { @@ -47,6 +50,8 @@ public interface IMessageReader : IDisposable float ReadSingle(); + string ReadString(int length); + string ReadString(); ReadOnlyMemory ReadBytesAndSize(); @@ -64,5 +69,10 @@ public interface IMessageReader : IDisposable void RemoveMessage(IMessageReader message); IMessageReader Copy(int offset = 0); + + T? ReadNetObject(IGame game) + where T : IInnerNetObject; + + Vector2 ReadVector2(); } } diff --git a/src/Impostor.Api/Net/Messages/IMessageWriter.cs b/src/Impostor.Api/Net/Messages/IMessageWriter.cs index 4f6765bfe..0f4b7fadd 100644 --- a/src/Impostor.Api/Net/Messages/IMessageWriter.cs +++ b/src/Impostor.Api/Net/Messages/IMessageWriter.cs @@ -1,6 +1,8 @@ using System; using System.Net; +using System.Numerics; using Impostor.Api.Games; +using Impostor.Api.Net.Inner; namespace Impostor.Api.Net.Messages { @@ -107,6 +109,10 @@ public interface IMessageWriter : IDisposable void WriteBytesAndSize(byte[] bytes, int offset, int length); + void Write(IInnerNetObject innerNetObject); + + void Write(Vector2 vector); + /// /// Starts a new message. /// @@ -124,4 +130,4 @@ public interface IMessageWriter : IDisposable /// New type of the message. void Clear(MessageType type); } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc00PlayAnimation.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc00PlayAnimation.cs new file mode 100644 index 000000000..f7f91835c --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc00PlayAnimation.cs @@ -0,0 +1,17 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc00PlayAnimation + { + public static void Serialize(IMessageWriter writer, TaskTypes task) + { + writer.Write((byte)task); + } + + public static void Deserialize(IMessageReader reader, out TaskTypes task) + { + task = (TaskTypes)reader.ReadByte(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc01CompleteTask.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc01CompleteTask.cs new file mode 100644 index 000000000..dfe7ec0d8 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc01CompleteTask.cs @@ -0,0 +1,15 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc01CompleteTask + { + public static void Serialize(IMessageWriter writer, uint taskId) + { + writer.WritePacked(taskId); + } + + public static void Deserialize(IMessageReader reader, out uint taskId) + { + taskId = reader.ReadPackedUInt32(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc02SyncSettings.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc02SyncSettings.cs new file mode 100644 index 000000000..047d21faf --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc02SyncSettings.cs @@ -0,0 +1,17 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc02SyncSettings + { + public static void Serialize(IMessageWriter writer, GameOptionsData gameOptionsData) + { + gameOptionsData.Serialize(writer); + } + + public static void Deserialize(IMessageReader reader, GameOptionsData gameOptionsData) + { + gameOptionsData.Deserialize(reader.ReadBytesAndSize()); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc03SetInfected.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc03SetInfected.cs new file mode 100644 index 000000000..27a11e9a1 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc03SetInfected.cs @@ -0,0 +1,17 @@ +using System; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc03SetInfected + { + public static void Serialize(IMessageWriter writer, byte[] infectedIds) + { + writer.WriteBytesAndSize(infectedIds); + } + + public static void Deserialize(IMessageReader reader, out ReadOnlyMemory infectedIds) + { + infectedIds = reader.ReadBytesAndSize(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc04Exiled.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc04Exiled.cs new file mode 100644 index 000000000..7dba967aa --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc04Exiled.cs @@ -0,0 +1,13 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc04Exiled + { + public static void Serialize(IMessageWriter writer) + { + } + + public static void Deserialize(IMessageReader reader) + { + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc05CheckName.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc05CheckName.cs new file mode 100644 index 000000000..014707513 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc05CheckName.cs @@ -0,0 +1,15 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc05CheckName + { + public static void Serialize(IMessageWriter writer, string name) + { + writer.Write(name); + } + + public static void Deserialize(IMessageReader reader, out string name) + { + name = reader.ReadString(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc06SetName.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc06SetName.cs new file mode 100644 index 000000000..e2e8ae488 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc06SetName.cs @@ -0,0 +1,15 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc06SetName + { + public static void Serialize(IMessageWriter writer, string name) + { + writer.Write(name); + } + + public static void Deserialize(IMessageReader reader, out string name) + { + name = reader.ReadString(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc07CheckColor.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc07CheckColor.cs new file mode 100644 index 000000000..d33875ad1 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc07CheckColor.cs @@ -0,0 +1,17 @@ +using Impostor.Api.Innersloth.Customization; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc07CheckColor + { + public static void Serialize(IMessageWriter writer, ColorType color) + { + writer.Write((byte)color); + } + + public static void Deserialize(IMessageReader reader, out ColorType color) + { + color = (ColorType)reader.ReadByte(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc08SetColor.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc08SetColor.cs new file mode 100644 index 000000000..50ea3d695 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc08SetColor.cs @@ -0,0 +1,17 @@ +using Impostor.Api.Innersloth.Customization; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc08SetColor + { + public static void Serialize(IMessageWriter writer, ColorType color) + { + writer.Write((byte)color); + } + + public static void Deserialize(IMessageReader reader, out ColorType color) + { + color = (ColorType)reader.ReadByte(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc09SetHat.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc09SetHat.cs new file mode 100644 index 000000000..caa9ff752 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc09SetHat.cs @@ -0,0 +1,17 @@ +using Impostor.Api.Innersloth.Customization; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc09SetHat + { + public static void Serialize(IMessageWriter writer, HatType hat) + { + writer.WritePacked((uint)hat); + } + + public static void Deserialize(IMessageReader reader, out HatType hat) + { + hat = (HatType)reader.ReadPackedUInt32(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc10SetSkin.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc10SetSkin.cs new file mode 100644 index 000000000..e57eeffff --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc10SetSkin.cs @@ -0,0 +1,17 @@ +using Impostor.Api.Innersloth.Customization; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc10SetSkin + { + public static void Serialize(IMessageWriter writer, SkinType skin) + { + writer.WritePacked((uint)skin); + } + + public static void Deserialize(IMessageReader reader, out SkinType skin) + { + skin = (SkinType)reader.ReadPackedUInt32(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc11ReportDeadBody.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc11ReportDeadBody.cs new file mode 100644 index 000000000..a8707a91e --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc11ReportDeadBody.cs @@ -0,0 +1,15 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc11ReportDeadBody + { + public static void Serialize(IMessageWriter writer, byte targetId) + { + writer.Write(targetId); + } + + public static void Deserialize(IMessageReader reader, out byte targetId) + { + targetId = reader.ReadByte(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc12MurderPlayer.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc12MurderPlayer.cs new file mode 100644 index 000000000..82f55f6c7 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc12MurderPlayer.cs @@ -0,0 +1,18 @@ +using Impostor.Api.Games; +using Impostor.Api.Net.Inner.Objects; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc12MurderPlayer + { + public static void Serialize(IMessageWriter writer, IInnerPlayerControl target) + { + writer.Write(target); + } + + public static void Deserialize(IMessageReader reader, IGame game, out IInnerPlayerControl? target) + { + target = reader.ReadNetObject(game); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc13SendChat.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc13SendChat.cs new file mode 100644 index 000000000..dcce22930 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc13SendChat.cs @@ -0,0 +1,15 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc13SendChat + { + public static void Serialize(IMessageWriter writer, string message) + { + writer.Write(message); + } + + public static void Deserialize(IMessageReader reader, out string message) + { + message = reader.ReadString(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc14StartMeeting.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc14StartMeeting.cs new file mode 100644 index 000000000..8001e43f2 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc14StartMeeting.cs @@ -0,0 +1,15 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc14StartMeeting + { + public static void Serialize(IMessageWriter writer, byte targetId) + { + writer.Write(targetId); + } + + public static void Deserialize(IMessageReader reader, out byte targetId) + { + targetId = reader.ReadByte(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc15SetScanner.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc15SetScanner.cs new file mode 100644 index 000000000..f46adea82 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc15SetScanner.cs @@ -0,0 +1,17 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc15SetScanner + { + public static void Serialize(IMessageWriter writer, bool on, byte scannerCount) + { + writer.Write(on); + writer.Write(scannerCount); + } + + public static void Deserialize(IMessageReader reader, out bool on, out byte scannerCount) + { + on = reader.ReadBoolean(); + scannerCount = reader.ReadByte(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc16SendChatNote.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc16SendChatNote.cs new file mode 100644 index 000000000..4def9d1b0 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc16SendChatNote.cs @@ -0,0 +1,19 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc16SendChatNote + { + public static void Serialize(IMessageWriter writer, byte playerId, ChatNoteType chatNoteType) + { + writer.Write(playerId); + writer.Write((byte)chatNoteType); + } + + public static void Deserialize(IMessageReader reader, out byte playerId, out ChatNoteType chatNoteType) + { + playerId = reader.ReadByte(); + chatNoteType = (ChatNoteType)reader.ReadByte(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc17SetPet.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc17SetPet.cs new file mode 100644 index 000000000..be67df58c --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc17SetPet.cs @@ -0,0 +1,17 @@ +using Impostor.Api.Innersloth.Customization; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc17SetPet + { + public static void Serialize(IMessageWriter writer, PetType pet) + { + writer.WritePacked((uint)pet); + } + + public static void Deserialize(IMessageReader reader, out PetType pet) + { + pet = (PetType)reader.ReadPackedUInt32(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc18SetStartCounter.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc18SetStartCounter.cs new file mode 100644 index 000000000..cb3c2d1e3 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc18SetStartCounter.cs @@ -0,0 +1,17 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc18SetStartCounter + { + public static void Serialize(IMessageWriter writer, int sequenceId, sbyte startCounter) + { + writer.Write(sequenceId); + writer.Write(startCounter); + } + + public static void Deserialize(IMessageReader reader, out int sequenceId, out sbyte startCounter) + { + sequenceId = reader.ReadPackedInt32(); + startCounter = reader.ReadSByte(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc19EnterVent.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc19EnterVent.cs new file mode 100644 index 000000000..eca9f1395 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc19EnterVent.cs @@ -0,0 +1,15 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc19EnterVent + { + public static void Serialize(IMessageWriter writer, int ventId) + { + writer.WritePacked(ventId); + } + + public static void Deserialize(IMessageReader reader, out int ventId) + { + ventId = reader.ReadPackedInt32(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc20ExitVent.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc20ExitVent.cs new file mode 100644 index 000000000..ddfaf4465 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc20ExitVent.cs @@ -0,0 +1,15 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc20ExitVent + { + public static void Serialize(IMessageWriter writer, int ventId) + { + writer.WritePacked(ventId); + } + + public static void Deserialize(IMessageReader reader, out int ventId) + { + ventId = reader.ReadPackedInt32(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc21SnapTo.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc21SnapTo.cs new file mode 100644 index 000000000..576a911dc --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc21SnapTo.cs @@ -0,0 +1,19 @@ +using System.Numerics; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc21SnapTo + { + public static void Serialize(IMessageWriter writer, Vector2 position, ushort minSid) + { + writer.Write(position); + writer.Write(minSid); + } + + public static void Deserialize(IMessageReader reader, out Vector2 position, out ushort minSid) + { + position = reader.ReadVector2(); + minSid = reader.ReadUInt16(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc22Close.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc22Close.cs new file mode 100644 index 000000000..00caaf396 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc22Close.cs @@ -0,0 +1,13 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc22Close + { + public static void Serialize(IMessageWriter writer) + { + } + + public static void Deserialize(IMessageReader reader) + { + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc23VotingComplete.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc23VotingComplete.cs new file mode 100644 index 000000000..bf9482738 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc23VotingComplete.cs @@ -0,0 +1,21 @@ +using System; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc23VotingComplete + { + public static void Serialize(IMessageWriter writer, byte[] states, byte playerId, bool tie) + { + writer.WriteBytesAndSize(states); + writer.Write(playerId); + writer.Write(tie); + } + + public static void Deserialize(IMessageReader reader, out ReadOnlyMemory states, out byte playerId, out bool tie) + { + states = reader.ReadBytesAndSize(); + playerId = reader.ReadByte(); + tie = reader.ReadBoolean(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc24CastVote.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc24CastVote.cs new file mode 100644 index 000000000..1c51bc17e --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc24CastVote.cs @@ -0,0 +1,17 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc24CastVote + { + public static void Serialize(IMessageWriter writer, byte playerId, sbyte suspectPlayerId) + { + writer.Write(playerId); + writer.Write(suspectPlayerId); + } + + public static void Deserialize(IMessageReader reader, out byte playerId, out sbyte suspectPlayerId) + { + playerId = reader.ReadByte(); + suspectPlayerId = reader.ReadSByte(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc25ClearVote.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc25ClearVote.cs new file mode 100644 index 000000000..5a89331b1 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc25ClearVote.cs @@ -0,0 +1,13 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc25ClearVote + { + public static void Serialize(IMessageWriter writer) + { + } + + public static void Deserialize(IMessageReader reader) + { + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc26AddVote.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc26AddVote.cs new file mode 100644 index 000000000..f665accbe --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc26AddVote.cs @@ -0,0 +1,17 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc26AddVote + { + public static void Serialize(IMessageWriter writer, int clientId, int targetClientId) + { + writer.Write(clientId); + writer.Write(targetClientId); + } + + public static void Deserialize(IMessageReader reader, out int clientId, out int targetClientId) + { + clientId = reader.ReadInt32(); + targetClientId = reader.ReadInt32(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc27CloseDoorsOfType.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc27CloseDoorsOfType.cs new file mode 100644 index 000000000..4e3c822de --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc27CloseDoorsOfType.cs @@ -0,0 +1,17 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc27CloseDoorsOfType + { + public static void Serialize(IMessageWriter writer, SystemTypes systemType) + { + writer.Write((byte)systemType); + } + + public static void Deserialize(IMessageReader reader, out SystemTypes systemType) + { + systemType = (SystemTypes)reader.ReadByte(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc28RepairSystem.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc28RepairSystem.cs new file mode 100644 index 000000000..411602d7f --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc28RepairSystem.cs @@ -0,0 +1,23 @@ +using Impostor.Api.Games; +using Impostor.Api.Innersloth; +using Impostor.Api.Net.Inner.Objects; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc28RepairSystem + { + public static void Serialize(IMessageWriter writer, SystemTypes systemType, IInnerPlayerControl player, byte amount) + { + writer.Write((byte)systemType); + writer.Write(player); + writer.Write(amount); + } + + public static void Deserialize(IMessageReader reader, IGame game, out SystemTypes systemType, out IInnerPlayerControl? player, out byte amount) + { + systemType = (SystemTypes)reader.ReadByte(); + player = reader.ReadNetObject(game); + amount = reader.ReadByte(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc29SetTasks.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc29SetTasks.cs new file mode 100644 index 000000000..aba9a7158 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc29SetTasks.cs @@ -0,0 +1,19 @@ +using System; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc29SetTasks + { + public static void Serialize(IMessageWriter writer, byte playerId, ReadOnlyMemory taskTypeIds) + { + writer.Write(playerId); + writer.Write(taskTypeIds); + } + + public static void Deserialize(IMessageReader reader, out byte playerId, out ReadOnlyMemory taskTypeIds) + { + playerId = reader.ReadByte(); + taskTypeIds = reader.ReadBytesAndSize(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc30UpdateGameData.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc30UpdateGameData.cs new file mode 100644 index 000000000..4403cf66d --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc30UpdateGameData.cs @@ -0,0 +1,18 @@ +using System; +using Impostor.Api.Net.Inner.Objects; + +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc30UpdateGameData + { + public static void Serialize(IMessageWriter writer) + { + throw new NotImplementedException(); + } + + public static void Deserialize(IMessageReader reader, IInnerGameData gameData) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Impostor.Api/ProjectRules.ruleset b/src/Impostor.Api/ProjectRules.ruleset index 4ba23c2fc..51021f56f 100644 --- a/src/Impostor.Api/ProjectRules.ruleset +++ b/src/Impostor.Api/ProjectRules.ruleset @@ -9,7 +9,8 @@ - + + diff --git a/src/Impostor.Api/Reactor/Mod.cs b/src/Impostor.Api/Reactor/Mod.cs new file mode 100644 index 000000000..2654c5fd3 --- /dev/null +++ b/src/Impostor.Api/Reactor/Mod.cs @@ -0,0 +1,21 @@ +namespace Impostor.Api.Reactor +{ + public readonly struct Mod + { + public readonly string Id; + public readonly string Version; + public readonly PluginSide Side; + + public Mod(string id, string version, PluginSide side) + { + Id = id; + Version = version; + Side = side; + } + + public override string ToString() + { + return $"{Id} ({Version})"; + } + } +} diff --git a/src/Impostor.Api/Reactor/ModList.cs b/src/Impostor.Api/Reactor/ModList.cs new file mode 100644 index 000000000..047c8b49f --- /dev/null +++ b/src/Impostor.Api/Reactor/ModList.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using Impostor.Api.Net.Messages; + +namespace Impostor.Api.Reactor +{ + public static class ModList + { + public static void Deserialize(IMessageReader reader, out ISet mods) + { + var length = reader.ReadPackedInt32(); + + mods = new HashSet(length); + + for (var i = 0; i < length; i++) + { + var id = reader.ReadString(); + var version = reader.ReadString(); + var pluginSide = (PluginSide)reader.ReadByte(); + + mods.Add(new Mod(id, version, pluginSide)); + } + } + } +} diff --git a/src/Impostor.Api/Reactor/ModdedHandshakeC2S.cs b/src/Impostor.Api/Reactor/ModdedHandshakeC2S.cs new file mode 100644 index 000000000..a79671206 --- /dev/null +++ b/src/Impostor.Api/Reactor/ModdedHandshakeC2S.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using Impostor.Api.Net.Messages; + +namespace Impostor.Api.Reactor +{ + public static class ModdedHandshakeC2S + { + public static void Deserialize(IMessageReader reader, out int clientVersion, out string name, out ISet? mods) + { + clientVersion = reader.ReadInt32(); + name = reader.ReadString(); + + if (reader.Length > reader.Position) + { + ModList.Deserialize(reader, out mods); + } + else + { + mods = null; + } + } + } +} diff --git a/src/Impostor.Api/Reactor/ModdedHandshakeS2C.cs b/src/Impostor.Api/Reactor/ModdedHandshakeS2C.cs new file mode 100644 index 000000000..07f4f9c88 --- /dev/null +++ b/src/Impostor.Api/Reactor/ModdedHandshakeS2C.cs @@ -0,0 +1,14 @@ +using Impostor.Api.Net.Messages; + +namespace Impostor.Api.Reactor +{ + public static class ModdedHandshakeS2C + { + public static void Serialize(IMessageWriter writer, string serverBrand) + { + writer.StartMessage(byte.MaxValue); + writer.Write(serverBrand); + writer.EndMessage(); + } + } +} diff --git a/src/Impostor.Api/Reactor/PluginSide.cs b/src/Impostor.Api/Reactor/PluginSide.cs new file mode 100644 index 000000000..30c588c7e --- /dev/null +++ b/src/Impostor.Api/Reactor/PluginSide.cs @@ -0,0 +1,23 @@ +namespace Impostor.Api.Reactor +{ + /// + /// Plugin side used in modded handshake + /// + public enum PluginSide : byte + { + /// + /// Required by both sides, reject connection if missing on the other side + /// + Both, + + /// + /// Required only by client + /// + ClientOnly, + + /// + /// Required only by server + /// + ServerOnly, + } +} diff --git a/src/Impostor.Api/Unity/Mathf.cs b/src/Impostor.Api/Unity/Mathf.cs index 4b034176d..f796decdf 100644 --- a/src/Impostor.Api/Unity/Mathf.cs +++ b/src/Impostor.Api/Unity/Mathf.cs @@ -50,5 +50,10 @@ public static float Clamp01(float value) /// The interpolated float result between the two float values. /// public static float Lerp(float a, float b, float t) => a + ((b - a) * Clamp01(t)); + + public static float ReverseLerp(float t) + { + return Clamp((t - -40f) / (40f - -40f), 0f, 1f); + } } -} \ No newline at end of file +} diff --git a/src/Impostor.Hazel/Impostor.Hazel.csproj b/src/Impostor.Hazel/Impostor.Hazel.csproj index 3e035fbe9..00997697c 100644 --- a/src/Impostor.Hazel/Impostor.Hazel.csproj +++ b/src/Impostor.Hazel/Impostor.Hazel.csproj @@ -4,7 +4,6 @@ true net5.0 HAZEL_BAG - 1.0.0 diff --git a/src/Impostor.Hazel/MessageReader.cs b/src/Impostor.Hazel/MessageReader.cs index 986d0b024..35933298d 100644 --- a/src/Impostor.Hazel/MessageReader.cs +++ b/src/Impostor.Hazel/MessageReader.cs @@ -1,10 +1,14 @@ using System; using System.Buffers; using System.Buffers.Binary; +using System.Numerics; using System.Runtime.CompilerServices; using System.Text; using Impostor.Api; +using Impostor.Api.Games; +using Impostor.Api.Net.Inner; using Impostor.Api.Net.Messages; +using Impostor.Api.Unity; using Microsoft.Extensions.ObjectPool; namespace Impostor.Hazel @@ -123,14 +127,18 @@ public unsafe float ReadSingle() return output; } - public string ReadString() + public string ReadString(int length) { - var len = ReadPackedInt32(); - var output = Encoding.UTF8.GetString(Buffer.AsSpan(ReadPosition, len)); - Position += len; + var output = Encoding.UTF8.GetString(Buffer.AsSpan(ReadPosition, length)); + Position += length; return output; } + public string ReadString() + { + return ReadString(ReadPackedInt32()); + } + public ReadOnlyMemory ReadBytesAndSize() { var len = ReadPackedInt32(); @@ -239,6 +247,19 @@ public IMessageReader Copy(int offset = 0) return reader; } + public T ReadNetObject(IGame game) where T : IInnerNetObject + { + return game.FindObjectByNetId(ReadPackedUInt32()); + } + + public Vector2 ReadVector2() + { + var x = ReadUInt16() / (float) ushort.MaxValue; + var y = ReadUInt16() / (float) ushort.MaxValue; + + return new Vector2(Mathf.Lerp(-40f, 40f, x), Mathf.Lerp(-40f, 40f, y)); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private byte FastByte() { diff --git a/src/Impostor.Hazel/MessageWriter.cs b/src/Impostor.Hazel/MessageWriter.cs index 5b7342a31..a7b57e78e 100644 --- a/src/Impostor.Hazel/MessageWriter.cs +++ b/src/Impostor.Hazel/MessageWriter.cs @@ -4,7 +4,10 @@ using System; using System.Collections.Generic; using System.Net; +using System.Numerics; using System.Text; +using Impostor.Api.Net.Inner; +using Impostor.Api.Unity; namespace Impostor.Hazel { @@ -89,6 +92,24 @@ public void Write(GameCode value) this.Write(value.Value); } + public void Write(IInnerNetObject innerNetObject) + { + if (innerNetObject == null) + { + this.Write(0); + } + else + { + this.WritePacked(innerNetObject.NetId); + } + } + + public void Write(Vector2 vector) + { + Write((ushort)(Mathf.ReverseLerp(vector.X) * (double) ushort.MaxValue)); + Write((ushort)(Mathf.ReverseLerp(vector.Y) * (double) ushort.MaxValue)); + } + /// public void StartMessage(byte typeFlag) { diff --git a/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs b/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs index a7a4309e9..7f439269d 100644 --- a/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs +++ b/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs @@ -309,9 +309,6 @@ private async ValueTask ProcessReliableReceive(ReadOnlyMemory bytes, //Get the ID form the packet var id = (ushort)((b1 << 8) + b2); - //Send an acknowledgement - await SendAck(id); - /* * It gets a little complicated here (note the fact I'm actually using a multiline comment for once...) * @@ -337,6 +334,8 @@ private async ValueTask ProcessReliableReceive(ReadOnlyMemory bytes, * So... */ + var result = true; + lock (reliableDataPacketsMissing) { //Calculate overwritePointer @@ -379,12 +378,15 @@ private async ValueTask ProcessReliableReceive(ReadOnlyMemory bytes, //See if we're missing it, else this packet is a duplicate as so we return false if (!reliableDataPacketsMissing.Remove(id)) { - return false; + result = false; } } } + + //Send an acknowledgement + await SendAck(id); - return true; + return result; } /// diff --git a/src/Impostor.Patcher/Impostor.Patcher.Shared/AmongUsModifier.cs b/src/Impostor.Patcher/Impostor.Patcher.Shared/AmongUsModifier.cs index 95f552480..7c1ced263 100644 --- a/src/Impostor.Patcher/Impostor.Patcher.Shared/AmongUsModifier.cs +++ b/src/Impostor.Patcher/Impostor.Patcher.Shared/AmongUsModifier.cs @@ -143,7 +143,10 @@ public async Task SaveIpAsync(string input) return false; } - return WriteIp(ipAddress, port); + var result = WriteIp(ipAddress, port); + OnSaved(ip, port); + + return result; } /// @@ -176,7 +179,6 @@ private bool WriteIp(IPAddress ipAddress, ushort port) region.Serialize(writer); - OnSaved(ip, port); return 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 e480870c8..8d71e56cf 100644 --- a/src/Impostor.Patcher/Impostor.Patcher.Shared/Impostor.Patcher.Shared.csproj +++ b/src/Impostor.Patcher/Impostor.Patcher.Shared/Impostor.Patcher.Shared.csproj @@ -2,7 +2,6 @@ netstandard2.0;netstandard2.1 - 1.0.0 diff --git a/src/Impostor.Plugins.Example/ExamplePluginStartup.cs b/src/Impostor.Plugins.Example/ExamplePluginStartup.cs index 936f15e25..673026daa 100644 --- a/src/Impostor.Plugins.Example/ExamplePluginStartup.cs +++ b/src/Impostor.Plugins.Example/ExamplePluginStartup.cs @@ -17,6 +17,7 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); } } } diff --git a/src/Impostor.Plugins.Example/Handlers/AnnouncementsListener.cs b/src/Impostor.Plugins.Example/Handlers/AnnouncementsListener.cs new file mode 100644 index 000000000..42ca3f28d --- /dev/null +++ b/src/Impostor.Plugins.Example/Handlers/AnnouncementsListener.cs @@ -0,0 +1,26 @@ +using Impostor.Api.Events; +using Impostor.Api.Events.Announcements; +using Impostor.Api.Innersloth; + +namespace Impostor.Plugins.Example.Handlers +{ + public class AnnouncementsListener : IEventListener + { + private const int Id = 50; + + [EventListener] + public void OnAnnouncementRequestEvent(IAnnouncementRequestEvent e) + { + if (e.Id == Id) + { + // Client already has announcement cached, lets just use that + e.Response.UseCached = true; + } + else + { + // Client is receiving this announcement for the first time, window will popup + e.Response.Announcement = new Announcement(Id, "Hello!"); + } + } + } +} diff --git a/src/Impostor.Server/Config/AnnouncementsServerConfig.cs b/src/Impostor.Server/Config/AnnouncementsServerConfig.cs new file mode 100644 index 000000000..5d61ac04c --- /dev/null +++ b/src/Impostor.Server/Config/AnnouncementsServerConfig.cs @@ -0,0 +1,22 @@ +using Impostor.Server.Utils; + +namespace Impostor.Server.Config +{ + internal class AnnouncementsServerConfig + { + private string? _resolvedListenIp; + + public const string Section = "AnnouncementsServer"; + + public bool Enabled { get; set; } = true; + + public string ListenIp { get; set; } = "0.0.0.0"; + + public ushort ListenPort { get; set; } = 22024; + + public string ResolveListenIp() + { + return _resolvedListenIp ??= IpUtils.ResolveIp(ListenIp); + } + } +} diff --git a/src/Impostor.Server/Config/AntiCheatConfig.cs b/src/Impostor.Server/Config/AntiCheatConfig.cs index f4807e7f1..ee1f62a62 100644 --- a/src/Impostor.Server/Config/AntiCheatConfig.cs +++ b/src/Impostor.Server/Config/AntiCheatConfig.cs @@ -4,6 +4,8 @@ public class AntiCheatConfig { public const string Section = "AntiCheat"; + public bool Enabled { get; set; } = true; + public bool BanIpFromGame { get; set; } = true; } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Events/Announcements/AnnouncementRequestEvent.cs b/src/Impostor.Server/Events/Announcements/AnnouncementRequestEvent.cs new file mode 100644 index 000000000..0f5b55291 --- /dev/null +++ b/src/Impostor.Server/Events/Announcements/AnnouncementRequestEvent.cs @@ -0,0 +1,29 @@ +using Impostor.Api.Events.Announcements; +using Impostor.Api.Innersloth; + +namespace Impostor.Server.Events.Announcements +{ + public class AnnouncementRequestEvent : IAnnouncementRequestEvent + { + public AnnouncementRequestEvent(int id, Language language) + { + Id = id; + Language = language; + } + + public int Id { get; } + + public Language Language { get; } + + public IAnnouncementRequestEvent.IResponse Response { get; set; } = new AnnouncementResponse(); + + public class AnnouncementResponse : IAnnouncementRequestEvent.IResponse + { + public FreeWeekendState FreeWeekendState { get; set; } = FreeWeekendState.NotFree; + + public bool UseCached { get; set; } = false; + + public Announcement? Announcement { get; set; } = null; + } + } +} diff --git a/src/Impostor.Server/Events/EventManager.cs b/src/Impostor.Server/Events/EventManager.cs index 5625c4dd9..0cc6e541e 100644 --- a/src/Impostor.Server/Events/EventManager.cs +++ b/src/Impostor.Server/Events/EventManager.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Impostor.Api; using Impostor.Api.Events; using Impostor.Api.Events.Managers; using Impostor.Server.Events.Register; @@ -91,10 +90,6 @@ public async ValueTask CallAsync(T @event) await eventListener.InvokeAsync(handler, @event, _serviceProvider); } } - catch (ImpostorCheatException) - { - throw; - } catch (Exception e) { _logger.LogError(e, "Invocation of event {0} threw an exception.", @event.GetType().Name); diff --git a/src/Impostor.Server/Events/Game/Player/PlayerChatEvent.cs b/src/Impostor.Server/Events/Game/Player/PlayerChatEvent.cs index 7b7eb22fe..32c156145 100644 --- a/src/Impostor.Server/Events/Game/Player/PlayerChatEvent.cs +++ b/src/Impostor.Server/Events/Game/Player/PlayerChatEvent.cs @@ -1,11 +1,12 @@ -using Impostor.Api.Events.Player; +using Impostor.Api.Events; +using Impostor.Api.Events.Player; using Impostor.Api.Games; using Impostor.Api.Net; using Impostor.Api.Net.Inner.Objects; namespace Impostor.Server.Events.Player { - public class PlayerChatEvent : IPlayerChatEvent + public class PlayerChatEvent : IPlayerChatEvent, IEventCancelable { public PlayerChatEvent(IGame game, IClientPlayer clientPlayer, IInnerPlayerControl playerControl, string message) { @@ -22,5 +23,7 @@ public PlayerChatEvent(IGame game, IClientPlayer clientPlayer, IInnerPlayerContr public IInnerPlayerControl PlayerControl { get; } public string Message { get; } + + public bool IsCancelled { get; set; } } } diff --git a/src/Impostor.Server/Events/Game/Player/PlayerCompletedTaskEvent.cs b/src/Impostor.Server/Events/Game/Player/PlayerCompletedTaskEvent.cs index 330135d16..00e2b2c8f 100644 --- a/src/Impostor.Server/Events/Game/Player/PlayerCompletedTaskEvent.cs +++ b/src/Impostor.Server/Events/Game/Player/PlayerCompletedTaskEvent.cs @@ -1,6 +1,5 @@ using Impostor.Api.Events.Player; using Impostor.Api.Games; -using Impostor.Api.Innersloth; using Impostor.Api.Net; using Impostor.Api.Net.Inner.Objects; diff --git a/src/Impostor.Server/Events/Game/Player/PlayerMovementEvent.cs b/src/Impostor.Server/Events/Game/Player/PlayerMovementEvent.cs index 31ac38861..60dbc1215 100644 --- a/src/Impostor.Server/Events/Game/Player/PlayerMovementEvent.cs +++ b/src/Impostor.Server/Events/Game/Player/PlayerMovementEvent.cs @@ -2,23 +2,46 @@ using Impostor.Api.Games; using Impostor.Api.Net; using Impostor.Api.Net.Inner.Objects; +using Microsoft.Extensions.ObjectPool; namespace Impostor.Server.Events.Player { - // TODO: Finish and use event, needs to be pooled - public class PlayerMovementEvent : IPlayerEvent + public class PlayerMovementEvent : IPlayerMovementEvent { - public PlayerMovementEvent(IGame game, IClientPlayer clientPlayer, IInnerPlayerControl playerControl) +#pragma warning disable 8766 + public IGame? Game { get; private set; } + + public IClientPlayer? ClientPlayer { get; private set; } + + public IInnerPlayerControl? PlayerControl { get; private set; } +#pragma warning restore 8766 + + public void Reset(IGame game, IClientPlayer clientPlayer, IInnerPlayerControl playerControl) { Game = game; ClientPlayer = clientPlayer; PlayerControl = playerControl; } - public IGame Game { get; } + public void Reset() + { + Game = null; + ClientPlayer = null; + PlayerControl = null; + } - public IClientPlayer ClientPlayer { get; } + public class PlayerMovementEventObjectPolicy : IPooledObjectPolicy + { + public PlayerMovementEvent Create() + { + return new PlayerMovementEvent(); + } - public IInnerPlayerControl PlayerControl { get; } + public bool Return(PlayerMovementEvent obj) + { + obj.Reset(); + return true; + } + } } } diff --git a/src/Impostor.Server/Extensions/MessageReaderExtensions.cs b/src/Impostor.Server/Extensions/MessageReaderExtensions.cs deleted file mode 100644 index 5f25e899b..000000000 --- a/src/Impostor.Server/Extensions/MessageReaderExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Impostor.Api.Net.Messages; -using Impostor.Server.Net.Inner; -using Impostor.Server.Net.State; - -namespace Impostor.Server -{ - internal static class MessageReaderExtensions - { - public static T ReadNetObject(this IMessageReader reader, Game game) - where T : InnerNetObject - { - return game.FindObjectByNetId(reader.ReadPackedUInt32()); - } - } -} \ No newline at end of file diff --git a/src/Impostor.Server/Extensions/ServiceProviderExtensions.cs b/src/Impostor.Server/Extensions/ServiceProviderExtensions.cs new file mode 100644 index 000000000..eee14806d --- /dev/null +++ b/src/Impostor.Server/Extensions/ServiceProviderExtensions.cs @@ -0,0 +1,22 @@ +using Impostor.Server.Events.Player; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.ObjectPool; + +namespace Impostor.Server +{ + public static class ServiceProviderExtensions + { + public static void AddEventPools(this IServiceCollection services) + { + services.TryAddSingleton(new DefaultObjectPoolProvider()); + + services.AddSingleton(serviceProvider => + { + var provider = serviceProvider.GetRequiredService(); + var policy = ActivatorUtilities.CreateInstance(serviceProvider); + return provider.Create(policy); + }); + } + } +} diff --git a/src/Impostor.Server/Impostor.Server.csproj b/src/Impostor.Server/Impostor.Server.csproj index ad5a6db05..663f7af43 100644 --- a/src/Impostor.Server/Impostor.Server.csproj +++ b/src/Impostor.Server/Impostor.Server.csproj @@ -16,7 +16,6 @@ Impostor.Server Impostor.Server Copyright © AeonLucid 2020 - 1.0.0 @@ -35,6 +34,8 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + + @@ -55,4 +56,4 @@ - \ No newline at end of file + diff --git a/src/Impostor.Server/Net/AnnouncementsService.cs b/src/Impostor.Server/Net/AnnouncementsService.cs new file mode 100644 index 000000000..d205045e7 --- /dev/null +++ b/src/Impostor.Server/Net/AnnouncementsService.cs @@ -0,0 +1,98 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; +using Impostor.Api.Events.Managers; +using Impostor.Api.Innersloth; +using Impostor.Api.Net.Messages; +using Impostor.Api.Net.Messages.Announcements; +using Impostor.Hazel; +using Impostor.Hazel.Udp; +using Impostor.Server.Config; +using Impostor.Server.Events.Announcements; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.ObjectPool; +using Microsoft.Extensions.Options; + +namespace Impostor.Server.Net +{ + internal class AnnouncementsService : IHostedService + { + private readonly AnnouncementsServerConfig _config; + private readonly ObjectPool _readerPool; + private readonly IEventManager _eventManager; + private UdpConnectionListener _connection; + + public AnnouncementsService(IOptions config, ObjectPool readerPool, IEventManager eventManager) + { + _config = config.Value; + _readerPool = readerPool; + _eventManager = eventManager; + } + + public async Task StartAsync(CancellationToken cancellationToken) + { + var endpoint = new IPEndPoint(IPAddress.Parse(_config.ResolveListenIp()), _config.ListenPort); + + var mode = endpoint.AddressFamily switch + { + AddressFamily.InterNetwork => IPMode.IPv4, + AddressFamily.InterNetworkV6 => IPMode.IPv6, + _ => throw new InvalidOperationException() + }; + + _connection = new UdpConnectionListener(endpoint, _readerPool, mode) + { + NewConnection = OnNewConnection, + }; + + await _connection.StartAsync(); + } + + public async Task StopAsync(CancellationToken cancellationToken) + { + await _connection.DisposeAsync(); + } + + private async ValueTask OnNewConnection(NewConnectionEventArgs e) + { + MessageHello.Deserialize(e.HandshakeData, out var announcementVersion, out var id, out var language); + + if (announcementVersion != 2) + { + await e.Connection.Disconnect("Unsupported announcement version"); + return; + } + + var @event = new AnnouncementRequestEvent(id, language); + await _eventManager.CallAsync(@event); + + var response = @event.Response; + + if (response.UseCached) + { + using var writer = MessageWriter.Get(MessageType.Reliable); + Message00UseCache.Serialize(writer); + await e.Connection.SendAsync(writer); + } + + if (response.Announcement != null) + { + using var writer = MessageWriter.Get(MessageType.Reliable); + var announcement = response.Announcement.Value; + Message01Update.Serialize(writer, announcement.Id, announcement.Message); + await e.Connection.SendAsync(writer); + } + + if (response.FreeWeekendState != FreeWeekendState.NotFree) + { + using var writer = MessageWriter.Get(MessageType.Reliable); + Message02SetFreeWeekend.Serialize(writer, response.FreeWeekendState); + await e.Connection.SendAsync(writer); + } + + await e.Connection.Disconnect(null); + } + } +} diff --git a/src/Impostor.Server/Net/Client.cs b/src/Impostor.Server/Net/Client.cs index 87a1bb40e..143a0d103 100644 --- a/src/Impostor.Server/Net/Client.cs +++ b/src/Impostor.Server/Net/Client.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using Impostor.Api; using Impostor.Api.Games; @@ -7,6 +8,7 @@ using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.C2S; using Impostor.Api.Net.Messages.S2C; +using Impostor.Api.Reactor; using Impostor.Hazel; using Impostor.Server.Config; using Impostor.Server.Net.Manager; @@ -22,8 +24,8 @@ internal class Client : ClientBase private readonly ClientManager _clientManager; private readonly GameManager _gameManager; - public Client(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, IHazelConnection connection) - : base(name, connection) + public Client(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, IHazelConnection connection, ISet mods) + : base(name, connection, mods) { _logger = logger; _antiCheatConfig = antiCheatOptions.Value; @@ -31,6 +33,25 @@ public Client(ILogger logger, IOptions antiCheatOptions _gameManager = gameManager; } + public override async ValueTask ReportCheatAsync(CheatContext context, string message) + { + _logger.LogWarning("Client {Name} ({Id}) was caught cheating: [{Context}] {Message}", Name, Id, context.Name, message); + + if (!_antiCheatConfig.Enabled) + { + return false; + } + + if (_antiCheatConfig.BanIpFromGame) + { + Player?.Game.BanIp(Connection.EndPoint.Address); + } + + await DisconnectAsync(DisconnectReason.Hacking, context.Name + ": " + message); + + return true; + } + public override async ValueTask HandleMessageAsync(IMessageReader reader, MessageType messageType) { var flag = reader.Tag; @@ -150,38 +171,25 @@ public override async ValueTask HandleMessageAsync(IMessageReader reader, Messag // Handle packet. using var readerCopy = reader.Copy(); - // TODO: Return value, either a bool (to cancel) or a writer (to cancel (null) or modify/overwrite). - try + var verified = await Player.Game.HandleGameDataAsync(readerCopy, Player, toPlayer); + if (verified) { - var verified = await Player.Game.HandleGameDataAsync(readerCopy, Player, toPlayer); - if (verified) + // Broadcast packet to all other players. + using (var writer = MessageWriter.Get(messageType)) { - // Broadcast packet to all other players. - using (var writer = MessageWriter.Get(messageType)) + if (toPlayer) { - if (toPlayer) - { - var target = reader.ReadPackedInt32(); - reader.CopyTo(writer); - await Player.Game.SendToAsync(writer, target); - } - else - { - reader.CopyTo(writer); - await Player.Game.SendToAllExceptAsync(writer, Id); - } + var target = reader.ReadPackedInt32(); + reader.CopyTo(writer); + await Player.Game.SendToAsync(writer, target); + } + else + { + reader.CopyTo(writer); + await Player.Game.SendToAllExceptAsync(writer, Id); } } } - catch (ImpostorCheatException e) - { - if (_antiCheatConfig.BanIpFromGame) - { - Player.Game.BanIp(Connection.EndPoint.Address); - } - - await DisconnectAsync(DisconnectReason.Hacking, e.Message); - } break; } @@ -196,7 +204,7 @@ public override async ValueTask HandleMessageAsync(IMessageReader reader, Messag Message08EndGameC2S.Deserialize( reader, out var gameOverReason); - + await Player.Game.HandleEndGame(reader, gameOverReason); break; } diff --git a/src/Impostor.Server/Net/ClientBase.cs b/src/Impostor.Server/Net/ClientBase.cs index 527919256..bae1fb33f 100644 --- a/src/Impostor.Server/Net/ClientBase.cs +++ b/src/Impostor.Server/Net/ClientBase.cs @@ -1,11 +1,14 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; +using Impostor.Api; using Impostor.Api.Innersloth; using Impostor.Api.Net; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.S2C; +using Impostor.Api.Reactor; using Impostor.Hazel; using Impostor.Server.Net.State; @@ -13,17 +16,34 @@ namespace Impostor.Server.Net { internal abstract class ClientBase : IClient { - protected ClientBase(string name, IHazelConnection connection) + protected ClientBase(string name, IHazelConnection connection, ISet mods) { Name = name; Connection = connection; + Mods = mods; Items = new ConcurrentDictionary(); + + ModIdMap = new Dictionary(); + + var i = -1; + + foreach (var mod in mods.OrderBy(x => x.Id)) + { + if (mod.Side == PluginSide.Both) + { + ModIdMap[i--] = mod.Id; + } + } } public int Id { get; set; } public string Name { get; } + public ISet Mods { get; } + + public Dictionary ModIdMap { get; } + public IHazelConnection Connection { get; } public IDictionary Items { get; } @@ -32,6 +52,11 @@ protected ClientBase(string name, IHazelConnection connection) IClientPlayer? IClient.Player => Player; + public virtual ValueTask ReportCheatAsync(CheatContext context, string message) + { + return new ValueTask(false); + } + public abstract ValueTask HandleMessageAsync(IMessageReader message, MessageType messageType); public abstract ValueTask HandleDisconnectAsync(string reason); diff --git a/src/Impostor.Server/Net/Factories/ClientFactory.cs b/src/Impostor.Server/Net/Factories/ClientFactory.cs index ad1fdc778..ab6eedf61 100644 --- a/src/Impostor.Server/Net/Factories/ClientFactory.cs +++ b/src/Impostor.Server/Net/Factories/ClientFactory.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using Impostor.Api.Net; +using Impostor.Api.Reactor; using Microsoft.Extensions.DependencyInjection; namespace Impostor.Server.Net.Factories @@ -14,9 +16,9 @@ public ClientFactory(IServiceProvider serviceProvider) _serviceProvider = serviceProvider; } - public ClientBase Create(IHazelConnection connection, string name, int clientVersion) + public ClientBase Create(IHazelConnection connection, string name, int clientVersion, ISet mods) { - var client = ActivatorUtilities.CreateInstance(_serviceProvider, name, connection); + var client = ActivatorUtilities.CreateInstance(_serviceProvider, name, connection, mods); connection.Client = client; return client; } diff --git a/src/Impostor.Server/Net/Factories/IClientFactory.cs b/src/Impostor.Server/Net/Factories/IClientFactory.cs index 6859ae3c9..bec1b79ba 100644 --- a/src/Impostor.Server/Net/Factories/IClientFactory.cs +++ b/src/Impostor.Server/Net/Factories/IClientFactory.cs @@ -1,9 +1,11 @@ -using Impostor.Api.Net; +using System.Collections.Generic; +using Impostor.Api.Net; +using Impostor.Api.Reactor; namespace Impostor.Server.Net.Factories { internal interface IClientFactory { - ClientBase Create(IHazelConnection connection, string name, int clientVersion); + ClientBase Create(IHazelConnection connection, string name, int clientVersion, ISet mods); } } \ No newline at end of file diff --git a/src/Impostor.Server/Net/Inner/InnerNetObject.Anticheat.cs b/src/Impostor.Server/Net/Inner/InnerNetObject.Anticheat.cs new file mode 100644 index 000000000..28b3457e4 --- /dev/null +++ b/src/Impostor.Server/Net/Inner/InnerNetObject.Anticheat.cs @@ -0,0 +1,98 @@ +using System.Threading.Tasks; +using Impostor.Api; +using Impostor.Api.Net; +using Impostor.Server.Net.Inner.Objects; + +namespace Impostor.Server.Net.Inner +{ + internal abstract partial class InnerNetObject + { + protected async ValueTask ValidateOwnership(CheatContext context, IClientPlayer sender) + { + if (!sender.IsOwner(this)) + { + if (await sender.Client.ReportCheatAsync(context, $"Failed ownership check on {GetType().Name}")) + { + return false; + } + } + + return true; + } + + protected async ValueTask ValidateHost(CheatContext context, IClientPlayer sender) + { + if (!sender.IsHost) + { + if (await sender.Client.ReportCheatAsync(context, "Failed host check")) + { + return false; + } + } + + return true; + } + + protected async ValueTask ValidateTarget(CheatContext context, IClientPlayer sender, IClientPlayer? target) + { + if (target == null) + { + if (await sender.Client.ReportCheatAsync(context, "Failed target check")) + { + return false; + } + } + + return true; + } + + protected async ValueTask ValidateBroadcast(CheatContext context, IClientPlayer sender, IClientPlayer? target) + { + if (target != null) + { + if (await sender.Client.ReportCheatAsync(context, "Failed broadcast check")) + { + return false; + } + } + + return true; + } + + protected async ValueTask ValidateCmd(CheatContext context, IClientPlayer sender, IClientPlayer? target) + { + if (target == null || !target.IsHost) + { + if (await sender.Client.ReportCheatAsync(context, "Failed cmd check")) + { + return false; + } + } + + return true; + } + + protected async ValueTask ValidateImpostor(CheatContext context, IClientPlayer sender, InnerPlayerInfo playerInfo, bool value = true) + { + if (playerInfo.IsImpostor != value) + { + if (await sender.Client.ReportCheatAsync(context, "Failed impostor check")) + { + return false; + } + } + + return true; + } + + protected async ValueTask UnregisteredCall(CheatContext context, IClientPlayer sender) + { + if (await sender.Client.ReportCheatAsync(context, "Client sent unregistered call")) + { + return false; + } + + return true; + } + } +} diff --git a/src/Impostor.Server/Net/Inner/InnerNetObject.cs b/src/Impostor.Server/Net/Inner/InnerNetObject.cs index 78f1a55cd..9579fe0ad 100644 --- a/src/Impostor.Server/Net/Inner/InnerNetObject.cs +++ b/src/Impostor.Server/Net/Inner/InnerNetObject.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; using Impostor.Api.Net; using Impostor.Api.Net.Inner; using Impostor.Api.Net.Messages; @@ -6,7 +7,7 @@ namespace Impostor.Server.Net.Inner { - internal abstract class InnerNetObject : GameObject, IInnerNetObject + internal abstract partial class InnerNetObject : GameObject, IInnerNetObject { private const int HostInheritId = -2; @@ -16,16 +17,31 @@ internal abstract class InnerNetObject : GameObject, IInnerNetObject public SpawnFlags SpawnFlags { get; internal set; } - public abstract ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader); - - public abstract bool Serialize(IMessageWriter writer, bool initialState); - - public abstract void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState); - public bool IsOwnedBy(IClientPlayer player) { return OwnerId == player.Client.Id || (OwnerId == HostInheritId && player.IsHost); } + + public abstract ValueTask SerializeAsync(IMessageWriter writer, bool initialState); + + public abstract ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState); + + public abstract ValueTask HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader); + + protected ValueTask HandleCustomRpc(IMessageReader reader, Game game) + { + var lengthOrShortId = reader.ReadPackedInt32(); + + var pluginId = lengthOrShortId < 0 + ? game.Host!.Client.ModIdMap[lengthOrShortId] + : reader.ReadString(lengthOrShortId); + + var id = reader.ReadPackedInt32(); + + // TODO handle custom rpcs + + return ValueTask.FromResult(true); + } } -} \ No newline at end of file +} 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 6cdd6b91f..56ff96e59 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.Api.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.Api.cs @@ -11,12 +11,12 @@ public async ValueTask SnapToAsync(Vector2 position) var minSid = (ushort)(_lastSequenceId + 5U); // Snap in the server. - SnapTo(position, minSid); + await SnapToAsync(_game.GetClientPlayer(OwnerId), position, minSid); // Broadcast to all clients. using (var writer = _game.StartRpc(NetId, RpcCalls.SnapTo)) { - WriteVector2(writer, position); + writer.Write(position); writer.Write(_lastSequenceId); await _game.FinishRpcAsync(writer); } diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs index d261c11e0..80dd6adf6 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs @@ -1,125 +1,84 @@ -using System.Numerics; +using System.Collections.Generic; +using System.Numerics; using System.Threading.Tasks; using Impostor.Api; -using Impostor.Api.Innersloth; +using Impostor.Api.Events.Managers; using Impostor.Api.Net; using Impostor.Api.Net.Messages; +using Impostor.Api.Net.Messages.Rpcs; +using Impostor.Server.Events.Player; using Impostor.Server.Net.State; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ObjectPool; namespace Impostor.Server.Net.Inner.Objects.Components { internal partial class InnerCustomNetworkTransform : InnerNetObject { - private static readonly FloatRange XRange = new FloatRange(-40f, 40f); - private static readonly FloatRange YRange = new FloatRange(-40f, 40f); - private readonly ILogger _logger; private readonly InnerPlayerControl _playerControl; private readonly Game _game; + private readonly IEventManager _eventManager; + private readonly ObjectPool _pool; private ushort _lastSequenceId; - private Vector2 _targetSyncPosition; - private Vector2 _targetSyncVelocity; - public InnerCustomNetworkTransform(ILogger logger, InnerPlayerControl playerControl, Game game) + 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; _playerControl = playerControl; _game = game; + _game = game; + _eventManager = eventManager; + _pool = pool; } private static bool SidGreaterThan(ushort newSid, ushort prevSid) { - var num = (ushort)(prevSid + (uint) short.MaxValue); + var num = (ushort)(prevSid + (uint)short.MaxValue); - return (int) prevSid < (int) num + return (int)prevSid < (int)num ? newSid > prevSid && newSid <= num : newSid > prevSid || newSid <= num; } - private static void WriteVector2(IMessageWriter writer, Vector2 vec) - { - writer.Write((ushort)(XRange.ReverseLerp(vec.X) * (double) ushort.MaxValue)); - writer.Write((ushort)(YRange.ReverseLerp(vec.Y) * (double) ushort.MaxValue)); - } - - private static Vector2 ReadVector2(IMessageReader reader) - { - var v1 = reader.ReadUInt16() / (float) ushort.MaxValue; - var v2 = reader.ReadUInt16() / (float) ushort.MaxValue; - - return new Vector2(XRange.Lerp(v1), YRange.Lerp(v2)); - } - - public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) - { - if (call == RpcCalls.SnapTo) - { - if (!sender.IsOwner(this)) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SnapTo)} to an unowned {nameof(InnerPlayerControl)}"); - } - - if (target != null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SnapTo)} to a specific player instead of broadcast"); - } - - if (!sender.Character.PlayerInfo.IsImpostor) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SnapTo)} as crewmate"); - } - - SnapTo(ReadVector2(reader), reader.ReadUInt16()); - } - else - { - _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerCustomNetworkTransform), call); - } - - return default; - } - - public override bool Serialize(IMessageWriter writer, bool initialState) + public override ValueTask SerializeAsync(IMessageWriter writer, bool initialState) { if (initialState) { writer.Write(_lastSequenceId); - WriteVector2(writer, _targetSyncPosition); - WriteVector2(writer, _targetSyncVelocity); - return true; + writer.Write(Position); + writer.Write(Velocity); + return new ValueTask(true); } // TODO: DirtyBits == 0 return false. _lastSequenceId++; writer.Write(_lastSequenceId); - WriteVector2(writer, _targetSyncPosition); - WriteVector2(writer, _targetSyncVelocity); - return true; + writer.Write(Position); + writer.Write(Velocity); + return new ValueTask(true); } - public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) + public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) { var sequenceId = reader.ReadUInt16(); if (initialState) { _lastSequenceId = sequenceId; - _targetSyncPosition = ReadVector2(reader); - _targetSyncVelocity = ReadVector2(reader); + await SetPositionAsync(sender, reader.ReadVector2(), reader.ReadVector2()); } else { - if (!sender.IsOwner(this)) + if (!await ValidateOwnership(CheatContext.Deserialize, sender) || !await ValidateBroadcast(CheatContext.Deserialize, sender, target)) { - throw new ImpostorCheatException($"Client attempted to send unowned {nameof(InnerCustomNetworkTransform)} data"); - } - - if (target != null) - { - throw new ImpostorCheatException($"Client attempted to send {nameof(InnerCustomNetworkTransform)} data to a specific player, must be broadcast"); + return; } if (!SidGreaterThan(sequenceId, _lastSequenceId)) @@ -128,21 +87,48 @@ public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IM } _lastSequenceId = sequenceId; - _targetSyncPosition = ReadVector2(reader); - _targetSyncVelocity = ReadVector2(reader); + await SetPositionAsync(sender, reader.ReadVector2(), reader.ReadVector2()); } } - private void SnapTo(Vector2 position, ushort minSid) + public override async ValueTask HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) + { + if (call == RpcCalls.SnapTo) + { + if (!await ValidateOwnership(call, sender) || !await ValidateImpostor(RpcCalls.MurderPlayer, sender, _playerControl.PlayerInfo)) + { + return false; + } + + Rpc21SnapTo.Deserialize(reader, out var position, out var minSid); + + await SnapToAsync(sender, position, minSid); + return true; + } + + return await UnregisteredCall(call, sender); + } + + internal async ValueTask SetPositionAsync(IClientPlayer sender, Vector2 position, Vector2 velocity) + { + Position = position; + Velocity = velocity; + + var playerMovementEvent = _pool.Get(); + playerMovementEvent.Reset(_game, sender, _playerControl); + await _eventManager.CallAsync(playerMovementEvent); + _pool.Return(playerMovementEvent); + } + + private ValueTask SnapToAsync(IClientPlayer sender, Vector2 position, ushort minSid) { if (!SidGreaterThan(minSid, _lastSequenceId)) { - return; + return default; } _lastSequenceId = minSid; - _targetSyncPosition = position; - _targetSyncVelocity = Vector2.Zero; + return SetPositionAsync(sender, position, Velocity); } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs index 29bc9962d..69f8dcd81 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs @@ -1,10 +1,11 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; -using Impostor.Api; using Impostor.Api.Events.Managers; using Impostor.Api.Innersloth; using Impostor.Api.Net; using Impostor.Api.Net.Messages; +using Impostor.Api.Net.Messages.Rpcs; using Impostor.Server.Events.Player; using Impostor.Server.Net.State; using Microsoft.Extensions.Logging; @@ -26,45 +27,45 @@ public InnerPlayerPhysics(ILogger logger, InnerPlayerControl _game = game; } - public override async ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) + public override ValueTask SerializeAsync(IMessageWriter writer, bool initialState) { - if (call != RpcCalls.EnterVent && call != RpcCalls.ExitVent) - { - _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerPlayerPhysics), call); - return; - } + throw new NotImplementedException(); + } - if (!sender.IsOwner(this)) - { - throw new ImpostorCheatException($"Client sent {call} to an unowned {nameof(InnerPlayerControl)}"); - } + public override ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) + { + throw new NotImplementedException(); + } - if (target != null) + public override async ValueTask HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) + { + if (!await ValidateOwnership(call, sender) || !await ValidateImpostor(RpcCalls.MurderPlayer, sender, _playerControl.PlayerInfo)) { - throw new ImpostorCheatException($"Client sent {call} to a specific player instead of broadcast"); + return false; } - if (!sender.Character.PlayerInfo.IsImpostor) + int ventId; + + switch (call) { - throw new ImpostorCheatException($"Client sent {call} as crewmate"); - } + case RpcCalls.EnterVent: + Rpc19EnterVent.Deserialize(reader, out ventId); + break; - var ventId = reader.ReadPackedUInt32(); - var ventEnter = call == RpcCalls.EnterVent; + case RpcCalls.ExitVent: + Rpc19EnterVent.Deserialize(reader, out ventId); + break; - await _eventManager.CallAsync(new PlayerVentEvent(_game, sender, _playerControl, (VentLocation)ventId, ventEnter)); + case RpcCalls.CustomRpc: + return await HandleCustomRpc(reader, _game); - return; - } + default: + return await UnregisteredCall(call, sender); + } - public override bool Serialize(IMessageWriter writer, bool initialState) - { - throw new NotImplementedException(); - } + await _eventManager.CallAsync(new PlayerVentEvent(_game, sender, _playerControl, (VentLocation)ventId, call == RpcCalls.EnterVent)); - public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) - { - throw new NotImplementedException(); + return true; } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerVoteBanSystem.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerVoteBanSystem.cs index 58b9b54a2..117f78e6d 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerVoteBanSystem.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerVoteBanSystem.cs @@ -5,6 +5,7 @@ using Impostor.Api.Net; using Impostor.Api.Net.Inner.Objects; using Impostor.Api.Net.Messages; +using Impostor.Api.Net.Messages.Rpcs; using Impostor.Server.Net.State; using Microsoft.Extensions.Logging; @@ -21,42 +22,16 @@ public InnerVoteBanSystem(ILogger logger) _votes = new Dictionary(); } - public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) - { - if (call != RpcCalls.AddVote) - { - _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerVoteBanSystem), call); - return default; - } - - var clientId = reader.ReadInt32(); - if (clientId != sender.Client.Id) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.AddVote)} as other client"); - } - - if (target != null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CastVote)} to wrong destinition, must be broadcast"); - } - - var targetClientId = reader.ReadInt32(); - - // TODO: Use. - - return default; - } - - public override bool Serialize(IMessageWriter writer, bool initialState) + public override ValueTask SerializeAsync(IMessageWriter writer, bool initialState) { throw new NotImplementedException(); } - public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) + public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) { - if (!sender.IsHost) + if (!await ValidateHost(CheatContext.Deserialize, sender)) { - throw new ImpostorCheatException($"Client attempted to send data for {nameof(InnerShipStatus)} as non-host"); + return; } var votes = _votes; @@ -84,5 +59,30 @@ public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IM } } } + + public override async ValueTask HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) + { + if (call == RpcCalls.AddVote) + { + if (!await ValidateOwnership(call, sender)) + { + return false; + } + + Rpc26AddVote.Deserialize(reader, out var clientId, out var targetClientId); + + if (clientId != sender.Client.Id) + { + if (await sender.Client.ReportCheatAsync(RpcCalls.AddVote, $"Client sent {nameof(RpcCalls.AddVote)} as other client")) + { + return false; + } + } + + return true; + } + + return await UnregisteredCall(call, sender); + } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs index ed6803888..0b2dbf4a5 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Threading.Tasks; using Impostor.Api; -using Impostor.Api.Innersloth; using Impostor.Api.Net; using Impostor.Api.Net.Inner.Objects; using Impostor.Api.Net.Messages; +using Impostor.Api.Net.Messages.Rpcs; using Impostor.Server.Net.Inner.Objects.Components; using Impostor.Server.Net.State; using Microsoft.Extensions.DependencyInjection; @@ -44,41 +44,59 @@ public InnerGameData(ILogger logger, Game game, IServiceProvider return _allPlayers.TryGetValue(id, out var player) ? player : null; } - public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) + public override ValueTask SerializeAsync(IMessageWriter writer, bool initialState) { - switch (call) + throw new NotImplementedException(); + } + + public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) + { + if (!await ValidateHost(CheatContext.Deserialize, sender)) { - case RpcCalls.SetTasks: + return; + } + + if (initialState) + { + var num = reader.ReadPackedInt32(); + + for (var i = 0; i < num; i++) { - if (!sender.IsHost) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetTasks)} but was not a host"); - } + var playerId = reader.ReadByte(); + var playerInfo = new InnerPlayerInfo(playerId); + + playerInfo.Deserialize(reader); - if (target != null) + if (!_allPlayers.TryAdd(playerInfo.PlayerId, playerInfo)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetTasks)} to a specific player instead of broadcast"); + throw new ImpostorException("Failed to add player to InnerGameData."); } + } + } + else + { + throw new NotImplementedException("This shouldn't happen, according to Among Us disassembly."); + } + } - var playerId = reader.ReadByte(); - var taskTypeIds = reader.ReadBytesAndSize(); + public override async ValueTask HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) + { + if (!await ValidateHost(call, sender)) + { + return false; + } + switch (call) + { + case RpcCalls.SetTasks: + { + Rpc29SetTasks.Deserialize(reader, out var playerId, out var taskTypeIds); SetTasks(playerId, taskTypeIds); break; } case RpcCalls.UpdateGameData: { - if (!sender.IsHost) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetTasks)} but was not a host"); - } - - if (target != null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetTasks)} to a specific player instead of broadcast"); - } - while (reader.Position < reader.Length) { using var message = reader.ReadMessage(); @@ -103,49 +121,14 @@ public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, R break; } - default: - { - _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerGameData), call); - break; - } - } - - return default; - } - - public override bool Serialize(IMessageWriter writer, bool initialState) - { - throw new NotImplementedException(); - } + case RpcCalls.CustomRpc: + return await HandleCustomRpc(reader, _game); - public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) - { - if (!sender.IsHost) - { - throw new ImpostorCheatException($"Client attempted to send data for {nameof(InnerGameData)} as non-host"); + default: + return await UnregisteredCall(call, sender); } - if (initialState) - { - var num = reader.ReadPackedInt32(); - - for (var i = 0; i < num; i++) - { - var playerId = reader.ReadByte(); - var playerInfo = new InnerPlayerInfo(playerId); - - playerInfo.Deserialize(reader); - - if (!_allPlayers.TryAdd(playerInfo.PlayerId, playerInfo)) - { - throw new ImpostorException("Failed to add player to InnerGameData."); - } - } - } - else - { - throw new NotImplementedException("This shouldn't happen, according to Among Us disassembly."); - } + return true; } internal void AddPlayer(InnerPlayerControl control) diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs b/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs index 63448edd2..78be5bd23 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs @@ -18,19 +18,19 @@ public InnerLobbyBehaviour(IGame game) Components.Add(this); } - public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) + public override ValueTask SerializeAsync(IMessageWriter writer, bool initialState) { throw new System.NotImplementedException(); } - public override bool Serialize(IMessageWriter writer, bool initialState) + public override ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) { throw new System.NotImplementedException(); } - public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) + public override ValueTask HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) { throw new System.NotImplementedException(); } } -} \ 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 c2bcb9d9d..96d829fb8 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Impostor.Api; @@ -6,6 +7,7 @@ using Impostor.Api.Innersloth; using Impostor.Api.Net; using Impostor.Api.Net.Messages; +using Impostor.Api.Net.Messages.Rpcs; using Impostor.Server.Events.Meeting; using Impostor.Server.Events.Player; using Impostor.Server.Net.State; @@ -46,131 +48,141 @@ private void PopulateButtons(byte reporter) .ToArray(); } - public override async ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) + public override ValueTask SerializeAsync(IMessageWriter writer, bool initialState) { - switch (call) + throw new NotImplementedException(); + } + + public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) + { + if (!await ValidateHost(CheatContext.Deserialize, sender) || !await ValidateBroadcast(CheatContext.Deserialize, sender, target)) { - case RpcCalls.Close: + return; + } + + if (initialState) + { + PopulateButtons(0); + + foreach (var playerState in _playerStates) { - if (!sender.IsHost) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.Close)} but was not a host"); - } + playerState.Deserialize(reader); - if (target != null) + if (playerState.DidReport) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.Close)} to a specific player instead of broadcast"); + ReporterId = playerState.TargetPlayerId; } - - break; } + } + else + { + var num = reader.ReadPackedUInt32(); - case RpcCalls.VotingComplete: + for (var i = 0; i < _playerStates.Length; i++) { - if (!sender.IsHost) + if ((num & 1 << i) != 0) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.VotingComplete)} but was not a host"); + _playerStates[i].Deserialize(reader); } + } + } + } - if (target != null) + public override async ValueTask HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) + { + switch (call) + { + case RpcCalls.Close: + { + if (!await ValidateHost(call, sender)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.VotingComplete)} to a specific player instead of broadcast"); + return false; } - var states = reader.ReadBytesAndSize(); - var playerId = reader.ReadByte(); - var tie = reader.ReadBoolean(); + Rpc22Close.Deserialize(reader); + break; + } - if (playerId != byte.MaxValue) + case RpcCalls.VotingComplete: + { + if (!await ValidateHost(call, sender)) { - var player = _game.GameNet.GameData.GetPlayerById(playerId); - if (player != null) - { - player.Controller.Die(DeathReason.Exile); - await _eventManager.CallAsync(new PlayerExileEvent(_game, sender, player.Controller)); - } + return false; } - await _eventManager.CallAsync(new MeetingEndedEvent(_game, this)); - + Rpc23VotingComplete.Deserialize(reader, out var states, out var playerId, out var tie); + await HandleVotingComplete(sender, states, playerId, tie); break; } case RpcCalls.CastVote: { - var srcPlayerId = reader.ReadByte(); - if (srcPlayerId != sender.Character.PlayerId) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CastVote)} to an unowned {nameof(InnerPlayerControl)}"); - } - - // Host broadcasts vote to others. - if (sender.IsHost && target != null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CastVote)} to a specific player instead of broadcast"); - } + Rpc24CastVote.Deserialize(reader, out var playerId, out var suspectPlayerId); + return await HandleCastVote(sender, target, playerId, suspectPlayerId); + } - // Player sends vote to host. - if (target == null || !target.IsHost) + case RpcCalls.ClearVote: + { + if (!await ValidateHost(call, sender)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CastVote)} to wrong destinition, must be host"); + return false; } - var targetPlayerId = reader.ReadByte(); + Rpc25ClearVote.Deserialize(reader); break; } + case RpcCalls.CustomRpc: + return await HandleCustomRpc(reader, _game); + default: - { - _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerMeetingHud), call); - break; - } + return await UnregisteredCall(call, sender); } - } - public override bool Serialize(IMessageWriter writer, bool initialState) - { - throw new NotImplementedException(); + return true; } - public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) + private async ValueTask HandleVotingComplete(ClientPlayer sender, ReadOnlyMemory states, byte playerId, bool tie) { - if (!sender.IsHost) + if (playerId != byte.MaxValue) { - throw new ImpostorCheatException($"Client attempted to send data for {nameof(InnerMeetingHud)} as non-host"); + var player = _game.GameNet.GameData.GetPlayerById(playerId); + if (player != null) + { + player.Controller.Die(DeathReason.Exile); + await _eventManager.CallAsync(new PlayerExileEvent(_game, sender, player.Controller)); + } } - if (target != null) - { - throw new ImpostorCheatException($"Client attempted to send {nameof(InnerMeetingHud)} data to a specific player, must be broadcast"); - } + await _eventManager.CallAsync(new MeetingEndedEvent(_game, this)); + } - if (initialState) + private async ValueTask HandleCastVote(ClientPlayer sender, ClientPlayer? target, byte playerId, sbyte suspectPlayerId) + { + if (sender.IsHost) { - PopulateButtons(0); - - foreach (var playerState in _playerStates) + if (!await ValidateBroadcast(RpcCalls.CastVote, sender, target)) { - playerState.Deserialize(reader); - - if (playerState.DidReport) - { - ReporterId = playerState.TargetPlayerId; - } + return false; } } else { - var num = reader.ReadPackedUInt32(); + if (!await ValidateCmd(RpcCalls.CastVote, sender, target)) + { + return false; + } + } - for (var i = 0; i < _playerStates.Length; i++) + if (playerId != sender.Character!.PlayerId) + { + if (await sender.Client.ReportCheatAsync(RpcCalls.CastVote, $"Client sent {nameof(RpcCalls.CastVote)} to an unowned {nameof(InnerPlayerControl)}")) { - if ((num & 1 << i) != 0) - { - _playerStates[i].Deserialize(reader); - } + return false; } } + + return true; } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs index 0a7997d5c..07c21267c 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs @@ -2,9 +2,9 @@ using Impostor.Api; using Impostor.Api.Innersloth; using Impostor.Api.Innersloth.Customization; -using Impostor.Api.Net; using Impostor.Api.Net.Inner.Objects; using Impostor.Api.Net.Inner.Objects.Components; +using Impostor.Api.Net.Messages.Rpcs; using Impostor.Server.Events.Player; namespace Impostor.Server.Net.Inner.Objects @@ -26,62 +26,42 @@ public async ValueTask SetNameAsync(string name) await _game.FinishRpcAsync(writer); } - public async ValueTask SetColorAsync(byte colorId) + public async ValueTask SetColorAsync(ColorType color) { - PlayerInfo.ColorId = colorId; + PlayerInfo.Color = color; using var writer = _game.StartRpc(NetId, RpcCalls.SetColor); - writer.Write(colorId); + Rpc08SetColor.Serialize(writer, color); await _game.FinishRpcAsync(writer); } - public ValueTask SetColorAsync(ColorType colorType) + public async ValueTask SetHatAsync(HatType hat) { - return SetColorAsync((byte)colorType); - } - - public async ValueTask SetHatAsync(uint hatId) - { - PlayerInfo.HatId = hatId; + PlayerInfo.Hat = hat; using var writer = _game.StartRpc(NetId, RpcCalls.SetHat); - writer.WritePacked(hatId); + Rpc09SetHat.Serialize(writer, hat); await _game.FinishRpcAsync(writer); } - public ValueTask SetHatAsync(HatType hatType) + public async ValueTask SetPetAsync(PetType pet) { - return SetHatAsync((uint)hatType); - } - - public async ValueTask SetPetAsync(uint petId) - { - PlayerInfo.PetId = petId; + PlayerInfo.Pet = pet; using var writer = _game.StartRpc(NetId, RpcCalls.SetPet); - writer.WritePacked(petId); + Rpc17SetPet.Serialize(writer, pet); await _game.FinishRpcAsync(writer); } - public ValueTask SetPetAsync(PetType petType) - { - return SetPetAsync((uint)petType); - } - - public async ValueTask SetSkinAsync(uint skinId) + public async ValueTask SetSkinAsync(SkinType skin) { - PlayerInfo.SkinId = skinId; + PlayerInfo.Skin = skin; using var writer = _game.StartRpc(NetId, RpcCalls.SetSkin); - writer.WritePacked(skinId); + Rpc10SetSkin.Serialize(writer, skin); await _game.FinishRpcAsync(writer); } - public ValueTask SetSkinAsync(SkinType skinType) - { - return SetSkinAsync((uint)skinType); - } - public async ValueTask SendChatAsync(string text) { using var writer = _game.StartRpc(NetId, RpcCalls.SendChat); @@ -101,38 +81,30 @@ public async ValueTask SendChatToPlayerAsync(string text, IInnerPlayerControl? p await _game.FinishRpcAsync(writer, player.OwnerId); } - public async ValueTask SetMurderedByAsync(IClientPlayer impostor) + public async ValueTask MurderPlayerAsync(IInnerPlayerControl target) { - if (impostor.Character == null) - { - throw new ImpostorException("Character is null."); - } - - if (!impostor.Character.PlayerInfo.IsImpostor) + if (!PlayerInfo.IsImpostor) { - throw new ImpostorProtocolException("Plugin tried to murder a player while the impostor specified was not an impostor."); + throw new ImpostorProtocolException("Tried to murder a player, but murderer was not the impostor."); } - if (impostor.Character.PlayerInfo.IsDead) + if (PlayerInfo.IsDead) { - throw new ImpostorProtocolException("Plugin tried to murder a player while the impostor specified was dead."); + throw new ImpostorProtocolException("Tried to murder a player, but murderer was not alive."); } - if (PlayerInfo.IsDead) + if (target.PlayerInfo.IsDead) { - return; + throw new ImpostorProtocolException("Tried to murder a player, but target was not alive."); } - // Update player. - Die(DeathReason.Kill); + ((InnerPlayerControl)target).Die(DeathReason.Kill); - // Send RPC. - using var writer = _game.StartRpc(impostor.Character.NetId, RpcCalls.MurderPlayer); - writer.WritePacked(NetId); + using var writer = _game.StartRpc(NetId, RpcCalls.MurderPlayer); + Rpc12MurderPlayer.Serialize(writer, target); await _game.FinishRpcAsync(writer); - // Notify plugins. - await _eventManager.CallAsync(new PlayerMurderEvent(_game, impostor, impostor.Character, this)); + await _eventManager.CallAsync(new PlayerMurderEvent(_game, _game.GetClientPlayer(OwnerId), this, target)); } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs index 1fe1dc833..c2759139a 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Impostor.Api; @@ -6,10 +7,13 @@ using Impostor.Api.Innersloth; using Impostor.Api.Innersloth.Customization; using Impostor.Api.Net; +using Impostor.Api.Net.Inner.Objects; using Impostor.Api.Net.Messages; +using Impostor.Api.Net.Messages.Rpcs; using Impostor.Server.Events.Player; using Impostor.Server.Net.Inner.Objects.Components; using Impostor.Server.Net.State; +using Impostor.Server.Utils; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -20,12 +24,14 @@ internal partial class InnerPlayerControl : InnerNetObject private readonly ILogger _logger; private readonly IEventManager _eventManager; private readonly Game _game; + private readonly ServerEnvironment _serverEnvironment; - public InnerPlayerControl(ILogger logger, IServiceProvider serviceProvider, IEventManager eventManager, Game game) + public InnerPlayerControl(ILogger logger, IServiceProvider serviceProvider, IEventManager eventManager, Game game, ServerEnvironment serverEnvironment) { _logger = logger; _eventManager = eventManager; _game = game; + _serverEnvironment = serverEnvironment; Physics = ActivatorUtilities.CreateInstance(serviceProvider, this, _eventManager, _game); NetworkTransform = ActivatorUtilities.CreateInstance(serviceProvider, this, _game); @@ -47,521 +53,543 @@ public InnerPlayerControl(ILogger logger, IServiceProvider s public InnerPlayerInfo PlayerInfo { get; internal set; } - public override async ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) + internal Queue RequestedPlayerName { get; } = new Queue(); + + internal Queue RequestedColorId { get; } = new Queue(); + + public override ValueTask SerializeAsync(IMessageWriter writer, bool initialState) + { + throw new NotImplementedException(); + } + + public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) + { + if (!await ValidateHost(CheatContext.Deserialize, sender)) + { + return; + } + + if (initialState) + { + IsNew = reader.ReadBoolean(); + } + + 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) { - // Play an animation. case RpcCalls.PlayAnimation: { - if (!sender.IsOwner(this)) + if (!await ValidateOwnership(call, sender)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.PlayAnimation)} to an unowned {nameof(InnerPlayerControl)}"); + return false; } - if (target != null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.PlayAnimation)} to a specific player instead of broadcast"); - } - - var animation = reader.ReadByte(); + Rpc00PlayAnimation.Deserialize(reader, out var task); break; } - // Complete a task. case RpcCalls.CompleteTask: { - if (!sender.IsOwner(this)) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CompleteTask)} to an unowned {nameof(InnerPlayerControl)}"); - } - - if (target != null) + if (!await ValidateOwnership(call, sender)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CompleteTask)} to a specific player instead of broadcast"); - } - - var taskId = reader.ReadPackedUInt32(); - var task = PlayerInfo.Tasks[(int)taskId]; - if (task == null) - { - _logger.LogWarning($"Client sent {nameof(RpcCalls.CompleteTask)} with a taskIndex that is not in their {nameof(InnerPlayerInfo)}"); - } - else - { - task.Complete = true; - await _eventManager.CallAsync(new PlayerCompletedTaskEvent(_game, sender, this, task)); + return false; } + Rpc01CompleteTask.Deserialize(reader, out var taskId); + await HandleCompleteTask(sender, taskId); break; } - // Update GameOptions. case RpcCalls.SyncSettings: { - if (!sender.IsHost) + if (!await ValidateHost(call, sender)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SyncSettings)} but was not a host"); + return false; } - _game.Options.Deserialize(reader.ReadBytesAndSize()); + Rpc02SyncSettings.Deserialize(reader, _game.Options); break; } - // Set Impostors. case RpcCalls.SetInfected: { - if (!sender.IsHost) + if (!await ValidateOwnership(call, sender) || !await ValidateHost(call, sender)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetInfected)} but was not a host"); + return false; } - var length = reader.ReadPackedInt32(); - - for (var i = 0; i < length; i++) - { - var playerId = reader.ReadByte(); - var player = _game.GameNet.GameData.GetPlayerById(playerId); - if (player != null) - { - player.IsImpostor = true; - } - } + Rpc03SetInfected.Deserialize(reader, out var infectedIds); + await HandleSetInfected(infectedIds); + break; + } - if (_game.GameState == GameStates.Starting) + case RpcCalls.CheckName: + { + if (!await ValidateOwnership(call, sender) || !await ValidateCmd(call, sender, target)) { - await _game.StartedAsync(); + return false; } - break; + Rpc05CheckName.Deserialize(reader, out var name); + return await HandleCheckName(sender, name); } - // Player was voted out. - case RpcCalls.Exiled: + case RpcCalls.SetName: { - if (!sender.IsHost) + if (!await ValidateHost(call, sender)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.Exiled)} but was not a host"); + return false; } - if (target != null) + Rpc06SetName.Deserialize(reader, out var name); + return await HandleSetName(sender, name); + } + + case RpcCalls.CheckColor: + { + if (!await ValidateOwnership(call, sender) || !await ValidateCmd(call, sender, target)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.Exiled)} to a specific player instead of broadcast"); + return false; } - // TODO: Not hit? - Die(DeathReason.Exile); - - await _eventManager.CallAsync(new PlayerExileEvent(_game, sender, this)); - break; + Rpc07CheckColor.Deserialize(reader, out var color); + return await HandleCheckColor(sender, color); } - // Validates the player name at the host. - case RpcCalls.CheckName: + case RpcCalls.SetColor: { - if (!sender.IsOwner(this)) + if (!await ValidateHost(call, sender)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CheckName)} to an unowned {nameof(InnerPlayerControl)}"); + return false; } - if (target == null || !target.IsHost) + Rpc08SetColor.Deserialize(reader, out var color); + return await HandleSetColor(sender, color); + } + + case RpcCalls.SetHat: + { + if (!await ValidateOwnership(call, sender)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CheckName)} to the wrong player"); + return false; } - var name = reader.ReadString(); + Rpc09SetHat.Deserialize(reader, out var hat); + return await HandleSetHat(sender, hat); + } - if (name.Length > 10) + case RpcCalls.SetSkin: + { + if (!await ValidateOwnership(call, sender)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CheckName)} with name exceeding 10 characters"); + return false; } - if (string.IsNullOrWhiteSpace(name) || !name.All(TextBox.IsCharAllowed)) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CheckName)} with name containing illegal characters"); - } + Rpc10SetSkin.Deserialize(reader, out var skin); + return await HandleSetSkin(sender, skin); + } - if (sender.Client.Name != name) + case RpcCalls.ReportDeadBody: + { + if (!await ValidateOwnership(call, sender)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetName)} with name not matching his name from handshake"); + return false; } - PlayerInfo.RequestedPlayerName = name; + Rpc11ReportDeadBody.Deserialize(reader, out var targetId); break; } - // Update the name of a player. - case RpcCalls.SetName: + case RpcCalls.MurderPlayer: { - if (!sender.IsHost) + if (!await ValidateOwnership(call, sender) || !await ValidateImpostor(RpcCalls.MurderPlayer, sender, PlayerInfo)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetName)} but was not a host"); + return false; } - if (target != null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetName)} to a specific player instead of broadcast"); - } - - var name = reader.ReadString(); + Rpc12MurderPlayer.Deserialize(reader, _game, out var murdered); + return await HandleMurderPlayer(sender, murdered); + } - if (sender.IsOwner(this)) + case RpcCalls.SendChat: + { + if (!await ValidateOwnership(call, sender)) { - if (_game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.PlayerName == name)) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetName)} with a name that is already used"); - } - - if (sender.Client.Name != name) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetName)} with name not matching his name from handshake"); - } + return false; } - else - { - if (PlayerInfo.RequestedPlayerName == null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetName)} for a player that didn't request it"); - } - var expected = PlayerInfo.RequestedPlayerName!; - - if (_game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.PlayerName == expected)) - { - var i = 1; - while (true) - { - string text = expected + " " + i; - - if (_game.Players.All(x => x.Character == null || x.Character == this || x.Character.PlayerInfo.PlayerName != text)) - { - expected = text; - break; - } - - i++; - } - } + Rpc13SendChat.Deserialize(reader, out var message); + return await HandleSendChat(sender, message); + } - if (name != expected) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetName)} with incorrect name"); - } + case RpcCalls.StartMeeting: + { + if (!await ValidateHost(call, sender)) + { + return false; } - PlayerInfo.PlayerName = name; - PlayerInfo.RequestedPlayerName = null; + Rpc14StartMeeting.Deserialize(reader, out var targetId); + await HandleStartMeeting(targetId); break; } - // Validates the color at the host. - case RpcCalls.CheckColor: + case RpcCalls.SetScanner: { - if (!sender.IsOwner(this)) + if (!await ValidateOwnership(call, sender)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CheckColor)} to an unowned {nameof(InnerPlayerControl)}"); + return false; } - if (target == null || !target.IsHost) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CheckColor)} to the wrong player"); - } - - var color = reader.ReadByte(); + Rpc15SetScanner.Deserialize(reader, out var on, out var scannerCount); + break; + } - if (color > Enum.GetValues().Length) + case RpcCalls.SendChatNote: + { + if (!await ValidateOwnership(call, sender)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CheckColor)} with invalid color"); + return false; } - PlayerInfo.RequestedColorId = color; + Rpc16SendChatNote.Deserialize(reader, out var playerId, out var chatNoteType); break; } - // Update the color of a player. - case RpcCalls.SetColor: + case RpcCalls.SetPet: { - if (!sender.IsHost) + if (!await ValidateOwnership(call, sender)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetColor)} but was not a host"); + return false; } - if (target != null) + Rpc17SetPet.Deserialize(reader, out var pet); + return await HandleSetPet(sender, pet); + } + + case RpcCalls.SetStartCounter: + { + if (!await ValidateOwnership(call, sender)) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetColor)} to a specific player instead of broadcast"); + return false; } - var color = reader.ReadByte(); + Rpc18SetStartCounter.Deserialize(reader, out var sequenceId, out var startCounter); + return await HandleSetStartCounter(sender, sequenceId, startCounter); + } - if (sender.IsOwner(this)) - { - if (_game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.ColorId == color)) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetColor)} with a color that is already used"); - } - } - else - { - if (PlayerInfo.RequestedColorId == null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetColor)} for a player that didn't request it"); - } + case RpcCalls.CustomRpc: + return await HandleCustomRpc(reader, _game); - var expected = PlayerInfo.RequestedColorId!.Value; + default: + return await UnregisteredCall(call, sender); + } - while (_game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.ColorId == expected)) - { - expected = (byte)((expected + 1) % Enum.GetValues().Length); - } + return true; + } - if (color != expected) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetColor)} with incorrect color"); - } - } + private async ValueTask HandleCompleteTask(ClientPlayer sender, uint taskId) + { + var task = PlayerInfo.Tasks.ElementAtOrDefault((int)taskId); - PlayerInfo.ColorId = color; - PlayerInfo.RequestedColorId = null; - break; - } + if (task != null) + { + task.Complete = true; + await _eventManager.CallAsync(new PlayerCompletedTaskEvent(_game, sender, this, task)); + } + else + { + _logger.LogWarning($"Client sent {nameof(RpcCalls.CompleteTask)} with a taskIndex that is not in their {nameof(InnerPlayerInfo)}"); + } + } - // Update the hat of a player. - case RpcCalls.SetHat: + private async ValueTask HandleSetInfected(ReadOnlyMemory infectedIds) + { + for (var i = 0; i < infectedIds.Length; i++) + { + var player = _game.GameNet.GameData.GetPlayerById(infectedIds.Span[i]); + if (player != null) { - if (!sender.IsOwner(this)) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetHat)} to an unowned {nameof(InnerPlayerControl)}"); - } + player.IsImpostor = true; + } + } - if (target != null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetHat)} to a specific player instead of broadcast"); - } + if (_game.GameState == GameStates.Starting) + { + await _game.StartedAsync(); + } + } - PlayerInfo.HatId = reader.ReadPackedUInt32(); - break; + private async ValueTask HandleCheckName(ClientPlayer sender, string name) + { + if (name.Length > 10) + { + if (await sender.Client.ReportCheatAsync(RpcCalls.CheckName, "Client sent name exceeding 10 characters")) + { + return false; } + } - case RpcCalls.SetSkin: + if (string.IsNullOrWhiteSpace(name) || !name.All(TextBox.IsCharAllowed)) + { + if (await sender.Client.ReportCheatAsync(RpcCalls.CheckName, "Client sent name containing illegal characters")) { - if (!sender.IsOwner(this)) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetSkin)} to an unowned {nameof(InnerPlayerControl)}"); - } - - if (target != null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetHat)} to a specific player instead of broadcast"); - } - - PlayerInfo.SkinId = reader.ReadPackedUInt32(); - break; + return false; } + } - // TODO: (ANTICHEAT) Location check? - // only called by a non-host player on to start meeting - case RpcCalls.ReportDeadBody: + if (sender.Client.Name != name) + { + if (await sender.Client.ReportCheatAsync(RpcCalls.CheckName, "Client sent name not matching his name from handshake")) { - if (!sender.IsOwner(this)) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.ReportDeadBody)} to an unowned {nameof(InnerPlayerControl)}"); - } - - if (target != null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.ReportDeadBody)} to a specific player instead of broadcast"); - } + return false; + } + } + RequestedPlayerName.Enqueue(name); - var deadBodyPlayerId = reader.ReadByte(); - // deadBodyPlayerId == byte.MaxValue -- means emergency call by button + return true; + } - break; + private async ValueTask HandleSetName(ClientPlayer sender, string name) + { + if (_game.GameState == GameStates.Started) + { + if (await sender.Client.ReportCheatAsync(RpcCalls.SetColor, "Client tried to set a name midgame")) + { + return false; } + } - // TODO: (ANTICHEAT) Cooldown check? - case RpcCalls.MurderPlayer: + if (sender.IsOwner(this)) + { + if (_game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.PlayerName == name)) { - if (!sender.IsOwner(this)) + if (await sender.Client.ReportCheatAsync(RpcCalls.SetName, "Client sent name that is already used")) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.MurderPlayer)} to an unowned {nameof(InnerPlayerControl)}"); + return false; } + } - if (target != null) + if (sender.Client.Name != name) + { + if (await sender.Client.ReportCheatAsync(RpcCalls.SetName, "Client sent name not matching his name from handshake")) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.MurderPlayer)} to a specific player instead of broadcast"); + return false; } + } + } + else + { + if (!RequestedPlayerName.Any()) + { + _logger.LogWarning($"Client sent {nameof(RpcCalls.SetName)} for a player that didn't request it"); + return false; + } - if (!sender.Character.PlayerInfo.IsImpostor) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.MurderPlayer)} as crewmate"); - } + var expected = RequestedPlayerName.Dequeue(); - if (!sender.Character.PlayerInfo.CanMurder(_game)) + if (_game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.PlayerName == expected)) + { + var i = 1; + while (true) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.MurderPlayer)} too fast"); - } + string text = expected + " " + i; - sender.Character.PlayerInfo.LastMurder = DateTimeOffset.UtcNow; + if (_game.Players.All(x => x.Character == null || x.Character == this || x.Character.PlayerInfo.PlayerName != text)) + { + expected = text; + break; + } - var player = reader.ReadNetObject(_game); - if (!player.PlayerInfo.IsDead) - { - player.Die(DeathReason.Kill); - await _eventManager.CallAsync(new PlayerMurderEvent(_game, sender, this, player)); + i++; } - - break; } - case RpcCalls.SendChat: + if (name != expected) { - if (!sender.IsOwner(this)) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SendChat)} to an unowned {nameof(InnerPlayerControl)}"); - } + _logger.LogWarning($"Client sent {nameof(RpcCalls.SetName)} with incorrect name"); + await SetNameAsync(expected); + return false; + } + } - if (target != null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SendChat)} to a specific player instead of broadcast"); - } + PlayerInfo.PlayerName = name; - var chat = reader.ReadString(); + return true; + } - await _eventManager.CallAsync(new PlayerChatEvent(_game, sender, this, chat)); - break; - } + private static readonly byte ColorsCount = (byte)Enum.GetValues().Length; - case RpcCalls.StartMeeting: + private async ValueTask HandleCheckColor(ClientPlayer sender, ColorType color) + { + if ((byte)color > ColorsCount) + { + if (await sender.Client.ReportCheatAsync(RpcCalls.CheckColor, "Client sent invalid color")) { - if (!sender.IsHost) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.StartMeeting)} but was not a host"); - } + return false; + } + } - if (target != null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.StartMeeting)} to a specific player instead of broadcast"); - } + RequestedColorId.Enqueue(color); - // deadBodyPlayerId == byte.MaxValue -- means emergency call by button - var deadBodyPlayerId = reader.ReadByte(); - var deadPlayer = deadBodyPlayerId != byte.MaxValue - ? _game.GameNet.GameData.GetPlayerById(deadBodyPlayerId)?.Controller - : null; + return true; + } - await _eventManager.CallAsync(new PlayerStartMeetingEvent(_game, _game.GetClientPlayer(this.OwnerId), this, deadPlayer)); - break; + private async ValueTask HandleSetColor(ClientPlayer sender, ColorType color) + { + if (_game.GameState == GameStates.Started) + { + if (await sender.Client.ReportCheatAsync(RpcCalls.SetColor, "Client tried to set a color midgame")) + { + return false; } + } - case RpcCalls.SetScanner: + if (sender.IsOwner(this)) + { + if (_game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.Color == color)) { - if (!sender.IsOwner(this)) + if (await sender.Client.ReportCheatAsync(RpcCalls.SetColor, "Client sent a color that is already used")) { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetScanner)} to an unowned {nameof(InnerPlayerControl)}"); + return false; } - - if (target != null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetScanner)} to a specific player instead of broadcast"); - } - - var on = reader.ReadBoolean(); - var count = reader.ReadByte(); - break; } - - case RpcCalls.SendChatNote: + } + else + { + if (!RequestedColorId.Any()) { - if (!sender.IsOwner(this)) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SendChatNote)} to an unowned {nameof(InnerPlayerControl)}"); - } + _logger.LogWarning($"Client sent {nameof(RpcCalls.SetColor)} for a player that didn't request it"); + return false; + } - if (target != null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SendChatNote)} to a specific player instead of broadcast"); - } + var expected = RequestedColorId.Dequeue(); - var playerId = reader.ReadByte(); - var chatNote = (ChatNoteType)reader.ReadByte(); - break; + while (_game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.Color == expected)) + { + expected = (ColorType)(((byte)expected + 1) % ColorsCount); } - case RpcCalls.SetPet: + if (color != expected) { - if (!sender.IsOwner(this)) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetPet)} to an unowned {nameof(InnerPlayerControl)}"); - } + _logger.LogWarning($"Client sent {nameof(RpcCalls.SetColor)} with incorrect color"); + await SetColorAsync(expected); + return false; + } + } - if (target != null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetPet)} to a specific player instead of broadcast"); - } + PlayerInfo.Color = color; - PlayerInfo.PetId = reader.ReadPackedUInt32(); - break; - } + return true; + } - // TODO: Understand this RPC - case RpcCalls.SetStartCounter: - { - if (!sender.IsOwner(this)) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetStartCounter)} to an unowned {nameof(InnerPlayerControl)}"); - } + private async ValueTask HandleSetHat(ClientPlayer sender, HatType hat) + { + if (_game.GameState == GameStates.Started && await sender.Client.ReportCheatAsync(RpcCalls.SetHat, "Client tried to change hat while not in lobby")) + { + return false; + } - if (target != null) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetStartCounter)} to a specific player instead of broadcast"); - } + PlayerInfo.Hat = hat; - // Used to compare with LastStartCounter. - var startCounter = reader.ReadPackedUInt32(); + return true; + } - // Is either start countdown or byte.MaxValue - var secondsLeft = reader.ReadByte(); - if (secondsLeft < byte.MaxValue) - { - await _eventManager.CallAsync(new PlayerSetStartCounterEvent(_game, sender, this, secondsLeft)); - } + private async ValueTask HandleSetSkin(ClientPlayer sender, SkinType skin) + { + if (_game.GameState == GameStates.Started && await sender.Client.ReportCheatAsync(RpcCalls.SetSkin, "Client tried to change skin while not in lobby")) + { + return false; + } - break; + PlayerInfo.Skin = skin; + + return true; + } + + private async ValueTask HandleMurderPlayer(ClientPlayer sender, IInnerPlayerControl? target) + { + // TODO record replay with timestamps + if (!_serverEnvironment.IsReplay && !PlayerInfo.CanMurder(_game)) + { + if (await sender.Client.ReportCheatAsync(RpcCalls.MurderPlayer, "Client tried to murder too fast")) + { + return false; } + } - default: + if (target == null || target.PlayerInfo.IsImpostor) + { + if (await sender.Client.ReportCheatAsync(RpcCalls.MurderPlayer, "Client tried to murder invalid target")) { - _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerPlayerControl), call); - break; + return false; } } + + PlayerInfo.LastMurder = DateTimeOffset.UtcNow; + + if (!target.PlayerInfo.IsDead) + { + ((InnerPlayerControl)target).Die(DeathReason.Kill); + await _eventManager.CallAsync(new PlayerMurderEvent(_game, sender, this, target)); + } + + return true; } - public override bool Serialize(IMessageWriter writer, bool initialState) + private async ValueTask HandleSendChat(ClientPlayer sender, string message) { - throw new NotImplementedException(); + var @event = new PlayerChatEvent(_game, sender, this, message); + await _eventManager.CallAsync(@event); + + return !@event.IsCancelled; } - public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) + private async ValueTask HandleStartMeeting(byte targetId) { - if (!sender.IsHost) - { - throw new ImpostorCheatException($"Client attempted to send data for {nameof(InnerPlayerControl)} as non-host"); - } + var deadPlayer = _game.GameNet.GameData.GetPlayerById(targetId)?.Controller; + await _eventManager.CallAsync(new PlayerStartMeetingEvent(_game, _game.GetClientPlayer(this.OwnerId), this, deadPlayer)); + } - if (initialState) + private async ValueTask HandleSetPet(ClientPlayer sender, PetType pet) + { + if (_game.GameState == GameStates.Started && await sender.Client.ReportCheatAsync(RpcCalls.SetPet, "Client tried to change pet while not in lobby")) { - IsNew = reader.ReadBoolean(); + return false; } - PlayerId = reader.ReadByte(); + PlayerInfo.Pet = pet; + + return true; } - internal void Die(DeathReason reason) + private async ValueTask HandleSetStartCounter(ClientPlayer sender, int sequenceId, sbyte startCounter) { - PlayerInfo.IsDead = true; - PlayerInfo.LastDeathReason = reason; + if (!sender.IsHost && startCounter != -1) + { + if (await sender.Client.ReportCheatAsync(RpcCalls.MurderPlayer, "Client tried to set start counter as a non-host")) + { + return false; + } + } + + if (startCounter != -1) + { + await _eventManager.CallAsync(new PlayerSetStartCounterEvent(_game, sender, this, (byte)startCounter)); + } + + return true; } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs index f1409f938..410b4af61 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Impostor.Api.Games; using Impostor.Api.Innersloth; +using Impostor.Api.Innersloth.Customization; using Impostor.Api.Net.Messages; namespace Impostor.Server.Net.Inner.Objects @@ -19,17 +20,13 @@ public InnerPlayerInfo(byte playerId) public string PlayerName { get; internal set; } - public string? RequestedPlayerName { get; internal set; } + public ColorType Color { get; internal set; } - public byte ColorId { get; internal set; } + public HatType Hat { get; internal set; } - public byte? RequestedColorId { get; internal set; } + public PetType Pet { get; internal set; } - public uint HatId { get; internal set; } - - public uint PetId { get; internal set; } - - public uint SkinId { get; internal set; } + public SkinType Skin { get; internal set; } public bool Disconnected { get; internal set; } @@ -61,10 +58,10 @@ public void Serialize(IMessageWriter writer) public void Deserialize(IMessageReader reader) { PlayerName = reader.ReadString(); - ColorId = reader.ReadByte(); - HatId = reader.ReadPackedUInt32(); - PetId = reader.ReadPackedUInt32(); - SkinId = reader.ReadPackedUInt32(); + Color = (ColorType)reader.ReadByte(); + Hat = (HatType)reader.ReadPackedUInt32(); + Pet = (PetType)reader.ReadPackedUInt32(); + Skin = (SkinType)reader.ReadPackedUInt32(); var flag = reader.ReadByte(); Disconnected = (flag & 1) > 0; IsImpostor = (flag & 2) > 0; diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs index b1a3f18f9..3725c8faa 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs @@ -6,6 +6,7 @@ using Impostor.Api.Net; using Impostor.Api.Net.Inner.Objects; using Impostor.Api.Net.Messages; +using Impostor.Api.Net.Messages.Rpcs; using Impostor.Server.Net.Inner.Objects.Systems; using Impostor.Server.Net.Inner.Objects.Systems.ShipStatus; using Impostor.Server.Net.State; @@ -37,82 +38,22 @@ public InnerShipStatus(ILogger logger, Game game) _systems.Add(SystemTypes.Sabotage, new SabotageSystemType(new[] { - (IActivatable)_systems[SystemTypes.Comms], - (IActivatable)_systems[SystemTypes.Reactor], - (IActivatable)_systems[SystemTypes.LifeSupp], - (IActivatable)_systems[SystemTypes.Electrical], + (IActivatable)_systems[SystemTypes.Comms], (IActivatable)_systems[SystemTypes.Reactor], (IActivatable)_systems[SystemTypes.LifeSupp], (IActivatable)_systems[SystemTypes.Electrical], })); Components.Add(this); } - public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, - IMessageReader reader) - { - switch (call) - { - case RpcCalls.CloseDoorsOfType: - { - if (target == null || !target.IsHost) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CloseDoorsOfType)} to wrong destinition, must be host"); - } - - if (!sender.Character.PlayerInfo.IsImpostor) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CloseDoorsOfType)} as crewmate"); - } - - var systemType = (SystemTypes)reader.ReadByte(); - - break; - } - - case RpcCalls.RepairSystem: - { - if (target == null || !target.IsHost) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.RepairSystem)} to wrong destinition, must be host"); - } - - var systemType = (SystemTypes)reader.ReadByte(); - if (systemType == SystemTypes.Sabotage && !sender.Character.PlayerInfo.IsImpostor) - { - throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.RepairSystem)} for {systemType} as crewmate"); - } - - var player = reader.ReadNetObject(_game); - var amount = reader.ReadByte(); - - // TODO: Modify data (?) - break; - } - - default: - { - _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerShipStatus), call); - break; - } - } - - return default; - } - - public override bool Serialize(IMessageWriter writer, bool initialState) + public override ValueTask SerializeAsync(IMessageWriter writer, bool initialState) { throw new NotImplementedException(); } - public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) + public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) { - if (!sender.IsHost) + if (!await ValidateHost(CheatContext.Deserialize, sender) || !await ValidateBroadcast(CheatContext.Deserialize, sender, target)) { - throw new ImpostorCheatException($"Client attempted to send data for {nameof(InnerShipStatus)} as non-host"); - } - - if (target != null) - { - throw new ImpostorCheatException($"Client attempted to send {nameof(InnerShipStatus)} data to a specific player, must be broadcast"); + return; } if (initialState) @@ -143,5 +84,47 @@ public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IM } } } + + public override async ValueTask HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) + { + if (!await ValidateCmd(call, sender, target)) + { + return false; + } + + switch (call) + { + case RpcCalls.CloseDoorsOfType: + { + if (!await ValidateImpostor(RpcCalls.MurderPlayer, sender, sender.Character!.PlayerInfo)) + { + return false; + } + + Rpc27CloseDoorsOfType.Deserialize(reader, out var systemType); + break; + } + + case RpcCalls.RepairSystem: + { + Rpc28RepairSystem.Deserialize(reader, _game, out var systemType, out var player, out var amount); + + if (systemType == SystemTypes.Sabotage && !await ValidateImpostor(call, sender, sender.Character!.PlayerInfo)) + { + return false; + } + + break; + } + + case RpcCalls.CustomRpc: + return await HandleCustomRpc(reader, _game); + + default: + return await UnregisteredCall(call, sender); + } + + return true; + } } -} \ 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 51e22d81d..cc7e46cd4 100644 --- a/src/Impostor.Server/Net/Manager/ClientManager.cs +++ b/src/Impostor.Server/Net/Manager/ClientManager.cs @@ -7,9 +7,11 @@ using Impostor.Api.Net; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.S2C; +using Impostor.Api.Reactor; using Impostor.Hazel; using Impostor.Server.Config; using Impostor.Server.Net.Factories; +using Impostor.Server.Utils; using Microsoft.Extensions.Logging; namespace Impostor.Server.Net.Manager @@ -23,6 +25,8 @@ internal partial class ClientManager GameVersion.GetVersion(2020, 11, 17), // 2020.11.17 }; + private static string ServerBrand { get; } = $"Impostor {DotnetUtils.GetVersion()}"; + private readonly ILogger _logger; private readonly ConcurrentDictionary _clients; private readonly IClientFactory _clientFactory; @@ -53,7 +57,7 @@ public int NextId() return clientId; } - public async ValueTask RegisterConnectionAsync(IHazelConnection connection, string name, int clientVersion) + public async ValueTask RegisterConnectionAsync(IHazelConnection connection, string name, int clientVersion, ISet? mods) { if (!SupportedVersions.Contains(clientVersion)) { @@ -79,12 +83,16 @@ public async ValueTask RegisterConnectionAsync(IHazelConnection connection, stri return; } - var client = _clientFactory.Create(connection, name, clientVersion); + var client = _clientFactory.Create(connection, name, clientVersion, mods ?? new HashSet(0)); var id = NextId(); client.Id = id; _logger.LogTrace("Client connected."); _clients.TryAdd(id, client); + + using var writer = MessageWriter.Get(MessageType.Reliable); + ModdedHandshakeS2C.Serialize(writer, ServerBrand); + await connection.SendAsync(writer); } public void Remove(IClient client) diff --git a/src/Impostor.Server/Net/Matchmaker.cs b/src/Impostor.Server/Net/Matchmaker.cs index 64ece55f0..e700703ca 100644 --- a/src/Impostor.Server/Net/Matchmaker.cs +++ b/src/Impostor.Server/Net/Matchmaker.cs @@ -2,6 +2,7 @@ using System.Net; using System.Net.Sockets; using System.Threading.Tasks; +using Impostor.Api.Reactor; using Impostor.Hazel; using Impostor.Hazel.Udp; using Impostor.Server.Net.Hazel; @@ -54,13 +55,12 @@ public async ValueTask StopAsync() private async ValueTask OnNewConnection(NewConnectionEventArgs e) { // Handshake. - var clientVersion = e.HandshakeData.ReadInt32(); - var name = e.HandshakeData.ReadString(); + ModdedHandshakeC2S.Deserialize(e.HandshakeData, out var clientVersion, out var name, out var mods); var connection = new HazelConnection(e.Connection, _connectionLogger); // Register client - await _clientManager.RegisterConnectionAsync(connection, name, clientVersion); + await _clientManager.RegisterConnectionAsync(connection, name, clientVersion, mods); } } } diff --git a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs index 3dad4b34d..bda07fda2 100644 --- a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs +++ b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs @@ -1,8 +1,10 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; using Impostor.Api.Innersloth; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.C2S; using Impostor.Api.Net.Messages.S2C; +using Impostor.Api.Reactor; using Impostor.Hazel; using Impostor.Server.Config; using Impostor.Server.Net.Hazel; @@ -23,10 +25,11 @@ internal class ClientRedirector : ClientBase public ClientRedirector( string name, HazelConnection connection, + ISet mods, ClientManager clientManager, INodeProvider nodeProvider, INodeLocator nodeLocator) - : base(name, connection) + : base(name, connection, mods) { _clientManager = clientManager; _nodeProvider = nodeProvider; diff --git a/src/Impostor.Server/Net/State/Game.Api.cs b/src/Impostor.Server/Net/State/Game.Api.cs index f395be292..1a623be96 100644 --- a/src/Impostor.Server/Net/State/Game.Api.cs +++ b/src/Impostor.Server/Net/State/Game.Api.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.IO; +using System.IO; using System.Net; using System.Threading.Tasks; using Impostor.Api; @@ -7,7 +6,6 @@ using Impostor.Api.Innersloth; using Impostor.Api.Net; using Impostor.Api.Net.Inner; -using Impostor.Api.Net.Inner.Objects; using Impostor.Server.Net.Inner; namespace Impostor.Server.Net.State @@ -46,25 +44,5 @@ public async ValueTask SyncSettingsAsync() await FinishRpcAsync(writer); } } - - public async ValueTask SetInfectedAsync(IEnumerable players) - { - if (Host.Character == null) - { - throw new ImpostorException("Attempted to set infected when the host was not spawned."); - } - - using (var writer = StartRpc(Host.Character.NetId, RpcCalls.SetInfected)) - { - writer.Write((byte)Host.Character.NetId); - - foreach (var player in players) - { - writer.Write((byte)player.PlayerId); - } - - await FinishRpcAsync(writer); - } - } } } diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index a84d9b59c..bb386d6fc 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Impostor.Api; using Impostor.Api.Innersloth; +using Impostor.Api.Net.Inner; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.S2C; using Impostor.Hazel; @@ -231,7 +232,7 @@ public async ValueTask HandleGameDataAsync(IMessageReader parent, ClientPl var netId = reader.ReadPackedUInt32(); if (_allObjectsFast.TryGetValue(netId, out var obj)) { - obj.Deserialize(sender, target, reader, false); + await obj.DeserializeAsync(sender, target, reader, false); } else { @@ -246,7 +247,10 @@ public async ValueTask HandleGameDataAsync(IMessageReader parent, ClientPl var netId = reader.ReadPackedUInt32(); if (_allObjectsFast.TryGetValue(netId, out var obj)) { - await obj.HandleRpc(sender, target, (RpcCalls) reader.ReadByte(), reader); + if (!await obj.HandleRpcAsync(sender, target, (RpcCalls)reader.ReadByte(), reader)) + { + return false; + } } else { @@ -261,7 +265,10 @@ public async ValueTask HandleGameDataAsync(IMessageReader parent, ClientPl // Only the host is allowed to despawn objects. if (!sender.IsHost) { - throw new ImpostorCheatException("Tried to send SpawnFlag as non-host."); + if (await sender.Client.ReportCheatAsync(new CheatContext(nameof(GameDataTag.SpawnFlag)), "Tried to send SpawnFlag as non-host.")) + { + return false; + } } var objectId = reader.ReadPackedUInt32(); @@ -322,7 +329,7 @@ public async ValueTask HandleGameDataAsync(IMessageReader parent, ClientPl using var readerSub = reader.ReadMessage(); if (readerSub.Length > 0) { - obj.Deserialize(sender, target, readerSub, true); + await obj.DeserializeAsync(sender, target, readerSub, true); } await OnSpawnAsync(obj); @@ -435,15 +442,15 @@ private void RemoveNetObject(InnerNetObject obj) obj.NetId = uint.MaxValue; } - public T FindObjectByNetId(uint netId) - where T : InnerNetObject + public T? FindObjectByNetId(uint netId) + where T : IInnerNetObject { if (_allObjectsFast.TryGetValue(netId, out var obj)) { - return (T) obj; + return (T)(IInnerNetObject)obj; } - return null; + return default; } } } diff --git a/src/Impostor.Server/Net/State/Game.Incoming.cs b/src/Impostor.Server/Net/State/Game.Incoming.cs index 4bf1c43c0..547224db2 100644 --- a/src/Impostor.Server/Net/State/Game.Incoming.cs +++ b/src/Impostor.Server/Net/State/Game.Incoming.cs @@ -1,10 +1,12 @@ using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Impostor.Api.Games; using Impostor.Api.Innersloth; using Impostor.Api.Net; using Impostor.Api.Net.Messages; +using Impostor.Api.Reactor; using Impostor.Hazel; using Impostor.Server.Events; using Microsoft.Extensions.DependencyInjection; @@ -79,6 +81,25 @@ private async ValueTask AddClientSafeAsync(ClientBase client) return GameJoinResult.FromError(GameJoinError.GameDestroyed); } + if (Host != null) + { + foreach (var hostMod in Host.Client.Mods) + { + if (hostMod.Side == PluginSide.Both && client.Mods.All(clientMod => hostMod.Id != clientMod.Id)) + { + return GameJoinResult.CreateCustomError($"You are missing {hostMod.Id} - {hostMod.Version}"); + } + } + + foreach (var clientMod in client.Mods) + { + if (clientMod.Side == PluginSide.Both && Host.Client.Mods.All(hostMod => clientMod.Id != hostMod.Id)) + { + return GameJoinResult.CreateCustomError($"Host of this game is missing {clientMod.Id} - {clientMod.Version}"); + } + } + } + var isNew = false; if (player == null || player.Game != this) diff --git a/src/Impostor.Server/Net/State/Game.State.cs b/src/Impostor.Server/Net/State/Game.State.cs index e31177607..e24e798a9 100644 --- a/src/Impostor.Server/Net/State/Game.State.cs +++ b/src/Impostor.Server/Net/State/Game.State.cs @@ -102,6 +102,12 @@ private async ValueTask MigrateHost() return; } + foreach (var player in _players.Values) + { + player.Character?.RequestedPlayerName.Clear(); + player.Character?.RequestedColorId.Clear(); + } + HostId = host.Client.Id; _logger.LogInformation("{0} - Assigned {1} ({2}) as new host.", Code, host.Client.Name, host.Client.Id); @@ -133,4 +139,4 @@ private async ValueTask CheckLimboPlayers() } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/State/Game.cs b/src/Impostor.Server/Net/State/Game.cs index 19198675e..a1aeb48a6 100644 --- a/src/Impostor.Server/Net/State/Game.cs +++ b/src/Impostor.Server/Net/State/Game.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; +using System.Numerics; using System.Threading.Tasks; using Impostor.Api.Events.Managers; using Impostor.Api.Games; @@ -71,7 +72,7 @@ public Game( public int PlayerCount => _players.Count; - public ClientPlayer Host => _players[HostId]; + public ClientPlayer? Host => _players.GetValueOrDefault(HostId); public IEnumerable Players => _players.Select(p => p.Value); @@ -92,16 +93,20 @@ public IClientPlayer GetClientPlayer(int clientId) return _players.TryGetValue(clientId, out var clientPlayer) ? clientPlayer : null; } - internal ValueTask StartedAsync() + internal async ValueTask StartedAsync() { if (GameState == GameStates.Starting) { + for (var i = 0; i < _players.Values.Count; i++) + { + var player = _players.Values.ElementAt(i); + await player.Character!.NetworkTransform.SetPositionAsync(player, MapSpawn.Maps[Options.Map].GetSpawnLocation(i, PlayerCount, true), Vector2.Zero); + } + GameState = GameStates.Started; - return _eventManager.CallAsync(new GameStartedEvent(this)); + await _eventManager.CallAsync(new GameStartedEvent(this)); } - - return default; } public ValueTask EndAsync() diff --git a/src/Impostor.Server/Plugins/PluginLoader.cs b/src/Impostor.Server/Plugins/PluginLoader.cs index 4e728868f..f753bd135 100644 --- a/src/Impostor.Server/Plugins/PluginLoader.cs +++ b/src/Impostor.Server/Plugins/PluginLoader.cs @@ -5,7 +5,6 @@ using System.Reflection; using System.Runtime.Loader; using Impostor.Api.Plugins; -using Impostor.Server.Utils; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileSystemGlobbing; using Microsoft.Extensions.Hosting; diff --git a/src/Impostor.Server/Program.cs b/src/Impostor.Server/Program.cs index d11694f71..2af8d5504 100644 --- a/src/Impostor.Server/Program.cs +++ b/src/Impostor.Server/Program.cs @@ -112,9 +112,16 @@ private static IHostBuilder CreateHostBuilder(string[] args) .GetSection(ServerRedirectorConfig.Section) .Get() ?? new ServerRedirectorConfig(); + var announcementsServer = host.Configuration + .GetSection(AnnouncementsServerConfig.Section) + .Get() ?? new AnnouncementsServerConfig(); + + services.AddSingleton(); + services.Configure(host.Configuration.GetSection(DebugConfig.Section)); services.Configure(host.Configuration.GetSection(AntiCheatConfig.Section)); services.Configure(host.Configuration.GetSection(ServerConfig.Section)); + services.Configure(host.Configuration.GetSection(AnnouncementsServerConfig.Section)); services.Configure(host.Configuration.GetSection(ServerRedirectorConfig.Section)); if (redirector.Enabled) @@ -191,12 +198,18 @@ private static IHostBuilder CreateHostBuilder(string[] args) services.AddSingleton(p => p.GetRequiredService()); } + services.AddEventPools(); services.AddHazel(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddHostedService(); + + if (announcementsServer.Enabled) + { + services.AddHostedService(); + } }) .UseSerilog() .UseConsoleLifetime() diff --git a/src/Impostor.Server/ProjectRules.ruleset b/src/Impostor.Server/ProjectRules.ruleset index 3654bc34c..fd6daac02 100644 --- a/src/Impostor.Server/ProjectRules.ruleset +++ b/src/Impostor.Server/ProjectRules.ruleset @@ -10,6 +10,7 @@ + diff --git a/src/Impostor.Server/Recorder/ClientRecorder.cs b/src/Impostor.Server/Recorder/ClientRecorder.cs index 5763c70b1..868aa0a4c 100644 --- a/src/Impostor.Server/Recorder/ClientRecorder.cs +++ b/src/Impostor.Server/Recorder/ClientRecorder.cs @@ -1,5 +1,7 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; using Impostor.Api.Net.Messages; +using Impostor.Api.Reactor; using Impostor.Server.Config; using Impostor.Server.Net; using Impostor.Server.Net.Hazel; @@ -16,8 +18,8 @@ internal class ClientRecorder : Client private bool _createdGame; private bool _recordAfter; - public ClientRecorder(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, HazelConnection connection, PacketRecorder recorder) - : base(logger, antiCheatOptions, clientManager, gameManager, name, connection) + public ClientRecorder(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, HazelConnection connection, ISet mods, PacketRecorder recorder) + : base(logger, antiCheatOptions, clientManager, gameManager, name, connection, mods) { _recorder = recorder; _isFirst = true; diff --git a/src/Impostor.Server/Utils/ServerEnvironment.cs b/src/Impostor.Server/Utils/ServerEnvironment.cs new file mode 100644 index 000000000..9c9836aa1 --- /dev/null +++ b/src/Impostor.Server/Utils/ServerEnvironment.cs @@ -0,0 +1,7 @@ +namespace Impostor.Server.Utils +{ + public class ServerEnvironment + { + public bool IsReplay { get; init; } + } +} diff --git a/src/Impostor.Server/config-full.json b/src/Impostor.Server/config-full.json index dfee1bcbf..edf7716ca 100644 --- a/src/Impostor.Server/config-full.json +++ b/src/Impostor.Server/config-full.json @@ -1,11 +1,17 @@ -{ +{ "Server": { "PublicIp": "127.0.0.1", "PublicPort": 22023, "ListenIp": "0.0.0.0", "ListenPort": 22023 }, + "AnnouncementsServer": { + "Enabled": true, + "ListenIp": "0.0.0.0", + "ListenPort": 22024 + }, "AntiCheat": { + "Enabled": true, "BanIpFromGame": true }, "ServerRedirector": { @@ -26,4 +32,4 @@ "GameRecorderEnabled": true, "GameRecorderPath": "" } -} \ No newline at end of file +} diff --git a/src/Impostor.Tools.ServerReplay/Program.cs b/src/Impostor.Tools.ServerReplay/Program.cs index 5aaa954cd..1f5e49452 100644 --- a/src/Impostor.Tools.ServerReplay/Program.cs +++ b/src/Impostor.Tools.ServerReplay/Program.cs @@ -13,12 +13,14 @@ using Impostor.Api.Net.Messages.C2S; using Impostor.Hazel; using Impostor.Hazel.Extensions; +using Impostor.Server; using Impostor.Server.Events; using Impostor.Server.Net; using Impostor.Server.Net.Factories; using Impostor.Server.Net.Manager; using Impostor.Server.Net.Redirector; using Impostor.Server.Recorder; +using Impostor.Server.Utils; using Impostor.Tools.ServerReplay.Mocks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -82,6 +84,11 @@ private static ServiceProvider BuildServices() { var services = new ServiceCollection(); + services.AddSingleton(new ServerEnvironment + { + IsReplay = true + }); + services.AddLogging(builder => { builder.ClearProviders(); @@ -99,6 +106,7 @@ private static ServiceProvider BuildServices() services.AddSingleton(); services.AddSingleton(); + services.AddEventPools(); services.AddHazel(); return services.BuildServiceProvider(); @@ -121,7 +129,7 @@ private static async Task ParseSession(BinaryReader reader) private static async Task ParsePacket(BinaryReader reader) { - var dataType = (RecordedPacketType) reader.ReadByte(); + var dataType = (RecordedPacketType)reader.ReadByte(); // Read client id. var clientId = reader.ReadInt32(); @@ -139,7 +147,7 @@ private static async Task ParsePacket(BinaryReader reader) // Create and register connection. var connection = new MockHazelConnection(address); - await _clientManager.RegisterConnectionAsync(connection, name, 50516550); + await _clientManager.RegisterConnectionAsync(connection, name, 50516550, null); // Store reference for ourselfs. Connections.Add(clientId, connection); From d4bffd20adfa7b5b4f69752d3bf46676f939500d Mon Sep 17 00:00:00 2001 From: js6pak Date: Wed, 3 Mar 2021 09:05:33 +0000 Subject: [PATCH 02/72] [skip ci] Update Building-from-source.md --- docs/Building-from-source.md | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/docs/Building-from-source.md b/docs/Building-from-source.md index cf3632f5f..2254f16ff 100644 --- a/docs/Building-from-source.md +++ b/docs/Building-from-source.md @@ -1,29 +1,20 @@ # Building from source -The solution contains two main projects, the Impostor client and server. The client is built using [.NET Framework 4.7.2](https://dotnet.microsoft.com/download/dotnet-framework/net472) and the server with [.NET 5](https://dotnet.microsoft.com/download/dotnet/5.0). - -Currently .NET 5 is not yet officially released, so in order to build using Visual Studio, you should have Visual Studio 2019 **Preview** installed. -This documentation will go over building both the [Server](#building-the-server) and the [Client](#building-the-client) and their requirements. +The solution contains two main projects, the Impostor server and patcher. The server is built using [.NET 5](https://dotnet.microsoft.com/download/dotnet/5.0) and the winforms patcher is with [.NET Framework 4.7.2](https://dotnet.microsoft.com/download/dotnet-framework/net472). ## Cloning Impostor -You need to clone Impostor with all submodules. - -```bash -git clone --recursive https://github.com/AeonLucid/Impostor.git -``` - -If you already have cloned Impostor but have errors related to Hazel, run the following. +You need to clone Impostor using git. ```bash -git submodule update --init +git clone https://github.com/AeonLucid/Impostor.git ``` ## Building the server ### Dependencies - [.NET 5 SDK](https://dotnet.microsoft.com/download/dotnet/5.0) -- [Visual Studio Preview](https://visualstudio.microsoft.com/vs/preview/) (Optional, only if you want the full IDE experience) +- [Rider](https://www.jetbrains.com/rider/) or [Visual Studio](https://visualstudio.microsoft.com/vs/) (Optional, only if you want the full IDE experience) ### Build using the CLI @@ -33,13 +24,13 @@ dotnet build ``` To setup the server, please look at [Running the server](Running-the-server.md). -## Building the client +## Building the winforms patcher ### Dependencies -* [.NET Framework 4.7.2 Developer Pack](https://dotnet.microsoft.com/download/dotnet-framework/thank-you/net472-developer-pack-offline-installer) +* [.NET Framework 4.7.2 Developer Pack](https://dotnet.microsoft.com/download/dotnet-framework/thank-you/net472-developer-pack-offline-installer) or [Mono](https://www.mono-project.com/download/) ### Build using the CLI ```bash -cd src/Impostor.Client/Impostor.Client.WinForms +cd src/Impostor.Patcher/Impostor.Patcher.WinForms dotnet build -``` \ No newline at end of file +``` From bbbf368a6f40810bd4dc9354433a8cede0a42034 Mon Sep 17 00:00:00 2001 From: js6pak Date: Wed, 3 Mar 2021 10:15:48 +0100 Subject: [PATCH 03/72] Bump version --- build.cake | 7 ++++++- src/Directory.Build.props | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/build.cake b/build.cake index e8d9519d9..13a2ae965 100644 --- a/build.cake +++ b/build.cake @@ -12,7 +12,12 @@ var configuration = Argument("configuration", "Release"); var msbuildSettings = new DotNetCoreMSBuildSettings(); -if (!buildRelease && buildId != null) { +if (buildRelease) +{ + msbuildSettings.Properties["Version"] = new[] { buildVersion }; +} +else if (buildId != null) +{ msbuildSettings.Properties["VersionSuffix"] = new[] { "ci." + buildId }; buildVersion += "-ci." + buildId; } diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 58fd8ce9a..81faf42b8 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,6 +1,6 @@ - 1.2.2 + 1.3.0 dev From 020a1b6447cc3a8e4ee1bbf61366427640556163 Mon Sep 17 00:00:00 2001 From: 112batman <53775078+112batman@users.noreply.github.com> Date: Wed, 3 Mar 2021 10:23:38 +0100 Subject: [PATCH 04/72] Implement IInnerNetObject in IInnerMeetingHud (#256) --- src/Impostor.Api/Net/Inner/Objects/IInnerMeetingHud.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Impostor.Api/Net/Inner/Objects/IInnerMeetingHud.cs b/src/Impostor.Api/Net/Inner/Objects/IInnerMeetingHud.cs index 9c89d0590..6d8f10672 100644 --- a/src/Impostor.Api/Net/Inner/Objects/IInnerMeetingHud.cs +++ b/src/Impostor.Api/Net/Inner/Objects/IInnerMeetingHud.cs @@ -1,6 +1,6 @@ namespace Impostor.Api.Net.Inner.Objects { - public interface IInnerMeetingHud + public interface IInnerMeetingHud : IInnerNetObject { } } From be19b1524bd77223d97ea37d704524391c28afb7 Mon Sep 17 00:00:00 2001 From: miniduikboot <5243971+miniduikboot@users.noreply.github.com> Date: Wed, 3 Mar 2021 15:36:17 +0100 Subject: [PATCH 05/72] Warn if plugin loader paths don't exist (#330) --- src/Impostor.Server/Plugins/PluginLoader.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Impostor.Server/Plugins/PluginLoader.cs b/src/Impostor.Server/Plugins/PluginLoader.cs index f753bd135..4b5d07a50 100644 --- a/src/Impostor.Server/Plugins/PluginLoader.cs +++ b/src/Impostor.Server/Plugins/PluginLoader.cs @@ -24,6 +24,8 @@ public static IHostBuilder UsePluginLoader(this IHostBuilder builder, PluginConf // Add the plugins and libraries. var pluginPaths = new List(config.Paths); var libraryPaths = new List(config.LibraryPaths); + CheckPaths(pluginPaths); + CheckPaths(libraryPaths); var rootFolder = Directory.GetCurrentDirectory(); @@ -120,6 +122,17 @@ public static IHostBuilder UsePluginLoader(this IHostBuilder builder, PluginConf return builder; } + private static void CheckPaths(IEnumerable paths) + { + foreach (var path in paths) + { + if (!Directory.Exists(path)) + { + Logger.Warning("Path {path} was specified in the PluginLoader configuration, but this folder doesn't exist!", path); + } + } + } + private static void RegisterAssemblies( IEnumerable paths, Matcher matcher, From e769b874c8fb300828a03941cf41efbfd1776280 Mon Sep 17 00:00:00 2001 From: js6pak Date: Thu, 4 Mar 2021 09:11:50 +0000 Subject: [PATCH 06/72] Add create game api (#241) --- .../Games/Extensions/GameManagerExtensions.cs | 2 +- src/Impostor.Api/Games/IGame.cs | 14 +++- .../Games/Managers/IGameManager.cs | 4 ++ .../Innersloth/GameOptionsData.cs | 65 +++++++------------ src/Impostor.Api/Innersloth/MapTypes.cs | 2 +- .../Messages/S2C/Message16GetGameListS2C.cs | 6 +- src/Impostor.Plugins.Example/ExamplePlugin.cs | 15 ++++- src/Impostor.Server/Net/Client.cs | 2 +- .../Net/Manager/GameManager.cs | 2 +- src/Impostor.Server/Net/State/Game.Api.cs | 16 ++++- src/Impostor.Server/Net/State/Game.cs | 2 + 11 files changed, 78 insertions(+), 52 deletions(-) diff --git a/src/Impostor.Api/Games/Extensions/GameManagerExtensions.cs b/src/Impostor.Api/Games/Extensions/GameManagerExtensions.cs index 9a5a2b4f1..6a95b3d4a 100644 --- a/src/Impostor.Api/Games/Extensions/GameManagerExtensions.cs +++ b/src/Impostor.Api/Games/Extensions/GameManagerExtensions.cs @@ -8,7 +8,7 @@ public static class GameManagerExtensions { public static int GetGameCount(this IGameManager manager, MapFlags map) { - return manager.Games.Count(game => map.HasFlag((MapFlags)(1 << game.Options.MapId))); + return manager.Games.Count(game => map.HasFlag((MapFlags)(1 << (byte)game.Options.Map))); } } } \ No newline at end of file diff --git a/src/Impostor.Api/Games/IGame.cs b/src/Impostor.Api/Games/IGame.cs index 7c6140c09..57c3fcd25 100644 --- a/src/Impostor.Api/Games/IGame.cs +++ b/src/Impostor.Api/Games/IGame.cs @@ -24,10 +24,15 @@ public interface IGame int PlayerCount { get; } - IClientPlayer Host { get; } + IClientPlayer? Host { get; } bool IsPublic { get; } + /// + /// Gets or sets display name on game list. + /// + string? DisplayName { get; set; } + IDictionary Items { get; } int HostId { get; } @@ -55,6 +60,13 @@ public interface IGame /// A representing the asynchronous operation. ValueTask SyncSettingsAsync(); + /// + /// Sets game's privacy. + /// + /// Privacy to set. + /// A representing the asynchronous operation. + ValueTask SetPrivacyAsync(bool isPublic); + /// /// Send the message to all players. /// diff --git a/src/Impostor.Api/Games/Managers/IGameManager.cs b/src/Impostor.Api/Games/Managers/IGameManager.cs index 10a05f077..7ee403fd2 100644 --- a/src/Impostor.Api/Games/Managers/IGameManager.cs +++ b/src/Impostor.Api/Games/Managers/IGameManager.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Threading.Tasks; +using Impostor.Api.Innersloth; namespace Impostor.Api.Games.Managers { @@ -7,5 +9,7 @@ public interface IGameManager IEnumerable Games { get; } IGame? Find(GameCode code); + + ValueTask CreateAsync(GameOptionsData options); } } \ No newline at end of file diff --git a/src/Impostor.Api/Innersloth/GameOptionsData.cs b/src/Impostor.Api/Innersloth/GameOptionsData.cs index 7f7e0c5ef..3d648445e 100644 --- a/src/Impostor.Api/Innersloth/GameOptionsData.cs +++ b/src/Impostor.Api/Innersloth/GameOptionsData.cs @@ -14,112 +14,97 @@ public class GameOptionsData /// /// Gets or sets host's version of the game. /// - public byte Version { get; set; } + public byte Version { get; set; } = LatestVersion; /// /// Gets or sets the maximum amount of players for this lobby. /// - public byte MaxPlayers { get; set; } + public byte MaxPlayers { get; set; } = 10; /// /// Gets or sets the language of the lobby as per enum. /// - public GameKeywords Keywords { get; set; } + public GameKeywords Keywords { get; set; } = GameKeywords.English; /// - /// Gets or sets the MapId selected for this lobby + /// Gets or sets the Map selected for this lobby. /// - /// - /// Skeld = 0, MiraHQ = 1, Polus = 2. - /// - internal byte MapId { get; set; } - - /// - /// Gets or sets the map selected for this lobby - /// - public MapTypes Map - { - get => (MapTypes)MapId; - set => MapId = (byte)value; - } + public MapTypes Map { get; set; } = MapTypes.Skeld; /// /// Gets or sets the Player speed modifier. /// - public float PlayerSpeedMod { get; set; } + public float PlayerSpeedMod { get; set; } = 1f; /// /// Gets or sets the Light modifier for the players that are members of the crew as a multiplier value. /// - public float CrewLightMod { get; set; } + public float CrewLightMod { get; set; } = 1f; /// /// Gets or sets the Light modifier for the players that are Impostors as a multiplier value. /// - public float ImpostorLightMod { get; set; } + public float ImpostorLightMod { get; set; } = 1f; /// /// Gets or sets the Impostor cooldown to kill in seconds. /// - public float KillCooldown { get; set; } + public float KillCooldown { get; set; } = 15f; /// /// Gets or sets the number of common tasks. /// - public int NumCommonTasks { get; set; } + public int NumCommonTasks { get; set; } = 1; /// /// Gets or sets the number of long tasks. /// - public int NumLongTasks { get; set; } + public int NumLongTasks { get; set; } = 1; /// /// Gets or sets the number of short tasks. /// - public int NumShortTasks { get; set; } + public int NumShortTasks { get; set; } = 2; /// /// Gets or sets the maximum amount of emergency meetings each player can call during the game in seconds. /// - public int NumEmergencyMeetings { get; set; } + public int NumEmergencyMeetings { get; set; } = 1; /// /// Gets or sets the cooldown between each time any player can call an emergency meeting in seconds. /// - public int EmergencyCooldown { get; set; } + public int EmergencyCooldown { get; set; } = 15; /// /// Gets or sets the number of impostors for this lobby. /// - public int NumImpostors { get; set; } + public int NumImpostors { get; set; } = 1; /// /// Gets or sets a value indicating whether ghosts (dead crew members) can do tasks. /// - public bool GhostsDoTasks { get; set; } + public bool GhostsDoTasks { get; set; } = true; /// /// Gets or sets the Kill as per values in . /// - /// - /// Short = 0, Normal = 1, Long = 2. - /// - public KillDistances KillDistance { get; set; } + public KillDistances KillDistance { get; set; } = KillDistances.Normal; /// /// Gets or sets the time for discussion before voting time in seconds. /// - public int DiscussionTime { get; set; } + public int DiscussionTime { get; set; } = 15; /// /// Gets or sets the time for voting in seconds. /// - public int VotingTime { get; set; } + public int VotingTime { get; set; } = 120; /// /// Gets or sets a value indicating whether an ejected player is an impostor or not. /// - public bool ConfirmImpostor { get; set; } + public bool ConfirmImpostor { get; set; } = true; /// /// Gets or sets a value indicating whether players are able to see tasks being performed by other players. @@ -127,7 +112,7 @@ public MapTypes Map /// /// By being set to true, tasks such as Empty Garbage, Submit Scan, Clear asteroids, Prime shields execution will be visible to other players. /// - public bool VisualTasks { get; set; } + public bool VisualTasks { get; set; } = true; /// /// Gets or sets a value indicating whether the vote is anonymous. @@ -137,12 +122,12 @@ public MapTypes Map /// /// Gets or sets the task bar update mode as per values in . /// - public TaskBarUpdate TaskBarUpdate { get; set; } + public TaskBarUpdate TaskBarUpdate { get; set; } = TaskBarUpdate.Always; /// /// Gets or sets a value indicating whether the GameOptions are the default ones. /// - public bool IsDefaults { get; set; } + public bool IsDefaults { get; set; } = true; /// /// Deserialize a packet/message to a new GameOptionsData object. @@ -166,7 +151,7 @@ public void Serialize(BinaryWriter writer, byte version = LatestVersion) writer.Write((byte)version); writer.Write((byte)MaxPlayers); writer.Write((uint)Keywords); - writer.Write((byte)MapId); + writer.Write((byte)Map); writer.Write((float)PlayerSpeedMod); writer.Write((float)CrewLightMod); writer.Write((float)ImpostorLightMod); @@ -223,7 +208,7 @@ public void Deserialize(ReadOnlyMemory memory) Version = bytes.ReadByte(); MaxPlayers = bytes.ReadByte(); Keywords = (GameKeywords)bytes.ReadUInt32(); - MapId = bytes.ReadByte(); + Map = (MapTypes)bytes.ReadByte(); PlayerSpeedMod = bytes.ReadSingle(); CrewLightMod = bytes.ReadSingle(); diff --git a/src/Impostor.Api/Innersloth/MapTypes.cs b/src/Impostor.Api/Innersloth/MapTypes.cs index 8dc07b5d1..2b5ede98d 100644 --- a/src/Impostor.Api/Innersloth/MapTypes.cs +++ b/src/Impostor.Api/Innersloth/MapTypes.cs @@ -1,6 +1,6 @@ namespace Impostor.Api.Innersloth { - public enum MapTypes + public enum MapTypes : byte { Skeld = 0, MiraHQ = 1, diff --git a/src/Impostor.Api/Net/Messages/S2C/Message16GetGameListS2C.cs b/src/Impostor.Api/Net/Messages/S2C/Message16GetGameListS2C.cs index 93386d764..0d742edc7 100644 --- a/src/Impostor.Api/Net/Messages/S2C/Message16GetGameListS2C.cs +++ b/src/Impostor.Api/Net/Messages/S2C/Message16GetGameListS2C.cs @@ -25,10 +25,10 @@ public static void Serialize(IMessageWriter writer, int skeldGameCount, int mira writer.Write(game.PublicIp.Address); writer.Write((ushort)game.PublicIp.Port); writer.Write(game.Code); - writer.Write(game.Host.Client.Name); + writer.Write(game.DisplayName ?? game.Host?.Client.Name ?? string.Empty); writer.Write((byte)game.PlayerCount); writer.WritePacked(1); // TODO: What does Age do? - writer.Write((byte)game.Options.MapId); + writer.Write((byte)game.Options.Map); writer.Write((byte)game.Options.NumImpostors); writer.Write((byte)game.Options.MaxPlayers); writer.EndMessage(); @@ -43,4 +43,4 @@ public static void Deserialize(IMessageReader reader) throw new System.NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Plugins.Example/ExamplePlugin.cs b/src/Impostor.Plugins.Example/ExamplePlugin.cs index dafba7c47..139e42c04 100644 --- a/src/Impostor.Plugins.Example/ExamplePlugin.cs +++ b/src/Impostor.Plugins.Example/ExamplePlugin.cs @@ -1,4 +1,6 @@ using System.Threading.Tasks; +using Impostor.Api.Games.Managers; +using Impostor.Api.Innersloth; using Impostor.Api.Plugins; using Microsoft.Extensions.Logging; @@ -12,16 +14,23 @@ namespace Impostor.Plugins.Example public class ExamplePlugin : PluginBase { private readonly ILogger _logger; + private readonly IGameManager _gameManager; - public ExamplePlugin(ILogger logger) + public ExamplePlugin(ILogger logger, IGameManager gameManager) { _logger = logger; + _gameManager = gameManager; } - public override ValueTask EnableAsync() + public override async ValueTask EnableAsync() { _logger.LogInformation("Example is being enabled."); - return default; + + var game = await _gameManager.CreateAsync(new GameOptionsData()); + game.DisplayName = "Example game"; + await game.SetPrivacyAsync(true); + + _logger.LogInformation("Created game {0}.", game.Code.Code); } public override ValueTask DisableAsync() diff --git a/src/Impostor.Server/Net/Client.cs b/src/Impostor.Server/Net/Client.cs index 143a0d103..87fc56c3d 100644 --- a/src/Impostor.Server/Net/Client.cs +++ b/src/Impostor.Server/Net/Client.cs @@ -332,7 +332,7 @@ private ValueTask OnRequestGameListAsync(GameOptionsData options) { using var message = MessageWriter.Get(MessageType.Reliable); - var games = _gameManager.FindListings((MapFlags)options.MapId, options.NumImpostors, options.Keywords); + var games = _gameManager.FindListings((MapFlags)options.Map, options.NumImpostors, options.Keywords); var skeldGameCount = _gameManager.GetGameCount(MapFlags.Skeld); var miraHqGameCount = _gameManager.GetGameCount(MapFlags.MiraHQ); diff --git a/src/Impostor.Server/Net/Manager/GameManager.cs b/src/Impostor.Server/Net/Manager/GameManager.cs index a37829e58..8d883a412 100644 --- a/src/Impostor.Server/Net/Manager/GameManager.cs +++ b/src/Impostor.Server/Net/Manager/GameManager.cs @@ -98,7 +98,7 @@ public IEnumerable FindListings(MapFlags map, int impostorCount, GameKeywo x.Value.PlayerCount < x.Value.Options.MaxPlayers)) { // Check for options. - if (!map.HasFlag((MapFlags)(1 << game.Options.MapId))) + if (!map.HasFlag((MapFlags)(1 << (byte)game.Options.Map))) { continue; } diff --git a/src/Impostor.Server/Net/State/Game.Api.cs b/src/Impostor.Server/Net/State/Game.Api.cs index 1a623be96..a2996915f 100644 --- a/src/Impostor.Server/Net/State/Game.Api.cs +++ b/src/Impostor.Server/Net/State/Game.Api.cs @@ -6,13 +6,15 @@ using Impostor.Api.Innersloth; using Impostor.Api.Net; using Impostor.Api.Net.Inner; +using Impostor.Api.Net.Messages; +using Impostor.Hazel; using Impostor.Server.Net.Inner; namespace Impostor.Server.Net.State { internal partial class Game : IGame { - IClientPlayer IGame.Host => Host; + IClientPlayer? IGame.Host => Host; IGameNet IGame.GameNet => GameNet; @@ -44,5 +46,17 @@ public async ValueTask SyncSettingsAsync() await FinishRpcAsync(writer); } } + + public async ValueTask SetPrivacyAsync(bool isPublic) + { + IsPublic = isPublic; + + using (var writer = MessageWriter.Get(MessageType.Reliable)) + { + WriteAlterGameMessage(writer, false, IsPublic); + + await SendToAllAsync(writer); + } + } } } diff --git a/src/Impostor.Server/Net/State/Game.cs b/src/Impostor.Server/Net/State/Game.cs index a1aeb48a6..6ca2fd687 100644 --- a/src/Impostor.Server/Net/State/Game.cs +++ b/src/Impostor.Server/Net/State/Game.cs @@ -60,6 +60,8 @@ public Game( public bool IsPublic { get; private set; } + public string? DisplayName { get; set; } + public int HostId { get; private set; } public GameStates GameState { get; private set; } From 9bd43b46293bcdd67a2696237ccc89e39b9c11dc Mon Sep 17 00:00:00 2001 From: js6pak Date: Sat, 6 Mar 2021 00:44:00 +0100 Subject: [PATCH 07/72] 2021.3.5 --- src/Impostor.Api/Innersloth/ChatType.cs | 8 ++++++++ .../Net/Messages/C2S/Message00HostGameC2S.cs | 7 +++++-- .../Net/Messages/C2S/Message01JoinGameC2S.cs | 11 ++++------- .../Net/Messages/C2S/Message16GetGameListC2S.cs | 5 +++-- .../Net/Messages/S2C/Message16GetGameListS2C.cs | 9 +-------- src/Impostor.Server/Net/Client.cs | 15 ++++----------- src/Impostor.Server/Net/Manager/ClientManager.cs | 6 ++---- .../Net/Redirector/ClientRedirector.cs | 7 ++----- 8 files changed, 29 insertions(+), 39 deletions(-) create mode 100644 src/Impostor.Api/Innersloth/ChatType.cs diff --git a/src/Impostor.Api/Innersloth/ChatType.cs b/src/Impostor.Api/Innersloth/ChatType.cs new file mode 100644 index 000000000..087c2b7ca --- /dev/null +++ b/src/Impostor.Api/Innersloth/ChatType.cs @@ -0,0 +1,8 @@ +namespace Impostor.Api.Innersloth +{ + public enum ChatType + { + FreeChatOrQuickChat = 1, + QuickChatOnly = 2, + } +} diff --git a/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs index f90d7f53f..86679facc 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs @@ -11,9 +11,12 @@ public static void Serialize(IMessageWriter writer, GameOptionsData gameOptionsD writer.EndMessage(); } - public static GameOptionsData Deserialize(IMessageReader reader) + public static GameOptionsData Deserialize(IMessageReader reader, out ChatType chatType) { - return GameOptionsData.DeserializeCreate(reader); + var gameOptionsData = GameOptionsData.DeserializeCreate(reader); + chatType = (ChatType)reader.ReadByte(); + + return gameOptionsData; } } } diff --git a/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs index f121b97ea..4b2541494 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs @@ -1,6 +1,4 @@ -using System; - -namespace Impostor.Api.Net.Messages.C2S +namespace Impostor.Api.Net.Messages.C2S { public static class Message01JoinGameC2S { @@ -9,12 +7,11 @@ public static void Serialize(IMessageWriter writer) throw new System.NotImplementedException(); } - public static void Deserialize(IMessageReader reader, out int gameCode, out byte unknown) + public static void Deserialize(IMessageReader reader, out int gameCode) { - var slice = reader.ReadBytes(sizeof(Int32) + sizeof(byte)).Span; + var slice = reader.ReadBytes(sizeof(int)).Span; gameCode = slice.ReadInt32(); - unknown = slice.ReadByte(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs index 2b7e12a76..bc32d5eee 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs @@ -9,10 +9,11 @@ public static void Serialize(IMessageWriter writer) throw new System.NotImplementedException(); } - public static void Deserialize(IMessageReader reader, out GameOptionsData options) + public static void Deserialize(IMessageReader reader, out GameOptionsData options, out ChatType chatType) { reader.ReadPackedInt32(); // Hardcoded 0. options = GameOptionsData.DeserializeCreate(reader); + chatType = (ChatType)reader.ReadByte(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/S2C/Message16GetGameListS2C.cs b/src/Impostor.Api/Net/Messages/S2C/Message16GetGameListS2C.cs index 0d742edc7..7b641929b 100644 --- a/src/Impostor.Api/Net/Messages/S2C/Message16GetGameListS2C.cs +++ b/src/Impostor.Api/Net/Messages/S2C/Message16GetGameListS2C.cs @@ -5,17 +5,10 @@ namespace Impostor.Api.Net.Messages.S2C { public class Message16GetGameListS2C { - public static void Serialize(IMessageWriter writer, int skeldGameCount, int miraHqGameCount, int polusGameCount, IEnumerable games) + public static void Serialize(IMessageWriter writer, IEnumerable games) { writer.StartMessage(MessageFlags.GetGameListV2); - // Count - writer.StartMessage(1); - writer.Write(skeldGameCount); // The Skeld - writer.Write(miraHqGameCount); // Mira HQ - writer.Write(polusGameCount); // Polus - writer.EndMessage(); - // Listing writer.StartMessage(0); diff --git a/src/Impostor.Server/Net/Client.cs b/src/Impostor.Server/Net/Client.cs index 87fc56c3d..713ef8831 100644 --- a/src/Impostor.Server/Net/Client.cs +++ b/src/Impostor.Server/Net/Client.cs @@ -63,7 +63,7 @@ public override async ValueTask HandleMessageAsync(IMessageReader reader, Messag case MessageFlags.HostGame: { // Read game settings. - var gameInfo = Message00HostGameC2S.Deserialize(reader); + var gameInfo = Message00HostGameC2S.Deserialize(reader, out _); // Create game. var game = await _gameManager.CreateAsync(gameInfo); @@ -80,10 +80,7 @@ public override async ValueTask HandleMessageAsync(IMessageReader reader, Messag case MessageFlags.JoinGame: { - Message01JoinGameC2S.Deserialize( - reader, - out var gameCode, - out _); + Message01JoinGameC2S.Deserialize(reader, out var gameCode); var game = _gameManager.Find(gameCode); if (game == null) @@ -248,7 +245,7 @@ public override async ValueTask HandleMessageAsync(IMessageReader reader, Messag case MessageFlags.GetGameListV2: { - Message16GetGameListC2S.Deserialize(reader, out var options); + Message16GetGameListC2S.Deserialize(reader, out var options, out _); await OnRequestGameListAsync(options); break; } @@ -334,11 +331,7 @@ private ValueTask OnRequestGameListAsync(GameOptionsData options) var games = _gameManager.FindListings((MapFlags)options.Map, options.NumImpostors, options.Keywords); - var skeldGameCount = _gameManager.GetGameCount(MapFlags.Skeld); - var miraHqGameCount = _gameManager.GetGameCount(MapFlags.MiraHQ); - var polusGameCount = _gameManager.GetGameCount(MapFlags.Polus); - - Message16GetGameListS2C.Serialize(message, skeldGameCount, miraHqGameCount, polusGameCount, games); + Message16GetGameListS2C.Serialize(message, games); return Connection.SendAsync(message); } diff --git a/src/Impostor.Server/Net/Manager/ClientManager.cs b/src/Impostor.Server/Net/Manager/ClientManager.cs index cc7e46cd4..32359f8fb 100644 --- a/src/Impostor.Server/Net/Manager/ClientManager.cs +++ b/src/Impostor.Server/Net/Manager/ClientManager.cs @@ -20,9 +20,7 @@ internal partial class ClientManager { private static HashSet SupportedVersions { get; } = new HashSet { - GameVersion.GetVersion(2020, 09, 07), // 2020.09.07 - 2020.09.22 - GameVersion.GetVersion(2020, 10, 08), // 2020.10.08 - GameVersion.GetVersion(2020, 11, 17), // 2020.11.17 + GameVersion.GetVersion(2021, 3, 5), // 2021.3.5 }; private static string ServerBrand { get; } = $"Impostor {DotnetUtils.GetVersion()}"; @@ -108,4 +106,4 @@ public bool Validate(IClient client) && ReferenceEquals(client, registeredClient); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs index bda07fda2..9a4edcc32 100644 --- a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs +++ b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs @@ -54,10 +54,7 @@ public override async ValueTask HandleMessageAsync(IMessageReader reader, Messag case MessageFlags.JoinGame: { - Message01JoinGameC2S.Deserialize( - reader, - out var gameCode, - out _); + Message01JoinGameC2S.Deserialize(reader, out var gameCode); using var packet = MessageWriter.Get(MessageType.Reliable); var endpoint = await _nodeLocator.FindAsync(GameCodeParser.IntToGameName(gameCode)); @@ -97,4 +94,4 @@ public override ValueTask HandleDisconnectAsync(string reason) return default; } } -} \ No newline at end of file +} From 781ba34e1b363788844072b291c0063ced43e7ad Mon Sep 17 00:00:00 2001 From: AeonLucid Date: Sat, 6 Mar 2021 17:07:35 +0100 Subject: [PATCH 08/72] Fix Impostor.Tools.ServerReplay compilation --- src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs | 6 ++++++ src/Impostor.Tools.ServerReplay/Program.cs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs index 86679facc..7d7ee5585 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs @@ -11,6 +11,12 @@ public static void Serialize(IMessageWriter writer, GameOptionsData gameOptionsD writer.EndMessage(); } + /// + /// Deserialize a packet. + /// + /// with 0. + /// The chat type selected in the client of the player. + /// Deserialized . public static GameOptionsData Deserialize(IMessageReader reader, out ChatType chatType) { var gameOptionsData = GameOptionsData.DeserializeCreate(reader); diff --git a/src/Impostor.Tools.ServerReplay/Program.cs b/src/Impostor.Tools.ServerReplay/Program.cs index 1f5e49452..c36ed24c6 100644 --- a/src/Impostor.Tools.ServerReplay/Program.cs +++ b/src/Impostor.Tools.ServerReplay/Program.cs @@ -177,7 +177,7 @@ private static async Task ParsePacket(BinaryReader reader) if (tag == MessageFlags.HostGame) { - GameOptions.Add(clientId, Message00HostGameC2S.Deserialize(message)); + GameOptions.Add(clientId, Message00HostGameC2S.Deserialize(message, out _)); } else if (Connections.TryGetValue(clientId, out var client)) { From 575ad25fb66adfd7de283cccb9582b96b653e756 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sat, 6 Mar 2021 16:10:58 +0100 Subject: [PATCH 09/72] New GameDataTags --- src/Impostor.Server/Net/State/Game.Data.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index bb386d6fc..cbe8d42e1 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -400,9 +400,16 @@ public async ValueTask HandleGameDataAsync(IMessageReader parent, ClientPl break; } + case 205: + case 206: + { + // TODO figure out what the hell is going on here + break; + } + default: { - _logger.LogTrace("Bad GameData tag {0}", reader.Tag); + _logger.LogWarning("Bad GameData tag {0}", reader.Tag); break; } } From acd2a56898f2f26811d0c96d2650378e61c91e67 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sat, 6 Mar 2021 17:20:36 +0100 Subject: [PATCH 10/72] Simplify Message01JoinGameC2S --- .../Net/Messages/C2S/Message01JoinGameC2S.cs | 10 +++++----- src/Impostor.Server/Net/Redirector/ClientRedirector.cs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs index 4b2541494..58a85120d 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs @@ -1,4 +1,6 @@ -namespace Impostor.Api.Net.Messages.C2S +using Impostor.Api.Games; + +namespace Impostor.Api.Net.Messages.C2S { public static class Message01JoinGameC2S { @@ -7,11 +9,9 @@ public static void Serialize(IMessageWriter writer) throw new System.NotImplementedException(); } - public static void Deserialize(IMessageReader reader, out int gameCode) + public static void Deserialize(IMessageReader reader, out GameCode gameCode) { - var slice = reader.ReadBytes(sizeof(int)).Span; - - gameCode = slice.ReadInt32(); + gameCode = reader.ReadInt32(); } } } diff --git a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs index 9a4edcc32..878a05273 100644 --- a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs +++ b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs @@ -57,7 +57,7 @@ public override async ValueTask HandleMessageAsync(IMessageReader reader, Messag Message01JoinGameC2S.Deserialize(reader, out var gameCode); using var packet = MessageWriter.Get(MessageType.Reliable); - var endpoint = await _nodeLocator.FindAsync(GameCodeParser.IntToGameName(gameCode)); + var endpoint = await _nodeLocator.FindAsync(gameCode); if (endpoint == null) { Message01JoinGameS2C.SerializeError(packet, false, DisconnectReason.GameMissing); From 1059a4da1659d9fee6f8501b0fbebbd7f4797a4a Mon Sep 17 00:00:00 2001 From: js6pak Date: Sat, 6 Mar 2021 18:13:16 +0100 Subject: [PATCH 11/72] Add debug logs in AnnouncementsService --- src/Impostor.Server/Net/AnnouncementsService.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Impostor.Server/Net/AnnouncementsService.cs b/src/Impostor.Server/Net/AnnouncementsService.cs index d205045e7..a58abf276 100644 --- a/src/Impostor.Server/Net/AnnouncementsService.cs +++ b/src/Impostor.Server/Net/AnnouncementsService.cs @@ -12,6 +12,7 @@ using Impostor.Server.Config; using Impostor.Server.Events.Announcements; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.ObjectPool; using Microsoft.Extensions.Options; @@ -19,13 +20,15 @@ namespace Impostor.Server.Net { internal class AnnouncementsService : IHostedService { + private readonly ILogger _logger; private readonly AnnouncementsServerConfig _config; private readonly ObjectPool _readerPool; private readonly IEventManager _eventManager; private UdpConnectionListener _connection; - public AnnouncementsService(IOptions config, ObjectPool readerPool, IEventManager eventManager) + public AnnouncementsService(ILogger logger, IOptions config, ObjectPool readerPool, IEventManager eventManager) { + _logger = logger; _config = config.Value; _readerPool = readerPool; _eventManager = eventManager; @@ -48,10 +51,13 @@ public async Task StartAsync(CancellationToken cancellationToken) }; await _connection.StartAsync(); + + _logger.LogInformation("Announcements server is listening on {Address}:{Port}", endpoint.Address, endpoint.Port); } public async Task StopAsync(CancellationToken cancellationToken) { + _logger.LogWarning("Announcements server is shutting down!"); await _connection.DisposeAsync(); } @@ -59,6 +65,8 @@ private async ValueTask OnNewConnection(NewConnectionEventArgs e) { MessageHello.Deserialize(e.HandshakeData, out var announcementVersion, out var id, out var language); + _logger.LogDebug("Client requested announcement (version: {Version}, id: {Id}, language: {Language})", announcementVersion, id, language); + if (announcementVersion != 2) { await e.Connection.Disconnect("Unsupported announcement version"); @@ -75,6 +83,8 @@ private async ValueTask OnNewConnection(NewConnectionEventArgs e) using var writer = MessageWriter.Get(MessageType.Reliable); Message00UseCache.Serialize(writer); await e.Connection.SendAsync(writer); + + _logger.LogDebug("Sent UseCache response"); } if (response.Announcement != null) @@ -83,6 +93,8 @@ private async ValueTask OnNewConnection(NewConnectionEventArgs e) var announcement = response.Announcement.Value; Message01Update.Serialize(writer, announcement.Id, announcement.Message); await e.Connection.SendAsync(writer); + + _logger.LogDebug("Sent ({Id}) {Message}", announcement.Id, announcement.Message); } if (response.FreeWeekendState != FreeWeekendState.NotFree) @@ -90,6 +102,8 @@ private async ValueTask OnNewConnection(NewConnectionEventArgs e) using var writer = MessageWriter.Get(MessageType.Reliable); Message02SetFreeWeekend.Serialize(writer, response.FreeWeekendState); await e.Connection.SendAsync(writer); + + _logger.LogDebug("Sent {FreeWeekendState} weekend state", response.FreeWeekendState); } await e.Connection.Disconnect(null); From 3090cea768c65189df7ac94243450c381bcb3262 Mon Sep 17 00:00:00 2001 From: miniduikboot <5243971+miniduikboot@users.noreply.github.com> Date: Sun, 7 Mar 2021 16:36:37 +0100 Subject: [PATCH 12/72] Remove fake player joining (#341) --- src/Impostor.Server/Net/State/Game.Data.cs | 45 +-------------------- src/Impostor.Server/Net/State/Game.State.cs | 1 - 2 files changed, 1 insertion(+), 45 deletions(-) diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index cbe8d42e1..eda8986cb 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -49,7 +49,6 @@ internal partial class Game private readonly Dictionary _allObjectsFast = new Dictionary(); private int _gamedataInitialized; - private bool _gamedataFakeReceived; private async ValueTask OnSpawnAsync(InnerNetObject netObj) { @@ -156,38 +155,8 @@ private async ValueTask OnDestroyAsync(InnerNetObject netObj) break; } - } - } - private async ValueTask InitGameDataAsync(ClientPlayer player) - { - if (Interlocked.Exchange(ref _gamedataInitialized, 1) != 0) - { - return; - } - /* - * The Among Us client on 20.9.22i spawns some components on the host side and - * only spawns these on other clients when someone else connects. This means that we can't - * parse data until someone connects because we don't know which component belongs to the NetId. - * - * We solve this by spawning a fake player and removing the player when the spawn GameData - * is received in HandleGameDataAsync. - */ - using (var message = MessageWriter.Get(MessageType.Reliable)) - { - // Spawn a fake player. - Message01JoinGameS2C.SerializeJoin(message, false, Code, FakeClientId, HostId); - - message.StartMessage(MessageFlags.GameData); - message.Write(Code); - message.StartMessage(GameDataTag.SceneChangeFlag); - message.WritePacked(FakeClientId); - message.Write("OnlineGame"); - message.EndMessage(); - message.EndMessage(); - - await player.Client.Connection.SendAsync(message); } } @@ -199,19 +168,7 @@ public async ValueTask HandleGameDataAsync(IMessageReader parent, ClientPl if (toPlayer) { var targetId = parent.ReadPackedInt32(); - if (targetId == FakeClientId && !_gamedataFakeReceived && sender.IsHost) - { - _gamedataFakeReceived = true; - - // Remove the fake client, we received the data. - using (var message = MessageWriter.Get(MessageType.Reliable)) - { - WriteRemovePlayerMessage(message, false, FakeClientId, (byte)DisconnectReason.ExitGame); - - await sender.Client.Connection.SendAsync(message); - } - } - else if (!TryGetPlayer(targetId, out target)) + if (!TryGetPlayer(targetId, out target)) { _logger.LogWarning("Player {0} tried to send GameData to unknown player {1}.", sender.Client.Id, targetId); return false; diff --git a/src/Impostor.Server/Net/State/Game.State.cs b/src/Impostor.Server/Net/State/Game.State.cs index e24e798a9..927548e72 100644 --- a/src/Impostor.Server/Net/State/Game.State.cs +++ b/src/Impostor.Server/Net/State/Game.State.cs @@ -25,7 +25,6 @@ private async ValueTask PlayerAdd(ClientPlayer player) if (HostId == -1) { HostId = player.Client.Id; - await InitGameDataAsync(player); } await _eventManager.CallAsync(new GamePlayerJoinedEvent(this, player)); From 0901be56f509e1b89aed43dbaebb8c81d8a1517e Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 7 Mar 2021 16:40:33 +0100 Subject: [PATCH 13/72] Implement GameData 205 --- src/Impostor.Api/Unity/RuntimePlatform.cs | 42 +++++++++++++++++++ src/Impostor.Server/Net/Inner/GameDataTag.cs | 3 +- src/Impostor.Server/Net/State/ClientPlayer.cs | 3 ++ src/Impostor.Server/Net/State/Game.Data.cs | 18 ++++++-- 4 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 src/Impostor.Api/Unity/RuntimePlatform.cs diff --git a/src/Impostor.Api/Unity/RuntimePlatform.cs b/src/Impostor.Api/Unity/RuntimePlatform.cs new file mode 100644 index 000000000..6951ca2a5 --- /dev/null +++ b/src/Impostor.Api/Unity/RuntimePlatform.cs @@ -0,0 +1,42 @@ +namespace Impostor.Api.Unity +{ + public enum RuntimePlatform + { + OSXEditor = 0, + OSXPlayer = 1, + WindowsPlayer = 2, + OSXWebPlayer = 3, + OSXDashboardPlayer = 4, + WindowsWebPlayer = 5, + WindowsEditor = 7, + IPhonePlayer = 8, + PS3 = 9, + XBOX360 = 10, + Android = 11, + NaCl = 12, + LinuxPlayer = 13, + FlashPlayer = 15, + LinuxEditor = 16, + WebGLPlayer = 17, + MetroPlayerX86 = 18, + WSAPlayerX86 = 18, + MetroPlayerX64 = 19, + WSAPlayerX64 = 19, + MetroPlayerARM = 20, + WSAPlayerARM = 20, + WP8Player = 21, + BlackBerryPlayer = 22, + TizenPlayer = 23, + PSP2 = 24, + PS4 = 25, + PSM = 26, + XboxOne = 27, + SamsungTVPlayer = 28, + WiiU = 30, + TvOs = 31, + Switch = 32, + Lumin = 33, + Stadia = 34, + CloudRendering = 35, + } +} diff --git a/src/Impostor.Server/Net/Inner/GameDataTag.cs b/src/Impostor.Server/Net/Inner/GameDataTag.cs index fa9ddb8cb..818f11ff7 100644 --- a/src/Impostor.Server/Net/Inner/GameDataTag.cs +++ b/src/Impostor.Server/Net/Inner/GameDataTag.cs @@ -9,5 +9,6 @@ public static class GameDataTag public const byte SceneChangeFlag = 6; public const byte ReadyFlag = 7; public const byte ChangeSettingsFlag = 8; + public const byte ClientInfoFlag = 205; } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/State/ClientPlayer.cs b/src/Impostor.Server/Net/State/ClientPlayer.cs index 107edbfef..ceb73b49e 100644 --- a/src/Impostor.Server/Net/State/ClientPlayer.cs +++ b/src/Impostor.Server/Net/State/ClientPlayer.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Impostor.Api.Net; using Impostor.Api.Net.Inner; +using Impostor.Api.Unity; using Impostor.Server.Net.Inner.Objects; using Microsoft.Extensions.Logging; @@ -36,6 +37,8 @@ public ClientPlayer(ILogger logger, ClientBase client, Game game) public string Scene { get; internal set; } + public RuntimePlatform? Platform { get; internal set; } + public void InitializeSpawnTimeout() { _spawnTimeout.Change(Constants.SpawnTimeout, -1); diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index eda8986cb..a2eaa09d3 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -7,6 +7,7 @@ using Impostor.Api.Net.Inner; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.S2C; +using Impostor.Api.Unity; using Impostor.Hazel; using Impostor.Server.Events.Meeting; using Impostor.Server.Events.Player; @@ -357,10 +358,21 @@ public async ValueTask HandleGameDataAsync(IMessageReader parent, ClientPl break; } - case 205: - case 206: + case GameDataTag.ClientInfoFlag: { - // TODO figure out what the hell is going on here + var clientId = reader.ReadPackedInt32(); + var platform = (RuntimePlatform)reader.ReadPackedInt32(); + + if (clientId != sender.Client.Id) + { + if (await sender.Client.ReportCheatAsync(new CheatContext(nameof(GameDataTag.ClientInfoFlag)), "Client sent info with wrong client id")) + { + return false; + } + } + + sender.Platform = platform; + break; } From 9915f8b0cf3ce69d97c871fddb44dddeb61913d8 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 7 Mar 2021 16:49:57 +0100 Subject: [PATCH 14/72] Expose IsCancelled to IPlayerChatEvent --- src/Impostor.Api/Events/Game/Player/IPlayerChatEvent.cs | 2 +- src/Impostor.Server/Events/Game/Player/PlayerChatEvent.cs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Impostor.Api/Events/Game/Player/IPlayerChatEvent.cs b/src/Impostor.Api/Events/Game/Player/IPlayerChatEvent.cs index 52efe9653..914701025 100644 --- a/src/Impostor.Api/Events/Game/Player/IPlayerChatEvent.cs +++ b/src/Impostor.Api/Events/Game/Player/IPlayerChatEvent.cs @@ -1,6 +1,6 @@ namespace Impostor.Api.Events.Player { - public interface IPlayerChatEvent : IPlayerEvent + public interface IPlayerChatEvent : IPlayerEvent, IEventCancelable { /// /// Gets the message sent by the player. diff --git a/src/Impostor.Server/Events/Game/Player/PlayerChatEvent.cs b/src/Impostor.Server/Events/Game/Player/PlayerChatEvent.cs index 32c156145..34ec95ed2 100644 --- a/src/Impostor.Server/Events/Game/Player/PlayerChatEvent.cs +++ b/src/Impostor.Server/Events/Game/Player/PlayerChatEvent.cs @@ -1,12 +1,11 @@ -using Impostor.Api.Events; -using Impostor.Api.Events.Player; +using Impostor.Api.Events.Player; using Impostor.Api.Games; using Impostor.Api.Net; using Impostor.Api.Net.Inner.Objects; namespace Impostor.Server.Events.Player { - public class PlayerChatEvent : IPlayerChatEvent, IEventCancelable + public class PlayerChatEvent : IPlayerChatEvent { public PlayerChatEvent(IGame game, IClientPlayer clientPlayer, IInnerPlayerControl playerControl, string message) { From 20d5284a7a54552111d676fdf3544576a9dda0e2 Mon Sep 17 00:00:00 2001 From: Galster-dev <46283010+Galster-dev@users.noreply.github.com> Date: Thu, 11 Mar 2021 01:06:12 +0300 Subject: [PATCH 15/72] minor README.md changes (#342) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1ce3f9494..6f2543b32 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ # Impostor [![Discord](https://img.shields.io/badge/Discord-chat-blue?style=flat-square)](https://discord.gg/Mk3w6Tb) -[![AppVeyor](https://img.shields.io/appveyor/build/Impostor/Impostor/dev?style=flat-square)](https://ci.appveyor.com/project/Impostor/Impostor/branch/dev) +[![AppVeyor](https://img.shields.io/appveyor/build/Impostor/Impostor/master?style=flat-square)](https://ci.appveyor.com/project/Impostor/Impostor/branch/master) Impostor is one of the first **Among Us** private servers, written in C#. -We support Steam, Itch, Android and iOS. The latest version supported is `2020.9.22`, the `dev` build currently supports `2020.11.17`. +We support Steam, Itch, Android and iOS. The latest version supported is `2020.9.22`, the `master` build currently supports `2020.12.9`. | Impostor version | Among Us version | Experimental | Download | |-|-|-|-| | 1.1.0 | 2020.09.07 - 2020.09.22 | No | [![Download](https://img.shields.io/badge/Download-v1.1.0-blue?style=flat-square)](https://github.com/Impostor/Impostor/releases/tag/v1.1.0) | -| 1.2.2 | 2020.09.22 - 2020.11.17 | Yes | [![Download](https://img.shields.io/badge/Download-v1.2.2-blue?style=flat-square)](https://ci.appveyor.com/project/Impostor/Impostor/branch/dev/artifacts) | +| 1.2.2 | 2020.09.22 - 2020.11.17 | Yes | [![Download](https://img.shields.io/badge/Download-v1.2.2-blue?style=flat-square)](https://ci.appveyor.com/project/Impostor/Impostor/branch/master/artifacts) | ## Features From 443168ef7163ac15111dd6da2d08c9f0f9f8cb86 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 14 Mar 2021 20:50:55 +0000 Subject: [PATCH 16/72] Add DateTime to server replays (#349) --- src/.editorconfig | 5 +- src/Impostor.Api/IDateTimeProvider.cs | 9 +++ src/Impostor.Server/Net/Client.cs | 4 +- src/Impostor.Server/Net/ClientBase.cs | 5 +- .../Net/Factories/ClientFactory.cs | 4 +- .../Net/Inner/Objects/InnerPlayerControl.cs | 12 ++-- .../Net/Inner/Objects/InnerPlayerInfo.cs | 5 +- .../Net/Redirector/ClientRedirector.cs | 3 +- src/Impostor.Server/Program.cs | 2 + src/Impostor.Server/RealDateTimeProvider.cs | 10 ++++ .../Recorder/ClientRecorder.cs | 4 +- .../Recorder/PacketRecorder.cs | 54 +++++++++++++----- .../Recorder/ServerReplayVersion.cs | 18 ++++++ .../FakeDateTimeProvider.cs | 10 ++++ src/Impostor.Tools.ServerReplay/Program.cs | 23 +++++++- .../sessions/.gitkeep | 0 ...on_1604255331821_dead_player_exception.dat | Bin 47057 -> 0 bytes 17 files changed, 135 insertions(+), 33 deletions(-) create mode 100644 src/Impostor.Api/IDateTimeProvider.cs create mode 100644 src/Impostor.Server/RealDateTimeProvider.cs create mode 100644 src/Impostor.Server/Recorder/ServerReplayVersion.cs create mode 100644 src/Impostor.Tools.ServerReplay/FakeDateTimeProvider.cs create mode 100644 src/Impostor.Tools.ServerReplay/sessions/.gitkeep delete mode 100644 src/Impostor.Tools.ServerReplay/sessions/session_1604255331821_dead_player_exception.dat diff --git a/src/.editorconfig b/src/.editorconfig index af97d16c2..38c708527 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -163,7 +163,7 @@ csharp_new_line_before_open_brace = all csharp_new_line_before_else = true csharp_new_line_before_catch = true csharp_new_line_before_finally = true -csharp_new_line_before_members_in_object_initializers = true +# csharp_new_line_before_members_in_object_initializers = true TODO seems like Rider/ReSharper has the value inverted, uncomment when its fixed csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_between_query_expression_clauses = true @@ -228,3 +228,6 @@ csharp_preserve_single_line_statements = true # warning RS0037: PublicAPI.txt is missing '#nullable enable' dotnet_diagnostic.RS0037.severity = none + +# ReSharper properties +resharper_trailing_comma_in_multiline_lists = true diff --git a/src/Impostor.Api/IDateTimeProvider.cs b/src/Impostor.Api/IDateTimeProvider.cs new file mode 100644 index 000000000..95b3dee9e --- /dev/null +++ b/src/Impostor.Api/IDateTimeProvider.cs @@ -0,0 +1,9 @@ +using System; + +namespace Impostor.Api +{ + public interface IDateTimeProvider + { + DateTimeOffset UtcNow { get; } + } +} diff --git a/src/Impostor.Server/Net/Client.cs b/src/Impostor.Server/Net/Client.cs index 713ef8831..f26de4026 100644 --- a/src/Impostor.Server/Net/Client.cs +++ b/src/Impostor.Server/Net/Client.cs @@ -24,8 +24,8 @@ internal class Client : ClientBase private readonly ClientManager _clientManager; private readonly GameManager _gameManager; - public Client(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, IHazelConnection connection, ISet mods) - : base(name, connection, mods) + public Client(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, int gameVersion, IHazelConnection connection, ISet mods) + : base(name, gameVersion, connection, mods) { _logger = logger; _antiCheatConfig = antiCheatOptions.Value; diff --git a/src/Impostor.Server/Net/ClientBase.cs b/src/Impostor.Server/Net/ClientBase.cs index bae1fb33f..7bff06efe 100644 --- a/src/Impostor.Server/Net/ClientBase.cs +++ b/src/Impostor.Server/Net/ClientBase.cs @@ -16,9 +16,10 @@ namespace Impostor.Server.Net { internal abstract class ClientBase : IClient { - protected ClientBase(string name, IHazelConnection connection, ISet mods) + protected ClientBase(string name, int gameVersion, IHazelConnection connection, ISet mods) { Name = name; + GameVersion = gameVersion; Connection = connection; Mods = mods; Items = new ConcurrentDictionary(); @@ -40,6 +41,8 @@ protected ClientBase(string name, IHazelConnection connection, ISet mods) public string Name { get; } + public int GameVersion { get; } + public ISet Mods { get; } public Dictionary ModIdMap { get; } diff --git a/src/Impostor.Server/Net/Factories/ClientFactory.cs b/src/Impostor.Server/Net/Factories/ClientFactory.cs index ab6eedf61..985ab4e0e 100644 --- a/src/Impostor.Server/Net/Factories/ClientFactory.cs +++ b/src/Impostor.Server/Net/Factories/ClientFactory.cs @@ -18,9 +18,9 @@ public ClientFactory(IServiceProvider serviceProvider) public ClientBase Create(IHazelConnection connection, string name, int clientVersion, ISet mods) { - var client = ActivatorUtilities.CreateInstance(_serviceProvider, name, connection, mods); + var client = ActivatorUtilities.CreateInstance(_serviceProvider, name, clientVersion, connection, mods); connection.Client = client; return client; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs index c2759139a..8391ed088 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs @@ -13,7 +13,6 @@ using Impostor.Server.Events.Player; using Impostor.Server.Net.Inner.Objects.Components; using Impostor.Server.Net.State; -using Impostor.Server.Utils; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -24,14 +23,14 @@ internal partial class InnerPlayerControl : InnerNetObject private readonly ILogger _logger; private readonly IEventManager _eventManager; private readonly Game _game; - private readonly ServerEnvironment _serverEnvironment; + private readonly IDateTimeProvider _dateTimeProvider; - public InnerPlayerControl(ILogger logger, IServiceProvider serviceProvider, IEventManager eventManager, Game game, ServerEnvironment serverEnvironment) + public InnerPlayerControl(ILogger logger, IServiceProvider serviceProvider, IEventManager eventManager, Game game, IDateTimeProvider dateTimeProvider) { _logger = logger; _eventManager = eventManager; _game = game; - _serverEnvironment = serverEnvironment; + _dateTimeProvider = dateTimeProvider; Physics = ActivatorUtilities.CreateInstance(serviceProvider, this, _eventManager, _game); NetworkTransform = ActivatorUtilities.CreateInstance(serviceProvider, this, _game); @@ -520,8 +519,7 @@ private async ValueTask HandleSetSkin(ClientPlayer sender, SkinType skin) private async ValueTask HandleMurderPlayer(ClientPlayer sender, IInnerPlayerControl? target) { - // TODO record replay with timestamps - if (!_serverEnvironment.IsReplay && !PlayerInfo.CanMurder(_game)) + if (!PlayerInfo.CanMurder(_game, _dateTimeProvider)) { if (await sender.Client.ReportCheatAsync(RpcCalls.MurderPlayer, "Client tried to murder too fast")) { @@ -537,7 +535,7 @@ private async ValueTask HandleMurderPlayer(ClientPlayer sender, IInnerPlay } } - PlayerInfo.LastMurder = DateTimeOffset.UtcNow; + PlayerInfo.LastMurder = _dateTimeProvider.UtcNow; if (!target.PlayerInfo.IsDead) { diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs index 410b4af61..301fc0881 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Impostor.Api; using Impostor.Api.Games; using Impostor.Api.Innersloth; using Impostor.Api.Innersloth.Customization; @@ -40,14 +41,14 @@ public InnerPlayerInfo(byte playerId) public DateTimeOffset LastMurder { get; set; } - public bool CanMurder(IGame game) + public bool CanMurder(IGame game, IDateTimeProvider dateTimeProvider) { if (!IsImpostor) { return false; } - return DateTimeOffset.UtcNow.Subtract(LastMurder).TotalSeconds >= game.Options.KillCooldown; + return dateTimeProvider.UtcNow.Subtract(LastMurder).TotalSeconds >= game.Options.KillCooldown; } public void Serialize(IMessageWriter writer) diff --git a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs index 878a05273..afae57e8b 100644 --- a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs +++ b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs @@ -24,12 +24,13 @@ internal class ClientRedirector : ClientBase public ClientRedirector( string name, + int gameVersion, HazelConnection connection, ISet mods, ClientManager clientManager, INodeProvider nodeProvider, INodeLocator nodeLocator) - : base(name, connection, mods) + : base(name, gameVersion, connection, mods) { _clientManager = clientManager; _nodeProvider = nodeProvider; diff --git a/src/Impostor.Server/Program.cs b/src/Impostor.Server/Program.cs index 2af8d5504..109c6be01 100644 --- a/src/Impostor.Server/Program.cs +++ b/src/Impostor.Server/Program.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Linq; +using Impostor.Api; using Impostor.Api.Events.Managers; using Impostor.Api.Games; using Impostor.Api.Games.Managers; @@ -117,6 +118,7 @@ private static IHostBuilder CreateHostBuilder(string[] args) .Get() ?? new AnnouncementsServerConfig(); services.AddSingleton(); + services.AddSingleton(); services.Configure(host.Configuration.GetSection(DebugConfig.Section)); services.Configure(host.Configuration.GetSection(AntiCheatConfig.Section)); diff --git a/src/Impostor.Server/RealDateTimeProvider.cs b/src/Impostor.Server/RealDateTimeProvider.cs new file mode 100644 index 000000000..506e0c0d9 --- /dev/null +++ b/src/Impostor.Server/RealDateTimeProvider.cs @@ -0,0 +1,10 @@ +using System; +using Impostor.Api; + +namespace Impostor.Server +{ + public class RealDateTimeProvider : IDateTimeProvider + { + public DateTimeOffset UtcNow => DateTimeOffset.UtcNow; + } +} diff --git a/src/Impostor.Server/Recorder/ClientRecorder.cs b/src/Impostor.Server/Recorder/ClientRecorder.cs index 868aa0a4c..fe9d94cc6 100644 --- a/src/Impostor.Server/Recorder/ClientRecorder.cs +++ b/src/Impostor.Server/Recorder/ClientRecorder.cs @@ -18,8 +18,8 @@ internal class ClientRecorder : Client private bool _createdGame; private bool _recordAfter; - public ClientRecorder(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, HazelConnection connection, ISet mods, PacketRecorder recorder) - : base(logger, antiCheatOptions, clientManager, gameManager, name, connection, mods) + public ClientRecorder(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, int gameVersion, HazelConnection connection, ISet mods, PacketRecorder recorder) + : base(logger, antiCheatOptions, clientManager, gameManager, name, gameVersion, connection, mods) { _recorder = recorder; _isFirst = true; diff --git a/src/Impostor.Server/Recorder/PacketRecorder.cs b/src/Impostor.Server/Recorder/PacketRecorder.cs index af2ea4f1f..c8efdb35a 100644 --- a/src/Impostor.Server/Recorder/PacketRecorder.cs +++ b/src/Impostor.Server/Recorder/PacketRecorder.cs @@ -8,6 +8,7 @@ using Impostor.Api.Net.Messages; using Impostor.Server.Config; using Impostor.Server.Net; +using Impostor.Server.Utils; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.ObjectPool; @@ -24,6 +25,7 @@ internal class PacketRecorder : BackgroundService private readonly ILogger _logger; private readonly ObjectPool _pool; private readonly Channel _channel; + private DateTimeOffset _startTime; public PacketRecorder(ILogger logger, IOptions options, ObjectPool pool) { @@ -42,10 +44,13 @@ public PacketRecorder(ILogger logger, IOptions opti 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 { @@ -73,7 +78,7 @@ public async Task WriteConnectAsync(ClientRecorder client) try { - WriteHeader(context, RecordedPacketType.Connect); + WritePacketHeader(context, RecordedPacketType.Connect); WriteClient(context, client, true); WriteLength(context); @@ -93,7 +98,7 @@ public async Task WriteDisconnectAsync(ClientRecorder client, string reason) try { - WriteHeader(context, RecordedPacketType.Disconnect); + WritePacketHeader(context, RecordedPacketType.Disconnect); WriteClient(context, client, false); context.Writer.Write(reason); WriteLength(context); @@ -114,7 +119,7 @@ public async Task WriteMessageAsync(ClientRecorder client, IMessageReader reader try { - WriteHeader(context, RecordedPacketType.Message); + WritePacketHeader(context, RecordedPacketType.Message); WriteClient(context, client, false); WritePacket(context, reader, messageType); WriteLength(context); @@ -135,7 +140,7 @@ public async Task WriteGameCreatedAsync(ClientRecorder client, GameCode gameCode try { - WriteHeader(context, RecordedPacketType.GameCreated); + WritePacketHeader(context, RecordedPacketType.GameCreated); WriteClient(context, client, false); WriteGameCode(context, gameCode); WriteLength(context); @@ -148,11 +153,33 @@ public async Task WriteGameCreatedAsync(ClientRecorder client, GameCode gameCode } } - private static void WriteHeader(PacketSerializationContext context, RecordedPacketType type) + private async Task WriteFileHeaderAsync() + { + var context = _pool.Get(); + + try + { + context.Writer.Write((uint)ServerReplayVersion.Initial); + context.Writer.Write(_startTime.ToUnixTimeMilliseconds()); + context.Writer.Write(DotnetUtils.GetVersion()); + + await WriteAsync(context.Stream); + } + finally + { + _pool.Return(context); + } + } + + private void WritePacketHeader(PacketSerializationContext context, RecordedPacketType type) { // Length placeholder. - context.Writer.Write((int) 0); - context.Writer.Write((byte) type); + context.Writer.Write(0); + + // Timestamp relative to recording start time. + context.Writer.Write((uint)(DateTimeOffset.UtcNow - _startTime).TotalMilliseconds); + + context.Writer.Write((byte)type); } private static void WriteClient(PacketSerializationContext context, ClientBase client, bool full) @@ -164,18 +191,19 @@ private static void WriteClient(PacketSerializationContext context, ClientBase c if (full) { - context.Writer.Write((byte) addressBytes.Length); + context.Writer.Write((byte)addressBytes.Length); context.Writer.Write(addressBytes); - context.Writer.Write((ushort) address.Port); + context.Writer.Write((ushort)address.Port); context.Writer.Write(client.Name); + context.Writer.Write(client.GameVersion); } } private static void WritePacket(PacketSerializationContext context, IMessageReader reader, MessageType messageType) { - context.Writer.Write((byte) messageType); - context.Writer.Write((byte) reader.Tag); - context.Writer.Write((int) reader.Length); + context.Writer.Write((byte)messageType); + context.Writer.Write((byte)reader.Tag); + context.Writer.Write((int)reader.Length); context.Writer.Write(reader.Buffer, reader.Offset, reader.Length); } @@ -189,7 +217,7 @@ private static void WriteLength(PacketSerializationContext context) var length = context.Stream.Position; context.Stream.Position = 0; - context.Writer.Write((int) length); + context.Writer.Write((int)length); context.Stream.Position = length; } diff --git a/src/Impostor.Server/Recorder/ServerReplayVersion.cs b/src/Impostor.Server/Recorder/ServerReplayVersion.cs new file mode 100644 index 000000000..648205b54 --- /dev/null +++ b/src/Impostor.Server/Recorder/ServerReplayVersion.cs @@ -0,0 +1,18 @@ +namespace Impostor.Server.Recorder +{ + /// + /// Version of the server replay data format. + /// + public enum ServerReplayVersion + { + /// + /// Initial version + /// + Initial = 1, + + /// + /// Latest version + /// + Latest = Initial, + } +} diff --git a/src/Impostor.Tools.ServerReplay/FakeDateTimeProvider.cs b/src/Impostor.Tools.ServerReplay/FakeDateTimeProvider.cs new file mode 100644 index 000000000..7bd4beb01 --- /dev/null +++ b/src/Impostor.Tools.ServerReplay/FakeDateTimeProvider.cs @@ -0,0 +1,10 @@ +using System; +using Impostor.Api; + +namespace Impostor.Tools.ServerReplay +{ + public class FakeDateTimeProvider : IDateTimeProvider + { + public DateTimeOffset UtcNow { get; set; } + } +} diff --git a/src/Impostor.Tools.ServerReplay/Program.cs b/src/Impostor.Tools.ServerReplay/Program.cs index c36ed24c6..261d679b6 100644 --- a/src/Impostor.Tools.ServerReplay/Program.cs +++ b/src/Impostor.Tools.ServerReplay/Program.cs @@ -4,6 +4,7 @@ using System.IO; using System.Net; using System.Threading.Tasks; +using Impostor.Api; using Impostor.Api.Events.Managers; using Impostor.Api.Games; using Impostor.Api.Games.Managers; @@ -42,6 +43,7 @@ internal static class Program private static MockGameCodeFactory _gameCodeFactory; private static ClientManager _clientManager; private static GameManager _gameManager; + private static FakeDateTimeProvider _fakeDateTimeProvider; private static async Task Main(string[] args) { @@ -53,7 +55,7 @@ private static async Task Main(string[] args) var stopwatch = Stopwatch.StartNew(); - foreach (var file in Directory.GetFiles(args[0])) + foreach (var file in Directory.GetFiles(args[0], "*.dat")) { // Clear. Connections.Clear(); @@ -67,6 +69,7 @@ private static async Task Main(string[] args) _gameCodeFactory = _serviceProvider.GetRequiredService(); _clientManager = _serviceProvider.GetRequiredService(); _gameManager = _serviceProvider.GetRequiredService(); + _fakeDateTimeProvider = _serviceProvider.GetRequiredService(); await using (var stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read)) using (var reader = new BinaryReader(stream)) @@ -89,6 +92,9 @@ private static ServiceProvider BuildServices() IsReplay = true }); + services.AddSingleton(); + services.AddSingleton(p => p.GetRequiredService()); + services.AddLogging(builder => { builder.ClearProviders(); @@ -114,6 +120,17 @@ private static ServiceProvider BuildServices() private static async Task ParseSession(BinaryReader reader) { + var protocolVersion = (ServerReplayVersion)reader.ReadUInt32(); + if (protocolVersion < ServerReplayVersion.Initial || protocolVersion > ServerReplayVersion.Latest) + { + throw new NotSupportedException("Session's protocol version is unsupported"); + } + + var startTime = _fakeDateTimeProvider.UtcNow = DateTimeOffset.FromUnixTimeMilliseconds(reader.ReadInt64()); + var serverVersion = reader.ReadString(); + + Logger.Information("Loaded session (server: {ServerVersion}, recorded at {StartTime})", serverVersion, startTime); + while (reader.BaseStream.Position < reader.BaseStream.Length) { var dataLength = reader.ReadInt32(); @@ -122,6 +139,7 @@ private static async Task ParseSession(BinaryReader reader) await using (var stream = new MemoryStream(data)) using (var readerInner = new BinaryReader(stream)) { + _fakeDateTimeProvider.UtcNow = startTime + TimeSpan.FromMilliseconds(readerInner.ReadUInt32()); await ParsePacket(readerInner); } } @@ -143,11 +161,12 @@ private static async Task ParsePacket(BinaryReader reader) var addressPort = reader.ReadUInt16(); var address = new IPEndPoint(new IPAddress(addressBytes), addressPort); var name = reader.ReadString(); + var gameVersion = reader.ReadInt32(); // Create and register connection. var connection = new MockHazelConnection(address); - await _clientManager.RegisterConnectionAsync(connection, name, 50516550, null); + await _clientManager.RegisterConnectionAsync(connection, name, gameVersion, null); // Store reference for ourselfs. Connections.Add(clientId, connection); diff --git a/src/Impostor.Tools.ServerReplay/sessions/.gitkeep b/src/Impostor.Tools.ServerReplay/sessions/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/src/Impostor.Tools.ServerReplay/sessions/session_1604255331821_dead_player_exception.dat b/src/Impostor.Tools.ServerReplay/sessions/session_1604255331821_dead_player_exception.dat deleted file mode 100644 index e5f441bb7c3890f6485d04b86bc1a77419906a43..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47057 zcmb`Q34B$>_4vckdTms5E2rS7s4i@q9`CJJ8p=mD2S{of`TAY z5k#rhePI}YujIcmESpY@4IvFn>Xiz?ep`(^WE<|XO=T_ zXXea3lLY{Vfq$ZwesuXGs{$|E-$i%gM|#CWl<&tA zCrcGh!GIiyiZTp;l#dt`X2gh8omg)ER|UQ(UxojqQ)(FT_=^~s zX+QpNY#jYf_S4^PP4qVo(!uA;!+c3H4zB=yAIe%>41T1n8AcX z@NcM41MWhdAG8V;%Mu~8P`lwLAN^EFC*4YoiE^eZhAd~I&9aZ~jvpz3QJA9?I8jJf z1Rb4fU5SSnf83e#=3X*y_Q>g%&%W6HZOkN#@P}1WA4esnP@RMqP6$r)%2fk2$7fhhc$QUk@d*yx^?So(>urGT)dKpY4opr4<*5ww$h(cGfzEcuBj zKc>6gYV)f}VQlvdGFYq;=auflWQ8G-dXWukkV-a$A<>m^Lo&@JR2*nX0W>6?i5aGe z2{}#^i*}gU-KfOOP|RBVNc9jMW@3XJCRR-CN>-8C1|#H=v$~^;53Ii6hE>ZPCI+^N z8PK$N+uo@5s zChUrOL&dIy<Kc2CMh`moDY(VaOO4T%DFwV{OYHe@298l^Ur zV6`E$b{uUeLA0R+(S{P@AaWB)a5j-z5*KS&O~mhLBDIESBEncjl0`eTtht*XIh_(Tp@@T*AN{ml;C1B9l$ZU^3x@l5X>0s&EcW;z{{9gy?<( zFGhZ~=8OOuPx=jCET%CRd#2=!-r}PX(+z^1v5O`wp0HR0#KBn|84DSpJM=j4 z*|iK1kHEoe9$BSTkpTG}2d|-9uqF+OUO*2U5cVlTyY$UB% z5oH9v`{tV~-b(r_nBJU~?2XptueNn=M#gDAg z0EuwV-bXkUJ-mP<8|Z~)VU5+|@FNu-4XWY;qP)$HB6Mq_K{n2aHL2}xFvs)|(jTNewY!4#}bMnXEw>BQ;|Wm8qrQ%JCLp#m8q4GfSe za=`$-V9yc%*kd;zyIB;Jsv-;id}P%bCzfx$MFV6b(EBU~$U&fU90TMcaP~P2kOxIi zzcZdmWN%o1bmX~AHuItMSr#aOXP;w%LYVvl3-p2SUu1zISpPB$6hrAT7AS#df5`%U zVe)YnD24A|V}UYQ{{{>6gVMKHpd221JK@}8H`iUKF_;Q?^_{QIVSxVd)w{nun*k~z z@z;-zV}L5S{WtT*G4?P3%HC&zYIy#)EKmbeK45`b_~Anq7zooo`qx=ZF6v`p%htG0hC3{I8Z(+#LM#TqxDO31K*-k5N|IcLOygvfL^hzSIS&znU{_TsWx zijK>E*JUv@igsL%W-g-xT9nO_#TrM>n&W_ZG&W<#P ziz*#gxBze&$;iO*tpU_Z=)Vn8&kFn~tk$u%xfa}(Vj`^(@jU!U$q7r1!w;8A`3qNS*qOu;u9Zpj!=<0{GG4md50@_daOq<4 zEnO_WrN;^XA1*lRa)Wv^Pff42z?m)9^mDLya$UuP0<%v|U>W#QBY6s??`6*JwAE9rPe^c7|o>*y;^VU3>Juw#ur z)pL#B%5S9HGCfMjed=i8Ky!7`!lfh2Vd3BlS@_AU(dUUZdhE81{O~rBcWP|{J*%nc ze5D$qm#}GbmQA%uCPRMsyl|T~kx=cB<>u+u=<|e8<_V+B)2-3xIc<>E=<~!HJz1Z+ zXlO1(h$K4~3v<1e$+N;1@yWzoLyZjSZ7aY_qW!yoT(5=ptS~o#sv^uSrshH})r&Mx z3vs0(OF9w+psJ8QA^}icxg_L!E$QcbE$QdWC4Hen%|#64EJc?^XjM-I0`LU^cvsR$ zi1h-xxdF8t0+6!gjnzw6&A&mYP=RicyyQ(xqLl^}i1PxvdjauYK!OcaV>MabHT831 z_<=X;ZaKKaCH%gXLj@XnIGmnhMC-2jqI6gM8V^i*N|eR}lb#ZN@*bGqAI4 zeF%k?4?zq$T|R`uOhe;CNKeAejbIe|G(Lnv^dYoPTWL0b;X_Er$vgc*=R+toeF&%}IuAQquJ_0l3;<^eHgaGrFs{(~?K((e`@Flr=^zE#VmxL^6 zebymCRgn#w$y7orR3HatKF``xt{0H!2GnvW!d&EWC0UHXD*J-7i|`^0gb(RcIw8 zMt0qkBwygo<6i|6r8w$*aqWr|7vG3itr2B8ex&>siQXD_dc1r5^I+nVgsUwQi010RC$5GACJEmOkB6{cfol0 z_V>YzuRi=FXw0AUX)t}txnBfht*nrE`&EFS#0rnATgZxs&FEURM_cObFacUwM{!mn z_Fd!TjYgHw177YZB1f^tNt=~~!0WPmR3#)MaNS5oLJFyn{iiA+6%+YGyWP2|KpJEo zjOKuJi0ev|-J>d@C;Y3cu#HiX0p*82X=QSeiNIRfJ*p~tp^DRn>iywaS(wO4%?ywY zA9VhsiK*^9I7~pOdsNfV8;rHhmKM!6ED$6;3tjs7h+Q8Q*L#p*$06vc{@>yqX?#S ze%-*7crgSzzHVSjyae{_XMw&jWgiQaLf|PDD1$wFSfC%=w;O>_t*e8i-ca>|V-%&9 zL%ElPd|34&E1|+mLIEVb^t|jx)I=5{Fi(zXRiF<7nX;o%fg(~N`w}zl8mb-qp&NUeXZuk+UO-A1$()~(e{oM zRYfXpg8F(S1Ej$lFWiXbV5LEokPZbe)C{k?&e|QM0zF~%b2Y>5U2`gs0pC2s0+}%W zC=2w0Lq}L33knXiKsK!IVu2j^rjrG7VSEP*0fMB0HbLpq&_*h7|DhHb zMk;Xsp%!Q-72_FTIP~9n)wxV3HUgS<%sh_)M#2+ME}6in7=^&w6B%GM0)5YCfYV6D zWCj=m-FG}b<&jm|uK0BL_l|8BFu+(WsC5@Iz!~t-u4Pjh;7oXH_Z8C^;4B1Qn9k&4 z90FN08Q^S8L-$!sU7Q2kcMh3lj~~>AGag3oV1aYtuTQYRd9eL)7MK8|A7g=uQ1$5J zGwo53n#f5o^pS%z7~p&u`|vB%8Q=m~@z5(&)Vf>Jg_ z7x@cmTbKFZKg4bsT-XwtO@{u}-2A3N6JXqht83(oMIssCdhp$L$4mxT0u$D=z*4wrL-kB% zm2Mf_di(qtw!cX2?3Tkv8(Cll4BW&5E8*6kvA_+m;m%#tnMB?QXKj9L8rFqw-Rfqz zVDr0EnaW!21+1|Frauk-^!`+IuU1Fu(VyM|S8RS^YVRA$mT7GFR_NIL1dau)M=sSm zTMLig)rF%8EwB!OSyPw-y$u?+jG4?xSP$h}&p)35HbDE`$0jj`bvta`#sVAR+k05x z4rt%b0-NB$?LTk>w>uGNq=B2RiEg$5tyu&zY42gkbrD+FjUm^Ck(P)1dM!sp_@Zwh z)35(sPjd-ZT{mdKb%Ry33S^GSRiG7K+jT4X6m>ulfsa}kpbde#AOj2|6>`?ErlFlw z$XUM%3?~&d!_p;k1gVg-epSLqQXyykDlm#v$QhOjj3yPdzN$;ZX{160y*g!ABoo!3vcZ}=)O0lwUE`4k422>*QY!V4H+62v}v=7kJ! zK4d%*oXP-`q4@EdX$&w020qpY=LOcVMa{(pFznHEIq*?|3*qaB(`VSj78RHZTOMM8 zX)x?T7MKoS|AGZ(z?S=2U?vQ^j|FDI*V|cOHf*_<1?Ir8dsyHi`1)=ZxEQu7Wt2AsUb%jvrr{a{ekws^D*M8PVE>);?u^JX`Vu3YKcn1sI0y!IDWgM&3D_ zld2oy-T`xOJ~rd#CYKpqXxNrDkg5h-cc5$+|= zO>bPAefr&?NqU-3ld^5lxc1jHWYl#A_aLy6bL!uVKn3U2-%cvz<{&lmKPMHOQ~y2$ z_DT1KD&c-F;1_N{oq*mIns}MzpaNSEm`DAMZsN5SmT$j|1Mc<$w!szKo6j#;c8eMN zNKL~%aOu6*%YIh{?uGPwSYSIGy_*Go4i9gQKi}?mRTcNa{w+Up!2JlELn8olmZD1d z1&rUaLiW2V@Bqxb>nhprs=$MA>*gu4TUCLF5Lh&osjP=#-R7wr@Q4@iDE#BjO4)O( zX?P4i`q|NG_Dxa+9*37Ukp%6U#}n}G9nCm=*8)$%|J!&v7L*p)0cUTlk;64L4LcF| zkZzJXv)_fl8aY@{CF~{@G*i+^*h4C4uB8L^BJdf_)^sgvzZY=83+S)`?czpKX4`+d zR%T##Y`G-xU(w;J<<*Hvd4O`OD~^K*jHTJF4(LMQA2dJK0f$Hh&9HUAVNyYJbRBSn zRM0G62RuzGXq`X@93>UB(x3yLAraWdgz1^~r?tFaVp4vTw^_9~Ud8U@Px2WC6*vwH?s%29 zzUV6THSDprb9-=Khn_#1H;h?hebWT=Rq~b>@U|E54vgM}Y0!KB-i7ZsvcRuk`|T|7 zYZ$$O1%3nH-^K#(!S;15@IH)Q%L2cJ?{8s&-@z^d^hN!F7x1ACXgA5H|0L6^^vy&m)0AohCVYn5%9DNuHNCe^!X0*)X> z!g8srGn_&BGxd*X?u7lfT+TI{kL^}bKnm5$*ySbR6E6w7y(Ij>me8BhKpVnjB%uFt zkRr1=;$x7aQQ;%g>GRcvS@X9y+I;|Oh36du}0=%E6l*U9L!BAb+n&_?}8 zIwnU3Av%C!%%&If2!5pA*BMEjl2a=qEfp1pMN)Sq$46h~}Q);;4Gexy`80y0se9RZn&s8+($WI(8DWLaPwqmomO*;3*T$W$T%GL?u(D<$2q zczh*hKqfq>Lsti=x9rsPdK3=|tT=Un7)Gv&%G-}m6B^a7@{2ag@Y2kk}FVDl{QdRh3;61 z3Sk5lBHT`e6(~yN&3WuenSja!R2B#KQ0}OC8_~DnUvn_zD|5!=p+Hep&M#{4iwfr# z6t$;JM2@P8r3YgxVj)P?;SR%Lg^F?qLa#MXr*MbisG$U5v&Oe|!*WErsuCHf5*et9 z18l3I4A78}GJp~ONw+h4P>mVkU(|w`+t7o&7=@uE1#co!jO&UKRS>%3dK$AdEM5>* zpbNkgUtGcS$vj*@WmwE2swo#x?iI7BG%TQynuf4oK581mf*Pr5@Cs^F>J@RQIxJq0 znuf5bM`{{m)FWLj`7|MHN>coq5H=+#Q70e5rX(fW3}GXhX|xinhVo=Mzt){C@Ew9y zYx@L0lCk0drjH}AOiexpyURU+7bCx{z%nH$1=sqEFtCgfl|e!Li!iW^(LFy`eDp;b zN$C_=rYP4RWhCUKVqlpfHL#2`Jj_Xl_BUIsBkGLW&g_fA2Vu51M~w24_$pD6W@$Q_ zTNRGAH9tx8YuaIo9fVT=Y8#MoQuv@IwHVZ-z%VGNNsT+G31z_5GD}mvl!iq;Q6;2# zNsv)b@=?2GG@-dDby_$Q#%Lq8h8Z4R^z*LJCbinoCM9NQlUiS^CMbI?22_b0IlVR` zZdz;WN-7X5a(amwVx=}p6FI%sjC!KB>UfyxjC-yE36S7?-dzO};dtjB`8c}@^bk?Y z?NxCVNP@*3o8-cw3M3=Y%shr#o`S&Vaw$!fkcz->7>`wXnir6612|3!Sppe5bssof zM{C7s6Lw4lS}4I6RS*SJuq?-M90c*c07W^77*nEA{>TwIf_~%=WF~*XM2={Yzoe8> z@-RLG{W2;*5f2>kAsm4xu<0bFbgl`8E{$W1v2P>Dj^g8x3irV1I!gs73hV)H?%cT z2V_Cr!9NGjztO)!lgMmXi-3OVraZ?B$b~^&%YynHHRX9Qr>jW@K2USf8-dSc*cTPZ zN8k?H1vJ4J9J3xj+P}9&4 zra!|1AXF7$6Vcd*|T^ z4A2|?=iQelGC)3L|N4tb3{U{gzv(`i0SaO2dlgd{pbx~qzYMp!SZC9yFVV+qs2%`s{MwN?14X;1*y%8{!x8OFRZ;CFp(l(! z;D~mnN~rOYkO938B*_t&n#fFu>&P2zkDpWk2mKxWM=?Ma0`JNBqbeaAfg9w^L(t4KrX3};|3MTgLR!FrAt@^db%lLi1XV>JSl(46Ctxa2guv@^SfB#M2wW#7 zV49V(__B!J?E-9Ist3BfznvwqBuC}$a(|bF+}~Tda-KO!A%RgO#Yq$OJT`6>%MHkYIUzg## zAHK`QWy-zl*ClwVFTP77q#VDl!uJ4tR|`+J__g#rayxYMov)SPa3K199S9a%5jk@dnyQ!m_+^>Khv?CT==<{~-n|6|8F z<=){quZ!q74=)a|i^G7>2_B1OAzx+{GOoMU<5?t@i@TA^(HMgIn!?Mm@s!K44v*px zEd*8dA`T>ivHZ+~K=?hu(qQ6r7QYu2bcilfo#)I$fBuQ9eeI@9VRJMu*BiAEs} zGjb==7&^bjY(kC=5zb8&ciZJ1v(_qa=SBsp*Fkb;KwWXz8BFHR0LK~2mcQ|2s@hSZ zU{|O-tVL%DhOh)Y`KVcJ8yJcyYzeo7=AUEgz zMo!_3AF>h089#O5XZ+}FBtoA43ua?&njqrT~^f^ZdE1{swA?iR^3rQt-`8Wg;llctg6*%RkUfKRUGw0{fpCy zSZg}#3oxbPCg++MG=w?cMW5-6+uac66<2{Um$fJrr-Y_3$GZxIdBs&gx~xSm$l6`G zXbE%vt3a4%UInDvTr?=krfcL@pW=@e%BdDz%G<)WCa6Hzz5x}GPJNy7D9w2@^(oOB zXMKH2jK*1CpAtBEXMKGNbya9OW*6gd*6Y0Tf)=*!^x+4-BOzw7eu5t@XZ=8jvwm1U z4FFEy#mFzqSznJ*&=+4v&ic4iIt8YVob|Dp-)C$$K!JXG7NUmI&Eh8c&0Eeucse?43(ozX&@^G4p#7lC(#i=;7>Gb6ejKT=8H zc^H&%zj^9IY2lxP&P^0vsV_y*OXcc^s=JI5M+;WEezPAXPOM!Ngc9fOdCQ^eaR0%- zSmIlu0V<&1;YtqZ58DozKubu45lu#6?aiS4M`dhT^KsCiLofm_9QrJnXz$ISJn>an z3EdA>aS5n`C0!;Ed3OgTAUfl_4?heVbQDJ*C;3moL^?slc{GVvDh5E`gVlq5ivqfG zs)n7N)l|}^8%wRL8U$9;LX^3Ts$w7ltC}tj4q_F^ zMW90VVJeUhw|7=at5$&mv`H2y^aA>L0YzRwu?=XR`Wu#$)HsUke~zztGHA>y+!+k~ zTAnN%>* z`I?533K<|>RnY=DyPrMR4(qJ~tuS`CZvs=2K?EjDWPmmVc1&V`VWeU*1GJNhDGV^2 zR8VLQU3HIu#65du{Bt#%BjLoJ2W0$n6&MA7*?Xsqf35+oPAXD+-aVZ0gBNcNQ;A~QHIRl(S zD&{f3cv3N+0nQ~AS2DnPq~asSX)|{QH*}Dw>dEomc%;<71#2)Z- zz~wMv|BqxKIu-LmfUbJ4@B-$00aqeW&86WgShcU>IwqS}L-D>>siEi+xxfp!#to>G z%fUE+y;g36P=N;6(K%;u+=~606Jr}11z;yql`sT>n+E@N`7+)7wF&O&ENrM*Hg}a6 zn>d4(!K66RknN3JizB{g23*i3*H>>U~?}%tQr7 zLhDnv$eD=>j1qutSt29OWxlp#h{LBf?A?Z{gwb9SQeZxwZp}zI%}YWm{PF3%IOx}% zan+WFKqf9eYk_nGmgB@j3-mf9H1C${! z6ankzrnanpUO>4QPyr)%4;`T2zTeg#KH0+pm2lcqdk5$@e79A>+1pa?L0}KS;f$|0>k#%5nyf5#cYF!NS0_xp>x@909 z7O;=KwIskX_OZ8?M96!ddvLC$2P|MupKVEk+g=>UJoeT?kG(lIU8}jE$KJZ+3bG2& zV{fx*1;-qCsz4eXeKART@l+rkfiAhHS_OI{Fk3$DsR9`YjF)?=RUp#~=mk4pKnbB$ zMO8u;OnROL@Uge&SRe;>KEndJFzF}@;A3x3vp{dyd6)(A;ju%Tm?x=P3ZSFw{#JX0 zu9ia~^zB;H!c=!31Zt(5P?b=Gz=v|7Tm_0rgx;nSvURHxO1*$G zH=yV+tbtE99@v$oN*IR#>&!db3pmFHxUsnye$yXO45vJm84n*&GD9m6 zYCg_|YH~{If%D+zgDfxsCU;GtqB56>R235u*h5W62TVdBK#flaoKGsK`Rahlq(XWP z)HF(GxJ{ z4!_~PU?zTLrL!A;q)kOW@D1-7;Q=%-B0mLHkB>MF#y9SZLs@3Q;!Z{(3!mSL4h)|+ zYvlCHXN$|`>b&E!-*uUK0{MuQ^7NNmIO=T1_fUMd2;uHuz From e359f0a15d35406a5553126ba26c80f4d819650d Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 14 Mar 2021 22:19:48 +0100 Subject: [PATCH 17/72] Update README.md --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6f2543b32..f34fe80d2 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,11 @@ Impostor is one of the first **Among Us** private servers, written in C#. -We support Steam, Itch, Android and iOS. The latest version supported is `2020.9.22`, the `master` build currently supports `2020.12.9`. - | Impostor version | Among Us version | Experimental | Download | |-|-|-|-| | 1.1.0 | 2020.09.07 - 2020.09.22 | No | [![Download](https://img.shields.io/badge/Download-v1.1.0-blue?style=flat-square)](https://github.com/Impostor/Impostor/releases/tag/v1.1.0) | -| 1.2.2 | 2020.09.22 - 2020.11.17 | Yes | [![Download](https://img.shields.io/badge/Download-v1.2.2-blue?style=flat-square)](https://ci.appveyor.com/project/Impostor/Impostor/branch/master/artifacts) | +| 1.2.2 | 2020.09.22 - 2020.11.17 | No | [![Download](https://img.shields.io/badge/Download-v1.2.2-blue?style=flat-square)](https://github.com/Impostor/Impostor/releases/tag/v1.2.2) | +| 1.3.0 | 2020.3.5 | Yes | [![Download](https://img.shields.io/badge/Download-master-blue?style=flat-square)](https://ci.appveyor.com/project/Impostor/Impostor/branch/master/artifacts) | ## Features @@ -27,9 +26,9 @@ If you just want to play on a server hosted by someone else, you need to follow #### Windows 1. Find the [latest release](https://github.com/AeonLucid/Impostor/releases/latest). -2. Download `Impostor-Client-win-x64.zip`. +2. Download `Impostor-Patcher-win-x64.zip`. 3. Extract the zip. -4. Run `Impostor.Client.exe`. +4. Run `Impostor.Patcher.exe`. 5. Follow the instructions inside the application. ![Client](docs/images/client.jpg) From ea1085406a63262abcd12637ec421da74d573593 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 14 Mar 2021 21:23:10 +0000 Subject: [PATCH 18/72] Fix typo in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f34fe80d2..a2d2810ba 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Impostor is one of the first **Among Us** private servers, written in C#. |-|-|-|-| | 1.1.0 | 2020.09.07 - 2020.09.22 | No | [![Download](https://img.shields.io/badge/Download-v1.1.0-blue?style=flat-square)](https://github.com/Impostor/Impostor/releases/tag/v1.1.0) | | 1.2.2 | 2020.09.22 - 2020.11.17 | No | [![Download](https://img.shields.io/badge/Download-v1.2.2-blue?style=flat-square)](https://github.com/Impostor/Impostor/releases/tag/v1.2.2) | -| 1.3.0 | 2020.3.5 | Yes | [![Download](https://img.shields.io/badge/Download-master-blue?style=flat-square)](https://ci.appveyor.com/project/Impostor/Impostor/branch/master/artifacts) | +| 1.3.0 | 2021.3.5 | Yes | [![Download](https://img.shields.io/badge/Download-master-blue?style=flat-square)](https://ci.appveyor.com/project/Impostor/Impostor/branch/master/artifacts) | ## Features From 7e16b5595a5bc8b85bacfec7bcab15799a490af1 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 14 Mar 2021 23:25:56 +0100 Subject: [PATCH 19/72] Include AntiCheat.Enabled in default config.json --- src/Impostor.Server/config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Impostor.Server/config.json b/src/Impostor.Server/config.json index d477c7452..1f68f968f 100644 --- a/src/Impostor.Server/config.json +++ b/src/Impostor.Server/config.json @@ -6,6 +6,7 @@ "ListenPort": 22023 }, "AntiCheat": { + "Enabled": true, "BanIpFromGame": true } -} \ No newline at end of file +} From f04bacf0de57cf862fb221586974984ee4f4e88f Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 14 Mar 2021 22:30:01 +0000 Subject: [PATCH 20/72] Update Server-configuration.md --- docs/Server-configuration.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/Server-configuration.md b/docs/Server-configuration.md index 5841ca7f9..75996a335 100644 --- a/docs/Server-configuration.md +++ b/docs/Server-configuration.md @@ -17,6 +17,7 @@ Some information about all the possible configurations. Click [here](https://git | Key | Default | Value | |-|-|-| +| **Enabled** | `true` | Whether the anticheat should be enabled. | | **BanIpFromGame** | `true` | When a player is caught hacking, they will be kicked from the server. If this value is set to `true`, the player will be banned instead and will not be able to rejoin that specific game. **(Setting this to false does not disable the anti-cheat!)** | ### ServerRedirector @@ -45,6 +46,7 @@ Server:PublicIp=127.0.0.1 Server:PublicPort=22023 Server:ListenIp=0.0.0.0 Server:ListenPort=22023 +AntiCheat:Enabled=true AntiCheat:BanIpFromGame=true ServerRedirector:Enabled=false ServerRedirector:Master=true @@ -65,6 +67,7 @@ IMPOSTOR_Server__PublicIp=127.0.0.1 IMPOSTOR_Server__PublicPort=22023 IMPOSTOR_Server__ListenIp=0.0.0.0 IMPOSTOR_Server__ListenPort=22023 +IMPOSTOR_AntiCheat__Enabled=true IMPOSTOR_AntiCheat__BanIpFromGame=true IMPOSTOR_ServerRedirector__Enabled=false IMPOSTOR_ServerRedirector__Master=true From e0041e89d8f6d21702de645545ec72207235ecae Mon Sep 17 00:00:00 2001 From: js6pak Date: Tue, 16 Mar 2021 21:40:54 +0100 Subject: [PATCH 21/72] Update docker CI --- .github/workflows/docker.yml | 14 +++++++++----- Dockerfile | 4 +++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index b31207599..5cc0db2d6 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -2,7 +2,7 @@ name: Docker on: push: - branches: dev + branches: master paths: - 'src/Impostor.Server/**' - 'src/Impostor.Shared/**' @@ -33,15 +33,16 @@ jobs: run: | DOCKER_IMAGE=aeonlucid/impostor VERSION=noop + VERSIONSUFFIX=docker if [[ $GITHUB_REF == refs/tags/* ]]; then VERSION=${GITHUB_REF#refs/tags/} + VERSIONSUFFIX= elif [[ $GITHUB_REF == refs/heads/* ]]; then - VERSION=$(echo ${GITHUB_REF#refs/heads/} | sed -r 's#/+#-#g') - if [ "${{ github.event.repository.default_branch }}" = "dev" ]; then - VERSION=nightly - fi + VERSION=nightly + VERSIONSUFFIX=docker.${{ github.run_number }} elif [[ $GITHUB_REF == refs/pull/* ]]; then VERSION=pr-${{ github.event.number }} + VERSIONSUFFIX=pr.${{ github.event.number }} fi TAGS="${DOCKER_IMAGE}:${VERSION}" if [[ $VERSION =~ ^v[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then @@ -49,6 +50,7 @@ jobs: fi echo ::set-output name=version::${VERSION} echo ::set-output name=tags::${TAGS} + echo ::set-output name=versionsuffix::${VERSIONSUFFIX} echo ::set-output name=created::$(date -u +'%Y-%m-%dT%H:%M:%SZ') - name: Set up QEMU uses: docker/setup-qemu-action@v1 @@ -68,3 +70,5 @@ jobs: platforms: linux/amd64,linux/arm/v7,linux/arm64 push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.prep.outputs.tags }} + build-args: | + VERSIONSUFFIX=${{ steps.prep.outputs.versionsuffix }} diff --git a/Dockerfile b/Dockerfile index 8f386da60..932addbb6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,8 @@ FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:5.0 AS build # https://github.com/containerd/containerd/blob/master/platforms/platforms.go#L17 ARG TARGETARCH +ARG VERSIONSUFFIX + WORKDIR /source # Copy csproj and restore. @@ -29,7 +31,7 @@ RUN case "$TARGETARCH" in \ arm) NETCORE_PLATFORM='linux-arm';; \ *) echo "unsupported architecture"; exit 1 ;; \ esac && \ - dotnet publish -c release -o /app -r "$NETCORE_PLATFORM" --no-restore ./src/Impostor.Server/Impostor.Server.csproj + dotnet publish -c release -o /app -r "$NETCORE_PLATFORM" -p:VersionSuffix="$VERSIONSUFFIX" --no-restore ./src/Impostor.Server/Impostor.Server.csproj # Final image. FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/runtime:5.0 From fe7a641bad9639f7b38e102e8876e3a680bac183 Mon Sep 17 00:00:00 2001 From: js6pak Date: Tue, 16 Mar 2021 22:12:56 +0100 Subject: [PATCH 22/72] Set VERSIONSUFFIX to docker by default --- .github/workflows/docker.yml | 2 +- Dockerfile | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 5cc0db2d6..51b61260a 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -36,7 +36,7 @@ jobs: VERSIONSUFFIX=docker if [[ $GITHUB_REF == refs/tags/* ]]; then VERSION=${GITHUB_REF#refs/tags/} - VERSIONSUFFIX= + VERSIONSUFFIX=none elif [[ $GITHUB_REF == refs/heads/* ]]; then VERSION=nightly VERSIONSUFFIX=docker.${{ github.run_number }} diff --git a/Dockerfile b/Dockerfile index 932addbb6..e8797a7c4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:5.0 AS build # https://github.com/containerd/containerd/blob/master/platforms/platforms.go#L17 ARG TARGETARCH -ARG VERSIONSUFFIX +ARG VERSIONSUFFIX="docker" WORKDIR /source @@ -31,6 +31,7 @@ RUN case "$TARGETARCH" in \ arm) NETCORE_PLATFORM='linux-arm';; \ *) echo "unsupported architecture"; exit 1 ;; \ esac && \ + [[ $VERSIONSUFFIX = "none" ]] && VERSIONSUFFIX=; \ dotnet publish -c release -o /app -r "$NETCORE_PLATFORM" -p:VersionSuffix="$VERSIONSUFFIX" --no-restore ./src/Impostor.Server/Impostor.Server.csproj # Final image. From be332e21d11125b330dfdbb5a41b353b13290c99 Mon Sep 17 00:00:00 2001 From: Minorusama Date: Tue, 23 Mar 2021 21:12:39 +0100 Subject: [PATCH 23/72] Add IInnerPlayerControl#ExileAsync (#271) --- .../Net/Inner/Objects/IInnerPlayerControl.cs | 7 +++++++ .../Inner/Objects/InnerPlayerControl.Api.cs | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs index c0ecf855d..0ee065ad8 100644 --- a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs +++ b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs @@ -98,5 +98,12 @@ public interface IInnerPlayerControl : IInnerNetObject /// Thrown when target is dead. /// Task that must be awaited. ValueTask MurderPlayerAsync(IInnerPlayerControl target); + + /// + /// Exile the current player. This doesn't produce a body to be reported. + /// Visible to all players. + /// + /// Task that must be awaited. + ValueTask ExileAsync(); } } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs index 07c21267c..e55f07920 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs @@ -106,5 +106,24 @@ public async ValueTask MurderPlayerAsync(IInnerPlayerControl target) await _eventManager.CallAsync(new PlayerMurderEvent(_game, _game.GetClientPlayer(OwnerId), this, target)); } + + public async ValueTask ExileAsync() + { + if (PlayerInfo.IsDead) + { + throw new ImpostorProtocolException("Tried to exile a player, but target was not alive."); + } + + // Update player. + Die(DeathReason.Exile); + + // Send RPC. + using var writer = _game.StartRpc(NetId, RpcCalls.Exiled); + Rpc04Exiled.Serialize(writer); + await _game.FinishRpcAsync(writer); + + // Notify plugins. + await _eventManager.CallAsync(new PlayerExileEvent(_game, _game.GetClientPlayer(OwnerId), this)); + } } } From dc759b1d573b59ff5c39dd2792c40ebdec7649a2 Mon Sep 17 00:00:00 2001 From: js6pak Date: Thu, 18 Mar 2021 21:34:47 +0100 Subject: [PATCH 24/72] Fix FloatRange ranges --- src/Impostor.Api/Unity/Mathf.cs | 4 +++- src/Impostor.Hazel/MessageReader.cs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Impostor.Api/Unity/Mathf.cs b/src/Impostor.Api/Unity/Mathf.cs index f796decdf..c907f816a 100644 --- a/src/Impostor.Api/Unity/Mathf.cs +++ b/src/Impostor.Api/Unity/Mathf.cs @@ -53,7 +53,9 @@ public static float Clamp01(float value) public static float ReverseLerp(float t) { - return Clamp((t - -40f) / (40f - -40f), 0f, 1f); + const float range = 50f; + + return Clamp((t - -range) / (range - -range), 0f, 1f); } } } diff --git a/src/Impostor.Hazel/MessageReader.cs b/src/Impostor.Hazel/MessageReader.cs index 35933298d..317e45b1e 100644 --- a/src/Impostor.Hazel/MessageReader.cs +++ b/src/Impostor.Hazel/MessageReader.cs @@ -254,10 +254,12 @@ public T ReadNetObject(IGame game) where T : IInnerNetObject public Vector2 ReadVector2() { + const float range = 50f; + var x = ReadUInt16() / (float) ushort.MaxValue; var y = ReadUInt16() / (float) ushort.MaxValue; - return new Vector2(Mathf.Lerp(-40f, 40f, x), Mathf.Lerp(-40f, 40f, y)); + return new Vector2(Mathf.Lerp(-range, range, x), Mathf.Lerp(-range, range, y)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] From 0f6bfb3597c570d804c76ff493069db5b75385e0 Mon Sep 17 00:00:00 2001 From: js6pak Date: Wed, 24 Mar 2021 16:38:23 +0100 Subject: [PATCH 25/72] 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 b5c140ef8..1b054f750 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 1e59a9baf..01b20d4c6 100644 --- a/src/Impostor.Api/Exceptions/ImpostorConfigException.cs +++ b/src/Impostor.Api/Exceptions/ImpostorConfigException.cs @@ -9,15 +9,15 @@ public ImpostorConfigException() { } - 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 188c50e85..03891942d 100644 --- a/src/Impostor.Api/Exceptions/ImpostorException.cs +++ b/src/Impostor.Api/Exceptions/ImpostorException.cs @@ -9,16 +9,16 @@ public ImpostorException() { } - 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 864602d04..513e590e4 100644 --- a/src/Impostor.Api/Exceptions/ImpostorProtocolException.cs +++ b/src/Impostor.Api/Exceptions/ImpostorProtocolException.cs @@ -9,15 +9,15 @@ public ImpostorProtocolException() { } - 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 57c3fcd25..58e92085f 100644 --- a/src/Impostor.Api/Games/IGame.cs +++ b/src/Impostor.Api/Games/IGame.cs @@ -37,7 +37,7 @@ public interface IGame 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 188f2a677..33c2ea01e 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 9526f58b1..21cdc944c 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 9717cff23..f4743c564 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 @@ public static string IntToGameName(int input) #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 @@ public static int GameNameToInt(string code) { return -1; } - + var len = code.Length; if (len == 6) { @@ -91,23 +50,8 @@ public static int GameNameToInt(string code) { 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 @@ public static int GenerateCode(int len) { 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 @@ public static int GenerateCode(int len) 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 @@ public static int GenerateCode(int len) 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 6a95d3747..5c30036c5 100644 --- a/src/Impostor.Api/Innersloth/GameOverReason.cs +++ b/src/Impostor.Api/Innersloth/GameOverReason.cs @@ -7,9 +7,7 @@ public enum GameOverReason : byte 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 c78978bd5..51580db1a 100644 --- a/src/Impostor.Api/Innersloth/RegionInfo.cs +++ b/src/Impostor.Api/Innersloth/RegionInfo.cs @@ -13,21 +13,10 @@ public RegionInfo(string name, string ping, IReadOnlyList servers) } 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 @@ public static RegionInfo Deserialize(BinaryReader reader) 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 778582349..21ba1ea7c 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 @@ public static ServerInfo Deserialize(BinaryReader reader) 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 7f91718b3..5de8bc94d 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 f4d7c1f69..ea9a5fc5b 100644 --- a/src/Impostor.Api/Innersloth/TaskBarUpdate.cs +++ b/src/Impostor.Api/Innersloth/TaskBarUpdate.cs @@ -4,6 +4,6 @@ public enum TaskBarUpdate : byte { 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 94f9b8be3..fa998414f 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 933a4de68..9cac0f2db 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 c0a05aeae..79b9f9649 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 d0a816dc0..8d8b4ac69 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 f82d2e89e..e75f80ec2 100644 --- a/src/Impostor.Api/Net/Inner/RpcCalls.cs +++ b/src/Impostor.Api/Net/Inner/RpcCalls.cs @@ -33,6 +33,6 @@ public enum RpcCalls : byte 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 51021f56f..000000000 --- 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 94ff4418f..42f452ac7 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 886e26e80..3e5adc84f 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 28b6ed3cd..cbde5b662 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 00997697c..7ab52af6f 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 282fe1078..9e81c5cc0 100644 --- a/src/Impostor.Hazel/NetworkConnection.cs +++ b/src/Impostor.Hazel/NetworkConnection.cs @@ -37,15 +37,11 @@ public abstract class NetworkConnection : Connection 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 22eed988f..8d3426e38 100644 --- a/src/Impostor.Hazel/Udp/UdpServerConnection.cs +++ b/src/Impostor.Hazel/Udp/UdpServerConnection.cs @@ -88,7 +88,7 @@ protected override void Dispose(bool disposing) 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 c59fa8784..7835c4ffb 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 8d71e56cf..3039810f9 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 71494365f..83f6e269e 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 9518e48e9..8fce4f886 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 dd4724dc1..f0ebef3dc 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 5d61ac04c..3ea3eb33a 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 630d1b488..ef37d3972 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 1c584333f..7ed3ae64c 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 0ccfa0d4c..63285ad77 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 @@ public class ServerRedirectorConfig { 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 d11b60ff3..c5752bf6b 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 190f7f398..e185c9a1f 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 0cc6e541e..4ab2d1536 100644 --- a/src/Impostor.Server/Events/EventManager.cs +++ b/src/Impostor.Server/Events/EventManager.cs @@ -27,7 +27,7 @@ public EventManager(ILogger logger, IServiceProvider serviceProvid } /// - 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 4ec4dcf92..b0704cfc3 100644 --- a/src/Impostor.Server/Events/Game/GameEndedEvent.cs +++ b/src/Impostor.Server/Events/Game/GameEndedEvent.cs @@ -13,7 +13,7 @@ public GameEndedEvent(IGame game, GameOverReason gameOverReason) } 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 479a3f641..3b39bc9b8 100644 --- a/src/Impostor.Server/Events/Register/IRegisteredEventListener.cs +++ b/src/Impostor.Server/Events/Register/IRegisteredEventListener.cs @@ -10,6 +10,6 @@ internal interface IRegisteredEventListener 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 a21c3b1f6..adec183b4 100644 --- a/src/Impostor.Server/Events/Register/InvokedRegisteredEventListener.cs +++ b/src/Impostor.Server/Events/Register/InvokedRegisteredEventListener.cs @@ -19,9 +19,9 @@ public InvokedRegisteredEventListener(IRegisteredEventListener innerObject, Func 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 e81e8f844..394f47d37 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 @@ public ManualRegisteredEventListener(IManualEventListener manualEventListener) _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 120a45ed3..6517aac8e 100644 --- a/src/Impostor.Server/Events/Register/RegisteredEventListener.cs +++ b/src/Impostor.Server/Events/Register/RegisteredEventListener.cs @@ -15,7 +15,7 @@ internal class RegisteredEventListener : IRegisteredEventListener 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 @@ public RegisteredEventListener(Type eventType, MethodInfo method, EventListenerA 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 @@ private Func CreateInvoker(MethodIn 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 dd668c5dd..d1a66ee84 100644 --- a/src/Impostor.Server/Events/Register/WrappedRegisteredEventListener.cs +++ b/src/Impostor.Server/Events/Register/WrappedRegisteredEventListener.cs @@ -19,9 +19,9 @@ public WrappedRegisteredEventListener(IRegisteredEventListener innerObject, obje 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 663f7af43..5cad72de6 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 a58abf276..6ca0bb9a1 100644 --- a/src/Impostor.Server/Net/AnnouncementsService.cs +++ b/src/Impostor.Server/Net/AnnouncementsService.cs @@ -24,7 +24,7 @@ internal class AnnouncementsService : IHostedService 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 @@ public async Task StartAsync(CancellationToken cancellationToken) { AddressFamily.InterNetwork => IPMode.IPv4, AddressFamily.InterNetworkV6 => IPMode.IPv6, - _ => throw new InvalidOperationException() + _ => throw new InvalidOperationException(), }; _connection = new UdpConnectionListener(endpoint, _readerPool, mode) @@ -58,7 +58,11 @@ public async Task StartAsync(CancellationToken cancellationToken) 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 f26de4026..45718e583 100644 --- a/src/Impostor.Server/Net/Client.cs +++ b/src/Impostor.Server/Net/Client.cs @@ -131,7 +131,7 @@ public override async ValueTask HandleMessageAsync(IMessageReader reader, Messag return; } - await Player.Game.HandleStartGame(reader); + await Player!.Game.HandleStartGame(reader); break; } @@ -151,7 +151,7 @@ public override async ValueTask HandleMessageAsync(IMessageReader reader, Messag 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 @@ public override async ValueTask HandleMessageAsync(IMessageReader reader, Messag // 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 @@ public override async ValueTask HandleMessageAsync(IMessageReader reader, Messag reader, out var gameOverReason); - await Player.Game.HandleEndGame(reader, gameOverReason); + await Player!.Game.HandleEndGame(reader, gameOverReason); break; } @@ -223,7 +223,7 @@ public override async ValueTask HandleMessageAsync(IMessageReader reader, Messag return; } - await Player.Game.HandleAlterGame(reader, Player, value); + await Player!.Game.HandleAlterGame(reader, Player, value); break; } @@ -239,7 +239,7 @@ public override async ValueTask HandleMessageAsync(IMessageReader reader, Messag 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 7bff06efe..78bcb9ec5 100644 --- a/src/Impostor.Server/Net/ClientBase.cs +++ b/src/Impostor.Server/Net/ClientBase.cs @@ -64,7 +64,6 @@ public virtual ValueTask ReportCheatAsync(CheatContext context, string mes 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 45d2be827..e663dec1b 100644 --- a/src/Impostor.Server/Net/Hazel/HazelConnection.cs +++ b/src/Impostor.Server/Net/Hazel/HazelConnection.cs @@ -25,14 +25,14 @@ public HazelConnection(Connection innerConnection, ILogger logg 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 9579fe0ad..5b65f464c 100644 --- a/src/Impostor.Server/Net/Inner/InnerNetObject.cs +++ b/src/Impostor.Server/Net/Inner/InnerNetObject.cs @@ -29,6 +29,7 @@ public bool IsOwnedBy(IClientPlayer player) 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 @@ protected ValueTask HandleCustomRpc(IMessageReader reader, Game game) 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 56ff96e59..0e70bd64f 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 @@ public async ValueTask SnapToAsync(Vector2 position) 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 80dd6adf6..0e475b8c2 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 @@ internal partial class InnerCustomNetworkTransform : InnerNetObject 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 @@ public InnerCustomNetworkTransform(ILogger logger, _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 @@ internal async ValueTask SetPositionAsync(IClientPlayer sender, Vector2 position _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 5d120c5cf..0219fbab2 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 fbf25102b..48f551b9a 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 @@ public PlayerVoteArea(InnerMeetingHud parent, byte targetPlayerId) 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 @@ public void Deserialize(IMessageReader reader) 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 96d829fb8..8f9c8f5e8 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 @@ internal partial class InnerMeetingHud : InnerNetObject 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 @@ public InnerMeetingHud(ILogger logger, IEventManager eventManag 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 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client 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 e55f07920..604c6e644 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 @@ public async ValueTask MurderPlayerAsync(IInnerPlayerControl target) 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 @@ public async ValueTask ExileAsync() 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 8391ed088..8cd808dbb 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 @@ public InnerPlayerControl(ILogger logger, IServiceProvider s public InnerCustomNetworkTransform NetworkTransform { get; } + [AllowNull] public InnerPlayerInfo PlayerInfo { get; internal set; } internal Queue RequestedPlayerName { get; } = new Queue(); @@ -76,12 +80,6 @@ public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPl 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 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client 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 @@ private async ValueTask HandleSetInfected(ReadOnlyMemory infectedIds) { 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 @@ private async ValueTask HandleSetName(ClientPlayer sender, string name) 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 @@ private async ValueTask HandleMurderPlayer(ClientPlayer sender, IInnerPlay 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 @@ private async ValueTask HandleSendChat(ClientPlayer sender, string message 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 301fc0881..1d488fbdc 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs @@ -15,11 +15,11 @@ public InnerPlayerInfo(byte playerId) 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 @@ public InnerPlayerInfo(byte playerId) 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 64b1f5f01..df374bff6 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 @@ public DoorsSystemType(IGame game) MapTypes.Skeld => 13, MapTypes.MiraHQ => 2, MapTypes.Polus => 12, - _ => throw new ArgumentOutOfRangeException() + _ => throw new ArgumentOutOfRangeException(), }; _doors = new Dictionary(doorCount); @@ -57,4 +57,4 @@ public void Deserialize(IMessageReader reader, bool initialState) } } } -} \ 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 32359f8fb..6ee4515f4 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 8d883a412..eef5d53d9 100644 --- a/src/Impostor.Server/Net/Manager/GameManager.cs +++ b/src/Impostor.Server/Net/Manager/GameManager.cs @@ -42,46 +42,9 @@ public GameManager(ILogger logger, IOptions config, I 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 @@ public async ValueTask RemoveAsync(GameCode gameCode) 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 e700703ca..a5518dc37 100644 --- a/src/Impostor.Server/Net/Matchmaker.cs +++ b/src/Impostor.Server/Net/Matchmaker.cs @@ -18,7 +18,7 @@ internal class Matchmaker 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 @@ public async ValueTask StartAsync(IPEndPoint ipEndPoint) { 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 12563b9a2..1c3391a9d 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 fd4cd56f7..baef6db44 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 0b6fdff81..f4595e353 100644 --- a/src/Impostor.Server/Net/Redirector/NodeLocatorRedis.cs +++ b/src/Impostor.Server/Net/Redirector/NodeLocatorRedis.cs @@ -16,7 +16,7 @@ public NodeLocatorRedis(ILogger logger, IDistributedCache cach _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 @@ public async ValueTask RemoveAsync(string gameCode) 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 2539a8f2d..c75392adf 100644 --- a/src/Impostor.Server/Net/Redirector/NodeLocatorUDP.cs +++ b/src/Impostor.Server/Net/Redirector/NodeLocatorUDP.cs @@ -14,9 +14,9 @@ public class NodeLocatorUdp : INodeLocator, IDisposable { 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 @@ public NodeLocatorUdp(ILogger logger, IOptions {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 @@ public void Update(IPEndPoint ip, string gameCode) } } - 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 @@ public ValueTask FindAsync(string gameCode) return ValueTask.FromResult(default(IPEndPoint)); } - return ValueTask.FromResult(node.Endpoint); + return ValueTask.FromResult(node.Endpoint)!; } return ValueTask.FromResult(default(IPEndPoint)); @@ -106,14 +102,14 @@ public ValueTask RemoveAsync(string gameCode) 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 @@ public void Dispose() 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 3706bb499..781e91f31 100644 --- a/src/Impostor.Server/Net/Redirector/NodeLocatorUDPService.cs +++ b/src/Impostor.Server/Net/Redirector/NodeLocatorUDPService.cs @@ -25,7 +25,7 @@ public NodeLocatorUdpService( _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 ceb73b49e..b615c064a 100644 --- a/src/Impostor.Server/Net/State/ClientPlayer.cs +++ b/src/Impostor.Server/Net/State/ClientPlayer.cs @@ -17,7 +17,7 @@ internal partial class ClientPlayer : IClientPlayer 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 @@ public ClientPlayer(ILogger logger, ClientBase client, Game game) 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 a2996915f..44257e763 100644 --- a/src/Impostor.Server/Net/State/Game.Api.cs +++ b/src/Impostor.Server/Net/State/Game.Api.cs @@ -25,7 +25,7 @@ public void BanIp(IPAddress ipAddress) 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 a2eaa09d3..b928a3c21 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -47,124 +47,24 @@ internal partial class Game }; 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 @@ public async ValueTask HandleGameDataAsync(IMessageReader parent, ClientPl 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 @@ public async ValueTask HandleGameDataAsync(IMessageReader parent, ClientPl return false; } - innerNetObject.SpawnFlags = (SpawnFlags) reader.ReadByte(); + innerNetObject.SpawnFlags = (SpawnFlags)reader.ReadByte(); var components = innerNetObject.GetComponentsInChildren(); var componentsCount = reader.ReadPackedInt32(); @@ -393,6 +293,113 @@ public async ValueTask HandleGameDataAsync(IMessageReader parent, ClientPl 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 @@ private void RemoveNetObject(InnerNetObject obj) 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 547224db2..8f9df6263 100644 --- a/src/Impostor.Server/Net/State/Game.Incoming.cs +++ b/src/Impostor.Server/Net/State/Game.Incoming.cs @@ -29,6 +29,74 @@ public async ValueTask HandleStartGame(IMessageReader message) 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 @@ public async ValueTask AddClientAsync(ClientBase client) 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 @@ private async ValueTask AddClientSafeAsync(ClientBase client) 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 927548e72..9f9d90473 100644 --- a/src/Impostor.Server/Net/State/Game.State.cs +++ b/src/Impostor.Server/Net/State/Game.State.cs @@ -66,7 +66,7 @@ private async ValueTask PlayerRemove(int playerId, bool isBan = false) 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 6ca2fd687..823c049f4 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 @@ public Game( public GameStates GameState { get; private set; } - internal GameNet GameNet { get; } - public GameOptionsData Options { get; } public IDictionary Items { get; } @@ -78,7 +77,9 @@ public Game( 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 @@ public bool TryGetPlayer(int id, out ClientPlayer player) 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 @@ internal async ValueTask StartedAsync() } } - 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 @@ private IEnumerable GetConnections(Func f { 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 34ea0fe64..4fed52763 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 c5542f9d0..37e0cbd91 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 5f6aee113..df1bf84ea 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 @@ public Assembly Load(AssemblyLoadContext context) 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 e6a5b6c81..f9f61a1fe 100644 --- a/src/Impostor.Server/Plugins/PluginInformation.cs +++ b/src/Impostor.Server/Plugins/PluginInformation.cs @@ -8,9 +8,9 @@ public class PluginInformation { 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 @@ public PluginInformation(IPluginStartup startup, Type pluginType) 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 4b5d07a50..90b9caf83 100644 --- a/src/Impostor.Server/Plugins/PluginLoader.cs +++ b/src/Impostor.Server/Plugins/PluginLoader.cs @@ -47,7 +47,7 @@ public static IHostBuilder UsePluginLoader(this IHostBuilder builder, PluginConf // 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 @@ public static IHostBuilder UsePluginLoader(this IHostBuilder builder, PluginConf 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 64424a14e..740cc4686 100644 --- a/src/Impostor.Server/Plugins/PluginLoaderException.cs +++ b/src/Impostor.Server/Plugins/PluginLoaderException.cs @@ -10,16 +10,16 @@ public PluginLoaderException() { } - 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 0afbc2239..84238f786 100644 --- a/src/Impostor.Server/Plugins/PluginLoaderService.cs +++ b/src/Impostor.Server/Plugins/PluginLoaderService.cs @@ -32,7 +32,7 @@ public async Task StartAsync(CancellationToken cancellationToken) _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 @@ public async Task StartAsync(CancellationToken cancellationToken) _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 109c6be01..ab582caaa 100644 --- a/src/Impostor.Server/Program.cs +++ b/src/Impostor.Server/Program.cs @@ -128,7 +128,7 @@ private static IHostBuilder CreateHostBuilder(string[] args) 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 @@ private static IHostBuilder CreateHostBuilder(string[] args) 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 fd6daac02..000000000 --- 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 c8efdb35a..c6531b456 100644 --- a/src/Impostor.Server/Recorder/PacketRecorder.cs +++ b/src/Impostor.Server/Recorder/PacketRecorder.cs @@ -31,7 +31,7 @@ public PacketRecorder(ILogger logger, IOptions opti { 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 @@ public PacketRecorder(ILogger logger, IOptions opti }); } - 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 @@ public async Task WriteConnectAsync(ClientRecorder client) WriteClient(context, client, true); WriteLength(context); - await WriteAsync(context.Stream); + await WriteAsync(context.Stream!); } finally { @@ -103,7 +75,7 @@ public async Task WriteDisconnectAsync(ClientRecorder client, string reason) context.Writer.Write(reason); WriteLength(context); - await WriteAsync(context.Stream); + await WriteAsync(context.Stream!); } finally { @@ -124,7 +96,7 @@ public async Task WriteMessageAsync(ClientRecorder client, IMessageReader reader WritePacket(context, reader, messageType); WriteLength(context); - await WriteAsync(context.Stream); + await WriteAsync(context.Stream!); } finally { @@ -145,7 +117,7 @@ public async Task WriteGameCreatedAsync(ClientRecorder client, GameCode gameCode WriteGameCode(context, gameCode); WriteLength(context); - await WriteAsync(context.Stream); + await WriteAsync(context.Stream!); } finally { @@ -153,6 +125,34 @@ public async Task WriteGameCreatedAsync(ClientRecorder client, GameCode gameCode } } + 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 @@ private async Task WriteFileHeaderAsync() context.Writer.Write(_startTime.ToUnixTimeMilliseconds()); context.Writer.Write(DotnetUtils.GetVersion()); - await WriteAsync(context.Stream); + await WriteAsync(context.Stream!); } finally { @@ -182,7 +182,7 @@ private void WritePacketHeader(PacketSerializationContext context, RecordedPacke 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 @@ private static void WriteClient(PacketSerializationContext context, ClientBase c } } - 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 @@ private static void WritePacket(PacketSerializationContext context, IMessageRead 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 07755f6b0..2290bcb42 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 @@ public class PacketSerializationContext 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 @@ public void Reset() } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Recorder/RecordedPacketType.cs b/src/Impostor.Server/Recorder/RecordedPacketType.cs index a8a20bca2..336cd57e7 100644 --- a/src/Impostor.Server/Recorder/RecordedPacketType.cs +++ b/src/Impostor.Server/Recorder/RecordedPacketType.cs @@ -5,6 +5,6 @@ internal enum RecordedPacketType : byte 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 3f96bf6b5..a4ccd6bf6 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 8f523dc38..571d7b949 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 98fa689f8..3b46f3f87 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 43f0257b6..327296f12 100644 --- a/src/Impostor.Tools.ServerReplay/Mocks/MockHazelConnection.cs +++ b/src/Impostor.Tools.ServerReplay/Mocks/MockHazelConnection.cs @@ -16,7 +16,7 @@ public MockHazelConnection(IPEndPoint endPoint) 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 @@ public ValueTask DisconnectAsync(string reason) return ValueTask.CompletedTask; } } -} \ No newline at end of file +} diff --git a/src/ProjectRules.ruleset b/src/ProjectRules.ruleset new file mode 100644 index 000000000..5102b80bf --- /dev/null +++ b/src/ProjectRules.ruleset @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + From e90ba734ab05f993ea791ef700eb852bdf0a179f Mon Sep 17 00:00:00 2001 From: js6pak Date: Wed, 24 Mar 2021 16:57:11 +0100 Subject: [PATCH 26/72] Code cleanup --- .../IAnnouncementRequestEvent.cs | 14 ++-- .../Attributes/EventListenerAttribute.cs | 4 +- .../Events/Game/IGameCreatedEvent.cs | 2 +- .../Events/Game/IGameDestroyedEvent.cs | 2 +- src/Impostor.Api/Events/Game/IGameEvent.cs | 2 +- .../Events/Game/IGameStartingEvent.cs | 2 +- .../Game/Player/IPlayerCompletedTaskEvent.cs | 3 +- .../Events/Game/Player/IPlayerEvent.cs | 8 +-- src/Impostor.Api/Events/IEvent.cs | 2 +- src/Impostor.Api/Events/IEventCancelable.cs | 2 +- src/Impostor.Api/Events/IEventListener.cs | 2 +- .../Events/Managers/IEventManager.cs | 10 +-- .../Extensions/SpanReaderExtensions.cs | 6 +- .../Extensions/SystemTypesExtensions.cs | 2 +- .../Games/Extensions/GameExtensions.cs | 2 +- .../Games/Extensions/GameManagerExtensions.cs | 2 +- src/Impostor.Api/Games/GameCode.cs | 8 +-- src/Impostor.Api/Games/GameJoinError.cs | 4 +- src/Impostor.Api/Games/GameJoinResult.cs | 2 +- src/Impostor.Api/Games/IGame.cs | 23 +++---- src/Impostor.Api/Games/IGameCodeFactory.cs | 2 +- .../Games/Managers/IGameManager.cs | 2 +- src/Impostor.Api/Innersloth/AlterGameTags.cs | 2 +- src/Impostor.Api/Innersloth/ChatNoteType.cs | 2 +- src/Impostor.Api/Innersloth/DeathReason.cs | 2 +- src/Impostor.Api/Innersloth/GameKeywords.cs | 2 +- .../Innersloth/GameOptionsData.cs | 56 +++++++-------- src/Impostor.Api/Innersloth/GameStates.cs | 2 +- src/Impostor.Api/Innersloth/GameVersion.cs | 2 +- src/Impostor.Api/Innersloth/MapFlags.cs | 2 +- src/Impostor.Api/Innersloth/MapTypes.cs | 2 +- .../Innersloth/SystemTypeHelpers.cs | 4 +- src/Impostor.Api/Innersloth/SystemTypes.cs | 4 +- src/Impostor.Api/Innersloth/TaskTypes.cs | 2 +- src/Impostor.Api/Innersloth/TextBox.cs | 2 +- src/Impostor.Api/Net/IClient.cs | 10 +-- src/Impostor.Api/Net/IClientPlayer.cs | 10 +-- src/Impostor.Api/Net/IHazelConnection.cs | 2 +- src/Impostor.Api/Net/Inner/IInnerNetObject.cs | 2 +- .../IInnerCustomNetworkTransform.cs | 2 +- .../Net/Inner/Objects/IInnerPlayerControl.cs | 24 +++---- .../Net/Inner/Objects/ITaskInfo.cs | 1 - src/Impostor.Api/Net/LimboStates.cs | 2 +- .../Net/Manager/IClientManager.cs | 2 +- .../Net/Messages/C2S/Message00HostGameC2S.cs | 4 +- .../Net/Messages/C2S/Message01JoinGameC2S.cs | 5 +- .../Messages/C2S/Message04RemovePlayerC2S.cs | 8 ++- .../Net/Messages/C2S/Message08EndGameC2S.cs | 7 +- .../Net/Messages/C2S/Message10AlterGameC2S.cs | 7 +- .../Messages/C2S/Message11KickPlayerC2S.cs | 8 ++- .../Messages/C2S/Message16GetGameListC2S.cs | 5 +- .../Net/Messages/IMessageReader.cs | 2 +- .../Net/Messages/IMessageWriter.cs | 2 +- .../Net/Messages/IMessageWriterProvider.cs | 8 +-- src/Impostor.Api/Net/Messages/MessageFlags.cs | 2 +- src/Impostor.Api/Net/Messages/MessageType.cs | 2 +- .../Net/Messages/S2C/Message00HostGameS2C.cs | 2 +- .../Net/Messages/S2C/Message01JoinGameS2C.cs | 4 +- .../Messages/S2C/Message04RemovePlayerS2C.cs | 7 +- .../Messages/S2C/Message07JoinedGameS2C.cs | 8 ++- .../Net/Messages/S2C/Message10AlterGameS2C.cs | 7 +- .../Messages/S2C/Message11KickPlayerS2C.cs | 8 ++- .../Messages/S2C/Message12WaitForHostS2C.cs | 8 ++- .../Net/Messages/S2C/Message13RedirectS2C.cs | 7 +- .../Messages/S2C/Message16GetGameListS2C.cs | 5 +- src/Impostor.Api/Plugins/IPlugin.cs | 2 +- src/Impostor.Api/Plugins/IPluginStartup.cs | 2 +- .../Plugins/ImpostorPluginAttribute.cs | 2 +- src/Impostor.Api/Plugins/PluginBase.cs | 2 +- src/Impostor.Api/Properties/AssemblyInfo.cs | 2 +- src/Impostor.Api/Reactor/PluginSide.cs | 8 +-- src/Impostor.Api/Unity/Mathf.cs | 10 +-- .../Data/MessageReader_Bytes.cs | 10 +-- .../Data/MessageReader_Bytes_Pooled.cs | 10 +-- .../MessageReader_Bytes_Pooled_Improved.cs | 4 -- src/Impostor.Benchmarks/Data/MessageWriter.cs | 34 +++++----- .../Data/Span/MessageReader_Span.cs | 1 - .../Tests/MessageReaderBenchmark.cs | 4 +- src/Impostor.Client.App/Program.cs | 5 +- src/Impostor.Hazel/Connection.cs | 56 +++++++-------- src/Impostor.Hazel/ConnectionListener.cs | 28 ++++---- src/Impostor.Hazel/ConnectionState.cs | 4 +- src/Impostor.Hazel/ConnectionStatistics.cs | 67 +++++++++--------- src/Impostor.Hazel/DataReceivedEventArgs.cs | 4 +- src/Impostor.Hazel/DisconnectedEventArgs.cs | 6 +- src/Impostor.Hazel/HazelException.cs | 6 +- src/Impostor.Hazel/IPMode.cs | 8 +-- src/Impostor.Hazel/IRecyclable.cs | 2 +- src/Impostor.Hazel/MessageReader.cs | 20 +++--- src/Impostor.Hazel/MessageWriter.cs | 46 ++++++------- src/Impostor.Hazel/NetworkConnection.cs | 16 ++--- .../NetworkConnectionListener.cs | 4 +- src/Impostor.Hazel/NewConnectionEventArgs.cs | 6 +- src/Impostor.Hazel/ObjectPoolCustom.cs | 8 +-- src/Impostor.Hazel/Udp/SendOptionInternal.cs | 2 +- .../Udp/UdpBroadcastListener.cs | 26 ++++--- src/Impostor.Hazel/Udp/UdpBroadcaster.cs | 16 +++-- src/Impostor.Hazel/Udp/UdpClientConnection.cs | 15 ++-- .../Udp/UdpConnection.KeepAlive.cs | 8 +-- .../Udp/UdpConnection.Reliable.cs | 68 +++++++++---------- src/Impostor.Hazel/Udp/UdpConnection.cs | 30 ++++---- .../Udp/UdpConnectionListener.cs | 12 ++-- .../Udp/UdpConnectionRateLimit.cs | 2 +- src/Impostor.Hazel/Udp/UdpServerConnection.cs | 6 +- .../Impostor.Patcher.Cli/Program.cs | 2 +- .../AmongUsModifier.cs | 6 +- .../Impostor.Patcher.Shared/Configuration.cs | 2 +- .../Events/ErrorEventArgs.cs | 2 +- .../Events/SavedEventArgs.cs | 2 +- .../Innersloth/RegionInfo.cs | 2 +- .../Innersloth/ServerInfo.cs | 6 +- .../Forms/FrmMain.Designer.cs | 4 +- .../Forms/FrmMain.cs | 4 +- .../Impostor.Patcher.WinForms/Program.cs | 2 +- src/Impostor.Plugins.Debugger/DebugPlugin.cs | 2 +- .../DebugPluginStartup.cs | 2 +- src/Impostor.Plugins.Example/ExamplePlugin.cs | 2 +- .../Handlers/PlayerEventListener.cs | 2 +- .../Config/DisconnectMessages.cs | 2 +- src/Impostor.Server/Constants.cs | 2 +- src/Impostor.Server/Events/MultiDisposable.cs | 2 +- .../Register/RegisteredEventListener.cs | 2 +- .../Events/Register/TemporaryEventRegister.cs | 2 +- .../Extensions/NodeLocatorExtensions.cs | 2 +- .../Extensions/TypeExtensions.cs | 2 +- .../Net/Factories/IClientFactory.cs | 2 +- src/Impostor.Server/Net/GameCodeFactory.cs | 2 +- src/Impostor.Server/Net/Inner/GameObject.cs | 2 +- .../Net/Inner/InnerNetObject.cs | 3 +- .../Components/InnerCustomNetworkTransform.cs | 3 +- .../Objects/Components/InnerPlayerPhysics.cs | 1 - .../Net/Inner/Objects/InnerLobbyBehaviour.cs | 9 +-- .../Net/Inner/Objects/InnerMeetingHud.cs | 1 - .../Net/Inner/Objects/Systems/IActivatable.cs | 2 +- .../Net/Inner/Objects/Systems/ISystemType.cs | 2 +- .../ShipStatus/HudOverrideSystemType.cs | 7 +- .../Systems/ShipStatus/LifeSuppSystemType.cs | 7 +- .../Systems/ShipStatus/MedScanSystem.cs | 7 +- .../Systems/ShipStatus/ReactorSystemType.cs | 4 +- .../Systems/ShipStatus/SabotageSystemType.cs | 7 +- .../ShipStatus/SecurityCameraSystemType.cs | 7 +- .../Systems/ShipStatus/SwitchSystem.cs | 7 +- src/Impostor.Server/Net/Inner/SpawnFlags.cs | 2 +- .../Net/Manager/ClientManager.Api.cs | 2 +- .../Net/Manager/GameManager.cs | 2 +- .../Net/Redirector/ClientRedirector.cs | 1 - .../Net/Redirector/INodeProvider.cs | 2 +- .../Net/Redirector/NodeProviderConfig.cs | 2 +- src/Impostor.Server/Net/State/Game.Data.cs | 4 -- .../Net/State/Game.Outgoing.cs | 2 +- .../Plugins/IAssemblyInformation.cs | 2 +- .../Plugins/LoadedAssemblyInformation.cs | 2 +- src/Impostor.Server/Plugins/PluginConfig.cs | 2 +- .../Plugins/PluginLoaderService.cs | 1 - .../Properties/AssemblyInfo.cs | 6 +- .../Recorder/PacketRecorder.cs | 2 +- ...tSerializationContextPooledObjectPolicy.cs | 2 +- .../Recorder/ServerReplayVersion.cs | 6 +- .../Events/EventManagerTests.cs | 15 ++-- src/Impostor.Tests/GameCodeTests.cs | 3 +- .../Hazel/MessageReaderTests.cs | 46 ++++++------- .../Hazel/MessageWriterTests.cs | 2 +- src/Impostor.Tools.Proxy/HexUtils.cs | 45 ++++++------ src/Impostor.Tools.Proxy/Program.cs | 53 ++++++++------- .../Mocks/MockGameCodeFactory.cs | 2 +- src/Impostor.Tools.ServerReplay/Program.cs | 2 +- 166 files changed, 638 insertions(+), 620 deletions(-) diff --git a/src/Impostor.Api/Events/Announcements/IAnnouncementRequestEvent.cs b/src/Impostor.Api/Events/Announcements/IAnnouncementRequestEvent.cs index b4eaa0152..a0e54452d 100644 --- a/src/Impostor.Api/Events/Announcements/IAnnouncementRequestEvent.cs +++ b/src/Impostor.Api/Events/Announcements/IAnnouncementRequestEvent.cs @@ -3,40 +3,40 @@ namespace Impostor.Api.Events.Announcements { /// - /// Event fired after client requests a announcement. + /// Event fired after client requests a announcement. /// public interface IAnnouncementRequestEvent : IEvent { public interface IResponse { /// - /// Gets or sets FreeWeekendState, currently unused by the client. + /// Gets or sets FreeWeekendState, currently unused by the client. /// public FreeWeekendState FreeWeekendState { get; set; } /// - /// Gets or sets a value indicating whether announcement should be loaded from client's cache, can save some bytes. + /// Gets or sets a value indicating whether announcement should be loaded from client's cache, can save some bytes. /// public bool UseCached { get; set; } /// - /// Gets or sets announcement, should be null when is set to true. + /// Gets or sets announcement, should be null when is set to true. /// public Announcement? Announcement { get; set; } } /// - /// Gets client's last announcement id. + /// Gets client's last announcement id. /// public int Id { get; } /// - /// Gets client's language. + /// Gets client's language. /// public Language Language { get; } /// - /// Gets or sets plugin made response. + /// Gets or sets plugin made response. /// public IResponse Response { get; set; } } diff --git a/src/Impostor.Api/Events/Attributes/EventListenerAttribute.cs b/src/Impostor.Api/Events/Attributes/EventListenerAttribute.cs index b31d2d1a7..9289fa5f8 100644 --- a/src/Impostor.Api/Events/Attributes/EventListenerAttribute.cs +++ b/src/Impostor.Api/Events/Attributes/EventListenerAttribute.cs @@ -27,8 +27,8 @@ public EventListenerAttribute(Type @event, EventPriority priority = EventPriorit public Type? Event { get; set; } /// - /// If set to true, the listener will be called regardless of the . + /// If set to true, the listener will be called regardless of the . /// public bool IgnoreCancelled { get; set; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Events/Game/IGameCreatedEvent.cs b/src/Impostor.Api/Events/Game/IGameCreatedEvent.cs index ef45f1dbe..48c8d7cca 100644 --- a/src/Impostor.Api/Events/Game/IGameCreatedEvent.cs +++ b/src/Impostor.Api/Events/Game/IGameCreatedEvent.cs @@ -3,7 +3,7 @@ namespace Impostor.Api.Events { /// - /// Called whenever a new is created. + /// Called whenever a new is created. /// public interface IGameCreatedEvent : IGameEvent { diff --git a/src/Impostor.Api/Events/Game/IGameDestroyedEvent.cs b/src/Impostor.Api/Events/Game/IGameDestroyedEvent.cs index 7ff7b460d..e598aaea4 100644 --- a/src/Impostor.Api/Events/Game/IGameDestroyedEvent.cs +++ b/src/Impostor.Api/Events/Game/IGameDestroyedEvent.cs @@ -3,7 +3,7 @@ namespace Impostor.Api.Events { /// - /// Called whenever a new is destroyed. + /// Called whenever a new is destroyed. /// public interface IGameDestroyedEvent : IGameEvent { diff --git a/src/Impostor.Api/Events/Game/IGameEvent.cs b/src/Impostor.Api/Events/Game/IGameEvent.cs index c9ae5790d..c188af3fe 100644 --- a/src/Impostor.Api/Events/Game/IGameEvent.cs +++ b/src/Impostor.Api/Events/Game/IGameEvent.cs @@ -5,7 +5,7 @@ namespace Impostor.Api.Events public interface IGameEvent : IEvent { /// - /// Gets the this event belongs to. + /// Gets the this event belongs to. /// IGame Game { get; } } diff --git a/src/Impostor.Api/Events/Game/IGameStartingEvent.cs b/src/Impostor.Api/Events/Game/IGameStartingEvent.cs index 5998bf249..3ba450ea5 100644 --- a/src/Impostor.Api/Events/Game/IGameStartingEvent.cs +++ b/src/Impostor.Api/Events/Game/IGameStartingEvent.cs @@ -3,7 +3,7 @@ /// /// Called when the game is going to start. /// When this is called, not all players are initialized properly yet. - /// If you want to get correct player states, use . + /// If you want to get correct player states, use . /// public interface IGameStartingEvent : IGameEvent { diff --git a/src/Impostor.Api/Events/Game/Player/IPlayerCompletedTaskEvent.cs b/src/Impostor.Api/Events/Game/Player/IPlayerCompletedTaskEvent.cs index 78ccd2d6a..a5e322855 100644 --- a/src/Impostor.Api/Events/Game/Player/IPlayerCompletedTaskEvent.cs +++ b/src/Impostor.Api/Events/Game/Player/IPlayerCompletedTaskEvent.cs @@ -1,5 +1,4 @@ -using Impostor.Api.Innersloth; -using Impostor.Api.Net.Inner.Objects; +using Impostor.Api.Net.Inner.Objects; namespace Impostor.Api.Events.Player { diff --git a/src/Impostor.Api/Events/Game/Player/IPlayerEvent.cs b/src/Impostor.Api/Events/Game/Player/IPlayerEvent.cs index 247fe645b..d8269ffbb 100644 --- a/src/Impostor.Api/Events/Game/Player/IPlayerEvent.cs +++ b/src/Impostor.Api/Events/Game/Player/IPlayerEvent.cs @@ -6,14 +6,14 @@ namespace Impostor.Api.Events.Player public interface IPlayerEvent : IGameEvent { /// - /// Gets the that triggered this . + /// Gets the that triggered this . /// IClientPlayer ClientPlayer { get; } /// - /// Gets the networked that triggered this . - /// This belongs to the . + /// Gets the networked that triggered this . + /// This belongs to the . /// IInnerPlayerControl PlayerControl { get; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Events/IEvent.cs b/src/Impostor.Api/Events/IEvent.cs index 796898e1a..3bdb3a670 100644 --- a/src/Impostor.Api/Events/IEvent.cs +++ b/src/Impostor.Api/Events/IEvent.cs @@ -3,4 +3,4 @@ public interface IEvent { } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Events/IEventCancelable.cs b/src/Impostor.Api/Events/IEventCancelable.cs index 319f02a22..d6d1ca669 100644 --- a/src/Impostor.Api/Events/IEventCancelable.cs +++ b/src/Impostor.Api/Events/IEventCancelable.cs @@ -7,4 +7,4 @@ public interface IEventCancelable : IEvent /// bool IsCancelled { get; set; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Events/IEventListener.cs b/src/Impostor.Api/Events/IEventListener.cs index 76392fcc5..f3e8e4102 100644 --- a/src/Impostor.Api/Events/IEventListener.cs +++ b/src/Impostor.Api/Events/IEventListener.cs @@ -3,4 +3,4 @@ public interface IEventListener { } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Events/Managers/IEventManager.cs b/src/Impostor.Api/Events/Managers/IEventManager.cs index 07a7f7cf1..35fb9bbcc 100644 --- a/src/Impostor.Api/Events/Managers/IEventManager.cs +++ b/src/Impostor.Api/Events/Managers/IEventManager.cs @@ -16,20 +16,20 @@ IDisposable RegisterListener(TListener listener, Func, Tas where TListener : IEventListener; /// - /// Returns true if an event with the type is registered. + /// Returns true if an event with the type is registered. /// - /// True if the is registered. + /// True if the is registered. /// Type of the event. bool IsRegistered() where TEvent : IEvent; /// - /// Call all the event listeners for the type . + /// Call all the event listeners for the type . /// /// The event argument. /// Type of the event. - /// A representing the asynchronous operation. + /// A representing the asynchronous operation. ValueTask CallAsync(TEvent @event) where TEvent : IEvent; } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Extensions/SpanReaderExtensions.cs b/src/Impostor.Api/Extensions/SpanReaderExtensions.cs index c103ee7bc..242f05496 100644 --- a/src/Impostor.Api/Extensions/SpanReaderExtensions.cs +++ b/src/Impostor.Api/Extensions/SpanReaderExtensions.cs @@ -5,7 +5,7 @@ namespace Impostor.Api { /// - /// Priovides a StreamReader-like api throught extensions + /// Priovides a StreamReader-like api throught extensions /// public static class SpanReaderExtensions { @@ -53,7 +53,7 @@ private static unsafe float Int32BitsToSingle(int value) } /// - /// Advances the position of by the size of . + /// Advances the position of by the size of . /// /// Type that will be read. /// input "stream"/span. @@ -67,4 +67,4 @@ private static unsafe ReadOnlySpan Advance(ref ReadOnlySpan input return original; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Extensions/SystemTypesExtensions.cs b/src/Impostor.Api/Extensions/SystemTypesExtensions.cs index 68f1efda1..4238b4d0d 100644 --- a/src/Impostor.Api/Extensions/SystemTypesExtensions.cs +++ b/src/Impostor.Api/Extensions/SystemTypesExtensions.cs @@ -9,4 +9,4 @@ public static string GetFriendlyName(this SystemTypes type) return SystemTypeHelpers.Names[(int)type]; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Games/Extensions/GameExtensions.cs b/src/Impostor.Api/Games/Extensions/GameExtensions.cs index a73697815..e30050f94 100644 --- a/src/Impostor.Api/Games/Extensions/GameExtensions.cs +++ b/src/Impostor.Api/Games/Extensions/GameExtensions.cs @@ -39,4 +39,4 @@ public static ValueTask SendToAsync(this IGame game, IMessageWriter writer, ICli return game.SendToAsync(writer, player.Client); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Games/Extensions/GameManagerExtensions.cs b/src/Impostor.Api/Games/Extensions/GameManagerExtensions.cs index 6a95b3d4a..de9a06692 100644 --- a/src/Impostor.Api/Games/Extensions/GameManagerExtensions.cs +++ b/src/Impostor.Api/Games/Extensions/GameManagerExtensions.cs @@ -11,4 +11,4 @@ public static int GetGameCount(this IGameManager manager, MapFlags map) return manager.Games.Count(game => map.HasFlag((MapFlags)(1 << (byte)game.Options.Map))); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Games/GameCode.cs b/src/Impostor.Api/Games/GameCode.cs index 2c30e7e9d..e24c28a48 100644 --- a/src/Impostor.Api/Games/GameCode.cs +++ b/src/Impostor.Api/Games/GameCode.cs @@ -48,19 +48,19 @@ public static GameCode Create() public static GameCode From(string value) => new GameCode(value); - /// + /// public bool Equals(GameCode other) { return Code == other.Code && Value == other.Value; } - /// + /// public override bool Equals(object? obj) { return obj is GameCode other && Equals(other); } - /// + /// public override int GetHashCode() { return HashCode.Combine(Code, Value); @@ -71,4 +71,4 @@ public override string ToString() return Code; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Games/GameJoinError.cs b/src/Impostor.Api/Games/GameJoinError.cs index 4889ea965..7fcb0f946 100644 --- a/src/Impostor.Api/Games/GameJoinError.cs +++ b/src/Impostor.Api/Games/GameJoinError.cs @@ -41,8 +41,8 @@ public enum GameJoinError /// Custom error by a plugin. /// /// - /// A custom message can be set in . + /// A custom message can be set in . /// Custom, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Games/GameJoinResult.cs b/src/Impostor.Api/Games/GameJoinResult.cs index b33a2b669..4b25c8f31 100644 --- a/src/Impostor.Api/Games/GameJoinResult.cs +++ b/src/Impostor.Api/Games/GameJoinResult.cs @@ -45,4 +45,4 @@ public static GameJoinResult FromError(GameJoinError error) return new GameJoinResult(error); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Games/IGame.cs b/src/Impostor.Api/Games/IGame.cs index 58e92085f..ecc11f811 100644 --- a/src/Impostor.Api/Games/IGame.cs +++ b/src/Impostor.Api/Games/IGame.cs @@ -29,7 +29,7 @@ public interface IGame bool IsPublic { get; } /// - /// Gets or sets display name on game list. + /// Gets or sets display name on game list. /// string? DisplayName { get; set; } @@ -43,28 +43,27 @@ public interface IGame where T : IInnerNetObject; /// - /// Adds an to the ban list of this game. - /// Prevents all future joins from this . - /// - /// This does not kick the player with that from the lobby. + /// Adds an to the ban list of this game. + /// Prevents all future joins from this . + /// This does not kick the player with that from the lobby. /// /// - /// The to ban. + /// The to ban. /// void BanIp(IPAddress ipAddress); /// - /// Syncs the internal to all players. + /// Syncs the internal to all players. /// Necessary to do if you modified it, otherwise it won't be used. /// - /// A representing the asynchronous operation. + /// A representing the asynchronous operation. ValueTask SyncSettingsAsync(); /// /// Sets game's privacy. /// /// Privacy to set. - /// A representing the asynchronous operation. + /// A representing the asynchronous operation. ValueTask SetPrivacyAsync(bool isPublic); /// @@ -72,7 +71,7 @@ public interface IGame /// /// Message to send. /// Required limbo state of the player. - /// A representing the asynchronous operation. + /// A representing the asynchronous operation. ValueTask SendToAllAsync(IMessageWriter writer, LimboStates states = LimboStates.NotLimbo); /// @@ -81,7 +80,7 @@ public interface IGame /// Message to send. /// The player to exclude from sending the message. /// Required limbo state of the player. - /// A representing the asynchronous operation. + /// A representing the asynchronous operation. ValueTask SendToAllExceptAsync(IMessageWriter writer, int senderId, LimboStates states = LimboStates.NotLimbo); /// @@ -89,7 +88,7 @@ public interface IGame /// /// Message to send. /// ID of the client. - /// A representing the asynchronous operation. + /// A representing the asynchronous operation. ValueTask SendToAsync(IMessageWriter writer, int id); } } diff --git a/src/Impostor.Api/Games/IGameCodeFactory.cs b/src/Impostor.Api/Games/IGameCodeFactory.cs index f264fe004..38f047fb5 100644 --- a/src/Impostor.Api/Games/IGameCodeFactory.cs +++ b/src/Impostor.Api/Games/IGameCodeFactory.cs @@ -4,4 +4,4 @@ public interface IGameCodeFactory { GameCode Create(); } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Games/Managers/IGameManager.cs b/src/Impostor.Api/Games/Managers/IGameManager.cs index 7ee403fd2..cdf8558cf 100644 --- a/src/Impostor.Api/Games/Managers/IGameManager.cs +++ b/src/Impostor.Api/Games/Managers/IGameManager.cs @@ -12,4 +12,4 @@ public interface IGameManager ValueTask CreateAsync(GameOptionsData options); } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/AlterGameTags.cs b/src/Impostor.Api/Innersloth/AlterGameTags.cs index 46d1b2ee0..a1d9c425d 100644 --- a/src/Impostor.Api/Innersloth/AlterGameTags.cs +++ b/src/Impostor.Api/Innersloth/AlterGameTags.cs @@ -4,4 +4,4 @@ public enum AlterGameTags : byte { ChangePrivacy = 1, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/ChatNoteType.cs b/src/Impostor.Api/Innersloth/ChatNoteType.cs index c16360177..697b0311f 100644 --- a/src/Impostor.Api/Innersloth/ChatNoteType.cs +++ b/src/Impostor.Api/Innersloth/ChatNoteType.cs @@ -4,4 +4,4 @@ public enum ChatNoteType : byte { DidVote = 0, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/DeathReason.cs b/src/Impostor.Api/Innersloth/DeathReason.cs index a07ac0566..8b8a430ff 100644 --- a/src/Impostor.Api/Innersloth/DeathReason.cs +++ b/src/Impostor.Api/Innersloth/DeathReason.cs @@ -6,4 +6,4 @@ public enum DeathReason Kill = 1, Disconnect = 2, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/GameKeywords.cs b/src/Impostor.Api/Innersloth/GameKeywords.cs index bbb463f7f..4b3c67055 100644 --- a/src/Impostor.Api/Innersloth/GameKeywords.cs +++ b/src/Impostor.Api/Innersloth/GameKeywords.cs @@ -16,4 +16,4 @@ public enum GameKeywords : uint Polish = 128, English = 256, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/GameOptionsData.cs b/src/Impostor.Api/Innersloth/GameOptionsData.cs index 3d648445e..5530c8878 100644 --- a/src/Impostor.Api/Innersloth/GameOptionsData.cs +++ b/src/Impostor.Api/Innersloth/GameOptionsData.cs @@ -7,130 +7,130 @@ namespace Impostor.Api.Innersloth public class GameOptionsData { /// - /// The latest major version of the game client. + /// The latest major version of the game client. /// public const int LatestVersion = 4; /// - /// Gets or sets host's version of the game. + /// Gets or sets host's version of the game. /// public byte Version { get; set; } = LatestVersion; /// - /// Gets or sets the maximum amount of players for this lobby. + /// Gets or sets the maximum amount of players for this lobby. /// public byte MaxPlayers { get; set; } = 10; /// - /// Gets or sets the language of the lobby as per enum. + /// Gets or sets the language of the lobby as per enum. /// public GameKeywords Keywords { get; set; } = GameKeywords.English; /// - /// Gets or sets the Map selected for this lobby. + /// Gets or sets the Map selected for this lobby. /// public MapTypes Map { get; set; } = MapTypes.Skeld; /// - /// Gets or sets the Player speed modifier. + /// Gets or sets the Player speed modifier. /// public float PlayerSpeedMod { get; set; } = 1f; /// - /// Gets or sets the Light modifier for the players that are members of the crew as a multiplier value. + /// Gets or sets the Light modifier for the players that are members of the crew as a multiplier value. /// public float CrewLightMod { get; set; } = 1f; /// - /// Gets or sets the Light modifier for the players that are Impostors as a multiplier value. + /// Gets or sets the Light modifier for the players that are Impostors as a multiplier value. /// public float ImpostorLightMod { get; set; } = 1f; /// - /// Gets or sets the Impostor cooldown to kill in seconds. + /// Gets or sets the Impostor cooldown to kill in seconds. /// public float KillCooldown { get; set; } = 15f; /// - /// Gets or sets the number of common tasks. + /// Gets or sets the number of common tasks. /// public int NumCommonTasks { get; set; } = 1; /// - /// Gets or sets the number of long tasks. + /// Gets or sets the number of long tasks. /// public int NumLongTasks { get; set; } = 1; /// - /// Gets or sets the number of short tasks. + /// Gets or sets the number of short tasks. /// public int NumShortTasks { get; set; } = 2; /// - /// Gets or sets the maximum amount of emergency meetings each player can call during the game in seconds. + /// Gets or sets the maximum amount of emergency meetings each player can call during the game in seconds. /// public int NumEmergencyMeetings { get; set; } = 1; /// - /// Gets or sets the cooldown between each time any player can call an emergency meeting in seconds. + /// Gets or sets the cooldown between each time any player can call an emergency meeting in seconds. /// public int EmergencyCooldown { get; set; } = 15; /// - /// Gets or sets the number of impostors for this lobby. + /// Gets or sets the number of impostors for this lobby. /// public int NumImpostors { get; set; } = 1; /// - /// Gets or sets a value indicating whether ghosts (dead crew members) can do tasks. + /// Gets or sets a value indicating whether ghosts (dead crew members) can do tasks. /// public bool GhostsDoTasks { get; set; } = true; /// - /// Gets or sets the Kill as per values in . + /// Gets or sets the Kill as per values in . /// public KillDistances KillDistance { get; set; } = KillDistances.Normal; /// - /// Gets or sets the time for discussion before voting time in seconds. + /// Gets or sets the time for discussion before voting time in seconds. /// public int DiscussionTime { get; set; } = 15; /// - /// Gets or sets the time for voting in seconds. + /// Gets or sets the time for voting in seconds. /// public int VotingTime { get; set; } = 120; /// - /// Gets or sets a value indicating whether an ejected player is an impostor or not. + /// Gets or sets a value indicating whether an ejected player is an impostor or not. /// public bool ConfirmImpostor { get; set; } = true; /// - /// Gets or sets a value indicating whether players are able to see tasks being performed by other players. + /// Gets or sets a value indicating whether players are able to see tasks being performed by other players. /// /// - /// By being set to true, tasks such as Empty Garbage, Submit Scan, Clear asteroids, Prime shields execution will be visible to other players. + /// By being set to true, tasks such as Empty Garbage, Submit Scan, Clear asteroids, Prime shields execution will be visible to other players. /// public bool VisualTasks { get; set; } = true; /// - /// Gets or sets a value indicating whether the vote is anonymous. + /// Gets or sets a value indicating whether the vote is anonymous. /// public bool AnonymousVotes { get; set; } /// - /// Gets or sets the task bar update mode as per values in . + /// Gets or sets the task bar update mode as per values in . /// public TaskBarUpdate TaskBarUpdate { get; set; } = TaskBarUpdate.Always; /// - /// Gets or sets a value indicating whether the GameOptions are the default ones. + /// Gets or sets a value indicating whether the GameOptions are the default ones. /// public bool IsDefaults { get; set; } = true; /// - /// Deserialize a packet/message to a new GameOptionsData object. + /// Deserialize a packet/message to a new GameOptionsData object. /// /// Message reader object containing the raw message. /// GameOptionsData object. @@ -142,7 +142,7 @@ public static GameOptionsData DeserializeCreate(IMessageReader reader) } /// - /// Serializes this instance of GameOptionsData object to a specified BinaryWriter. + /// Serializes this instance of GameOptionsData object to a specified BinaryWriter. /// /// The stream to write the message to. /// The version of the game. @@ -198,7 +198,7 @@ public void Serialize(IMessageWriter writer) } /// - /// Deserialize a ReadOnlyMemory object to this instance of the GameOptionsData object. + /// Deserialize a ReadOnlyMemory object to this instance of the GameOptionsData object. /// /// Memory containing the message/packet. public void Deserialize(ReadOnlyMemory memory) diff --git a/src/Impostor.Api/Innersloth/GameStates.cs b/src/Impostor.Api/Innersloth/GameStates.cs index f5aaa9cc5..8e791de7d 100644 --- a/src/Impostor.Api/Innersloth/GameStates.cs +++ b/src/Impostor.Api/Innersloth/GameStates.cs @@ -8,4 +8,4 @@ public enum GameStates : byte Ended = 3, Destroyed = 4, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/GameVersion.cs b/src/Impostor.Api/Innersloth/GameVersion.cs index c11933ee3..501558959 100644 --- a/src/Impostor.Api/Innersloth/GameVersion.cs +++ b/src/Impostor.Api/Innersloth/GameVersion.cs @@ -7,4 +7,4 @@ public static int GetVersion(int year, int month, int day, int rev = 0) return (year * 25000) + (month * 1800) + (day * 50) + rev; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/MapFlags.cs b/src/Impostor.Api/Innersloth/MapFlags.cs index ad462a273..9b0d8f02a 100644 --- a/src/Impostor.Api/Innersloth/MapFlags.cs +++ b/src/Impostor.Api/Innersloth/MapFlags.cs @@ -9,4 +9,4 @@ public enum MapFlags MiraHQ = 2, Polus = 4, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/MapTypes.cs b/src/Impostor.Api/Innersloth/MapTypes.cs index 2b5ede98d..2706933aa 100644 --- a/src/Impostor.Api/Innersloth/MapTypes.cs +++ b/src/Impostor.Api/Innersloth/MapTypes.cs @@ -6,4 +6,4 @@ public enum MapTypes : byte MiraHQ = 1, Polus = 2, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/SystemTypeHelpers.cs b/src/Impostor.Api/Innersloth/SystemTypeHelpers.cs index ad88c28af..e9ba29bec 100644 --- a/src/Impostor.Api/Innersloth/SystemTypeHelpers.cs +++ b/src/Impostor.Api/Innersloth/SystemTypeHelpers.cs @@ -20,9 +20,9 @@ static SystemTypeHelpers() SystemTypes.LifeSupp => "O2", SystemTypes.LowerEngine => "Lower Engine", SystemTypes.LockerRoom => "Locker Room", - _ => x.ToString() + _ => x.ToString(), }; }).ToArray(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/SystemTypes.cs b/src/Impostor.Api/Innersloth/SystemTypes.cs index 5de8bc94d..6a072e771 100644 --- a/src/Impostor.Api/Innersloth/SystemTypes.cs +++ b/src/Impostor.Api/Innersloth/SystemTypes.cs @@ -39,7 +39,7 @@ public enum SystemTypes : byte Sabotage = 17, /// - /// Decontam on Mira and bottom decontam on Polus + /// Decontam on Mira and bottom decontam on Polus /// Decontamination = 18, @@ -58,7 +58,7 @@ public enum SystemTypes : byte Dropship = 25, /// - /// Top decontam on Polus + /// Top decontam on Polus /// Decontamination2 = 26, diff --git a/src/Impostor.Api/Innersloth/TaskTypes.cs b/src/Impostor.Api/Innersloth/TaskTypes.cs index 8b15354a4..d4794796c 100644 --- a/src/Impostor.Api/Innersloth/TaskTypes.cs +++ b/src/Impostor.Api/Innersloth/TaskTypes.cs @@ -46,4 +46,4 @@ public enum TaskTypes : uint RecordTemperature = 41, RebootWifi = 42, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Innersloth/TextBox.cs b/src/Impostor.Api/Innersloth/TextBox.cs index 9533d83ac..1928ce283 100644 --- a/src/Impostor.Api/Innersloth/TextBox.cs +++ b/src/Impostor.Api/Innersloth/TextBox.cs @@ -7,4 +7,4 @@ public static bool IsCharAllowed(char i) return i == ' ' || (i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z') || (i >= '0' && i <= '9') || (i >= 'À' && i <= 'ÿ') || (i >= 'Ѐ' && i <= 'џ') || (i >= 'ㄱ' && i <= 'ㆎ') || (i >= '가' && i <= '힣'); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/IClient.cs b/src/Impostor.Api/Net/IClient.cs index 1ba594470..790b1c0b8 100644 --- a/src/Impostor.Api/Net/IClient.cs +++ b/src/Impostor.Api/Net/IClient.cs @@ -29,7 +29,7 @@ public interface IClient string Name { get; } /// - /// Gets mods sent by client in modded handshake. + /// Gets mods sent by client in modded handshake. /// ISet Mods { get; } @@ -57,7 +57,7 @@ public interface IClient IDictionary Items { get; } /// - /// Gets or sets the current game data of the . + /// Gets or sets the current game data of the . /// IClientPlayer? Player { get; } @@ -68,16 +68,16 @@ public interface IClient ValueTask HandleDisconnectAsync(string reason); /// - /// Disconnect the client with a . + /// Disconnect the client with a . /// /// /// The message to show to the player. /// /// - /// Only used when is set to . + /// Only used when is set to . /// /// - /// A representing the asynchronous operation. + /// A representing the asynchronous operation. /// ValueTask DisconnectAsync(DisconnectReason reason, string? message = null); } diff --git a/src/Impostor.Api/Net/IClientPlayer.cs b/src/Impostor.Api/Net/IClientPlayer.cs index 60702101e..f11c87375 100644 --- a/src/Impostor.Api/Net/IClientPlayer.cs +++ b/src/Impostor.Api/Net/IClientPlayer.cs @@ -6,7 +6,7 @@ namespace Impostor.Api.Net { /// - /// Represents a player in . + /// Represents a player in . /// public interface IClientPlayer { @@ -16,7 +16,7 @@ public interface IClientPlayer IClient Client { get; } /// - /// Gets the game where the belongs to. + /// Gets the game where the belongs to. /// IGame Game { get; } @@ -30,10 +30,10 @@ public interface IClientPlayer public bool IsHost { get; } /// - /// Checks if the specified is owned by . + /// Checks if the specified is owned by . /// - /// The . - /// Returns true if owned by . + /// The . + /// Returns true if owned by . bool IsOwner(IInnerNetObject netObject); ValueTask KickAsync(); diff --git a/src/Impostor.Api/Net/IHazelConnection.cs b/src/Impostor.Api/Net/IHazelConnection.cs index 4e6c4b3fd..c012bd192 100644 --- a/src/Impostor.Api/Net/IHazelConnection.cs +++ b/src/Impostor.Api/Net/IHazelConnection.cs @@ -38,4 +38,4 @@ public interface IHazelConnection /// ValueTask DisconnectAsync(string? reason); } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Inner/IInnerNetObject.cs b/src/Impostor.Api/Net/Inner/IInnerNetObject.cs index c17137799..8cfadb8e6 100644 --- a/src/Impostor.Api/Net/Inner/IInnerNetObject.cs +++ b/src/Impostor.Api/Net/Inner/IInnerNetObject.cs @@ -6,4 +6,4 @@ public interface IInnerNetObject public int OwnerId { get; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Inner/Objects/Components/IInnerCustomNetworkTransform.cs b/src/Impostor.Api/Net/Inner/Objects/Components/IInnerCustomNetworkTransform.cs index 2dd470947..5ad4763c7 100644 --- a/src/Impostor.Api/Net/Inner/Objects/Components/IInnerCustomNetworkTransform.cs +++ b/src/Impostor.Api/Net/Inner/Objects/Components/IInnerCustomNetworkTransform.cs @@ -16,7 +16,7 @@ public interface IInnerCustomNetworkTransform : IInnerNetObject Vector2 Velocity { get; } /// - /// Snaps the current to the given position . + /// Snaps the current to the given position . /// /// The target position. /// Task that must be awaited. diff --git a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs index 0ee065ad8..711f878b4 100644 --- a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs +++ b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs @@ -7,30 +7,30 @@ namespace Impostor.Api.Net.Inner.Objects public interface IInnerPlayerControl : IInnerNetObject { /// - /// Gets the assigned by the client of the host of the game. + /// Gets the assigned by the client of the host of the game. /// byte PlayerId { get; } /// - /// Gets the of the . + /// Gets the of the . /// Contains vent logic. /// IInnerPlayerPhysics Physics { get; } /// - /// Gets the of the . + /// Gets the of the . /// Contains position data about the player. /// IInnerCustomNetworkTransform NetworkTransform { get; } /// - /// Gets the of the . + /// Gets the of the . /// Contains metadata about the player. /// IInnerPlayerInfo PlayerInfo { get; } /// - /// Sets the name of the current . + /// Sets the name of the current . /// Visible to all players. /// /// A name for the player. @@ -38,7 +38,7 @@ public interface IInnerPlayerControl : IInnerNetObject ValueTask SetNameAsync(string name); /// - /// Sets the color of the current . + /// Sets the color of the current . /// Visible to all players. /// /// A color for the player. @@ -46,7 +46,7 @@ public interface IInnerPlayerControl : IInnerNetObject ValueTask SetColorAsync(ColorType colorType); /// - /// Sets the hat of the current . + /// Sets the hat of the current . /// Visible to all players. /// /// An hat for the player. @@ -54,7 +54,7 @@ public interface IInnerPlayerControl : IInnerNetObject ValueTask SetHatAsync(HatType hatType); /// - /// Sets the pet of the current . + /// Sets the pet of the current . /// Visible to all players. /// /// A pet for the player. @@ -62,7 +62,7 @@ public interface IInnerPlayerControl : IInnerNetObject ValueTask SetPetAsync(PetType petType); /// - /// Sets the skin of the current . + /// Sets the skin of the current . /// Visible to all players. /// /// A skin for the player. @@ -70,7 +70,7 @@ public interface IInnerPlayerControl : IInnerNetObject ValueTask SetSkinAsync(SkinType skinType); /// - /// Send a chat message as the current . + /// Send a chat message as the current . /// Visible to all players. /// /// The message to send. @@ -78,7 +78,7 @@ public interface IInnerPlayerControl : IInnerNetObject ValueTask SendChatAsync(string text); /// - /// Send a chat message as the current . + /// Send a chat message as the current . /// Visible to only the current. /// /// The message to send. @@ -90,7 +90,7 @@ public interface IInnerPlayerControl : IInnerNetObject ValueTask SendChatToPlayerAsync(string text, IInnerPlayerControl? player = null); /// - /// Murder player. + /// Murder player. /// /// Target player to murder. /// Thrown when player is not the impostor. diff --git a/src/Impostor.Api/Net/Inner/Objects/ITaskInfo.cs b/src/Impostor.Api/Net/Inner/Objects/ITaskInfo.cs index 2b6dd86f0..f4e54b151 100644 --- a/src/Impostor.Api/Net/Inner/Objects/ITaskInfo.cs +++ b/src/Impostor.Api/Net/Inner/Objects/ITaskInfo.cs @@ -1,5 +1,4 @@ using Impostor.Api.Innersloth; -using Impostor.Api.Net.Messages; namespace Impostor.Api.Net.Inner.Objects { diff --git a/src/Impostor.Api/Net/LimboStates.cs b/src/Impostor.Api/Net/LimboStates.cs index 44c493e81..5d1242d4b 100644 --- a/src/Impostor.Api/Net/LimboStates.cs +++ b/src/Impostor.Api/Net/LimboStates.cs @@ -10,4 +10,4 @@ public enum LimboStates WaitingForHost = 4, All = PreSpawn | NotLimbo | WaitingForHost, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Manager/IClientManager.cs b/src/Impostor.Api/Net/Manager/IClientManager.cs index 92bf89f0d..737e42f37 100644 --- a/src/Impostor.Api/Net/Manager/IClientManager.cs +++ b/src/Impostor.Api/Net/Manager/IClientManager.cs @@ -6,4 +6,4 @@ public interface IClientManager { IEnumerable Clients { get; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs index 7d7ee5585..e81e861f6 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs @@ -14,9 +14,9 @@ public static void Serialize(IMessageWriter writer, GameOptionsData gameOptionsD /// /// Deserialize a packet. /// - /// with 0. + /// with 0. /// The chat type selected in the client of the player. - /// Deserialized . + /// Deserialized . public static GameOptionsData Deserialize(IMessageReader reader, out ChatType chatType) { var gameOptionsData = GameOptionsData.DeserializeCreate(reader); diff --git a/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs index 58a85120d..e7771e7c9 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs @@ -1,4 +1,5 @@ -using Impostor.Api.Games; +using System; +using Impostor.Api.Games; namespace Impostor.Api.Net.Messages.C2S { @@ -6,7 +7,7 @@ public static class Message01JoinGameC2S { public static void Serialize(IMessageWriter writer) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public static void Deserialize(IMessageReader reader, out GameCode gameCode) diff --git a/src/Impostor.Api/Net/Messages/C2S/Message04RemovePlayerC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message04RemovePlayerC2S.cs index 99cdcfa7f..a3bcedfcb 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message04RemovePlayerC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message04RemovePlayerC2S.cs @@ -1,10 +1,12 @@ -namespace Impostor.Api.Net.Messages.C2S +using System; + +namespace Impostor.Api.Net.Messages.C2S { public class Message04RemovePlayerC2S { public static void Serialize(IMessageWriter writer) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public static void Deserialize(IMessageReader reader, out int playerId, out byte reason) @@ -13,4 +15,4 @@ public static void Deserialize(IMessageReader reader, out int playerId, out byte reason = reader.ReadByte(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/C2S/Message08EndGameC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message08EndGameC2S.cs index 7ca5e3a61..d264294cf 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message08EndGameC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message08EndGameC2S.cs @@ -1,4 +1,5 @@ -using Impostor.Api.Innersloth; +using System; +using Impostor.Api.Innersloth; namespace Impostor.Api.Net.Messages.C2S { @@ -6,7 +7,7 @@ public class Message08EndGameC2S { public static void Serialize(IMessageWriter writer) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public static void Deserialize(IMessageReader reader, out GameOverReason gameOverReason) @@ -15,4 +16,4 @@ public static void Deserialize(IMessageReader reader, out GameOverReason gameOve reader.ReadBoolean(); // showAd } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/C2S/Message10AlterGameC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message10AlterGameC2S.cs index 330f3b5ba..57db66902 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message10AlterGameC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message10AlterGameC2S.cs @@ -1,4 +1,5 @@ -using Impostor.Api.Innersloth; +using System; +using Impostor.Api.Innersloth; namespace Impostor.Api.Net.Messages.C2S { @@ -6,7 +7,7 @@ public class Message10AlterGameC2S { public static void Serialize(IMessageWriter writer) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public static void Deserialize(IMessageReader reader, out AlterGameTags gameTag, out bool isPublic) @@ -17,4 +18,4 @@ public static void Deserialize(IMessageReader reader, out AlterGameTags gameTag, isPublic = slice.ReadBoolean(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/C2S/Message11KickPlayerC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message11KickPlayerC2S.cs index 7c5b8b980..acafcee06 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message11KickPlayerC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message11KickPlayerC2S.cs @@ -1,10 +1,12 @@ -namespace Impostor.Api.Net.Messages.C2S +using System; + +namespace Impostor.Api.Net.Messages.C2S { public class Message11KickPlayerC2S { public static void Serialize(IMessageWriter writer) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public static void Deserialize(IMessageReader reader, out int playerId, out bool isBan) @@ -13,4 +15,4 @@ public static void Deserialize(IMessageReader reader, out int playerId, out bool isBan = reader.ReadBoolean(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs index bc32d5eee..72be48d7a 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs @@ -1,4 +1,5 @@ -using Impostor.Api.Innersloth; +using System; +using Impostor.Api.Innersloth; namespace Impostor.Api.Net.Messages.C2S { @@ -6,7 +7,7 @@ public class Message16GetGameListC2S { public static void Serialize(IMessageWriter writer) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public static void Deserialize(IMessageReader reader, out GameOptionsData options, out ChatType chatType) diff --git a/src/Impostor.Api/Net/Messages/IMessageReader.cs b/src/Impostor.Api/Net/Messages/IMessageReader.cs index 1eb82d1f3..397ad5adb 100644 --- a/src/Impostor.Api/Net/Messages/IMessageReader.cs +++ b/src/Impostor.Api/Net/Messages/IMessageReader.cs @@ -18,7 +18,7 @@ public interface IMessageReader : IDisposable byte[] Buffer { get; } /// - /// Gets the offset of our current in the entire . + /// Gets the offset of our current in the entire . /// int Offset { get; } diff --git a/src/Impostor.Api/Net/Messages/IMessageWriter.cs b/src/Impostor.Api/Net/Messages/IMessageWriter.cs index 0f4b7fadd..fd500adcd 100644 --- a/src/Impostor.Api/Net/Messages/IMessageWriter.cs +++ b/src/Impostor.Api/Net/Messages/IMessageWriter.cs @@ -74,7 +74,7 @@ public interface IMessageWriter : IDisposable void Write(string value); /// - /// Writes a to the message. + /// Writes a to the message. /// /// Value to write. void Write(IPAddress value); diff --git a/src/Impostor.Api/Net/Messages/IMessageWriterProvider.cs b/src/Impostor.Api/Net/Messages/IMessageWriterProvider.cs index f39893930..cf9200426 100644 --- a/src/Impostor.Api/Net/Messages/IMessageWriterProvider.cs +++ b/src/Impostor.Api/Net/Messages/IMessageWriterProvider.cs @@ -3,14 +3,14 @@ public interface IMessageWriterProvider { /// - /// Retrieves a from the internal pool. - /// Make sure to call when you are done! + /// Retrieves a from the internal pool. + /// Make sure to call when you are done! /// /// - /// Whether to send the message as or . + /// Whether to send the message as or . /// Reliable packets will ensure delivery while unreliable packets may be lost. /// - /// A from the pool. + /// A from the pool. IMessageWriter Get(MessageType sendOption = MessageType.Unreliable); } } diff --git a/src/Impostor.Api/Net/Messages/MessageFlags.cs b/src/Impostor.Api/Net/Messages/MessageFlags.cs index aea0c60db..2ebf475dc 100644 --- a/src/Impostor.Api/Net/Messages/MessageFlags.cs +++ b/src/Impostor.Api/Net/Messages/MessageFlags.cs @@ -19,4 +19,4 @@ public static class MessageFlags public const byte GetGameList = 9; public const byte GetGameListV2 = 16; } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/MessageType.cs b/src/Impostor.Api/Net/Messages/MessageType.cs index 16043585d..50acb5246 100644 --- a/src/Impostor.Api/Net/Messages/MessageType.cs +++ b/src/Impostor.Api/Net/Messages/MessageType.cs @@ -29,4 +29,4 @@ public enum MessageType : byte /// Reliable, } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/S2C/Message00HostGameS2C.cs b/src/Impostor.Api/Net/Messages/S2C/Message00HostGameS2C.cs index 8402d1007..8fef2251e 100644 --- a/src/Impostor.Api/Net/Messages/S2C/Message00HostGameS2C.cs +++ b/src/Impostor.Api/Net/Messages/S2C/Message00HostGameS2C.cs @@ -17,4 +17,4 @@ public static GameOptionsData Deserialize(IMessageReader reader) throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/S2C/Message01JoinGameS2C.cs b/src/Impostor.Api/Net/Messages/S2C/Message01JoinGameS2C.cs index c45520105..74fdc4055 100644 --- a/src/Impostor.Api/Net/Messages/S2C/Message01JoinGameS2C.cs +++ b/src/Impostor.Api/Net/Messages/S2C/Message01JoinGameS2C.cs @@ -44,7 +44,7 @@ public static void SerializeError(IMessageWriter writer, bool clear, DisconnectR public static void Deserialize(IMessageReader reader) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/S2C/Message04RemovePlayerS2C.cs b/src/Impostor.Api/Net/Messages/S2C/Message04RemovePlayerS2C.cs index 77b447d05..bcdca0486 100644 --- a/src/Impostor.Api/Net/Messages/S2C/Message04RemovePlayerS2C.cs +++ b/src/Impostor.Api/Net/Messages/S2C/Message04RemovePlayerS2C.cs @@ -1,4 +1,5 @@ -using Impostor.Api.Innersloth; +using System; +using Impostor.Api.Innersloth; namespace Impostor.Api.Net.Messages.S2C { @@ -23,7 +24,7 @@ public static void Serialize(IMessageWriter writer, bool clear, int gameCode, in public static void Deserialize(IMessageReader reader) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/S2C/Message07JoinedGameS2C.cs b/src/Impostor.Api/Net/Messages/S2C/Message07JoinedGameS2C.cs index da6eb40ca..857fea1b8 100644 --- a/src/Impostor.Api/Net/Messages/S2C/Message07JoinedGameS2C.cs +++ b/src/Impostor.Api/Net/Messages/S2C/Message07JoinedGameS2C.cs @@ -1,4 +1,6 @@ -namespace Impostor.Api.Net.Messages.S2C +using System; + +namespace Impostor.Api.Net.Messages.S2C { public static class Message07JoinedGameS2C { @@ -25,7 +27,7 @@ public static void Serialize(IMessageWriter writer, bool clear, int gameCode, in public static void Deserialize(IMessageReader reader) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/S2C/Message10AlterGameS2C.cs b/src/Impostor.Api/Net/Messages/S2C/Message10AlterGameS2C.cs index fa155dfab..40c949d3a 100644 --- a/src/Impostor.Api/Net/Messages/S2C/Message10AlterGameS2C.cs +++ b/src/Impostor.Api/Net/Messages/S2C/Message10AlterGameS2C.cs @@ -1,4 +1,5 @@ -using Impostor.Api.Innersloth; +using System; +using Impostor.Api.Innersloth; namespace Impostor.Api.Net.Messages.S2C { @@ -20,7 +21,7 @@ public static void Serialize(IMessageWriter writer, bool clear, int gameCode, bo public static void Deserialize(IMessageReader reader) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/S2C/Message11KickPlayerS2C.cs b/src/Impostor.Api/Net/Messages/S2C/Message11KickPlayerS2C.cs index 1e2b6efc1..7ffdb7b5e 100644 --- a/src/Impostor.Api/Net/Messages/S2C/Message11KickPlayerS2C.cs +++ b/src/Impostor.Api/Net/Messages/S2C/Message11KickPlayerS2C.cs @@ -1,4 +1,6 @@ -namespace Impostor.Api.Net.Messages.S2C +using System; + +namespace Impostor.Api.Net.Messages.S2C { public class Message11KickPlayerS2C { @@ -18,7 +20,7 @@ public static void Serialize(IMessageWriter writer, bool clear, int gameCode, in public static void Deserialize(IMessageReader reader) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/S2C/Message12WaitForHostS2C.cs b/src/Impostor.Api/Net/Messages/S2C/Message12WaitForHostS2C.cs index 5964b1c55..8cf9046f9 100644 --- a/src/Impostor.Api/Net/Messages/S2C/Message12WaitForHostS2C.cs +++ b/src/Impostor.Api/Net/Messages/S2C/Message12WaitForHostS2C.cs @@ -1,4 +1,6 @@ -namespace Impostor.Api.Net.Messages.S2C +using System; + +namespace Impostor.Api.Net.Messages.S2C { public class Message12WaitForHostS2C { @@ -17,7 +19,7 @@ public static void Serialize(IMessageWriter writer, bool clear, int gameCode, in public static void Deserialize(IMessageReader reader) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/S2C/Message13RedirectS2C.cs b/src/Impostor.Api/Net/Messages/S2C/Message13RedirectS2C.cs index 4b93b0eef..0576c71d5 100644 --- a/src/Impostor.Api/Net/Messages/S2C/Message13RedirectS2C.cs +++ b/src/Impostor.Api/Net/Messages/S2C/Message13RedirectS2C.cs @@ -1,4 +1,5 @@ -using System.Net; +using System; +using System.Net; namespace Impostor.Api.Net.Messages.S2C { @@ -19,7 +20,7 @@ public static void Serialize(IMessageWriter writer, bool clear, IPEndPoint ipEnd public static void Deserialize(IMessageReader reader) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Net/Messages/S2C/Message16GetGameListS2C.cs b/src/Impostor.Api/Net/Messages/S2C/Message16GetGameListS2C.cs index 7b641929b..a09259ba6 100644 --- a/src/Impostor.Api/Net/Messages/S2C/Message16GetGameListS2C.cs +++ b/src/Impostor.Api/Net/Messages/S2C/Message16GetGameListS2C.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Impostor.Api.Games; namespace Impostor.Api.Net.Messages.S2C @@ -33,7 +34,7 @@ public static void Serialize(IMessageWriter writer, IEnumerable games) public static void Deserialize(IMessageReader reader) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } } } diff --git a/src/Impostor.Api/Plugins/IPlugin.cs b/src/Impostor.Api/Plugins/IPlugin.cs index fd0f38f07..9f1efcf58 100644 --- a/src/Impostor.Api/Plugins/IPlugin.cs +++ b/src/Impostor.Api/Plugins/IPlugin.cs @@ -11,4 +11,4 @@ public interface IPlugin : IEventListener ValueTask ReloadAsync(); } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Plugins/IPluginStartup.cs b/src/Impostor.Api/Plugins/IPluginStartup.cs index aa6a35f82..e9d858573 100644 --- a/src/Impostor.Api/Plugins/IPluginStartup.cs +++ b/src/Impostor.Api/Plugins/IPluginStartup.cs @@ -9,4 +9,4 @@ public interface IPluginStartup void ConfigureServices(IServiceCollection services); } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Plugins/ImpostorPluginAttribute.cs b/src/Impostor.Api/Plugins/ImpostorPluginAttribute.cs index b31bd4789..e2d6b0249 100644 --- a/src/Impostor.Api/Plugins/ImpostorPluginAttribute.cs +++ b/src/Impostor.Api/Plugins/ImpostorPluginAttribute.cs @@ -21,4 +21,4 @@ public ImpostorPluginAttribute(string package, string name, string author, strin public string Version { get; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Plugins/PluginBase.cs b/src/Impostor.Api/Plugins/PluginBase.cs index 03843638f..9d6f2b4f3 100644 --- a/src/Impostor.Api/Plugins/PluginBase.cs +++ b/src/Impostor.Api/Plugins/PluginBase.cs @@ -19,4 +19,4 @@ public virtual ValueTask ReloadAsync() return default; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Api/Properties/AssemblyInfo.cs b/src/Impostor.Api/Properties/AssemblyInfo.cs index c02e44aff..30143b8fa 100644 --- a/src/Impostor.Api/Properties/AssemblyInfo.cs +++ b/src/Impostor.Api/Properties/AssemblyInfo.cs @@ -1,3 +1,3 @@ using System.Runtime.CompilerServices; -[assembly:InternalsVisibleTo("Impostor.Server")] \ No newline at end of file +[assembly: InternalsVisibleTo("Impostor.Server")] diff --git a/src/Impostor.Api/Reactor/PluginSide.cs b/src/Impostor.Api/Reactor/PluginSide.cs index 30c588c7e..2118299bf 100644 --- a/src/Impostor.Api/Reactor/PluginSide.cs +++ b/src/Impostor.Api/Reactor/PluginSide.cs @@ -1,22 +1,22 @@ namespace Impostor.Api.Reactor { /// - /// Plugin side used in modded handshake + /// Plugin side used in modded handshake /// public enum PluginSide : byte { /// - /// Required by both sides, reject connection if missing on the other side + /// Required by both sides, reject connection if missing on the other side /// Both, /// - /// Required only by client + /// Required only by client /// ClientOnly, /// - /// Required only by server + /// Required only by server /// ServerOnly, } diff --git a/src/Impostor.Api/Unity/Mathf.cs b/src/Impostor.Api/Unity/Mathf.cs index c907f816a..5ab93c743 100644 --- a/src/Impostor.Api/Unity/Mathf.cs +++ b/src/Impostor.Api/Unity/Mathf.cs @@ -3,13 +3,13 @@ public static class Mathf { /// - /// Clamps the given value between the given minimum float and maximum float values. Returns the given value if it is within the min and max range. + /// Clamps the given value between the given minimum float and maximum float values. Returns the given value if it is within the min and max range. /// /// The floating point value to restrict inside the range defined by the min and max values. /// The minimum floating point value to compare against. /// The maximum floating point value to compare against. /// - /// The float result between the min and max values. + /// The float result between the min and max values. /// public static float Clamp(float value, float min, float max) { @@ -26,7 +26,7 @@ public static float Clamp(float value, float min, float max) } /// - /// Clamps value between 0 and 1 and returns value. + /// Clamps value between 0 and 1 and returns value. /// /// Value. /// Clamped value. @@ -41,13 +41,13 @@ public static float Clamp01(float value) } /// - /// Linearly interpolates between a and b by t. + /// Linearly interpolates between a and b by t. /// /// The start value. /// The end value. /// The interpolation value between the two floats. /// - /// The interpolated float result between the two float values. + /// The interpolated float result between the two float values. /// public static float Lerp(float a, float b, float t) => a + ((b - a) * Clamp01(t)); diff --git a/src/Impostor.Benchmarks/Data/MessageReader_Bytes.cs b/src/Impostor.Benchmarks/Data/MessageReader_Bytes.cs index 2aba724eb..7788f0e8a 100644 --- a/src/Impostor.Benchmarks/Data/MessageReader_Bytes.cs +++ b/src/Impostor.Benchmarks/Data/MessageReader_Bytes.cs @@ -41,7 +41,7 @@ public MessageReader_Bytes ReadMessage() public bool ReadBoolean() { - byte val = FastByte(); + var val = FastByte(); return val != 0; } @@ -88,7 +88,7 @@ public unsafe float ReadSingle() float output = 0; fixed (byte* bufPtr = &this.Buffer[Position]) { - byte* outPtr = (byte*)&output; + var outPtr = (byte*)&output; *outPtr = *bufPtr; *(outPtr + 1) = *(bufPtr + 1); @@ -134,13 +134,13 @@ public int ReadPackedInt32() public uint ReadPackedUInt32() { - bool readMore = true; - int shift = 0; + var readMore = true; + var shift = 0; uint output = 0; while (readMore) { - byte b = FastByte(); + var b = FastByte(); if (b >= 0x80) { readMore = true; diff --git a/src/Impostor.Benchmarks/Data/MessageReader_Bytes_Pooled.cs b/src/Impostor.Benchmarks/Data/MessageReader_Bytes_Pooled.cs index 110333626..3c88ffb7c 100644 --- a/src/Impostor.Benchmarks/Data/MessageReader_Bytes_Pooled.cs +++ b/src/Impostor.Benchmarks/Data/MessageReader_Bytes_Pooled.cs @@ -65,7 +65,7 @@ public MessageReader_Bytes_Pooled ReadMessage() public bool ReadBoolean() { - byte val = FastByte(); + var val = FastByte(); return val != 0; } @@ -112,7 +112,7 @@ public unsafe float ReadSingle() float output = 0; fixed (byte* bufPtr = &this.Buffer[Position]) { - byte* outPtr = (byte*)&output; + var outPtr = (byte*)&output; *outPtr = *bufPtr; *(outPtr + 1) = *(bufPtr + 1); @@ -158,13 +158,13 @@ public int ReadPackedInt32() public uint ReadPackedUInt32() { - bool readMore = true; - int shift = 0; + var readMore = true; + var shift = 0; uint output = 0; while (readMore) { - byte b = FastByte(); + var b = FastByte(); if (b >= 0x80) { readMore = true; diff --git a/src/Impostor.Benchmarks/Data/MessageReader_Bytes_Pooled_Improved.cs b/src/Impostor.Benchmarks/Data/MessageReader_Bytes_Pooled_Improved.cs index 006684797..cb5d18dc6 100644 --- a/src/Impostor.Benchmarks/Data/MessageReader_Bytes_Pooled_Improved.cs +++ b/src/Impostor.Benchmarks/Data/MessageReader_Bytes_Pooled_Improved.cs @@ -1,10 +1,6 @@ using System; using System.Buffers.Binary; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; using System.Runtime.CompilerServices; -using System.Text; using Microsoft.Extensions.ObjectPool; namespace Impostor.Benchmarks.Data diff --git a/src/Impostor.Benchmarks/Data/MessageWriter.cs b/src/Impostor.Benchmarks/Data/MessageWriter.cs index 42f452ac7..b55b7970e 100644 --- a/src/Impostor.Benchmarks/Data/MessageWriter.cs +++ b/src/Impostor.Benchmarks/Data/MessageWriter.cs @@ -32,7 +32,7 @@ public byte[] ToByteArray(bool includeHeader) { if (includeHeader) { - byte[] output = new byte[this.Length]; + var output = new byte[this.Length]; System.Buffer.BlockCopy(this.Buffer, 0, output, 0, this.Length); return output; } @@ -41,17 +41,17 @@ public byte[] ToByteArray(bool includeHeader) switch (this.SendOption) { case MessageType.Reliable: - { - byte[] output = new byte[this.Length - 3]; - System.Buffer.BlockCopy(this.Buffer, 3, output, 0, this.Length - 3); - return output; - } + { + var output = new byte[this.Length - 3]; + System.Buffer.BlockCopy(this.Buffer, 3, output, 0, this.Length - 3); + return output; + } case MessageType.Unreliable: - { - byte[] output = new byte[this.Length - 1]; - System.Buffer.BlockCopy(this.Buffer, 1, output, 0, this.Length - 1); - return output; - } + { + var output = new byte[this.Length - 1]; + System.Buffer.BlockCopy(this.Buffer, 1, output, 0, this.Length - 1); + return output; + } default: throw new ArgumentOutOfRangeException(); } @@ -87,7 +87,7 @@ public void StartMessage(byte typeFlag) public void EndMessage() { var lastMessageStart = messageStarts.Pop(); - ushort length = (ushort)(this.Position - lastMessageStart - 3); // Minus length and type byte + var length = (ushort)(this.Position - lastMessageStart - 3); // Minus length and type byte this.Buffer[lastMessageStart] = (byte)length; this.Buffer[lastMessageStart + 1] = (byte)(length >> 8); } @@ -173,7 +173,7 @@ public unsafe void Write(float value) { fixed (byte* ptr = &this.Buffer[this.Position]) { - byte* valuePtr = (byte*)&value; + var valuePtr = (byte*)&value; *ptr = *valuePtr; *(ptr + 1) = *(valuePtr + 1); @@ -260,7 +260,7 @@ public void WritePacked(uint value) { do { - byte b = (byte)(value & 0xFF); + var b = (byte)(value & 0xFF); if (value >= 0x80) { b |= 0x80; @@ -275,7 +275,7 @@ public void WritePacked(uint value) public void Write(MessageWriter msg, bool includeHeader) { - int offset = 0; + var offset = 0; if (!includeHeader) { switch (msg.SendOption) @@ -298,8 +298,8 @@ public unsafe static bool IsLittleEndian() byte b; unsafe { - int i = 1; - byte* bp = (byte*)&i; + var i = 1; + var bp = (byte*)&i; b = *bp; } diff --git a/src/Impostor.Benchmarks/Data/Span/MessageReader_Span.cs b/src/Impostor.Benchmarks/Data/Span/MessageReader_Span.cs index 5636dbed0..3a7edecb8 100644 --- a/src/Impostor.Benchmarks/Data/Span/MessageReader_Span.cs +++ b/src/Impostor.Benchmarks/Data/Span/MessageReader_Span.cs @@ -1,6 +1,5 @@ using System; using System.Buffers.Binary; -using Impostor.Hazel; namespace Impostor.Benchmarks.Data.Span { diff --git a/src/Impostor.Benchmarks/Tests/MessageReaderBenchmark.cs b/src/Impostor.Benchmarks/Tests/MessageReaderBenchmark.cs index abf16428b..dbaf2279d 100644 --- a/src/Impostor.Benchmarks/Tests/MessageReaderBenchmark.cs +++ b/src/Impostor.Benchmarks/Tests/MessageReaderBenchmark.cs @@ -4,10 +4,8 @@ using Impostor.Benchmarks.Data; using Impostor.Benchmarks.Data.Pool; using Impostor.Benchmarks.Extensions; -using Impostor.Hazel; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.ObjectPool; -using MessageWriter = Impostor.Benchmarks.Data.MessageWriter; namespace Impostor.Benchmarks.Tests { @@ -24,7 +22,7 @@ public void Setup() message.StartMessage(1); message.Write((ushort)3100); message.Write((byte)100); - message.Write((int) int.MaxValue); + message.Write((int)int.MaxValue); message.WritePacked(int.MaxValue); message.EndMessage(); diff --git a/src/Impostor.Client.App/Program.cs b/src/Impostor.Client.App/Program.cs index aa8866ade..ba039a572 100644 --- a/src/Impostor.Client.App/Program.cs +++ b/src/Impostor.Client.App/Program.cs @@ -1,5 +1,4 @@ -using System; -using System.Net; +using System.Net; using System.Threading; using System.Threading.Tasks; using Impostor.Api.Innersloth; @@ -31,7 +30,7 @@ private static async Task Main(string[] args) Message00HostGameC2S.Serialize(writeGameCreate, new GameOptionsData { MaxPlayers = 4, - NumImpostors = 2 + NumImpostors = 2, }); // TODO: ObjectPool for MessageReaders diff --git a/src/Impostor.Hazel/Connection.cs b/src/Impostor.Hazel/Connection.cs index dec8cfecb..23d7f4b69 100644 --- a/src/Impostor.Hazel/Connection.cs +++ b/src/Impostor.Hazel/Connection.cs @@ -11,7 +11,7 @@ namespace Impostor.Hazel /// /// /// - /// Connection is the base class for all connections that Hazel can make. It provides common functionality and a + /// Connection is the base class for all connections that Hazel can make. It provides common functionality and a /// standard interface to allow connections to be swapped easily. /// /// @@ -29,7 +29,7 @@ namespace Impostor.Hazel /// /// /// - /// + /// public abstract class Connection : IDisposable { private static readonly ILogger Logger = Log.ForContext(); @@ -39,34 +39,34 @@ public abstract class Connection : IDisposable /// /// /// - /// DataReceived is invoked everytime a message is received from the end point of this connection, the message - /// that was received can be found in the alongside other information from the + /// DataReceived is invoked everytime a message is received from the end point of this connection, the message + /// that was received can be found in the alongside other information from the /// event. /// /// /// /// - /// + /// /// public Func DataReceived; public int TestLagMs = -1; public int TestDropRate = 0; protected int testDropCount = 0; - + /// /// Called when the end point disconnects or an error occurs. /// /// /// - /// Disconnected is invoked when the connection is closed due to an exception occuring or because the remote - /// end point disconnected. If it was invoked due to an exception occuring then the exception is available - /// in the passed with the event. + /// Disconnected is invoked when the connection is closed due to an exception occuring or because the remote + /// end point disconnected. If it was invoked due to an exception occuring then the exception is available + /// in the passed with the event. /// /// /// /// - /// + /// /// public Func Disconnected; @@ -74,8 +74,8 @@ public abstract class Connection : IDisposable /// The remote end point of this Connection. /// /// - /// This is the end point that this connection is connected to (i.e. the other device). This returns an abstract - /// which can then be cast to an appropriate end point depending on the + /// This is the end point that this connection is connected to (i.e. the other device). This returns an abstract + /// which can then be cast to an appropriate end point depending on the /// connection type. /// public IPEndPoint EndPoint { get; protected set; } @@ -95,7 +95,7 @@ public abstract class Connection : IDisposable /// /// /// All implementers should be aware that when this is set to ConnectionState.Connected it will - /// release all threads that are blocked on . + /// release all threads that are blocked on . /// public ConnectionState State { @@ -103,7 +103,7 @@ public ConnectionState State { return this._state; } - + protected set { this._state = value; @@ -113,13 +113,13 @@ protected set protected ConnectionState _state; protected virtual void SetState(ConnectionState state) { } - + /// /// Constructor that initializes the ConnecitonStatistics object. /// /// - /// This constructor initialises with empty statistics and sets to - /// . + /// This constructor initialises with empty statistics and sets to + /// . /// protected Connection() { @@ -128,21 +128,21 @@ protected Connection() } /// - /// Sends a number of bytes to the end point of the connection using the specified . + /// Sends a number of bytes to the end point of the connection using the specified . /// /// The message to send. /// /// /// /// The messageType parameter is only a request to use those options and the actual method used to send the - /// data is up to the implementation. There are circumstances where this parameter may be ignored but in + /// data is up to the implementation. There are circumstances where this parameter may be ignored but in /// general any implementer should aim to always follow the user's request. /// /// public abstract ValueTask SendAsync(IMessageWriter msg); /// - /// Sends a number of bytes to the end point of the connection using the specified . + /// Sends a number of bytes to the end point of the connection using the specified . /// /// The bytes of the message to send. /// The option specifying how the message should be sent. @@ -150,7 +150,7 @@ protected Connection() /// /// /// The messageType parameter is only a request to use those options and the actual method used to send the - /// data is up to the implementation. There are circumstances where this parameter may be ignored but in + /// data is up to the implementation. There are circumstances where this parameter may be ignored but in /// general any implementer should aim to always follow the user's request. /// /// @@ -167,9 +167,9 @@ protected Connection() /// Invokes the DataReceived event. /// /// The bytes received. - /// The the message was received with. + /// The the message was received with. /// - /// Invokes the event on this connection to alert subscribers a new message has been + /// Invokes the event on this connection to alert subscribers a new message has been /// received. The bytes and the send option that the message was sent with should be passed in to give to the /// subscribers. /// @@ -197,8 +197,8 @@ protected async ValueTask InvokeDataReceived(IMessageReader msg, MessageType mes /// The exception, if any, that occurred to cause this. /// Extra disconnect data /// - /// Invokes the event to alert subscribres this connection has been disconnected either - /// by the end point or because an error occurred. If an error occurred the error should be passed in in order to + /// Invokes the event to alert subscribres this connection has been disconnected either + /// by the end point or because an error occurred. If an error occurred the error should be passed in in order to /// pass to the subscribers, otherwise null can be passed in. /// protected async ValueTask InvokeDisconnected(string e, IMessageReader reader) @@ -219,11 +219,11 @@ protected async ValueTask InvokeDisconnected(string e, IMessageReader reader) } /// - /// For times when you want to force the disconnect handler to fire as well as close it. - /// If you only want to close it, just use Dispose. + /// For times when you want to force the disconnect handler to fire as well as close it. + /// If you only want to close it, just use Dispose. /// public abstract ValueTask Disconnect(string reason, MessageWriter writer = null); - + /// /// Disposes of this NetworkConnection. /// diff --git a/src/Impostor.Hazel/ConnectionListener.cs b/src/Impostor.Hazel/ConnectionListener.cs index 116f657e4..6c2f942ff 100644 --- a/src/Impostor.Hazel/ConnectionListener.cs +++ b/src/Impostor.Hazel/ConnectionListener.cs @@ -10,16 +10,16 @@ namespace Impostor.Hazel /// /// /// - /// ConnectionListeners are server side objects that listen for clients and create matching server side connections + /// ConnectionListeners are server side objects that listen for clients and create matching server side connections /// for each client in a similar way to TCP does. These connections should be ready for communication immediately. /// /// - /// Each time a client connects the event will be invoked to alert all subscribers to - /// the new connection. A disconnected event is then present on the that is passed to the + /// Each time a client connects the event will be invoked to alert all subscribers to + /// the new connection. A disconnected event is then present on the that is passed to the /// subscribers. /// /// - /// + /// public abstract class ConnectionListener : IAsyncDisposable { private static readonly ILogger Logger = Log.ForContext(); @@ -29,18 +29,18 @@ public abstract class ConnectionListener : IAsyncDisposable /// /// /// - /// NewConnection is invoked each time a client connects to the listener. The - /// contains the new for communication with this + /// NewConnection is invoked each time a client connects to the listener. The + /// contains the new for communication with this /// client. /// /// - /// Hazel may or may not store connections so it is your responsibility to keep track and properly Dispose of - /// connections to your server. + /// Hazel may or may not store connections so it is your responsibility to keep track and properly Dispose of + /// connections to your server. /// /// /// /// - /// + /// /// public Func NewConnection; @@ -49,15 +49,15 @@ public abstract class ConnectionListener : IAsyncDisposable /// /// /// - /// This instructs the listener to begin listening for new clients connecting to the server. When a new client - /// connects the event will be invoked containing the connection to the new client. + /// This instructs the listener to begin listening for new clients connecting to the server. When a new client + /// connects the event will be invoked containing the connection to the new client. /// /// - /// To stop listening you should call . + /// To stop listening you should call . /// /// /// - /// + /// /// public abstract Task StartAsync(); @@ -67,7 +67,7 @@ public abstract class ConnectionListener : IAsyncDisposable /// The user sent bytes that were received as part of the handshake. /// The connection to pass in the arguments. /// - /// Implementers should call this to invoke the event before data is received so that + /// Implementers should call this to invoke the event before data is received so that /// subscribers do not miss any data that may have been sent immediately after connecting. /// internal async Task InvokeNewConnection(IMessageReader msg, Connection connection) diff --git a/src/Impostor.Hazel/ConnectionState.cs b/src/Impostor.Hazel/ConnectionState.cs index 5dd7c6a07..c9fd4de0f 100644 --- a/src/Impostor.Hazel/ConnectionState.cs +++ b/src/Impostor.Hazel/ConnectionState.cs @@ -1,7 +1,7 @@ namespace Impostor.Hazel { /// - /// Represents the state a is currently in. + /// Represents the state a is currently in. /// public enum ConnectionState { @@ -9,7 +9,7 @@ public enum ConnectionState /// The Connection has either not been established yet or has been disconnected. /// NotConnected, - + /// /// The Connection is currently connecting to an endpoint. /// diff --git a/src/Impostor.Hazel/ConnectionStatistics.cs b/src/Impostor.Hazel/ConnectionStatistics.cs index 48026208e..cd7567cf0 100644 --- a/src/Impostor.Hazel/ConnectionStatistics.cs +++ b/src/Impostor.Hazel/ConnectionStatistics.cs @@ -2,12 +2,13 @@ using System.Threading; [assembly: InternalsVisibleTo("Hazel.Tests")] + namespace Impostor.Hazel { /// - /// Holds statistics about the traffic through a . + /// Holds statistics about the traffic through a . /// - /// + /// public class ConnectionStatistics { private const int ExpectedMTU = 1200; @@ -27,8 +28,8 @@ public int MessagesSent /// The number of messages sent larger than 576 bytes. This is smaller than most default MTUs. /// /// - /// This is the number of unreliable messages that were sent from the , incremented - /// each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not + /// This is the number of unreliable messages that were sent from the , incremented + /// each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not /// counted and messages are only counted once all other operations in the send are complete. /// public int FragmentableMessagesSent @@ -48,8 +49,8 @@ public int FragmentableMessagesSent /// The number of unreliable messages sent. /// /// - /// This is the number of unreliable messages that were sent from the , incremented - /// each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not + /// This is the number of unreliable messages that were sent from the , incremented + /// each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not /// counted and messages are only counted once all other operations in the send are complete. /// public int UnreliableMessagesSent @@ -69,8 +70,8 @@ public int UnreliableMessagesSent /// The number of reliable messages sent. /// /// - /// This is the number of reliable messages that were sent from the , incremented - /// each time that LogReliableSend is called by the Connection. Messages that caused an error are not + /// This is the number of reliable messages that were sent from the , incremented + /// each time that LogReliableSend is called by the Connection. Messages that caused an error are not /// counted and messages are only counted once all other operations in the send are complete. /// public int ReliableMessagesSent @@ -90,8 +91,8 @@ public int ReliableMessagesSent /// The number of fragmented messages sent. /// /// - /// This is the number of fragmented messages that were sent from the , incremented - /// each time that LogFragmentedSend is called by the Connection. Messages that caused an error are not + /// This is the number of fragmented messages that were sent from the , incremented + /// each time that LogFragmentedSend is called by the Connection. Messages that caused an error are not /// counted and messages are only counted once all other operations in the send are complete. /// public int FragmentedMessagesSent @@ -111,8 +112,8 @@ public int FragmentedMessagesSent /// The number of acknowledgement messages sent. /// /// - /// This is the number of acknowledgements that were sent from the , incremented - /// each time that LogAcknowledgementSend is called by the Connection. Messages that caused an error are not + /// This is the number of acknowledgements that were sent from the , incremented + /// each time that LogAcknowledgementSend is called by the Connection. Messages that caused an error are not /// counted and messages are only counted once all other operations in the send are complete. /// public int AcknowledgementMessagesSent @@ -132,8 +133,8 @@ public int AcknowledgementMessagesSent /// The number of hello messages sent. /// /// - /// This is the number of hello messages that were sent from the , incremented - /// each time that LogHelloSend is called by the Connection. Messages that caused an error are not + /// This is the number of hello messages that were sent from the , incremented + /// each time that LogHelloSend is called by the Connection. Messages that caused an error are not /// counted and messages are only counted once all other operations in the send are complete. /// public int HelloMessagesSent @@ -154,12 +155,12 @@ public int HelloMessagesSent /// /// /// - /// This is the number of bytes of data (i.e. user bytes) that were sent from the , - /// accumulated each time that LogSend is called by the Connection. Messages that caused an error are not + /// This is the number of bytes of data (i.e. user bytes) that were sent from the , + /// accumulated each time that LogSend is called by the Connection. Messages that caused an error are not /// counted and messages are only counted once all other operations in the send are complete. /// /// - /// For the number of bytes including protocol bytes see . + /// For the number of bytes including protocol bytes see . /// /// public long DataBytesSent @@ -180,13 +181,13 @@ public long DataBytesSent /// /// /// - /// This is the total number of bytes (the data bytes plus protocol bytes) that were sent from the - /// , accumulated each time that LogSend is called by the Connection. Messages that - /// caused an error are not counted and messages are only counted once all other operations in the send are + /// This is the total number of bytes (the data bytes plus protocol bytes) that were sent from the + /// , accumulated each time that LogSend is called by the Connection. Messages that + /// caused an error are not counted and messages are only counted once all other operations in the send are /// complete. /// /// - /// For the number of data bytes excluding protocol bytes see . + /// For the number of data bytes excluding protocol bytes see . /// /// public long TotalBytesSent @@ -212,12 +213,12 @@ public int MessagesReceived return UnreliableMessagesReceived + ReliableMessagesReceived + FragmentedMessagesReceived + AcknowledgementMessagesReceived + helloMessagesReceived; } } - + /// /// The number of unreliable messages received. /// /// - /// This is the number of unreliable messages that were received by the , incremented + /// This is the number of unreliable messages that were received by the , incremented /// each time that LogUnreliableReceive is called by the Connection. Messages are counted before the receive event is invoked. /// public int UnreliableMessagesReceived @@ -237,7 +238,7 @@ public int UnreliableMessagesReceived /// The number of reliable messages received. /// /// - /// This is the number of reliable messages that were received by the , incremented + /// This is the number of reliable messages that were received by the , incremented /// each time that LogReliableReceive is called by the Connection. Messages are counted before the receive event is invoked. /// public int ReliableMessagesReceived @@ -257,7 +258,7 @@ public int ReliableMessagesReceived /// The number of fragmented messages received. /// /// - /// This is the number of fragmented messages that were received by the , incremented + /// This is the number of fragmented messages that were received by the , incremented /// each time that LogFragmentedReceive is called by the Connection. Messages are counted before the receive event is invoked. /// public int FragmentedMessagesReceived @@ -277,7 +278,7 @@ public int FragmentedMessagesReceived /// The number of acknowledgement messages received. /// /// - /// This is the number of acknowledgement messages that were received by the , incremented + /// This is the number of acknowledgement messages that were received by the , incremented /// each time that LogAcknowledgemntReceive is called by the Connection. Messages are counted before the receive event is invoked. /// public int AcknowledgementMessagesReceived @@ -297,7 +298,7 @@ public int AcknowledgementMessagesReceived /// The number of ping messages received. /// /// - /// This is the number of hello messages that were received by the , incremented + /// This is the number of hello messages that were received by the , incremented /// each time that LogHelloReceive is called by the Connection. Messages are counted before the receive event is invoked. /// public int PingMessagesReceived @@ -317,7 +318,7 @@ public int PingMessagesReceived /// The number of hello messages received. /// /// - /// This is the number of hello messages that were received by the , incremented + /// This is the number of hello messages that were received by the , incremented /// each time that LogHelloReceive is called by the Connection. Messages are counted before the receive event is invoked. /// public int HelloMessagesReceived @@ -338,12 +339,12 @@ public int HelloMessagesReceived /// /// /// - /// This is the number of bytes of data (i.e. user bytes) that were received by the , + /// This is the number of bytes of data (i.e. user bytes) that were received by the , /// accumulated each time that LogReceive is called by the Connection. Messages are counted before the receive /// event is invoked. /// /// - /// For the number of bytes including protocol bytes see . + /// For the number of bytes including protocol bytes see . /// /// public long DataBytesReceived @@ -364,12 +365,12 @@ public long DataBytesReceived /// /// /// - /// This is the total number of bytes (the data bytes plus protocol bytes) that were received by the - /// , accumulated each time that LogReceive is called by the Connection. Messages are + /// This is the total number of bytes (the data bytes plus protocol bytes) that were received by the + /// , accumulated each time that LogReceive is called by the Connection. Messages are /// counted before the receive event is invoked. /// /// - /// For the number of data bytes excluding protocol bytes see . + /// For the number of data bytes excluding protocol bytes see . /// /// public long TotalBytesReceived diff --git a/src/Impostor.Hazel/DataReceivedEventArgs.cs b/src/Impostor.Hazel/DataReceivedEventArgs.cs index 9176d8d93..d2259e58e 100644 --- a/src/Impostor.Hazel/DataReceivedEventArgs.cs +++ b/src/Impostor.Hazel/DataReceivedEventArgs.cs @@ -12,10 +12,10 @@ public struct DataReceivedEventArgs public readonly IMessageReader Message; /// - /// The the data was sent with. + /// The the data was sent with. /// public readonly MessageType Type; - + public DataReceivedEventArgs(Connection sender, IMessageReader msg, MessageType type) { this.Sender = sender; diff --git a/src/Impostor.Hazel/DisconnectedEventArgs.cs b/src/Impostor.Hazel/DisconnectedEventArgs.cs index d46df4b9c..4872aea97 100644 --- a/src/Impostor.Hazel/DisconnectedEventArgs.cs +++ b/src/Impostor.Hazel/DisconnectedEventArgs.cs @@ -6,13 +6,13 @@ namespace Impostor.Hazel public class DisconnectedEventArgs : EventArgs { /// - /// Optional disconnect reason. May be null. + /// Optional disconnect reason. May be null. /// public readonly string Reason; /// - /// Optional data sent with a disconnect message. May be null. - /// You must not recycle this. If you need the message outside of a callback, you should copy it. + /// Optional data sent with a disconnect message. May be null. + /// You must not recycle this. If you need the message outside of a callback, you should copy it. /// public readonly IMessageReader Message; diff --git a/src/Impostor.Hazel/HazelException.cs b/src/Impostor.Hazel/HazelException.cs index 8c6fc3c12..81c8017a8 100644 --- a/src/Impostor.Hazel/HazelException.cs +++ b/src/Impostor.Hazel/HazelException.cs @@ -8,14 +8,12 @@ namespace Impostor.Hazel [Serializable] public class HazelException : Exception { - internal HazelException(string msg) : base (msg) + internal HazelException(string msg) : base(msg) { - } - internal HazelException(string msg, Exception e) : base (msg, e) + internal HazelException(string msg, Exception e) : base(msg, e) { - } } } diff --git a/src/Impostor.Hazel/IPMode.cs b/src/Impostor.Hazel/IPMode.cs index 5eb6679e5..3f4395841 100644 --- a/src/Impostor.Hazel/IPMode.cs +++ b/src/Impostor.Hazel/IPMode.cs @@ -4,8 +4,8 @@ /// Represents the IP version that a connection or listener will use. /// /// - /// If you wand a client to connect or be able to connect using IPv6 then you should use , - /// this sets the underlying sockets to use IPv6 but still allow IPv4 sockets to connect for backwards compatability + /// If you wand a client to connect or be able to connect using IPv6 then you should use , + /// this sets the underlying sockets to use IPv6 but still allow IPv4 sockets to connect for backwards compatability /// and hence it is the default IPMode in most cases. /// public enum IPMode @@ -16,9 +16,9 @@ public enum IPMode IPv4, /// - /// Instruction to use IPv6 only, IPv4 connections will not be able to connect. IPv4 addresses can be connected + /// Instruction to use IPv6 only, IPv4 connections will not be able to connect. IPv4 addresses can be connected /// by converting to IPv6 addresses. /// - IPv6 + IPv6, } } diff --git a/src/Impostor.Hazel/IRecyclable.cs b/src/Impostor.Hazel/IRecyclable.cs index 69be1225b..0ddc04cd1 100644 --- a/src/Impostor.Hazel/IRecyclable.cs +++ b/src/Impostor.Hazel/IRecyclable.cs @@ -3,7 +3,7 @@ /// /// Interface for all items that can be returned to an object pool. /// - /// + /// public interface IRecyclable { /// diff --git a/src/Impostor.Hazel/MessageReader.cs b/src/Impostor.Hazel/MessageReader.cs index 317e45b1e..969e41b04 100644 --- a/src/Impostor.Hazel/MessageReader.cs +++ b/src/Impostor.Hazel/MessageReader.cs @@ -78,7 +78,7 @@ public IMessageReader ReadMessage() public bool ReadBoolean() { - byte val = FastByte(); + var val = FastByte(); return val != 0; } @@ -159,13 +159,13 @@ public int ReadPackedInt32() public uint ReadPackedUInt32() { - bool readMore = true; - int shift = 0; + var readMore = true; + var shift = 0; uint output = 0; while (readMore) { - byte b = FastByte(); + var b = FastByte(); if (b >= 0x80) { readMore = true; @@ -185,8 +185,8 @@ public uint ReadPackedUInt32() public void CopyTo(IMessageWriter writer) { - writer.Write((ushort) Length); - writer.Write((byte) Tag); + writer.Write((ushort)Length); + writer.Write((byte)Tag); writer.Write(Buffer.AsMemory(Offset, Length)); } @@ -213,7 +213,7 @@ public void RemoveMessage(IMessageReader message) System.Buffer.BlockCopy(Buffer, offsetEnd, Buffer, offsetStart, lengthToCopy); - ((MessageReader) message).Parent.AdjustLength(message.Offset, message.Length + 3); + ((MessageReader)message).Parent.AdjustLength(message.Offset, message.Length + 3); } private void AdjustLength(int offset, int amount) @@ -255,9 +255,9 @@ public T ReadNetObject(IGame game) where T : IInnerNetObject public Vector2 ReadVector2() { const float range = 50f; - - var x = ReadUInt16() / (float) ushort.MaxValue; - var y = ReadUInt16() / (float) ushort.MaxValue; + + var x = ReadUInt16() / (float)ushort.MaxValue; + var y = ReadUInt16() / (float)ushort.MaxValue; return new Vector2(Mathf.Lerp(-range, range, x), Mathf.Lerp(-range, range, y)); } diff --git a/src/Impostor.Hazel/MessageWriter.cs b/src/Impostor.Hazel/MessageWriter.cs index a7b57e78e..bb71a71b5 100644 --- a/src/Impostor.Hazel/MessageWriter.cs +++ b/src/Impostor.Hazel/MessageWriter.cs @@ -1,12 +1,11 @@ -using Impostor.Api.Games; -using Impostor.Api.Net.Messages; - -using System; +using System; using System.Collections.Generic; using System.Net; using System.Numerics; using System.Text; +using Impostor.Api.Games; using Impostor.Api.Net.Inner; +using Impostor.Api.Net.Messages; using Impostor.Api.Unity; namespace Impostor.Hazel @@ -39,7 +38,7 @@ public byte[] ToByteArray(bool includeHeader) { if (includeHeader) { - byte[] output = new byte[this.Length]; + var output = new byte[this.Length]; System.Buffer.BlockCopy(this.Buffer, 0, output, 0, this.Length); return output; } @@ -48,17 +47,17 @@ public byte[] ToByteArray(bool includeHeader) switch (this.SendOption) { case MessageType.Reliable: - { - byte[] output = new byte[this.Length - 3]; - System.Buffer.BlockCopy(this.Buffer, 3, output, 0, this.Length - 3); - return output; - } + { + var output = new byte[this.Length - 3]; + System.Buffer.BlockCopy(this.Buffer, 3, output, 0, this.Length - 3); + return output; + } case MessageType.Unreliable: - { - byte[] output = new byte[this.Length - 1]; - System.Buffer.BlockCopy(this.Buffer, 1, output, 0, this.Length - 1); - return output; - } + { + var output = new byte[this.Length - 1]; + System.Buffer.BlockCopy(this.Buffer, 1, output, 0, this.Length - 1); + return output; + } default: throw new ArgumentOutOfRangeException(); } @@ -67,7 +66,6 @@ public byte[] ToByteArray(bool includeHeader) throw new NotImplementedException(); } - /// /// The option specifying how the message should be sent. public static MessageWriter Get(MessageType sendOption = MessageType.Unreliable) { @@ -106,8 +104,8 @@ public void Write(IInnerNetObject innerNetObject) public void Write(Vector2 vector) { - Write((ushort)(Mathf.ReverseLerp(vector.X) * (double) ushort.MaxValue)); - Write((ushort)(Mathf.ReverseLerp(vector.Y) * (double) ushort.MaxValue)); + Write((ushort)(Mathf.ReverseLerp(vector.X) * (double)ushort.MaxValue)); + Write((ushort)(Mathf.ReverseLerp(vector.Y) * (double)ushort.MaxValue)); } /// @@ -122,7 +120,7 @@ public void StartMessage(byte typeFlag) public void EndMessage() { var lastMessageStart = messageStarts.Pop(); - ushort length = (ushort)(this.Position - lastMessageStart - 3); // Minus length and type byte + var length = (ushort)(this.Position - lastMessageStart - 3); // Minus length and type byte this.Buffer[lastMessageStart] = (byte)length; this.Buffer[lastMessageStart + 1] = (byte)(length >> 8); } @@ -215,7 +213,7 @@ public unsafe void Write(float value) { fixed (byte* ptr = &this.Buffer[this.Position]) { - byte* valuePtr = (byte*)&value; + var valuePtr = (byte*)&value; *ptr = *valuePtr; *(ptr + 1) = *(valuePtr + 1); @@ -302,7 +300,7 @@ public void WritePacked(uint value) { do { - byte b = (byte)(value & 0xFF); + var b = (byte)(value & 0xFF); if (value >= 0x80) { b |= 0x80; @@ -317,7 +315,7 @@ public void WritePacked(uint value) public void Write(MessageWriter msg, bool includeHeader) { - int offset = 0; + var offset = 0; if (!includeHeader) { switch (msg.SendOption) @@ -340,8 +338,8 @@ public unsafe static bool IsLittleEndian() byte b; unsafe { - int i = 1; - byte* bp = (byte*)&i; + var i = 1; + var bp = (byte*)&i; b = *bp; } diff --git a/src/Impostor.Hazel/NetworkConnection.cs b/src/Impostor.Hazel/NetworkConnection.cs index 9e81c5cc0..b530f017d 100644 --- a/src/Impostor.Hazel/NetworkConnection.cs +++ b/src/Impostor.Hazel/NetworkConnection.cs @@ -12,17 +12,17 @@ public enum HazelInternalErrors ReceivedZeroBytes, PingsWithoutResponse, ReliablePacketWithoutResponse, - ConnectionDisconnected + ConnectionDisconnected, } /// - /// Abstract base class for a to a remote end point via a network protocol like TCP or UDP. + /// Abstract base class for a to a remote end point via a network protocol like TCP or UDP. /// - /// + /// public abstract class NetworkConnection : Connection { /// - /// An event that gives us a chance to send well-formed disconnect messages to clients when an internal disconnect happens. + /// An event that gives us a chance to send well-formed disconnect messages to clients when an internal disconnect happens. /// public Func OnInternalDisconnect; @@ -30,8 +30,8 @@ public abstract class NetworkConnection : Connection /// The remote end point of this connection. /// /// - /// This is the end point of the other device given as an rather than a generic - /// as the base does. + /// This is the end point of the other device given as an rather than a generic + /// as the base does. /// public IPEndPoint RemoteEndPoint { get; protected set; } @@ -67,14 +67,14 @@ protected async ValueTask DisconnectRemote(string reason, IMessageReader reader) } /// - /// Called when socket is disconnected internally + /// Called when socket is disconnected internally /// internal async ValueTask DisconnectInternal(HazelInternalErrors error, string reason) { var handler = this.OnInternalDisconnect; if (handler != null) { - MessageWriter messageToRemote = handler(error); + var messageToRemote = handler(error); if (messageToRemote != null) { try diff --git a/src/Impostor.Hazel/NetworkConnectionListener.cs b/src/Impostor.Hazel/NetworkConnectionListener.cs index e1d7ffaf8..e2824b1c9 100644 --- a/src/Impostor.Hazel/NetworkConnectionListener.cs +++ b/src/Impostor.Hazel/NetworkConnectionListener.cs @@ -3,9 +3,9 @@ namespace Impostor.Hazel { /// - /// Abstract base class for a for network based connections. + /// Abstract base class for a for network based connections. /// - /// + /// public abstract class NetworkConnectionListener : ConnectionListener { /// diff --git a/src/Impostor.Hazel/NewConnectionEventArgs.cs b/src/Impostor.Hazel/NewConnectionEventArgs.cs index be9e7a214..77ec05de2 100644 --- a/src/Impostor.Hazel/NewConnectionEventArgs.cs +++ b/src/Impostor.Hazel/NewConnectionEventArgs.cs @@ -5,13 +5,13 @@ namespace Impostor.Hazel public struct NewConnectionEventArgs { /// - /// The data received from the client in the handshake. - /// This data is yours. Remember to recycle it. + /// The data received from the client in the handshake. + /// This data is yours. Remember to recycle it. /// public readonly IMessageReader HandshakeData; /// - /// The to the new client. + /// The to the new client. /// public readonly Connection Connection; diff --git a/src/Impostor.Hazel/ObjectPoolCustom.cs b/src/Impostor.Hazel/ObjectPoolCustom.cs index 5c9ef9b40..f1256eb61 100644 --- a/src/Impostor.Hazel/ObjectPoolCustom.cs +++ b/src/Impostor.Hazel/ObjectPoolCustom.cs @@ -8,7 +8,7 @@ namespace Impostor.Hazel /// A fairly simple object pool for items that will be created a lot. /// /// The type that is pooled. - /// + /// public sealed class ObjectPoolCustom where T : IRecyclable { private int numberCreated; @@ -32,7 +32,7 @@ public sealed class ObjectPoolCustom where T : IRecyclable /// /// private readonly Func objectFactory; - + /// /// Internal constructor for our ObjectPool. /// @@ -48,7 +48,7 @@ internal ObjectPoolCustom(Func objectFactory) internal T GetObject() { #if HAZEL_BAG - if (!pool.TryTake(out T item)) + if (!pool.TryTake(out var item)) { Interlocked.Increment(ref numberCreated); item = objectFactory.Invoke(); @@ -85,7 +85,7 @@ internal T GetObject() /// The item to return. internal void PutObject(T item) { - if (inuse.TryRemove(item, out bool b)) + if (inuse.TryRemove(item, out var b)) { #if HAZEL_BAG pool.Add(item); diff --git a/src/Impostor.Hazel/Udp/SendOptionInternal.cs b/src/Impostor.Hazel/Udp/SendOptionInternal.cs index c0c4e2127..11baa854f 100644 --- a/src/Impostor.Hazel/Udp/SendOptionInternal.cs +++ b/src/Impostor.Hazel/Udp/SendOptionInternal.cs @@ -11,7 +11,7 @@ public enum UdpSendOption : byte Hello = 8, /// - /// A single byte of continued existence + /// A single byte of continued existence /// Ping = 12, diff --git a/src/Impostor.Hazel/Udp/UdpBroadcastListener.cs b/src/Impostor.Hazel/Udp/UdpBroadcastListener.cs index ed7b68dbd..3c768efc3 100644 --- a/src/Impostor.Hazel/Udp/UdpBroadcastListener.cs +++ b/src/Impostor.Hazel/Udp/UdpBroadcastListener.cs @@ -89,21 +89,21 @@ private void HandleData(IAsyncResult result) return; } - if (numBytes < 3 + if (numBytes < 3 || buffer[0] != 4 || buffer[1] != 2) { this.StartListen(); return; } - IPEndPoint ipEnd = (IPEndPoint)endpt; - string data = UTF8Encoding.UTF8.GetString(buffer, 2, numBytes - 2); - int dataHash = data.GetHashCode(); + var ipEnd = (IPEndPoint)endpt; + var data = UTF8Encoding.UTF8.GetString(buffer, 2, numBytes - 2); + var dataHash = data.GetHashCode(); lock (packets) { - bool found = false; - for (int i = 0; i < this.packets.Count; ++i) + var found = false; + for (var i = 0; i < this.packets.Count; ++i) { var pkt = this.packets[i]; if (pkt == null || pkt.Data == null) @@ -146,11 +146,17 @@ public void Dispose() { if (this.socket != null) { - try { this.socket.Shutdown(SocketShutdown.Both); } catch { } - try { this.socket.Close(); } catch { } - try { this.socket.Dispose(); } catch { } + try { this.socket.Shutdown(SocketShutdown.Both); } + catch { } + + try { this.socket.Close(); } + catch { } + + try { this.socket.Dispose(); } + catch { } + this.socket = null; } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Hazel/Udp/UdpBroadcaster.cs b/src/Impostor.Hazel/Udp/UdpBroadcaster.cs index 5fa1ccac2..32f0e187a 100644 --- a/src/Impostor.Hazel/Udp/UdpBroadcaster.cs +++ b/src/Impostor.Hazel/Udp/UdpBroadcaster.cs @@ -26,7 +26,7 @@ public UdpBroadcaster(int port, Action logger = null) /// public void SetData(string data) { - int len = UTF8Encoding.UTF8.GetByteCount(data); + var len = UTF8Encoding.UTF8.GetByteCount(data); this.data = new byte[len + 2]; this.data[0] = 4; this.data[1] = 2; @@ -69,11 +69,17 @@ public void Dispose() { if (this.socket != null) { - try { this.socket.Shutdown(SocketShutdown.Both); } catch { } - try { this.socket.Close(); } catch { } - try { this.socket.Dispose(); } catch { } + try { this.socket.Shutdown(SocketShutdown.Both); } + catch { } + + try { this.socket.Close(); } + catch { } + + try { this.socket.Dispose(); } + catch { } + this.socket = null; } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Hazel/Udp/UdpClientConnection.cs b/src/Impostor.Hazel/Udp/UdpClientConnection.cs index 5125ebe80..cb27e2400 100644 --- a/src/Impostor.Hazel/Udp/UdpClientConnection.cs +++ b/src/Impostor.Hazel/Udp/UdpClientConnection.cs @@ -1,9 +1,7 @@ using System; -using System.Buffers; using System.Net; using System.Net.Sockets; using System.Threading; -using System.Threading.Channels; using System.Threading.Tasks; using Impostor.Api.Net.Messages; using Microsoft.Extensions.ObjectPool; @@ -14,7 +12,7 @@ namespace Impostor.Hazel.Udp /// /// Represents a client's connection to a server that uses the UDP protocol. /// - /// + /// public sealed class UdpClientConnection : UdpConnection { private static readonly ILogger Logger = Log.ForContext(); @@ -31,7 +29,7 @@ public sealed class UdpClientConnection : UdpConnection /// /// Creates a new UdpClientConnection. /// - /// A to connect to. + /// A to connect to. public UdpClientConnection(IPEndPoint remoteEndPoint, ObjectPool readerPool, IPMode ipMode = IPMode.IPv4) : base(null, readerPool) { EndPoint = remoteEndPoint; @@ -40,7 +38,7 @@ public UdpClientConnection(IPEndPoint remoteEndPoint, ObjectPool _socket = new UdpClient { - DontFragment = false + DontFragment = false, }; _reliablePacketTimer = new Timer(ManageReliablePacketsInternal, null, 100, Timeout.Infinite); @@ -213,8 +211,11 @@ protected override void Dispose(bool disposing) { State = ConnectionState.NotConnected; - try { _socket.Close(); } catch { } - try { _socket.Dispose(); } catch { } + try { _socket.Close(); } + catch { } + + try { _socket.Dispose(); } + catch { } _reliablePacketTimer.Dispose(); _connectWaitLock.Dispose(); diff --git a/src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs b/src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs index a73291bc4..e8303a4e7 100644 --- a/src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs +++ b/src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs @@ -8,7 +8,6 @@ namespace Impostor.Hazel.Udp { partial class UdpConnection { - /// /// Class to hold packet data /// @@ -58,6 +57,7 @@ public int KeepAliveInterval ResetKeepAliveTimer(); } } + private int keepAliveInterval = 1500; public int MissingPingsUntilDisconnect { get; set; } = 6; @@ -109,9 +109,9 @@ private async void HandleKeepAlive(object state) // pings should cause a disconnect. private async ValueTask SendPing() { - ushort id = (ushort)Interlocked.Increment(ref lastIDAllocated); + var id = (ushort)Interlocked.Increment(ref lastIDAllocated); - byte[] bytes = new byte[3]; + var bytes = new byte[3]; bytes[0] = (byte)UdpSendOption.Ping; bytes[1] = (byte)(id >> 8); bytes[2] = (byte)id; @@ -164,4 +164,4 @@ private void DisposeKeepAliveTimer() } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs b/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs index 7f439269d..9c13f22df 100644 --- a/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs +++ b/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs @@ -15,25 +15,25 @@ partial class UdpConnection /// /// /// - /// For reliable delivery data is resent at specified intervals unless an acknowledgement is received from the + /// For reliable delivery data is resent at specified intervals unless an acknowledgement is received from the /// receiving device. The ResendTimeout specifies the interval between the packets being resent, each time a packet - /// is resent the interval is increased for that packet until the duration exceeds the value. + /// is resent the interval is increased for that packet until the duration exceeds the value. /// /// - /// Setting this to its default of 0 will mean the timeout is 2 times the value of the average ping, usually + /// Setting this to its default of 0 will mean the timeout is 2 times the value of the average ping, usually /// resulting in a more dynamic resend that responds to endpoints on slower or faster connections. /// /// public volatile int ResendTimeout = 0; /// - /// Max number of times to resend. 0 == no limit + /// Max number of times to resend. 0 == no limit /// public volatile int ResendLimit = 0; /// - /// A compounding multiplier to back off resend timeout. - /// Applied to ping before first timeout when ResendTimeout == 0. + /// A compounding multiplier to back off resend timeout. + /// Applied to ping before first timeout when ResendTimeout == 0. /// public volatile float ResendPingMultiplier = 2; @@ -48,7 +48,7 @@ partial class UdpConnection internal ConcurrentDictionary reliableDataPacketsSent = new ConcurrentDictionary(); /// - /// Packet ids that have not been received, but are expected. + /// Packet ids that have not been received, but are expected. /// private HashSet reliableDataPacketsMissing = new HashSet(); @@ -63,7 +63,7 @@ partial class UdpConnection /// Returns the average ping to this endpoint. /// /// - /// This returns the average ping for a one-way trip as calculated from the reliable packets that have been sent + /// This returns the average ping for a one-way trip as calculated from the reliable packets that have been sent /// and acknowledged by the endpoint. /// public float AveragePingMs = 500; @@ -72,7 +72,7 @@ partial class UdpConnection /// The maximum times a message should be resent before marking the endpoint as disconnected. /// /// - /// Reliable packets will be resent at an interval defined in for the number of times + /// Reliable packets will be resent at an interval defined in for the number of times /// specified here. Once a packet has been retransmitted this number of times and has not been acknowledged the /// connection will be marked as disconnected and the Disconnected event /// will be invoked. @@ -136,10 +136,10 @@ public async ValueTask Resend() var connection = this.Connection; if (!this.Acknowledged && connection != null) { - long lifetime = this.Stopwatch.ElapsedMilliseconds; + var lifetime = this.Stopwatch.ElapsedMilliseconds; if (lifetime >= connection.DisconnectTimeout) { - if (connection.reliableDataPacketsSent.TryRemove(this.Id, out Packet self)) + if (connection.reliableDataPacketsSent.TryRemove(this.Id, out var self)) { await connection.DisconnectInternal(HazelInternalErrors.ReliablePacketWithoutResponse, $"Reliable packet {self.Id} (size={this.Length}) was not ack'd after {lifetime}ms ({self.Retransmissions} resends)"); @@ -155,7 +155,7 @@ public async ValueTask Resend() if (connection.ResendLimit != 0 && this.Retransmissions > connection.ResendLimit) { - if (connection.reliableDataPacketsSent.TryRemove(this.Id, out Packet self)) + if (connection.reliableDataPacketsSent.TryRemove(this.Id, out var self)) { await connection.DisconnectInternal(HazelInternalErrors.ReliablePacketWithoutResponse, $"Reliable packet {self.Id} (size={this.Length}) was not ack'd after {self.Retransmissions} resends ({lifetime}ms)"); @@ -196,12 +196,12 @@ public void Recycle() internal async ValueTask ManageReliablePackets() { - int output = 0; + var output = 0; if (this.reliableDataPacketsSent.Count > 0) { foreach (var kvp in this.reliableDataPacketsSent) { - Packet pkt = kvp.Value; + var pkt = kvp.Value; try { @@ -222,12 +222,12 @@ internal async ValueTask ManageReliablePackets() /// The callback to make once the packet has been acknowledged. protected void AttachReliableID(byte[] buffer, int offset, int sendLength, Action ackCallback = null) { - ushort id = (ushort)Interlocked.Increment(ref lastIDAllocated); + var id = (ushort)Interlocked.Increment(ref lastIDAllocated); buffer[offset] = (byte)(id >> 8); buffer[offset + 1] = (byte)id; - Packet packet = Packet.GetObject(); + var packet = Packet.GetObject(); packet.Set( id, this, @@ -260,7 +260,7 @@ private async ValueTask ReliableSend(byte sendOption, byte[] data, Action ackCal //Inform keepalive not to send for a while ResetKeepAliveTimer(); - byte[] bytes = new byte[data.Length + 3]; + var bytes = new byte[data.Length + 3]; //Add message type bytes[0] = sendOption; @@ -333,35 +333,35 @@ private async ValueTask ProcessReliableReceive(ReadOnlyMemory bytes, * * So... */ - + var result = true; lock (reliableDataPacketsMissing) { //Calculate overwritePointer - ushort overwritePointer = (ushort)(reliableReceiveLast - 32768); + var overwritePointer = (ushort)(reliableReceiveLast - 32768); //Calculate if it is a new packet by examining if it is within the range bool isNew; if (overwritePointer < reliableReceiveLast) - isNew = id > reliableReceiveLast || id <= overwritePointer; //Figure (2) + isNew = id > reliableReceiveLast || id <= overwritePointer; //Figure (2) else - isNew = id > reliableReceiveLast && id <= overwritePointer; //Figure (3) - + isNew = id > reliableReceiveLast && id <= overwritePointer; //Figure (3) + //If it's new or we've not received anything yet if (isNew) { // Mark items between the most recent receive and the id received as missing if (id > reliableReceiveLast) { - for (ushort i = (ushort)(reliableReceiveLast + 1); i < id; i++) + for (var i = (ushort)(reliableReceiveLast + 1); i < id; i++) { reliableDataPacketsMissing.Add(i); } } else { - int cnt = (ushort.MaxValue - reliableReceiveLast) + id; + var cnt = (ushort.MaxValue - reliableReceiveLast) + id; for (ushort i = 1; i < cnt; ++i) { reliableDataPacketsMissing.Add((ushort)(i + reliableReceiveLast)); @@ -371,7 +371,7 @@ private async ValueTask ProcessReliableReceive(ReadOnlyMemory bytes, //Update the most recently received reliableReceiveLast = id; } - + //Else it could be a missing packet else { @@ -382,7 +382,7 @@ private async ValueTask ProcessReliableReceive(ReadOnlyMemory bytes, } } } - + //Send an acknowledgement await SendAck(id); @@ -397,13 +397,13 @@ private void AcknowledgementMessageReceive(ReadOnlySpan bytes) { this.pingsSinceAck = 0; - ushort id = (ushort)((bytes[1] << 8) + bytes[2]); + var id = (ushort)((bytes[1] << 8) + bytes[2]); AcknowledgeMessageId(id); if (bytes.Length == 4) { - byte recentPackets = bytes[3]; - for (int i = 1; i <= 8; ++i) + var recentPackets = bytes[3]; + for (var i = 1; i <= 8; ++i) { if ((recentPackets & 1) != 0) { @@ -420,7 +420,7 @@ private void AcknowledgementMessageReceive(ReadOnlySpan bytes) private void AcknowledgeMessageId(ushort id) { // Dispose of timer and remove from dictionary - if (reliableDataPacketsSent.TryRemove(id, out Packet packet)) + if (reliableDataPacketsSent.TryRemove(id, out var packet)) { float rt = packet.Stopwatch.ElapsedMilliseconds; @@ -432,7 +432,7 @@ private void AcknowledgeMessageId(ushort id) this.AveragePingMs = Math.Max(50, this.AveragePingMs * .7f + rt * .3f); } } - else if (this.activePingPackets.TryRemove(id, out PingPacket pingPkt)) + else if (this.activePingPackets.TryRemove(id, out var pingPkt)) { float rt = pingPkt.Stopwatch.ElapsedMilliseconds; @@ -455,7 +455,7 @@ private async ValueTask SendAck(ushort id) byte recentPackets = 0; lock (this.reliableDataPacketsMissing) { - for (int i = 1; i <= 8; ++i) + for (var i = 1; i <= 8; ++i) { if (!this.reliableDataPacketsMissing.Contains((ushort)(id - i))) { @@ -464,12 +464,12 @@ private async ValueTask SendAck(ushort id) } } - byte[] bytes = new byte[] + var bytes = new byte[] { (byte)UdpSendOption.Acknowledgement, (byte)(id >> 8), (byte)(id >> 0), - recentPackets + recentPackets, }; try diff --git a/src/Impostor.Hazel/Udp/UdpConnection.cs b/src/Impostor.Hazel/Udp/UdpConnection.cs index 5288d3ce2..4106bfe14 100644 --- a/src/Impostor.Hazel/Udp/UdpConnection.cs +++ b/src/Impostor.Hazel/Udp/UdpConnection.cs @@ -34,7 +34,7 @@ protected UdpConnection(ConnectionListener listener, ObjectPool r Pipeline = Channel.CreateUnbounded(new UnboundedChannelOptions { SingleReader = true, - SingleWriter = true + SingleWriter = true, }); } @@ -113,13 +113,13 @@ private async Task ReadAsync() /// protected abstract ValueTask WriteBytesToConnection(byte[] bytes, int length); - /// + /// public override async ValueTask SendAsync(IMessageWriter msg) { if (this._state != ConnectionState.Connected) throw new InvalidOperationException("Could not send data as this Connection is not connected. Did you disconnect?"); - byte[] buffer = new byte[msg.Length]; + var buffer = new byte[msg.Length]; Buffer.BlockCopy(msg.Buffer, 0, buffer, 0, msg.Length); switch (msg.SendOption) @@ -139,13 +139,13 @@ public override async ValueTask SendAsync(IMessageWriter msg) } } - /// + /// /// /// /// - /// Udp connections can currently send messages using and - /// . Fragmented messages are not currently supported and will default to - /// until implemented. + /// Udp connections can currently send messages using and + /// . Fragmented messages are not currently supported and will default to + /// until implemented. /// /// public override async ValueTask SendBytes(byte[] bytes, MessageType sendOption = MessageType.Unreliable) @@ -153,12 +153,12 @@ public override async ValueTask SendBytes(byte[] bytes, MessageType sendOption = //Add header information and send await HandleSend(bytes, (byte)sendOption); } - + /// /// Handles the reliable/fragmented sending from this connection. /// /// The data being sent. - /// The specified as its byte value. + /// The specified as its byte value. /// The callback to invoke when this packet is acknowledged. /// The bytes that should actually be sent. protected async ValueTask HandleSend(byte[] data, byte sendOption, Action ackCallback = null) @@ -170,7 +170,7 @@ protected async ValueTask HandleSend(byte[] data, byte sendOption, Action ackCal case (byte)UdpSendOption.Hello: await ReliableSend(sendOption, data, ackCallback); break; - + //Treat all else as unreliable default: await UnreliableSend(sendOption, data); @@ -226,14 +226,16 @@ protected async ValueTask HandleReceive(MessageReader message) { await DisconnectRemote("The remote sent a disconnect request", reader); } + break; - + //Treat everything else as unreliable default: using (var reader = message.Copy(1)) { await InvokeDataReceived(reader, MessageType.Unreliable); } + Statistics.LogUnreliableReceive(message.Length - 1, message.Length); break; } @@ -258,7 +260,7 @@ ValueTask UnreliableSend(byte sendOption, byte[] data) /// async ValueTask UnreliableSend(byte sendOption, byte[] data, int offset, int length) { - byte[] bytes = new byte[length + 1]; + var bytes = new byte[length + 1]; //Add message type bytes[0] = sendOption; @@ -293,8 +295,8 @@ protected ValueTask SendHello(byte[] bytes, Action acknowledgeCallback) return HandleSend(actualBytes, (byte)UdpSendOption.Hello, acknowledgeCallback); } - - /// + + /// protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/Impostor.Hazel/Udp/UdpConnectionListener.cs b/src/Impostor.Hazel/Udp/UdpConnectionListener.cs index 573a00cbf..782bf6137 100644 --- a/src/Impostor.Hazel/Udp/UdpConnectionListener.cs +++ b/src/Impostor.Hazel/Udp/UdpConnectionListener.cs @@ -4,7 +4,6 @@ using System.Net; using System.Net.Sockets; using System.Threading; -using System.Threading.Channels; using System.Threading.Tasks; using Microsoft.Extensions.ObjectPool; using Serilog; @@ -20,11 +19,12 @@ public class UdpConnectionListener : NetworkConnectionListener private static readonly ILogger Logger = Log.ForContext(); /// - /// A callback for early connection rejection. - /// * Return false to reject connection. - /// * A null response is ok, we just won't send anything. + /// A callback for early connection rejection. + /// * Return false to reject connection. + /// * A null response is ok, we just won't send anything. /// public AcceptConnectionCheck AcceptConnection; + public delegate bool AcceptConnectionCheck(IPEndPoint endPoint, byte[] input, out byte[] response); private readonly UdpClient _socket; @@ -37,7 +37,7 @@ public class UdpConnectionListener : NetworkConnectionListener private Task _executingTask; /// - /// Creates a new UdpConnectionListener for the given , port and . + /// Creates a new UdpConnectionListener for the given , port and . /// /// The endpoint to listen on. /// @@ -72,7 +72,7 @@ public UdpConnectionListener(IPEndPoint endPoint, ObjectPool read } public int ConnectionCount => this._allConnections.Count; - + private async void ManageReliablePackets(object state) { foreach (var kvp in _allConnections) diff --git a/src/Impostor.Hazel/Udp/UdpConnectionRateLimit.cs b/src/Impostor.Hazel/Udp/UdpConnectionRateLimit.cs index 64881d3da..b90d7b15f 100644 --- a/src/Impostor.Hazel/Udp/UdpConnectionRateLimit.cs +++ b/src/Impostor.Hazel/Udp/UdpConnectionRateLimit.cs @@ -72,4 +72,4 @@ public void Dispose() _timer.Dispose(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Hazel/Udp/UdpServerConnection.cs b/src/Impostor.Hazel/Udp/UdpServerConnection.cs index 8d3426e38..8c6cc067a 100644 --- a/src/Impostor.Hazel/Udp/UdpServerConnection.cs +++ b/src/Impostor.Hazel/Udp/UdpServerConnection.cs @@ -9,14 +9,14 @@ namespace Impostor.Hazel.Udp /// /// Represents a servers's connection to a client that uses the UDP protocol. /// - /// + /// internal sealed class UdpServerConnection : UdpConnection { /// /// The connection listener that we use the socket of. /// /// - /// Udp server connections utilize the same socket in the listener for sends/receives, this is the listener that + /// Udp server connections utilize the same socket in the listener for sends/receives, this is the listener that /// created this connection and is hence the listener this conenction sends and receives via. /// public UdpConnectionListener Listener { get; private set; } @@ -63,7 +63,7 @@ protected override async ValueTask SendDisconnect(MessageWriter data = nul if (this._state != ConnectionState.Connected) return false; this._state = ConnectionState.NotConnected; } - + var bytes = EmptyDisconnectBytes; if (data != null && data.Length > 0) { diff --git a/src/Impostor.Patcher/Impostor.Patcher.Cli/Program.cs b/src/Impostor.Patcher/Impostor.Patcher.Cli/Program.cs index 76653a1b5..26c00d9cc 100644 --- a/src/Impostor.Patcher/Impostor.Patcher.Cli/Program.cs +++ b/src/Impostor.Patcher/Impostor.Patcher.Cli/Program.cs @@ -23,7 +23,7 @@ internal static Task Main(string[] args) "--name", () => AmongUsModifier.DefaultRegionName, "Name for server region" - ) + ), }; rootCommand.Handler = CommandHandler.Create((address, name) => diff --git a/src/Impostor.Patcher/Impostor.Patcher.Shared/AmongUsModifier.cs b/src/Impostor.Patcher/Impostor.Patcher.Shared/AmongUsModifier.cs index 7c1ced263..d3b6de7e5 100644 --- a/src/Impostor.Patcher/Impostor.Patcher.Shared/AmongUsModifier.cs +++ b/src/Impostor.Patcher/Impostor.Patcher.Shared/AmongUsModifier.cs @@ -63,7 +63,7 @@ private string FindProtonAppData() var libraries = new List { - steamApps + steamApps, }; var vdf = Path.Combine(steamApps, "libraryfolders.vdf"); @@ -174,7 +174,7 @@ private bool WriteIp(IPAddress ipAddress, ushort port) var ip = ipAddress.ToString(); var region = new RegionInfo(RegionName, ip, new[] { - new ServerInfo($"{RegionName}-Master-1", ip, port) + new ServerInfo($"{RegionName}-Master-1", ip, port), }); region.Serialize(writer); @@ -246,4 +246,4 @@ private void OnSaved(string ipAddress, ushort port) public event EventHandler Error; public event EventHandler Saved; } -} \ No newline at end of file +} diff --git a/src/Impostor.Patcher/Impostor.Patcher.Shared/Configuration.cs b/src/Impostor.Patcher/Impostor.Patcher.Shared/Configuration.cs index b256156cd..56bf29743 100644 --- a/src/Impostor.Patcher/Impostor.Patcher.Shared/Configuration.cs +++ b/src/Impostor.Patcher/Impostor.Patcher.Shared/Configuration.cs @@ -62,4 +62,4 @@ public void AddIp(string ip) } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Patcher/Impostor.Patcher.Shared/Events/ErrorEventArgs.cs b/src/Impostor.Patcher/Impostor.Patcher.Shared/Events/ErrorEventArgs.cs index 7211d5d35..b7925d3d1 100644 --- a/src/Impostor.Patcher/Impostor.Patcher.Shared/Events/ErrorEventArgs.cs +++ b/src/Impostor.Patcher/Impostor.Patcher.Shared/Events/ErrorEventArgs.cs @@ -11,4 +11,4 @@ public ErrorEventArgs(string message) public string Message { get; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Patcher/Impostor.Patcher.Shared/Events/SavedEventArgs.cs b/src/Impostor.Patcher/Impostor.Patcher.Shared/Events/SavedEventArgs.cs index c91d07197..a0f08ae47 100644 --- a/src/Impostor.Patcher/Impostor.Patcher.Shared/Events/SavedEventArgs.cs +++ b/src/Impostor.Patcher/Impostor.Patcher.Shared/Events/SavedEventArgs.cs @@ -13,4 +13,4 @@ public SavedEventArgs(string ipAddress, ushort port) public string IpAddress { get; } public ushort Port { get; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Patcher/Impostor.Patcher.Shared/Innersloth/RegionInfo.cs b/src/Impostor.Patcher/Impostor.Patcher.Shared/Innersloth/RegionInfo.cs index 01b74d1d8..77fbb6be0 100644 --- a/src/Impostor.Patcher/Impostor.Patcher.Shared/Innersloth/RegionInfo.cs +++ b/src/Impostor.Patcher/Impostor.Patcher.Shared/Innersloth/RegionInfo.cs @@ -45,4 +45,4 @@ public static RegionInfo Deserialize(BinaryReader reader) return new RegionInfo(name, ping, servers); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Patcher/Impostor.Patcher.Shared/Innersloth/ServerInfo.cs b/src/Impostor.Patcher/Impostor.Patcher.Shared/Innersloth/ServerInfo.cs index 7203c8489..4768377a3 100644 --- a/src/Impostor.Patcher/Impostor.Patcher.Shared/Innersloth/ServerInfo.cs +++ b/src/Impostor.Patcher/Impostor.Patcher.Shared/Innersloth/ServerInfo.cs @@ -15,7 +15,7 @@ public ServerInfo(string name, string ip, ushort port) Ip = ip; Port = port; } - + public void Serialize(BinaryWriter writer) { writer.Write(Name); @@ -30,8 +30,8 @@ public static ServerInfo Deserialize(BinaryReader reader) var ip = new IPAddress(reader.ReadBytes(4)).ToString(); var port = reader.ReadUInt16(); var unknown = reader.ReadInt32(); - + return new ServerInfo(name, ip, port); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Patcher/Impostor.Patcher.WinForms/Forms/FrmMain.Designer.cs b/src/Impostor.Patcher/Impostor.Patcher.WinForms/Forms/FrmMain.Designer.cs index 0f6320b4f..4667c454f 100644 --- a/src/Impostor.Patcher/Impostor.Patcher.WinForms/Forms/FrmMain.Designer.cs +++ b/src/Impostor.Patcher/Impostor.Patcher.WinForms/Forms/FrmMain.Designer.cs @@ -81,7 +81,7 @@ private void InitializeComponent() this.lblUrl.Name = "lblUrl"; this.lblUrl.Size = new System.Drawing.Size(212, 13); this.lblUrl.TabIndex = 5; - this.lblUrl.Text = "https://github.com/AeonLucid/Impostor"; + this.lblUrl.Text = "https://github.com/Impostor/Impostor"; this.lblUrl.Click += new System.EventHandler(this.lblUrl_Click); // // label3 @@ -138,4 +138,4 @@ private void InitializeComponent() private System.Windows.Forms.Label label3; private System.Windows.Forms.ComboBox comboIp; } -} \ No newline at end of file +} diff --git a/src/Impostor.Patcher/Impostor.Patcher.WinForms/Forms/FrmMain.cs b/src/Impostor.Patcher/Impostor.Patcher.WinForms/Forms/FrmMain.cs index 5c06669e0..dd3696f5a 100644 --- a/src/Impostor.Patcher/Impostor.Patcher.WinForms/Forms/FrmMain.cs +++ b/src/Impostor.Patcher/Impostor.Patcher.WinForms/Forms/FrmMain.cs @@ -95,7 +95,7 @@ private async void buttonLaunch_Click(object sender, EventArgs e) private void lblUrl_Click(object sender, EventArgs e) { - Process.Start("https://github.com/AeonLucid/Impostor"); + Process.Start("https://github.com/Impostor/Impostor"); } private void RefreshComboIps() @@ -111,4 +111,4 @@ private void RefreshComboIps() } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Patcher/Impostor.Patcher.WinForms/Program.cs b/src/Impostor.Patcher/Impostor.Patcher.WinForms/Program.cs index 7ca903533..f48149064 100644 --- a/src/Impostor.Patcher/Impostor.Patcher.WinForms/Program.cs +++ b/src/Impostor.Patcher/Impostor.Patcher.WinForms/Program.cs @@ -14,4 +14,4 @@ private static void Main() Application.Run(new FrmMain()); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Plugins.Debugger/DebugPlugin.cs b/src/Impostor.Plugins.Debugger/DebugPlugin.cs index 8f57e89e0..a978619bb 100644 --- a/src/Impostor.Plugins.Debugger/DebugPlugin.cs +++ b/src/Impostor.Plugins.Debugger/DebugPlugin.cs @@ -10,4 +10,4 @@ namespace Impostor.Plugins.Debugger public class DebugPlugin : PluginBase { } -} \ No newline at end of file +} diff --git a/src/Impostor.Plugins.Debugger/DebugPluginStartup.cs b/src/Impostor.Plugins.Debugger/DebugPluginStartup.cs index cc36ce661..c39ce314a 100644 --- a/src/Impostor.Plugins.Debugger/DebugPluginStartup.cs +++ b/src/Impostor.Plugins.Debugger/DebugPluginStartup.cs @@ -32,4 +32,4 @@ public void ConfigureHost(IHostBuilder host) }); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Plugins.Example/ExamplePlugin.cs b/src/Impostor.Plugins.Example/ExamplePlugin.cs index 139e42c04..73fea6ad6 100644 --- a/src/Impostor.Plugins.Example/ExamplePlugin.cs +++ b/src/Impostor.Plugins.Example/ExamplePlugin.cs @@ -29,7 +29,7 @@ public override async ValueTask EnableAsync() var game = await _gameManager.CreateAsync(new GameOptionsData()); game.DisplayName = "Example game"; await game.SetPrivacyAsync(true); - + _logger.LogInformation("Created game {0}.", game.Code.Code); } diff --git a/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs b/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs index 0190d3b14..c62433c64 100644 --- a/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs +++ b/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs @@ -94,7 +94,7 @@ public async ValueTask OnPlayerChat(IPlayerChatEvent e) [EventListener] public void OnPlayerStartMeetingEvent(IPlayerStartMeetingEvent e) { - _logger.LogDebug($"Player {e.PlayerControl.PlayerInfo.PlayerName} start meeting, reason: " + (e.Body==null ? "Emergency call button" : "Found the body of the player "+e.Body.PlayerInfo.PlayerName)); + _logger.LogDebug($"Player {e.PlayerControl.PlayerInfo.PlayerName} start meeting, reason: " + (e.Body == null ? "Emergency call button" : "Found the body of the player " + e.Body.PlayerInfo.PlayerName)); } } } diff --git a/src/Impostor.Server/Config/DisconnectMessages.cs b/src/Impostor.Server/Config/DisconnectMessages.cs index a86735f8f..6bf8e7286 100644 --- a/src/Impostor.Server/Config/DisconnectMessages.cs +++ b/src/Impostor.Server/Config/DisconnectMessages.cs @@ -16,4 +16,4 @@ public static class DisconnectMessages public const string UsernameIllegalCharacters = "Your username contains illegal characters, please remove them."; } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Constants.cs b/src/Impostor.Server/Constants.cs index 62d90b290..ce0114aac 100644 --- a/src/Impostor.Server/Constants.cs +++ b/src/Impostor.Server/Constants.cs @@ -5,4 +5,4 @@ internal static class Constants public const int SpawnTimeout = 2500; public const int ConnectionTimeout = 2500; } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Events/MultiDisposable.cs b/src/Impostor.Server/Events/MultiDisposable.cs index b68f06401..b1e2348b0 100644 --- a/src/Impostor.Server/Events/MultiDisposable.cs +++ b/src/Impostor.Server/Events/MultiDisposable.cs @@ -4,7 +4,7 @@ namespace Impostor.Server.Events { /// - /// Disposes multiple . + /// Disposes multiple . /// internal class MultiDisposable : IDisposable { diff --git a/src/Impostor.Server/Events/Register/RegisteredEventListener.cs b/src/Impostor.Server/Events/Register/RegisteredEventListener.cs index 6517aac8e..76d2a2af0 100644 --- a/src/Impostor.Server/Events/Register/RegisteredEventListener.cs +++ b/src/Impostor.Server/Events/Register/RegisteredEventListener.cs @@ -159,7 +159,7 @@ public ValueTask InvokeAsync(object? eventHandler, object @event, IServiceProvid 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(); } } diff --git a/src/Impostor.Server/Events/Register/TemporaryEventRegister.cs b/src/Impostor.Server/Events/Register/TemporaryEventRegister.cs index 1446ad1eb..f2bfee254 100644 --- a/src/Impostor.Server/Events/Register/TemporaryEventRegister.cs +++ b/src/Impostor.Server/Events/Register/TemporaryEventRegister.cs @@ -56,4 +56,4 @@ public void Dispose() } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Extensions/NodeLocatorExtensions.cs b/src/Impostor.Server/Extensions/NodeLocatorExtensions.cs index 370bca620..96ceb4d4e 100644 --- a/src/Impostor.Server/Extensions/NodeLocatorExtensions.cs +++ b/src/Impostor.Server/Extensions/NodeLocatorExtensions.cs @@ -10,4 +10,4 @@ public static async ValueTask ExistsAsync(this INodeLocator nodeLocator, s return await nodeLocator.FindAsync(gameCode) != null; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Extensions/TypeExtensions.cs b/src/Impostor.Server/Extensions/TypeExtensions.cs index 55d42fbda..396d987f1 100644 --- a/src/Impostor.Server/Extensions/TypeExtensions.cs +++ b/src/Impostor.Server/Extensions/TypeExtensions.cs @@ -64,4 +64,4 @@ public static string GetFriendlyName(this MethodBase method, bool showParameters return str; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Factories/IClientFactory.cs b/src/Impostor.Server/Net/Factories/IClientFactory.cs index bec1b79ba..a72a23bab 100644 --- a/src/Impostor.Server/Net/Factories/IClientFactory.cs +++ b/src/Impostor.Server/Net/Factories/IClientFactory.cs @@ -8,4 +8,4 @@ internal interface IClientFactory { ClientBase Create(IHazelConnection connection, string name, int clientVersion, ISet mods); } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/GameCodeFactory.cs b/src/Impostor.Server/Net/GameCodeFactory.cs index 2a0553fc8..f8b0de478 100644 --- a/src/Impostor.Server/Net/GameCodeFactory.cs +++ b/src/Impostor.Server/Net/GameCodeFactory.cs @@ -9,4 +9,4 @@ public GameCode Create() return GameCode.Create(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Inner/GameObject.cs b/src/Impostor.Server/Net/Inner/GameObject.cs index 9b53d708f..7fd4f0125 100644 --- a/src/Impostor.Server/Net/Inner/GameObject.cs +++ b/src/Impostor.Server/Net/Inner/GameObject.cs @@ -26,4 +26,4 @@ public List GetComponentsInChildren() return result; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Inner/InnerNetObject.cs b/src/Impostor.Server/Net/Inner/InnerNetObject.cs index 5b65f464c..8cbea9a26 100644 --- a/src/Impostor.Server/Net/Inner/InnerNetObject.cs +++ b/src/Impostor.Server/Net/Inner/InnerNetObject.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Threading.Tasks; +using System.Threading.Tasks; using Impostor.Api.Net; using Impostor.Api.Net.Inner; using Impostor.Api.Net.Messages; diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs index 0e475b8c2..ff5c21d59 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Numerics; +using System.Numerics; using System.Threading.Tasks; using Impostor.Api; using Impostor.Api.Events.Managers; diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs index 69f8dcd81..4eb5f8a1a 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Threading.Tasks; using Impostor.Api.Events.Managers; using Impostor.Api.Innersloth; diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs b/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs index 78be5bd23..3dfd74158 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Impostor.Api.Games; using Impostor.Api.Net; using Impostor.Api.Net.Inner.Objects; @@ -20,17 +21,17 @@ public InnerLobbyBehaviour(IGame game) public override ValueTask SerializeAsync(IMessageWriter writer, bool initialState) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public override ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public override ValueTask HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs index 8f9c8f5e8..a2d6f0e79 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading.Tasks; diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/IActivatable.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/IActivatable.cs index e595b25a9..66a164c78 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Systems/IActivatable.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/IActivatable.cs @@ -4,4 +4,4 @@ public interface IActivatable { bool IsActive { get; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ISystemType.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ISystemType.cs index a6ef88e58..441d7c35b 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Systems/ISystemType.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ISystemType.cs @@ -8,4 +8,4 @@ public interface ISystemType void Deserialize(IMessageReader reader, bool initialState); } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HudOverrideSystemType.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HudOverrideSystemType.cs index 42aa8d379..4349233f0 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HudOverrideSystemType.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HudOverrideSystemType.cs @@ -1,4 +1,5 @@ -using Impostor.Api.Net.Messages; +using System; +using Impostor.Api.Net.Messages; namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus { @@ -8,7 +9,7 @@ public class HudOverrideSystemType : ISystemType, IActivatable public void Serialize(IMessageWriter writer, bool initialState) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public void Deserialize(IMessageReader reader, bool initialState) @@ -16,4 +17,4 @@ public void Deserialize(IMessageReader reader, bool initialState) IsActive = reader.ReadBoolean(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/LifeSuppSystemType.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/LifeSuppSystemType.cs index f64402434..681ebe163 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/LifeSuppSystemType.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/LifeSuppSystemType.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Impostor.Api.Net.Messages; namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus @@ -19,7 +20,7 @@ public LifeSuppSystemType() public void Serialize(IMessageWriter writer, bool initialState) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public void Deserialize(IMessageReader reader, bool initialState) @@ -41,4 +42,4 @@ public void Deserialize(IMessageReader reader, bool initialState) } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/MedScanSystem.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/MedScanSystem.cs index 007b9d0af..4c2287fee 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/MedScanSystem.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/MedScanSystem.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Impostor.Api.Net.Messages; namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus @@ -14,7 +15,7 @@ public MedScanSystem() public void Serialize(IMessageWriter writer, bool initialState) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public void Deserialize(IMessageReader reader, bool initialState) @@ -29,4 +30,4 @@ public void Deserialize(IMessageReader reader, bool initialState) } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/ReactorSystemType.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/ReactorSystemType.cs index 438091846..7bc2ab373 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/ReactorSystemType.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/ReactorSystemType.cs @@ -20,7 +20,7 @@ public ReactorSystemType() public void Serialize(IMessageWriter writer, bool initialState) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public void Deserialize(IMessageReader reader, bool initialState) @@ -36,4 +36,4 @@ public void Deserialize(IMessageReader reader, bool initialState) } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/SabotageSystemType.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/SabotageSystemType.cs index 193cfe80b..73c10c38f 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/SabotageSystemType.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/SabotageSystemType.cs @@ -1,4 +1,5 @@ -using Impostor.Api.Net.Messages; +using System; +using Impostor.Api.Net.Messages; namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus { @@ -15,7 +16,7 @@ public SabotageSystemType(IActivatable[] specials) public void Serialize(IMessageWriter writer, bool initialState) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public void Deserialize(IMessageReader reader, bool initialState) @@ -23,4 +24,4 @@ public void Deserialize(IMessageReader reader, bool initialState) Timer = reader.ReadSingle(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/SecurityCameraSystemType.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/SecurityCameraSystemType.cs index df41b68ec..d79645560 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/SecurityCameraSystemType.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/SecurityCameraSystemType.cs @@ -1,4 +1,5 @@ -using Impostor.Api.Net.Messages; +using System; +using Impostor.Api.Net.Messages; namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus { @@ -8,7 +9,7 @@ public class SecurityCameraSystemType : ISystemType public void Serialize(IMessageWriter writer, bool initialState) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public void Deserialize(IMessageReader reader, bool initialState) @@ -16,4 +17,4 @@ public void Deserialize(IMessageReader reader, bool initialState) InUse = reader.ReadByte(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/SwitchSystem.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/SwitchSystem.cs index 925774ab9..eb2b57260 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/SwitchSystem.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/SwitchSystem.cs @@ -1,4 +1,5 @@ -using Impostor.Api.Net.Messages; +using System; +using Impostor.Api.Net.Messages; namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus { @@ -14,7 +15,7 @@ public class SwitchSystem : ISystemType, IActivatable public void Serialize(IMessageWriter writer, bool initialState) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public void Deserialize(IMessageReader reader, bool initialState) @@ -24,4 +25,4 @@ public void Deserialize(IMessageReader reader, bool initialState) Value = reader.ReadByte(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Inner/SpawnFlags.cs b/src/Impostor.Server/Net/Inner/SpawnFlags.cs index 1860098ce..28c2a1ab9 100644 --- a/src/Impostor.Server/Net/Inner/SpawnFlags.cs +++ b/src/Impostor.Server/Net/Inner/SpawnFlags.cs @@ -8,4 +8,4 @@ public enum SpawnFlags : byte None = 0, IsClientCharacter = 1, } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Manager/ClientManager.Api.cs b/src/Impostor.Server/Net/Manager/ClientManager.Api.cs index 6cbe5bf61..1ff970dad 100644 --- a/src/Impostor.Server/Net/Manager/ClientManager.Api.cs +++ b/src/Impostor.Server/Net/Manager/ClientManager.Api.cs @@ -8,4 +8,4 @@ internal partial class ClientManager : IClientManager { IEnumerable IClientManager.Clients => _clients.Values; } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Manager/GameManager.cs b/src/Impostor.Server/Net/Manager/GameManager.cs index eef5d53d9..b10e79164 100644 --- a/src/Impostor.Server/Net/Manager/GameManager.cs +++ b/src/Impostor.Server/Net/Manager/GameManager.cs @@ -115,7 +115,7 @@ 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++) + for (var i = 0; i < 10 && !success; i++) { (success, game) = await TryCreateAsync(options); } diff --git a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs index afae57e8b..0cfa76d0f 100644 --- a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs +++ b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs @@ -10,7 +10,6 @@ using Impostor.Server.Net.Hazel; using Impostor.Server.Net.Manager; using Serilog; -using ILogger = Serilog.ILogger; namespace Impostor.Server.Net.Redirector { diff --git a/src/Impostor.Server/Net/Redirector/INodeProvider.cs b/src/Impostor.Server/Net/Redirector/INodeProvider.cs index 318fcb2d6..fb7240c89 100644 --- a/src/Impostor.Server/Net/Redirector/INodeProvider.cs +++ b/src/Impostor.Server/Net/Redirector/INodeProvider.cs @@ -6,4 +6,4 @@ internal interface INodeProvider { IPEndPoint Get(); } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/Redirector/NodeProviderConfig.cs b/src/Impostor.Server/Net/Redirector/NodeProviderConfig.cs index 4e19c43cf..7e2982e80 100644 --- a/src/Impostor.Server/Net/Redirector/NodeProviderConfig.cs +++ b/src/Impostor.Server/Net/Redirector/NodeProviderConfig.cs @@ -40,4 +40,4 @@ public IPEndPoint Get() } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index b928a3c21..9e5fd0148 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -1,14 +1,10 @@ using System; using System.Collections.Generic; -using System.Threading; using System.Threading.Tasks; using Impostor.Api; -using Impostor.Api.Innersloth; using Impostor.Api.Net.Inner; using Impostor.Api.Net.Messages; -using Impostor.Api.Net.Messages.S2C; using Impostor.Api.Unity; -using Impostor.Hazel; using Impostor.Server.Events.Meeting; using Impostor.Server.Events.Player; using Impostor.Server.Net.Inner; diff --git a/src/Impostor.Server/Net/State/Game.Outgoing.cs b/src/Impostor.Server/Net/State/Game.Outgoing.cs index 21b606701..5c84f9472 100644 --- a/src/Impostor.Server/Net/State/Game.Outgoing.cs +++ b/src/Impostor.Server/Net/State/Game.Outgoing.cs @@ -55,7 +55,7 @@ internal IMessageWriter StartRpc(uint targetNetId, RpcCalls callId, int targetCl writer.StartMessage(GameDataTag.RpcFlag); writer.WritePacked(targetNetId); - writer.Write((byte) callId); + writer.Write((byte)callId); return writer; } diff --git a/src/Impostor.Server/Plugins/IAssemblyInformation.cs b/src/Impostor.Server/Plugins/IAssemblyInformation.cs index fb36e92a5..f724cf29e 100644 --- a/src/Impostor.Server/Plugins/IAssemblyInformation.cs +++ b/src/Impostor.Server/Plugins/IAssemblyInformation.cs @@ -11,4 +11,4 @@ public interface IAssemblyInformation Assembly Load(AssemblyLoadContext context); } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Plugins/LoadedAssemblyInformation.cs b/src/Impostor.Server/Plugins/LoadedAssemblyInformation.cs index 720367cc9..5f7d0bbc1 100644 --- a/src/Impostor.Server/Plugins/LoadedAssemblyInformation.cs +++ b/src/Impostor.Server/Plugins/LoadedAssemblyInformation.cs @@ -22,4 +22,4 @@ public Assembly Load(AssemblyLoadContext context) return _assembly; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Plugins/PluginConfig.cs b/src/Impostor.Server/Plugins/PluginConfig.cs index 22dc9e90d..66afceb33 100644 --- a/src/Impostor.Server/Plugins/PluginConfig.cs +++ b/src/Impostor.Server/Plugins/PluginConfig.cs @@ -8,4 +8,4 @@ public class PluginConfig public List LibraryPaths { get; set; } = new List(); } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Plugins/PluginLoaderService.cs b/src/Impostor.Server/Plugins/PluginLoaderService.cs index 84238f786..40e13b5b8 100644 --- a/src/Impostor.Server/Plugins/PluginLoaderService.cs +++ b/src/Impostor.Server/Plugins/PluginLoaderService.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Impostor.Api.Plugins; diff --git a/src/Impostor.Server/Properties/AssemblyInfo.cs b/src/Impostor.Server/Properties/AssemblyInfo.cs index 84c51585a..eed7af613 100644 --- a/src/Impostor.Server/Properties/AssemblyInfo.cs +++ b/src/Impostor.Server/Properties/AssemblyInfo.cs @@ -1,5 +1,5 @@ using System.Runtime.CompilerServices; -[assembly:InternalsVisibleTo("Impostor.Benchmarks")] -[assembly:InternalsVisibleTo("Impostor.Tests")] -[assembly:InternalsVisibleTo("Impostor.Tools.ServerReplay")] +[assembly: InternalsVisibleTo("Impostor.Benchmarks")] +[assembly: InternalsVisibleTo("Impostor.Tests")] +[assembly: InternalsVisibleTo("Impostor.Tools.ServerReplay")] diff --git a/src/Impostor.Server/Recorder/PacketRecorder.cs b/src/Impostor.Server/Recorder/PacketRecorder.cs index c6531b456..905e02628 100644 --- a/src/Impostor.Server/Recorder/PacketRecorder.cs +++ b/src/Impostor.Server/Recorder/PacketRecorder.cs @@ -17,7 +17,7 @@ namespace Impostor.Server.Recorder { /// - /// Records all packets received in . + /// Records all packets received in . /// internal class PacketRecorder : BackgroundService { diff --git a/src/Impostor.Server/Recorder/PacketSerializationContextPooledObjectPolicy.cs b/src/Impostor.Server/Recorder/PacketSerializationContextPooledObjectPolicy.cs index 17b355f54..e45948e84 100644 --- a/src/Impostor.Server/Recorder/PacketSerializationContextPooledObjectPolicy.cs +++ b/src/Impostor.Server/Recorder/PacketSerializationContextPooledObjectPolicy.cs @@ -15,4 +15,4 @@ public bool Return(PacketSerializationContext obj) return true; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Recorder/ServerReplayVersion.cs b/src/Impostor.Server/Recorder/ServerReplayVersion.cs index 648205b54..2eb3b49d0 100644 --- a/src/Impostor.Server/Recorder/ServerReplayVersion.cs +++ b/src/Impostor.Server/Recorder/ServerReplayVersion.cs @@ -1,17 +1,17 @@ namespace Impostor.Server.Recorder { /// - /// Version of the server replay data format. + /// Version of the server replay data format. /// public enum ServerReplayVersion { /// - /// Initial version + /// Initial version /// Initial = 1, /// - /// Latest version + /// Latest version /// Latest = Initial, } diff --git a/src/Impostor.Tests/Events/EventManagerTests.cs b/src/Impostor.Tests/Events/EventManagerTests.cs index d222d79b9..a510803a5 100644 --- a/src/Impostor.Tests/Events/EventManagerTests.cs +++ b/src/Impostor.Tests/Events/EventManagerTests.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Net.Sockets; using System.Threading.Tasks; using Impostor.Api.Events; using Impostor.Api.Events.Managers; @@ -11,10 +10,10 @@ namespace Impostor.Tests.Events { public class EventManagerTests { - public static readonly IEnumerable TestModes = new [] + public static readonly IEnumerable TestModes = new[] { new object[] { TestMode.Service }, - new object[] { TestMode.Temporary } + new object[] { TestMode.Temporary }, }; [Theory] @@ -38,14 +37,14 @@ public async Task CallPriority(TestMode mode) await eventManager.CallAsync(new SetValueEvent(1)); - Assert.Equal(new [] + Assert.Equal(new[] { EventPriority.Monitor, EventPriority.Highest, EventPriority.High, EventPriority.Normal, EventPriority.Low, - EventPriority.Lowest + EventPriority.Lowest, }, listener.Priorities); } @@ -78,10 +77,10 @@ public async Task CancelPriority(TestMode mode) await eventManager.CallAsync(new SetValueEvent(1)); - Assert.Equal(new [] + Assert.Equal(new[] { EventPriority.Monitor, - EventPriority.Highest + EventPriority.Highest, }, listener.Priorities); } @@ -115,7 +114,7 @@ private static IEventManager CreatEventManager(TestMode mode, params IEventListe public enum TestMode { Service, - Temporary + Temporary, } public interface ISetValueEvent : IEventCancelable diff --git a/src/Impostor.Tests/GameCodeTests.cs b/src/Impostor.Tests/GameCodeTests.cs index de9812351..6f0c23b4f 100644 --- a/src/Impostor.Tests/GameCodeTests.cs +++ b/src/Impostor.Tests/GameCodeTests.cs @@ -1,5 +1,4 @@ using Impostor.Api.Innersloth; - using Xunit; namespace Impostor.Tests @@ -26,4 +25,4 @@ public void CodeV2() Assert.Equal(codeInt, GameCodeParser.GameNameToInt(code)); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Tests/Hazel/MessageReaderTests.cs b/src/Impostor.Tests/Hazel/MessageReaderTests.cs index e7fa0dff8..c0ecbdd7b 100644 --- a/src/Impostor.Tests/Hazel/MessageReaderTests.cs +++ b/src/Impostor.Tests/Hazel/MessageReaderTests.cs @@ -72,7 +72,7 @@ public void ReadProperBool() public void ReadProperString() { const string Test1 = "Hello"; - string Test2 = new string(' ', 1024); + var Test2 = new string(' ', 1024); var msg = new MessageWriter(2048); msg.StartMessage(1); msg.Write(Test1); @@ -128,18 +128,18 @@ public void CopyMessage() var msg = new MessageWriter(2048); msg.StartMessage(1); - msg.StartMessage(2); - msg.Write(Test1); - msg.Write(Test2); - msg.StartMessage(2); - msg.Write(Test1); - msg.Write(Test2); - msg.StartMessage(2); - msg.Write(Test1); - msg.Write(Test2); - msg.EndMessage(); - msg.EndMessage(); - msg.EndMessage(); + msg.StartMessage(2); + msg.Write(Test1); + msg.Write(Test2); + msg.StartMessage(2); + msg.Write(Test1); + msg.Write(Test2); + msg.StartMessage(2); + msg.Write(Test1); + msg.Write(Test2); + msg.EndMessage(); + msg.EndMessage(); + msg.EndMessage(); msg.EndMessage(); // Read message. @@ -217,7 +217,7 @@ public void CopyToMessage() 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x70, 0x61, 0x63, 0x6B, 0x65, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x63, 0x6F, 0x70, - 0x79, 0x69, 0x6E, 0x67, 0x2E + 0x79, 0x69, 0x6E, 0x67, 0x2E, }; var readerPool = CreateReaderPool(); @@ -301,15 +301,15 @@ public void RemoveMessage() var messageWriter = new MessageWriter(1024); messageWriter.StartMessage(0); - messageWriter.StartMessage(1); - messageWriter.Write("HiTest1"); - messageWriter.StartMessage(2); - messageWriter.Write("RemoveMe!"); - messageWriter.EndMessage(); - messageWriter.EndMessage(); - messageWriter.StartMessage(2); - messageWriter.Write("HiTest2"); - messageWriter.EndMessage(); + messageWriter.StartMessage(1); + messageWriter.Write("HiTest1"); + messageWriter.StartMessage(2); + messageWriter.Write("RemoveMe!"); + messageWriter.EndMessage(); + messageWriter.EndMessage(); + messageWriter.StartMessage(2); + messageWriter.Write("HiTest2"); + messageWriter.EndMessage(); messageWriter.EndMessage(); // Copy buffer. diff --git a/src/Impostor.Tests/Hazel/MessageWriterTests.cs b/src/Impostor.Tests/Hazel/MessageWriterTests.cs index 83d67da9d..f15819112 100644 --- a/src/Impostor.Tests/Hazel/MessageWriterTests.cs +++ b/src/Impostor.Tests/Hazel/MessageWriterTests.cs @@ -35,4 +35,4 @@ static void WriteSomeData(MessageWriter oldVer) } } } -} \ No newline at end of file +} diff --git a/src/Impostor.Tools.Proxy/HexUtils.cs b/src/Impostor.Tools.Proxy/HexUtils.cs index 79517b4d2..f04e226b0 100644 --- a/src/Impostor.Tools.Proxy/HexUtils.cs +++ b/src/Impostor.Tools.Proxy/HexUtils.cs @@ -8,28 +8,28 @@ public static class HexUtils public static string HexDump(byte[] bytes, int bytesPerLine = 16) { if (bytes == null) return ""; - int bytesLength = bytes.Length; + var bytesLength = bytes.Length; - char[] HexChars = "0123456789ABCDEF".ToCharArray(); + var HexChars = "0123456789ABCDEF".ToCharArray(); - int firstHexColumn = - 8 // 8 characters for the address - + 3; // 3 spaces + var firstHexColumn = + 8 // 8 characters for the address + + 3; // 3 spaces - int firstCharColumn = firstHexColumn - + bytesPerLine * 3 // - 2 digit for the hexadecimal value and 1 space - + (bytesPerLine - 1) / 8 // - 1 extra space every 8 characters from the 9th - + 2; // 2 spaces + var firstCharColumn = firstHexColumn + + bytesPerLine * 3 // - 2 digit for the hexadecimal value and 1 space + + (bytesPerLine - 1) / 8 // - 1 extra space every 8 characters from the 9th + + 2; // 2 spaces - int lineLength = firstCharColumn - + bytesPerLine // - characters to show the ascii value - + Environment.NewLine.Length; // Carriage return and line feed (should normally be 2) + var lineLength = firstCharColumn + + bytesPerLine // - characters to show the ascii value + + Environment.NewLine.Length; // Carriage return and line feed (should normally be 2) - char[] line = (new String(' ', lineLength - Environment.NewLine.Length) + Environment.NewLine).ToCharArray(); - int expectedLines = (bytesLength + bytesPerLine - 1) / bytesPerLine; - StringBuilder result = new StringBuilder(expectedLines * lineLength); + var line = (new string(' ', lineLength - Environment.NewLine.Length) + Environment.NewLine).ToCharArray(); + var expectedLines = (bytesLength + bytesPerLine - 1) / bytesPerLine; + var result = new StringBuilder(expectedLines * lineLength); - for (int i = 0; i < bytesLength; i += bytesPerLine) + for (var i = 0; i < bytesLength; i += bytesPerLine) { line[0] = HexChars[(i >> 28) & 0xF]; line[1] = HexChars[(i >> 24) & 0xF]; @@ -40,10 +40,10 @@ public static string HexDump(byte[] bytes, int bytesPerLine = 16) line[6] = HexChars[(i >> 4) & 0xF]; line[7] = HexChars[(i >> 0) & 0xF]; - int hexColumn = firstHexColumn; - int charColumn = firstCharColumn; + var hexColumn = firstHexColumn; + var charColumn = firstCharColumn; - for (int j = 0; j < bytesPerLine; j++) + for (var j = 0; j < bytesPerLine; j++) { if (j > 0 && (j & 7) == 0) hexColumn++; if (i + j >= bytesLength) @@ -54,17 +54,20 @@ public static string HexDump(byte[] bytes, int bytesPerLine = 16) } else { - byte b = bytes[i + j]; + var b = bytes[i + j]; line[hexColumn] = HexChars[(b >> 4) & 0xF]; line[hexColumn + 1] = HexChars[b & 0xF]; line[charColumn] = (b < 32 ? '·' : (char)b); } + hexColumn += 3; charColumn++; } + result.Append(line); } + return result.ToString(); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Tools.Proxy/Program.cs b/src/Impostor.Tools.Proxy/Program.cs index 468cdd15e..c7f9cfac6 100644 --- a/src/Impostor.Tools.Proxy/Program.cs +++ b/src/Impostor.Tools.Proxy/Program.cs @@ -18,22 +18,22 @@ internal static class Program private static readonly Dictionary TagMap = new Dictionary { - {0, "HostGame"}, - {1, "JoinGame"}, - {2, "StartGame"}, - {3, "RemoveGame"}, - {4, "RemovePlayer"}, - {5, "GameData"}, - {6, "GameDataTo"}, - {7, "JoinedGame"}, - {8, "EndGame"}, - {9, "GetGameList"}, - {10, "AlterGame"}, - {11, "KickPlayer"}, - {12, "WaitForHost"}, - {13, "Redirect"}, - {14, "ReselectServer"}, - {16, "GetGameListV2"} + { 0, "HostGame" }, + { 1, "JoinGame" }, + { 2, "StartGame" }, + { 3, "RemoveGame" }, + { 4, "RemovePlayer" }, + { 5, "GameData" }, + { 6, "GameDataTo" }, + { 7, "JoinedGame" }, + { 8, "EndGame" }, + { 9, "GetGameList" }, + { 10, "AlterGame" }, + { 11, "KickPlayer" }, + { 12, "WaitForHost" }, + { 13, "Redirect" }, + { 14, "ReselectServer" }, + { 16, "GetGameListV2" }, }; private static IServiceProvider _serviceProvider; @@ -46,7 +46,7 @@ private static void Main(string[] args) _serviceProvider = services.BuildServiceProvider(); _readerPool = _serviceProvider.GetRequiredService>(); - + var devices = LivePacketDevice.AllLocalMachine; if (devices.Count == 0) { @@ -77,7 +77,7 @@ private static void PacketHandler(Packet packet) var ip = packet.Ethernet.IpV4; var ipSrc = ip.Source.ToString(); var udp = ip.Udp; - + // True if this is our own packet. using (var stream = udp.Payload.ToMemoryStream()) { @@ -86,14 +86,14 @@ private static void PacketHandler(Packet packet) reader.Update(stream.ToArray()); var option = reader.Buffer[0]; - if (option == (byte) MessageType.Reliable) + if (option == (byte)MessageType.Reliable) { reader.Seek(reader.Position + 3); } - else if (option == (byte) UdpSendOption.Acknowledgement || - option == (byte) UdpSendOption.Ping || - option == (byte) UdpSendOption.Hello || - option == (byte) UdpSendOption.Disconnect) + else if (option == (byte)UdpSendOption.Acknowledgement || + option == (byte)UdpSendOption.Ping || + option == (byte)UdpSendOption.Hello || + option == (byte)UdpSendOption.Disconnect) { return; } @@ -101,9 +101,9 @@ private static void PacketHandler(Packet packet) { reader.Seek(reader.Position + 1); } - + var isSent = ipSrc.StartsWith("192."); - + while (true) { if (reader.Position >= reader.Length) @@ -120,7 +120,7 @@ private static void PacketHandler(Packet packet) { HandleToClient(ipSrc, message); } - + if (message.Position < message.Length) { Console.ForegroundColor = ConsoleColor.Red; @@ -160,6 +160,7 @@ private static void HandleToClient(string source, IMessageReader packet) { Console.WriteLine("- PlayerId " + packet.ReadPackedInt32()); } + break; case 10: Console.WriteLine("- GameCode " + packet.ReadInt32()); diff --git a/src/Impostor.Tools.ServerReplay/Mocks/MockGameCodeFactory.cs b/src/Impostor.Tools.ServerReplay/Mocks/MockGameCodeFactory.cs index 1111b7e71..7dc9196fe 100644 --- a/src/Impostor.Tools.ServerReplay/Mocks/MockGameCodeFactory.cs +++ b/src/Impostor.Tools.ServerReplay/Mocks/MockGameCodeFactory.cs @@ -11,4 +11,4 @@ public GameCode Create() return Result; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Tools.ServerReplay/Program.cs b/src/Impostor.Tools.ServerReplay/Program.cs index 261d679b6..65401efa0 100644 --- a/src/Impostor.Tools.ServerReplay/Program.cs +++ b/src/Impostor.Tools.ServerReplay/Program.cs @@ -89,7 +89,7 @@ private static ServiceProvider BuildServices() services.AddSingleton(new ServerEnvironment { - IsReplay = true + IsReplay = true, }); services.AddSingleton(); From bc85ef68104d1725bacef2bc7ad8ffb52bf7f8b0 Mon Sep 17 00:00:00 2001 From: js6pak Date: Wed, 24 Mar 2021 17:55:15 +0100 Subject: [PATCH 27/72] Fix xmldoc warnings --- src/Directory.Build.props | 4 ++++ .../Events/Attributes/EventListenerAttribute.cs | 6 +++--- .../Events/Game/Player/IPlayerStartMeetingEvent.cs | 2 +- src/Impostor.Api/Events/IEventCancelable.cs | 2 +- src/Impostor.Api/Events/Managers/IEventManager.cs | 6 +++--- src/Impostor.Api/Extensions/SpanReaderExtensions.cs | 6 +++--- src/Impostor.Api/Impostor.Api.csproj | 1 + src/Impostor.Api/Net/IClient.cs | 4 ++-- src/Impostor.Api/Net/IHazelConnection.cs | 6 +++--- .../Net/Messages/IMessageWriterProvider.cs | 2 +- src/Impostor.Api/Reactor/PluginSide.cs | 2 +- src/Impostor.Server/Extensions/TypeExtensions.cs | 2 +- src/Impostor.Server/Impostor.Server.csproj | 1 + src/Impostor.Server/Recorder/ServerReplayVersion.cs | 4 ++-- src/ProjectRules.ruleset | 5 ++--- src/stylecop.json | 11 +++++++++++ 16 files changed, 40 insertions(+), 24 deletions(-) create mode 100644 src/stylecop.json diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 81faf42b8..1bcb40ab4 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -3,5 +3,9 @@ 1.3.0 dev + + + + diff --git a/src/Impostor.Api/Events/Attributes/EventListenerAttribute.cs b/src/Impostor.Api/Events/Attributes/EventListenerAttribute.cs index 9289fa5f8..da1e48960 100644 --- a/src/Impostor.Api/Events/Attributes/EventListenerAttribute.cs +++ b/src/Impostor.Api/Events/Attributes/EventListenerAttribute.cs @@ -17,17 +17,17 @@ public EventListenerAttribute(Type @event, EventPriority priority = EventPriorit } /// - /// The priority of the event listener. + /// Gets or sets the priority of the event listener. /// public EventPriority Priority { get; set; } /// - /// The events that the listener is listening to. + /// Gets or sets the event that the listener is listening to. /// public Type? Event { get; set; } /// - /// If set to true, the listener will be called regardless of the . + /// Gets or sets a value indicating whether the listener will be called regardless of the . /// public bool IgnoreCancelled { get; set; } } diff --git a/src/Impostor.Api/Events/Game/Player/IPlayerStartMeetingEvent.cs b/src/Impostor.Api/Events/Game/Player/IPlayerStartMeetingEvent.cs index 1a28115eb..016d131d2 100644 --- a/src/Impostor.Api/Events/Game/Player/IPlayerStartMeetingEvent.cs +++ b/src/Impostor.Api/Events/Game/Player/IPlayerStartMeetingEvent.cs @@ -5,7 +5,7 @@ namespace Impostor.Api.Events.Player public interface IPlayerStartMeetingEvent : IPlayerEvent { /// - /// Gets the player who's body got reported. Is null when the meeting started by Emergency call button + /// Gets the player who's body got reported. Is null when the meeting started by Emergency call button. /// IInnerPlayerControl? Body { get; } } diff --git a/src/Impostor.Api/Events/IEventCancelable.cs b/src/Impostor.Api/Events/IEventCancelable.cs index d6d1ca669..1902284ee 100644 --- a/src/Impostor.Api/Events/IEventCancelable.cs +++ b/src/Impostor.Api/Events/IEventCancelable.cs @@ -3,7 +3,7 @@ public interface IEventCancelable : IEvent { /// - /// True if the event was cancelled. + /// Gets or sets a value indicating whether the event was cancelled. /// bool IsCancelled { get; set; } } diff --git a/src/Impostor.Api/Events/Managers/IEventManager.cs b/src/Impostor.Api/Events/Managers/IEventManager.cs index 35fb9bbcc..3d73768a1 100644 --- a/src/Impostor.Api/Events/Managers/IEventManager.cs +++ b/src/Impostor.Api/Events/Managers/IEventManager.cs @@ -16,15 +16,15 @@ IDisposable RegisterListener(TListener listener, Func, Tas where TListener : IEventListener; /// - /// Returns true if an event with the type is registered. + /// Returns true if an event with the type is registered. /// - /// True if the is registered. + /// True if the is registered. /// Type of the event. bool IsRegistered() where TEvent : IEvent; /// - /// Call all the event listeners for the type . + /// Call all the event listeners for the type . /// /// The event argument. /// Type of the event. diff --git a/src/Impostor.Api/Extensions/SpanReaderExtensions.cs b/src/Impostor.Api/Extensions/SpanReaderExtensions.cs index 242f05496..78e5a4567 100644 --- a/src/Impostor.Api/Extensions/SpanReaderExtensions.cs +++ b/src/Impostor.Api/Extensions/SpanReaderExtensions.cs @@ -5,7 +5,7 @@ namespace Impostor.Api { /// - /// Priovides a StreamReader-like api throught extensions + /// Priovides a StreamReader-like api throught extensions. /// public static class SpanReaderExtensions { @@ -53,11 +53,11 @@ private static unsafe float Int32BitsToSingle(int value) } /// - /// Advances the position of by the size of . + /// Advances the position of by the size of . /// /// Type that will be read. /// input "stream"/span. - /// The original input + /// The original input. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe ReadOnlySpan Advance(ref ReadOnlySpan input) where T : unmanaged diff --git a/src/Impostor.Api/Impostor.Api.csproj b/src/Impostor.Api/Impostor.Api.csproj index 33c2ea01e..86b4f09d9 100644 --- a/src/Impostor.Api/Impostor.Api.csproj +++ b/src/Impostor.Api/Impostor.Api.csproj @@ -18,6 +18,7 @@ https://github.com/Impostor/Impostor git https://github.com/Impostor/Impostor + true diff --git a/src/Impostor.Api/Net/IClient.cs b/src/Impostor.Api/Net/IClient.cs index 790b1c0b8..d9631d7d6 100644 --- a/src/Impostor.Api/Net/IClient.cs +++ b/src/Impostor.Api/Net/IClient.cs @@ -57,7 +57,7 @@ public interface IClient IDictionary Items { get; } /// - /// Gets or sets the current game data of the . + /// Gets the current game data of the . /// IClientPlayer? Player { get; } @@ -74,7 +74,7 @@ public interface IClient /// The message to show to the player. /// /// - /// Only used when is set to . + /// Only used when is set to . /// /// /// A representing the asynchronous operation. diff --git a/src/Impostor.Api/Net/IHazelConnection.cs b/src/Impostor.Api/Net/IHazelConnection.cs index c012bd192..e2a9cfbf9 100644 --- a/src/Impostor.Api/Net/IHazelConnection.cs +++ b/src/Impostor.Api/Net/IHazelConnection.cs @@ -20,7 +20,7 @@ public interface IHazelConnection bool IsConnected { get; } /// - /// Gets the client of the connection. + /// Gets or sets the client of the connection. /// IClient? Client { get; set; } @@ -28,14 +28,14 @@ public interface IHazelConnection /// Sends a message writer to the connection. /// /// The message. - /// + /// Task that must be awaited. ValueTask SendAsync(IMessageWriter writer); /// /// Disconnects the client and invokes the disconnect handler. /// /// A reason. - /// + /// Task that must be awaited. ValueTask DisconnectAsync(string? reason); } } diff --git a/src/Impostor.Api/Net/Messages/IMessageWriterProvider.cs b/src/Impostor.Api/Net/Messages/IMessageWriterProvider.cs index cf9200426..16a48ecf8 100644 --- a/src/Impostor.Api/Net/Messages/IMessageWriterProvider.cs +++ b/src/Impostor.Api/Net/Messages/IMessageWriterProvider.cs @@ -4,7 +4,7 @@ public interface IMessageWriterProvider { /// /// Retrieves a from the internal pool. - /// Make sure to call when you are done! + /// Make sure to call when you are done!. /// /// /// Whether to send the message as or . diff --git a/src/Impostor.Api/Reactor/PluginSide.cs b/src/Impostor.Api/Reactor/PluginSide.cs index 2118299bf..4523dfc62 100644 --- a/src/Impostor.Api/Reactor/PluginSide.cs +++ b/src/Impostor.Api/Reactor/PluginSide.cs @@ -1,7 +1,7 @@ namespace Impostor.Api.Reactor { /// - /// Plugin side used in modded handshake + /// Plugin side used in modded handshake. /// public enum PluginSide : byte { diff --git a/src/Impostor.Server/Extensions/TypeExtensions.cs b/src/Impostor.Server/Extensions/TypeExtensions.cs index 396d987f1..a49cb5e2b 100644 --- a/src/Impostor.Server/Extensions/TypeExtensions.cs +++ b/src/Impostor.Server/Extensions/TypeExtensions.cs @@ -45,7 +45,7 @@ public static string GetFriendlyName(this Type type) /// /// The method. /// True if the parameters should be included in the name. - /// Friendly name of the method + /// Friendly name of the method. public static string GetFriendlyName(this MethodBase method, bool showParameters = true) { var str = method.Name; diff --git a/src/Impostor.Server/Impostor.Server.csproj b/src/Impostor.Server/Impostor.Server.csproj index 5cad72de6..ba444fc81 100644 --- a/src/Impostor.Server/Impostor.Server.csproj +++ b/src/Impostor.Server/Impostor.Server.csproj @@ -9,6 +9,7 @@ ../ProjectRules.ruleset enable false + true diff --git a/src/Impostor.Server/Recorder/ServerReplayVersion.cs b/src/Impostor.Server/Recorder/ServerReplayVersion.cs index 2eb3b49d0..ce77e3c7d 100644 --- a/src/Impostor.Server/Recorder/ServerReplayVersion.cs +++ b/src/Impostor.Server/Recorder/ServerReplayVersion.cs @@ -6,12 +6,12 @@ namespace Impostor.Server.Recorder public enum ServerReplayVersion { /// - /// Initial version + /// Initial version. /// Initial = 1, /// - /// Latest version + /// Latest version. /// Latest = Initial, } diff --git a/src/ProjectRules.ruleset b/src/ProjectRules.ruleset index 5102b80bf..5484352e8 100644 --- a/src/ProjectRules.ruleset +++ b/src/ProjectRules.ruleset @@ -1,6 +1,6 @@  - - + + @@ -17,7 +17,6 @@ - diff --git a/src/stylecop.json b/src/stylecop.json new file mode 100644 index 000000000..216b35a2a --- /dev/null +++ b/src/stylecop.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "orderingRules": { + "usingDirectivesPlacement": "preserve" + }, + "layoutRules": { + "newlineAtEndOfFile": "require" + } + } +} From ef5320c82093d4f4063fcd2067af3cada7a525b1 Mon Sep 17 00:00:00 2001 From: js6pak Date: Wed, 24 Mar 2021 19:04:11 +0100 Subject: [PATCH 28/72] Update cake --- .config/dotnet-tools.json | 2 +- build.cake | 6 +++--- src/Directory.Build.props | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 727dfd760..6cf141eb6 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "cake.tool": { - "version": "0.38.5", + "version": "1.1.0", "commands": [ "dotnet-cake" ] diff --git a/build.cake b/build.cake index 13a2ae965..25a5e17b3 100644 --- a/build.cake +++ b/build.cake @@ -1,6 +1,6 @@ -#addin "nuget:?package=SharpZipLib&Version=1.3.0" -#addin "nuget:?package=Cake.Compression&Version=0.2.4" -#addin "nuget:?package=Cake.FileHelpers&Version=3.3.0" +#addin "nuget:?package=SharpZipLib&Version=1.3.1" +#addin "nuget:?package=Cake.Compression&Version=0.2.6" +#addin "nuget:?package=Cake.FileHelpers&Version=4.0.1" var buildId = EnvironmentVariable("GITHUB_RUN_NUMBER") ?? EnvironmentVariable("APPVEYOR_BUILD_VERSION"); var buildRelease = EnvironmentVariable("APPVEYOR_REPO_TAG") == "true"; diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 1bcb40ab4..10f1890ab 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -5,7 +5,7 @@ - + From fbed06bf810abf8de63252d578c0e279e3ec03bb Mon Sep 17 00:00:00 2001 From: js6pak Date: Wed, 24 Mar 2021 19:08:23 +0100 Subject: [PATCH 29/72] Add icon to nuspec --- src/Impostor.Api/Impostor.Api.csproj | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Impostor.Api/Impostor.Api.csproj b/src/Impostor.Api/Impostor.Api.csproj index 86b4f09d9..4cd5e425f 100644 --- a/src/Impostor.Api/Impostor.Api.csproj +++ b/src/Impostor.Api/Impostor.Api.csproj @@ -15,12 +15,17 @@ Impostor.Api Among Us;Impostor;Impostor Plugin https://raw.githubusercontent.com/Impostor/Impostor/dev/docs/images/logo_64.png + logo_64.png https://github.com/Impostor/Impostor git https://github.com/Impostor/Impostor true + + + + From f4dc0cd403f2ee3baa9b1b82db875e7af1112976 Mon Sep 17 00:00:00 2001 From: js6pak Date: Wed, 24 Mar 2021 19:53:01 +0100 Subject: [PATCH 30/72] Revert hazel changes for easier merging with its upstream --- src/Impostor.Hazel/Connection.cs | 56 +++++++-------- src/Impostor.Hazel/ConnectionListener.cs | 28 ++++---- src/Impostor.Hazel/ConnectionState.cs | 4 +- src/Impostor.Hazel/ConnectionStatistics.cs | 67 +++++++++--------- src/Impostor.Hazel/DataReceivedEventArgs.cs | 4 +- src/Impostor.Hazel/DisconnectedEventArgs.cs | 6 +- src/Impostor.Hazel/HazelException.cs | 6 +- src/Impostor.Hazel/IPMode.cs | 8 +-- src/Impostor.Hazel/IRecyclable.cs | 2 +- src/Impostor.Hazel/Impostor.Hazel.csproj | 24 +++---- src/Impostor.Hazel/MessageReader.cs | 20 +++--- src/Impostor.Hazel/MessageWriter.cs | 46 +++++++------ src/Impostor.Hazel/NetworkConnection.cs | 16 ++--- .../NetworkConnectionListener.cs | 4 +- src/Impostor.Hazel/NewConnectionEventArgs.cs | 6 +- src/Impostor.Hazel/ObjectPoolCustom.cs | 8 +-- src/Impostor.Hazel/Udp/SendOptionInternal.cs | 2 +- .../Udp/UdpBroadcastListener.cs | 26 +++---- src/Impostor.Hazel/Udp/UdpBroadcaster.cs | 16 ++--- src/Impostor.Hazel/Udp/UdpClientConnection.cs | 15 ++-- .../Udp/UdpConnection.KeepAlive.cs | 8 +-- .../Udp/UdpConnection.Reliable.cs | 68 +++++++++---------- src/Impostor.Hazel/Udp/UdpConnection.cs | 30 ++++---- .../Udp/UdpConnectionListener.cs | 12 ++-- .../Udp/UdpConnectionRateLimit.cs | 2 +- src/Impostor.Hazel/Udp/UdpServerConnection.cs | 6 +- 26 files changed, 239 insertions(+), 251 deletions(-) diff --git a/src/Impostor.Hazel/Connection.cs b/src/Impostor.Hazel/Connection.cs index 23d7f4b69..dec8cfecb 100644 --- a/src/Impostor.Hazel/Connection.cs +++ b/src/Impostor.Hazel/Connection.cs @@ -11,7 +11,7 @@ namespace Impostor.Hazel /// /// /// - /// Connection is the base class for all connections that Hazel can make. It provides common functionality and a + /// Connection is the base class for all connections that Hazel can make. It provides common functionality and a /// standard interface to allow connections to be swapped easily. /// /// @@ -29,7 +29,7 @@ namespace Impostor.Hazel /// /// /// - /// + /// public abstract class Connection : IDisposable { private static readonly ILogger Logger = Log.ForContext(); @@ -39,34 +39,34 @@ public abstract class Connection : IDisposable /// /// /// - /// DataReceived is invoked everytime a message is received from the end point of this connection, the message - /// that was received can be found in the alongside other information from the + /// DataReceived is invoked everytime a message is received from the end point of this connection, the message + /// that was received can be found in the alongside other information from the /// event. /// /// /// /// - /// + /// /// public Func DataReceived; public int TestLagMs = -1; public int TestDropRate = 0; protected int testDropCount = 0; - + /// /// Called when the end point disconnects or an error occurs. /// /// /// - /// Disconnected is invoked when the connection is closed due to an exception occuring or because the remote - /// end point disconnected. If it was invoked due to an exception occuring then the exception is available - /// in the passed with the event. + /// Disconnected is invoked when the connection is closed due to an exception occuring or because the remote + /// end point disconnected. If it was invoked due to an exception occuring then the exception is available + /// in the passed with the event. /// /// /// /// - /// + /// /// public Func Disconnected; @@ -74,8 +74,8 @@ public abstract class Connection : IDisposable /// The remote end point of this Connection. /// /// - /// This is the end point that this connection is connected to (i.e. the other device). This returns an abstract - /// which can then be cast to an appropriate end point depending on the + /// This is the end point that this connection is connected to (i.e. the other device). This returns an abstract + /// which can then be cast to an appropriate end point depending on the /// connection type. /// public IPEndPoint EndPoint { get; protected set; } @@ -95,7 +95,7 @@ public abstract class Connection : IDisposable /// /// /// All implementers should be aware that when this is set to ConnectionState.Connected it will - /// release all threads that are blocked on . + /// release all threads that are blocked on . /// public ConnectionState State { @@ -103,7 +103,7 @@ public ConnectionState State { return this._state; } - + protected set { this._state = value; @@ -113,13 +113,13 @@ protected set protected ConnectionState _state; protected virtual void SetState(ConnectionState state) { } - + /// /// Constructor that initializes the ConnecitonStatistics object. /// /// - /// This constructor initialises with empty statistics and sets to - /// . + /// This constructor initialises with empty statistics and sets to + /// . /// protected Connection() { @@ -128,21 +128,21 @@ protected Connection() } /// - /// Sends a number of bytes to the end point of the connection using the specified . + /// Sends a number of bytes to the end point of the connection using the specified . /// /// The message to send. /// /// /// /// The messageType parameter is only a request to use those options and the actual method used to send the - /// data is up to the implementation. There are circumstances where this parameter may be ignored but in + /// data is up to the implementation. There are circumstances where this parameter may be ignored but in /// general any implementer should aim to always follow the user's request. /// /// public abstract ValueTask SendAsync(IMessageWriter msg); /// - /// Sends a number of bytes to the end point of the connection using the specified . + /// Sends a number of bytes to the end point of the connection using the specified . /// /// The bytes of the message to send. /// The option specifying how the message should be sent. @@ -150,7 +150,7 @@ protected Connection() /// /// /// The messageType parameter is only a request to use those options and the actual method used to send the - /// data is up to the implementation. There are circumstances where this parameter may be ignored but in + /// data is up to the implementation. There are circumstances where this parameter may be ignored but in /// general any implementer should aim to always follow the user's request. /// /// @@ -167,9 +167,9 @@ protected Connection() /// Invokes the DataReceived event. /// /// The bytes received. - /// The the message was received with. + /// The the message was received with. /// - /// Invokes the event on this connection to alert subscribers a new message has been + /// Invokes the event on this connection to alert subscribers a new message has been /// received. The bytes and the send option that the message was sent with should be passed in to give to the /// subscribers. /// @@ -197,8 +197,8 @@ protected async ValueTask InvokeDataReceived(IMessageReader msg, MessageType mes /// The exception, if any, that occurred to cause this. /// Extra disconnect data /// - /// Invokes the event to alert subscribres this connection has been disconnected either - /// by the end point or because an error occurred. If an error occurred the error should be passed in in order to + /// Invokes the event to alert subscribres this connection has been disconnected either + /// by the end point or because an error occurred. If an error occurred the error should be passed in in order to /// pass to the subscribers, otherwise null can be passed in. /// protected async ValueTask InvokeDisconnected(string e, IMessageReader reader) @@ -219,11 +219,11 @@ protected async ValueTask InvokeDisconnected(string e, IMessageReader reader) } /// - /// For times when you want to force the disconnect handler to fire as well as close it. - /// If you only want to close it, just use Dispose. + /// For times when you want to force the disconnect handler to fire as well as close it. + /// If you only want to close it, just use Dispose. /// public abstract ValueTask Disconnect(string reason, MessageWriter writer = null); - + /// /// Disposes of this NetworkConnection. /// diff --git a/src/Impostor.Hazel/ConnectionListener.cs b/src/Impostor.Hazel/ConnectionListener.cs index 6c2f942ff..116f657e4 100644 --- a/src/Impostor.Hazel/ConnectionListener.cs +++ b/src/Impostor.Hazel/ConnectionListener.cs @@ -10,16 +10,16 @@ namespace Impostor.Hazel /// /// /// - /// ConnectionListeners are server side objects that listen for clients and create matching server side connections + /// ConnectionListeners are server side objects that listen for clients and create matching server side connections /// for each client in a similar way to TCP does. These connections should be ready for communication immediately. /// /// - /// Each time a client connects the event will be invoked to alert all subscribers to - /// the new connection. A disconnected event is then present on the that is passed to the + /// Each time a client connects the event will be invoked to alert all subscribers to + /// the new connection. A disconnected event is then present on the that is passed to the /// subscribers. /// /// - /// + /// public abstract class ConnectionListener : IAsyncDisposable { private static readonly ILogger Logger = Log.ForContext(); @@ -29,18 +29,18 @@ public abstract class ConnectionListener : IAsyncDisposable /// /// /// - /// NewConnection is invoked each time a client connects to the listener. The - /// contains the new for communication with this + /// NewConnection is invoked each time a client connects to the listener. The + /// contains the new for communication with this /// client. /// /// - /// Hazel may or may not store connections so it is your responsibility to keep track and properly Dispose of - /// connections to your server. + /// Hazel may or may not store connections so it is your responsibility to keep track and properly Dispose of + /// connections to your server. /// /// /// /// - /// + /// /// public Func NewConnection; @@ -49,15 +49,15 @@ public abstract class ConnectionListener : IAsyncDisposable /// /// /// - /// This instructs the listener to begin listening for new clients connecting to the server. When a new client - /// connects the event will be invoked containing the connection to the new client. + /// This instructs the listener to begin listening for new clients connecting to the server. When a new client + /// connects the event will be invoked containing the connection to the new client. /// /// - /// To stop listening you should call . + /// To stop listening you should call . /// /// /// - /// + /// /// public abstract Task StartAsync(); @@ -67,7 +67,7 @@ public abstract class ConnectionListener : IAsyncDisposable /// The user sent bytes that were received as part of the handshake. /// The connection to pass in the arguments. /// - /// Implementers should call this to invoke the event before data is received so that + /// Implementers should call this to invoke the event before data is received so that /// subscribers do not miss any data that may have been sent immediately after connecting. /// internal async Task InvokeNewConnection(IMessageReader msg, Connection connection) diff --git a/src/Impostor.Hazel/ConnectionState.cs b/src/Impostor.Hazel/ConnectionState.cs index c9fd4de0f..5dd7c6a07 100644 --- a/src/Impostor.Hazel/ConnectionState.cs +++ b/src/Impostor.Hazel/ConnectionState.cs @@ -1,7 +1,7 @@ namespace Impostor.Hazel { /// - /// Represents the state a is currently in. + /// Represents the state a is currently in. /// public enum ConnectionState { @@ -9,7 +9,7 @@ public enum ConnectionState /// The Connection has either not been established yet or has been disconnected. /// NotConnected, - + /// /// The Connection is currently connecting to an endpoint. /// diff --git a/src/Impostor.Hazel/ConnectionStatistics.cs b/src/Impostor.Hazel/ConnectionStatistics.cs index cd7567cf0..48026208e 100644 --- a/src/Impostor.Hazel/ConnectionStatistics.cs +++ b/src/Impostor.Hazel/ConnectionStatistics.cs @@ -2,13 +2,12 @@ using System.Threading; [assembly: InternalsVisibleTo("Hazel.Tests")] - namespace Impostor.Hazel { /// - /// Holds statistics about the traffic through a . + /// Holds statistics about the traffic through a . /// - /// + /// public class ConnectionStatistics { private const int ExpectedMTU = 1200; @@ -28,8 +27,8 @@ public int MessagesSent /// The number of messages sent larger than 576 bytes. This is smaller than most default MTUs. /// /// - /// This is the number of unreliable messages that were sent from the , incremented - /// each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not + /// This is the number of unreliable messages that were sent from the , incremented + /// each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not /// counted and messages are only counted once all other operations in the send are complete. /// public int FragmentableMessagesSent @@ -49,8 +48,8 @@ public int FragmentableMessagesSent /// The number of unreliable messages sent. /// /// - /// This is the number of unreliable messages that were sent from the , incremented - /// each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not + /// This is the number of unreliable messages that were sent from the , incremented + /// each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not /// counted and messages are only counted once all other operations in the send are complete. /// public int UnreliableMessagesSent @@ -70,8 +69,8 @@ public int UnreliableMessagesSent /// The number of reliable messages sent. /// /// - /// This is the number of reliable messages that were sent from the , incremented - /// each time that LogReliableSend is called by the Connection. Messages that caused an error are not + /// This is the number of reliable messages that were sent from the , incremented + /// each time that LogReliableSend is called by the Connection. Messages that caused an error are not /// counted and messages are only counted once all other operations in the send are complete. /// public int ReliableMessagesSent @@ -91,8 +90,8 @@ public int ReliableMessagesSent /// The number of fragmented messages sent. /// /// - /// This is the number of fragmented messages that were sent from the , incremented - /// each time that LogFragmentedSend is called by the Connection. Messages that caused an error are not + /// This is the number of fragmented messages that were sent from the , incremented + /// each time that LogFragmentedSend is called by the Connection. Messages that caused an error are not /// counted and messages are only counted once all other operations in the send are complete. /// public int FragmentedMessagesSent @@ -112,8 +111,8 @@ public int FragmentedMessagesSent /// The number of acknowledgement messages sent. /// /// - /// This is the number of acknowledgements that were sent from the , incremented - /// each time that LogAcknowledgementSend is called by the Connection. Messages that caused an error are not + /// This is the number of acknowledgements that were sent from the , incremented + /// each time that LogAcknowledgementSend is called by the Connection. Messages that caused an error are not /// counted and messages are only counted once all other operations in the send are complete. /// public int AcknowledgementMessagesSent @@ -133,8 +132,8 @@ public int AcknowledgementMessagesSent /// The number of hello messages sent. /// /// - /// This is the number of hello messages that were sent from the , incremented - /// each time that LogHelloSend is called by the Connection. Messages that caused an error are not + /// This is the number of hello messages that were sent from the , incremented + /// each time that LogHelloSend is called by the Connection. Messages that caused an error are not /// counted and messages are only counted once all other operations in the send are complete. /// public int HelloMessagesSent @@ -155,12 +154,12 @@ public int HelloMessagesSent /// /// /// - /// This is the number of bytes of data (i.e. user bytes) that were sent from the , - /// accumulated each time that LogSend is called by the Connection. Messages that caused an error are not + /// This is the number of bytes of data (i.e. user bytes) that were sent from the , + /// accumulated each time that LogSend is called by the Connection. Messages that caused an error are not /// counted and messages are only counted once all other operations in the send are complete. /// /// - /// For the number of bytes including protocol bytes see . + /// For the number of bytes including protocol bytes see . /// /// public long DataBytesSent @@ -181,13 +180,13 @@ public long DataBytesSent /// /// /// - /// This is the total number of bytes (the data bytes plus protocol bytes) that were sent from the - /// , accumulated each time that LogSend is called by the Connection. Messages that - /// caused an error are not counted and messages are only counted once all other operations in the send are + /// This is the total number of bytes (the data bytes plus protocol bytes) that were sent from the + /// , accumulated each time that LogSend is called by the Connection. Messages that + /// caused an error are not counted and messages are only counted once all other operations in the send are /// complete. /// /// - /// For the number of data bytes excluding protocol bytes see . + /// For the number of data bytes excluding protocol bytes see . /// /// public long TotalBytesSent @@ -213,12 +212,12 @@ public int MessagesReceived return UnreliableMessagesReceived + ReliableMessagesReceived + FragmentedMessagesReceived + AcknowledgementMessagesReceived + helloMessagesReceived; } } - + /// /// The number of unreliable messages received. /// /// - /// This is the number of unreliable messages that were received by the , incremented + /// This is the number of unreliable messages that were received by the , incremented /// each time that LogUnreliableReceive is called by the Connection. Messages are counted before the receive event is invoked. /// public int UnreliableMessagesReceived @@ -238,7 +237,7 @@ public int UnreliableMessagesReceived /// The number of reliable messages received. /// /// - /// This is the number of reliable messages that were received by the , incremented + /// This is the number of reliable messages that were received by the , incremented /// each time that LogReliableReceive is called by the Connection. Messages are counted before the receive event is invoked. /// public int ReliableMessagesReceived @@ -258,7 +257,7 @@ public int ReliableMessagesReceived /// The number of fragmented messages received. /// /// - /// This is the number of fragmented messages that were received by the , incremented + /// This is the number of fragmented messages that were received by the , incremented /// each time that LogFragmentedReceive is called by the Connection. Messages are counted before the receive event is invoked. /// public int FragmentedMessagesReceived @@ -278,7 +277,7 @@ public int FragmentedMessagesReceived /// The number of acknowledgement messages received. /// /// - /// This is the number of acknowledgement messages that were received by the , incremented + /// This is the number of acknowledgement messages that were received by the , incremented /// each time that LogAcknowledgemntReceive is called by the Connection. Messages are counted before the receive event is invoked. /// public int AcknowledgementMessagesReceived @@ -298,7 +297,7 @@ public int AcknowledgementMessagesReceived /// The number of ping messages received. /// /// - /// This is the number of hello messages that were received by the , incremented + /// This is the number of hello messages that were received by the , incremented /// each time that LogHelloReceive is called by the Connection. Messages are counted before the receive event is invoked. /// public int PingMessagesReceived @@ -318,7 +317,7 @@ public int PingMessagesReceived /// The number of hello messages received. /// /// - /// This is the number of hello messages that were received by the , incremented + /// This is the number of hello messages that were received by the , incremented /// each time that LogHelloReceive is called by the Connection. Messages are counted before the receive event is invoked. /// public int HelloMessagesReceived @@ -339,12 +338,12 @@ public int HelloMessagesReceived /// /// /// - /// This is the number of bytes of data (i.e. user bytes) that were received by the , + /// This is the number of bytes of data (i.e. user bytes) that were received by the , /// accumulated each time that LogReceive is called by the Connection. Messages are counted before the receive /// event is invoked. /// /// - /// For the number of bytes including protocol bytes see . + /// For the number of bytes including protocol bytes see . /// /// public long DataBytesReceived @@ -365,12 +364,12 @@ public long DataBytesReceived /// /// /// - /// This is the total number of bytes (the data bytes plus protocol bytes) that were received by the - /// , accumulated each time that LogReceive is called by the Connection. Messages are + /// This is the total number of bytes (the data bytes plus protocol bytes) that were received by the + /// , accumulated each time that LogReceive is called by the Connection. Messages are /// counted before the receive event is invoked. /// /// - /// For the number of data bytes excluding protocol bytes see . + /// For the number of data bytes excluding protocol bytes see . /// /// public long TotalBytesReceived diff --git a/src/Impostor.Hazel/DataReceivedEventArgs.cs b/src/Impostor.Hazel/DataReceivedEventArgs.cs index d2259e58e..9176d8d93 100644 --- a/src/Impostor.Hazel/DataReceivedEventArgs.cs +++ b/src/Impostor.Hazel/DataReceivedEventArgs.cs @@ -12,10 +12,10 @@ public struct DataReceivedEventArgs public readonly IMessageReader Message; /// - /// The the data was sent with. + /// The the data was sent with. /// public readonly MessageType Type; - + public DataReceivedEventArgs(Connection sender, IMessageReader msg, MessageType type) { this.Sender = sender; diff --git a/src/Impostor.Hazel/DisconnectedEventArgs.cs b/src/Impostor.Hazel/DisconnectedEventArgs.cs index 4872aea97..d46df4b9c 100644 --- a/src/Impostor.Hazel/DisconnectedEventArgs.cs +++ b/src/Impostor.Hazel/DisconnectedEventArgs.cs @@ -6,13 +6,13 @@ namespace Impostor.Hazel public class DisconnectedEventArgs : EventArgs { /// - /// Optional disconnect reason. May be null. + /// Optional disconnect reason. May be null. /// public readonly string Reason; /// - /// Optional data sent with a disconnect message. May be null. - /// You must not recycle this. If you need the message outside of a callback, you should copy it. + /// Optional data sent with a disconnect message. May be null. + /// You must not recycle this. If you need the message outside of a callback, you should copy it. /// public readonly IMessageReader Message; diff --git a/src/Impostor.Hazel/HazelException.cs b/src/Impostor.Hazel/HazelException.cs index 81c8017a8..8c6fc3c12 100644 --- a/src/Impostor.Hazel/HazelException.cs +++ b/src/Impostor.Hazel/HazelException.cs @@ -8,12 +8,14 @@ namespace Impostor.Hazel [Serializable] public class HazelException : Exception { - internal HazelException(string msg) : base(msg) + internal HazelException(string msg) : base (msg) { + } - internal HazelException(string msg, Exception e) : base(msg, e) + internal HazelException(string msg, Exception e) : base (msg, e) { + } } } diff --git a/src/Impostor.Hazel/IPMode.cs b/src/Impostor.Hazel/IPMode.cs index 3f4395841..5eb6679e5 100644 --- a/src/Impostor.Hazel/IPMode.cs +++ b/src/Impostor.Hazel/IPMode.cs @@ -4,8 +4,8 @@ /// Represents the IP version that a connection or listener will use. /// /// - /// If you wand a client to connect or be able to connect using IPv6 then you should use , - /// this sets the underlying sockets to use IPv6 but still allow IPv4 sockets to connect for backwards compatability + /// If you wand a client to connect or be able to connect using IPv6 then you should use , + /// this sets the underlying sockets to use IPv6 but still allow IPv4 sockets to connect for backwards compatability /// and hence it is the default IPMode in most cases. /// public enum IPMode @@ -16,9 +16,9 @@ public enum IPMode IPv4, /// - /// Instruction to use IPv6 only, IPv4 connections will not be able to connect. IPv4 addresses can be connected + /// Instruction to use IPv6 only, IPv4 connections will not be able to connect. IPv4 addresses can be connected /// by converting to IPv6 addresses. /// - IPv6, + IPv6 } } diff --git a/src/Impostor.Hazel/IRecyclable.cs b/src/Impostor.Hazel/IRecyclable.cs index 0ddc04cd1..69be1225b 100644 --- a/src/Impostor.Hazel/IRecyclable.cs +++ b/src/Impostor.Hazel/IRecyclable.cs @@ -3,7 +3,7 @@ /// /// Interface for all items that can be returned to an object pool. /// - /// + /// public interface IRecyclable { /// diff --git a/src/Impostor.Hazel/Impostor.Hazel.csproj b/src/Impostor.Hazel/Impostor.Hazel.csproj index 7ab52af6f..00997697c 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/MessageReader.cs b/src/Impostor.Hazel/MessageReader.cs index 969e41b04..317e45b1e 100644 --- a/src/Impostor.Hazel/MessageReader.cs +++ b/src/Impostor.Hazel/MessageReader.cs @@ -78,7 +78,7 @@ public IMessageReader ReadMessage() public bool ReadBoolean() { - var val = FastByte(); + byte val = FastByte(); return val != 0; } @@ -159,13 +159,13 @@ public int ReadPackedInt32() public uint ReadPackedUInt32() { - var readMore = true; - var shift = 0; + bool readMore = true; + int shift = 0; uint output = 0; while (readMore) { - var b = FastByte(); + byte b = FastByte(); if (b >= 0x80) { readMore = true; @@ -185,8 +185,8 @@ public uint ReadPackedUInt32() public void CopyTo(IMessageWriter writer) { - writer.Write((ushort)Length); - writer.Write((byte)Tag); + writer.Write((ushort) Length); + writer.Write((byte) Tag); writer.Write(Buffer.AsMemory(Offset, Length)); } @@ -213,7 +213,7 @@ public void RemoveMessage(IMessageReader message) System.Buffer.BlockCopy(Buffer, offsetEnd, Buffer, offsetStart, lengthToCopy); - ((MessageReader)message).Parent.AdjustLength(message.Offset, message.Length + 3); + ((MessageReader) message).Parent.AdjustLength(message.Offset, message.Length + 3); } private void AdjustLength(int offset, int amount) @@ -255,9 +255,9 @@ public T ReadNetObject(IGame game) where T : IInnerNetObject public Vector2 ReadVector2() { const float range = 50f; - - var x = ReadUInt16() / (float)ushort.MaxValue; - var y = ReadUInt16() / (float)ushort.MaxValue; + + var x = ReadUInt16() / (float) ushort.MaxValue; + var y = ReadUInt16() / (float) ushort.MaxValue; return new Vector2(Mathf.Lerp(-range, range, x), Mathf.Lerp(-range, range, y)); } diff --git a/src/Impostor.Hazel/MessageWriter.cs b/src/Impostor.Hazel/MessageWriter.cs index bb71a71b5..a7b57e78e 100644 --- a/src/Impostor.Hazel/MessageWriter.cs +++ b/src/Impostor.Hazel/MessageWriter.cs @@ -1,11 +1,12 @@ -using System; +using Impostor.Api.Games; +using Impostor.Api.Net.Messages; + +using System; using System.Collections.Generic; using System.Net; using System.Numerics; using System.Text; -using Impostor.Api.Games; using Impostor.Api.Net.Inner; -using Impostor.Api.Net.Messages; using Impostor.Api.Unity; namespace Impostor.Hazel @@ -38,7 +39,7 @@ public byte[] ToByteArray(bool includeHeader) { if (includeHeader) { - var output = new byte[this.Length]; + byte[] output = new byte[this.Length]; System.Buffer.BlockCopy(this.Buffer, 0, output, 0, this.Length); return output; } @@ -47,17 +48,17 @@ public byte[] ToByteArray(bool includeHeader) switch (this.SendOption) { case MessageType.Reliable: - { - var output = new byte[this.Length - 3]; - System.Buffer.BlockCopy(this.Buffer, 3, output, 0, this.Length - 3); - return output; - } + { + byte[] output = new byte[this.Length - 3]; + System.Buffer.BlockCopy(this.Buffer, 3, output, 0, this.Length - 3); + return output; + } case MessageType.Unreliable: - { - var output = new byte[this.Length - 1]; - System.Buffer.BlockCopy(this.Buffer, 1, output, 0, this.Length - 1); - return output; - } + { + byte[] output = new byte[this.Length - 1]; + System.Buffer.BlockCopy(this.Buffer, 1, output, 0, this.Length - 1); + return output; + } default: throw new ArgumentOutOfRangeException(); } @@ -66,6 +67,7 @@ public byte[] ToByteArray(bool includeHeader) throw new NotImplementedException(); } + /// /// The option specifying how the message should be sent. public static MessageWriter Get(MessageType sendOption = MessageType.Unreliable) { @@ -104,8 +106,8 @@ public void Write(IInnerNetObject innerNetObject) public void Write(Vector2 vector) { - Write((ushort)(Mathf.ReverseLerp(vector.X) * (double)ushort.MaxValue)); - Write((ushort)(Mathf.ReverseLerp(vector.Y) * (double)ushort.MaxValue)); + Write((ushort)(Mathf.ReverseLerp(vector.X) * (double) ushort.MaxValue)); + Write((ushort)(Mathf.ReverseLerp(vector.Y) * (double) ushort.MaxValue)); } /// @@ -120,7 +122,7 @@ public void StartMessage(byte typeFlag) public void EndMessage() { var lastMessageStart = messageStarts.Pop(); - var length = (ushort)(this.Position - lastMessageStart - 3); // Minus length and type byte + ushort length = (ushort)(this.Position - lastMessageStart - 3); // Minus length and type byte this.Buffer[lastMessageStart] = (byte)length; this.Buffer[lastMessageStart + 1] = (byte)(length >> 8); } @@ -213,7 +215,7 @@ public unsafe void Write(float value) { fixed (byte* ptr = &this.Buffer[this.Position]) { - var valuePtr = (byte*)&value; + byte* valuePtr = (byte*)&value; *ptr = *valuePtr; *(ptr + 1) = *(valuePtr + 1); @@ -300,7 +302,7 @@ public void WritePacked(uint value) { do { - var b = (byte)(value & 0xFF); + byte b = (byte)(value & 0xFF); if (value >= 0x80) { b |= 0x80; @@ -315,7 +317,7 @@ public void WritePacked(uint value) public void Write(MessageWriter msg, bool includeHeader) { - var offset = 0; + int offset = 0; if (!includeHeader) { switch (msg.SendOption) @@ -338,8 +340,8 @@ public unsafe static bool IsLittleEndian() byte b; unsafe { - var i = 1; - var bp = (byte*)&i; + int i = 1; + byte* bp = (byte*)&i; b = *bp; } diff --git a/src/Impostor.Hazel/NetworkConnection.cs b/src/Impostor.Hazel/NetworkConnection.cs index b530f017d..9e81c5cc0 100644 --- a/src/Impostor.Hazel/NetworkConnection.cs +++ b/src/Impostor.Hazel/NetworkConnection.cs @@ -12,17 +12,17 @@ public enum HazelInternalErrors ReceivedZeroBytes, PingsWithoutResponse, ReliablePacketWithoutResponse, - ConnectionDisconnected, + ConnectionDisconnected } /// - /// Abstract base class for a to a remote end point via a network protocol like TCP or UDP. + /// Abstract base class for a to a remote end point via a network protocol like TCP or UDP. /// - /// + /// public abstract class NetworkConnection : Connection { /// - /// An event that gives us a chance to send well-formed disconnect messages to clients when an internal disconnect happens. + /// An event that gives us a chance to send well-formed disconnect messages to clients when an internal disconnect happens. /// public Func OnInternalDisconnect; @@ -30,8 +30,8 @@ public abstract class NetworkConnection : Connection /// The remote end point of this connection. /// /// - /// This is the end point of the other device given as an rather than a generic - /// as the base does. + /// This is the end point of the other device given as an rather than a generic + /// as the base does. /// public IPEndPoint RemoteEndPoint { get; protected set; } @@ -67,14 +67,14 @@ protected async ValueTask DisconnectRemote(string reason, IMessageReader reader) } /// - /// Called when socket is disconnected internally + /// Called when socket is disconnected internally /// internal async ValueTask DisconnectInternal(HazelInternalErrors error, string reason) { var handler = this.OnInternalDisconnect; if (handler != null) { - var messageToRemote = handler(error); + MessageWriter messageToRemote = handler(error); if (messageToRemote != null) { try diff --git a/src/Impostor.Hazel/NetworkConnectionListener.cs b/src/Impostor.Hazel/NetworkConnectionListener.cs index e2824b1c9..e1d7ffaf8 100644 --- a/src/Impostor.Hazel/NetworkConnectionListener.cs +++ b/src/Impostor.Hazel/NetworkConnectionListener.cs @@ -3,9 +3,9 @@ namespace Impostor.Hazel { /// - /// Abstract base class for a for network based connections. + /// Abstract base class for a for network based connections. /// - /// + /// public abstract class NetworkConnectionListener : ConnectionListener { /// diff --git a/src/Impostor.Hazel/NewConnectionEventArgs.cs b/src/Impostor.Hazel/NewConnectionEventArgs.cs index 77ec05de2..be9e7a214 100644 --- a/src/Impostor.Hazel/NewConnectionEventArgs.cs +++ b/src/Impostor.Hazel/NewConnectionEventArgs.cs @@ -5,13 +5,13 @@ namespace Impostor.Hazel public struct NewConnectionEventArgs { /// - /// The data received from the client in the handshake. - /// This data is yours. Remember to recycle it. + /// The data received from the client in the handshake. + /// This data is yours. Remember to recycle it. /// public readonly IMessageReader HandshakeData; /// - /// The to the new client. + /// The to the new client. /// public readonly Connection Connection; diff --git a/src/Impostor.Hazel/ObjectPoolCustom.cs b/src/Impostor.Hazel/ObjectPoolCustom.cs index f1256eb61..5c9ef9b40 100644 --- a/src/Impostor.Hazel/ObjectPoolCustom.cs +++ b/src/Impostor.Hazel/ObjectPoolCustom.cs @@ -8,7 +8,7 @@ namespace Impostor.Hazel /// A fairly simple object pool for items that will be created a lot. /// /// The type that is pooled. - /// + /// public sealed class ObjectPoolCustom where T : IRecyclable { private int numberCreated; @@ -32,7 +32,7 @@ public sealed class ObjectPoolCustom where T : IRecyclable /// /// private readonly Func objectFactory; - + /// /// Internal constructor for our ObjectPool. /// @@ -48,7 +48,7 @@ internal ObjectPoolCustom(Func objectFactory) internal T GetObject() { #if HAZEL_BAG - if (!pool.TryTake(out var item)) + if (!pool.TryTake(out T item)) { Interlocked.Increment(ref numberCreated); item = objectFactory.Invoke(); @@ -85,7 +85,7 @@ internal T GetObject() /// The item to return. internal void PutObject(T item) { - if (inuse.TryRemove(item, out var b)) + if (inuse.TryRemove(item, out bool b)) { #if HAZEL_BAG pool.Add(item); diff --git a/src/Impostor.Hazel/Udp/SendOptionInternal.cs b/src/Impostor.Hazel/Udp/SendOptionInternal.cs index 11baa854f..c0c4e2127 100644 --- a/src/Impostor.Hazel/Udp/SendOptionInternal.cs +++ b/src/Impostor.Hazel/Udp/SendOptionInternal.cs @@ -11,7 +11,7 @@ public enum UdpSendOption : byte Hello = 8, /// - /// A single byte of continued existence + /// A single byte of continued existence /// Ping = 12, diff --git a/src/Impostor.Hazel/Udp/UdpBroadcastListener.cs b/src/Impostor.Hazel/Udp/UdpBroadcastListener.cs index 3c768efc3..ed7b68dbd 100644 --- a/src/Impostor.Hazel/Udp/UdpBroadcastListener.cs +++ b/src/Impostor.Hazel/Udp/UdpBroadcastListener.cs @@ -89,21 +89,21 @@ private void HandleData(IAsyncResult result) return; } - if (numBytes < 3 + if (numBytes < 3 || buffer[0] != 4 || buffer[1] != 2) { this.StartListen(); return; } - var ipEnd = (IPEndPoint)endpt; - var data = UTF8Encoding.UTF8.GetString(buffer, 2, numBytes - 2); - var dataHash = data.GetHashCode(); + IPEndPoint ipEnd = (IPEndPoint)endpt; + string data = UTF8Encoding.UTF8.GetString(buffer, 2, numBytes - 2); + int dataHash = data.GetHashCode(); lock (packets) { - var found = false; - for (var i = 0; i < this.packets.Count; ++i) + bool found = false; + for (int i = 0; i < this.packets.Count; ++i) { var pkt = this.packets[i]; if (pkt == null || pkt.Data == null) @@ -146,17 +146,11 @@ public void Dispose() { if (this.socket != null) { - try { this.socket.Shutdown(SocketShutdown.Both); } - catch { } - - try { this.socket.Close(); } - catch { } - - try { this.socket.Dispose(); } - catch { } - + try { this.socket.Shutdown(SocketShutdown.Both); } catch { } + try { this.socket.Close(); } catch { } + try { this.socket.Dispose(); } catch { } this.socket = null; } } } -} +} \ No newline at end of file diff --git a/src/Impostor.Hazel/Udp/UdpBroadcaster.cs b/src/Impostor.Hazel/Udp/UdpBroadcaster.cs index 32f0e187a..5fa1ccac2 100644 --- a/src/Impostor.Hazel/Udp/UdpBroadcaster.cs +++ b/src/Impostor.Hazel/Udp/UdpBroadcaster.cs @@ -26,7 +26,7 @@ public UdpBroadcaster(int port, Action logger = null) /// public void SetData(string data) { - var len = UTF8Encoding.UTF8.GetByteCount(data); + int len = UTF8Encoding.UTF8.GetByteCount(data); this.data = new byte[len + 2]; this.data[0] = 4; this.data[1] = 2; @@ -69,17 +69,11 @@ public void Dispose() { if (this.socket != null) { - try { this.socket.Shutdown(SocketShutdown.Both); } - catch { } - - try { this.socket.Close(); } - catch { } - - try { this.socket.Dispose(); } - catch { } - + try { this.socket.Shutdown(SocketShutdown.Both); } catch { } + try { this.socket.Close(); } catch { } + try { this.socket.Dispose(); } catch { } this.socket = null; } } } -} +} \ No newline at end of file diff --git a/src/Impostor.Hazel/Udp/UdpClientConnection.cs b/src/Impostor.Hazel/Udp/UdpClientConnection.cs index cb27e2400..5125ebe80 100644 --- a/src/Impostor.Hazel/Udp/UdpClientConnection.cs +++ b/src/Impostor.Hazel/Udp/UdpClientConnection.cs @@ -1,7 +1,9 @@ using System; +using System.Buffers; using System.Net; using System.Net.Sockets; using System.Threading; +using System.Threading.Channels; using System.Threading.Tasks; using Impostor.Api.Net.Messages; using Microsoft.Extensions.ObjectPool; @@ -12,7 +14,7 @@ namespace Impostor.Hazel.Udp /// /// Represents a client's connection to a server that uses the UDP protocol. /// - /// + /// public sealed class UdpClientConnection : UdpConnection { private static readonly ILogger Logger = Log.ForContext(); @@ -29,7 +31,7 @@ public sealed class UdpClientConnection : UdpConnection /// /// Creates a new UdpClientConnection. /// - /// A to connect to. + /// A to connect to. public UdpClientConnection(IPEndPoint remoteEndPoint, ObjectPool readerPool, IPMode ipMode = IPMode.IPv4) : base(null, readerPool) { EndPoint = remoteEndPoint; @@ -38,7 +40,7 @@ public UdpClientConnection(IPEndPoint remoteEndPoint, ObjectPool _socket = new UdpClient { - DontFragment = false, + DontFragment = false }; _reliablePacketTimer = new Timer(ManageReliablePacketsInternal, null, 100, Timeout.Infinite); @@ -211,11 +213,8 @@ protected override void Dispose(bool disposing) { State = ConnectionState.NotConnected; - try { _socket.Close(); } - catch { } - - try { _socket.Dispose(); } - catch { } + try { _socket.Close(); } catch { } + try { _socket.Dispose(); } catch { } _reliablePacketTimer.Dispose(); _connectWaitLock.Dispose(); diff --git a/src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs b/src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs index e8303a4e7..a73291bc4 100644 --- a/src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs +++ b/src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs @@ -8,6 +8,7 @@ namespace Impostor.Hazel.Udp { partial class UdpConnection { + /// /// Class to hold packet data /// @@ -57,7 +58,6 @@ public int KeepAliveInterval ResetKeepAliveTimer(); } } - private int keepAliveInterval = 1500; public int MissingPingsUntilDisconnect { get; set; } = 6; @@ -109,9 +109,9 @@ private async void HandleKeepAlive(object state) // pings should cause a disconnect. private async ValueTask SendPing() { - var id = (ushort)Interlocked.Increment(ref lastIDAllocated); + ushort id = (ushort)Interlocked.Increment(ref lastIDAllocated); - var bytes = new byte[3]; + byte[] bytes = new byte[3]; bytes[0] = (byte)UdpSendOption.Ping; bytes[1] = (byte)(id >> 8); bytes[2] = (byte)id; @@ -164,4 +164,4 @@ private void DisposeKeepAliveTimer() } } } -} +} \ No newline at end of file diff --git a/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs b/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs index 9c13f22df..7f439269d 100644 --- a/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs +++ b/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs @@ -15,25 +15,25 @@ partial class UdpConnection /// /// /// - /// For reliable delivery data is resent at specified intervals unless an acknowledgement is received from the + /// For reliable delivery data is resent at specified intervals unless an acknowledgement is received from the /// receiving device. The ResendTimeout specifies the interval between the packets being resent, each time a packet - /// is resent the interval is increased for that packet until the duration exceeds the value. + /// is resent the interval is increased for that packet until the duration exceeds the value. /// /// - /// Setting this to its default of 0 will mean the timeout is 2 times the value of the average ping, usually + /// Setting this to its default of 0 will mean the timeout is 2 times the value of the average ping, usually /// resulting in a more dynamic resend that responds to endpoints on slower or faster connections. /// /// public volatile int ResendTimeout = 0; /// - /// Max number of times to resend. 0 == no limit + /// Max number of times to resend. 0 == no limit /// public volatile int ResendLimit = 0; /// - /// A compounding multiplier to back off resend timeout. - /// Applied to ping before first timeout when ResendTimeout == 0. + /// A compounding multiplier to back off resend timeout. + /// Applied to ping before first timeout when ResendTimeout == 0. /// public volatile float ResendPingMultiplier = 2; @@ -48,7 +48,7 @@ partial class UdpConnection internal ConcurrentDictionary reliableDataPacketsSent = new ConcurrentDictionary(); /// - /// Packet ids that have not been received, but are expected. + /// Packet ids that have not been received, but are expected. /// private HashSet reliableDataPacketsMissing = new HashSet(); @@ -63,7 +63,7 @@ partial class UdpConnection /// Returns the average ping to this endpoint. /// /// - /// This returns the average ping for a one-way trip as calculated from the reliable packets that have been sent + /// This returns the average ping for a one-way trip as calculated from the reliable packets that have been sent /// and acknowledged by the endpoint. /// public float AveragePingMs = 500; @@ -72,7 +72,7 @@ partial class UdpConnection /// The maximum times a message should be resent before marking the endpoint as disconnected. /// /// - /// Reliable packets will be resent at an interval defined in for the number of times + /// Reliable packets will be resent at an interval defined in for the number of times /// specified here. Once a packet has been retransmitted this number of times and has not been acknowledged the /// connection will be marked as disconnected and the Disconnected event /// will be invoked. @@ -136,10 +136,10 @@ public async ValueTask Resend() var connection = this.Connection; if (!this.Acknowledged && connection != null) { - var lifetime = this.Stopwatch.ElapsedMilliseconds; + long lifetime = this.Stopwatch.ElapsedMilliseconds; if (lifetime >= connection.DisconnectTimeout) { - if (connection.reliableDataPacketsSent.TryRemove(this.Id, out var self)) + if (connection.reliableDataPacketsSent.TryRemove(this.Id, out Packet self)) { await connection.DisconnectInternal(HazelInternalErrors.ReliablePacketWithoutResponse, $"Reliable packet {self.Id} (size={this.Length}) was not ack'd after {lifetime}ms ({self.Retransmissions} resends)"); @@ -155,7 +155,7 @@ public async ValueTask Resend() if (connection.ResendLimit != 0 && this.Retransmissions > connection.ResendLimit) { - if (connection.reliableDataPacketsSent.TryRemove(this.Id, out var self)) + if (connection.reliableDataPacketsSent.TryRemove(this.Id, out Packet self)) { await connection.DisconnectInternal(HazelInternalErrors.ReliablePacketWithoutResponse, $"Reliable packet {self.Id} (size={this.Length}) was not ack'd after {self.Retransmissions} resends ({lifetime}ms)"); @@ -196,12 +196,12 @@ public void Recycle() internal async ValueTask ManageReliablePackets() { - var output = 0; + int output = 0; if (this.reliableDataPacketsSent.Count > 0) { foreach (var kvp in this.reliableDataPacketsSent) { - var pkt = kvp.Value; + Packet pkt = kvp.Value; try { @@ -222,12 +222,12 @@ internal async ValueTask ManageReliablePackets() /// The callback to make once the packet has been acknowledged. protected void AttachReliableID(byte[] buffer, int offset, int sendLength, Action ackCallback = null) { - var id = (ushort)Interlocked.Increment(ref lastIDAllocated); + ushort id = (ushort)Interlocked.Increment(ref lastIDAllocated); buffer[offset] = (byte)(id >> 8); buffer[offset + 1] = (byte)id; - var packet = Packet.GetObject(); + Packet packet = Packet.GetObject(); packet.Set( id, this, @@ -260,7 +260,7 @@ private async ValueTask ReliableSend(byte sendOption, byte[] data, Action ackCal //Inform keepalive not to send for a while ResetKeepAliveTimer(); - var bytes = new byte[data.Length + 3]; + byte[] bytes = new byte[data.Length + 3]; //Add message type bytes[0] = sendOption; @@ -333,35 +333,35 @@ private async ValueTask ProcessReliableReceive(ReadOnlyMemory bytes, * * So... */ - + var result = true; lock (reliableDataPacketsMissing) { //Calculate overwritePointer - var overwritePointer = (ushort)(reliableReceiveLast - 32768); + ushort overwritePointer = (ushort)(reliableReceiveLast - 32768); //Calculate if it is a new packet by examining if it is within the range bool isNew; if (overwritePointer < reliableReceiveLast) - isNew = id > reliableReceiveLast || id <= overwritePointer; //Figure (2) + isNew = id > reliableReceiveLast || id <= overwritePointer; //Figure (2) else - isNew = id > reliableReceiveLast && id <= overwritePointer; //Figure (3) - + isNew = id > reliableReceiveLast && id <= overwritePointer; //Figure (3) + //If it's new or we've not received anything yet if (isNew) { // Mark items between the most recent receive and the id received as missing if (id > reliableReceiveLast) { - for (var i = (ushort)(reliableReceiveLast + 1); i < id; i++) + for (ushort i = (ushort)(reliableReceiveLast + 1); i < id; i++) { reliableDataPacketsMissing.Add(i); } } else { - var cnt = (ushort.MaxValue - reliableReceiveLast) + id; + int cnt = (ushort.MaxValue - reliableReceiveLast) + id; for (ushort i = 1; i < cnt; ++i) { reliableDataPacketsMissing.Add((ushort)(i + reliableReceiveLast)); @@ -371,7 +371,7 @@ private async ValueTask ProcessReliableReceive(ReadOnlyMemory bytes, //Update the most recently received reliableReceiveLast = id; } - + //Else it could be a missing packet else { @@ -382,7 +382,7 @@ private async ValueTask ProcessReliableReceive(ReadOnlyMemory bytes, } } } - + //Send an acknowledgement await SendAck(id); @@ -397,13 +397,13 @@ private void AcknowledgementMessageReceive(ReadOnlySpan bytes) { this.pingsSinceAck = 0; - var id = (ushort)((bytes[1] << 8) + bytes[2]); + ushort id = (ushort)((bytes[1] << 8) + bytes[2]); AcknowledgeMessageId(id); if (bytes.Length == 4) { - var recentPackets = bytes[3]; - for (var i = 1; i <= 8; ++i) + byte recentPackets = bytes[3]; + for (int i = 1; i <= 8; ++i) { if ((recentPackets & 1) != 0) { @@ -420,7 +420,7 @@ private void AcknowledgementMessageReceive(ReadOnlySpan bytes) private void AcknowledgeMessageId(ushort id) { // Dispose of timer and remove from dictionary - if (reliableDataPacketsSent.TryRemove(id, out var packet)) + if (reliableDataPacketsSent.TryRemove(id, out Packet packet)) { float rt = packet.Stopwatch.ElapsedMilliseconds; @@ -432,7 +432,7 @@ private void AcknowledgeMessageId(ushort id) this.AveragePingMs = Math.Max(50, this.AveragePingMs * .7f + rt * .3f); } } - else if (this.activePingPackets.TryRemove(id, out var pingPkt)) + else if (this.activePingPackets.TryRemove(id, out PingPacket pingPkt)) { float rt = pingPkt.Stopwatch.ElapsedMilliseconds; @@ -455,7 +455,7 @@ private async ValueTask SendAck(ushort id) byte recentPackets = 0; lock (this.reliableDataPacketsMissing) { - for (var i = 1; i <= 8; ++i) + for (int i = 1; i <= 8; ++i) { if (!this.reliableDataPacketsMissing.Contains((ushort)(id - i))) { @@ -464,12 +464,12 @@ private async ValueTask SendAck(ushort id) } } - var bytes = new byte[] + byte[] bytes = new byte[] { (byte)UdpSendOption.Acknowledgement, (byte)(id >> 8), (byte)(id >> 0), - recentPackets, + recentPackets }; try diff --git a/src/Impostor.Hazel/Udp/UdpConnection.cs b/src/Impostor.Hazel/Udp/UdpConnection.cs index 4106bfe14..5288d3ce2 100644 --- a/src/Impostor.Hazel/Udp/UdpConnection.cs +++ b/src/Impostor.Hazel/Udp/UdpConnection.cs @@ -34,7 +34,7 @@ protected UdpConnection(ConnectionListener listener, ObjectPool r Pipeline = Channel.CreateUnbounded(new UnboundedChannelOptions { SingleReader = true, - SingleWriter = true, + SingleWriter = true }); } @@ -113,13 +113,13 @@ private async Task ReadAsync() /// protected abstract ValueTask WriteBytesToConnection(byte[] bytes, int length); - /// + /// public override async ValueTask SendAsync(IMessageWriter msg) { if (this._state != ConnectionState.Connected) throw new InvalidOperationException("Could not send data as this Connection is not connected. Did you disconnect?"); - var buffer = new byte[msg.Length]; + byte[] buffer = new byte[msg.Length]; Buffer.BlockCopy(msg.Buffer, 0, buffer, 0, msg.Length); switch (msg.SendOption) @@ -139,13 +139,13 @@ public override async ValueTask SendAsync(IMessageWriter msg) } } - /// + /// /// /// /// - /// Udp connections can currently send messages using and - /// . Fragmented messages are not currently supported and will default to - /// until implemented. + /// Udp connections can currently send messages using and + /// . Fragmented messages are not currently supported and will default to + /// until implemented. /// /// public override async ValueTask SendBytes(byte[] bytes, MessageType sendOption = MessageType.Unreliable) @@ -153,12 +153,12 @@ public override async ValueTask SendBytes(byte[] bytes, MessageType sendOption = //Add header information and send await HandleSend(bytes, (byte)sendOption); } - + /// /// Handles the reliable/fragmented sending from this connection. /// /// The data being sent. - /// The specified as its byte value. + /// The specified as its byte value. /// The callback to invoke when this packet is acknowledged. /// The bytes that should actually be sent. protected async ValueTask HandleSend(byte[] data, byte sendOption, Action ackCallback = null) @@ -170,7 +170,7 @@ protected async ValueTask HandleSend(byte[] data, byte sendOption, Action ackCal case (byte)UdpSendOption.Hello: await ReliableSend(sendOption, data, ackCallback); break; - + //Treat all else as unreliable default: await UnreliableSend(sendOption, data); @@ -226,16 +226,14 @@ protected async ValueTask HandleReceive(MessageReader message) { await DisconnectRemote("The remote sent a disconnect request", reader); } - break; - + //Treat everything else as unreliable default: using (var reader = message.Copy(1)) { await InvokeDataReceived(reader, MessageType.Unreliable); } - Statistics.LogUnreliableReceive(message.Length - 1, message.Length); break; } @@ -260,7 +258,7 @@ ValueTask UnreliableSend(byte sendOption, byte[] data) /// async ValueTask UnreliableSend(byte sendOption, byte[] data, int offset, int length) { - var bytes = new byte[length + 1]; + byte[] bytes = new byte[length + 1]; //Add message type bytes[0] = sendOption; @@ -295,8 +293,8 @@ protected ValueTask SendHello(byte[] bytes, Action acknowledgeCallback) return HandleSend(actualBytes, (byte)UdpSendOption.Hello, acknowledgeCallback); } - - /// + + /// protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/Impostor.Hazel/Udp/UdpConnectionListener.cs b/src/Impostor.Hazel/Udp/UdpConnectionListener.cs index 782bf6137..573a00cbf 100644 --- a/src/Impostor.Hazel/Udp/UdpConnectionListener.cs +++ b/src/Impostor.Hazel/Udp/UdpConnectionListener.cs @@ -4,6 +4,7 @@ using System.Net; using System.Net.Sockets; using System.Threading; +using System.Threading.Channels; using System.Threading.Tasks; using Microsoft.Extensions.ObjectPool; using Serilog; @@ -19,12 +20,11 @@ public class UdpConnectionListener : NetworkConnectionListener private static readonly ILogger Logger = Log.ForContext(); /// - /// A callback for early connection rejection. - /// * Return false to reject connection. - /// * A null response is ok, we just won't send anything. + /// A callback for early connection rejection. + /// * Return false to reject connection. + /// * A null response is ok, we just won't send anything. /// public AcceptConnectionCheck AcceptConnection; - public delegate bool AcceptConnectionCheck(IPEndPoint endPoint, byte[] input, out byte[] response); private readonly UdpClient _socket; @@ -37,7 +37,7 @@ public class UdpConnectionListener : NetworkConnectionListener private Task _executingTask; /// - /// Creates a new UdpConnectionListener for the given , port and . + /// Creates a new UdpConnectionListener for the given , port and . /// /// The endpoint to listen on. /// @@ -72,7 +72,7 @@ public UdpConnectionListener(IPEndPoint endPoint, ObjectPool read } public int ConnectionCount => this._allConnections.Count; - + private async void ManageReliablePackets(object state) { foreach (var kvp in _allConnections) diff --git a/src/Impostor.Hazel/Udp/UdpConnectionRateLimit.cs b/src/Impostor.Hazel/Udp/UdpConnectionRateLimit.cs index b90d7b15f..64881d3da 100644 --- a/src/Impostor.Hazel/Udp/UdpConnectionRateLimit.cs +++ b/src/Impostor.Hazel/Udp/UdpConnectionRateLimit.cs @@ -72,4 +72,4 @@ public void Dispose() _timer.Dispose(); } } -} +} \ No newline at end of file diff --git a/src/Impostor.Hazel/Udp/UdpServerConnection.cs b/src/Impostor.Hazel/Udp/UdpServerConnection.cs index 8c6cc067a..8d3426e38 100644 --- a/src/Impostor.Hazel/Udp/UdpServerConnection.cs +++ b/src/Impostor.Hazel/Udp/UdpServerConnection.cs @@ -9,14 +9,14 @@ namespace Impostor.Hazel.Udp /// /// Represents a servers's connection to a client that uses the UDP protocol. /// - /// + /// internal sealed class UdpServerConnection : UdpConnection { /// /// The connection listener that we use the socket of. /// /// - /// Udp server connections utilize the same socket in the listener for sends/receives, this is the listener that + /// Udp server connections utilize the same socket in the listener for sends/receives, this is the listener that /// created this connection and is hence the listener this conenction sends and receives via. /// public UdpConnectionListener Listener { get; private set; } @@ -63,7 +63,7 @@ protected override async ValueTask SendDisconnect(MessageWriter data = nul if (this._state != ConnectionState.Connected) return false; this._state = ConnectionState.NotConnected; } - + var bytes = EmptyDisconnectBytes; if (data != null && data.Length > 0) { From a90bbebab9ad70cd61fa62c22cb50a785d411766 Mon Sep 17 00:00:00 2001 From: js6pak Date: Wed, 24 Mar 2021 20:04:40 +0100 Subject: [PATCH 31/72] Update appveyor.yml for the ultimate yellow-less experience --- appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index ce3b999ae..ca2bc2cb6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -30,7 +30,6 @@ test: off artifacts: - path: ./build/*.zip - - path: ./build/*.tar.gz - path: ./build/*.nupkg - path: ./build/*.snupkg From 3321e3049f4ef6ef7e24c1c4ae6148cf428e8e9b Mon Sep 17 00:00:00 2001 From: js6pak Date: Wed, 24 Mar 2021 20:05:26 +0100 Subject: [PATCH 32/72] Make configs actually work with dependency injection --- .../Config/AnnouncementsServerConfig.cs | 17 +++------- src/Impostor.Server/Config/DebugConfig.cs | 15 ++------- .../Config/ServerRedirectorConfig.cs | 32 ++++++------------- .../Config/ServerRedirectorNode.cs | 15 +++------ 4 files changed, 21 insertions(+), 58 deletions(-) diff --git a/src/Impostor.Server/Config/AnnouncementsServerConfig.cs b/src/Impostor.Server/Config/AnnouncementsServerConfig.cs index 3ea3eb33a..43f8f8ff8 100644 --- a/src/Impostor.Server/Config/AnnouncementsServerConfig.cs +++ b/src/Impostor.Server/Config/AnnouncementsServerConfig.cs @@ -1,5 +1,4 @@ -using System.Text.Json.Serialization; -using Impostor.Server.Utils; +using Impostor.Server.Utils; namespace Impostor.Server.Config { @@ -9,19 +8,11 @@ internal class AnnouncementsServerConfig private string? _resolvedListenIp; - [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; } + public bool Enabled { get; set; } = true; - public string ListenIp { get; } + public string ListenIp { get; set; } = "0.0.0.0"; - public ushort ListenPort { get; } + public ushort ListenPort { get; set; } = 22024; public string ResolveListenIp() { diff --git a/src/Impostor.Server/Config/DebugConfig.cs b/src/Impostor.Server/Config/DebugConfig.cs index ef37d3972..72529de35 100644 --- a/src/Impostor.Server/Config/DebugConfig.cs +++ b/src/Impostor.Server/Config/DebugConfig.cs @@ -1,20 +1,11 @@ -using System.Text.Json.Serialization; - -namespace Impostor.Server.Config +namespace Impostor.Server.Config { public class DebugConfig { public const string Section = "Debug"; - [JsonConstructor] - public DebugConfig(bool gameRecorderEnabled = false, string? gameRecorderPath = null) - { - GameRecorderEnabled = gameRecorderEnabled; - GameRecorderPath = gameRecorderPath; - } - - public bool GameRecorderEnabled { get; } + public bool GameRecorderEnabled { get; set; } - public string? GameRecorderPath { get; } + public string GameRecorderPath { get; set; } = string.Empty; } } diff --git a/src/Impostor.Server/Config/ServerRedirectorConfig.cs b/src/Impostor.Server/Config/ServerRedirectorConfig.cs index 63285ad77..686ad7fdb 100644 --- a/src/Impostor.Server/Config/ServerRedirectorConfig.cs +++ b/src/Impostor.Server/Config/ServerRedirectorConfig.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using System.Text.Json.Serialization; +using System.Diagnostics.CodeAnalysis; namespace Impostor.Server.Config { @@ -7,35 +7,21 @@ public class ServerRedirectorConfig { public const string Section = "ServerRedirector"; - [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 Enabled { get; set; } - public bool Enabled { get; } + public bool Master { get; set; } - public bool Master { get; } + public NodeLocator? Locator { get; set; } - public NodeLocator? Locator { get; } - - public List? Nodes { get; } + public List? Nodes { get; set; } public class NodeLocator { - [JsonConstructor] - public NodeLocator(string redis, string udpMasterEndpoint) - { - Redis = redis; - UdpMasterEndpoint = udpMasterEndpoint; - } - - public string Redis { get; } + [AllowNull] + public string Redis { get; set; } - public string UdpMasterEndpoint { get; } + [AllowNull] + public string UdpMasterEndpoint { get; set; } } } } diff --git a/src/Impostor.Server/Config/ServerRedirectorNode.cs b/src/Impostor.Server/Config/ServerRedirectorNode.cs index c5752bf6b..c47951234 100644 --- a/src/Impostor.Server/Config/ServerRedirectorNode.cs +++ b/src/Impostor.Server/Config/ServerRedirectorNode.cs @@ -1,18 +1,13 @@ -using System.Text.Json.Serialization; +using System.Diagnostics.CodeAnalysis; namespace Impostor.Server.Config { public class ServerRedirectorNode { - [JsonConstructor] - public ServerRedirectorNode(string ip, ushort port) - { - Ip = ip; - Port = port; - } + [AllowNull] + public string Ip { get; set; } - public string Ip { get; } - - public ushort Port { get; } + [AllowNull] + public ushort Port { get; set; } } } From 40a41f357338b190dbeb8c629d6910380fc23691 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 28 Mar 2021 19:27:49 +0200 Subject: [PATCH 33/72] Fix a bug causing InnerPlayerInfo.Controller to be always null --- src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs | 5 ++++- src/Impostor.Server/Net/State/Game.Data.cs | 9 ++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs index 0b2dbf4a5..aa617bc3a 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs @@ -131,7 +131,7 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client return true; } - internal void AddPlayer(InnerPlayerControl control) + internal InnerPlayerInfo? AddPlayer(InnerPlayerControl control) { var playerId = control.PlayerId; var playerInfo = new InnerPlayerInfo(control.PlayerId); @@ -139,7 +139,10 @@ internal void AddPlayer(InnerPlayerControl control) if (_allPlayers.TryAdd(playerId, playerInfo)) { control.PlayerInfo = playerInfo; + return playerInfo; } + + return null; } private void SetTasks(byte playerId, ReadOnlyMemory taskTypeIds) diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index 9e5fd0148..90bf765f5 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -329,16 +329,11 @@ private async ValueTask OnSpawnAsync(InnerNetObject netObj) player.DisableSpawnTimeout(); // Hook up InnerPlayerControl <-> InnerPlayerControl.PlayerInfo. - var playerInfo = GameNet.GameData!.GetPlayerById(control.PlayerId); + var playerInfo = GameNet.GameData!.GetPlayerById(control.PlayerId) ?? GameNet.GameData.AddPlayer(control); if (playerInfo != null) { - playerInfo.Controller = control; - control.PlayerInfo = playerInfo; - } - else - { - GameNet.GameData.AddPlayer(control); + control.PlayerInfo.Controller = control; } await _eventManager.CallAsync(new PlayerSpawnedEvent(this, player, control)); From a0627bbc879a21eba5e9a1d3a9f72b1ffc645501 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 28 Mar 2021 20:46:31 +0200 Subject: [PATCH 34/72] Always hook control with playerInfo --- src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs | 1 - src/Impostor.Server/Net/State/Game.Data.cs | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs index aa617bc3a..011af37b0 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs @@ -138,7 +138,6 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client if (_allPlayers.TryAdd(playerId, playerInfo)) { - control.PlayerInfo = playerInfo; return playerInfo; } diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index 90bf765f5..250c3078d 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -333,7 +333,8 @@ private async ValueTask OnSpawnAsync(InnerNetObject netObj) if (playerInfo != null) { - control.PlayerInfo.Controller = control; + playerInfo.Controller = control; + control.PlayerInfo = playerInfo; } await _eventManager.CallAsync(new PlayerSpawnedEvent(this, player, control)); From b90e5b2c88a0e00e551ea076bfa453b415714ffc Mon Sep 17 00:00:00 2001 From: js6pak Date: Fri, 2 Apr 2021 23:42:22 +0200 Subject: [PATCH 35/72] Switch back hazel to submodule --- .gitmodules | 3 + src/Impostor.Client/Impostor.Client.csproj | 2 +- src/Impostor.Hazel/Connection.cs | 249 -------- src/Impostor.Hazel/ConnectionListener.cs | 100 ---- src/Impostor.Hazel/ConnectionState.cs | 23 - src/Impostor.Hazel/ConnectionStatistics.cs | 566 ------------------ src/Impostor.Hazel/DataReceivedEventArgs.cs | 26 - src/Impostor.Hazel/DisconnectedEventArgs.cs | 25 - .../Extensions/ServiceProviderExtensions.cs | 21 - src/Impostor.Hazel/HazelException.cs | 21 - src/Impostor.Hazel/IPMode.cs | 24 - src/Impostor.Hazel/IRecyclable.cs | 24 - src/Impostor.Hazel/Impostor.Hazel.csproj | 18 - src/Impostor.Hazel/MessageReader.cs | 279 --------- src/Impostor.Hazel/MessageReaderPolicy.cs | 27 - src/Impostor.Hazel/MessageWriter.cs | 356 ----------- src/Impostor.Hazel/NetworkConnection.cs | 117 ---- .../NetworkConnectionListener.cs | 21 - src/Impostor.Hazel/NewConnectionEventArgs.cs | 24 - src/Impostor.Hazel/ObjectPoolCustom.cs | 107 ---- src/Impostor.Hazel/Udp/SendOptionInternal.cs | 33 - .../Udp/UdpBroadcastListener.cs | 156 ----- src/Impostor.Hazel/Udp/UdpBroadcaster.cs | 79 --- src/Impostor.Hazel/Udp/UdpClientConnection.cs | 225 ------- .../Udp/UdpConnection.KeepAlive.cs | 167 ------ .../Udp/UdpConnection.Reliable.cs | 493 --------------- src/Impostor.Hazel/Udp/UdpConnection.cs | 312 ---------- .../Udp/UdpConnectionListener.cs | 281 --------- .../Udp/UdpConnectionRateLimit.cs | 75 --- src/Impostor.Hazel/Udp/UdpServerConnection.cs | 97 --- src/Impostor.Server/Impostor.Server.csproj | 2 +- .../Impostor.Tools.Proxy.csproj | 2 +- src/Impostor.sln | 2 +- 33 files changed, 7 insertions(+), 3950 deletions(-) create mode 100644 .gitmodules delete mode 100644 src/Impostor.Hazel/Connection.cs delete mode 100644 src/Impostor.Hazel/ConnectionListener.cs delete mode 100644 src/Impostor.Hazel/ConnectionState.cs delete mode 100644 src/Impostor.Hazel/ConnectionStatistics.cs delete mode 100644 src/Impostor.Hazel/DataReceivedEventArgs.cs delete mode 100644 src/Impostor.Hazel/DisconnectedEventArgs.cs delete mode 100644 src/Impostor.Hazel/Extensions/ServiceProviderExtensions.cs delete mode 100644 src/Impostor.Hazel/HazelException.cs delete mode 100644 src/Impostor.Hazel/IPMode.cs delete mode 100644 src/Impostor.Hazel/IRecyclable.cs delete mode 100644 src/Impostor.Hazel/Impostor.Hazel.csproj delete mode 100644 src/Impostor.Hazel/MessageReader.cs delete mode 100644 src/Impostor.Hazel/MessageReaderPolicy.cs delete mode 100644 src/Impostor.Hazel/MessageWriter.cs delete mode 100644 src/Impostor.Hazel/NetworkConnection.cs delete mode 100644 src/Impostor.Hazel/NetworkConnectionListener.cs delete mode 100644 src/Impostor.Hazel/NewConnectionEventArgs.cs delete mode 100644 src/Impostor.Hazel/ObjectPoolCustom.cs delete mode 100644 src/Impostor.Hazel/Udp/SendOptionInternal.cs delete mode 100644 src/Impostor.Hazel/Udp/UdpBroadcastListener.cs delete mode 100644 src/Impostor.Hazel/Udp/UdpBroadcaster.cs delete mode 100644 src/Impostor.Hazel/Udp/UdpClientConnection.cs delete mode 100644 src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs delete mode 100644 src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs delete mode 100644 src/Impostor.Hazel/Udp/UdpConnection.cs delete mode 100644 src/Impostor.Hazel/Udp/UdpConnectionListener.cs delete mode 100644 src/Impostor.Hazel/Udp/UdpConnectionRateLimit.cs delete mode 100644 src/Impostor.Hazel/Udp/UdpServerConnection.cs diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..598f78b6a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/Impostor.Hazel"] + path = src/Impostor.Hazel + url = https://github.com/Impostor/Impostor.Hazel diff --git a/src/Impostor.Client/Impostor.Client.csproj b/src/Impostor.Client/Impostor.Client.csproj index cbde5b662..75e19aa8a 100644 --- a/src/Impostor.Client/Impostor.Client.csproj +++ b/src/Impostor.Client/Impostor.Client.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/Impostor.Hazel/Connection.cs b/src/Impostor.Hazel/Connection.cs deleted file mode 100644 index dec8cfecb..000000000 --- a/src/Impostor.Hazel/Connection.cs +++ /dev/null @@ -1,249 +0,0 @@ -using System; -using System.Net; -using System.Threading.Tasks; -using Impostor.Api.Net.Messages; -using Serilog; - -namespace Impostor.Hazel -{ - /// - /// Base class for all connections. - /// - /// - /// - /// Connection is the base class for all connections that Hazel can make. It provides common functionality and a - /// standard interface to allow connections to be swapped easily. - /// - /// - /// Any class inheriting from Connection should provide the 3 standard guarantees that Hazel provides: - /// - /// - /// Thread Safe - /// - /// - /// Connection Orientated - /// - /// - /// Packet/Message Based - /// - /// - /// - /// - /// - public abstract class Connection : IDisposable - { - private static readonly ILogger Logger = Log.ForContext(); - - /// - /// Called when a message has been received. - /// - /// - /// - /// DataReceived is invoked everytime a message is received from the end point of this connection, the message - /// that was received can be found in the alongside other information from the - /// event. - /// - /// - /// - /// - /// - /// - public Func DataReceived; - - public int TestLagMs = -1; - public int TestDropRate = 0; - protected int testDropCount = 0; - - /// - /// Called when the end point disconnects or an error occurs. - /// - /// - /// - /// Disconnected is invoked when the connection is closed due to an exception occuring or because the remote - /// end point disconnected. If it was invoked due to an exception occuring then the exception is available - /// in the passed with the event. - /// - /// - /// - /// - /// - /// - public Func Disconnected; - - /// - /// The remote end point of this Connection. - /// - /// - /// This is the end point that this connection is connected to (i.e. the other device). This returns an abstract - /// which can then be cast to an appropriate end point depending on the - /// connection type. - /// - public IPEndPoint EndPoint { get; protected set; } - - public IPMode IPMode { get; protected set; } - - /// - /// The traffic statistics about this Connection. - /// - /// - /// Contains statistics about the number of messages and bytes sent and received by this connection. - /// - public ConnectionStatistics Statistics { get; protected set; } - - /// - /// The state of this connection. - /// - /// - /// All implementers should be aware that when this is set to ConnectionState.Connected it will - /// release all threads that are blocked on . - /// - public ConnectionState State - { - get - { - return this._state; - } - - protected set - { - this._state = value; - this.SetState(value); - } - } - - protected ConnectionState _state; - protected virtual void SetState(ConnectionState state) { } - - /// - /// Constructor that initializes the ConnecitonStatistics object. - /// - /// - /// This constructor initialises with empty statistics and sets to - /// . - /// - protected Connection() - { - this.Statistics = new ConnectionStatistics(); - this.State = ConnectionState.NotConnected; - } - - /// - /// Sends a number of bytes to the end point of the connection using the specified . - /// - /// The message to send. - /// - /// - /// - /// The messageType parameter is only a request to use those options and the actual method used to send the - /// data is up to the implementation. There are circumstances where this parameter may be ignored but in - /// general any implementer should aim to always follow the user's request. - /// - /// - public abstract ValueTask SendAsync(IMessageWriter msg); - - /// - /// Sends a number of bytes to the end point of the connection using the specified . - /// - /// The bytes of the message to send. - /// The option specifying how the message should be sent. - /// - /// - /// - /// The messageType parameter is only a request to use those options and the actual method used to send the - /// data is up to the implementation. There are circumstances where this parameter may be ignored but in - /// general any implementer should aim to always follow the user's request. - /// - /// - public abstract ValueTask SendBytes(byte[] bytes, MessageType messageType = MessageType.Unreliable); - - /// - /// Connects the connection to a server and begins listening. - /// This method does not block. - /// - /// The bytes of data to send in the handshake. - public abstract ValueTask ConnectAsync(byte[] bytes = null); - - /// - /// Invokes the DataReceived event. - /// - /// The bytes received. - /// The the message was received with. - /// - /// Invokes the event on this connection to alert subscribers a new message has been - /// received. The bytes and the send option that the message was sent with should be passed in to give to the - /// subscribers. - /// - protected async ValueTask InvokeDataReceived(IMessageReader msg, MessageType messageType) - { - // Make a copy to avoid race condition between null check and invocation - var handler = DataReceived; - if (handler != null) - { - try - { - await handler(new DataReceivedEventArgs(this, msg, messageType)); - } - catch (Exception e) - { - Logger.Error(e, "Invoking data received failed"); - await Disconnect("Invoking data received failed"); - } - } - } - - /// - /// Invokes the Disconnected event. - /// - /// The exception, if any, that occurred to cause this. - /// Extra disconnect data - /// - /// Invokes the event to alert subscribres this connection has been disconnected either - /// by the end point or because an error occurred. If an error occurred the error should be passed in in order to - /// pass to the subscribers, otherwise null can be passed in. - /// - protected async ValueTask InvokeDisconnected(string e, IMessageReader reader) - { - // Make a copy to avoid race condition between null check and invocation - var handler = Disconnected; - if (handler != null) - { - try - { - await handler(new DisconnectedEventArgs(e, reader)); - } - catch (Exception ex) - { - Logger.Error(ex, "Error in InvokeDisconnected"); - } - } - } - - /// - /// For times when you want to force the disconnect handler to fire as well as close it. - /// If you only want to close it, just use Dispose. - /// - public abstract ValueTask Disconnect(string reason, MessageWriter writer = null); - - /// - /// Disposes of this NetworkConnection. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Disposes of this NetworkConnection. - /// - /// Are we currently disposing? - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - this.DataReceived = null; - this.Disconnected = null; - } - } - } -} diff --git a/src/Impostor.Hazel/ConnectionListener.cs b/src/Impostor.Hazel/ConnectionListener.cs deleted file mode 100644 index 116f657e4..000000000 --- a/src/Impostor.Hazel/ConnectionListener.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using System.Threading.Tasks; -using Impostor.Api.Net.Messages; -using Serilog; - -namespace Impostor.Hazel -{ - /// - /// Base class for all connection listeners. - /// - /// - /// - /// ConnectionListeners are server side objects that listen for clients and create matching server side connections - /// for each client in a similar way to TCP does. These connections should be ready for communication immediately. - /// - /// - /// Each time a client connects the event will be invoked to alert all subscribers to - /// the new connection. A disconnected event is then present on the that is passed to the - /// subscribers. - /// - /// - /// - public abstract class ConnectionListener : IAsyncDisposable - { - private static readonly ILogger Logger = Log.ForContext(); - - /// - /// Invoked when a new client connects. - /// - /// - /// - /// NewConnection is invoked each time a client connects to the listener. The - /// contains the new for communication with this - /// client. - /// - /// - /// Hazel may or may not store connections so it is your responsibility to keep track and properly Dispose of - /// connections to your server. - /// - /// - /// - /// - /// - /// - public Func NewConnection; - - /// - /// Makes this connection listener begin listening for connections. - /// - /// - /// - /// This instructs the listener to begin listening for new clients connecting to the server. When a new client - /// connects the event will be invoked containing the connection to the new client. - /// - /// - /// To stop listening you should call . - /// - /// - /// - /// - /// - public abstract Task StartAsync(); - - /// - /// Invokes the NewConnection event with the supplied connection. - /// - /// The user sent bytes that were received as part of the handshake. - /// The connection to pass in the arguments. - /// - /// Implementers should call this to invoke the event before data is received so that - /// subscribers do not miss any data that may have been sent immediately after connecting. - /// - internal async Task InvokeNewConnection(IMessageReader msg, Connection connection) - { - // Make a copy to avoid race condition between null check and invocation - var handler = NewConnection; - if (handler != null) - { - try - { - await handler(new NewConnectionEventArgs(msg, connection)); - } - catch (Exception e) - { - Logger.Error(e, "Accepting connection failed"); - await connection.Disconnect("Accepting connection failed"); - } - } - } - - /// - /// Call to dispose of the connection listener. - /// - public virtual ValueTask DisposeAsync() - { - this.NewConnection = null; - return ValueTask.CompletedTask; - } - } -} diff --git a/src/Impostor.Hazel/ConnectionState.cs b/src/Impostor.Hazel/ConnectionState.cs deleted file mode 100644 index 5dd7c6a07..000000000 --- a/src/Impostor.Hazel/ConnectionState.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Impostor.Hazel -{ - /// - /// Represents the state a is currently in. - /// - public enum ConnectionState - { - /// - /// The Connection has either not been established yet or has been disconnected. - /// - NotConnected, - - /// - /// The Connection is currently connecting to an endpoint. - /// - Connecting, - - /// - /// The Connection is connected and data can be transfered. - /// - Connected, - } -} diff --git a/src/Impostor.Hazel/ConnectionStatistics.cs b/src/Impostor.Hazel/ConnectionStatistics.cs deleted file mode 100644 index 48026208e..000000000 --- a/src/Impostor.Hazel/ConnectionStatistics.cs +++ /dev/null @@ -1,566 +0,0 @@ -using System.Runtime.CompilerServices; -using System.Threading; - -[assembly: InternalsVisibleTo("Hazel.Tests")] -namespace Impostor.Hazel -{ - /// - /// Holds statistics about the traffic through a . - /// - /// - public class ConnectionStatistics - { - private const int ExpectedMTU = 1200; - - /// - /// The total number of messages sent. - /// - public int MessagesSent - { - get - { - return UnreliableMessagesSent + ReliableMessagesSent + FragmentedMessagesSent + AcknowledgementMessagesSent + HelloMessagesSent; - } - } - - /// - /// The number of messages sent larger than 576 bytes. This is smaller than most default MTUs. - /// - /// - /// This is the number of unreliable messages that were sent from the , incremented - /// each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not - /// counted and messages are only counted once all other operations in the send are complete. - /// - public int FragmentableMessagesSent - { - get - { - return fragmentableMessagesSent; - } - } - - /// - /// The number of messages sent larger than 576 bytes. - /// - int fragmentableMessagesSent; - - /// - /// The number of unreliable messages sent. - /// - /// - /// This is the number of unreliable messages that were sent from the , incremented - /// each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not - /// counted and messages are only counted once all other operations in the send are complete. - /// - public int UnreliableMessagesSent - { - get - { - return unreliableMessagesSent; - } - } - - /// - /// The number of unreliable messages sent. - /// - int unreliableMessagesSent; - - /// - /// The number of reliable messages sent. - /// - /// - /// This is the number of reliable messages that were sent from the , incremented - /// each time that LogReliableSend is called by the Connection. Messages that caused an error are not - /// counted and messages are only counted once all other operations in the send are complete. - /// - public int ReliableMessagesSent - { - get - { - return reliableMessagesSent; - } - } - - /// - /// The number of unreliable messages sent. - /// - int reliableMessagesSent; - - /// - /// The number of fragmented messages sent. - /// - /// - /// This is the number of fragmented messages that were sent from the , incremented - /// each time that LogFragmentedSend is called by the Connection. Messages that caused an error are not - /// counted and messages are only counted once all other operations in the send are complete. - /// - public int FragmentedMessagesSent - { - get - { - return fragmentedMessagesSent; - } - } - - /// - /// The number of fragmented messages sent. - /// - int fragmentedMessagesSent; - - /// - /// The number of acknowledgement messages sent. - /// - /// - /// This is the number of acknowledgements that were sent from the , incremented - /// each time that LogAcknowledgementSend is called by the Connection. Messages that caused an error are not - /// counted and messages are only counted once all other operations in the send are complete. - /// - public int AcknowledgementMessagesSent - { - get - { - return acknowledgementMessagesSent; - } - } - - /// - /// The number of acknowledgement messages sent. - /// - int acknowledgementMessagesSent; - - /// - /// The number of hello messages sent. - /// - /// - /// This is the number of hello messages that were sent from the , incremented - /// each time that LogHelloSend is called by the Connection. Messages that caused an error are not - /// counted and messages are only counted once all other operations in the send are complete. - /// - public int HelloMessagesSent - { - get - { - return helloMessagesSent; - } - } - - /// - /// The number of hello messages sent. - /// - int helloMessagesSent; - - /// - /// The number of bytes of data sent. - /// - /// - /// - /// This is the number of bytes of data (i.e. user bytes) that were sent from the , - /// accumulated each time that LogSend is called by the Connection. Messages that caused an error are not - /// counted and messages are only counted once all other operations in the send are complete. - /// - /// - /// For the number of bytes including protocol bytes see . - /// - /// - public long DataBytesSent - { - get - { - return Interlocked.Read(ref dataBytesSent); - } - } - - /// - /// The number of bytes of data sent. - /// - long dataBytesSent; - - /// - /// The number of bytes sent in total. - /// - /// - /// - /// This is the total number of bytes (the data bytes plus protocol bytes) that were sent from the - /// , accumulated each time that LogSend is called by the Connection. Messages that - /// caused an error are not counted and messages are only counted once all other operations in the send are - /// complete. - /// - /// - /// For the number of data bytes excluding protocol bytes see . - /// - /// - public long TotalBytesSent - { - get - { - return Interlocked.Read(ref totalBytesSent); - } - } - - /// - /// The number of bytes sent in total. - /// - long totalBytesSent; - - /// - /// The total number of messages received. - /// - public int MessagesReceived - { - get - { - return UnreliableMessagesReceived + ReliableMessagesReceived + FragmentedMessagesReceived + AcknowledgementMessagesReceived + helloMessagesReceived; - } - } - - /// - /// The number of unreliable messages received. - /// - /// - /// This is the number of unreliable messages that were received by the , incremented - /// each time that LogUnreliableReceive is called by the Connection. Messages are counted before the receive event is invoked. - /// - public int UnreliableMessagesReceived - { - get - { - return unreliableMessagesReceived; - } - } - - /// - /// The number of unreliable messages received. - /// - int unreliableMessagesReceived; - - /// - /// The number of reliable messages received. - /// - /// - /// This is the number of reliable messages that were received by the , incremented - /// each time that LogReliableReceive is called by the Connection. Messages are counted before the receive event is invoked. - /// - public int ReliableMessagesReceived - { - get - { - return reliableMessagesReceived; - } - } - - /// - /// The number of reliable messages received. - /// - int reliableMessagesReceived; - - /// - /// The number of fragmented messages received. - /// - /// - /// This is the number of fragmented messages that were received by the , incremented - /// each time that LogFragmentedReceive is called by the Connection. Messages are counted before the receive event is invoked. - /// - public int FragmentedMessagesReceived - { - get - { - return fragmentedMessagesReceived; - } - } - - /// - /// The number of fragmented messages received. - /// - int fragmentedMessagesReceived; - - /// - /// The number of acknowledgement messages received. - /// - /// - /// This is the number of acknowledgement messages that were received by the , incremented - /// each time that LogAcknowledgemntReceive is called by the Connection. Messages are counted before the receive event is invoked. - /// - public int AcknowledgementMessagesReceived - { - get - { - return acknowledgementMessagesReceived; - } - } - - /// - /// The number of acknowledgement messages received. - /// - int acknowledgementMessagesReceived; - - /// - /// The number of ping messages received. - /// - /// - /// This is the number of hello messages that were received by the , incremented - /// each time that LogHelloReceive is called by the Connection. Messages are counted before the receive event is invoked. - /// - public int PingMessagesReceived - { - get - { - return pingMessagesReceived; - } - } - - /// - /// The number of hello messages received. - /// - int pingMessagesReceived; - - /// - /// The number of hello messages received. - /// - /// - /// This is the number of hello messages that were received by the , incremented - /// each time that LogHelloReceive is called by the Connection. Messages are counted before the receive event is invoked. - /// - public int HelloMessagesReceived - { - get - { - return helloMessagesReceived; - } - } - - /// - /// The number of hello messages received. - /// - int helloMessagesReceived; - - /// - /// The number of bytes of data received. - /// - /// - /// - /// This is the number of bytes of data (i.e. user bytes) that were received by the , - /// accumulated each time that LogReceive is called by the Connection. Messages are counted before the receive - /// event is invoked. - /// - /// - /// For the number of bytes including protocol bytes see . - /// - /// - public long DataBytesReceived - { - get - { - return Interlocked.Read(ref dataBytesReceived); - } - } - - /// - /// The number of bytes of data received. - /// - long dataBytesReceived; - - /// - /// The number of bytes received in total. - /// - /// - /// - /// This is the total number of bytes (the data bytes plus protocol bytes) that were received by the - /// , accumulated each time that LogReceive is called by the Connection. Messages are - /// counted before the receive event is invoked. - /// - /// - /// For the number of data bytes excluding protocol bytes see . - /// - /// - public long TotalBytesReceived - { - get - { - return Interlocked.Read(ref totalBytesReceived); - } - } - - /// - /// The number of bytes received in total. - /// - long totalBytesReceived; - - public int MessagesResent { get { return messagesResent; } } - int messagesResent; - - /// - /// Logs the sending of an unreliable data packet in the statistics. - /// - /// The number of bytes of data sent. - /// The total number of bytes sent. - /// - /// This should be called after the data has been sent and should only be called for data that is sent sucessfully. - /// - internal void LogUnreliableSend(int dataLength, int totalLength) - { - Interlocked.Increment(ref unreliableMessagesSent); - Interlocked.Add(ref dataBytesSent, dataLength); - Interlocked.Add(ref totalBytesSent, totalLength); - - if (totalLength > ExpectedMTU) - { - Interlocked.Increment(ref fragmentableMessagesSent); - } - } - - /// - /// Logs the sending of a reliable data packet in the statistics. - /// - /// The number of bytes of data sent. - /// The total number of bytes sent. - /// - /// This should be called after the data has been sent and should only be called for data that is sent sucessfully. - /// - internal void LogReliableSend(int dataLength, int totalLength) - { - Interlocked.Increment(ref reliableMessagesSent); - Interlocked.Add(ref dataBytesSent, dataLength); - Interlocked.Add(ref totalBytesSent, totalLength); - - if (totalLength > ExpectedMTU) - { - Interlocked.Increment(ref fragmentableMessagesSent); - } - } - - /// - /// Logs the sending of a fragmented data packet in the statistics. - /// - /// The number of bytes of data sent. - /// The total number of bytes sent. - /// - /// This should be called after the data has been sent and should only be called for data that is sent sucessfully. - /// - internal void LogFragmentedSend(int dataLength, int totalLength) - { - Interlocked.Increment(ref fragmentedMessagesSent); - Interlocked.Add(ref dataBytesSent, dataLength); - Interlocked.Add(ref totalBytesSent, totalLength); - - if (totalLength > ExpectedMTU) - { - Interlocked.Increment(ref fragmentableMessagesSent); - } - } - - /// - /// Logs the sending of a acknowledgement data packet in the statistics. - /// - /// The total number of bytes sent. - /// - /// This should be called after the data has been sent and should only be called for data that is sent sucessfully. - /// - internal void LogAcknowledgementSend(int totalLength) - { - Interlocked.Increment(ref acknowledgementMessagesSent); - Interlocked.Add(ref totalBytesSent, totalLength); - } - - /// - /// Logs the sending of a hellp data packet in the statistics. - /// - /// The total number of bytes sent. - /// - /// This should be called after the data has been sent and should only be called for data that is sent sucessfully. - /// - internal void LogHelloSend(int totalLength) - { - Interlocked.Increment(ref helloMessagesSent); - Interlocked.Add(ref totalBytesSent, totalLength); - } - - /// - /// Logs the receiving of an unreliable data packet in the statistics. - /// - /// The number of bytes of data received. - /// The total number of bytes received. - /// - /// This should be called before the received event is invoked so it is up to date for subscribers to that event. - /// - internal void LogUnreliableReceive(int dataLength, int totalLength) - { - Interlocked.Increment(ref unreliableMessagesReceived); - Interlocked.Add(ref dataBytesReceived, dataLength); - Interlocked.Add(ref totalBytesReceived, totalLength); - } - - /// - /// Logs the receiving of a reliable data packet in the statistics. - /// - /// The number of bytes of data received. - /// The total number of bytes received. - /// - /// This should be called before the received event is invoked so it is up to date for subscribers to that event. - /// - internal void LogReliableReceive(int dataLength, int totalLength) - { - Interlocked.Increment(ref reliableMessagesReceived); - Interlocked.Add(ref dataBytesReceived, dataLength); - Interlocked.Add(ref totalBytesReceived, totalLength); - } - - /// - /// Logs the receiving of a fragmented data packet in the statistics. - /// - /// The number of bytes of data received. - /// The total number of bytes received. - /// - /// This should be called before the received event is invoked so it is up to date for subscribers to that event. - /// - internal void LogFragmentedReceive(int dataLength, int totalLength) - { - Interlocked.Increment(ref fragmentedMessagesReceived); - Interlocked.Add(ref dataBytesReceived, dataLength); - Interlocked.Add(ref totalBytesReceived, totalLength); - } - - /// - /// Logs the receiving of an acknowledgement data packet in the statistics. - /// - /// The total number of bytes received. - /// - /// This should be called before the received event is invoked so it is up to date for subscribers to that event. - /// - internal void LogAcknowledgementReceive(int totalLength) - { - Interlocked.Increment(ref acknowledgementMessagesReceived); - Interlocked.Add(ref totalBytesReceived, totalLength); - } - - /// - /// Logs the receiving of a hello data packet in the statistics. - /// - /// The total number of bytes received. - /// - /// This should be called before the received event is invoked so it is up to date for subscribers to that event. - /// - internal void LogPingReceive(int totalLength) - { - Interlocked.Increment(ref pingMessagesReceived); - Interlocked.Add(ref totalBytesReceived, totalLength); - } - - /// - /// Logs the receiving of a hello data packet in the statistics. - /// - /// The total number of bytes received. - /// - /// This should be called before the received event is invoked so it is up to date for subscribers to that event. - /// - internal void LogHelloReceive(int totalLength) - { - Interlocked.Increment(ref helloMessagesReceived); - Interlocked.Add(ref totalBytesReceived, totalLength); - } - - internal void LogMessageResent() - { - Interlocked.Increment(ref messagesResent); - } - } -} diff --git a/src/Impostor.Hazel/DataReceivedEventArgs.cs b/src/Impostor.Hazel/DataReceivedEventArgs.cs deleted file mode 100644 index 9176d8d93..000000000 --- a/src/Impostor.Hazel/DataReceivedEventArgs.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Impostor.Api.Net.Messages; - -namespace Impostor.Hazel -{ - public struct DataReceivedEventArgs - { - public readonly Connection Sender; - - /// - /// The bytes received from the client. - /// - public readonly IMessageReader Message; - - /// - /// The the data was sent with. - /// - public readonly MessageType Type; - - public DataReceivedEventArgs(Connection sender, IMessageReader msg, MessageType type) - { - this.Sender = sender; - this.Message = msg; - this.Type = type; - } - } -} diff --git a/src/Impostor.Hazel/DisconnectedEventArgs.cs b/src/Impostor.Hazel/DisconnectedEventArgs.cs deleted file mode 100644 index d46df4b9c..000000000 --- a/src/Impostor.Hazel/DisconnectedEventArgs.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using Impostor.Api.Net.Messages; - -namespace Impostor.Hazel -{ - public class DisconnectedEventArgs : EventArgs - { - /// - /// Optional disconnect reason. May be null. - /// - public readonly string Reason; - - /// - /// Optional data sent with a disconnect message. May be null. - /// You must not recycle this. If you need the message outside of a callback, you should copy it. - /// - public readonly IMessageReader Message; - - public DisconnectedEventArgs(string reason, IMessageReader message) - { - this.Reason = reason; - this.Message = message; - } - } -} diff --git a/src/Impostor.Hazel/Extensions/ServiceProviderExtensions.cs b/src/Impostor.Hazel/Extensions/ServiceProviderExtensions.cs deleted file mode 100644 index 56c738071..000000000 --- a/src/Impostor.Hazel/Extensions/ServiceProviderExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.ObjectPool; - -namespace Impostor.Hazel.Extensions -{ - public static class ServiceProviderExtensions - { - public static void AddHazel(this IServiceCollection services) - { - services.TryAddSingleton(new DefaultObjectPoolProvider()); - - services.AddSingleton(serviceProvider => - { - var provider = serviceProvider.GetRequiredService(); - var policy = ActivatorUtilities.CreateInstance(serviceProvider); - return provider.Create(policy); - }); - } - } -} diff --git a/src/Impostor.Hazel/HazelException.cs b/src/Impostor.Hazel/HazelException.cs deleted file mode 100644 index 8c6fc3c12..000000000 --- a/src/Impostor.Hazel/HazelException.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; - -namespace Impostor.Hazel -{ - /// - /// Wrapper for exceptions thrown from Hazel. - /// - [Serializable] - public class HazelException : Exception - { - internal HazelException(string msg) : base (msg) - { - - } - - internal HazelException(string msg, Exception e) : base (msg, e) - { - - } - } -} diff --git a/src/Impostor.Hazel/IPMode.cs b/src/Impostor.Hazel/IPMode.cs deleted file mode 100644 index 5eb6679e5..000000000 --- a/src/Impostor.Hazel/IPMode.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace Impostor.Hazel -{ - /// - /// Represents the IP version that a connection or listener will use. - /// - /// - /// If you wand a client to connect or be able to connect using IPv6 then you should use , - /// this sets the underlying sockets to use IPv6 but still allow IPv4 sockets to connect for backwards compatability - /// and hence it is the default IPMode in most cases. - /// - public enum IPMode - { - /// - /// Instruction to use IPv4 only, IPv6 connections will not be able to connect. - /// - IPv4, - - /// - /// Instruction to use IPv6 only, IPv4 connections will not be able to connect. IPv4 addresses can be connected - /// by converting to IPv6 addresses. - /// - IPv6 - } -} diff --git a/src/Impostor.Hazel/IRecyclable.cs b/src/Impostor.Hazel/IRecyclable.cs deleted file mode 100644 index 69be1225b..000000000 --- a/src/Impostor.Hazel/IRecyclable.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace Impostor.Hazel -{ - /// - /// Interface for all items that can be returned to an object pool. - /// - /// - public interface IRecyclable - { - /// - /// Returns this object back to the object pool. - /// - /// - /// - /// Calling this when you are done with the object returns the object back to a pool in order to be reused. - /// This can reduce the amount of work the GC has to do dramatically but it is optional to call this. - /// - /// - /// Calling this indicates to Hazel that this can be reused and thus you should only call this when you are - /// completely finished with the object as the contents can be overwritten at any point after. - /// - /// - void Recycle(); - } -} diff --git a/src/Impostor.Hazel/Impostor.Hazel.csproj b/src/Impostor.Hazel/Impostor.Hazel.csproj deleted file mode 100644 index 00997697c..000000000 --- a/src/Impostor.Hazel/Impostor.Hazel.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - true - net5.0 - HAZEL_BAG - - - - - - - - - - - - diff --git a/src/Impostor.Hazel/MessageReader.cs b/src/Impostor.Hazel/MessageReader.cs deleted file mode 100644 index 317e45b1e..000000000 --- a/src/Impostor.Hazel/MessageReader.cs +++ /dev/null @@ -1,279 +0,0 @@ -using System; -using System.Buffers; -using System.Buffers.Binary; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Text; -using Impostor.Api; -using Impostor.Api.Games; -using Impostor.Api.Net.Inner; -using Impostor.Api.Net.Messages; -using Impostor.Api.Unity; -using Microsoft.Extensions.ObjectPool; - -namespace Impostor.Hazel -{ - public class MessageReader : IMessageReader - { - private static readonly ArrayPool ArrayPool = ArrayPool.Shared; - - private readonly ObjectPool _pool; - private bool _inUse; - - internal MessageReader(ObjectPool pool) - { - _pool = pool; - } - - public byte[] Buffer { get; private set; } - - public int Offset { get; internal set; } - - public int Position { get; internal set; } - - public int Length { get; internal set; } - - public byte Tag { get; private set; } - - public MessageReader Parent { get; private set; } - - private int ReadPosition => Offset + Position; - - public void Update(byte[] buffer, int offset = 0, int position = 0, int? length = null, byte tag = byte.MaxValue, MessageReader parent = null) - { - _inUse = true; - - Buffer = buffer; - Offset = offset; - Position = position; - Length = length ?? buffer.Length; - Tag = tag; - Parent = parent; - } - - internal void Reset() - { - _inUse = false; - - Tag = byte.MaxValue; - Buffer = null; - Offset = 0; - Position = 0; - Length = 0; - Parent = null; - } - - public IMessageReader ReadMessage() - { - var length = ReadUInt16(); - var tag = FastByte(); - var pos = ReadPosition; - - Position += length; - - var reader = _pool.Get(); - reader.Update(Buffer, pos, 0, length, tag, this); - return reader; - } - - public bool ReadBoolean() - { - byte val = FastByte(); - return val != 0; - } - - public sbyte ReadSByte() - { - return (sbyte)FastByte(); - } - - public byte ReadByte() - { - return FastByte(); - } - - public ushort ReadUInt16() - { - var output = BinaryPrimitives.ReadUInt16LittleEndian(Buffer.AsSpan(ReadPosition)); - Position += sizeof(ushort); - return output; - } - - public short ReadInt16() - { - var output = BinaryPrimitives.ReadInt16LittleEndian(Buffer.AsSpan(ReadPosition)); - Position += sizeof(short); - return output; - } - - public uint ReadUInt32() - { - var output = BinaryPrimitives.ReadUInt32LittleEndian(Buffer.AsSpan(ReadPosition)); - Position += sizeof(uint); - return output; - } - - public int ReadInt32() - { - var output = BinaryPrimitives.ReadInt32LittleEndian(Buffer.AsSpan(ReadPosition)); - Position += sizeof(int); - return output; - } - - public unsafe float ReadSingle() - { - var output = BinaryPrimitives.ReadSingleLittleEndian(Buffer.AsSpan(ReadPosition)); - Position += sizeof(float); - return output; - } - - public string ReadString(int length) - { - var output = Encoding.UTF8.GetString(Buffer.AsSpan(ReadPosition, length)); - Position += length; - return output; - } - - public string ReadString() - { - return ReadString(ReadPackedInt32()); - } - - public ReadOnlyMemory ReadBytesAndSize() - { - var len = ReadPackedInt32(); - return ReadBytes(len); - } - - public ReadOnlyMemory ReadBytes(int length) - { - var output = Buffer.AsMemory(ReadPosition, length); - Position += length; - return output; - } - - public int ReadPackedInt32() - { - return (int)ReadPackedUInt32(); - } - - public uint ReadPackedUInt32() - { - bool readMore = true; - int shift = 0; - uint output = 0; - - while (readMore) - { - byte b = FastByte(); - if (b >= 0x80) - { - readMore = true; - b ^= 0x80; - } - else - { - readMore = false; - } - - output |= (uint)(b << shift); - shift += 7; - } - - return output; - } - - public void CopyTo(IMessageWriter writer) - { - writer.Write((ushort) Length); - writer.Write((byte) Tag); - writer.Write(Buffer.AsMemory(Offset, Length)); - } - - public void Seek(int position) - { - Position = position; - } - - public void RemoveMessage(IMessageReader message) - { - if (message.Buffer != Buffer) - { - throw new ImpostorProtocolException("Tried to remove message from a message that does not have the same buffer."); - } - - // Offset of where to start removing. - var offsetStart = message.Offset - 3; - - // Offset of where to end removing. - var offsetEnd = message.Offset + message.Length; - - // The amount of bytes to copy over ourselves. - var lengthToCopy = message.Buffer.Length - offsetEnd; - - System.Buffer.BlockCopy(Buffer, offsetEnd, Buffer, offsetStart, lengthToCopy); - - ((MessageReader) message).Parent.AdjustLength(message.Offset, message.Length + 3); - } - - private void AdjustLength(int offset, int amount) - { - this.Length -= amount; - - if (this.ReadPosition > offset) - { - this.Position -= amount; - } - - if (Parent != null) - { - var lengthOffset = this.Offset - 3; - var curLen = this.Buffer[lengthOffset] | - (this.Buffer[lengthOffset + 1] << 8); - - curLen -= amount; - - this.Buffer[lengthOffset] = (byte)curLen; - this.Buffer[lengthOffset + 1] = (byte)(this.Buffer[lengthOffset + 1] >> 8); - - Parent.AdjustLength(offset, amount); - } - } - - public IMessageReader Copy(int offset = 0) - { - var reader = _pool.Get(); - reader.Update(Buffer, Offset + offset, Position, Length - offset, Tag, Parent); - return reader; - } - - public T ReadNetObject(IGame game) where T : IInnerNetObject - { - return game.FindObjectByNetId(ReadPackedUInt32()); - } - - public Vector2 ReadVector2() - { - const float range = 50f; - - var x = ReadUInt16() / (float) ushort.MaxValue; - var y = ReadUInt16() / (float) ushort.MaxValue; - - return new Vector2(Mathf.Lerp(-range, range, x), Mathf.Lerp(-range, range, y)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private byte FastByte() - { - return Buffer[Offset + Position++]; - } - - public void Dispose() - { - if (_inUse) - { - _pool.Return(this); - } - } - } -} diff --git a/src/Impostor.Hazel/MessageReaderPolicy.cs b/src/Impostor.Hazel/MessageReaderPolicy.cs deleted file mode 100644 index ef3939a48..000000000 --- a/src/Impostor.Hazel/MessageReaderPolicy.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.ObjectPool; - -namespace Impostor.Hazel -{ - public class MessageReaderPolicy : IPooledObjectPolicy - { - private readonly IServiceProvider _serviceProvider; - - public MessageReaderPolicy(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - - public MessageReader Create() - { - return new MessageReader(_serviceProvider.GetRequiredService>()); - } - - public bool Return(MessageReader obj) - { - obj.Reset(); - return true; - } - } -} diff --git a/src/Impostor.Hazel/MessageWriter.cs b/src/Impostor.Hazel/MessageWriter.cs deleted file mode 100644 index a7b57e78e..000000000 --- a/src/Impostor.Hazel/MessageWriter.cs +++ /dev/null @@ -1,356 +0,0 @@ -using Impostor.Api.Games; -using Impostor.Api.Net.Messages; - -using System; -using System.Collections.Generic; -using System.Net; -using System.Numerics; -using System.Text; -using Impostor.Api.Net.Inner; -using Impostor.Api.Unity; - -namespace Impostor.Hazel -{ - public class MessageWriter : IMessageWriter, IRecyclable, IDisposable - { - private static int BufferSize = 64000; - private static readonly ObjectPoolCustom WriterPool = new ObjectPoolCustom(() => new MessageWriter(BufferSize)); - - public MessageType SendOption { get; private set; } - - private Stack messageStarts = new Stack(); - - public MessageWriter(byte[] buffer) - { - this.Buffer = buffer; - this.Length = this.Buffer.Length; - } - - public MessageWriter(int bufferSize) - { - this.Buffer = new byte[bufferSize]; - } - - public byte[] Buffer { get; } - public int Length { get; set; } - public int Position { get; set; } - - public byte[] ToByteArray(bool includeHeader) - { - if (includeHeader) - { - byte[] output = new byte[this.Length]; - System.Buffer.BlockCopy(this.Buffer, 0, output, 0, this.Length); - return output; - } - else - { - switch (this.SendOption) - { - case MessageType.Reliable: - { - byte[] output = new byte[this.Length - 3]; - System.Buffer.BlockCopy(this.Buffer, 3, output, 0, this.Length - 3); - return output; - } - case MessageType.Unreliable: - { - byte[] output = new byte[this.Length - 1]; - System.Buffer.BlockCopy(this.Buffer, 1, output, 0, this.Length - 1); - return output; - } - default: - throw new ArgumentOutOfRangeException(); - } - } - - throw new NotImplementedException(); - } - - /// - /// The option specifying how the message should be sent. - public static MessageWriter Get(MessageType sendOption = MessageType.Unreliable) - { - var output = WriterPool.GetObject(); - output.Clear(sendOption); - - return output; - } - - public bool HasBytes(int expected) - { - if (this.SendOption == MessageType.Unreliable) - { - return this.Length > 1 + expected; - } - - return this.Length > 3 + expected; - } - - public void Write(GameCode value) - { - this.Write(value.Value); - } - - public void Write(IInnerNetObject innerNetObject) - { - if (innerNetObject == null) - { - this.Write(0); - } - else - { - this.WritePacked(innerNetObject.NetId); - } - } - - public void Write(Vector2 vector) - { - Write((ushort)(Mathf.ReverseLerp(vector.X) * (double) ushort.MaxValue)); - Write((ushort)(Mathf.ReverseLerp(vector.Y) * (double) ushort.MaxValue)); - } - - /// - public void StartMessage(byte typeFlag) - { - messageStarts.Push(this.Position); - this.Position += 2; // Skip for size - this.Write(typeFlag); - } - - /// - public void EndMessage() - { - var lastMessageStart = messageStarts.Pop(); - ushort length = (ushort)(this.Position - lastMessageStart - 3); // Minus length and type byte - this.Buffer[lastMessageStart] = (byte)length; - this.Buffer[lastMessageStart + 1] = (byte)(length >> 8); - } - - /// - public void CancelMessage() - { - this.Position = this.messageStarts.Pop(); - this.Length = this.Position; - } - - public void Clear(MessageType sendOption) - { - this.messageStarts.Clear(); - this.SendOption = sendOption; - this.Buffer[0] = (byte)sendOption; - switch (sendOption) - { - default: - case MessageType.Unreliable: - this.Length = this.Position = 1; - break; - - case MessageType.Reliable: - this.Length = this.Position = 3; - break; - } - } - - /// - public void Recycle() - { - this.Position = this.Length = 0; - WriterPool.PutObject(this); - } - - #region WriteMethods - - public void Write(bool value) - { - this.Buffer[this.Position++] = (byte)(value ? 1 : 0); - if (this.Position > this.Length) this.Length = this.Position; - } - - public void Write(sbyte value) - { - this.Buffer[this.Position++] = (byte)value; - if (this.Position > this.Length) this.Length = this.Position; - } - - public void Write(byte value) - { - this.Buffer[this.Position++] = value; - if (this.Position > this.Length) this.Length = this.Position; - } - - public void Write(short value) - { - this.Buffer[this.Position++] = (byte)value; - this.Buffer[this.Position++] = (byte)(value >> 8); - if (this.Position > this.Length) this.Length = this.Position; - } - - public void Write(ushort value) - { - this.Buffer[this.Position++] = (byte)value; - this.Buffer[this.Position++] = (byte)(value >> 8); - if (this.Position > this.Length) this.Length = this.Position; - } - - public void Write(uint value) - { - this.Buffer[this.Position++] = (byte)value; - this.Buffer[this.Position++] = (byte)(value >> 8); - this.Buffer[this.Position++] = (byte)(value >> 16); - this.Buffer[this.Position++] = (byte)(value >> 24); - if (this.Position > this.Length) this.Length = this.Position; - } - - public void Write(int value) - { - this.Buffer[this.Position++] = (byte)value; - this.Buffer[this.Position++] = (byte)(value >> 8); - this.Buffer[this.Position++] = (byte)(value >> 16); - this.Buffer[this.Position++] = (byte)(value >> 24); - if (this.Position > this.Length) this.Length = this.Position; - } - - public unsafe void Write(float value) - { - fixed (byte* ptr = &this.Buffer[this.Position]) - { - byte* valuePtr = (byte*)&value; - - *ptr = *valuePtr; - *(ptr + 1) = *(valuePtr + 1); - *(ptr + 2) = *(valuePtr + 2); - *(ptr + 3) = *(valuePtr + 3); - } - - this.Position += 4; - if (this.Position > this.Length) this.Length = this.Position; - } - - public void Write(string value) - { - var bytes = UTF8Encoding.UTF8.GetBytes(value); - this.WritePacked(bytes.Length); - this.Write(bytes); - } - - public void Write(IPAddress value) - { - this.Write(value.GetAddressBytes()); - } - - public void WriteBytesAndSize(byte[] bytes) - { - this.WritePacked((uint)bytes.Length); - this.Write(bytes); - } - - public void WriteBytesAndSize(byte[] bytes, int length) - { - this.WritePacked((uint)length); - this.Write(bytes, length); - } - - public void WriteBytesAndSize(byte[] bytes, int offset, int length) - { - this.WritePacked((uint)length); - this.Write(bytes, offset, length); - } - - public void Write(ReadOnlyMemory data) - { - Write(data.Span); - } - - public void Write(ReadOnlySpan bytes) - { - bytes.CopyTo(this.Buffer.AsSpan(this.Position, bytes.Length)); - - this.Position += bytes.Length; - if (this.Position > this.Length) this.Length = this.Position; - } - - public void Write(byte[] bytes) - { - Array.Copy(bytes, 0, this.Buffer, this.Position, bytes.Length); - this.Position += bytes.Length; - if (this.Position > this.Length) this.Length = this.Position; - } - - public void Write(byte[] bytes, int offset, int length) - { - Array.Copy(bytes, offset, this.Buffer, this.Position, length); - this.Position += length; - if (this.Position > this.Length) this.Length = this.Position; - } - - public void Write(byte[] bytes, int length) - { - Array.Copy(bytes, 0, this.Buffer, this.Position, length); - this.Position += length; - if (this.Position > this.Length) this.Length = this.Position; - } - - /// - public void WritePacked(int value) - { - this.WritePacked((uint)value); - } - - /// - public void WritePacked(uint value) - { - do - { - byte b = (byte)(value & 0xFF); - if (value >= 0x80) - { - b |= 0x80; - } - - this.Write(b); - value >>= 7; - } while (value > 0); - } - - #endregion WriteMethods - - public void Write(MessageWriter msg, bool includeHeader) - { - int offset = 0; - if (!includeHeader) - { - switch (msg.SendOption) - { - case MessageType.Unreliable: - offset = 1; - break; - - case MessageType.Reliable: - offset = 3; - break; - } - } - - this.Write(msg.Buffer, offset, msg.Length - offset); - } - - public unsafe static bool IsLittleEndian() - { - byte b; - unsafe - { - int i = 1; - byte* bp = (byte*)&i; - b = *bp; - } - - return b == 1; - } - - public void Dispose() - { - Recycle(); - } - } -} diff --git a/src/Impostor.Hazel/NetworkConnection.cs b/src/Impostor.Hazel/NetworkConnection.cs deleted file mode 100644 index 9e81c5cc0..000000000 --- a/src/Impostor.Hazel/NetworkConnection.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; -using System.Net; -using System.Threading.Tasks; -using Impostor.Api.Net.Messages; - -namespace Impostor.Hazel -{ - public enum HazelInternalErrors - { - SocketExceptionSend, - SocketExceptionReceive, - ReceivedZeroBytes, - PingsWithoutResponse, - ReliablePacketWithoutResponse, - ConnectionDisconnected - } - - /// - /// Abstract base class for a to a remote end point via a network protocol like TCP or UDP. - /// - /// - public abstract class NetworkConnection : Connection - { - /// - /// An event that gives us a chance to send well-formed disconnect messages to clients when an internal disconnect happens. - /// - public Func OnInternalDisconnect; - - /// - /// The remote end point of this connection. - /// - /// - /// This is the end point of the other device given as an rather than a generic - /// as the base does. - /// - public IPEndPoint RemoteEndPoint { get; protected set; } - - public long GetIP4Address() - { - 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); - } - - /// - /// Sends a disconnect message to the end point. - /// - protected abstract ValueTask SendDisconnect(MessageWriter writer); - - /// - /// Called when the socket has been disconnected at the remote host. - /// - protected async ValueTask DisconnectRemote(string reason, IMessageReader reader) - { - if (await SendDisconnect(null)) - { - try - { - await InvokeDisconnected(reason, reader); - } - catch { } - } - - this.Dispose(); - } - - /// - /// Called when socket is disconnected internally - /// - internal async ValueTask DisconnectInternal(HazelInternalErrors error, string reason) - { - var handler = this.OnInternalDisconnect; - if (handler != null) - { - MessageWriter messageToRemote = handler(error); - if (messageToRemote != null) - { - try - { - await Disconnect(reason, messageToRemote); - } - finally - { - messageToRemote.Recycle(); - } - } - else - { - await Disconnect(reason); - } - } - else - { - await Disconnect(reason); - } - } - - /// - /// Called when the socket has been disconnected locally. - /// - public override async ValueTask Disconnect(string reason, MessageWriter writer = null) - { - if (await SendDisconnect(writer)) - { - try - { - await InvokeDisconnected(reason, null); - } - catch { } - } - - this.Dispose(); - } - } -} diff --git a/src/Impostor.Hazel/NetworkConnectionListener.cs b/src/Impostor.Hazel/NetworkConnectionListener.cs deleted file mode 100644 index e1d7ffaf8..000000000 --- a/src/Impostor.Hazel/NetworkConnectionListener.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Net; - -namespace Impostor.Hazel -{ - /// - /// Abstract base class for a for network based connections. - /// - /// - public abstract class NetworkConnectionListener : ConnectionListener - { - /// - /// The local end point the listener is listening for new clients on. - /// - public IPEndPoint EndPoint { get; protected set; } - - /// - /// The IPMode the listener is listening for new clients on. - /// - public IPMode IPMode { get; protected set; } - } -} diff --git a/src/Impostor.Hazel/NewConnectionEventArgs.cs b/src/Impostor.Hazel/NewConnectionEventArgs.cs deleted file mode 100644 index be9e7a214..000000000 --- a/src/Impostor.Hazel/NewConnectionEventArgs.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Impostor.Api.Net.Messages; - -namespace Impostor.Hazel -{ - public struct NewConnectionEventArgs - { - /// - /// The data received from the client in the handshake. - /// This data is yours. Remember to recycle it. - /// - public readonly IMessageReader HandshakeData; - - /// - /// The to the new client. - /// - public readonly Connection Connection; - - public NewConnectionEventArgs(IMessageReader handshakeData, Connection connection) - { - this.HandshakeData = handshakeData; - this.Connection = connection; - } - } -} diff --git a/src/Impostor.Hazel/ObjectPoolCustom.cs b/src/Impostor.Hazel/ObjectPoolCustom.cs deleted file mode 100644 index 5c9ef9b40..000000000 --- a/src/Impostor.Hazel/ObjectPoolCustom.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Threading; - -namespace Impostor.Hazel -{ - /// - /// A fairly simple object pool for items that will be created a lot. - /// - /// The type that is pooled. - /// - public sealed class ObjectPoolCustom where T : IRecyclable - { - private int numberCreated; - public int NumberCreated { get { return numberCreated; } } - - public int NumberInUse { get { return this.inuse.Count; } } - public int NumberNotInUse { get { return this.pool.Count; } } - public int Size { get { return this.NumberInUse + this.NumberNotInUse; } } - -#if HAZEL_BAG - private readonly ConcurrentBag pool = new ConcurrentBag(); -#else - private readonly List pool = new List(); -#endif - - // Unavailable objects - private readonly ConcurrentDictionary inuse = new ConcurrentDictionary(); - - /// - /// The generator for creating new objects. - /// - /// - private readonly Func objectFactory; - - /// - /// Internal constructor for our ObjectPool. - /// - internal ObjectPoolCustom(Func objectFactory) - { - this.objectFactory = objectFactory; - } - - /// - /// Returns a pooled object of type T, if none are available another is created. - /// - /// An instance of T. - internal T GetObject() - { -#if HAZEL_BAG - if (!pool.TryTake(out T item)) - { - Interlocked.Increment(ref numberCreated); - item = objectFactory.Invoke(); - } -#else - T item; - lock (this.pool) - { - if (this.pool.Count > 0) - { - var idx = this.pool.Count - 1; - item = this.pool[idx]; - this.pool.RemoveAt(idx); - } - else - { - Interlocked.Increment(ref numberCreated); - item = objectFactory.Invoke(); - } - } -#endif - - if (!inuse.TryAdd(item, true)) - { - throw new Exception("Duplicate pull " + typeof(T).Name); - } - - return item; - } - - /// - /// Returns an object to the pool. - /// - /// The item to return. - internal void PutObject(T item) - { - if (inuse.TryRemove(item, out bool b)) - { -#if HAZEL_BAG - pool.Add(item); -#else - lock (this.pool) - { - pool.Add(item); - } -#endif - } - else - { -#if DEBUG - throw new Exception("Duplicate add " + typeof(T).Name); -#endif - } - } - } -} diff --git a/src/Impostor.Hazel/Udp/SendOptionInternal.cs b/src/Impostor.Hazel/Udp/SendOptionInternal.cs deleted file mode 100644 index c0c4e2127..000000000 --- a/src/Impostor.Hazel/Udp/SendOptionInternal.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace Impostor.Hazel.Udp -{ - /// - /// Extra internal states for SendOption enumeration when using UDP. - /// - public enum UdpSendOption : byte - { - /// - /// Hello message for initiating communication. - /// - Hello = 8, - - /// - /// A single byte of continued existence - /// - Ping = 12, - - /// - /// Message for discontinuing communication. - /// - Disconnect = 9, - - /// - /// Message acknowledging the receipt of a message. - /// - Acknowledgement = 10, - - /// - /// Message that is part of a larger, fragmented message. - /// - Fragment = 11, - } -} diff --git a/src/Impostor.Hazel/Udp/UdpBroadcastListener.cs b/src/Impostor.Hazel/Udp/UdpBroadcastListener.cs deleted file mode 100644 index ed7b68dbd..000000000 --- a/src/Impostor.Hazel/Udp/UdpBroadcastListener.cs +++ /dev/null @@ -1,156 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Sockets; -using System.Text; - -namespace Impostor.Hazel.Udp -{ - public class BroadcastPacket - { - public string Data; - public DateTime ReceiveTime; - public IPEndPoint Sender; - - public BroadcastPacket(string data, IPEndPoint sender) - { - this.Data = data; - this.Sender = sender; - this.ReceiveTime = DateTime.Now; - } - - public string GetAddress() - { - return this.Sender.Address.ToString(); - } - } - - public class UdpBroadcastListener : IDisposable - { - private Socket socket; - private EndPoint endpoint; - private Action logger; - - private byte[] buffer = new byte[1024]; - - private List packets = new List(); - - public bool Running { get; private set; } - - /// - public UdpBroadcastListener(int port, Action logger = null) - { - this.logger = logger; - this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - this.socket.EnableBroadcast = true; - this.socket.MulticastLoopback = false; - this.endpoint = new IPEndPoint(IPAddress.Any, port); - this.socket.Bind(this.endpoint); - } - - /// - public void StartListen() - { - if (this.Running) return; - this.Running = true; - - try - { - EndPoint endpt = new IPEndPoint(IPAddress.Any, 0); - this.socket.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref endpt, this.HandleData, null); - } - catch (NullReferenceException) { } - catch (Exception e) - { - this.logger?.Invoke("BroadcastListener: " + e); - this.Dispose(); - } - } - - private void HandleData(IAsyncResult result) - { - this.Running = false; - - int numBytes; - EndPoint endpt = new IPEndPoint(IPAddress.Any, 0); - try - { - numBytes = this.socket.EndReceiveFrom(result, ref endpt); - } - catch (NullReferenceException) - { - // Already disposed - return; - } - catch (Exception e) - { - this.logger?.Invoke("BroadcastListener: " + e); - this.Dispose(); - return; - } - - if (numBytes < 3 - || buffer[0] != 4 || buffer[1] != 2) - { - this.StartListen(); - return; - } - - IPEndPoint ipEnd = (IPEndPoint)endpt; - string data = UTF8Encoding.UTF8.GetString(buffer, 2, numBytes - 2); - int dataHash = data.GetHashCode(); - - lock (packets) - { - bool found = false; - for (int i = 0; i < this.packets.Count; ++i) - { - var pkt = this.packets[i]; - if (pkt == null || pkt.Data == null) - { - this.packets.RemoveAt(i); - i--; - continue; - } - - if (pkt.Data.GetHashCode() == dataHash - && pkt.Sender.Equals(ipEnd)) - { - this.packets[i].ReceiveTime = DateTime.Now; - break; - } - } - - if (!found) - { - this.packets.Add(new BroadcastPacket(data, ipEnd)); - } - } - - this.StartListen(); - } - - /// - public BroadcastPacket[] GetPackets() - { - lock (this.packets) - { - var output = this.packets.ToArray(); - this.packets.Clear(); - return output; - } - } - - /// - public void Dispose() - { - if (this.socket != null) - { - try { this.socket.Shutdown(SocketShutdown.Both); } catch { } - try { this.socket.Close(); } catch { } - try { this.socket.Dispose(); } catch { } - this.socket = null; - } - } - } -} \ No newline at end of file diff --git a/src/Impostor.Hazel/Udp/UdpBroadcaster.cs b/src/Impostor.Hazel/Udp/UdpBroadcaster.cs deleted file mode 100644 index 5fa1ccac2..000000000 --- a/src/Impostor.Hazel/Udp/UdpBroadcaster.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Text; - -namespace Impostor.Hazel.Udp -{ - /// - public class UdpBroadcaster : IDisposable - { - private Socket socket; - private byte[] data; - private EndPoint endpoint; - private Action logger; - - /// - public UdpBroadcaster(int port, Action logger = null) - { - this.logger = logger; - this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - this.socket.EnableBroadcast = true; - this.socket.MulticastLoopback = false; - this.endpoint = new IPEndPoint(IPAddress.Broadcast, port); - } - - /// - public void SetData(string data) - { - int len = UTF8Encoding.UTF8.GetByteCount(data); - this.data = new byte[len + 2]; - this.data[0] = 4; - this.data[1] = 2; - - UTF8Encoding.UTF8.GetBytes(data, 0, data.Length, this.data, 2); - } - - /// - public void Broadcast() - { - if (this.data == null) - { - return; - } - - try - { - this.socket.BeginSendTo(data, 0, data.Length, SocketFlags.None, this.endpoint, this.FinishSendTo, null); - } - catch (Exception e) - { - this.logger?.Invoke("BroadcastListener: " + e); - } - } - - private void FinishSendTo(IAsyncResult evt) - { - try - { - this.socket.EndSendTo(evt); - } - catch (Exception e) - { - this.logger?.Invoke("BroadcastListener: " + e); - } - } - - /// - public void Dispose() - { - if (this.socket != null) - { - try { this.socket.Shutdown(SocketShutdown.Both); } catch { } - try { this.socket.Close(); } catch { } - try { this.socket.Dispose(); } catch { } - this.socket = null; - } - } - } -} \ No newline at end of file diff --git a/src/Impostor.Hazel/Udp/UdpClientConnection.cs b/src/Impostor.Hazel/Udp/UdpClientConnection.cs deleted file mode 100644 index 5125ebe80..000000000 --- a/src/Impostor.Hazel/Udp/UdpClientConnection.cs +++ /dev/null @@ -1,225 +0,0 @@ -using System; -using System.Buffers; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Channels; -using System.Threading.Tasks; -using Impostor.Api.Net.Messages; -using Microsoft.Extensions.ObjectPool; -using Serilog; - -namespace Impostor.Hazel.Udp -{ - /// - /// Represents a client's connection to a server that uses the UDP protocol. - /// - /// - public sealed class UdpClientConnection : UdpConnection - { - private static readonly ILogger Logger = Log.ForContext(); - - /// - /// The socket we're connected via. - /// - private readonly UdpClient _socket; - - private readonly Timer _reliablePacketTimer; - private readonly SemaphoreSlim _connectWaitLock; - private Task _listenTask; - - /// - /// Creates a new UdpClientConnection. - /// - /// A to connect to. - public UdpClientConnection(IPEndPoint remoteEndPoint, ObjectPool readerPool, IPMode ipMode = IPMode.IPv4) : base(null, readerPool) - { - EndPoint = remoteEndPoint; - RemoteEndPoint = remoteEndPoint; - IPMode = ipMode; - - _socket = new UdpClient - { - DontFragment = false - }; - - _reliablePacketTimer = new Timer(ManageReliablePacketsInternal, null, 100, Timeout.Infinite); - _connectWaitLock = new SemaphoreSlim(1, 1); - } - - ~UdpClientConnection() - { - Dispose(false); - } - - private async void ManageReliablePacketsInternal(object state) - { - await ManageReliablePackets(); - - try - { - _reliablePacketTimer.Change(100, Timeout.Infinite); - } - catch - { - // ignored - } - } - - /// - protected override ValueTask WriteBytesToConnection(byte[] bytes, int length) - { - return WriteBytesToConnectionReal(bytes, length); - } - - private async ValueTask WriteBytesToConnectionReal(byte[] bytes, int length) - { - try - { - await _socket.SendAsync(bytes, length); - } - catch (NullReferenceException) { } - catch (ObjectDisposedException) - { - // Already disposed and disconnected... - } - catch (SocketException ex) - { - await DisconnectInternal(HazelInternalErrors.SocketExceptionSend, "Could not send data as a SocketException occurred: " + ex.Message); - } - } - - /// - public override async ValueTask ConnectAsync(byte[] bytes = null) - { - State = ConnectionState.Connecting; - - try - { - _socket.Connect(RemoteEndPoint); - } - catch (SocketException e) - { - State = ConnectionState.NotConnected; - throw new HazelException("A SocketException occurred while binding to the port.", e); - } - - try - { - _listenTask = Task.Factory.StartNew(ListenAsync, TaskCreationOptions.LongRunning); - } - catch (ObjectDisposedException) - { - // If the socket's been disposed then we can just end there but make sure we're in NotConnected state. - // If we end up here I'm really lost... - State = ConnectionState.NotConnected; - return; - } - catch (SocketException e) - { - Dispose(); - throw new HazelException("A SocketException occurred while initiating a receive operation.", e); - } - - // Write bytes to the server to tell it hi (and to punch a hole in our NAT, if present) - // When acknowledged set the state to connected - await SendHello(bytes, () => - { - State = ConnectionState.Connected; - InitializeKeepAliveTimer(); - }); - - await _connectWaitLock.WaitAsync(TimeSpan.FromSeconds(10)); - } - - private async Task ListenAsync() - { - // Start packet handler. - await StartAsync(); - - // Listen. - while (State != ConnectionState.NotConnected) - { - UdpReceiveResult data; - - try - { - data = await _socket.ReceiveAsync(); - } - catch (SocketException e) - { - await DisconnectInternal(HazelInternalErrors.SocketExceptionReceive, "Socket exception while reading data: " + e.Message); - return; - } - catch (Exception) - { - return; - } - - if (data.Buffer.Length == 0) - { - await DisconnectInternal(HazelInternalErrors.ReceivedZeroBytes, "Received 0 bytes"); - return; - } - - // Write to client. - await Pipeline.Writer.WriteAsync(data.Buffer); - } - } - - protected override void SetState(ConnectionState state) - { - if (state == ConnectionState.Connected) - { - _connectWaitLock.Release(); - } - } - - /// - /// Sends a disconnect message to the end point. - /// You may include optional disconnect data. The SendOption must be unreliable. - /// - protected override async ValueTask SendDisconnect(MessageWriter data = null) - { - lock (this) - { - if (_state == ConnectionState.NotConnected) return false; - _state = ConnectionState.NotConnected; - } - - var bytes = EmptyDisconnectBytes; - if (data != null && data.Length > 0) - { - if (data.SendOption != MessageType.Unreliable) - { - throw new ArgumentException("Disconnect messages can only be unreliable."); - } - - bytes = data.ToByteArray(true); - bytes[0] = (byte)UdpSendOption.Disconnect; - } - - try - { - await _socket.SendAsync(bytes, bytes.Length, RemoteEndPoint); - } - catch { } - - return true; - } - - /// - protected override void Dispose(bool disposing) - { - State = ConnectionState.NotConnected; - - try { _socket.Close(); } catch { } - try { _socket.Dispose(); } catch { } - - _reliablePacketTimer.Dispose(); - _connectWaitLock.Dispose(); - - base.Dispose(disposing); - } - } -} diff --git a/src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs b/src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs deleted file mode 100644 index a73291bc4..000000000 --- a/src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; - -namespace Impostor.Hazel.Udp -{ - partial class UdpConnection - { - - /// - /// Class to hold packet data - /// - public class PingPacket : IRecyclable - { - private static readonly ObjectPoolCustom PacketPool = new ObjectPoolCustom(() => new PingPacket()); - - public readonly Stopwatch Stopwatch = new Stopwatch(); - - internal static PingPacket GetObject() - { - return PacketPool.GetObject(); - } - - public void Recycle() - { - Stopwatch.Stop(); - PacketPool.PutObject(this); - } - } - - internal ConcurrentDictionary activePingPackets = new ConcurrentDictionary(); - - /// - /// The interval from data being received or transmitted to a keepalive packet being sent in milliseconds. - /// - /// - /// - /// Keepalive packets serve to close connections when an endpoint abruptly disconnects and to ensure than any - /// NAT devices do not close their translation for our argument. By ensuring there is regular contact the - /// connection can detect and prevent these issues. - /// - /// - /// The default value is 10 seconds, set to System.Threading.Timeout.Infinite to disable keepalive packets. - /// - /// - public int KeepAliveInterval - { - get - { - return keepAliveInterval; - } - - set - { - keepAliveInterval = value; - ResetKeepAliveTimer(); - } - } - private int keepAliveInterval = 1500; - - public int MissingPingsUntilDisconnect { get; set; } = 6; - private volatile int pingsSinceAck = 0; - - /// - /// The timer creating keepalive pulses. - /// - private Timer keepAliveTimer; - - /// - /// Starts the keepalive timer. - /// - protected void InitializeKeepAliveTimer() - { - keepAliveTimer = new Timer( - HandleKeepAlive, - null, - keepAliveInterval, - keepAliveInterval - ); - } - - private async void HandleKeepAlive(object state) - { - if (this.State != ConnectionState.Connected) return; - - if (this.pingsSinceAck >= this.MissingPingsUntilDisconnect) - { - this.DisposeKeepAliveTimer(); - await this.DisconnectInternal(HazelInternalErrors.PingsWithoutResponse, $"Sent {this.pingsSinceAck} pings that remote has not responded to."); - return; - } - - try - { - Interlocked.Increment(ref pingsSinceAck); - await SendPing(); - } - catch - { - } - } - - // Pings are special, quasi-reliable packets. - // We send them to trigger responses that validate our connection is alive - // An unacked ping should never be the sole cause of a disconnect. - // Rather, the responses will reset our pingsSinceAck, enough unacked - // pings should cause a disconnect. - private async ValueTask SendPing() - { - ushort id = (ushort)Interlocked.Increment(ref lastIDAllocated); - - byte[] bytes = new byte[3]; - bytes[0] = (byte)UdpSendOption.Ping; - bytes[1] = (byte)(id >> 8); - bytes[2] = (byte)id; - - PingPacket pkt; - if (!this.activePingPackets.TryGetValue(id, out pkt)) - { - pkt = PingPacket.GetObject(); - if (!this.activePingPackets.TryAdd(id, pkt)) - { - throw new Exception("This shouldn't be possible"); - } - } - - pkt.Stopwatch.Restart(); - - await WriteBytesToConnection(bytes, bytes.Length); - - Statistics.LogReliableSend(0, bytes.Length); - } - - /// - /// Resets the keepalive timer to zero. - /// - private void ResetKeepAliveTimer() - { - try - { - keepAliveTimer.Change(keepAliveInterval, keepAliveInterval); - } - catch { } - } - - /// - /// Disposes of the keep alive timer. - /// - private void DisposeKeepAliveTimer() - { - if (this.keepAliveTimer != null) - { - this.keepAliveTimer.Dispose(); - } - - foreach (var kvp in activePingPackets) - { - if (this.activePingPackets.TryRemove(kvp.Key, out var pkt)) - { - pkt.Recycle(); - } - } - } - } -} \ No newline at end of file diff --git a/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs b/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs deleted file mode 100644 index 7f439269d..000000000 --- a/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs +++ /dev/null @@ -1,493 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using Impostor.Api.Net.Messages; - -namespace Impostor.Hazel.Udp -{ - partial class UdpConnection - { - /// - /// The starting timeout, in miliseconds, at which data will be resent. - /// - /// - /// - /// For reliable delivery data is resent at specified intervals unless an acknowledgement is received from the - /// receiving device. The ResendTimeout specifies the interval between the packets being resent, each time a packet - /// is resent the interval is increased for that packet until the duration exceeds the value. - /// - /// - /// Setting this to its default of 0 will mean the timeout is 2 times the value of the average ping, usually - /// resulting in a more dynamic resend that responds to endpoints on slower or faster connections. - /// - /// - public volatile int ResendTimeout = 0; - - /// - /// Max number of times to resend. 0 == no limit - /// - public volatile int ResendLimit = 0; - - /// - /// A compounding multiplier to back off resend timeout. - /// Applied to ping before first timeout when ResendTimeout == 0. - /// - public volatile float ResendPingMultiplier = 2; - - /// - /// Holds the last ID allocated. - /// - private int lastIDAllocated = 0; - - /// - /// The packets of data that have been transmitted reliably and not acknowledged. - /// - internal ConcurrentDictionary reliableDataPacketsSent = new ConcurrentDictionary(); - - /// - /// Packet ids that have not been received, but are expected. - /// - private HashSet reliableDataPacketsMissing = new HashSet(); - - /// - /// The packet id that was received last. - /// - private volatile ushort reliableReceiveLast = ushort.MaxValue; - - private object PingLock = new object(); - - /// - /// Returns the average ping to this endpoint. - /// - /// - /// This returns the average ping for a one-way trip as calculated from the reliable packets that have been sent - /// and acknowledged by the endpoint. - /// - public float AveragePingMs = 500; - - /// - /// The maximum times a message should be resent before marking the endpoint as disconnected. - /// - /// - /// Reliable packets will be resent at an interval defined in for the number of times - /// specified here. Once a packet has been retransmitted this number of times and has not been acknowledged the - /// connection will be marked as disconnected and the Disconnected event - /// will be invoked. - /// - public volatile int DisconnectTimeout = 5000; - - /// - /// Class to hold packet data - /// - public class Packet : IRecyclable - { - /// - /// Object pool for this event. - /// - public static readonly ObjectPoolCustom PacketPool = new ObjectPoolCustom(() => new Packet()); - - /// - /// Returns an instance of this object from the pool. - /// - /// - internal static Packet GetObject() - { - return PacketPool.GetObject(); - } - - public ushort Id; - private byte[] Data; - private UdpConnection Connection; - private int Length; - - public int NextTimeout; - public volatile bool Acknowledged; - - public Action AckCallback; - - public int Retransmissions; - public Stopwatch Stopwatch = new Stopwatch(); - - Packet() - { - } - - internal void Set(ushort id, UdpConnection connection, byte[] data, int length, int timeout, Action ackCallback) - { - this.Id = id; - this.Data = data; - this.Connection = connection; - this.Length = length; - - this.Acknowledged = false; - this.NextTimeout = timeout; - this.AckCallback = ackCallback; - this.Retransmissions = 0; - - this.Stopwatch.Restart(); - } - - // Packets resent - public async ValueTask Resend() - { - var connection = this.Connection; - if (!this.Acknowledged && connection != null) - { - long lifetime = this.Stopwatch.ElapsedMilliseconds; - if (lifetime >= connection.DisconnectTimeout) - { - if (connection.reliableDataPacketsSent.TryRemove(this.Id, out Packet self)) - { - await connection.DisconnectInternal(HazelInternalErrors.ReliablePacketWithoutResponse, $"Reliable packet {self.Id} (size={this.Length}) was not ack'd after {lifetime}ms ({self.Retransmissions} resends)"); - - self.Recycle(); - } - - return 0; - } - - if (lifetime >= this.NextTimeout) - { - ++this.Retransmissions; - if (connection.ResendLimit != 0 - && this.Retransmissions > connection.ResendLimit) - { - if (connection.reliableDataPacketsSent.TryRemove(this.Id, out Packet self)) - { - await connection.DisconnectInternal(HazelInternalErrors.ReliablePacketWithoutResponse, $"Reliable packet {self.Id} (size={this.Length}) was not ack'd after {self.Retransmissions} resends ({lifetime}ms)"); - - self.Recycle(); - } - - return 0; - } - - this.NextTimeout += (int)Math.Min(this.NextTimeout * connection.ResendPingMultiplier, 1000); - try - { - await connection.WriteBytesToConnection(this.Data, this.Length); - connection.Statistics.LogMessageResent(); - return 1; - } - catch (InvalidOperationException) - { - await connection.DisconnectInternal(HazelInternalErrors.ConnectionDisconnected, "Could not resend data as connection is no longer connected"); - } - } - } - - return 0; - } - - /// - /// Returns this object back to the object pool from whence it came. - /// - public void Recycle() - { - this.Acknowledged = true; - this.Connection = null; - - PacketPool.PutObject(this); - } - } - - internal async ValueTask ManageReliablePackets() - { - int output = 0; - if (this.reliableDataPacketsSent.Count > 0) - { - foreach (var kvp in this.reliableDataPacketsSent) - { - Packet pkt = kvp.Value; - - try - { - output += await pkt.Resend(); - } - catch { } - } - } - - return output; - } - - /// - /// Adds a 2 byte ID to the packet at offset and stores the packet reference for retransmission. - /// - /// The buffer to attach to. - /// The offset to attach at. - /// The callback to make once the packet has been acknowledged. - protected void AttachReliableID(byte[] buffer, int offset, int sendLength, Action ackCallback = null) - { - ushort id = (ushort)Interlocked.Increment(ref lastIDAllocated); - - buffer[offset] = (byte)(id >> 8); - buffer[offset + 1] = (byte)id; - - Packet packet = Packet.GetObject(); - packet.Set( - id, - this, - buffer, - sendLength, - ResendTimeout > 0 ? ResendTimeout : (int)Math.Min(AveragePingMs * this.ResendPingMultiplier, 300), - ackCallback); - - if (!reliableDataPacketsSent.TryAdd(id, packet)) - { - throw new Exception("That shouldn't be possible"); - } - } - - public static int ClampToInt(float value, int min, int max) - { - if (value < min) return min; - if (value > max) return max; - return (int)value; - } - - /// - /// Sends the bytes reliably and stores the send. - /// - /// - /// The byte array to write to. - /// The callback to make once the packet has been acknowledged. - private async ValueTask ReliableSend(byte sendOption, byte[] data, Action ackCallback = null) - { - //Inform keepalive not to send for a while - ResetKeepAliveTimer(); - - byte[] bytes = new byte[data.Length + 3]; - - //Add message type - bytes[0] = sendOption; - - //Add reliable ID - AttachReliableID(bytes, 1, bytes.Length, ackCallback); - - //Copy data into new array - Buffer.BlockCopy(data, 0, bytes, bytes.Length - data.Length, data.Length); - - //Write to connection - await WriteBytesToConnection(bytes, bytes.Length); - - Statistics.LogReliableSend(data.Length, bytes.Length); - } - - /// - /// Handles a reliable message being received and invokes the data event. - /// - /// The buffer received. - private async ValueTask ReliableMessageReceive(MessageReader message) - { - if (await ProcessReliableReceive(message.Buffer, 1)) - { - message.Offset += 3; - message.Length -= 3; - message.Position = 0; - - await InvokeDataReceived(message, MessageType.Reliable); - } - - Statistics.LogReliableReceive(message.Length - 3, message.Length); - } - - /// - /// Handles receives from reliable packets. - /// - /// The buffer containing the data. - /// The offset of the reliable header. - /// Whether the packet was a new packet or not. - private async ValueTask ProcessReliableReceive(ReadOnlyMemory bytes, int offset) - { - var b1 = bytes.Span[offset]; - var b2 = bytes.Span[offset + 1]; - - //Get the ID form the packet - var id = (ushort)((b1 << 8) + b2); - - /* - * It gets a little complicated here (note the fact I'm actually using a multiline comment for once...) - * - * In a simple world if our data is greater than the last reliable packet received (reliableReceiveLast) - * then it is guaranteed to be a new packet, if it's not we can see if we are missing that packet (lookup - * in reliableDataPacketsMissing). - * - * --------rrl############# (1) - * - * (where --- are packets received already and #### are packets that will be counted as new) - * - * Unfortunately if id becomes greater than 65535 it will loop back to zero so we will add a pointer that - * specifies any packets with an id behind it are also new (overwritePointer). - * - * ####op----------rrl##### (2) - * - * ------rll#########op---- (3) - * - * Anything behind than the reliableReceiveLast pointer (but greater than the overwritePointer is either a - * missing packet or something we've already received so when we change the pointers we need to make sure - * we keep note of what hasn't been received yet (reliableDataPacketsMissing). - * - * So... - */ - - var result = true; - - lock (reliableDataPacketsMissing) - { - //Calculate overwritePointer - ushort overwritePointer = (ushort)(reliableReceiveLast - 32768); - - //Calculate if it is a new packet by examining if it is within the range - bool isNew; - if (overwritePointer < reliableReceiveLast) - isNew = id > reliableReceiveLast || id <= overwritePointer; //Figure (2) - else - isNew = id > reliableReceiveLast && id <= overwritePointer; //Figure (3) - - //If it's new or we've not received anything yet - if (isNew) - { - // Mark items between the most recent receive and the id received as missing - if (id > reliableReceiveLast) - { - for (ushort i = (ushort)(reliableReceiveLast + 1); i < id; i++) - { - reliableDataPacketsMissing.Add(i); - } - } - else - { - int cnt = (ushort.MaxValue - reliableReceiveLast) + id; - for (ushort i = 1; i < cnt; ++i) - { - reliableDataPacketsMissing.Add((ushort)(i + reliableReceiveLast)); - } - } - - //Update the most recently received - reliableReceiveLast = id; - } - - //Else it could be a missing packet - else - { - //See if we're missing it, else this packet is a duplicate as so we return false - if (!reliableDataPacketsMissing.Remove(id)) - { - result = false; - } - } - } - - //Send an acknowledgement - await SendAck(id); - - return result; - } - - /// - /// Handles acknowledgement packets to us. - /// - /// The buffer containing the data. - private void AcknowledgementMessageReceive(ReadOnlySpan bytes) - { - this.pingsSinceAck = 0; - - ushort id = (ushort)((bytes[1] << 8) + bytes[2]); - AcknowledgeMessageId(id); - - if (bytes.Length == 4) - { - byte recentPackets = bytes[3]; - for (int i = 1; i <= 8; ++i) - { - if ((recentPackets & 1) != 0) - { - AcknowledgeMessageId((ushort)(id - i)); - } - - recentPackets >>= 1; - } - } - - Statistics.LogReliableReceive(0, bytes.Length); - } - - private void AcknowledgeMessageId(ushort id) - { - // Dispose of timer and remove from dictionary - if (reliableDataPacketsSent.TryRemove(id, out Packet packet)) - { - float rt = packet.Stopwatch.ElapsedMilliseconds; - - packet.AckCallback?.Invoke(); - packet.Recycle(); - - lock (PingLock) - { - this.AveragePingMs = Math.Max(50, this.AveragePingMs * .7f + rt * .3f); - } - } - else if (this.activePingPackets.TryRemove(id, out PingPacket pingPkt)) - { - float rt = pingPkt.Stopwatch.ElapsedMilliseconds; - - pingPkt.Recycle(); - - lock (PingLock) - { - this.AveragePingMs = Math.Max(50, this.AveragePingMs * .7f + rt * .3f); - } - } - } - - /// - /// Sends an acknowledgement for a packet given its identification bytes. - /// - /// The first identification byte. - /// The second identification byte. - private async ValueTask SendAck(ushort id) - { - byte recentPackets = 0; - lock (this.reliableDataPacketsMissing) - { - for (int i = 1; i <= 8; ++i) - { - if (!this.reliableDataPacketsMissing.Contains((ushort)(id - i))) - { - recentPackets |= (byte)(1 << (i - 1)); - } - } - } - - byte[] bytes = new byte[] - { - (byte)UdpSendOption.Acknowledgement, - (byte)(id >> 8), - (byte)(id >> 0), - recentPackets - }; - - try - { - await WriteBytesToConnection(bytes, bytes.Length); - } - catch (InvalidOperationException) { } - } - - private void DisposeReliablePackets() - { - foreach (var kvp in reliableDataPacketsSent) - { - if (this.reliableDataPacketsSent.TryRemove(kvp.Key, out var pkt)) - { - pkt.Recycle(); - } - } - } - } -} diff --git a/src/Impostor.Hazel/Udp/UdpConnection.cs b/src/Impostor.Hazel/Udp/UdpConnection.cs deleted file mode 100644 index 5288d3ce2..000000000 --- a/src/Impostor.Hazel/Udp/UdpConnection.cs +++ /dev/null @@ -1,312 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Channels; -using System.Threading.Tasks; -using Impostor.Api.Net.Messages; -using Microsoft.Extensions.ObjectPool; -using Serilog; - -namespace Impostor.Hazel.Udp -{ - /// - /// Represents a connection that uses the UDP protocol. - /// - /// - public abstract partial class UdpConnection : NetworkConnection - { - protected static readonly byte[] EmptyDisconnectBytes = { (byte)UdpSendOption.Disconnect }; - - private static readonly ILogger Logger = Log.ForContext(); - private readonly ConnectionListener _listener; - private readonly ObjectPool _readerPool; - private readonly CancellationTokenSource _stoppingCts; - - private bool _isDisposing; - private bool _isFirst = true; - private Task _executingTask; - - protected UdpConnection(ConnectionListener listener, ObjectPool readerPool) - { - _listener = listener; - _readerPool = readerPool; - _stoppingCts = new CancellationTokenSource(); - - Pipeline = Channel.CreateUnbounded(new UnboundedChannelOptions - { - SingleReader = true, - SingleWriter = true - }); - } - - internal Channel Pipeline { get; } - - public Task StartAsync() - { - // Store the task we're executing - _executingTask = Task.Factory.StartNew(ReadAsync, TaskCreationOptions.LongRunning); - - // If the task is completed then return it, this will bubble cancellation and failure to the caller - if (_executingTask.IsCompleted) - { - return _executingTask; - } - - // Otherwise it's running - return Task.CompletedTask; - } - - public void Stop() - { - // Stop called without start - if (_executingTask == null) - { - return; - } - - // Signal cancellation to methods. - _stoppingCts.Cancel(); - - try - { - // Cancel reader. - Pipeline.Writer.Complete(); - } - catch (ChannelClosedException) - { - // Already done. - } - - // Remove references. - if (!_isDisposing) - { - Dispose(true); - } - } - - private async Task ReadAsync() - { - var reader = new MessageReader(_readerPool); - - while (!_stoppingCts.IsCancellationRequested) - { - var result = await Pipeline.Reader.ReadAsync(_stoppingCts.Token); - - try - { - reader.Update(result); - - await HandleReceive(reader); - } - catch (Exception e) - { - Logger.Error(e, "Exception during ReadAsync"); - Dispose(true); - break; - } - } - } - - /// - /// Writes the given bytes to the connection. - /// - /// The bytes to write. - /// - protected abstract ValueTask WriteBytesToConnection(byte[] bytes, int length); - - /// - public override async ValueTask SendAsync(IMessageWriter msg) - { - if (this._state != ConnectionState.Connected) - throw new InvalidOperationException("Could not send data as this Connection is not connected. Did you disconnect?"); - - byte[] buffer = new byte[msg.Length]; - Buffer.BlockCopy(msg.Buffer, 0, buffer, 0, msg.Length); - - switch (msg.SendOption) - { - case MessageType.Reliable: - ResetKeepAliveTimer(); - - AttachReliableID(buffer, 1, buffer.Length); - await WriteBytesToConnection(buffer, buffer.Length); - Statistics.LogReliableSend(buffer.Length - 3, buffer.Length); - break; - - default: - await WriteBytesToConnection(buffer, buffer.Length); - Statistics.LogUnreliableSend(buffer.Length - 1, buffer.Length); - break; - } - } - - /// - /// - /// - /// - /// Udp connections can currently send messages using and - /// . Fragmented messages are not currently supported and will default to - /// until implemented. - /// - /// - public override async ValueTask SendBytes(byte[] bytes, MessageType sendOption = MessageType.Unreliable) - { - //Add header information and send - await HandleSend(bytes, (byte)sendOption); - } - - /// - /// Handles the reliable/fragmented sending from this connection. - /// - /// The data being sent. - /// The specified as its byte value. - /// The callback to invoke when this packet is acknowledged. - /// The bytes that should actually be sent. - protected async ValueTask HandleSend(byte[] data, byte sendOption, Action ackCallback = null) - { - switch (sendOption) - { - case (byte)UdpSendOption.Ping: - case (byte)MessageType.Reliable: - case (byte)UdpSendOption.Hello: - await ReliableSend(sendOption, data, ackCallback); - break; - - //Treat all else as unreliable - default: - await UnreliableSend(sendOption, data); - break; - } - } - - /// - /// Handles the receiving of data. - /// - /// The buffer containing the bytes received. - protected async ValueTask HandleReceive(MessageReader message) - { - // Check if the first message received is the hello packet. - if (_isFirst) - { - _isFirst = false; - - // Slice 4 bytes to get handshake data. - if (_listener != null) - { - using (var handshake = message.Copy(4)) - { - await _listener.InvokeNewConnection(handshake, this); - } - } - } - - switch (message.Buffer[0]) - { - //Handle reliable receives - case (byte)MessageType.Reliable: - await ReliableMessageReceive(message); - break; - - //Handle acknowledgments - case (byte)UdpSendOption.Acknowledgement: - AcknowledgementMessageReceive(message.Buffer); - break; - - //We need to acknowledge hello and ping messages but dont want to invoke any events! - case (byte)UdpSendOption.Ping: - await ProcessReliableReceive(message.Buffer, 1); - Statistics.LogHelloReceive(message.Length); - break; - case (byte)UdpSendOption.Hello: - await ProcessReliableReceive(message.Buffer, 1); - Statistics.LogHelloReceive(message.Length); - break; - - case (byte)UdpSendOption.Disconnect: - using (var reader = message.Copy(1)) - { - await DisconnectRemote("The remote sent a disconnect request", reader); - } - break; - - //Treat everything else as unreliable - default: - using (var reader = message.Copy(1)) - { - await InvokeDataReceived(reader, MessageType.Unreliable); - } - Statistics.LogUnreliableReceive(message.Length - 1, message.Length); - break; - } - } - - /// - /// Sends bytes using the unreliable UDP protocol. - /// - /// The SendOption to attach. - /// The data. - ValueTask UnreliableSend(byte sendOption, byte[] data) - { - return UnreliableSend(sendOption, data, 0, data.Length); - } - - /// - /// Sends bytes using the unreliable UDP protocol. - /// - /// The data. - /// The SendOption to attach. - /// - /// - async ValueTask UnreliableSend(byte sendOption, byte[] data, int offset, int length) - { - byte[] bytes = new byte[length + 1]; - - //Add message type - bytes[0] = sendOption; - - //Copy data into new array - Buffer.BlockCopy(data, offset, bytes, bytes.Length - length, length); - - //Write to connection - await WriteBytesToConnection(bytes, bytes.Length); - - Statistics.LogUnreliableSend(length, bytes.Length); - } - - /// - /// Sends a hello packet to the remote endpoint. - /// - /// - /// The callback to invoke when the hello packet is acknowledged. - protected ValueTask SendHello(byte[] bytes, Action acknowledgeCallback) - { - //First byte of handshake is version indicator so add data after - byte[] actualBytes; - if (bytes == null) - { - actualBytes = new byte[1]; - } - else - { - actualBytes = new byte[bytes.Length + 1]; - Buffer.BlockCopy(bytes, 0, actualBytes, 1, bytes.Length); - } - - return HandleSend(actualBytes, (byte)UdpSendOption.Hello, acknowledgeCallback); - } - - /// - protected override void Dispose(bool disposing) - { - if (disposing) - { - _isDisposing = true; - - Stop(); - DisposeKeepAliveTimer(); - DisposeReliablePackets(); - } - - base.Dispose(disposing); - } - } -} diff --git a/src/Impostor.Hazel/Udp/UdpConnectionListener.cs b/src/Impostor.Hazel/Udp/UdpConnectionListener.cs deleted file mode 100644 index 573a00cbf..000000000 --- a/src/Impostor.Hazel/Udp/UdpConnectionListener.cs +++ /dev/null @@ -1,281 +0,0 @@ -using System; -using System.Buffers; -using System.Collections.Concurrent; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Channels; -using System.Threading.Tasks; -using Microsoft.Extensions.ObjectPool; -using Serilog; - -namespace Impostor.Hazel.Udp -{ - /// - /// Listens for new UDP connections and creates UdpConnections for them. - /// - /// - public class UdpConnectionListener : NetworkConnectionListener - { - private static readonly ILogger Logger = Log.ForContext(); - - /// - /// A callback for early connection rejection. - /// * Return false to reject connection. - /// * A null response is ok, we just won't send anything. - /// - public AcceptConnectionCheck AcceptConnection; - public delegate bool AcceptConnectionCheck(IPEndPoint endPoint, byte[] input, out byte[] response); - - private readonly UdpClient _socket; - private readonly ObjectPool _readerPool; - private readonly MemoryPool _pool; - private readonly Timer _reliablePacketTimer; - private readonly ConcurrentDictionary _allConnections; - private readonly CancellationTokenSource _stoppingCts; - private readonly UdpConnectionRateLimit _connectionRateLimit; - private Task _executingTask; - - /// - /// Creates a new UdpConnectionListener for the given , port and . - /// - /// The endpoint to listen on. - /// - public UdpConnectionListener(IPEndPoint endPoint, ObjectPool readerPool, IPMode ipMode = IPMode.IPv4) - { - EndPoint = endPoint; - IPMode = ipMode; - - _readerPool = readerPool; - _pool = MemoryPool.Shared; - _socket = new UdpClient(endPoint); - - try - { - _socket.DontFragment = false; - } - catch (SocketException) - { - } - - _reliablePacketTimer = new Timer(ManageReliablePackets, null, 100, Timeout.Infinite); - - _allConnections = new ConcurrentDictionary(); - - _stoppingCts = new CancellationTokenSource(); - _stoppingCts.Token.Register(() => - { - _socket.Dispose(); - }); - - _connectionRateLimit = new UdpConnectionRateLimit(); - } - - public int ConnectionCount => this._allConnections.Count; - - private async void ManageReliablePackets(object state) - { - foreach (var kvp in _allConnections) - { - var sock = kvp.Value; - await sock.ManageReliablePackets(); - } - - try - { - this._reliablePacketTimer.Change(100, Timeout.Infinite); - } - catch { } - } - - /// - public override Task StartAsync() - { - // Store the task we're executing - _executingTask = Task.Factory.StartNew(ListenAsync, TaskCreationOptions.LongRunning); - - // If the task is completed then return it, this will bubble cancellation and failure to the caller - if (_executingTask.IsCompleted) - { - return _executingTask; - } - - // Otherwise it's running - return Task.CompletedTask; - } - - private async Task StopAsync() - { - // Stop called without start - if (_executingTask == null) - { - return; - } - - try - { - // Signal cancellation to the executing method - _stoppingCts.Cancel(); - } - finally - { - // Wait until the task completes or the timeout triggers - await Task.WhenAny(_executingTask, Task.Delay(TimeSpan.FromSeconds(5))); - } - } - - /// - /// Instructs the listener to begin listening. - /// - private async Task ListenAsync() - { - try - { - while (!_stoppingCts.IsCancellationRequested) - { - UdpReceiveResult data; - - try - { - data = await _socket.ReceiveAsync(); - - if (data.Buffer.Length == 0) - { - Logger.Fatal("Hazel read 0 bytes from UDP server socket."); - continue; - } - } - catch (SocketException) - { - // Client no longer reachable, pretend it didn't happen - continue; - } - catch (ObjectDisposedException) - { - // Socket was disposed, don't care. - return; - } - - // Get client from active clients - if (!_allConnections.TryGetValue(data.RemoteEndPoint, out var client)) - { - // Check for malformed connection attempts - if (data.Buffer[0] != (byte)UdpSendOption.Hello) - { - continue; - } - - // Check rateLimit. - if (!_connectionRateLimit.IsAllowed(data.RemoteEndPoint.Address)) - { - Logger.Warning("Ratelimited connection attempt from {0}.", data.RemoteEndPoint); - continue; - } - - // Create new client - client = new UdpServerConnection(this, data.RemoteEndPoint, IPMode, _readerPool); - - // Store the client - if (!_allConnections.TryAdd(data.RemoteEndPoint, client)) - { - throw new HazelException("Failed to add a connection. This should never happen."); - } - - // Activate the reader loop of the client - await client.StartAsync(); - } - - // Write to client. - await client.Pipeline.Writer.WriteAsync(data.Buffer); - } - } - catch (Exception e) - { - Logger.Error(e, "Listen loop error"); - } - } - -#if DEBUG - public int TestDropRate = -1; - private int dropCounter = 0; -#endif - - /// - /// Sends data from the listener socket. - /// - /// The bytes to send. - /// The endpoint to send to. - internal async ValueTask SendData(byte[] bytes, int length, IPEndPoint endPoint) - { - if (length > bytes.Length) return; - -#if DEBUG - if (TestDropRate > 0) - { - if (Interlocked.Increment(ref dropCounter) % TestDropRate == 0) - { - return; - } - } -#endif - - try - { - await _socket.SendAsync(bytes, length, endPoint); - } - catch (SocketException e) - { - Logger.Error(e, "Could not send data as a SocketException occurred"); - } - catch (ObjectDisposedException) - { - //Keep alive timer probably ran, ignore - return; - } - } - - /// - /// Sends data from the listener socket. - /// - /// The bytes to send. - /// - /// The endpoint to send to. - internal void SendDataSync(byte[] bytes, int length, IPEndPoint endPoint) - { - try - { - _socket.Send(bytes, length, endPoint); - } - catch (SocketException e) - { - Logger.Error(e, "Could not send data sync as a SocketException occurred"); - } - } - - /// - /// Removes a virtual connection from the list. - /// - /// The endpoint of the virtual connection. - internal void RemoveConnectionTo(EndPoint endPoint) - { - this._allConnections.TryRemove(endPoint, out var conn); - } - - /// - public override async ValueTask DisposeAsync() - { - foreach (var kvp in _allConnections) - { - kvp.Value.Dispose(); - } - - await StopAsync(); - - await _reliablePacketTimer.DisposeAsync(); - - _connectionRateLimit.Dispose(); - - await base.DisposeAsync(); - } - } -} diff --git a/src/Impostor.Hazel/Udp/UdpConnectionRateLimit.cs b/src/Impostor.Hazel/Udp/UdpConnectionRateLimit.cs deleted file mode 100644 index 64881d3da..000000000 --- a/src/Impostor.Hazel/Udp/UdpConnectionRateLimit.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Net; -using System.Threading; -using Serilog; - -namespace Impostor.Hazel.Udp -{ - public class UdpConnectionRateLimit : IDisposable - { - private static readonly ILogger Logger = Log.ForContext(); - - // Allow burst to 5 connections. - // Decrease by 1 every second. - private const int MaxConnections = 5; - private const int FalloffMs = 1000; - - private readonly ConcurrentDictionary _connectionCount; - private readonly Timer _timer; - private bool _isDisposed; - - public UdpConnectionRateLimit() - { - _connectionCount = new ConcurrentDictionary(); - _timer = new Timer(UpdateRateLimit, null, FalloffMs, Timeout.Infinite); - } - - private void UpdateRateLimit(object state) - { - try - { - foreach (var pair in _connectionCount) - { - var count = pair.Value - 1; - if (count > 0) - { - _connectionCount.TryUpdate(pair.Key, count, pair.Value); - } - else - { - _connectionCount.TryRemove(pair); - } - } - } - catch (Exception e) - { - Logger.Error(e, "Exception caught in UpdateRateLimit."); - } - finally - { - if (!_isDisposed) - { - _timer.Change(FalloffMs, Timeout.Infinite); - } - } - } - - public bool IsAllowed(IPAddress key) - { - if (_connectionCount.TryGetValue(key, out var value) && value >= MaxConnections) - { - return false; - } - - _connectionCount.AddOrUpdate(key, _ => 1, (_, i) => i + 1); - return true; - } - - public void Dispose() - { - _isDisposed = true; - _timer.Dispose(); - } - } -} \ No newline at end of file diff --git a/src/Impostor.Hazel/Udp/UdpServerConnection.cs b/src/Impostor.Hazel/Udp/UdpServerConnection.cs deleted file mode 100644 index 8d3426e38..000000000 --- a/src/Impostor.Hazel/Udp/UdpServerConnection.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Net; -using System.Threading.Tasks; -using Impostor.Api.Net.Messages; -using Microsoft.Extensions.ObjectPool; - -namespace Impostor.Hazel.Udp -{ - /// - /// Represents a servers's connection to a client that uses the UDP protocol. - /// - /// - internal sealed class UdpServerConnection : UdpConnection - { - /// - /// The connection listener that we use the socket of. - /// - /// - /// Udp server connections utilize the same socket in the listener for sends/receives, this is the listener that - /// created this connection and is hence the listener this conenction sends and receives via. - /// - public UdpConnectionListener Listener { get; private set; } - - /// - /// Creates a UdpConnection for the virtual connection to the endpoint. - /// - /// The listener that created this connection. - /// The endpoint that we are connected to. - /// The IPMode we are connected using. - internal UdpServerConnection(UdpConnectionListener listener, IPEndPoint endPoint, IPMode IPMode, ObjectPool readerPool) : base(listener, readerPool) - { - this.Listener = listener; - this.RemoteEndPoint = endPoint; - this.EndPoint = endPoint; - this.IPMode = IPMode; - - State = ConnectionState.Connected; - this.InitializeKeepAliveTimer(); - } - - /// - protected override async ValueTask WriteBytesToConnection(byte[] bytes, int length) - { - await Listener.SendData(bytes, length, RemoteEndPoint); - } - - /// - /// - /// This will always throw a HazelException. - /// - public override ValueTask ConnectAsync(byte[] bytes = null) - { - throw new InvalidOperationException("Cannot manually connect a UdpServerConnection, did you mean to use UdpClientConnection?"); - } - - /// - /// Sends a disconnect message to the end point. - /// - protected override async ValueTask SendDisconnect(MessageWriter data = null) - { - lock (this) - { - if (this._state != ConnectionState.Connected) return false; - this._state = ConnectionState.NotConnected; - } - - var bytes = EmptyDisconnectBytes; - if (data != null && data.Length > 0) - { - if (data.SendOption != MessageType.Unreliable) throw new ArgumentException("Disconnect messages can only be unreliable."); - - bytes = data.ToByteArray(true); - bytes[0] = (byte)UdpSendOption.Disconnect; - } - - try - { - await Listener.SendData(bytes, bytes.Length, RemoteEndPoint); - } - catch { } - - return true; - } - - protected override void Dispose(bool disposing) - { - Listener.RemoveConnectionTo(RemoteEndPoint); - - if (disposing) - { - _ = SendDisconnect(); - } - - base.Dispose(disposing); - } - } -} diff --git a/src/Impostor.Server/Impostor.Server.csproj b/src/Impostor.Server/Impostor.Server.csproj index ba444fc81..49bb222cb 100644 --- a/src/Impostor.Server/Impostor.Server.csproj +++ b/src/Impostor.Server/Impostor.Server.csproj @@ -21,7 +21,7 @@ - + diff --git a/src/Impostor.Tools.Proxy/Impostor.Tools.Proxy.csproj b/src/Impostor.Tools.Proxy/Impostor.Tools.Proxy.csproj index 571d7b949..11360170f 100644 --- a/src/Impostor.Tools.Proxy/Impostor.Tools.Proxy.csproj +++ b/src/Impostor.Tools.Proxy/Impostor.Tools.Proxy.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/Impostor.sln b/src/Impostor.sln index b9706de66..976ce4836 100644 --- a/src/Impostor.sln +++ b/src/Impostor.sln @@ -25,7 +25,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugins", "plugins", "{36AA EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Impostor.Plugins.Debugger", "Impostor.Plugins.Debugger\Impostor.Plugins.Debugger.csproj", "{ECBCAA3B-B974-41CF-AFFC-6F5AA4C42FA7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Impostor.Hazel", "Impostor.Hazel\Impostor.Hazel.csproj", "{671B753B-31AE-4C36-AD71-09CF00FA17CA}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Impostor.Hazel", "Impostor.Hazel\Hazel\Hazel.csproj", "{671B753B-31AE-4C36-AD71-09CF00FA17CA}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "client", "client", "{9F1919B0-915B-4749-9944-697DF7E7F67F}" EndProject From 11e87e51db522e8d01ac889053eff98680957a75 Mon Sep 17 00:00:00 2001 From: js6pak Date: Fri, 2 Apr 2021 23:44:47 +0200 Subject: [PATCH 36/72] Update airship constants --- src/Impostor.Api/Innersloth/Platforms.cs | 15 +++++++++++++++ .../Innersloth/{ChatType.cs => QuickChatModes.cs} | 2 +- .../Net/Messages/C2S/Message00HostGameC2S.cs | 6 +++--- .../Net/Messages/C2S/Message16GetGameListC2S.cs | 4 ++-- src/Impostor.Server/Net/Inner/GameDataTag.cs | 3 ++- src/Impostor.Server/Net/Manager/ClientManager.cs | 2 +- src/Impostor.Server/Net/State/Game.Data.cs | 4 ++-- 7 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 src/Impostor.Api/Innersloth/Platforms.cs rename src/Impostor.Api/Innersloth/{ChatType.cs => QuickChatModes.cs} (78%) diff --git a/src/Impostor.Api/Innersloth/Platforms.cs b/src/Impostor.Api/Innersloth/Platforms.cs new file mode 100644 index 000000000..ab2c0e748 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Platforms.cs @@ -0,0 +1,15 @@ +namespace Impostor.Api.Innersloth +{ + public enum Platforms + { + Unknown, + StandaloneEpicPC, + StandaloneSteamPC, + StandaloneMac, + StandaloneWin10, + StandaloneItch, + IPhone, + Android, + Switch, + } +} diff --git a/src/Impostor.Api/Innersloth/ChatType.cs b/src/Impostor.Api/Innersloth/QuickChatModes.cs similarity index 78% rename from src/Impostor.Api/Innersloth/ChatType.cs rename to src/Impostor.Api/Innersloth/QuickChatModes.cs index 087c2b7ca..192026474 100644 --- a/src/Impostor.Api/Innersloth/ChatType.cs +++ b/src/Impostor.Api/Innersloth/QuickChatModes.cs @@ -1,6 +1,6 @@ namespace Impostor.Api.Innersloth { - public enum ChatType + public enum QuickChatModes { FreeChatOrQuickChat = 1, QuickChatOnly = 2, diff --git a/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs index e81e861f6..2a61a1832 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs @@ -15,12 +15,12 @@ public static void Serialize(IMessageWriter writer, GameOptionsData gameOptionsD /// Deserialize a packet. /// /// with 0. - /// The chat type selected in the client of the player. + /// The chat type selected in the client of the player. /// Deserialized . - public static GameOptionsData Deserialize(IMessageReader reader, out ChatType chatType) + public static GameOptionsData Deserialize(IMessageReader reader, out QuickChatModes chatMode) { var gameOptionsData = GameOptionsData.DeserializeCreate(reader); - chatType = (ChatType)reader.ReadByte(); + chatMode = (QuickChatModes)reader.ReadByte(); return gameOptionsData; } diff --git a/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs index 72be48d7a..01237678d 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs @@ -10,11 +10,11 @@ public static void Serialize(IMessageWriter writer) throw new NotImplementedException(); } - public static void Deserialize(IMessageReader reader, out GameOptionsData options, out ChatType chatType) + public static void Deserialize(IMessageReader reader, out GameOptionsData options, out QuickChatModes chatMode) { reader.ReadPackedInt32(); // Hardcoded 0. options = GameOptionsData.DeserializeCreate(reader); - chatType = (ChatType)reader.ReadByte(); + chatMode = (QuickChatModes)reader.ReadByte(); } } } diff --git a/src/Impostor.Server/Net/Inner/GameDataTag.cs b/src/Impostor.Server/Net/Inner/GameDataTag.cs index 818f11ff7..300ce81be 100644 --- a/src/Impostor.Server/Net/Inner/GameDataTag.cs +++ b/src/Impostor.Server/Net/Inner/GameDataTag.cs @@ -9,6 +9,7 @@ public static class GameDataTag public const byte SceneChangeFlag = 6; public const byte ReadyFlag = 7; public const byte ChangeSettingsFlag = 8; - public const byte ClientInfoFlag = 205; + public const byte ConsoleDeclareClientPlatformFlag = 205; + public const byte PS4RoomRequest = 206; } } diff --git a/src/Impostor.Server/Net/Manager/ClientManager.cs b/src/Impostor.Server/Net/Manager/ClientManager.cs index 6ee4515f4..e7ec17189 100644 --- a/src/Impostor.Server/Net/Manager/ClientManager.cs +++ b/src/Impostor.Server/Net/Manager/ClientManager.cs @@ -20,7 +20,7 @@ internal partial class ClientManager { private static readonly HashSet SupportedVersions = new HashSet { - GameVersion.GetVersion(2021, 3, 5), // 2021.3.5 + GameVersion.GetVersion(2021, 3, 25), // 2021.3.31s }; private static readonly string ServerBrand = $"Impostor {DotnetUtils.GetVersion()}"; diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index 250c3078d..968076814 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -254,14 +254,14 @@ public async ValueTask HandleGameDataAsync(IMessageReader parent, ClientPl break; } - case GameDataTag.ClientInfoFlag: + case GameDataTag.ConsoleDeclareClientPlatformFlag: { var clientId = reader.ReadPackedInt32(); var platform = (RuntimePlatform)reader.ReadPackedInt32(); if (clientId != sender.Client.Id) { - if (await sender.Client.ReportCheatAsync(new CheatContext(nameof(GameDataTag.ClientInfoFlag)), "Client sent info with wrong client id")) + if (await sender.Client.ReportCheatAsync(new CheatContext(nameof(GameDataTag.ConsoleDeclareClientPlatformFlag)), "Client sent info with wrong client id")) { return false; } From 989b06d04cacef84bdfacafc00161fd36deae47c Mon Sep 17 00:00:00 2001 From: js6pak Date: Fri, 2 Apr 2021 23:45:01 +0200 Subject: [PATCH 37/72] Use BitConverter.Int32BitsToSingle in SpanReaderExtensions --- src/Impostor.Api/Extensions/SpanReaderExtensions.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Impostor.Api/Extensions/SpanReaderExtensions.cs b/src/Impostor.Api/Extensions/SpanReaderExtensions.cs index 78e5a4567..05b891ab4 100644 --- a/src/Impostor.Api/Extensions/SpanReaderExtensions.cs +++ b/src/Impostor.Api/Extensions/SpanReaderExtensions.cs @@ -35,9 +35,7 @@ public static float ReadSingle(this ref ReadOnlySpan input) { var original = Advance(ref input); - // BitConverter.Int32BitsToSingle - // Doesn't exist in net 2.0 for some reason - return Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(original)); + return BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(original)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -46,12 +44,6 @@ public static bool ReadBoolean(this ref ReadOnlySpan input) return input.ReadByte() != 0; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe float Int32BitsToSingle(int value) - { - return *((float*)&value); - } - /// /// Advances the position of by the size of . /// From 7c34836d50a7ef1fc94583b4596a5b437ccb291a Mon Sep 17 00:00:00 2001 From: js6pak Date: Thu, 25 Mar 2021 22:17:31 +0100 Subject: [PATCH 38/72] Remove reactor stuff --- src/Impostor.Api/Net/IClient.cs | 6 ----- src/Impostor.Api/Net/Inner/RpcCalls.cs | 1 - .../Net/Messages/C2S/HandshakeC2S.cs | 12 ++++++++++ src/Impostor.Api/Reactor/Mod.cs | 21 ---------------- src/Impostor.Api/Reactor/ModList.cs | 24 ------------------- .../Reactor/ModdedHandshakeC2S.cs | 23 ------------------ .../Reactor/ModdedHandshakeS2C.cs | 14 ----------- src/Impostor.Api/Reactor/PluginSide.cs | 23 ------------------ src/Impostor.Server/Net/Client.cs | 6 ++--- src/Impostor.Server/Net/ClientBase.cs | 21 +--------------- .../Net/Factories/ClientFactory.cs | 6 ++--- .../Net/Factories/IClientFactory.cs | 6 ++--- .../Net/Inner/InnerNetObject.cs | 14 ----------- .../Objects/Components/InnerPlayerPhysics.cs | 3 --- .../Net/Inner/Objects/InnerGameData.cs | 3 --- .../Net/Inner/Objects/InnerMeetingHud.cs | 3 --- .../Net/Inner/Objects/InnerPlayerControl.cs | 3 --- .../Net/Inner/Objects/InnerShipStatus.cs | 3 --- .../Net/Manager/ClientManager.cs | 13 +++------- src/Impostor.Server/Net/Matchmaker.cs | 7 +++--- .../Net/Redirector/ClientRedirector.cs | 7 ++---- .../Net/State/Game.Incoming.cs | 21 ---------------- src/Impostor.Server/Program.cs | 2 +- .../Recorder/ClientRecorder.cs | 8 +++---- .../Recorder/PacketRecorder.cs | 2 +- src/Impostor.Server/Utils/DotnetUtils.cs | 19 ++++++++------- src/Impostor.Tools.ServerReplay/Program.cs | 2 +- 27 files changed, 45 insertions(+), 228 deletions(-) create mode 100644 src/Impostor.Api/Net/Messages/C2S/HandshakeC2S.cs delete mode 100644 src/Impostor.Api/Reactor/Mod.cs delete mode 100644 src/Impostor.Api/Reactor/ModList.cs delete mode 100644 src/Impostor.Api/Reactor/ModdedHandshakeC2S.cs delete mode 100644 src/Impostor.Api/Reactor/ModdedHandshakeS2C.cs delete mode 100644 src/Impostor.Api/Reactor/PluginSide.cs diff --git a/src/Impostor.Api/Net/IClient.cs b/src/Impostor.Api/Net/IClient.cs index d9631d7d6..66ab9c5ef 100644 --- a/src/Impostor.Api/Net/IClient.cs +++ b/src/Impostor.Api/Net/IClient.cs @@ -2,7 +2,6 @@ using System.Threading.Tasks; using Impostor.Api.Innersloth; using Impostor.Api.Net.Messages; -using Impostor.Api.Reactor; namespace Impostor.Api.Net { @@ -28,11 +27,6 @@ public interface IClient /// string Name { get; } - /// - /// Gets mods sent by client in modded handshake. - /// - ISet Mods { get; } - /// /// Gets the connection of the client. /// diff --git a/src/Impostor.Api/Net/Inner/RpcCalls.cs b/src/Impostor.Api/Net/Inner/RpcCalls.cs index e75f80ec2..506017d1a 100644 --- a/src/Impostor.Api/Net/Inner/RpcCalls.cs +++ b/src/Impostor.Api/Net/Inner/RpcCalls.cs @@ -33,6 +33,5 @@ public enum RpcCalls : byte RepairSystem = 28, SetTasks = 29, UpdateGameData = 30, - CustomRpc = byte.MaxValue, } } diff --git a/src/Impostor.Api/Net/Messages/C2S/HandshakeC2S.cs b/src/Impostor.Api/Net/Messages/C2S/HandshakeC2S.cs new file mode 100644 index 000000000..649e5eec8 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/C2S/HandshakeC2S.cs @@ -0,0 +1,12 @@ +namespace Impostor.Api.Net.Messages.C2S +{ + public static class HandshakeC2S + { + public static void Deserialize(IMessageReader reader, out int clientVersion, out string name, out uint lastNonceReceived) + { + clientVersion = reader.ReadInt32(); + name = reader.ReadString(); + lastNonceReceived = reader.ReadUInt32(); + } + } +} diff --git a/src/Impostor.Api/Reactor/Mod.cs b/src/Impostor.Api/Reactor/Mod.cs deleted file mode 100644 index 2654c5fd3..000000000 --- a/src/Impostor.Api/Reactor/Mod.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Impostor.Api.Reactor -{ - public readonly struct Mod - { - public readonly string Id; - public readonly string Version; - public readonly PluginSide Side; - - public Mod(string id, string version, PluginSide side) - { - Id = id; - Version = version; - Side = side; - } - - public override string ToString() - { - return $"{Id} ({Version})"; - } - } -} diff --git a/src/Impostor.Api/Reactor/ModList.cs b/src/Impostor.Api/Reactor/ModList.cs deleted file mode 100644 index 047c8b49f..000000000 --- a/src/Impostor.Api/Reactor/ModList.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.Generic; -using Impostor.Api.Net.Messages; - -namespace Impostor.Api.Reactor -{ - public static class ModList - { - public static void Deserialize(IMessageReader reader, out ISet mods) - { - var length = reader.ReadPackedInt32(); - - mods = new HashSet(length); - - for (var i = 0; i < length; i++) - { - var id = reader.ReadString(); - var version = reader.ReadString(); - var pluginSide = (PluginSide)reader.ReadByte(); - - mods.Add(new Mod(id, version, pluginSide)); - } - } - } -} diff --git a/src/Impostor.Api/Reactor/ModdedHandshakeC2S.cs b/src/Impostor.Api/Reactor/ModdedHandshakeC2S.cs deleted file mode 100644 index a79671206..000000000 --- a/src/Impostor.Api/Reactor/ModdedHandshakeC2S.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; -using Impostor.Api.Net.Messages; - -namespace Impostor.Api.Reactor -{ - public static class ModdedHandshakeC2S - { - public static void Deserialize(IMessageReader reader, out int clientVersion, out string name, out ISet? mods) - { - clientVersion = reader.ReadInt32(); - name = reader.ReadString(); - - if (reader.Length > reader.Position) - { - ModList.Deserialize(reader, out mods); - } - else - { - mods = null; - } - } - } -} diff --git a/src/Impostor.Api/Reactor/ModdedHandshakeS2C.cs b/src/Impostor.Api/Reactor/ModdedHandshakeS2C.cs deleted file mode 100644 index 07f4f9c88..000000000 --- a/src/Impostor.Api/Reactor/ModdedHandshakeS2C.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Impostor.Api.Net.Messages; - -namespace Impostor.Api.Reactor -{ - public static class ModdedHandshakeS2C - { - public static void Serialize(IMessageWriter writer, string serverBrand) - { - writer.StartMessage(byte.MaxValue); - writer.Write(serverBrand); - writer.EndMessage(); - } - } -} diff --git a/src/Impostor.Api/Reactor/PluginSide.cs b/src/Impostor.Api/Reactor/PluginSide.cs deleted file mode 100644 index 4523dfc62..000000000 --- a/src/Impostor.Api/Reactor/PluginSide.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Impostor.Api.Reactor -{ - /// - /// Plugin side used in modded handshake. - /// - public enum PluginSide : byte - { - /// - /// Required by both sides, reject connection if missing on the other side - /// - Both, - - /// - /// Required only by client - /// - ClientOnly, - - /// - /// Required only by server - /// - ServerOnly, - } -} diff --git a/src/Impostor.Server/Net/Client.cs b/src/Impostor.Server/Net/Client.cs index 45718e583..6c5547ec0 100644 --- a/src/Impostor.Server/Net/Client.cs +++ b/src/Impostor.Server/Net/Client.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Threading.Tasks; using Impostor.Api; using Impostor.Api.Games; @@ -8,7 +7,6 @@ using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.C2S; using Impostor.Api.Net.Messages.S2C; -using Impostor.Api.Reactor; using Impostor.Hazel; using Impostor.Server.Config; using Impostor.Server.Net.Manager; @@ -24,8 +22,8 @@ internal class Client : ClientBase private readonly ClientManager _clientManager; private readonly GameManager _gameManager; - public Client(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, int gameVersion, IHazelConnection connection, ISet mods) - : base(name, gameVersion, connection, mods) + public Client(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, int gameVersion, IHazelConnection connection) + : base(name, gameVersion, connection) { _logger = logger; _antiCheatConfig = antiCheatOptions.Value; diff --git a/src/Impostor.Server/Net/ClientBase.cs b/src/Impostor.Server/Net/ClientBase.cs index 78bcb9ec5..9874a7171 100644 --- a/src/Impostor.Server/Net/ClientBase.cs +++ b/src/Impostor.Server/Net/ClientBase.cs @@ -1,14 +1,12 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Impostor.Api; using Impostor.Api.Innersloth; using Impostor.Api.Net; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.S2C; -using Impostor.Api.Reactor; using Impostor.Hazel; using Impostor.Server.Net.State; @@ -16,25 +14,12 @@ namespace Impostor.Server.Net { internal abstract class ClientBase : IClient { - protected ClientBase(string name, int gameVersion, IHazelConnection connection, ISet mods) + protected ClientBase(string name, int gameVersion, IHazelConnection connection) { Name = name; GameVersion = gameVersion; Connection = connection; - Mods = mods; Items = new ConcurrentDictionary(); - - ModIdMap = new Dictionary(); - - var i = -1; - - foreach (var mod in mods.OrderBy(x => x.Id)) - { - if (mod.Side == PluginSide.Both) - { - ModIdMap[i--] = mod.Id; - } - } } public int Id { get; set; } @@ -43,10 +28,6 @@ protected ClientBase(string name, int gameVersion, IHazelConnection connection, public int GameVersion { get; } - public ISet Mods { get; } - - public Dictionary ModIdMap { get; } - public IHazelConnection Connection { get; } public IDictionary Items { get; } diff --git a/src/Impostor.Server/Net/Factories/ClientFactory.cs b/src/Impostor.Server/Net/Factories/ClientFactory.cs index 985ab4e0e..e7d3e668f 100644 --- a/src/Impostor.Server/Net/Factories/ClientFactory.cs +++ b/src/Impostor.Server/Net/Factories/ClientFactory.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using Impostor.Api.Net; -using Impostor.Api.Reactor; using Microsoft.Extensions.DependencyInjection; namespace Impostor.Server.Net.Factories @@ -16,9 +14,9 @@ public ClientFactory(IServiceProvider serviceProvider) _serviceProvider = serviceProvider; } - public ClientBase Create(IHazelConnection connection, string name, int clientVersion, ISet mods) + public ClientBase Create(IHazelConnection connection, string name, int clientVersion) { - var client = ActivatorUtilities.CreateInstance(_serviceProvider, name, clientVersion, connection, mods); + var client = ActivatorUtilities.CreateInstance(_serviceProvider, name, clientVersion, connection); connection.Client = client; return client; } diff --git a/src/Impostor.Server/Net/Factories/IClientFactory.cs b/src/Impostor.Server/Net/Factories/IClientFactory.cs index a72a23bab..11a1ddc95 100644 --- a/src/Impostor.Server/Net/Factories/IClientFactory.cs +++ b/src/Impostor.Server/Net/Factories/IClientFactory.cs @@ -1,11 +1,9 @@ -using System.Collections.Generic; -using Impostor.Api.Net; -using Impostor.Api.Reactor; +using Impostor.Api.Net; namespace Impostor.Server.Net.Factories { internal interface IClientFactory { - ClientBase Create(IHazelConnection connection, string name, int clientVersion, ISet mods); + ClientBase Create(IHazelConnection connection, string name, int clientVersion); } } diff --git a/src/Impostor.Server/Net/Inner/InnerNetObject.cs b/src/Impostor.Server/Net/Inner/InnerNetObject.cs index 8cbea9a26..073e5811f 100644 --- a/src/Impostor.Server/Net/Inner/InnerNetObject.cs +++ b/src/Impostor.Server/Net/Inner/InnerNetObject.cs @@ -27,19 +27,5 @@ public bool IsOwnedBy(IClientPlayer player) public abstract ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState); 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(); - - var pluginId = lengthOrShortId < 0 - ? game.Host!.Client.ModIdMap[lengthOrShortId] - : reader.ReadString(lengthOrShortId); - - var id = reader.ReadPackedInt32(); - - return ValueTask.FromResult(true); - } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs index 4eb5f8a1a..14e8690c7 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs @@ -55,9 +55,6 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client Rpc19EnterVent.Deserialize(reader, out ventId); break; - case RpcCalls.CustomRpc: - return await HandleCustomRpc(reader, _game); - default: return await UnregisteredCall(call, sender); } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs index 011af37b0..d6a16fdad 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs @@ -121,9 +121,6 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client break; } - case RpcCalls.CustomRpc: - return await HandleCustomRpc(reader, _game); - default: return await UnregisteredCall(call, sender); } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs index a2d6f0e79..f41680b16 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs @@ -122,9 +122,6 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client break; } - case RpcCalls.CustomRpc: - return await HandleCustomRpc(reader, _game); - default: return await UnregisteredCall(call, sender); } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs index 8cd808dbb..7bbf8e78a 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs @@ -285,9 +285,6 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client return await HandleSetStartCounter(sender, sequenceId, startCounter); } - case RpcCalls.CustomRpc: - return await HandleCustomRpc(reader, _game); - default: return await UnregisteredCall(call, sender); } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs index 3725c8faa..d51c0b8d2 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs @@ -117,9 +117,6 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client break; } - case RpcCalls.CustomRpc: - return await HandleCustomRpc(reader, _game); - default: return await UnregisteredCall(call, sender); } diff --git a/src/Impostor.Server/Net/Manager/ClientManager.cs b/src/Impostor.Server/Net/Manager/ClientManager.cs index e7ec17189..d5355ddc7 100644 --- a/src/Impostor.Server/Net/Manager/ClientManager.cs +++ b/src/Impostor.Server/Net/Manager/ClientManager.cs @@ -3,15 +3,14 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Impostor.Api.Events.Managers; using Impostor.Api.Innersloth; using Impostor.Api.Net; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.S2C; -using Impostor.Api.Reactor; using Impostor.Hazel; using Impostor.Server.Config; using Impostor.Server.Net.Factories; -using Impostor.Server.Utils; using Microsoft.Extensions.Logging; namespace Impostor.Server.Net.Manager @@ -23,8 +22,6 @@ internal partial class ClientManager GameVersion.GetVersion(2021, 3, 25), // 2021.3.31s }; - private static readonly string ServerBrand = $"Impostor {DotnetUtils.GetVersion()}"; - private readonly ILogger _logger; private readonly ConcurrentDictionary _clients; private readonly IClientFactory _clientFactory; @@ -55,7 +52,7 @@ public int NextId() return clientId; } - public async ValueTask RegisterConnectionAsync(IHazelConnection connection, string name, int clientVersion, ISet? mods) + public async ValueTask RegisterConnectionAsync(IHazelConnection connection, string name, int clientVersion) { if (!SupportedVersions.Contains(clientVersion)) { @@ -81,16 +78,12 @@ public async ValueTask RegisterConnectionAsync(IHazelConnection connection, stri return; } - var client = _clientFactory.Create(connection, name, clientVersion, mods ?? new HashSet(0)); + var client = _clientFactory.Create(connection, name, clientVersion); var id = NextId(); client.Id = id; _logger.LogTrace("Client connected."); _clients.TryAdd(id, client); - - using var writer = MessageWriter.Get(MessageType.Reliable); - ModdedHandshakeS2C.Serialize(writer, ServerBrand); - await connection.SendAsync(writer); } public void Remove(IClient client) diff --git a/src/Impostor.Server/Net/Matchmaker.cs b/src/Impostor.Server/Net/Matchmaker.cs index a5518dc37..e7ce3ace0 100644 --- a/src/Impostor.Server/Net/Matchmaker.cs +++ b/src/Impostor.Server/Net/Matchmaker.cs @@ -2,7 +2,8 @@ using System.Net; using System.Net.Sockets; using System.Threading.Tasks; -using Impostor.Api.Reactor; +using Impostor.Api.Events.Managers; +using Impostor.Api.Net.Messages.C2S; using Impostor.Hazel; using Impostor.Hazel.Udp; using Impostor.Server.Net.Hazel; @@ -60,12 +61,12 @@ public async ValueTask StopAsync() private async ValueTask OnNewConnection(NewConnectionEventArgs e) { // Handshake. - ModdedHandshakeC2S.Deserialize(e.HandshakeData, out var clientVersion, out var name, out var mods); + HandshakeC2S.Deserialize(e.HandshakeData, out var clientVersion, out var name); var connection = new HazelConnection(e.Connection, _connectionLogger); // Register client - await _clientManager.RegisterConnectionAsync(connection, name, clientVersion, mods); + await _clientManager.RegisterConnectionAsync(connection, name, clientVersion); } } } diff --git a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs index 0cfa76d0f..22dc0a7d1 100644 --- a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs +++ b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs @@ -1,10 +1,8 @@ -using System.Collections.Generic; -using System.Threading.Tasks; +using System.Threading.Tasks; using Impostor.Api.Innersloth; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.C2S; using Impostor.Api.Net.Messages.S2C; -using Impostor.Api.Reactor; using Impostor.Hazel; using Impostor.Server.Config; using Impostor.Server.Net.Hazel; @@ -25,11 +23,10 @@ public ClientRedirector( string name, int gameVersion, HazelConnection connection, - ISet mods, ClientManager clientManager, INodeProvider nodeProvider, INodeLocator nodeLocator) - : base(name, gameVersion, connection, mods) + : base(name, gameVersion, connection) { _clientManager = clientManager; _nodeProvider = nodeProvider; diff --git a/src/Impostor.Server/Net/State/Game.Incoming.cs b/src/Impostor.Server/Net/State/Game.Incoming.cs index 8f9df6263..6e1620803 100644 --- a/src/Impostor.Server/Net/State/Game.Incoming.cs +++ b/src/Impostor.Server/Net/State/Game.Incoming.cs @@ -1,12 +1,10 @@ using System; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Impostor.Api.Games; using Impostor.Api.Innersloth; using Impostor.Api.Net; using Impostor.Api.Net.Messages; -using Impostor.Api.Reactor; using Impostor.Hazel; using Impostor.Server.Events; using Microsoft.Extensions.DependencyInjection; @@ -173,25 +171,6 @@ private async ValueTask AddClientSafeAsync(ClientBase client) return GameJoinResult.FromError(GameJoinError.GameDestroyed); } - if (Host != null) - { - foreach (var hostMod in Host.Client.Mods) - { - if (hostMod.Side == PluginSide.Both && client.Mods.All(clientMod => hostMod.Id != clientMod.Id)) - { - return GameJoinResult.CreateCustomError($"You are missing {hostMod.Id} - {hostMod.Version}"); - } - } - - foreach (var clientMod in client.Mods) - { - if (clientMod.Side == PluginSide.Both && Host.Client.Mods.All(hostMod => clientMod.Id != hostMod.Id)) - { - return GameJoinResult.CreateCustomError($"Host of this game is missing {clientMod.Id} - {clientMod.Version}"); - } - } - } - var isNew = false; if (player == null || player.Game != this) diff --git a/src/Impostor.Server/Program.cs b/src/Impostor.Server/Program.cs index ab582caaa..03514d902 100644 --- a/src/Impostor.Server/Program.cs +++ b/src/Impostor.Server/Program.cs @@ -59,7 +59,7 @@ private static int Main(string[] args) try { - Log.Information("Starting Impostor v{0}", DotnetUtils.GetVersion()); + Log.Information("Starting Impostor v{0}", DotnetUtils.Version); CreateHostBuilder(args).Build().Run(); return 0; } diff --git a/src/Impostor.Server/Recorder/ClientRecorder.cs b/src/Impostor.Server/Recorder/ClientRecorder.cs index fe9d94cc6..31af22a5d 100644 --- a/src/Impostor.Server/Recorder/ClientRecorder.cs +++ b/src/Impostor.Server/Recorder/ClientRecorder.cs @@ -1,7 +1,5 @@ -using System.Collections.Generic; -using System.Threading.Tasks; +using System.Threading.Tasks; using Impostor.Api.Net.Messages; -using Impostor.Api.Reactor; using Impostor.Server.Config; using Impostor.Server.Net; using Impostor.Server.Net.Hazel; @@ -18,8 +16,8 @@ internal class ClientRecorder : Client private bool _createdGame; private bool _recordAfter; - public ClientRecorder(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, int gameVersion, HazelConnection connection, ISet mods, PacketRecorder recorder) - : base(logger, antiCheatOptions, clientManager, gameManager, name, gameVersion, connection, mods) + public ClientRecorder(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, int gameVersion, HazelConnection connection, PacketRecorder recorder) + : base(logger, antiCheatOptions, clientManager, gameManager, name, gameVersion, connection) { _recorder = recorder; _isFirst = true; diff --git a/src/Impostor.Server/Recorder/PacketRecorder.cs b/src/Impostor.Server/Recorder/PacketRecorder.cs index 905e02628..12985f1a2 100644 --- a/src/Impostor.Server/Recorder/PacketRecorder.cs +++ b/src/Impostor.Server/Recorder/PacketRecorder.cs @@ -161,7 +161,7 @@ private async Task WriteFileHeaderAsync() { context.Writer.Write((uint)ServerReplayVersion.Initial); context.Writer.Write(_startTime.ToUnixTimeMilliseconds()); - context.Writer.Write(DotnetUtils.GetVersion()); + context.Writer.Write(DotnetUtils.Version); await WriteAsync(context.Stream!); } diff --git a/src/Impostor.Server/Utils/DotnetUtils.cs b/src/Impostor.Server/Utils/DotnetUtils.cs index 48a0ac0a8..25a4c7cc9 100644 --- a/src/Impostor.Server/Utils/DotnetUtils.cs +++ b/src/Impostor.Server/Utils/DotnetUtils.cs @@ -2,19 +2,22 @@ namespace Impostor.Server.Utils { - internal static class DotnetUtils + public static class DotnetUtils { - private const string DefaultUnknownBuild = "UNKNOWN"; + private static string? _version; - public static string GetVersion() + public static string Version { - var attribute = typeof(DotnetUtils).Assembly.GetCustomAttribute(); - if (attribute != null) + get { - return attribute.InformationalVersion; - } + if (_version == null) + { + var attribute = typeof(DotnetUtils).Assembly.GetCustomAttribute(); + _version = attribute != null ? attribute.InformationalVersion : "UNKNOWN"; + } - return DefaultUnknownBuild; + return _version; + } } } } diff --git a/src/Impostor.Tools.ServerReplay/Program.cs b/src/Impostor.Tools.ServerReplay/Program.cs index 65401efa0..16b756eaf 100644 --- a/src/Impostor.Tools.ServerReplay/Program.cs +++ b/src/Impostor.Tools.ServerReplay/Program.cs @@ -166,7 +166,7 @@ private static async Task ParsePacket(BinaryReader reader) // Create and register connection. var connection = new MockHazelConnection(address); - await _clientManager.RegisterConnectionAsync(connection, name, gameVersion, null); + await _clientManager.RegisterConnectionAsync(connection, name, gameVersion); // Store reference for ourselfs. Connections.Add(clientId, connection); From a39fae332551b3ebf1112d90d064dcbe2be2c626 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sat, 3 Apr 2021 00:07:06 +0200 Subject: [PATCH 39/72] Initial auth implementation --- .../Net/Messages/Auth/Message01Complete.cs | 15 ++++ .../Net/Messages/Auth/MessageHandshake.cs | 14 +++ .../Config/AuthServerConfig.cs | 27 ++++++ src/Impostor.Server/Net/AuthService.cs | 88 +++++++++++++++++++ src/Impostor.Server/Net/Matchmaker.cs | 2 +- src/Impostor.Server/Program.cs | 10 +++ 6 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 src/Impostor.Api/Net/Messages/Auth/Message01Complete.cs create mode 100644 src/Impostor.Api/Net/Messages/Auth/MessageHandshake.cs create mode 100644 src/Impostor.Server/Config/AuthServerConfig.cs create mode 100644 src/Impostor.Server/Net/AuthService.cs diff --git a/src/Impostor.Api/Net/Messages/Auth/Message01Complete.cs b/src/Impostor.Api/Net/Messages/Auth/Message01Complete.cs new file mode 100644 index 000000000..2572f8c4e --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Auth/Message01Complete.cs @@ -0,0 +1,15 @@ +namespace Impostor.Api.Net.Messages.Auth +{ + public static class Message01Complete + { + public static void Serialize(IMessageWriter writer, uint nonce) + { + writer.WritePacked(nonce); + } + + public static void Deserialize(IMessageReader reader, out uint nonce) + { + nonce = reader.ReadUInt32(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Auth/MessageHandshake.cs b/src/Impostor.Api/Net/Messages/Auth/MessageHandshake.cs new file mode 100644 index 000000000..146d0046a --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Auth/MessageHandshake.cs @@ -0,0 +1,14 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.Auth +{ + public static class MessageHandshake + { + public static void Deserialize(IMessageReader reader, out int clientVersion, out Platforms platform, out string clientId) + { + clientVersion = reader.ReadInt32(); + platform = (Platforms)reader.ReadByte(); + clientId = reader.ReadString(); + } + } +} diff --git a/src/Impostor.Server/Config/AuthServerConfig.cs b/src/Impostor.Server/Config/AuthServerConfig.cs new file mode 100644 index 000000000..72c8efe4a --- /dev/null +++ b/src/Impostor.Server/Config/AuthServerConfig.cs @@ -0,0 +1,27 @@ +using System.IO; +using Impostor.Server.Utils; + +namespace Impostor.Server.Config +{ + internal class AuthServerConfig + { + public const string Section = "AuthServer"; + + private string? _resolvedListenIp; + + public bool Enabled { get; set; } = false; + + public string ListenIp { get; set; } = "0.0.0.0"; + + public ushort ListenPort { get; set; } = 22025; + + public string Certificate { get; set; } = Path.Combine("dtls", "certificate.pem"); + + public string PrivateKey { get; set; } = Path.Combine("dtls", "key.pem"); + + public string ResolveListenIp() + { + return _resolvedListenIp ??= IpUtils.ResolveIp(ListenIp); + } + } +} diff --git a/src/Impostor.Server/Net/AuthService.cs b/src/Impostor.Server/Net/AuthService.cs new file mode 100644 index 000000000..c8a95b200 --- /dev/null +++ b/src/Impostor.Server/Net/AuthService.cs @@ -0,0 +1,88 @@ +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; +using Impostor.Api.Events.Managers; +using Impostor.Api.Net.Messages; +using Impostor.Api.Net.Messages.Auth; +using Impostor.Hazel; +using Impostor.Hazel.Dtls; +using Impostor.Server.Config; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ObjectPool; +using Microsoft.Extensions.Options; + +namespace Impostor.Server.Net +{ + internal class AuthService : IHostedService + { + private readonly ILogger _logger; + private readonly AuthServerConfig _config; + private readonly ObjectPool _readerPool; + private readonly IEventManager _eventManager; + private DtlsConnectionListener? _connection; + + public AuthService(ILogger logger, IOptions config, ObjectPool readerPool, IEventManager eventManager) + { + _logger = logger; + _config = config.Value; + _readerPool = readerPool; + _eventManager = eventManager; + } + + public async Task StartAsync(CancellationToken cancellationToken) + { + var endpoint = new IPEndPoint(IPAddress.Parse(_config.ResolveListenIp()), _config.ListenPort); + + var mode = endpoint.AddressFamily switch + { + AddressFamily.InterNetwork => IPMode.IPv4, + AddressFamily.InterNetworkV6 => IPMode.IPv6, + _ => throw new InvalidOperationException(), + }; + + var rsa = RSA.Create(); + rsa.ImportPkcs8PrivateKey(Convert.FromBase64String(string.Join(string.Empty, (await File.ReadAllLinesAsync(_config.PrivateKey, cancellationToken)).Where(x => !x.StartsWith("-----")))), out _); + var cert = new X509Certificate2(_config.Certificate).CopyWithPrivateKey(rsa); + + _connection = new DtlsConnectionListener(endpoint, _readerPool, mode); + _connection.SetCertificate(cert); + _connection.NewConnection = ConnectionOnNewConnection; + + await _connection.StartAsync(); + + _logger.LogInformation("Auth server is listening on {Address}:{Port}", endpoint.Address, endpoint.Port); + } + + public async Task StopAsync(CancellationToken cancellationToken) + { + _logger.LogWarning("Auth server is shutting down!"); + + if (_connection != null) + { + await _connection.DisposeAsync(); + } + } + + private ValueTask ConnectionOnNewConnection(NewConnectionEventArgs e) + { + MessageHandshake.Deserialize(e.HandshakeData, out var clientVersion, out var platform, out var clientId); + + _logger.LogTrace("New authentication request: {clientVersion}, {platform}, {clientId}", clientVersion, platform, clientId); + + using var writer = MessageWriter.Get(MessageType.Reliable); + + writer.StartMessage(1); + Message01Complete.Serialize(writer, (uint)RandomNumberGenerator.GetInt32(int.MinValue, int.MaxValue)); + writer.EndMessage(); + + return e.Connection.SendAsync(writer); + } + } +} diff --git a/src/Impostor.Server/Net/Matchmaker.cs b/src/Impostor.Server/Net/Matchmaker.cs index e7ce3ace0..6af4f5599 100644 --- a/src/Impostor.Server/Net/Matchmaker.cs +++ b/src/Impostor.Server/Net/Matchmaker.cs @@ -61,7 +61,7 @@ public async ValueTask StopAsync() private async ValueTask OnNewConnection(NewConnectionEventArgs e) { // Handshake. - HandshakeC2S.Deserialize(e.HandshakeData, out var clientVersion, out var name); + HandshakeC2S.Deserialize(e.HandshakeData, out var clientVersion, out var name, out _); var connection = new HazelConnection(e.Connection, _connectionLogger); diff --git a/src/Impostor.Server/Program.cs b/src/Impostor.Server/Program.cs index 03514d902..d82a23626 100644 --- a/src/Impostor.Server/Program.cs +++ b/src/Impostor.Server/Program.cs @@ -117,6 +117,10 @@ private static IHostBuilder CreateHostBuilder(string[] args) .GetSection(AnnouncementsServerConfig.Section) .Get() ?? new AnnouncementsServerConfig(); + var authServer = host.Configuration + .GetSection(AuthServerConfig.Section) + .Get() ?? new AuthServerConfig(); + services.AddSingleton(); services.AddSingleton(); @@ -124,6 +128,7 @@ private static IHostBuilder CreateHostBuilder(string[] args) services.Configure(host.Configuration.GetSection(AntiCheatConfig.Section)); services.Configure(host.Configuration.GetSection(ServerConfig.Section)); services.Configure(host.Configuration.GetSection(AnnouncementsServerConfig.Section)); + services.Configure(host.Configuration.GetSection(AuthServerConfig.Section)); services.Configure(host.Configuration.GetSection(ServerRedirectorConfig.Section)); if (redirector.Enabled) @@ -212,6 +217,11 @@ private static IHostBuilder CreateHostBuilder(string[] args) { services.AddHostedService(); } + + if (authServer.Enabled) + { + services.AddHostedService(); + } }) .UseSerilog() .UseConsoleLifetime() From 4f53d3f4e6ddf6d28c2642c79c38e68a69301474 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sat, 3 Apr 2021 00:14:33 +0200 Subject: [PATCH 40/72] Hopefully fix the submodule --- src/Impostor.Hazel | 1 + 1 file changed, 1 insertion(+) create mode 160000 src/Impostor.Hazel diff --git a/src/Impostor.Hazel b/src/Impostor.Hazel new file mode 160000 index 000000000..8de027461 --- /dev/null +++ b/src/Impostor.Hazel @@ -0,0 +1 @@ +Subproject commit 8de027461e59af67fb9dc0d9b925a88ad4a01d26 From a63fc400993813bc4163c88550fd096c99efe0b8 Mon Sep 17 00:00:00 2001 From: miniduikboot <5243971+miniduikboot@users.noreply.github.com> Date: Wed, 31 Mar 2021 21:49:51 +0200 Subject: [PATCH 41/72] Gamedata packets are now have initial state false I managed to get into a lobby with this --- src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs index d6a16fdad..a1f56ed50 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs @@ -75,7 +75,8 @@ public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPl } else { - throw new NotImplementedException("This shouldn't happen, according to Among Us disassembly."); + // It'll send an message per dirty player + // throw new NotImplementedException("This shouldn't happen, according to Among Us disassembly."); } } From 92e3506f5119b2de786639e6c64d2ecfefbac4a6 Mon Sep 17 00:00:00 2001 From: miniduikboot <5243971+miniduikboot@users.noreply.github.com> Date: Wed, 31 Mar 2021 23:22:56 +0200 Subject: [PATCH 42/72] First attempt at getting some airship stuff online --- src/Impostor.Api/Innersloth/MapTypes.cs | 1 + src/Impostor.Api/Innersloth/SystemTypes.cs | 34 ++++++++++++++++++++++ src/Impostor.Server/Net/State/Game.Data.cs | 1 + 3 files changed, 36 insertions(+) diff --git a/src/Impostor.Api/Innersloth/MapTypes.cs b/src/Impostor.Api/Innersloth/MapTypes.cs index 2706933aa..5de0adb65 100644 --- a/src/Impostor.Api/Innersloth/MapTypes.cs +++ b/src/Impostor.Api/Innersloth/MapTypes.cs @@ -5,5 +5,6 @@ public enum MapTypes : byte Skeld = 0, MiraHQ = 1, Polus = 2, + Airship = 4, } } diff --git a/src/Impostor.Api/Innersloth/SystemTypes.cs b/src/Impostor.Api/Innersloth/SystemTypes.cs index 6a072e771..74affbfd1 100644 --- a/src/Impostor.Api/Innersloth/SystemTypes.cs +++ b/src/Impostor.Api/Innersloth/SystemTypes.cs @@ -67,5 +67,39 @@ public enum SystemTypes : byte Specimens = 28, BoilerRoom = 29, + + VaultRoom = 30, + + Cockpit = 31, + + Armory = 32, + + Kitchen = 33, + + ViewingDeck = 34, + + HallOfPortraits = 35, + + CargoBay = 36, + + Ventilation = 37, + + Showers = 38, + + Engine = 39, + + Brig = 40, + + MeetingRoom = 41, + + Records = 42, + + Lounge = 43, + + GapRoom = 44, + + MainHall = 45, + + Medical = 46, } } diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index 968076814..e69147086 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -40,6 +40,7 @@ internal partial class Game typeof(InnerShipStatus), // HeadQuarters typeof(InnerShipStatus), // PlanetMap typeof(InnerShipStatus), // AprilShipStatus + typeof(InnerShipStatus), // Airship }; private readonly List _allObjects = new List(); From d31115096755c9b1cef72dae0aa9773ff64f995f Mon Sep 17 00:00:00 2001 From: miniduikboot <5243971+miniduikboot@users.noreply.github.com> Date: Thu, 1 Apr 2021 16:57:34 +0200 Subject: [PATCH 43/72] API: update enums for airship --- src/Impostor.Api/Innersloth/MapSpawn.cs | 1 + src/Impostor.Api/Net/Inner/RpcCalls.cs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Impostor.Api/Innersloth/MapSpawn.cs b/src/Impostor.Api/Innersloth/MapSpawn.cs index 61dea0f6d..3f59f0a8f 100644 --- a/src/Impostor.Api/Innersloth/MapSpawn.cs +++ b/src/Impostor.Api/Innersloth/MapSpawn.cs @@ -18,6 +18,7 @@ private MapSpawn(float spawnRadius, Vector2 initialSpawnCenter, Vector2 meetingS [MapTypes.Skeld] = new MapSpawn(1.6f, new Vector2(-0.72f, 0.62f), new Vector2(-0.72f, 0.62f)), [MapTypes.MiraHQ] = new MapSpawn(1.55f, new Vector2(-4.4f, 2.2f), new Vector2(24.043f, 1.72f)), [MapTypes.Polus] = new MapSpawn(1f, new Vector2(16.64f, -2.46f), new Vector2(17.726f, -16.286f)), + [MapTypes.Airship] = new MapSpawn(0f, new Vector2(-0.66f, -0.5f), new Vector2(-0.66f, -0.5f)), }; public float SpawnRadius { get; } diff --git a/src/Impostor.Api/Net/Inner/RpcCalls.cs b/src/Impostor.Api/Net/Inner/RpcCalls.cs index 506017d1a..6176d3c67 100644 --- a/src/Impostor.Api/Net/Inner/RpcCalls.cs +++ b/src/Impostor.Api/Net/Inner/RpcCalls.cs @@ -1,4 +1,4 @@ -namespace Impostor.Server.Net.Inner +namespace Impostor.Server.Net.Inner { public enum RpcCalls : byte { @@ -33,5 +33,7 @@ public enum RpcCalls : byte RepairSystem = 28, SetTasks = 29, UpdateGameData = 30, + ClimbLadder = 31, + UsePlatform = 32, } } From 4c1bd4a57813bbf81afab6afeefa6304e568040b Mon Sep 17 00:00:00 2001 From: miniduikboot <5243971+miniduikboot@users.noreply.github.com> Date: Thu, 1 Apr 2021 17:49:41 +0200 Subject: [PATCH 44/72] editorconfig: Don't indent blocks in case contents This is more in line with the existing codebase --- src/.editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/.editorconfig b/src/.editorconfig index 38c708527..88f363eae 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -171,7 +171,7 @@ csharp_new_line_between_query_expression_clauses = true csharp_indent_block_contents = true csharp_indent_braces = false csharp_indent_case_contents = true -csharp_indent_case_contents_when_block = true +csharp_indent_case_contents_when_block = false csharp_indent_switch_labels = true csharp_indent_labels = flush_left From 16a2b0aac658a1c80a9d9933d95d5088728619b6 Mon Sep 17 00:00:00 2001 From: miniduikboot <5243971+miniduikboot@users.noreply.github.com> Date: Thu, 1 Apr 2021 18:16:04 +0200 Subject: [PATCH 45/72] I counted the doors on Airship and I hope I counted correctly --- .../Net/Inner/Objects/Systems/ShipStatus/DoorsSystemType.cs | 1 + 1 file changed, 1 insertion(+) 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 df374bff6..03ba1df92 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/DoorsSystemType.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/DoorsSystemType.cs @@ -18,6 +18,7 @@ public DoorsSystemType(IGame game) MapTypes.Skeld => 13, MapTypes.MiraHQ => 2, MapTypes.Polus => 12, + MapTypes.Airship => 21, // TODO do the toilet doors count? 21 yes, 17 no _ => throw new ArgumentOutOfRangeException(), }; From d5ae007d1c0af4cc883fb6a64810bbac6680ea07 Mon Sep 17 00:00:00 2001 From: miniduikboot <5243971+miniduikboot@users.noreply.github.com> Date: Fri, 2 Apr 2021 00:41:19 +0200 Subject: [PATCH 46/72] implement rpc 31: climb ladder --- .../Net/Messages/Rpcs/Rpc31ClimbLadder.cs | 17 +++++++++++++++++ .../Objects/Components/InnerPlayerPhysics.cs | 4 ++++ 2 files changed, 21 insertions(+) create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc31ClimbLadder.cs diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc31ClimbLadder.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc31ClimbLadder.cs new file mode 100644 index 000000000..a31522167 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc31ClimbLadder.cs @@ -0,0 +1,17 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc31ClimbLadder + { + public static void Serialize(IMessageWriter writer, byte ladderId, byte lastClimbLadderSid) + { + writer.Write(ladderId); + writer.Write(lastClimbLadderSid); + } + + public static void Deserialize(IMessageReader reader, out byte ladderId, out byte lastClimbLadderSid) + { + ladderId = reader.ReadByte(); + lastClimbLadderSid = reader.ReadByte(); + } + } +} diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs index 14e8690c7..19d4dd504 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs @@ -55,6 +55,10 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client Rpc19EnterVent.Deserialize(reader, out ventId); break; + case RpcCalls.ClimbLadder: + Rpc31ClimbLadder.Deserialize(reader, out byte ladderId, out byte lastClimbLadderSid); + return true; + default: return await UnregisteredCall(call, sender); } From c01062ed65cf93e81e56080d6872b6b73e523fc2 Mon Sep 17 00:00:00 2001 From: miniduikboot <5243971+miniduikboot@users.noreply.github.com> Date: Fri, 2 Apr 2021 00:42:26 +0200 Subject: [PATCH 47/72] implement rpc 32: use platform --- .../Net/Messages/Rpcs/Rpc32UsePlatform.cs | 13 +++++++++++++ .../Net/Inner/Objects/InnerPlayerControl.cs | 11 +++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/Impostor.Api/Net/Messages/Rpcs/Rpc32UsePlatform.cs diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc32UsePlatform.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc32UsePlatform.cs new file mode 100644 index 000000000..9344be201 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc32UsePlatform.cs @@ -0,0 +1,13 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc32UsePlatform + { + public static void Serialize(IMessageWriter writer) + { + } + + public static void Deserialize(IMessageReader reader) + { + } + } +} diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs index 7bbf8e78a..49e069baf 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs @@ -285,6 +285,17 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client return await HandleSetStartCounter(sender, sequenceId, startCounter); } + case RpcCalls.UsePlatform: + { + if (!await ValidateOwnership(call, sender)) + { + return false; + } + + Rpc32UsePlatform.Deserialize(reader); + break; + } + default: return await UnregisteredCall(call, sender); } From 66c2434320077130b47ec6512d372e25e2178caa Mon Sep 17 00:00:00 2001 From: miniduikboot <5243971+miniduikboot@users.noreply.github.com> Date: Fri, 2 Apr 2021 22:42:15 +0200 Subject: [PATCH 48/72] Implement HeliSabotageSystemType It works, although I'm not completely sure why. --- .../Net/Inner/Objects/InnerShipStatus.cs | 2 +- .../ShipStatus/HeliSabotageSystemType.cs | 57 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs index d51c0b8d2..575a64ac2 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs @@ -29,7 +29,7 @@ public InnerShipStatus(ILogger logger, Game game) { [SystemTypes.Electrical] = new SwitchSystem(), [SystemTypes.MedBay] = new MedScanSystem(), - [SystemTypes.Reactor] = new ReactorSystemType(), + [SystemTypes.Reactor] = game.Options.Map == MapTypes.Airship ? new HeliSabotageSystemType() : new ReactorSystemType(), [SystemTypes.LifeSupp] = new LifeSuppSystemType(), [SystemTypes.Security] = new SecurityCameraSystemType(), [SystemTypes.Comms] = new HudOverrideSystemType(), diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs new file mode 100644 index 000000000..f29c4b8df --- /dev/null +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using Impostor.Api.Net.Messages; +using Microsoft.Extensions.Logging; + +namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus +{ + public class HeliSabotageSystemType : ISystemType, IActivatable + { + public HeliSabotageSystemType() + { + Countdown = 10000f; + ActiveConsoles = new HashSet>(); + CompletedConsoles = new HashSet(); + } + + public float Countdown { get; private set; } + + public float Timer { get; private set; } + + public HashSet> ActiveConsoles { get; } + + public HashSet CompletedConsoles { get; } + + public bool IsActive => Countdown < 10000.0; + + public void Serialize(IMessageWriter writer, bool initialState) + { + throw new NotImplementedException(); + } + + public void Deserialize(IMessageReader reader, bool initialState) + { + // TODO: Find out what these 2 bytes are used for + _ = reader.ReadByte(); + _ = reader.ReadByte(); + Countdown = reader.ReadSingle(); + Timer = reader.ReadSingle(); + ActiveConsoles.Clear(); // TODO: Thread safety + CompletedConsoles.Clear(); // TODO: Thread safety + + var count = reader.ReadPackedUInt32(); + + for (var i = 0; i < count; i++) + { + ActiveConsoles.Add(new Tuple(reader.ReadByte(), reader.ReadByte())); + } + + var count2 = reader.ReadPackedUInt32(); + + for (var i = 0; i < count2; i++) + { + CompletedConsoles.Add(reader.ReadByte()); + } + } + } +} From 47aebe7b7b564893efa42bea96fe09eac3a412f6 Mon Sep 17 00:00:00 2001 From: miniduikboot <5243971+miniduikboot@users.noreply.github.com> Date: Sat, 3 Apr 2021 00:08:51 +0200 Subject: [PATCH 49/72] Fix InnerShipStatus deserializing 3.31 now distributes them as multiple messages This also explains the two weird bytes in HeliSabotage, so these can be removed too --- .../Net/Inner/Objects/InnerShipStatus.cs | 28 ++++--------------- .../ShipStatus/HeliSabotageSystemType.cs | 3 -- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs index 575a64ac2..c571c5a31 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs @@ -56,31 +56,13 @@ public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPl return; } - if (initialState) + while (reader.Position < reader.Length) { - // TODO: (_systems[SystemTypes.Doors] as DoorsSystemType).SetDoors(); - foreach (var systemType in SystemTypeHelpers.AllTypes) + IMessageReader msgReader = reader.ReadMessage(); + SystemTypes type = (SystemTypes)msgReader.Tag; + if (_systems.TryGetValue(type, out var value)) { - if (_systems.TryGetValue(systemType, out var system)) - { - system.Deserialize(reader, true); - } - } - } - else - { - var count = reader.ReadPackedUInt32(); - - foreach (var systemType in SystemTypeHelpers.AllTypes) - { - // TODO: Not sure what is going on here, check. - if ((count & 1 << (int)(systemType & (SystemTypes.ShipTasks | SystemTypes.Doors))) != 0L) - { - if (_systems.TryGetValue(systemType, out var system)) - { - system.Deserialize(reader, false); - } - } + value.Deserialize(msgReader, initialState); } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs index f29c4b8df..22a2a22d5 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs @@ -31,9 +31,6 @@ public void Serialize(IMessageWriter writer, bool initialState) public void Deserialize(IMessageReader reader, bool initialState) { - // TODO: Find out what these 2 bytes are used for - _ = reader.ReadByte(); - _ = reader.ReadByte(); Countdown = reader.ReadSingle(); Timer = reader.ReadSingle(); ActiveConsoles.Clear(); // TODO: Thread safety From 7fd68e31e6e2f6713b4c58525a9beada56424bef Mon Sep 17 00:00:00 2001 From: miniduikboot <5243971+miniduikboot@users.noreply.github.com> Date: Sat, 3 Apr 2021 00:37:12 +0200 Subject: [PATCH 50/72] Fix Docker container build --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index e8797a7c4..ae6b0706e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ WORKDIR /source # Copy csproj and restore. COPY src/Impostor.Server/Impostor.Server.csproj ./src/Impostor.Server/Impostor.Server.csproj COPY src/Impostor.Api/Impostor.Api.csproj ./src/Impostor.Api/Impostor.Api.csproj -COPY src/Impostor.Hazel/Impostor.Hazel.csproj ./src/Impostor.Hazel/Impostor.Hazel.csproj +COPY src/Impostor.Hazel/Hazel/Hazel.csproj ./src/Impostor.Hazel/Hazel/Hazel.csproj RUN case "$TARGETARCH" in \ amd64) NETCORE_PLATFORM='linux-x64';; \ @@ -21,7 +21,7 @@ RUN case "$TARGETARCH" in \ esac && \ dotnet restore -r "$NETCORE_PLATFORM" ./src/Impostor.Server/Impostor.Server.csproj && \ dotnet restore -r "$NETCORE_PLATFORM" ./src/Impostor.Api/Impostor.Api.csproj && \ - dotnet restore -r "$NETCORE_PLATFORM" ./src/Impostor.Hazel/Impostor.Hazel.csproj + dotnet restore -r "$NETCORE_PLATFORM" ./src/Impostor.Hazel/Hazel/Hazel.csproj # Copy everything else. COPY src/. ./src/ From 441d9c300c67bd134fc23b8672a3aa1900245544 Mon Sep 17 00:00:00 2001 From: miniduikboot <5243971+miniduikboot@users.noreply.github.com> Date: Sat, 3 Apr 2021 00:46:34 +0200 Subject: [PATCH 51/72] Move PlayerVentEvent call to applicable RPC's --- .../Net/Inner/Objects/Components/InnerPlayerPhysics.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs index 19d4dd504..ce93dbb02 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs @@ -49,22 +49,22 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client { case RpcCalls.EnterVent: Rpc19EnterVent.Deserialize(reader, out ventId); + await _eventManager.CallAsync(new PlayerVentEvent(_game, sender, _playerControl, (VentLocation)ventId, true)); break; case RpcCalls.ExitVent: Rpc19EnterVent.Deserialize(reader, out ventId); + await _eventManager.CallAsync(new PlayerVentEvent(_game, sender, _playerControl, (VentLocation)ventId, false)); break; case RpcCalls.ClimbLadder: Rpc31ClimbLadder.Deserialize(reader, out byte ladderId, out byte lastClimbLadderSid); - return true; + break; default: return await UnregisteredCall(call, sender); } - await _eventManager.CallAsync(new PlayerVentEvent(_game, sender, _playerControl, (VentLocation)ventId, call == RpcCalls.EnterVent)); - return true; } } From d801a36af8fc82037469d924c864328157007332 Mon Sep 17 00:00:00 2001 From: miniduikboot <5243971+miniduikboot@users.noreply.github.com> Date: Sun, 4 Apr 2021 10:35:00 +0200 Subject: [PATCH 52/72] Rename things for 6pak --- src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs | 6 +++--- .../Objects/Systems/ShipStatus/HeliSabotageSystemType.cs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs index c571c5a31..8ae003b24 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs @@ -58,11 +58,11 @@ public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPl while (reader.Position < reader.Length) { - IMessageReader msgReader = reader.ReadMessage(); - SystemTypes type = (SystemTypes)msgReader.Tag; + IMessageReader messageReader = reader.ReadMessage(); + SystemTypes type = (SystemTypes)messageReader.Tag; if (_systems.TryGetValue(type, out var value)) { - value.Deserialize(msgReader, initialState); + value.Deserialize(messageReader, initialState); } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs index 22a2a22d5..1d6be3206 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs @@ -36,16 +36,16 @@ public void Deserialize(IMessageReader reader, bool initialState) ActiveConsoles.Clear(); // TODO: Thread safety CompletedConsoles.Clear(); // TODO: Thread safety - var count = reader.ReadPackedUInt32(); + var activeCount = reader.ReadPackedUInt32(); - for (var i = 0; i < count; i++) + for (var i = 0; i < activeCount; i++) { ActiveConsoles.Add(new Tuple(reader.ReadByte(), reader.ReadByte())); } - var count2 = reader.ReadPackedUInt32(); + var completedCount = reader.ReadPackedUInt32(); - for (var i = 0; i < count2; i++) + for (var i = 0; i < completedCount; i++) { CompletedConsoles.Add(reader.ReadByte()); } From b5cee4824251981b57c968b7418f7adf4d2997db Mon Sep 17 00:00:00 2001 From: John Tran Date: Sun, 4 Apr 2021 20:31:28 +1000 Subject: [PATCH 53/72] Airship Vent Enums (#373) Co-authored-by: miniduikboot <5243971+miniduikboot@users.noreply.github.com> Co-authored-by: John Tran --- src/Impostor.Api/Innersloth/VentLocation.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Impostor.Api/Innersloth/VentLocation.cs b/src/Impostor.Api/Innersloth/VentLocation.cs index f9b8567ac..0092c6960 100644 --- a/src/Impostor.Api/Innersloth/VentLocation.cs +++ b/src/Impostor.Api/Innersloth/VentLocation.cs @@ -44,5 +44,19 @@ public enum VentLocation : uint PolusRightStabilizer = 9, PolusLeftStabilizer = 10, PolusOutsideAdmin = 11, + + // Airship + AirshipVault = 0, + AirshipCockpit = 1, + AirshipViewingDeck = 2, + AirshipEngineRoom = 3, + AirshipKitchen = 4, + AirshipMainHallBottom = 5, + AirshipGapRight = 6, + AirshipGapLeft = 7, + AirshipMainHallTop = 8, + AirshipShowers = 9, + AirshipRecords = 10, + AirshipCargoBay = 11, } } From 60bf6b5f589c2922e4d3296425a7698c5d1ca31f Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 4 Apr 2021 12:32:03 +0200 Subject: [PATCH 54/72] Fix namespaces --- src/Impostor.Api/CheatContext.cs | 2 +- src/Impostor.Api/Net/Inner/RpcCalls.cs | 2 +- .../Inner/Objects/Components/InnerCustomNetworkTransform.Api.cs | 1 + .../Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs | 1 + .../Net/Inner/Objects/Components/InnerPlayerPhysics.cs | 1 + .../Net/Inner/Objects/Components/InnerVoteBanSystem.cs | 1 + src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs | 1 + src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs | 1 + src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs | 1 + src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs | 1 + src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs | 1 + src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs | 1 + src/Impostor.Server/Net/State/Game.Outgoing.cs | 1 + 13 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Impostor.Api/CheatContext.cs b/src/Impostor.Api/CheatContext.cs index 45a9956e6..7508a7877 100644 --- a/src/Impostor.Api/CheatContext.cs +++ b/src/Impostor.Api/CheatContext.cs @@ -1,4 +1,4 @@ -using Impostor.Server.Net.Inner; +using Impostor.Api.Net.Inner; namespace Impostor.Api { diff --git a/src/Impostor.Api/Net/Inner/RpcCalls.cs b/src/Impostor.Api/Net/Inner/RpcCalls.cs index 6176d3c67..b288df39c 100644 --- a/src/Impostor.Api/Net/Inner/RpcCalls.cs +++ b/src/Impostor.Api/Net/Inner/RpcCalls.cs @@ -1,4 +1,4 @@ -namespace Impostor.Server.Net.Inner +namespace Impostor.Api.Net.Inner { public enum RpcCalls : byte { 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 0e70bd64f..2447aea6a 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.Api.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.Api.cs @@ -1,5 +1,6 @@ using System.Numerics; using System.Threading.Tasks; +using Impostor.Api.Net.Inner; using Impostor.Api.Net.Inner.Objects.Components; namespace Impostor.Server.Net.Inner.Objects.Components diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs index ff5c21d59..e9c152227 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs @@ -3,6 +3,7 @@ using Impostor.Api; using Impostor.Api.Events.Managers; using Impostor.Api.Net; +using Impostor.Api.Net.Inner; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.Rpcs; using Impostor.Server.Events.Player; diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs index ce93dbb02..ce8c8b5eb 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs @@ -3,6 +3,7 @@ using Impostor.Api.Events.Managers; using Impostor.Api.Innersloth; using Impostor.Api.Net; +using Impostor.Api.Net.Inner; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.Rpcs; using Impostor.Server.Events.Player; diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerVoteBanSystem.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerVoteBanSystem.cs index 117f78e6d..3a310c88e 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerVoteBanSystem.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerVoteBanSystem.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Impostor.Api; using Impostor.Api.Net; +using Impostor.Api.Net.Inner; using Impostor.Api.Net.Inner.Objects; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.Rpcs; diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs index a1f56ed50..bcbda030e 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Impostor.Api; using Impostor.Api.Net; +using Impostor.Api.Net.Inner; using Impostor.Api.Net.Inner.Objects; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.Rpcs; diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs b/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs index 3dfd74158..3a44fc525 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Impostor.Api.Games; using Impostor.Api.Net; +using Impostor.Api.Net.Inner; using Impostor.Api.Net.Inner.Objects; using Impostor.Api.Net.Messages; using Impostor.Server.Net.State; diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs index f41680b16..a40602836 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs @@ -6,6 +6,7 @@ using Impostor.Api.Events.Managers; using Impostor.Api.Innersloth; using Impostor.Api.Net; +using Impostor.Api.Net.Inner; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.Rpcs; using Impostor.Server.Events.Meeting; diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs index 604c6e644..a2382e2be 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs @@ -2,6 +2,7 @@ using Impostor.Api; using Impostor.Api.Innersloth; using Impostor.Api.Innersloth.Customization; +using Impostor.Api.Net.Inner; using Impostor.Api.Net.Inner.Objects; using Impostor.Api.Net.Inner.Objects.Components; using Impostor.Api.Net.Messages.Rpcs; diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs index 49e069baf..bd56e58ac 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs @@ -8,6 +8,7 @@ using Impostor.Api.Innersloth; using Impostor.Api.Innersloth.Customization; using Impostor.Api.Net; +using Impostor.Api.Net.Inner; using Impostor.Api.Net.Inner.Objects; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.Rpcs; diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs index 8ae003b24..119b24cf6 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs @@ -4,6 +4,7 @@ using Impostor.Api; using Impostor.Api.Innersloth; using Impostor.Api.Net; +using Impostor.Api.Net.Inner; using Impostor.Api.Net.Inner.Objects; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.Rpcs; diff --git a/src/Impostor.Server/Net/State/Game.Outgoing.cs b/src/Impostor.Server/Net/State/Game.Outgoing.cs index 5c84f9472..b5b654eaf 100644 --- a/src/Impostor.Server/Net/State/Game.Outgoing.cs +++ b/src/Impostor.Server/Net/State/Game.Outgoing.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Impostor.Api.Innersloth; using Impostor.Api.Net; +using Impostor.Api.Net.Inner; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.S2C; using Impostor.Hazel; From 225b56e71fd42f9c5514ca7a16ee0097658c5b63 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 4 Apr 2021 12:54:19 +0200 Subject: [PATCH 55/72] Fix cheatcontext in ValidateImpostor calls --- .../Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs | 2 +- .../Net/Inner/Objects/Components/InnerPlayerPhysics.cs | 2 +- src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs | 2 +- src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs index e9c152227..e9e3dfb9e 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs @@ -86,7 +86,7 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client { if (call == RpcCalls.SnapTo) { - if (!await ValidateOwnership(call, sender) || !await ValidateImpostor(RpcCalls.MurderPlayer, sender, _playerControl.PlayerInfo)) + if (!await ValidateOwnership(call, sender) || !await ValidateImpostor(call, sender, _playerControl.PlayerInfo)) { return false; } diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs index ce8c8b5eb..80daa38f2 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs @@ -39,7 +39,7 @@ public override ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? public override async ValueTask HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) { - if (!await ValidateOwnership(call, sender) || !await ValidateImpostor(RpcCalls.MurderPlayer, sender, _playerControl.PlayerInfo)) + if (!await ValidateOwnership(call, sender) || !await ValidateImpostor(call, sender, _playerControl.PlayerInfo)) { return false; } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs index bd56e58ac..bf4ed8c5d 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs @@ -210,7 +210,7 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client case RpcCalls.MurderPlayer: { - if (!await ValidateOwnership(call, sender) || !await ValidateImpostor(RpcCalls.MurderPlayer, sender, PlayerInfo)) + if (!await ValidateOwnership(call, sender) || !await ValidateImpostor(call, sender, PlayerInfo)) { return false; } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs index 119b24cf6..dd8b511f7 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs @@ -79,7 +79,7 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client { case RpcCalls.CloseDoorsOfType: { - if (!await ValidateImpostor(RpcCalls.MurderPlayer, sender, sender.Character!.PlayerInfo)) + if (!await ValidateImpostor(call, sender, sender.Character!.PlayerInfo)) { return false; } From 13bddeb7bdd6d954faf5beec309ac83c1095aa72 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 4 Apr 2021 19:48:25 +0200 Subject: [PATCH 56/72] Split ShipStatus to multiple classes, implement new door types --- .../Innersloth/Customization/ColorType.cs | 2 +- src/Impostor.Api/Net/Inner/IGameNet.cs | 1 + src/Impostor.Api/Net/Inner/IInnerNetObject.cs | 6 +- .../Objects/ShipStatus/IInnerAirshipStatus.cs | 6 ++ .../ShipStatus/IInnerMiraShipStatus.cs | 6 ++ .../ShipStatus/IInnerPolusShipStatus.cs | 6 ++ .../{ => ShipStatus}/IInnerShipStatus.cs | 2 +- .../ShipStatus/IInnerSkeldShipStatus.cs | 6 ++ src/Impostor.Api/Net/Inner/RpcCalls.cs | 1 - .../Net/Inner/InnerNetObject.cs | 15 +++++ .../InnerCustomNetworkTransform.Api.cs | 6 +- .../Components/InnerCustomNetworkTransform.cs | 7 +-- .../Objects/Components/InnerPlayerPhysics.cs | 36 +++++++----- .../Objects/Components/InnerVoteBanSystem.cs | 2 +- .../Net/Inner/Objects/InnerGameData.cs | 53 +++++++----------- .../Net/Inner/Objects/InnerLobbyBehaviour.cs | 7 +-- .../Net/Inner/Objects/InnerMeetingHud.cs | 14 ++--- .../Inner/Objects/InnerPlayerControl.Api.cs | 40 ++++++------- .../Net/Inner/Objects/InnerPlayerControl.cs | 52 +++++++++-------- .../Net/Inner/Objects/InnerPlayerInfo.cs | 10 +++- .../Objects/ShipStatus/InnerAirshipStatus.cs | 31 ++++++++++ .../Objects/ShipStatus/InnerMiraShipStatus.cs | 27 +++++++++ .../ShipStatus/InnerPolusShipStatus.cs | 28 ++++++++++ .../{ => ShipStatus}/InnerShipStatus.cs | 56 +++++++++---------- .../ShipStatus/InnerSkeldShipStatus.cs | 29 ++++++++++ .../Systems/ShipStatus/AutoDoorsSystemType.cs | 44 +++++++++++++++ .../Systems/ShipStatus/DoorsSystemType.cs | 47 +++++----------- .../Systems/ShipStatus/ElectricalDoors.cs | 30 ++++++++++ .../ShipStatus/HeliSabotageSystemType.cs | 1 - .../ShipStatus/MovingPlatformBehaviour.cs | 22 ++++++++ src/Impostor.Server/Net/State/Game.Api.cs | 1 - src/Impostor.Server/Net/State/Game.Data.cs | 13 +++-- src/Impostor.Server/Net/State/GameNet.Api.cs | 1 + src/Impostor.Server/Net/State/GameNet.cs | 1 + 34 files changed, 419 insertions(+), 190 deletions(-) create mode 100644 src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerAirshipStatus.cs create mode 100644 src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerMiraShipStatus.cs create mode 100644 src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerPolusShipStatus.cs rename src/Impostor.Api/Net/Inner/Objects/{ => ShipStatus}/IInnerShipStatus.cs (56%) create mode 100644 src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerSkeldShipStatus.cs create mode 100644 src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs create mode 100644 src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs create mode 100644 src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs rename src/Impostor.Server/Net/Inner/Objects/{ => ShipStatus}/InnerShipStatus.cs (62%) create mode 100644 src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs create mode 100644 src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/AutoDoorsSystemType.cs create mode 100644 src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/ElectricalDoors.cs create mode 100644 src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/MovingPlatformBehaviour.cs diff --git a/src/Impostor.Api/Innersloth/Customization/ColorType.cs b/src/Impostor.Api/Innersloth/Customization/ColorType.cs index fc7be4cfa..d9e43a68a 100644 --- a/src/Impostor.Api/Innersloth/Customization/ColorType.cs +++ b/src/Impostor.Api/Innersloth/Customization/ColorType.cs @@ -1,6 +1,6 @@ namespace Impostor.Api.Innersloth.Customization { - public enum ColorType : byte + public enum ColorType { Red = 0, Blue = 1, diff --git a/src/Impostor.Api/Net/Inner/IGameNet.cs b/src/Impostor.Api/Net/Inner/IGameNet.cs index 9cac0f2db..7b068d108 100644 --- a/src/Impostor.Api/Net/Inner/IGameNet.cs +++ b/src/Impostor.Api/Net/Inner/IGameNet.cs @@ -1,4 +1,5 @@ using Impostor.Api.Net.Inner.Objects; +using Impostor.Api.Net.Inner.Objects.ShipStatus; namespace Impostor.Api.Net.Inner { diff --git a/src/Impostor.Api/Net/Inner/IInnerNetObject.cs b/src/Impostor.Api/Net/Inner/IInnerNetObject.cs index 8cfadb8e6..db868b63c 100644 --- a/src/Impostor.Api/Net/Inner/IInnerNetObject.cs +++ b/src/Impostor.Api/Net/Inner/IInnerNetObject.cs @@ -1,9 +1,13 @@ -namespace Impostor.Api.Net.Inner +using Impostor.Api.Games; + +namespace Impostor.Api.Net.Inner { public interface IInnerNetObject { public uint NetId { get; } public int OwnerId { get; } + + public IGame Game { get; } } } diff --git a/src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerAirshipStatus.cs b/src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerAirshipStatus.cs new file mode 100644 index 000000000..2711b89be --- /dev/null +++ b/src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerAirshipStatus.cs @@ -0,0 +1,6 @@ +namespace Impostor.Api.Net.Inner.Objects.ShipStatus +{ + public interface IInnerAirshipStatus : IInnerShipStatus + { + } +} diff --git a/src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerMiraShipStatus.cs b/src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerMiraShipStatus.cs new file mode 100644 index 000000000..870a9456e --- /dev/null +++ b/src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerMiraShipStatus.cs @@ -0,0 +1,6 @@ +namespace Impostor.Api.Net.Inner.Objects.ShipStatus +{ + public interface IInnerMiraShipStatus : IInnerShipStatus + { + } +} diff --git a/src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerPolusShipStatus.cs b/src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerPolusShipStatus.cs new file mode 100644 index 000000000..5e336bd1a --- /dev/null +++ b/src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerPolusShipStatus.cs @@ -0,0 +1,6 @@ +namespace Impostor.Api.Net.Inner.Objects.ShipStatus +{ + public interface IInnerPolusShipStatus : IInnerShipStatus + { + } +} diff --git a/src/Impostor.Api/Net/Inner/Objects/IInnerShipStatus.cs b/src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerShipStatus.cs similarity index 56% rename from src/Impostor.Api/Net/Inner/Objects/IInnerShipStatus.cs rename to src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerShipStatus.cs index 79b9f9649..c00769d98 100644 --- a/src/Impostor.Api/Net/Inner/Objects/IInnerShipStatus.cs +++ b/src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerShipStatus.cs @@ -1,4 +1,4 @@ -namespace Impostor.Api.Net.Inner.Objects +namespace Impostor.Api.Net.Inner.Objects.ShipStatus { public interface IInnerShipStatus : IInnerNetObject { diff --git a/src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerSkeldShipStatus.cs b/src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerSkeldShipStatus.cs new file mode 100644 index 000000000..e0e9df17a --- /dev/null +++ b/src/Impostor.Api/Net/Inner/Objects/ShipStatus/IInnerSkeldShipStatus.cs @@ -0,0 +1,6 @@ +namespace Impostor.Api.Net.Inner.Objects.ShipStatus +{ + public interface IInnerSkeldShipStatus : IInnerShipStatus + { + } +} diff --git a/src/Impostor.Api/Net/Inner/RpcCalls.cs b/src/Impostor.Api/Net/Inner/RpcCalls.cs index b288df39c..44f85e7aa 100644 --- a/src/Impostor.Api/Net/Inner/RpcCalls.cs +++ b/src/Impostor.Api/Net/Inner/RpcCalls.cs @@ -32,7 +32,6 @@ public enum RpcCalls : byte CloseDoorsOfType = 27, RepairSystem = 28, SetTasks = 29, - UpdateGameData = 30, ClimbLadder = 31, UsePlatform = 32, } diff --git a/src/Impostor.Server/Net/Inner/InnerNetObject.cs b/src/Impostor.Server/Net/Inner/InnerNetObject.cs index 073e5811f..4a1510414 100644 --- a/src/Impostor.Server/Net/Inner/InnerNetObject.cs +++ b/src/Impostor.Server/Net/Inner/InnerNetObject.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Impostor.Api.Games; using Impostor.Api.Net; using Impostor.Api.Net.Inner; using Impostor.Api.Net.Messages; @@ -10,10 +11,19 @@ internal abstract partial class InnerNetObject : GameObject, IInnerNetObject { private const int HostInheritId = -2; + protected InnerNetObject(Game game) + { + Game = game; + } + public uint NetId { get; internal set; } public int OwnerId { get; internal set; } + public Game Game { get; } + + IGame IInnerNetObject.Game => Game; + public SpawnFlags SpawnFlags { get; internal set; } public bool IsOwnedBy(IClientPlayer player) @@ -27,5 +37,10 @@ public bool IsOwnedBy(IClientPlayer player) public abstract ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState); public abstract ValueTask HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader); + + public virtual ValueTask OnSpawnAsync() + { + return default; + } } } 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 2447aea6a..b73b835f8 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.Api.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.Api.cs @@ -12,14 +12,14 @@ public async ValueTask SnapToAsync(Vector2 position) 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)) + using (var writer = Game.StartRpc(NetId, RpcCalls.SnapTo)) { writer.Write(position); writer.Write(_lastSequenceId); - await _game.FinishRpcAsync(writer); + await Game.FinishRpcAsync(writer); } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs index e9e3dfb9e..d1a48a3a0 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs @@ -17,18 +17,15 @@ internal partial class InnerCustomNetworkTransform : InnerNetObject { private readonly ILogger _logger; private readonly InnerPlayerControl _playerControl; - private readonly Game _game; private readonly IEventManager _eventManager; private readonly ObjectPool _pool; private ushort _lastSequenceId; - public InnerCustomNetworkTransform(ILogger logger, InnerPlayerControl playerControl, Game game, IEventManager eventManager, ObjectPool pool) + public InnerCustomNetworkTransform(Game game, ILogger logger, InnerPlayerControl playerControl, IEventManager eventManager, ObjectPool pool) : base(game) { _logger = logger; _playerControl = playerControl; - _game = game; - _game = game; _eventManager = eventManager; _pool = pool; } @@ -106,7 +103,7 @@ internal async ValueTask SetPositionAsync(IClientPlayer sender, Vector2 position Velocity = velocity; var playerMovementEvent = _pool.Get(); - playerMovementEvent.Reset(_game, sender, _playerControl); + playerMovementEvent.Reset(Game, sender, _playerControl); await _eventManager.CallAsync(playerMovementEvent); _pool.Return(playerMovementEvent); } diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs index 80daa38f2..0f20750c6 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs @@ -17,14 +17,12 @@ internal partial class InnerPlayerPhysics : InnerNetObject private readonly ILogger _logger; private readonly InnerPlayerControl _playerControl; private readonly IEventManager _eventManager; - private readonly Game _game; - public InnerPlayerPhysics(ILogger logger, InnerPlayerControl playerControl, IEventManager eventManager, Game game) + public InnerPlayerPhysics(Game game, ILogger logger, InnerPlayerControl playerControl, IEventManager eventManager) : base(game) { _logger = logger; _playerControl = playerControl; _eventManager = eventManager; - _game = game; } public override ValueTask SerializeAsync(IMessageWriter writer, bool initialState) @@ -39,27 +37,39 @@ public override ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? public override async ValueTask HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) { - if (!await ValidateOwnership(call, sender) || !await ValidateImpostor(call, sender, _playerControl.PlayerInfo)) + if (!await ValidateOwnership(call, sender)) { return false; } - int ventId; - switch (call) { case RpcCalls.EnterVent: - Rpc19EnterVent.Deserialize(reader, out ventId); - await _eventManager.CallAsync(new PlayerVentEvent(_game, sender, _playerControl, (VentLocation)ventId, true)); - break; - case RpcCalls.ExitVent: - Rpc19EnterVent.Deserialize(reader, out ventId); - await _eventManager.CallAsync(new PlayerVentEvent(_game, sender, _playerControl, (VentLocation)ventId, false)); + if (!await ValidateImpostor(call, sender, _playerControl.PlayerInfo)) + { + return false; + } + + int ventId; + + switch (call) + { + case RpcCalls.EnterVent: + Rpc19EnterVent.Deserialize(reader, out ventId); + break; + case RpcCalls.ExitVent: + Rpc20ExitVent.Deserialize(reader, out ventId); + break; + default: + throw new ArgumentOutOfRangeException(nameof(call), call, null); + } + + await _eventManager.CallAsync(new PlayerVentEvent(Game, sender, _playerControl, (VentLocation)ventId, call == RpcCalls.EnterVent)); break; case RpcCalls.ClimbLadder: - Rpc31ClimbLadder.Deserialize(reader, out byte ladderId, out byte lastClimbLadderSid); + Rpc31ClimbLadder.Deserialize(reader, out var ladderId, out var lastClimbLadderSid); break; default: diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerVoteBanSystem.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerVoteBanSystem.cs index 3a310c88e..ac6304140 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerVoteBanSystem.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerVoteBanSystem.cs @@ -17,7 +17,7 @@ internal class InnerVoteBanSystem : InnerNetObject, IInnerVoteBanSystem private readonly ILogger _logger; private readonly Dictionary _votes; - public InnerVoteBanSystem(ILogger logger) + public InnerVoteBanSystem(Game game, ILogger logger) : base(game) { _logger = logger; _votes = new Dictionary(); diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs index bcbda030e..0a29d6378 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerGameData.cs @@ -18,17 +18,15 @@ namespace Impostor.Server.Net.Inner.Objects internal partial class InnerGameData : InnerNetObject, IInnerGameData { private readonly ILogger _logger; - private readonly Game _game; private readonly ConcurrentDictionary _allPlayers; - public InnerGameData(ILogger logger, Game game, IServiceProvider serviceProvider) + public InnerGameData(Game game, ILogger logger, IServiceProvider serviceProvider) : base(game) { _logger = logger; - _game = game; _allPlayers = new ConcurrentDictionary(); Components.Add(this); - Components.Add(ActivatorUtilities.CreateInstance(serviceProvider)); + Components.Add(ActivatorUtilities.CreateInstance(serviceProvider, game)); } public int PlayerCount => _allPlayers.Count; @@ -76,8 +74,25 @@ public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPl } else { - // It'll send an message per dirty player - // throw new NotImplementedException("This shouldn't happen, according to Among Us disassembly."); + while (reader.Position < reader.Length) + { + var inner = reader.ReadMessage(); + var playerInfo = this.GetPlayerById(inner.Tag); + if (playerInfo != null) + { + playerInfo.Deserialize(inner); + } + else + { + playerInfo = new InnerPlayerInfo(inner.Tag); + playerInfo.Deserialize(inner); + + if (!_allPlayers.TryAdd(playerInfo.PlayerId, playerInfo)) + { + throw new ImpostorException("Failed to add player to InnerGameData."); + } + } + } } } @@ -97,32 +112,6 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client break; } - case RpcCalls.UpdateGameData: - { - while (reader.Position < reader.Length) - { - using var message = reader.ReadMessage(); - var player = GetPlayerById(message.Tag); - if (player != null) - { - player.Deserialize(message); - } - else - { - var playerInfo = new InnerPlayerInfo(message.Tag); - - playerInfo.Deserialize(reader); - - if (!_allPlayers.TryAdd(playerInfo.PlayerId, playerInfo)) - { - throw new ImpostorException("Failed to add player to InnerGameData."); - } - } - } - - break; - } - default: return await UnregisteredCall(call, sender); } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs b/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs index 3a44fc525..c897a6860 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerLobbyBehaviour.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using Impostor.Api.Games; using Impostor.Api.Net; using Impostor.Api.Net.Inner; using Impostor.Api.Net.Inner.Objects; @@ -11,12 +10,8 @@ namespace Impostor.Server.Net.Inner.Objects { internal class InnerLobbyBehaviour : InnerNetObject, IInnerLobbyBehaviour { - private readonly IGame _game; - - public InnerLobbyBehaviour(IGame game) + public InnerLobbyBehaviour(Game game) : base(game) { - _game = game; - Components.Add(this); } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs index a40602836..f774cd0c0 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs @@ -20,18 +20,14 @@ internal partial class InnerMeetingHud : InnerNetObject { private readonly ILogger _logger; private readonly IEventManager _eventManager; - private readonly Game _game; - private readonly GameNet _gameNet; [AllowNull] private PlayerVoteArea[] _playerStates; - public InnerMeetingHud(ILogger logger, IEventManager eventManager, Game game) + public InnerMeetingHud(Game game, ILogger logger, IEventManager eventManager) : base(game) { _logger = logger; _eventManager = eventManager; - _game = game; - _gameNet = game.GameNet; _playerStates = null; Components.Add(this); @@ -132,7 +128,7 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client private void PopulateButtons(byte reporter) { - _playerStates = _gameNet.GameData!.Players + _playerStates = Game.GameNet.GameData!.Players .Select(x => { var area = new PlayerVoteArea(this, x.Key); @@ -146,15 +142,15 @@ private async ValueTask HandleVotingComplete(ClientPlayer sender, ReadOnlyMemory { if (playerId != byte.MaxValue) { - var player = _game.GameNet.GameData!.GetPlayerById(playerId); + 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)); + await _eventManager.CallAsync(new PlayerExileEvent(Game, sender, player.Controller)); } } - await _eventManager.CallAsync(new MeetingEndedEvent(_game, this)); + await _eventManager.CallAsync(new MeetingEndedEvent(Game, this)); } private async ValueTask HandleCastVote(ClientPlayer sender, ClientPlayer? target, byte playerId, sbyte suspectPlayerId) diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs index a2382e2be..8804bee90 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs @@ -22,52 +22,52 @@ public async ValueTask SetNameAsync(string name) { PlayerInfo.PlayerName = name; - using var writer = _game.StartRpc(NetId, RpcCalls.SetName); + using var writer = Game.StartRpc(NetId, RpcCalls.SetName); writer.Write(name); - await _game.FinishRpcAsync(writer); + await Game.FinishRpcAsync(writer); } public async ValueTask SetColorAsync(ColorType color) { PlayerInfo.Color = color; - using var writer = _game.StartRpc(NetId, RpcCalls.SetColor); + using var writer = Game.StartRpc(NetId, RpcCalls.SetColor); Rpc08SetColor.Serialize(writer, color); - await _game.FinishRpcAsync(writer); + await Game.FinishRpcAsync(writer); } public async ValueTask SetHatAsync(HatType hat) { PlayerInfo.Hat = hat; - using var writer = _game.StartRpc(NetId, RpcCalls.SetHat); + using var writer = Game.StartRpc(NetId, RpcCalls.SetHat); Rpc09SetHat.Serialize(writer, hat); - await _game.FinishRpcAsync(writer); + await Game.FinishRpcAsync(writer); } public async ValueTask SetPetAsync(PetType pet) { PlayerInfo.Pet = pet; - using var writer = _game.StartRpc(NetId, RpcCalls.SetPet); + using var writer = Game.StartRpc(NetId, RpcCalls.SetPet); Rpc17SetPet.Serialize(writer, pet); - await _game.FinishRpcAsync(writer); + await Game.FinishRpcAsync(writer); } public async ValueTask SetSkinAsync(SkinType skin) { PlayerInfo.Skin = skin; - using var writer = _game.StartRpc(NetId, RpcCalls.SetSkin); + using var writer = Game.StartRpc(NetId, RpcCalls.SetSkin); Rpc10SetSkin.Serialize(writer, skin); - await _game.FinishRpcAsync(writer); + await Game.FinishRpcAsync(writer); } public async ValueTask SendChatAsync(string text) { - using var writer = _game.StartRpc(NetId, RpcCalls.SendChat); + using var writer = Game.StartRpc(NetId, RpcCalls.SendChat); writer.Write(text); - await _game.FinishRpcAsync(writer); + await Game.FinishRpcAsync(writer); } public async ValueTask SendChatToPlayerAsync(string text, IInnerPlayerControl? player = null) @@ -77,9 +77,9 @@ public async ValueTask SendChatToPlayerAsync(string text, IInnerPlayerControl? p player = this; } - using var writer = _game.StartRpc(NetId, RpcCalls.SendChat); + using var writer = Game.StartRpc(NetId, RpcCalls.SendChat); writer.Write(text); - await _game.FinishRpcAsync(writer, player.OwnerId); + await Game.FinishRpcAsync(writer, player.OwnerId); } public async ValueTask MurderPlayerAsync(IInnerPlayerControl target) @@ -101,11 +101,11 @@ public async ValueTask MurderPlayerAsync(IInnerPlayerControl target) ((InnerPlayerControl)target).Die(DeathReason.Kill); - using var writer = _game.StartRpc(NetId, RpcCalls.MurderPlayer); + using var writer = Game.StartRpc(NetId, RpcCalls.MurderPlayer); Rpc12MurderPlayer.Serialize(writer, target); - await _game.FinishRpcAsync(writer); + 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() @@ -119,12 +119,12 @@ public async ValueTask ExileAsync() Die(DeathReason.Exile); // Send RPC. - using var writer = _game.StartRpc(NetId, RpcCalls.Exiled); + using var writer = Game.StartRpc(NetId, RpcCalls.Exiled); Rpc04Exiled.Serialize(writer); - await _game.FinishRpcAsync(writer); + 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 bf4ed8c5d..06191a18f 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs @@ -26,18 +26,16 @@ internal partial class InnerPlayerControl : InnerNetObject private readonly ILogger _logger; private readonly IEventManager _eventManager; - private readonly Game _game; private readonly IDateTimeProvider _dateTimeProvider; - public InnerPlayerControl(ILogger logger, IServiceProvider serviceProvider, IEventManager eventManager, Game game, IDateTimeProvider dateTimeProvider) + public InnerPlayerControl(Game game, ILogger logger, IServiceProvider serviceProvider, IEventManager eventManager, IDateTimeProvider dateTimeProvider) : base(game) { _logger = logger; _eventManager = eventManager; - _game = game; _dateTimeProvider = dateTimeProvider; - Physics = ActivatorUtilities.CreateInstance(serviceProvider, this, _eventManager, _game); - NetworkTransform = ActivatorUtilities.CreateInstance(serviceProvider, this, _game); + Physics = ActivatorUtilities.CreateInstance(serviceProvider, this, _eventManager, game); + NetworkTransform = ActivatorUtilities.CreateInstance(serviceProvider, this, game); Components.Add(this); Components.Add(Physics); @@ -115,7 +113,7 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client return false; } - Rpc02SyncSettings.Deserialize(reader, _game.Options); + Rpc02SyncSettings.Deserialize(reader, Game.Options); break; } @@ -215,7 +213,7 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client return false; } - Rpc12MurderPlayer.Deserialize(reader, _game, out var murdered); + Rpc12MurderPlayer.Deserialize(reader, Game, out var murdered); return await HandleMurderPlayer(sender, murdered); } @@ -317,7 +315,7 @@ private async ValueTask HandleCompleteTask(ClientPlayer sender, uint taskId) if (task != null) { task.Complete = true; - await _eventManager.CallAsync(new PlayerCompletedTaskEvent(_game, sender, this, task)); + await _eventManager.CallAsync(new PlayerCompletedTaskEvent(Game, sender, this, task)); } else { @@ -329,16 +327,16 @@ private async ValueTask HandleSetInfected(ReadOnlyMemory infectedIds) { 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; } } - if (_game.GameState == GameStates.Starting) + if (Game.GameState == GameStates.Starting) { - await _game.StartedAsync(); + await Game.StartedAsync(); } } @@ -375,7 +373,7 @@ private async ValueTask HandleCheckName(ClientPlayer sender, string name) private async ValueTask HandleSetName(ClientPlayer sender, string name) { - if (_game.GameState == GameStates.Started) + if (Game.GameState == GameStates.Started) { if (await sender.Client.ReportCheatAsync(RpcCalls.SetColor, "Client tried to set a name midgame")) { @@ -385,7 +383,7 @@ private async ValueTask HandleSetName(ClientPlayer sender, string name) if (sender.IsOwner(this)) { - if (_game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.PlayerName == name)) + if (Game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.PlayerName == name)) { if (await sender.Client.ReportCheatAsync(RpcCalls.SetName, "Client sent name that is already used")) { @@ -411,14 +409,14 @@ private async ValueTask HandleSetName(ClientPlayer sender, string name) var expected = RequestedPlayerName.Dequeue(); - if (_game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.PlayerName == expected)) + if (Game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.PlayerName == expected)) { var i = 1; while (true) { string text = expected + " " + i; - if (_game.Players.All(x => x.Character == null || x.Character == this || x.Character.PlayerInfo.PlayerName != text)) + if (Game.Players.All(x => x.Character == null || x.Character == this || x.Character.PlayerInfo.PlayerName != text)) { expected = text; break; @@ -458,7 +456,7 @@ private async ValueTask HandleCheckColor(ClientPlayer sender, ColorType co private async ValueTask HandleSetColor(ClientPlayer sender, ColorType color) { - if (_game.GameState == GameStates.Started) + if (Game.GameState == GameStates.Started) { if (await sender.Client.ReportCheatAsync(RpcCalls.SetColor, "Client tried to set a color midgame")) { @@ -468,7 +466,7 @@ private async ValueTask HandleSetColor(ClientPlayer sender, ColorType colo if (sender.IsOwner(this)) { - if (_game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.Color == color)) + if (Game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.Color == color)) { if (await sender.Client.ReportCheatAsync(RpcCalls.SetColor, "Client sent a color that is already used")) { @@ -486,7 +484,7 @@ private async ValueTask HandleSetColor(ClientPlayer sender, ColorType colo var expected = RequestedColorId.Dequeue(); - while (_game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.Color == expected)) + while (Game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.Color == expected)) { expected = (ColorType)(((byte)expected + 1) % ColorsCount); } @@ -506,7 +504,7 @@ private async ValueTask HandleSetColor(ClientPlayer sender, ColorType colo private async ValueTask HandleSetHat(ClientPlayer sender, HatType hat) { - if (_game.GameState == GameStates.Started && await sender.Client.ReportCheatAsync(RpcCalls.SetHat, "Client tried to change hat while not in lobby")) + if (Game.GameState == GameStates.Started && await sender.Client.ReportCheatAsync(RpcCalls.SetHat, "Client tried to change hat while not in lobby")) { return false; } @@ -518,7 +516,7 @@ private async ValueTask HandleSetHat(ClientPlayer sender, HatType hat) private async ValueTask HandleSetSkin(ClientPlayer sender, SkinType skin) { - if (_game.GameState == GameStates.Started && await sender.Client.ReportCheatAsync(RpcCalls.SetSkin, "Client tried to change skin while not in lobby")) + if (Game.GameState == GameStates.Started && await sender.Client.ReportCheatAsync(RpcCalls.SetSkin, "Client tried to change skin while not in lobby")) { return false; } @@ -530,7 +528,7 @@ private async ValueTask HandleSetSkin(ClientPlayer sender, SkinType skin) private async ValueTask HandleMurderPlayer(ClientPlayer sender, IInnerPlayerControl? target) { - if (!PlayerInfo.CanMurder(_game, _dateTimeProvider)) + if (!PlayerInfo.CanMurder(Game, _dateTimeProvider)) { if (await sender.Client.ReportCheatAsync(RpcCalls.MurderPlayer, "Client tried to murder too fast")) { @@ -551,7 +549,7 @@ private async ValueTask HandleMurderPlayer(ClientPlayer sender, IInnerPlay if (target != null && !target.PlayerInfo.IsDead) { ((InnerPlayerControl)target).Die(DeathReason.Kill); - await _eventManager.CallAsync(new PlayerMurderEvent(_game, sender, this, target)); + await _eventManager.CallAsync(new PlayerMurderEvent(Game, sender, this, target)); } return true; @@ -559,7 +557,7 @@ private async ValueTask HandleMurderPlayer(ClientPlayer sender, IInnerPlay private async ValueTask HandleSendChat(ClientPlayer sender, string message) { - var @event = new PlayerChatEvent(_game, sender, this, message); + var @event = new PlayerChatEvent(Game, sender, this, message); await _eventManager.CallAsync(@event); return !@event.IsCancelled; @@ -567,13 +565,13 @@ private async ValueTask HandleSendChat(ClientPlayer sender, string message 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) { - if (_game.GameState == GameStates.Started && await sender.Client.ReportCheatAsync(RpcCalls.SetPet, "Client tried to change pet while not in lobby")) + if (Game.GameState == GameStates.Started && await sender.Client.ReportCheatAsync(RpcCalls.SetPet, "Client tried to change pet while not in lobby")) { return false; } @@ -595,7 +593,7 @@ private async ValueTask HandleSetStartCounter(ClientPlayer sender, int seq if (startCounter != -1) { - await _eventManager.CallAsync(new PlayerSetStartCounterEvent(_game, sender, this, (byte)startCounter)); + await _eventManager.CallAsync(new PlayerSetStartCounterEvent(Game, sender, this, (byte)startCounter)); } return true; diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs index 1d488fbdc..763782a32 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs @@ -59,15 +59,23 @@ public void Serialize(IMessageWriter writer) public void Deserialize(IMessageReader reader) { PlayerName = reader.ReadString(); - Color = (ColorType)reader.ReadByte(); + Color = (ColorType)reader.ReadPackedInt32(); Hat = (HatType)reader.ReadPackedUInt32(); Pet = (PetType)reader.ReadPackedUInt32(); Skin = (SkinType)reader.ReadPackedUInt32(); + var flag = reader.ReadByte(); Disconnected = (flag & 1) > 0; IsImpostor = (flag & 2) > 0; IsDead = (flag & 4) > 0; + var taskCount = reader.ReadByte(); + + if (Tasks.Count != taskCount) + { + Tasks = new List(taskCount); + } + for (var i = 0; i < taskCount; i++) { Tasks[i] ??= new InnerGameData.TaskInfo(); diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs new file mode 100644 index 000000000..8776a8c49 --- /dev/null +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using Impostor.Api.Innersloth; +using Impostor.Api.Net.Inner.Objects.ShipStatus; +using Impostor.Server.Net.Inner.Objects.Systems; +using Impostor.Server.Net.Inner.Objects.Systems.ShipStatus; +using Impostor.Server.Net.State; + +namespace Impostor.Server.Net.Inner.Objects.ShipStatus +{ + internal class InnerAirshipStatus : InnerShipStatus, IInnerAirshipStatus + { + public InnerAirshipStatus(Game game) : base(game) + { + } + + public override Dictionary Doors { get; } = new Dictionary(21); + + protected override void AddSystems(Dictionary systems) + { + base.AddSystems(systems); + + systems.Add(SystemTypes.Doors, new DoorsSystemType(Doors)); + systems.Add(SystemTypes.Comms, new HudOverrideSystemType()); + systems.Add(SystemTypes.GapRoom, new MovingPlatformBehaviour()); + systems.Add(SystemTypes.Reactor, new HeliSabotageSystemType()); + systems.Add(SystemTypes.Decontamination, new ElectricalDoors(Doors)); + systems.Add(SystemTypes.Decontamination2, new AutoDoorsSystemType(Doors)); + systems.Add(SystemTypes.Security, new SecurityCameraSystemType()); + } + } +} diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs new file mode 100644 index 000000000..04d033fb1 --- /dev/null +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Impostor.Api.Innersloth; +using Impostor.Api.Net.Inner.Objects.ShipStatus; +using Impostor.Server.Net.Inner.Objects.Systems; +using Impostor.Server.Net.Inner.Objects.Systems.ShipStatus; +using Impostor.Server.Net.State; + +namespace Impostor.Server.Net.Inner.Objects.ShipStatus +{ + internal class InnerMiraShipStatus : InnerShipStatus, IInnerMiraShipStatus + { + public InnerMiraShipStatus(Game game) : base(game) + { + } + + public override Dictionary Doors { get; } = new Dictionary(0); + + protected override void AddSystems(Dictionary systems) + { + base.AddSystems(systems); + + systems.Add(SystemTypes.Comms, new HudOverrideSystemType()); + systems.Add(SystemTypes.Reactor, new ReactorSystemType()); + systems.Add(SystemTypes.LifeSupp, new LifeSuppSystemType()); + } + } +} diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs new file mode 100644 index 000000000..7ec077d28 --- /dev/null +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using Impostor.Api.Innersloth; +using Impostor.Api.Net.Inner.Objects.ShipStatus; +using Impostor.Server.Net.Inner.Objects.Systems; +using Impostor.Server.Net.Inner.Objects.Systems.ShipStatus; +using Impostor.Server.Net.State; + +namespace Impostor.Server.Net.Inner.Objects.ShipStatus +{ + internal class InnerPolusShipStatus : InnerShipStatus, IInnerPolusShipStatus + { + public InnerPolusShipStatus(Game game) : base(game) + { + } + + public override Dictionary Doors { get; } = new Dictionary(12); + + protected override void AddSystems(Dictionary systems) + { + base.AddSystems(systems); + + systems.Add(SystemTypes.Doors, new DoorsSystemType(Doors)); + systems.Add(SystemTypes.Comms, new HudOverrideSystemType()); + systems.Add(SystemTypes.Security, new SecurityCameraSystemType()); + systems.Add(SystemTypes.Laboratory, new ReactorSystemType()); + } + } +} diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs similarity index 62% rename from src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs rename to src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs index dd8b511f7..418adef34 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs @@ -1,48 +1,42 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Impostor.Api; using Impostor.Api.Innersloth; using Impostor.Api.Net; using Impostor.Api.Net.Inner; -using Impostor.Api.Net.Inner.Objects; +using Impostor.Api.Net.Inner.Objects.ShipStatus; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.Rpcs; using Impostor.Server.Net.Inner.Objects.Systems; using Impostor.Server.Net.Inner.Objects.Systems.ShipStatus; using Impostor.Server.Net.State; -using Microsoft.Extensions.Logging; -namespace Impostor.Server.Net.Inner.Objects +namespace Impostor.Server.Net.Inner.Objects.ShipStatus { - internal class InnerShipStatus : InnerNetObject, IInnerShipStatus + internal abstract class InnerShipStatus : InnerNetObject, IInnerShipStatus { - private readonly ILogger _logger; - private readonly Game _game; - private readonly Dictionary _systems; + private readonly Dictionary _systems = new Dictionary(); - public InnerShipStatus(ILogger logger, Game game) + protected InnerShipStatus(Game game) : base(game) { - _logger = logger; - _game = game; + Components.Add(this); + } - _systems = new Dictionary - { - [SystemTypes.Electrical] = new SwitchSystem(), - [SystemTypes.MedBay] = new MedScanSystem(), - [SystemTypes.Reactor] = game.Options.Map == MapTypes.Airship ? new HeliSabotageSystemType() : new ReactorSystemType(), - [SystemTypes.LifeSupp] = new LifeSuppSystemType(), - [SystemTypes.Security] = new SecurityCameraSystemType(), - [SystemTypes.Comms] = new HudOverrideSystemType(), - [SystemTypes.Doors] = new DoorsSystemType(_game), - }; - - _systems.Add(SystemTypes.Sabotage, new SabotageSystemType(new[] + public abstract Dictionary Doors { get; } + + public override ValueTask OnSpawnAsync() + { + for (var i = 0; i < Doors.Count; i++) { - (IActivatable)_systems[SystemTypes.Comms], (IActivatable)_systems[SystemTypes.Reactor], (IActivatable)_systems[SystemTypes.LifeSupp], (IActivatable)_systems[SystemTypes.Electrical], - })); + Doors.Add(i, false); + } - Components.Add(this); + AddSystems(_systems); + _systems.Add(SystemTypes.Sabotage, new SabotageSystemType(_systems.Values.OfType().ToArray())); + + return base.OnSpawnAsync(); } public override ValueTask SerializeAsync(IMessageWriter writer, bool initialState) @@ -59,8 +53,8 @@ public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPl while (reader.Position < reader.Length) { - IMessageReader messageReader = reader.ReadMessage(); - SystemTypes type = (SystemTypes)messageReader.Tag; + var messageReader = reader.ReadMessage(); + var type = (SystemTypes)messageReader.Tag; if (_systems.TryGetValue(type, out var value)) { value.Deserialize(messageReader, initialState); @@ -90,7 +84,7 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client case RpcCalls.RepairSystem: { - Rpc28RepairSystem.Deserialize(reader, _game, out var systemType, out var player, out var amount); + Rpc28RepairSystem.Deserialize(reader, Game, out var systemType, out var player, out var amount); if (systemType == SystemTypes.Sabotage && !await ValidateImpostor(call, sender, sender.Character!.PlayerInfo)) { @@ -106,5 +100,11 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client return true; } + + protected virtual void AddSystems(Dictionary systems) + { + systems.Add(SystemTypes.Electrical, new SwitchSystem()); + systems.Add(SystemTypes.MedBay, new MedScanSystem()); + } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs new file mode 100644 index 000000000..12df2f354 --- /dev/null +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using Impostor.Api.Innersloth; +using Impostor.Api.Net.Inner.Objects.ShipStatus; +using Impostor.Server.Net.Inner.Objects.Systems; +using Impostor.Server.Net.Inner.Objects.Systems.ShipStatus; +using Impostor.Server.Net.State; + +namespace Impostor.Server.Net.Inner.Objects.ShipStatus +{ + internal class InnerSkeldShipStatus : InnerShipStatus, IInnerSkeldShipStatus + { + public InnerSkeldShipStatus(Game game) : base(game) + { + } + + public override Dictionary Doors { get; } = new Dictionary(13); + + protected override void AddSystems(Dictionary systems) + { + base.AddSystems(systems); + + systems.Add(SystemTypes.Doors, new AutoDoorsSystemType(Doors)); + systems.Add(SystemTypes.Comms, new HudOverrideSystemType()); + systems.Add(SystemTypes.Security, new SecurityCameraSystemType()); + systems.Add(SystemTypes.Reactor, new ReactorSystemType()); + systems.Add(SystemTypes.LifeSupp, new LifeSuppSystemType()); + } + } +} diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/AutoDoorsSystemType.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/AutoDoorsSystemType.cs new file mode 100644 index 000000000..5a1457508 --- /dev/null +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/AutoDoorsSystemType.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using Impostor.Api.Net.Messages; + +namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus +{ + public class AutoDoorsSystemType : ISystemType + { + private readonly Dictionary _doors; + + public AutoDoorsSystemType(Dictionary doors) + { + _doors = doors; + } + + public void Serialize(IMessageWriter writer, bool initialState) + { + throw new NotImplementedException(); + } + + public void Deserialize(IMessageReader reader, bool initialState) + { + if (initialState) + { + for (var i = 0; i < _doors.Count; i++) + { + _doors[i] = reader.ReadBoolean(); + } + } + else + { + var num = reader.ReadPackedUInt32(); + + for (var i = 0; i < _doors.Count; i++) + { + if ((num & 1 << i) != 0) + { + _doors[i] = reader.ReadBoolean(); + } + } + } + } + } +} 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 03ba1df92..2bc71301b 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/DoorsSystemType.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/DoorsSystemType.cs @@ -1,6 +1,5 @@ -using System; +using System; using System.Collections.Generic; -using Impostor.Api.Games; using Impostor.Api.Innersloth; using Impostor.Api.Net.Messages; @@ -8,26 +7,12 @@ namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus { public class DoorsSystemType : ISystemType { - // TODO: AutoDoors + private readonly Dictionary _timers = new Dictionary(); private readonly Dictionary _doors; - public DoorsSystemType(IGame game) + public DoorsSystemType(Dictionary doors) { - var doorCount = game.Options.Map switch - { - MapTypes.Skeld => 13, - MapTypes.MiraHQ => 2, - MapTypes.Polus => 12, - MapTypes.Airship => 21, // TODO do the toilet doors count? 21 yes, 17 no - _ => throw new ArgumentOutOfRangeException(), - }; - - _doors = new Dictionary(doorCount); - - for (var i = 0; i < doorCount; i++) - { - _doors.Add(i, false); - } + _doors = doors; } public void Serialize(IMessageWriter writer, bool initialState) @@ -37,24 +22,18 @@ public void Serialize(IMessageWriter writer, bool initialState) public void Deserialize(IMessageReader reader, bool initialState) { - if (initialState) + var num = reader.ReadByte(); + for (var i = 0; i < num; i++) { - for (var i = 0; i < _doors.Count; i++) - { - _doors[i] = reader.ReadBoolean(); - } + var systemType = (SystemTypes)reader.ReadByte(); + var value = reader.ReadSingle(); + + _timers[systemType] = value; } - else - { - var num = reader.ReadPackedUInt32(); - for (var i = 0; i < _doors.Count; i++) - { - if ((num & 1 << i) != 0) - { - _doors[i] = reader.ReadBoolean(); - } - } + for (var j = 0; j < _doors.Count; j++) + { + _doors[j] = reader.ReadBoolean(); } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/ElectricalDoors.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/ElectricalDoors.cs new file mode 100644 index 000000000..cadb995ca --- /dev/null +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/ElectricalDoors.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using Impostor.Api.Net.Messages; + +namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus +{ + public class ElectricalDoors : ISystemType + { + private readonly Dictionary _doors; + + public ElectricalDoors(Dictionary doors) + { + _doors = doors; + } + + public void Serialize(IMessageWriter writer, bool initialState) + { + throw new NotImplementedException(); + } + + public void Deserialize(IMessageReader reader, bool initialState) + { + var num = reader.ReadUInt32(); + for (var i = 0; i < _doors.Count; i++) + { + _doors[i] = (num & (ulong)(1L << (i & 31))) > 0UL; + } + } + } +} diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs index 1d6be3206..d72ed5b63 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/HeliSabotageSystemType.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using Impostor.Api.Net.Messages; -using Microsoft.Extensions.Logging; namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus { diff --git a/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/MovingPlatformBehaviour.cs b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/MovingPlatformBehaviour.cs new file mode 100644 index 000000000..82cfb1fbd --- /dev/null +++ b/src/Impostor.Server/Net/Inner/Objects/Systems/ShipStatus/MovingPlatformBehaviour.cs @@ -0,0 +1,22 @@ +using System; +using Impostor.Api.Net.Messages; + +namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus +{ + public class MovingPlatformBehaviour : ISystemType, IActivatable + { + public bool IsActive { get; private set; } + + public void Serialize(IMessageWriter writer, bool initialState) + { + throw new NotImplementedException(); + } + + public void Deserialize(IMessageReader reader, bool initialState) + { + var sid = reader.ReadByte(); + var targetId = reader.ReadUInt32(); + var isLeft = reader.ReadBoolean(); + } + } +} diff --git a/src/Impostor.Server/Net/State/Game.Api.cs b/src/Impostor.Server/Net/State/Game.Api.cs index 44257e763..a35858568 100644 --- a/src/Impostor.Server/Net/State/Game.Api.cs +++ b/src/Impostor.Server/Net/State/Game.Api.cs @@ -8,7 +8,6 @@ using Impostor.Api.Net.Inner; using Impostor.Api.Net.Messages; using Impostor.Hazel; -using Impostor.Server.Net.Inner; namespace Impostor.Server.Net.State { diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index e69147086..74b3c7bba 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -10,6 +10,7 @@ using Impostor.Server.Net.Inner; using Impostor.Server.Net.Inner.Objects; using Impostor.Server.Net.Inner.Objects.Components; +using Impostor.Server.Net.Inner.Objects.ShipStatus; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -32,15 +33,15 @@ internal partial class Game private static readonly Type[] SpawnableObjects = { - typeof(InnerShipStatus), // ShipStatus + typeof(InnerSkeldShipStatus), typeof(InnerMeetingHud), typeof(InnerLobbyBehaviour), typeof(InnerGameData), typeof(InnerPlayerControl), - typeof(InnerShipStatus), // HeadQuarters - typeof(InnerShipStatus), // PlanetMap - typeof(InnerShipStatus), // AprilShipStatus - typeof(InnerShipStatus), // Airship + typeof(InnerMiraShipStatus), + typeof(InnerPolusShipStatus), + typeof(InnerSkeldShipStatus), // April fools skeld + typeof(InnerAirshipStatus), }; private readonly List _allObjects = new List(); @@ -349,6 +350,8 @@ private async ValueTask OnSpawnAsync(InnerNetObject netObj) break; } } + + await netObj.OnSpawnAsync(); } private async ValueTask OnDestroyAsync(InnerNetObject netObj) diff --git a/src/Impostor.Server/Net/State/GameNet.Api.cs b/src/Impostor.Server/Net/State/GameNet.Api.cs index 4fed52763..3af856ce4 100644 --- a/src/Impostor.Server/Net/State/GameNet.Api.cs +++ b/src/Impostor.Server/Net/State/GameNet.Api.cs @@ -1,5 +1,6 @@ using Impostor.Api.Net.Inner; using Impostor.Api.Net.Inner.Objects; +using Impostor.Api.Net.Inner.Objects.ShipStatus; namespace Impostor.Server.Net.State { diff --git a/src/Impostor.Server/Net/State/GameNet.cs b/src/Impostor.Server/Net/State/GameNet.cs index 37e0cbd91..bb7a8e253 100644 --- a/src/Impostor.Server/Net/State/GameNet.cs +++ b/src/Impostor.Server/Net/State/GameNet.cs @@ -1,5 +1,6 @@ using Impostor.Server.Net.Inner.Objects; using Impostor.Server.Net.Inner.Objects.Components; +using Impostor.Server.Net.Inner.Objects.ShipStatus; namespace Impostor.Server.Net.State { From 4866a350f86b402f5af3d9f1df7cb7a081c0f076 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 4 Apr 2021 23:27:10 +0200 Subject: [PATCH 57/72] Implement airship spawning, closes #376 --- src/Impostor.Api/Innersloth/MapSpawn.cs | 46 ------------------- .../Components/InnerCustomNetworkTransform.cs | 39 +++++++++++++++- .../Objects/ShipStatus/InnerAirshipStatus.cs | 25 ++++++++++ .../Objects/ShipStatus/InnerMiraShipStatus.cs | 7 +++ .../ShipStatus/InnerPolusShipStatus.cs | 29 ++++++++++++ .../Objects/ShipStatus/InnerShipStatus.cs | 24 ++++++++++ .../ShipStatus/InnerSkeldShipStatus.cs | 7 +++ src/Impostor.Server/Net/State/Game.Data.cs | 5 ++ src/Impostor.Server/Net/State/Game.cs | 6 +-- 9 files changed, 137 insertions(+), 51 deletions(-) delete mode 100644 src/Impostor.Api/Innersloth/MapSpawn.cs diff --git a/src/Impostor.Api/Innersloth/MapSpawn.cs b/src/Impostor.Api/Innersloth/MapSpawn.cs deleted file mode 100644 index 3f59f0a8f..000000000 --- a/src/Impostor.Api/Innersloth/MapSpawn.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Numerics; - -namespace Impostor.Api.Innersloth -{ - public class MapSpawn - { - private MapSpawn(float spawnRadius, Vector2 initialSpawnCenter, Vector2 meetingSpawnCenter) - { - SpawnRadius = spawnRadius; - InitialSpawnCenter = initialSpawnCenter; - MeetingSpawnCenter = meetingSpawnCenter; - } - - public static Dictionary Maps { get; } = new Dictionary - { - [MapTypes.Skeld] = new MapSpawn(1.6f, new Vector2(-0.72f, 0.62f), new Vector2(-0.72f, 0.62f)), - [MapTypes.MiraHQ] = new MapSpawn(1.55f, new Vector2(-4.4f, 2.2f), new Vector2(24.043f, 1.72f)), - [MapTypes.Polus] = new MapSpawn(1f, new Vector2(16.64f, -2.46f), new Vector2(17.726f, -16.286f)), - [MapTypes.Airship] = new MapSpawn(0f, new Vector2(-0.66f, -0.5f), new Vector2(-0.66f, -0.5f)), - }; - - public float SpawnRadius { get; } - - public Vector2 InitialSpawnCenter { get; } - - public Vector2 MeetingSpawnCenter { get; } - - public Vector2 GetSpawnLocation(int playerId, int numPlayer, bool initialSpawn) - { - var vector = new Vector2(0, 1); - vector = Rotate(vector, (playerId - 1) * (360f / numPlayer)); - vector *= this.SpawnRadius; - return (initialSpawn ? this.InitialSpawnCenter : this.MeetingSpawnCenter) + vector + new Vector2(0f, 0.3636f); - } - - private static Vector2 Rotate(Vector2 self, float degrees) - { - var f = 0.017453292f * degrees; - var num = (float)Math.Cos(f); - var num2 = (float)Math.Sin(f); - return new Vector2((self.X * num) - (num2 * self.Y), (self.X * num2) + (num * self.Y)); - } - } -} diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs index d1a48a3a0..5df6b8a98 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs @@ -1,4 +1,5 @@ -using System.Numerics; +using System.Linq; +using System.Numerics; using System.Threading.Tasks; using Impostor.Api; using Impostor.Api.Events.Managers; @@ -7,6 +8,7 @@ using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.Rpcs; using Impostor.Server.Events.Player; +using Impostor.Server.Net.Inner.Objects.ShipStatus; using Impostor.Server.Net.State; using Microsoft.Extensions.Logging; using Microsoft.Extensions.ObjectPool; @@ -21,6 +23,7 @@ internal partial class InnerCustomNetworkTransform : InnerNetObject private readonly ObjectPool _pool; private ushort _lastSequenceId; + private bool _spawnSnapAllowed; public InnerCustomNetworkTransform(Game game, ILogger logger, InnerPlayerControl playerControl, IEventManager eventManager, ObjectPool pool) : base(game) { @@ -83,13 +86,34 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client { if (call == RpcCalls.SnapTo) { - if (!await ValidateOwnership(call, sender) || !await ValidateImpostor(call, sender, _playerControl.PlayerInfo)) + if (!await ValidateOwnership(call, sender)) { return false; } Rpc21SnapTo.Deserialize(reader, out var position, out var minSid); + if (Game.GameNet.ShipStatus is InnerAirshipStatus airshipStatus) + { + // As part of airship spawning, clients are sending snap to -25 40 for no reason(?), cancelling it works just fine + if (Approximately(position, airshipStatus.PreSpawnLocation)) + { + return false; + } + + if (_spawnSnapAllowed && airshipStatus.SpawnLocations.Any(location => Approximately(position, location))) + { + _spawnSnapAllowed = false; + return true; + } + } + + if (!await ValidateImpostor(call, sender, _playerControl.PlayerInfo)) + { + return false; + } + + // TODO validate vent location await SnapToAsync(sender, position, minSid); return true; } @@ -108,6 +132,11 @@ internal async ValueTask SetPositionAsync(IClientPlayer sender, Vector2 position _pool.Return(playerMovementEvent); } + internal void OnPlayerSpawn() + { + _spawnSnapAllowed = true; + } + private static bool SidGreaterThan(ushort newSid, ushort prevSid) { var num = (ushort)(prevSid + (uint)short.MaxValue); @@ -117,6 +146,12 @@ private static bool SidGreaterThan(ushort newSid, ushort prevSid) : newSid > prevSid || newSid <= num; } + private static bool Approximately(Vector2 a, Vector2 b, float tolerance = 0.1f) + { + var abs = Vector2.Abs(a - b); + return abs.X <= tolerance && abs.Y <= tolerance; + } + private ValueTask SnapToAsync(IClientPlayer sender, Vector2 position, ushort minSid) { if (!SidGreaterThan(minSid, _lastSequenceId)) diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs index 8776a8c49..7f8562809 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs @@ -1,4 +1,6 @@ +using System; using System.Collections.Generic; +using System.Numerics; using Impostor.Api.Innersloth; using Impostor.Api.Net.Inner.Objects.ShipStatus; using Impostor.Server.Net.Inner.Objects.Systems; @@ -15,6 +17,29 @@ public InnerAirshipStatus(Game game) : base(game) public override Dictionary Doors { get; } = new Dictionary(21); + public override float SpawnRadius => throw new NotSupportedException(); + + public override Vector2 InitialSpawnCenter => throw new NotSupportedException(); + + public override Vector2 MeetingSpawnCenter => throw new NotSupportedException(); + + public Vector2 PreSpawnLocation { get; } = new Vector2(-25f, 40f); + + public Vector2[] SpawnLocations { get; } = + { + new Vector2(-0.7f, 8.5f), // Brig + new Vector2(-0.7f, -1.0f), // Engine + new Vector2(15.5f, 0.0f), // MainHall + new Vector2(-7.0f, -11.5f), // Kitchen + new Vector2(20.0f, 10.5f), // Records + new Vector2(33.5f, -1.5f), // CargoBay + }; + + public override Vector2 GetSpawnLocation(InnerPlayerControl player, int numPlayers, bool initialSpawn) + { + return new Vector2(-25, 40); + } + protected override void AddSystems(Dictionary systems) { base.AddSystems(systems); diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs index 04d033fb1..02daf3160 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Numerics; using Impostor.Api.Innersloth; using Impostor.Api.Net.Inner.Objects.ShipStatus; using Impostor.Server.Net.Inner.Objects.Systems; @@ -15,6 +16,12 @@ public InnerMiraShipStatus(Game game) : base(game) public override Dictionary Doors { get; } = new Dictionary(0); + public override float SpawnRadius => 1.55f; + + public override Vector2 InitialSpawnCenter { get; } = new Vector2(-4.4f, 2.2f); + + public override Vector2 MeetingSpawnCenter { get; } = new Vector2(24.043f, 1.72f); + protected override void AddSystems(Dictionary systems) { base.AddSystems(systems); diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs index 7ec077d28..262b313b8 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Numerics; using Impostor.Api.Innersloth; using Impostor.Api.Net.Inner.Objects.ShipStatus; using Impostor.Server.Net.Inner.Objects.Systems; @@ -15,6 +16,34 @@ public InnerPolusShipStatus(Game game) : base(game) public override Dictionary Doors { get; } = new Dictionary(12); + public override float SpawnRadius => 1f; + + public override Vector2 InitialSpawnCenter { get; } = new Vector2(16.64f, -2.46f); + + public override Vector2 MeetingSpawnCenter { get; } = new Vector2(17.726f, -16.286f); + + public Vector2 MeetingSpawnCenter2 { get; } = new Vector2(-17.7f, -17.5f); + + public override Vector2 GetSpawnLocation(InnerPlayerControl player, int numPlayers, bool initialSpawn) + { + if (initialSpawn) + { + return base.GetSpawnLocation(player, numPlayers, initialSpawn); + } + + Vector2 position; + if (player.PlayerId < 5) + { + position = this.MeetingSpawnCenter + (new Vector2(1, 0) * player.PlayerId); + } + else + { + position = this.MeetingSpawnCenter2 + (new Vector2(1, 0) * (player.PlayerId - 5)); + } + + return position; + } + protected override void AddSystems(Dictionary systems) { base.AddSystems(systems); diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs index 418adef34..dcfa24f08 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Numerics; using System.Threading.Tasks; using Impostor.Api; using Impostor.Api.Innersloth; @@ -26,6 +27,12 @@ protected InnerShipStatus(Game game) : base(game) public abstract Dictionary Doors { get; } + public abstract float SpawnRadius { get; } + + public abstract Vector2 InitialSpawnCenter { get; } + + public abstract Vector2 MeetingSpawnCenter { get; } + public override ValueTask OnSpawnAsync() { for (var i = 0; i < Doors.Count; i++) @@ -101,10 +108,27 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client return true; } + public virtual Vector2 GetSpawnLocation(InnerPlayerControl player, int numPlayers, bool initialSpawn) + { + var vector = new Vector2(0, 1); + vector = Rotate(vector, (player.PlayerId - 1) * (360f / numPlayers)); + vector *= this.SpawnRadius; + return (initialSpawn ? this.InitialSpawnCenter : this.MeetingSpawnCenter) + vector + new Vector2(0f, 0.3636f); + } + protected virtual void AddSystems(Dictionary systems) { systems.Add(SystemTypes.Electrical, new SwitchSystem()); systems.Add(SystemTypes.MedBay, new MedScanSystem()); } + + private static Vector2 Rotate(Vector2 self, float degrees) + { + var f = 0.017453292f * degrees; + var cos = MathF.Cos(f); + var sin = MathF.Sin(f); + + return new Vector2((self.X * cos) - (sin * self.Y), (self.X * sin) + (cos * self.Y)); + } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs index 12df2f354..9580b7be4 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Numerics; using Impostor.Api.Innersloth; using Impostor.Api.Net.Inner.Objects.ShipStatus; using Impostor.Server.Net.Inner.Objects.Systems; @@ -15,6 +16,12 @@ public InnerSkeldShipStatus(Game game) : base(game) public override Dictionary Doors { get; } = new Dictionary(13); + public override float SpawnRadius => 1.6f; + + public override Vector2 InitialSpawnCenter { get; } = new Vector2(-0.72f, 0.62f); + + public override Vector2 MeetingSpawnCenter { get; } = new Vector2(-0.72f, 0.62f); + protected override void AddSystems(Dictionary systems) { base.AddSystems(systems); diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index 74b3c7bba..9a09c1b77 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -346,6 +346,11 @@ private async ValueTask OnSpawnAsync(InnerNetObject netObj) case InnerMeetingHud meetingHud: { + foreach (var player in _players.Values) + { + player.Character?.NetworkTransform.OnPlayerSpawn(); + } + await _eventManager.CallAsync(new MeetingStartedEvent(this, meetingHud)); break; } diff --git a/src/Impostor.Server/Net/State/Game.cs b/src/Impostor.Server/Net/State/Game.cs index 823c049f4..20f6c01b2 100644 --- a/src/Impostor.Server/Net/State/Game.cs +++ b/src/Impostor.Server/Net/State/Game.cs @@ -105,10 +105,10 @@ internal async ValueTask StartedAsync() { if (GameState == GameStates.Starting) { - for (var i = 0; i < _players.Values.Count; i++) + foreach (var player in _players.Values) { - var player = _players.Values.ElementAt(i); - await player.Character!.NetworkTransform.SetPositionAsync(player, MapSpawn.Maps[Options.Map].GetSpawnLocation(i, PlayerCount, true), Vector2.Zero); + player.Character?.NetworkTransform.OnPlayerSpawn(); + await player.Character!.NetworkTransform.SetPositionAsync(player, GameNet.ShipStatus!.GetSpawnLocation(player.Character, PlayerCount, true), Vector2.Zero); } GameState = GameStates.Started; From 0a30fe5a3e69a242112875b677b109fc838dc0f4 Mon Sep 17 00:00:00 2001 From: js6pak Date: Mon, 5 Apr 2021 15:27:25 +0200 Subject: [PATCH 58/72] Bring back tar.gz for unix builds --- appveyor.yml | 1 + build.cake | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index ca2bc2cb6..ce3b999ae 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -30,6 +30,7 @@ test: off artifacts: - path: ./build/*.zip + - path: ./build/*.tar.gz - path: ./build/*.nupkg - path: ./build/*.snupkg diff --git a/build.cake b/build.cake index 25a5e17b3..d274c0bde 100644 --- a/build.cake +++ b/build.cake @@ -52,7 +52,11 @@ private void ImpostorPublish(string name, string project, string runtime, bool i } } - Zip(projBuildDir, buildDir.CombineWithFilePath(projBuildName + ".zip")); + if (runtime == "win-x64") { + Zip(projBuildDir, buildDir.CombineWithFilePath(projBuildName + ".zip")); + } else { + GZipCompress(projBuildDir, buildDir.CombineWithFilePath(projBuildName + ".tar.gz")); + } } private void ImpostorPublishNF(string name, string project) { From 970f826dc80fde9cf89e9749faf7b51be498e9a3 Mon Sep 17 00:00:00 2001 From: John Tran Date: Wed, 7 Apr 2021 04:50:50 +1000 Subject: [PATCH 59/72] Allow Android Versions (#375) Co-authored-by: js6pak Co-authored-by: John Tran --- src/Impostor.Server/Net/Manager/ClientManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Impostor.Server/Net/Manager/ClientManager.cs b/src/Impostor.Server/Net/Manager/ClientManager.cs index d5355ddc7..7a10181a7 100644 --- a/src/Impostor.Server/Net/Manager/ClientManager.cs +++ b/src/Impostor.Server/Net/Manager/ClientManager.cs @@ -20,6 +20,7 @@ internal partial class ClientManager private static readonly HashSet SupportedVersions = new HashSet { GameVersion.GetVersion(2021, 3, 25), // 2021.3.31s + GameVersion.GetVersion(2021, 4, 2), // 2021.4.2a }; private readonly ILogger _logger; From 304b4bb7bff8f25efb5eb0b8a2861219f5a40e5a Mon Sep 17 00:00:00 2001 From: js6pak Date: Tue, 6 Apr 2021 20:23:44 +0200 Subject: [PATCH 60/72] Rework vent api --- .../Events/Game/Player/IPlayerVentEvent.cs | 2 +- .../Innersloth/Maps/AirshipData.cs | 49 +++++++++++++++ src/Impostor.Api/Innersloth/Maps/MapData.cs | 24 +++++++ src/Impostor.Api/Innersloth/Maps/MiraData.cs | 47 ++++++++++++++ src/Impostor.Api/Innersloth/Maps/PolusData.cs | 49 +++++++++++++++ src/Impostor.Api/Innersloth/Maps/SkeldData.cs | 53 ++++++++++++++++ .../Innersloth/Maps/Vents/AirshipVent.cs | 27 ++++++++ .../Innersloth/Maps/Vents/MiraVent.cs | 26 ++++++++ .../Innersloth/Maps/Vents/PolusVent.cs | 27 ++++++++ .../Innersloth/Maps/Vents/SkeldVent.cs | 29 +++++++++ src/Impostor.Api/Innersloth/Vent.cs | 26 ++++++++ src/Impostor.Api/Innersloth/VentLocation.cs | 62 ------------------- .../Events/Game/Player/PlayerVentEvent.cs | 6 +- .../Objects/Components/InnerPlayerPhysics.cs | 3 +- .../Objects/ShipStatus/InnerAirshipStatus.cs | 3 + .../Objects/ShipStatus/InnerMiraShipStatus.cs | 3 + .../ShipStatus/InnerPolusShipStatus.cs | 3 + .../Objects/ShipStatus/InnerShipStatus.cs | 3 + .../ShipStatus/InnerSkeldShipStatus.cs | 3 + 19 files changed, 378 insertions(+), 67 deletions(-) create mode 100644 src/Impostor.Api/Innersloth/Maps/AirshipData.cs create mode 100644 src/Impostor.Api/Innersloth/Maps/MapData.cs create mode 100644 src/Impostor.Api/Innersloth/Maps/MiraData.cs create mode 100644 src/Impostor.Api/Innersloth/Maps/PolusData.cs create mode 100644 src/Impostor.Api/Innersloth/Maps/SkeldData.cs create mode 100644 src/Impostor.Api/Innersloth/Maps/Vents/AirshipVent.cs create mode 100644 src/Impostor.Api/Innersloth/Maps/Vents/MiraVent.cs create mode 100644 src/Impostor.Api/Innersloth/Maps/Vents/PolusVent.cs create mode 100644 src/Impostor.Api/Innersloth/Maps/Vents/SkeldVent.cs create mode 100644 src/Impostor.Api/Innersloth/Vent.cs delete mode 100644 src/Impostor.Api/Innersloth/VentLocation.cs diff --git a/src/Impostor.Api/Events/Game/Player/IPlayerVentEvent.cs b/src/Impostor.Api/Events/Game/Player/IPlayerVentEvent.cs index 81f178bc7..b1d6d8bd2 100644 --- a/src/Impostor.Api/Events/Game/Player/IPlayerVentEvent.cs +++ b/src/Impostor.Api/Events/Game/Player/IPlayerVentEvent.cs @@ -7,7 +7,7 @@ public interface IPlayerVentEvent : IPlayerEvent /// /// Gets get the id of the used vent. /// - public VentLocation VentId { get; } + public Vent Vent { get; } /// /// Gets a value indicating whether the vent was entered or exited. diff --git a/src/Impostor.Api/Innersloth/Maps/AirshipData.cs b/src/Impostor.Api/Innersloth/Maps/AirshipData.cs new file mode 100644 index 000000000..04657d00d --- /dev/null +++ b/src/Impostor.Api/Innersloth/Maps/AirshipData.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Impostor.Api.Innersloth.Maps.Vents; + +namespace Impostor.Api.Innersloth.Maps +{ + public class AirshipData : MapData + { + public AirshipData() + { + Vents = new[] + { + new AirshipVent(AirshipVent.Ids.Vault, new Vector2(-12.6322f, 8.4735f)), + new AirshipVent(AirshipVent.Ids.Cockpit, new Vector2(-22.099f, -1.512f)), + new AirshipVent(AirshipVent.Ids.ViewingDeck, new Vector2(-15.659f, -11.6991f)), + new AirshipVent(AirshipVent.Ids.EngineRoom, new Vector2(0.203f, -2.5361f)), + new AirshipVent(AirshipVent.Ids.Kitchen, new Vector2(-2.6019f, -9.338f)), + new AirshipVent(AirshipVent.Ids.MainHallBottom, new Vector2(7.021f, -3.730999f)), + new AirshipVent(AirshipVent.Ids.GapRight, new Vector2(9.814f, 3.206f)), + new AirshipVent(AirshipVent.Ids.GapLeft, new Vector2(12.663f, 5.922f)), + new AirshipVent(AirshipVent.Ids.MainHallTop, new Vector2(3.605f, 6.923f)), + new AirshipVent(AirshipVent.Ids.Showers, new Vector2(23.9869f, -1.386f)), + new AirshipVent(AirshipVent.Ids.Records, new Vector2(23.2799f, 8.259998f)), + new AirshipVent(AirshipVent.Ids.CargoBay, new Vector2(30.4409f, -3.577f)), + }.ToDictionary(x => x.Id, x => (Vent)x); + + ConnectVents(AirshipVent.Ids.Vault, left: AirshipVent.Ids.Cockpit); + ConnectVents(AirshipVent.Ids.Cockpit, left: AirshipVent.Ids.Vault, right: AirshipVent.Ids.ViewingDeck); + ConnectVents(AirshipVent.Ids.ViewingDeck, left: AirshipVent.Ids.Cockpit); + ConnectVents(AirshipVent.Ids.EngineRoom, left: AirshipVent.Ids.Kitchen, right: AirshipVent.Ids.MainHallBottom); + ConnectVents(AirshipVent.Ids.Kitchen, left: AirshipVent.Ids.EngineRoom, right: AirshipVent.Ids.MainHallBottom); + ConnectVents(AirshipVent.Ids.MainHallBottom, left: AirshipVent.Ids.EngineRoom, right: AirshipVent.Ids.Kitchen); + ConnectVents(AirshipVent.Ids.GapRight, left: AirshipVent.Ids.MainHallTop, right: AirshipVent.Ids.GapLeft); + ConnectVents(AirshipVent.Ids.GapLeft, left: AirshipVent.Ids.MainHallTop, right: AirshipVent.Ids.GapRight); + ConnectVents(AirshipVent.Ids.MainHallTop, left: AirshipVent.Ids.GapLeft, right: AirshipVent.Ids.GapRight); + ConnectVents(AirshipVent.Ids.Showers, left: AirshipVent.Ids.Records, right: AirshipVent.Ids.CargoBay); + ConnectVents(AirshipVent.Ids.Records, left: AirshipVent.Ids.Showers, right: AirshipVent.Ids.CargoBay); + ConnectVents(AirshipVent.Ids.CargoBay, left: AirshipVent.Ids.Showers, right: AirshipVent.Ids.Records); + } + + public override IReadOnlyDictionary Vents { get; } + + private void ConnectVents(AirshipVent.Ids vent, AirshipVent.Ids? left = null, AirshipVent.Ids? center = null, AirshipVent.Ids? right = null) + { + ConnectVents((int)vent, (int?)left, (int?)center, (int?)right); + } + } +} diff --git a/src/Impostor.Api/Innersloth/Maps/MapData.cs b/src/Impostor.Api/Innersloth/Maps/MapData.cs new file mode 100644 index 000000000..53428f59a --- /dev/null +++ b/src/Impostor.Api/Innersloth/Maps/MapData.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Impostor.Api.Innersloth.Maps +{ + public abstract class MapData + { + public static IReadOnlyDictionary Maps { get; } = new Dictionary + { + [MapTypes.Skeld] = new SkeldData(), + [MapTypes.MiraHQ] = new MiraData(), + [MapTypes.Polus] = new PolusData(), + [MapTypes.Airship] = new AirshipData(), + }; + + public abstract IReadOnlyDictionary Vents { get; } + + protected void ConnectVents(int vent, int? left = null, int? center = null, int? right = null) + { + Vents[vent].Left = left != null ? Vents[left.Value] : null; + Vents[vent].Center = center != null ? Vents[center.Value] : null; + Vents[vent].Right = right != null ? Vents[right.Value] : null; + } + } +} diff --git a/src/Impostor.Api/Innersloth/Maps/MiraData.cs b/src/Impostor.Api/Innersloth/Maps/MiraData.cs new file mode 100644 index 000000000..41f2c61fe --- /dev/null +++ b/src/Impostor.Api/Innersloth/Maps/MiraData.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Impostor.Api.Innersloth.Maps.Vents; + +namespace Impostor.Api.Innersloth.Maps +{ + public class MiraData : MapData + { + public MiraData() + { + Vents = new[] + { + new MiraVent(MiraVent.Ids.Balcony, new Vector2(23.77f, -1.94f)), + new MiraVent(MiraVent.Ids.Cafeteria, new Vector2(23.9f, 7.18f)), + new MiraVent(MiraVent.Ids.Reactor, new Vector2(0.4800001f, 10.697f)), + new MiraVent(MiraVent.Ids.Laboratory, new Vector2(11.606f, 13.816f)), + new MiraVent(MiraVent.Ids.Office, new Vector2(13.28f, 20.13f)), + new MiraVent(MiraVent.Ids.Admin, new Vector2(22.39f, 17.23f)), + new MiraVent(MiraVent.Ids.Greenhouse, new Vector2(17.85f, 25.23f)), + new MiraVent(MiraVent.Ids.Medbay, new Vector2(15.41f, -1.82f)), + new MiraVent(MiraVent.Ids.Decontamination, new Vector2(6.83f, 3.145f)), + new MiraVent(MiraVent.Ids.LockerRoom, new Vector2(4.29f, 0.5299997f)), + new MiraVent(MiraVent.Ids.Launchpad, new Vector2(-6.18f, 3.56f)), + }.ToDictionary(x => x.Id, x => (Vent)x); + + ConnectVents(MiraVent.Ids.Balcony, left: MiraVent.Ids.Medbay, right: MiraVent.Ids.Cafeteria); + ConnectVents(MiraVent.Ids.Cafeteria, left: MiraVent.Ids.Admin, right: MiraVent.Ids.Balcony); + ConnectVents(MiraVent.Ids.Reactor, left: MiraVent.Ids.Laboratory, center: MiraVent.Ids.Decontamination, right: MiraVent.Ids.Launchpad); + ConnectVents(MiraVent.Ids.Laboratory, left: MiraVent.Ids.Reactor, center: MiraVent.Ids.Decontamination, right: MiraVent.Ids.Office); + ConnectVents(MiraVent.Ids.Office, left: MiraVent.Ids.Laboratory, center: MiraVent.Ids.Admin, right: MiraVent.Ids.Greenhouse); + ConnectVents(MiraVent.Ids.Admin, left: MiraVent.Ids.Greenhouse, center: MiraVent.Ids.Cafeteria, right: MiraVent.Ids.Office); + ConnectVents(MiraVent.Ids.Greenhouse, left: MiraVent.Ids.Admin, right: MiraVent.Ids.Office); + ConnectVents(MiraVent.Ids.Medbay, left: MiraVent.Ids.Balcony, right: MiraVent.Ids.LockerRoom); + ConnectVents(MiraVent.Ids.Decontamination, left: MiraVent.Ids.Reactor, center: MiraVent.Ids.LockerRoom, right: MiraVent.Ids.Laboratory); + ConnectVents(MiraVent.Ids.LockerRoom, left: MiraVent.Ids.Medbay, center: MiraVent.Ids.Launchpad, right: MiraVent.Ids.Decontamination); + ConnectVents(MiraVent.Ids.Launchpad, left: MiraVent.Ids.Reactor, right: MiraVent.Ids.LockerRoom); + } + + public override IReadOnlyDictionary Vents { get; } + + private void ConnectVents(MiraVent.Ids vent, MiraVent.Ids? left = null, MiraVent.Ids? center = null, MiraVent.Ids? right = null) + { + ConnectVents((int)vent, (int?)left, (int?)center, (int?)right); + } + } +} diff --git a/src/Impostor.Api/Innersloth/Maps/PolusData.cs b/src/Impostor.Api/Innersloth/Maps/PolusData.cs new file mode 100644 index 000000000..5748d26f1 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Maps/PolusData.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Impostor.Api.Innersloth.Maps.Vents; + +namespace Impostor.Api.Innersloth.Maps +{ + public class PolusData : MapData + { + public PolusData() + { + Vents = new[] + { + new PolusVent(PolusVent.Ids.Security, new Vector2(1.929f, -9.558001f)), + new PolusVent(PolusVent.Ids.Electrical, new Vector2(6.9f, -14.41f)), + new PolusVent(PolusVent.Ids.O2, new Vector2(3.51f, -16.58f)), + new PolusVent(PolusVent.Ids.Communications, new Vector2(12.304f, -18.898f)), + new PolusVent(PolusVent.Ids.Office, new Vector2(16.379f, -19.599f)), + new PolusVent(PolusVent.Ids.Admin, new Vector2(20.089f, -25.517f)), + new PolusVent(PolusVent.Ids.Laboratory, new Vector2(32.963f, -9.526f)), + new PolusVent(PolusVent.Ids.Lava, new Vector2(30.907f, -11.86f)), + new PolusVent(PolusVent.Ids.Storage, new Vector2(22f, -12.19f)), + new PolusVent(PolusVent.Ids.RightStabilizer, new Vector2(24.02f, -8.39f)), + new PolusVent(PolusVent.Ids.LeftStabilizer, new Vector2(9.64f, -7.72f)), + new PolusVent(PolusVent.Ids.OutsideAdmin, new Vector2(18.93f, -24.85f)), + }.ToDictionary(x => x.Id, x => (Vent)x); + + ConnectVents(PolusVent.Ids.Security, left: PolusVent.Ids.O2, right: PolusVent.Ids.Electrical); + ConnectVents(PolusVent.Ids.Electrical, left: PolusVent.Ids.O2, right: PolusVent.Ids.Security); + ConnectVents(PolusVent.Ids.O2, left: PolusVent.Ids.Electrical, right: PolusVent.Ids.Security); + ConnectVents(PolusVent.Ids.Communications, left: PolusVent.Ids.Storage, right: PolusVent.Ids.Office); + ConnectVents(PolusVent.Ids.Office, left: PolusVent.Ids.Communications, right: PolusVent.Ids.Storage); + ConnectVents(PolusVent.Ids.Admin, left: PolusVent.Ids.OutsideAdmin, right: PolusVent.Ids.Lava); + ConnectVents(PolusVent.Ids.Laboratory, right: PolusVent.Ids.Lava); + ConnectVents(PolusVent.Ids.Lava, left: PolusVent.Ids.Laboratory, right: PolusVent.Ids.Admin); + ConnectVents(PolusVent.Ids.Storage, left: PolusVent.Ids.Communications, right: PolusVent.Ids.Office); + ConnectVents(PolusVent.Ids.RightStabilizer, left: PolusVent.Ids.LeftStabilizer); + ConnectVents(PolusVent.Ids.LeftStabilizer, left: PolusVent.Ids.RightStabilizer); + ConnectVents(PolusVent.Ids.OutsideAdmin, right: PolusVent.Ids.Admin); + } + + public override IReadOnlyDictionary Vents { get; } + + private void ConnectVents(PolusVent.Ids vent, PolusVent.Ids? left = null, PolusVent.Ids? center = null, PolusVent.Ids? right = null) + { + ConnectVents((int)vent, (int?)left, (int?)center, (int?)right); + } + } +} diff --git a/src/Impostor.Api/Innersloth/Maps/SkeldData.cs b/src/Impostor.Api/Innersloth/Maps/SkeldData.cs new file mode 100644 index 000000000..b0bb95d95 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Maps/SkeldData.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Impostor.Api.Innersloth.Maps.Vents; + +namespace Impostor.Api.Innersloth.Maps +{ + public class SkeldData : MapData + { + public SkeldData() + { + Vents = new[] + { + new SkeldVent(SkeldVent.Ids.Admin, new Vector2(2.544f, -9.955201f)), + new SkeldVent(SkeldVent.Ids.RightHallway, new Vector2(9.384f, -6.438f)), + new SkeldVent(SkeldVent.Ids.Cafeteria, new Vector2(4.2588f, -0.276f)), + new SkeldVent(SkeldVent.Ids.Electrical, new Vector2(-9.7764f, -8.034f)), + new SkeldVent(SkeldVent.Ids.UpperEngine, new Vector2(-15.288f, 2.52f)), + new SkeldVent(SkeldVent.Ids.Security, new Vector2(-12.534f, -6.9492f)), + new SkeldVent(SkeldVent.Ids.Medbay, new Vector2(-10.608f, -4.176f)), + new SkeldVent(SkeldVent.Ids.Weapons, new Vector2(8.820001f, 3.324f)), + new SkeldVent(SkeldVent.Ids.LowerReactor, new Vector2(-20.796f, -6.9528f)), + new SkeldVent(SkeldVent.Ids.LowerEngine, new Vector2(-15.2508f, -13.656f)), + new SkeldVent(SkeldVent.Ids.Shields, new Vector2(9.5232f, -14.3376f)), + new SkeldVent(SkeldVent.Ids.UpperReactor, new Vector2(-21.876f, -3.0516f)), + new SkeldVent(SkeldVent.Ids.UpperNavigation, new Vector2(16.008f, -3.168f)), + new SkeldVent(SkeldVent.Ids.LowerNavigation, new Vector2(16.008f, -6.384f)), + }.ToDictionary(x => x.Id, x => (Vent)x); + + ConnectVents(SkeldVent.Ids.Admin, left: SkeldVent.Ids.Cafeteria, right: SkeldVent.Ids.RightHallway); + ConnectVents(SkeldVent.Ids.RightHallway, left: SkeldVent.Ids.Admin, right: SkeldVent.Ids.Cafeteria); + ConnectVents(SkeldVent.Ids.Cafeteria, left: SkeldVent.Ids.Admin, right: SkeldVent.Ids.RightHallway); + ConnectVents(SkeldVent.Ids.Electrical, left: SkeldVent.Ids.Security, right: SkeldVent.Ids.Medbay); + ConnectVents(SkeldVent.Ids.UpperEngine, left: SkeldVent.Ids.UpperReactor); + ConnectVents(SkeldVent.Ids.Security, left: SkeldVent.Ids.Medbay, right: SkeldVent.Ids.Electrical); + ConnectVents(SkeldVent.Ids.Medbay, left: SkeldVent.Ids.Security, right: SkeldVent.Ids.Electrical); + ConnectVents(SkeldVent.Ids.Weapons, right: SkeldVent.Ids.UpperNavigation); + ConnectVents(SkeldVent.Ids.LowerReactor, left: SkeldVent.Ids.LowerEngine); + ConnectVents(SkeldVent.Ids.LowerEngine, left: SkeldVent.Ids.LowerReactor); + ConnectVents(SkeldVent.Ids.Shields, left: SkeldVent.Ids.LowerNavigation); + ConnectVents(SkeldVent.Ids.UpperReactor, left: SkeldVent.Ids.UpperEngine); + ConnectVents(SkeldVent.Ids.UpperNavigation, right: SkeldVent.Ids.Weapons); + ConnectVents(SkeldVent.Ids.LowerNavigation, right: SkeldVent.Ids.Shields); + } + + public override IReadOnlyDictionary Vents { get; } + + private void ConnectVents(SkeldVent.Ids vent, SkeldVent.Ids? left = null, SkeldVent.Ids? center = null, SkeldVent.Ids? right = null) + { + ConnectVents((int)vent, (int?)left, (int?)center, (int?)right); + } + } +} diff --git a/src/Impostor.Api/Innersloth/Maps/Vents/AirshipVent.cs b/src/Impostor.Api/Innersloth/Maps/Vents/AirshipVent.cs new file mode 100644 index 000000000..7605504c8 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Maps/Vents/AirshipVent.cs @@ -0,0 +1,27 @@ +using System.Numerics; + +namespace Impostor.Api.Innersloth.Maps.Vents +{ + public class AirshipVent : Vent + { + internal AirshipVent(Ids id, Vector2 position) : base((int)id, id.ToString(), position) + { + } + + public enum Ids + { + Vault = 0, + Cockpit = 1, + ViewingDeck = 2, + EngineRoom = 3, + Kitchen = 4, + MainHallBottom = 5, + GapRight = 6, + GapLeft = 7, + MainHallTop = 8, + Showers = 9, + Records = 10, + CargoBay = 11, + } + } +} diff --git a/src/Impostor.Api/Innersloth/Maps/Vents/MiraVent.cs b/src/Impostor.Api/Innersloth/Maps/Vents/MiraVent.cs new file mode 100644 index 000000000..775401a35 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Maps/Vents/MiraVent.cs @@ -0,0 +1,26 @@ +using System.Numerics; + +namespace Impostor.Api.Innersloth.Maps.Vents +{ + public class MiraVent : Vent + { + internal MiraVent(Ids id, Vector2 position) : base((int)id, id.ToString(), position) + { + } + + public enum Ids + { + Balcony = 1, + Cafeteria = 2, + Reactor = 3, + Laboratory = 4, + Office = 5, + Admin = 6, + Greenhouse = 7, + Medbay = 8, + Decontamination = 9, + LockerRoom = 10, + Launchpad = 11, + } + } +} diff --git a/src/Impostor.Api/Innersloth/Maps/Vents/PolusVent.cs b/src/Impostor.Api/Innersloth/Maps/Vents/PolusVent.cs new file mode 100644 index 000000000..8310af07b --- /dev/null +++ b/src/Impostor.Api/Innersloth/Maps/Vents/PolusVent.cs @@ -0,0 +1,27 @@ +using System.Numerics; + +namespace Impostor.Api.Innersloth.Maps.Vents +{ + public class PolusVent : Vent + { + internal PolusVent(Ids id, Vector2 position) : base((int)id, id.ToString(), position) + { + } + + public enum Ids + { + Security = 0, + Electrical = 1, + O2 = 2, + Communications = 3, + Office = 4, + Admin = 5, + Laboratory = 6, + Lava = 7, + Storage = 8, + RightStabilizer = 9, + LeftStabilizer = 10, + OutsideAdmin = 11, + } + } +} diff --git a/src/Impostor.Api/Innersloth/Maps/Vents/SkeldVent.cs b/src/Impostor.Api/Innersloth/Maps/Vents/SkeldVent.cs new file mode 100644 index 000000000..e670a8d3d --- /dev/null +++ b/src/Impostor.Api/Innersloth/Maps/Vents/SkeldVent.cs @@ -0,0 +1,29 @@ +using System.Numerics; + +namespace Impostor.Api.Innersloth.Maps.Vents +{ + public class SkeldVent : Vent + { + internal SkeldVent(Ids id, Vector2 position) : base((int)id, id.ToString(), position) + { + } + + public enum Ids + { + Admin = 0, + RightHallway = 1, + Cafeteria = 2, + Electrical = 3, + UpperEngine = 4, + Security = 5, + Medbay = 6, + Weapons = 7, + LowerReactor = 8, + LowerEngine = 9, + Shields = 10, + UpperReactor = 11, + UpperNavigation = 12, + LowerNavigation = 13, + } + } +} diff --git a/src/Impostor.Api/Innersloth/Vent.cs b/src/Impostor.Api/Innersloth/Vent.cs new file mode 100644 index 000000000..723207b28 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Vent.cs @@ -0,0 +1,26 @@ +using System.Numerics; + +namespace Impostor.Api.Innersloth +{ + public abstract class Vent + { + internal Vent(int id, string name, Vector2 position) + { + Id = id; + Name = name; + Position = position; + } + + public int Id { get; } + + public string Name { get; } + + public Vector2 Position { get; } + + public Vent? Left { get; internal set; } + + public Vent? Center { get; internal set; } + + public Vent? Right { get; internal set; } + } +} diff --git a/src/Impostor.Api/Innersloth/VentLocation.cs b/src/Impostor.Api/Innersloth/VentLocation.cs deleted file mode 100644 index 0092c6960..000000000 --- a/src/Impostor.Api/Innersloth/VentLocation.cs +++ /dev/null @@ -1,62 +0,0 @@ -namespace Impostor.Api.Innersloth -{ - public enum VentLocation : uint - { - // Skeld - SkeldAdmin = 0, - SkeldRightHallway = 1, - SkeldCafeteria = 2, - SkeldElectrical = 3, - SkeldUpperEngine = 4, - SkeldSecurity = 5, - SkeldMedbay = 6, - SkeldWeapons = 7, - SkeldLowerReactor = 8, - SkeldLowerEngine = 9, - SkeldShields = 10, - SkeldUpperReactor = 11, - SkeldUpperNavigation = 12, - SkeldLowerNavigation = 13, - - // Mira HQ - MiraBalcony = 1, - MiraCafeteria = 2, - MiraReactor = 3, - MiraLaboratory = 4, - MiraOffice = 5, - MiraAdmin = 6, - MiraGreenhouse = 7, - MiraMedbay = 8, - MiraDecontamination = 9, - MiraLockerRoom = 10, - MiraLaunchpad = 11, - - // Polus - PolusSecurity = 0, - PolusElectrical = 1, - PolusO2 = 2, - PolusCommunications = 3, - PolusOffice = 4, - PolusAdmin = 5, - PolusLaboratory = 6, - PolusLava = 7, - PolusStorage = 8, - PolusRightStabilizer = 9, - PolusLeftStabilizer = 10, - PolusOutsideAdmin = 11, - - // Airship - AirshipVault = 0, - AirshipCockpit = 1, - AirshipViewingDeck = 2, - AirshipEngineRoom = 3, - AirshipKitchen = 4, - AirshipMainHallBottom = 5, - AirshipGapRight = 6, - AirshipGapLeft = 7, - AirshipMainHallTop = 8, - AirshipShowers = 9, - AirshipRecords = 10, - AirshipCargoBay = 11, - } -} diff --git a/src/Impostor.Server/Events/Game/Player/PlayerVentEvent.cs b/src/Impostor.Server/Events/Game/Player/PlayerVentEvent.cs index 0798d40b9..e64cec0d9 100644 --- a/src/Impostor.Server/Events/Game/Player/PlayerVentEvent.cs +++ b/src/Impostor.Server/Events/Game/Player/PlayerVentEvent.cs @@ -8,12 +8,12 @@ namespace Impostor.Server.Events.Player { public class PlayerVentEvent : IPlayerVentEvent { - public PlayerVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl innerPlayerPhysics, VentLocation ventId, bool ventEnter) + public PlayerVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl innerPlayerPhysics, Vent vent, bool ventEnter) { Game = game; ClientPlayer = sender; PlayerControl = innerPlayerPhysics; - VentId = ventId; + Vent = vent; VentEnter = ventEnter; } @@ -23,7 +23,7 @@ public PlayerVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl inn public IInnerPlayerControl PlayerControl { get; } - public VentLocation VentId { get; } + public Vent Vent { get; } public bool VentEnter { get; } } diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs index 0f20750c6..b51c97a50 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Impostor.Api.Events.Managers; using Impostor.Api.Innersloth; +using Impostor.Api.Innersloth.Maps; using Impostor.Api.Net; using Impostor.Api.Net.Inner; using Impostor.Api.Net.Messages; @@ -65,7 +66,7 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client throw new ArgumentOutOfRangeException(nameof(call), call, null); } - await _eventManager.CallAsync(new PlayerVentEvent(Game, sender, _playerControl, (VentLocation)ventId, call == RpcCalls.EnterVent)); + await _eventManager.CallAsync(new PlayerVentEvent(Game, sender, _playerControl, Game.GameNet.ShipStatus!.Data.Vents[ventId], call == RpcCalls.EnterVent)); break; case RpcCalls.ClimbLadder: diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs index 7f8562809..84861b1a4 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Numerics; using Impostor.Api.Innersloth; +using Impostor.Api.Innersloth.Maps; using Impostor.Api.Net.Inner.Objects.ShipStatus; using Impostor.Server.Net.Inner.Objects.Systems; using Impostor.Server.Net.Inner.Objects.Systems.ShipStatus; @@ -15,6 +16,8 @@ public InnerAirshipStatus(Game game) : base(game) { } + public override MapData Data => MapData.Maps[MapTypes.Airship]; + public override Dictionary Doors { get; } = new Dictionary(21); public override float SpawnRadius => throw new NotSupportedException(); diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs index 02daf3160..143c98f77 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Numerics; using Impostor.Api.Innersloth; +using Impostor.Api.Innersloth.Maps; using Impostor.Api.Net.Inner.Objects.ShipStatus; using Impostor.Server.Net.Inner.Objects.Systems; using Impostor.Server.Net.Inner.Objects.Systems.ShipStatus; @@ -14,6 +15,8 @@ public InnerMiraShipStatus(Game game) : base(game) { } + public override MapData Data => MapData.Maps[MapTypes.MiraHQ]; + public override Dictionary Doors { get; } = new Dictionary(0); public override float SpawnRadius => 1.55f; diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs index 262b313b8..7301bc44c 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Numerics; using Impostor.Api.Innersloth; +using Impostor.Api.Innersloth.Maps; using Impostor.Api.Net.Inner.Objects.ShipStatus; using Impostor.Server.Net.Inner.Objects.Systems; using Impostor.Server.Net.Inner.Objects.Systems.ShipStatus; @@ -14,6 +15,8 @@ public InnerPolusShipStatus(Game game) : base(game) { } + public override MapData Data => MapData.Maps[MapTypes.Polus]; + public override Dictionary Doors { get; } = new Dictionary(12); public override float SpawnRadius => 1f; diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs index dcfa24f08..0f7a4edd8 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Impostor.Api; using Impostor.Api.Innersloth; +using Impostor.Api.Innersloth.Maps; using Impostor.Api.Net; using Impostor.Api.Net.Inner; using Impostor.Api.Net.Inner.Objects.ShipStatus; @@ -25,6 +26,8 @@ protected InnerShipStatus(Game game) : base(game) Components.Add(this); } + public abstract MapData Data { get; } + public abstract Dictionary Doors { get; } public abstract float SpawnRadius { get; } diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs index 9580b7be4..6d04f5bb2 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Numerics; using Impostor.Api.Innersloth; +using Impostor.Api.Innersloth.Maps; using Impostor.Api.Net.Inner.Objects.ShipStatus; using Impostor.Server.Net.Inner.Objects.Systems; using Impostor.Server.Net.Inner.Objects.Systems.ShipStatus; @@ -14,6 +15,8 @@ public InnerSkeldShipStatus(Game game) : base(game) { } + public override MapData Data { get; } = MapData.Maps[MapTypes.Skeld]; + public override Dictionary Doors { get; } = new Dictionary(13); public override float SpawnRadius => 1.6f; From f03e72206e7ba239571a28e1901b3a12af8d7bd5 Mon Sep 17 00:00:00 2001 From: js6pak Date: Tue, 6 Apr 2021 20:24:20 +0200 Subject: [PATCH 61/72] Update example plugin --- .../Events/Game/IGamePlayerJoinedEvent.cs | 5 ++- .../Events/Game/IGamePlayerLeftEvent.cs | 7 +++- .../Handlers/GameEventListener.cs | 30 ++++++++--------- .../Handlers/MeetingEventListener.cs | 15 ++++++--- .../Handlers/PlayerEventListener.cs | 33 ++++++++++--------- 5 files changed, 54 insertions(+), 36 deletions(-) diff --git a/src/Impostor.Api/Events/Game/IGamePlayerJoinedEvent.cs b/src/Impostor.Api/Events/Game/IGamePlayerJoinedEvent.cs index 921568e5f..280d397d9 100644 --- a/src/Impostor.Api/Events/Game/IGamePlayerJoinedEvent.cs +++ b/src/Impostor.Api/Events/Game/IGamePlayerJoinedEvent.cs @@ -1,6 +1,9 @@ -namespace Impostor.Api.Events +using Impostor.Api.Net; + +namespace Impostor.Api.Events { public interface IGamePlayerJoinedEvent : IGameEvent { + IClientPlayer Player { get; } } } diff --git a/src/Impostor.Api/Events/Game/IGamePlayerLeftEvent.cs b/src/Impostor.Api/Events/Game/IGamePlayerLeftEvent.cs index 21d8b7c22..4568a602c 100644 --- a/src/Impostor.Api/Events/Game/IGamePlayerLeftEvent.cs +++ b/src/Impostor.Api/Events/Game/IGamePlayerLeftEvent.cs @@ -1,6 +1,11 @@ -namespace Impostor.Api.Events +using Impostor.Api.Net; + +namespace Impostor.Api.Events { public interface IGamePlayerLeftEvent : IGameEvent { + IClientPlayer Player { get; } + + bool IsBan { get; } } } diff --git a/src/Impostor.Plugins.Example/Handlers/GameEventListener.cs b/src/Impostor.Plugins.Example/Handlers/GameEventListener.cs index be2d0f3ff..eabbdf149 100644 --- a/src/Impostor.Plugins.Example/Handlers/GameEventListener.cs +++ b/src/Impostor.Plugins.Example/Handlers/GameEventListener.cs @@ -1,64 +1,64 @@ -using System; -using Impostor.Api.Events; +using Impostor.Api.Events; +using Microsoft.Extensions.Logging; namespace Impostor.Plugins.Example.Handlers { public class GameEventListener : IEventListener { - [EventListener(EventPriority.Monitor)] - public void OnGame(IGameEvent e) + private readonly ILogger _logger; + + public GameEventListener(ILogger logger) { - Console.WriteLine(e.GetType().Name + " triggered"); + _logger = logger; } [EventListener] public void OnGameCreated(IGameCreatedEvent e) { - Console.WriteLine("Game > created"); + _logger.LogInformation("Game {code} > created", e.Game.Code); } [EventListener] public void OnGameStarting(IGameStartingEvent e) { - Console.WriteLine("Game > starting"); + _logger.LogInformation("Game {code} > starting", e.Game.Code); } [EventListener] public void OnGameStarted(IGameStartedEvent e) { - Console.WriteLine("Game > started"); + _logger.LogInformation("Game {code} > started", e.Game.Code); foreach (var player in e.Game.Players) { - var info = player.Character.PlayerInfo; + var info = player.Character!.PlayerInfo; - Console.WriteLine($"- {info.PlayerName} {info.IsImpostor}"); + _logger.LogInformation("- {player} is {role}", info.PlayerName, info.IsImpostor ? "an impostor" : "a crewmate"); } } [EventListener] public void OnGameEnded(IGameEndedEvent e) { - Console.WriteLine("Game > ended"); - Console.WriteLine("- Reason: " + e.GameOverReason); + _logger.LogInformation("Game {code} > ended because {reason}", e.Game.Code, e.GameOverReason); } [EventListener] public void OnGameDestroyed(IGameDestroyedEvent e) { - Console.WriteLine("Game > destroyed"); + _logger.LogInformation("Game {code} > destroyed", e.Game.Code); } [EventListener] public void OnPlayerJoined(IGamePlayerJoinedEvent e) { - Console.WriteLine("Player joined a game."); + _logger.LogInformation("Game {code} > {player} joined", e.Game.Code, e.Player.Client.Name); } [EventListener] public void OnPlayerLeftGame(IGamePlayerLeftEvent e) { - Console.WriteLine("Player left a game."); + _logger.LogInformation("Game {code} > {player} left", e.Game.Code, e.Player.Client.Name); } } } diff --git a/src/Impostor.Plugins.Example/Handlers/MeetingEventListener.cs b/src/Impostor.Plugins.Example/Handlers/MeetingEventListener.cs index 847532c50..84948a71c 100644 --- a/src/Impostor.Plugins.Example/Handlers/MeetingEventListener.cs +++ b/src/Impostor.Plugins.Example/Handlers/MeetingEventListener.cs @@ -1,21 +1,28 @@ -using System; -using Impostor.Api.Events; +using Impostor.Api.Events; using Impostor.Api.Events.Meeting; +using Microsoft.Extensions.Logging; namespace Impostor.Plugins.Example.Handlers { public class MeetingEventListener : IEventListener { + private readonly ILogger _logger; + + public MeetingEventListener(ILogger logger) + { + _logger = logger; + } + [EventListener] public void OnMeetingStarted(IMeetingStartedEvent e) { - Console.WriteLine("Meeting > started"); + _logger.LogInformation("Meeting > started"); } [EventListener] public void OnMeetingEnded(IMeetingEndedEvent e) { - Console.WriteLine("Meeting > ended"); + _logger.LogInformation("Meeting > ended"); } } } diff --git a/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs b/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs index c62433c64..a052fd712 100644 --- a/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs +++ b/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs @@ -10,7 +10,7 @@ namespace Impostor.Plugins.Example.Handlers { public class PlayerEventListener : IEventListener { - private static readonly Random Random = new Random(); + private readonly Random _random = new Random(); private readonly ILogger _logger; @@ -22,48 +22,45 @@ public PlayerEventListener(ILogger logger) [EventListener] public void OnPlayerSpawned(IPlayerSpawnedEvent e) { - _logger.LogDebug(e.PlayerControl.PlayerInfo.PlayerName + " spawned"); + _logger.LogInformation("Player {player} > spawned", e.PlayerControl.PlayerInfo.PlayerName); // Need to make a local copy because it might be possible that // the event gets changed after being handled. var clientPlayer = e.ClientPlayer; var playerControl = e.PlayerControl; - /* Task.Run(async () => { - Console.WriteLine("Starting player task."); + _logger.LogDebug("Starting player task"); // Give the player time to load. await Task.Delay(TimeSpan.FromSeconds(3)); - while (clientPlayer.Client.Connection != null && - clientPlayer.Client.Connection.IsConnected) + while (clientPlayer.Client.Connection != null && clientPlayer.Client.Connection.IsConnected) { // Modify player properties. - await playerControl.SetColorAsync((byte) Random.Next(1, 9)); - await playerControl.SetHatAsync((uint) Random.Next(1, 9)); - await playerControl.SetSkinAsync((uint) Random.Next(1, 9)); - await playerControl.SetPetAsync((uint) Random.Next(1, 9)); + await playerControl.SetColorAsync((ColorType)_random.Next(1, 9)); + await playerControl.SetHatAsync((HatType)_random.Next(1, 9)); + await playerControl.SetSkinAsync((SkinType)_random.Next(1, 9)); + await playerControl.SetPetAsync((PetType)_random.Next(1, 9)); await Task.Delay(TimeSpan.FromMilliseconds(5000)); } - _logger.LogDebug("Stopping player task."); + _logger.LogDebug("Stopping player task"); }); - */ } [EventListener] public void OnPlayerDestroyed(IPlayerDestroyedEvent e) { - _logger.LogDebug(e.PlayerControl.PlayerInfo.PlayerName + " destroyed"); + _logger.LogInformation("Player {player} > destroyed", e.PlayerControl.PlayerInfo.PlayerName); } [EventListener] public async ValueTask OnPlayerChat(IPlayerChatEvent e) { - _logger.LogDebug(e.PlayerControl.PlayerInfo.PlayerName + " said " + e.Message); + _logger.LogInformation("Player {player} > said {message}", e.PlayerControl.PlayerInfo.PlayerName, e.Message); if (e.Message == "test") { @@ -94,7 +91,13 @@ public async ValueTask OnPlayerChat(IPlayerChatEvent e) [EventListener] public void OnPlayerStartMeetingEvent(IPlayerStartMeetingEvent e) { - _logger.LogDebug($"Player {e.PlayerControl.PlayerInfo.PlayerName} start meeting, reason: " + (e.Body == null ? "Emergency call button" : "Found the body of the player " + e.Body.PlayerInfo.PlayerName)); + _logger.LogInformation("Player {player} > started meeting, reason: {reason}", e.PlayerControl.PlayerInfo.PlayerName, e.Body == null ? "Emergency call button" : "Found the body of the player " + e.Body.PlayerInfo.PlayerName); + } + + [EventListener] + public void OnPlayerVentEvent(IPlayerVentEvent e) + { + _logger.LogInformation("Player {player} " + (e.VentEnter ? "entered" : "exit") + " the vent in {vent}", e.PlayerControl.PlayerInfo.PlayerName, e.Vent.Name); } } } From bfba4385fd96cadc885420acb441d7f433216482 Mon Sep 17 00:00:00 2001 From: js6pak Date: Tue, 6 Apr 2021 21:10:53 +0200 Subject: [PATCH 62/72] Make PlayerVentEvent an actual PlayerVentEvent --- .../Game/Player/IPlayerEnterVentEvent.cs | 12 +++++++++ .../Game/Player/IPlayerExitVentEvent.cs | 12 +++++++++ .../Events/Game/Player/IPlayerVentEvent.cs | 5 ---- .../Handlers/PlayerEventListener.cs | 14 +++++++++- .../Game/Player/PlayerEnterVentEvent.cs | 27 +++++++++++++++++++ .../Events/Game/Player/PlayerExitVentEvent.cs | 27 +++++++++++++++++++ .../Events/Game/Player/PlayerVentEvent.cs | 5 +--- .../Components/InnerCustomNetworkTransform.cs | 19 ++++++++++++- .../Objects/Components/InnerPlayerPhysics.cs | 13 ++++++++- 9 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 src/Impostor.Api/Events/Game/Player/IPlayerEnterVentEvent.cs create mode 100644 src/Impostor.Api/Events/Game/Player/IPlayerExitVentEvent.cs create mode 100644 src/Impostor.Server/Events/Game/Player/PlayerEnterVentEvent.cs create mode 100644 src/Impostor.Server/Events/Game/Player/PlayerExitVentEvent.cs diff --git a/src/Impostor.Api/Events/Game/Player/IPlayerEnterVentEvent.cs b/src/Impostor.Api/Events/Game/Player/IPlayerEnterVentEvent.cs new file mode 100644 index 000000000..dddcb3bf8 --- /dev/null +++ b/src/Impostor.Api/Events/Game/Player/IPlayerEnterVentEvent.cs @@ -0,0 +1,12 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Events.Player +{ + public interface IPlayerEnterVentEvent : IPlayerEvent + { + /// + /// Gets get the id of the used vent. + /// + public Vent Vent { get; } + } +} diff --git a/src/Impostor.Api/Events/Game/Player/IPlayerExitVentEvent.cs b/src/Impostor.Api/Events/Game/Player/IPlayerExitVentEvent.cs new file mode 100644 index 000000000..516f80b7d --- /dev/null +++ b/src/Impostor.Api/Events/Game/Player/IPlayerExitVentEvent.cs @@ -0,0 +1,12 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Events.Player +{ + public interface IPlayerExitVentEvent : IPlayerEvent + { + /// + /// Gets get the id of the used vent. + /// + public Vent Vent { get; } + } +} diff --git a/src/Impostor.Api/Events/Game/Player/IPlayerVentEvent.cs b/src/Impostor.Api/Events/Game/Player/IPlayerVentEvent.cs index b1d6d8bd2..0ab202d41 100644 --- a/src/Impostor.Api/Events/Game/Player/IPlayerVentEvent.cs +++ b/src/Impostor.Api/Events/Game/Player/IPlayerVentEvent.cs @@ -8,10 +8,5 @@ public interface IPlayerVentEvent : IPlayerEvent /// Gets get the id of the used vent. /// public Vent Vent { get; } - - /// - /// Gets a value indicating whether the vent was entered or exited. - /// - public bool VentEnter { get; } } } diff --git a/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs b/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs index a052fd712..fbef0f40b 100644 --- a/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs +++ b/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs @@ -94,10 +94,22 @@ public void OnPlayerStartMeetingEvent(IPlayerStartMeetingEvent e) _logger.LogInformation("Player {player} > started meeting, reason: {reason}", e.PlayerControl.PlayerInfo.PlayerName, e.Body == null ? "Emergency call button" : "Found the body of the player " + e.Body.PlayerInfo.PlayerName); } + [EventListener] + public void OnPlayerEnterVentEvent(IPlayerEnterVentEvent e) + { + _logger.LogInformation("Player {player} entered the vent in {vent}", e.PlayerControl.PlayerInfo.PlayerName, e.Vent.Name); + } + + [EventListener] + public void OnPlayerExitVentEvent(IPlayerExitVentEvent e) + { + _logger.LogInformation("Player {player} exit the vent in {vent}", e.PlayerControl.PlayerInfo.PlayerName, e.Vent.Name); + } + [EventListener] public void OnPlayerVentEvent(IPlayerVentEvent e) { - _logger.LogInformation("Player {player} " + (e.VentEnter ? "entered" : "exit") + " the vent in {vent}", e.PlayerControl.PlayerInfo.PlayerName, e.Vent.Name); + _logger.LogInformation("Player {player} vented to {vent}", e.PlayerControl.PlayerInfo.PlayerName, e.Vent.Name); } } } diff --git a/src/Impostor.Server/Events/Game/Player/PlayerEnterVentEvent.cs b/src/Impostor.Server/Events/Game/Player/PlayerEnterVentEvent.cs new file mode 100644 index 000000000..8e22eb6df --- /dev/null +++ b/src/Impostor.Server/Events/Game/Player/PlayerEnterVentEvent.cs @@ -0,0 +1,27 @@ +using Impostor.Api.Events.Player; +using Impostor.Api.Games; +using Impostor.Api.Innersloth; +using Impostor.Api.Net; +using Impostor.Api.Net.Inner.Objects; + +namespace Impostor.Server.Events.Player +{ + public class PlayerEnterVentEvent : IPlayerEnterVentEvent + { + public PlayerEnterVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl innerPlayerPhysics, Vent vent) + { + Game = game; + ClientPlayer = sender; + PlayerControl = innerPlayerPhysics; + Vent = vent; + } + + public IGame Game { get; } + + public IClientPlayer ClientPlayer { get; } + + public IInnerPlayerControl PlayerControl { get; } + + public Vent Vent { get; } + } +} diff --git a/src/Impostor.Server/Events/Game/Player/PlayerExitVentEvent.cs b/src/Impostor.Server/Events/Game/Player/PlayerExitVentEvent.cs new file mode 100644 index 000000000..93842b225 --- /dev/null +++ b/src/Impostor.Server/Events/Game/Player/PlayerExitVentEvent.cs @@ -0,0 +1,27 @@ +using Impostor.Api.Events.Player; +using Impostor.Api.Games; +using Impostor.Api.Innersloth; +using Impostor.Api.Net; +using Impostor.Api.Net.Inner.Objects; + +namespace Impostor.Server.Events.Player +{ + public class PlayerExitVentEvent : IPlayerExitVentEvent + { + public PlayerExitVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl innerPlayerPhysics, Vent vent) + { + Game = game; + ClientPlayer = sender; + PlayerControl = innerPlayerPhysics; + Vent = vent; + } + + public IGame Game { get; } + + public IClientPlayer ClientPlayer { get; } + + public IInnerPlayerControl PlayerControl { get; } + + public Vent Vent { get; } + } +} diff --git a/src/Impostor.Server/Events/Game/Player/PlayerVentEvent.cs b/src/Impostor.Server/Events/Game/Player/PlayerVentEvent.cs index e64cec0d9..82a99cdf6 100644 --- a/src/Impostor.Server/Events/Game/Player/PlayerVentEvent.cs +++ b/src/Impostor.Server/Events/Game/Player/PlayerVentEvent.cs @@ -8,13 +8,12 @@ namespace Impostor.Server.Events.Player { public class PlayerVentEvent : IPlayerVentEvent { - public PlayerVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl innerPlayerPhysics, Vent vent, bool ventEnter) + public PlayerVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl innerPlayerPhysics, Vent vent) { Game = game; ClientPlayer = sender; PlayerControl = innerPlayerPhysics; Vent = vent; - VentEnter = ventEnter; } public IGame Game { get; } @@ -24,7 +23,5 @@ public PlayerVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl inn public IInnerPlayerControl PlayerControl { get; } public Vent Vent { get; } - - public bool VentEnter { get; } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs index 5df6b8a98..0b5290548 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs @@ -17,6 +17,8 @@ namespace Impostor.Server.Net.Inner.Objects.Components { internal partial class InnerCustomNetworkTransform : InnerNetObject { + private static readonly Vector2 ColliderOffset = new Vector2(0f, -0.4f); + private readonly ILogger _logger; private readonly InnerPlayerControl _playerControl; private readonly IEventManager _eventManager; @@ -113,7 +115,22 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client return false; } - // TODO validate vent location + var vents = Game.GameNet.ShipStatus!.Data.Vents.Values; + + var vent = vents.SingleOrDefault(x => Approximately(x.Position, position + ColliderOffset)); + + if (vent == null) + { + if (await sender.Client.ReportCheatAsync(call, "Failed vent position check")) + { + return false; + } + } + else + { + await _eventManager.CallAsync(new PlayerVentEvent(Game, sender, _playerControl, vent)); + } + await SnapToAsync(sender, position, minSid); return true; } diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs index b51c97a50..edd7b1de8 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs @@ -66,7 +66,18 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client throw new ArgumentOutOfRangeException(nameof(call), call, null); } - await _eventManager.CallAsync(new PlayerVentEvent(Game, sender, _playerControl, Game.GameNet.ShipStatus!.Data.Vents[ventId], call == RpcCalls.EnterVent)); + var vent = Game.GameNet.ShipStatus!.Data.Vents[ventId]; + + switch (call) + { + case RpcCalls.EnterVent: + await _eventManager.CallAsync(new PlayerEnterVentEvent(Game, sender, _playerControl, vent)); + break; + case RpcCalls.ExitVent: + await _eventManager.CallAsync(new PlayerExitVentEvent(Game, sender, _playerControl, vent)); + break; + } + break; case RpcCalls.ClimbLadder: From 7764987f91f5f2b20f7fc9f4ab07cf46f330c357 Mon Sep 17 00:00:00 2001 From: js6pak Date: Fri, 9 Apr 2021 23:51:50 +0200 Subject: [PATCH 63/72] Specify enum values for Platforms --- src/Impostor.Api/Innersloth/Platforms.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Impostor.Api/Innersloth/Platforms.cs b/src/Impostor.Api/Innersloth/Platforms.cs index ab2c0e748..2388e39e5 100644 --- a/src/Impostor.Api/Innersloth/Platforms.cs +++ b/src/Impostor.Api/Innersloth/Platforms.cs @@ -2,14 +2,14 @@ namespace Impostor.Api.Innersloth { public enum Platforms { - Unknown, - StandaloneEpicPC, - StandaloneSteamPC, - StandaloneMac, - StandaloneWin10, - StandaloneItch, - IPhone, - Android, - Switch, + Unknown = 0, + StandaloneEpicPC = 1, + StandaloneSteamPC = 2, + StandaloneMac = 3, + StandaloneWin10 = 4, + StandaloneItch = 5, + IPhone = 6, + Android = 7, + Switch = 8, } } From 1d66f079069074c75fea015777e89347e927311a Mon Sep 17 00:00:00 2001 From: js6pak Date: Sat, 10 Apr 2021 17:14:17 +0200 Subject: [PATCH 64/72] Make vent data initialization much cleaner --- .../Game/Player/IPlayerEnterVentEvent.cs | 7 ++- .../Game/Player/IPlayerExitVentEvent.cs | 7 ++- .../Events/Game/Player/IPlayerVentEvent.cs | 7 ++- .../Extensions/DictionaryExtensions.cs | 16 +++++ src/Impostor.Api/Innersloth/IVent.cs | 19 ++++++ .../Innersloth/Maps/AirshipData.cs | 53 +++++++---------- src/Impostor.Api/Innersloth/Maps/IMapData.cs | 17 ++++++ src/Impostor.Api/Innersloth/Maps/MapData.cs | 24 -------- src/Impostor.Api/Innersloth/Maps/MiraData.cs | 50 +++++++--------- src/Impostor.Api/Innersloth/Maps/PolusData.cs | 53 +++++++---------- src/Impostor.Api/Innersloth/Maps/SkeldData.cs | 59 ++++++++----------- .../Innersloth/Maps/Vents/AirshipVent.cs | 38 +++++++++++- .../Innersloth/Maps/Vents/MiraVent.cs | 38 +++++++++++- .../Innersloth/Maps/Vents/PolusVent.cs | 38 +++++++++++- .../Innersloth/Maps/Vents/SkeldVent.cs | 38 +++++++++++- src/Impostor.Api/Innersloth/Vent.cs | 26 -------- .../Handlers/PlayerEventListener.cs | 4 +- .../Game/Player/PlayerEnterVentEvent.cs | 4 +- .../Events/Game/Player/PlayerExitVentEvent.cs | 4 +- .../Events/Game/Player/PlayerVentEvent.cs | 6 +- .../Objects/ShipStatus/InnerAirshipStatus.cs | 2 +- .../Objects/ShipStatus/InnerMiraShipStatus.cs | 2 +- .../ShipStatus/InnerPolusShipStatus.cs | 2 +- .../Objects/ShipStatus/InnerShipStatus.cs | 2 +- .../ShipStatus/InnerSkeldShipStatus.cs | 2 +- 25 files changed, 310 insertions(+), 208 deletions(-) create mode 100644 src/Impostor.Api/Extensions/DictionaryExtensions.cs create mode 100644 src/Impostor.Api/Innersloth/IVent.cs create mode 100644 src/Impostor.Api/Innersloth/Maps/IMapData.cs delete mode 100644 src/Impostor.Api/Innersloth/Maps/MapData.cs delete mode 100644 src/Impostor.Api/Innersloth/Vent.cs diff --git a/src/Impostor.Api/Events/Game/Player/IPlayerEnterVentEvent.cs b/src/Impostor.Api/Events/Game/Player/IPlayerEnterVentEvent.cs index dddcb3bf8..fac832b7d 100644 --- a/src/Impostor.Api/Events/Game/Player/IPlayerEnterVentEvent.cs +++ b/src/Impostor.Api/Events/Game/Player/IPlayerEnterVentEvent.cs @@ -2,11 +2,14 @@ namespace Impostor.Api.Events.Player { + /// + /// Called whenever a player enters a vent. + /// public interface IPlayerEnterVentEvent : IPlayerEvent { /// - /// Gets get the id of the used vent. + /// Gets the entered vent. /// - public Vent Vent { get; } + public IVent Vent { get; } } } diff --git a/src/Impostor.Api/Events/Game/Player/IPlayerExitVentEvent.cs b/src/Impostor.Api/Events/Game/Player/IPlayerExitVentEvent.cs index 516f80b7d..84dc1afcc 100644 --- a/src/Impostor.Api/Events/Game/Player/IPlayerExitVentEvent.cs +++ b/src/Impostor.Api/Events/Game/Player/IPlayerExitVentEvent.cs @@ -2,11 +2,14 @@ namespace Impostor.Api.Events.Player { + /// + /// Called whenever a player exits a vent. + /// public interface IPlayerExitVentEvent : IPlayerEvent { /// - /// Gets get the id of the used vent. + /// Gets the exited vent. /// - public Vent Vent { get; } + public IVent Vent { get; } } } diff --git a/src/Impostor.Api/Events/Game/Player/IPlayerVentEvent.cs b/src/Impostor.Api/Events/Game/Player/IPlayerVentEvent.cs index 0ab202d41..959e75342 100644 --- a/src/Impostor.Api/Events/Game/Player/IPlayerVentEvent.cs +++ b/src/Impostor.Api/Events/Game/Player/IPlayerVentEvent.cs @@ -2,11 +2,14 @@ namespace Impostor.Api.Events.Player { + /// + /// Called whenever a player moves to another vent. + /// public interface IPlayerVentEvent : IPlayerEvent { /// - /// Gets get the id of the used vent. + /// Gets the vent player moved to. /// - public Vent Vent { get; } + public IVent NewVent { get; } } } diff --git a/src/Impostor.Api/Extensions/DictionaryExtensions.cs b/src/Impostor.Api/Extensions/DictionaryExtensions.cs new file mode 100644 index 000000000..b8b682feb --- /dev/null +++ b/src/Impostor.Api/Extensions/DictionaryExtensions.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace Impostor.Api +{ + public static class DictionaryExtensions + { + /// Returns a read-only wrapper for the dictionary. + /// An object that acts as a read-only wrapper around the . + public static ReadOnlyDictionary AsReadOnly(this IDictionary dictionary) + where TKey : notnull + { + return new ReadOnlyDictionary(dictionary); + } + } +} diff --git a/src/Impostor.Api/Innersloth/IVent.cs b/src/Impostor.Api/Innersloth/IVent.cs new file mode 100644 index 000000000..4c697f624 --- /dev/null +++ b/src/Impostor.Api/Innersloth/IVent.cs @@ -0,0 +1,19 @@ +using System.Numerics; + +namespace Impostor.Api.Innersloth +{ + public interface IVent + { + int Id { get; } + + string Name { get; } + + Vector2 Position { get; } + + IVent? Left { get; } + + IVent? Center { get; } + + IVent? Right { get; } + } +} diff --git a/src/Impostor.Api/Innersloth/Maps/AirshipData.cs b/src/Impostor.Api/Innersloth/Maps/AirshipData.cs index 04657d00d..46504c9eb 100644 --- a/src/Impostor.Api/Innersloth/Maps/AirshipData.cs +++ b/src/Impostor.Api/Innersloth/Maps/AirshipData.cs @@ -5,45 +5,34 @@ namespace Impostor.Api.Innersloth.Maps { - public class AirshipData : MapData + public class AirshipData : IMapData { + private readonly IReadOnlyDictionary _vents; + public AirshipData() { - Vents = new[] + var vents = new[] { - new AirshipVent(AirshipVent.Ids.Vault, new Vector2(-12.6322f, 8.4735f)), - new AirshipVent(AirshipVent.Ids.Cockpit, new Vector2(-22.099f, -1.512f)), - new AirshipVent(AirshipVent.Ids.ViewingDeck, new Vector2(-15.659f, -11.6991f)), - new AirshipVent(AirshipVent.Ids.EngineRoom, new Vector2(0.203f, -2.5361f)), - new AirshipVent(AirshipVent.Ids.Kitchen, new Vector2(-2.6019f, -9.338f)), - new AirshipVent(AirshipVent.Ids.MainHallBottom, new Vector2(7.021f, -3.730999f)), - new AirshipVent(AirshipVent.Ids.GapRight, new Vector2(9.814f, 3.206f)), - new AirshipVent(AirshipVent.Ids.GapLeft, new Vector2(12.663f, 5.922f)), - new AirshipVent(AirshipVent.Ids.MainHallTop, new Vector2(3.605f, 6.923f)), - new AirshipVent(AirshipVent.Ids.Showers, new Vector2(23.9869f, -1.386f)), - new AirshipVent(AirshipVent.Ids.Records, new Vector2(23.2799f, 8.259998f)), - new AirshipVent(AirshipVent.Ids.CargoBay, new Vector2(30.4409f, -3.577f)), - }.ToDictionary(x => x.Id, x => (Vent)x); + new AirshipVent(this, AirshipVent.Ids.Vault, new Vector2(-12.6322f, 8.4735f), left: AirshipVent.Ids.Cockpit), + new AirshipVent(this, AirshipVent.Ids.Cockpit, new Vector2(-22.099f, -1.512f), left: AirshipVent.Ids.Vault, right: AirshipVent.Ids.ViewingDeck), + new AirshipVent(this, AirshipVent.Ids.ViewingDeck, new Vector2(-15.659f, -11.6991f), left: AirshipVent.Ids.Cockpit), + new AirshipVent(this, AirshipVent.Ids.EngineRoom, new Vector2(0.203f, -2.5361f), left: AirshipVent.Ids.Kitchen, right: AirshipVent.Ids.MainHallBottom), + new AirshipVent(this, AirshipVent.Ids.Kitchen, new Vector2(-2.6019f, -9.338f), left: AirshipVent.Ids.EngineRoom, right: AirshipVent.Ids.MainHallBottom), + new AirshipVent(this, AirshipVent.Ids.MainHallBottom, new Vector2(7.021f, -3.730999f), left: AirshipVent.Ids.EngineRoom, right: AirshipVent.Ids.Kitchen), + new AirshipVent(this, AirshipVent.Ids.GapRight, new Vector2(9.814f, 3.206f), left: AirshipVent.Ids.MainHallTop, right: AirshipVent.Ids.GapLeft), + new AirshipVent(this, AirshipVent.Ids.GapLeft, new Vector2(12.663f, 5.922f), left: AirshipVent.Ids.MainHallTop, right: AirshipVent.Ids.GapRight), + new AirshipVent(this, AirshipVent.Ids.MainHallTop, new Vector2(3.605f, 6.923f), left: AirshipVent.Ids.GapLeft, right: AirshipVent.Ids.GapRight), + new AirshipVent(this, AirshipVent.Ids.Showers, new Vector2(23.9869f, -1.386f), left: AirshipVent.Ids.Records, right: AirshipVent.Ids.CargoBay), + new AirshipVent(this, AirshipVent.Ids.Records, new Vector2(23.2799f, 8.259998f), left: AirshipVent.Ids.Showers, right: AirshipVent.Ids.CargoBay), + new AirshipVent(this, AirshipVent.Ids.CargoBay, new Vector2(30.4409f, -3.577f), left: AirshipVent.Ids.Showers, right: AirshipVent.Ids.Records), + }; - ConnectVents(AirshipVent.Ids.Vault, left: AirshipVent.Ids.Cockpit); - ConnectVents(AirshipVent.Ids.Cockpit, left: AirshipVent.Ids.Vault, right: AirshipVent.Ids.ViewingDeck); - ConnectVents(AirshipVent.Ids.ViewingDeck, left: AirshipVent.Ids.Cockpit); - ConnectVents(AirshipVent.Ids.EngineRoom, left: AirshipVent.Ids.Kitchen, right: AirshipVent.Ids.MainHallBottom); - ConnectVents(AirshipVent.Ids.Kitchen, left: AirshipVent.Ids.EngineRoom, right: AirshipVent.Ids.MainHallBottom); - ConnectVents(AirshipVent.Ids.MainHallBottom, left: AirshipVent.Ids.EngineRoom, right: AirshipVent.Ids.Kitchen); - ConnectVents(AirshipVent.Ids.GapRight, left: AirshipVent.Ids.MainHallTop, right: AirshipVent.Ids.GapLeft); - ConnectVents(AirshipVent.Ids.GapLeft, left: AirshipVent.Ids.MainHallTop, right: AirshipVent.Ids.GapRight); - ConnectVents(AirshipVent.Ids.MainHallTop, left: AirshipVent.Ids.GapLeft, right: AirshipVent.Ids.GapRight); - ConnectVents(AirshipVent.Ids.Showers, left: AirshipVent.Ids.Records, right: AirshipVent.Ids.CargoBay); - ConnectVents(AirshipVent.Ids.Records, left: AirshipVent.Ids.Showers, right: AirshipVent.Ids.CargoBay); - ConnectVents(AirshipVent.Ids.CargoBay, left: AirshipVent.Ids.Showers, right: AirshipVent.Ids.Records); + Vents = vents.ToDictionary(x => x.Id, x => x).AsReadOnly(); + _vents = vents.ToDictionary(x => (int)x.Id, x => (IVent)x).AsReadOnly(); } - public override IReadOnlyDictionary Vents { get; } + public IReadOnlyDictionary Vents { get; } - private void ConnectVents(AirshipVent.Ids vent, AirshipVent.Ids? left = null, AirshipVent.Ids? center = null, AirshipVent.Ids? right = null) - { - ConnectVents((int)vent, (int?)left, (int?)center, (int?)right); - } + IReadOnlyDictionary IMapData.Vents => _vents; } } diff --git a/src/Impostor.Api/Innersloth/Maps/IMapData.cs b/src/Impostor.Api/Innersloth/Maps/IMapData.cs new file mode 100644 index 000000000..8f94b38cd --- /dev/null +++ b/src/Impostor.Api/Innersloth/Maps/IMapData.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace Impostor.Api.Innersloth.Maps +{ + public interface IMapData + { + public static IReadOnlyDictionary Maps { get; } = new Dictionary + { + [MapTypes.Skeld] = new SkeldData(), + [MapTypes.MiraHQ] = new MiraData(), + [MapTypes.Polus] = new PolusData(), + [MapTypes.Airship] = new AirshipData(), + }.AsReadOnly(); + + IReadOnlyDictionary Vents { get; } + } +} diff --git a/src/Impostor.Api/Innersloth/Maps/MapData.cs b/src/Impostor.Api/Innersloth/Maps/MapData.cs deleted file mode 100644 index 53428f59a..000000000 --- a/src/Impostor.Api/Innersloth/Maps/MapData.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.Generic; - -namespace Impostor.Api.Innersloth.Maps -{ - public abstract class MapData - { - public static IReadOnlyDictionary Maps { get; } = new Dictionary - { - [MapTypes.Skeld] = new SkeldData(), - [MapTypes.MiraHQ] = new MiraData(), - [MapTypes.Polus] = new PolusData(), - [MapTypes.Airship] = new AirshipData(), - }; - - public abstract IReadOnlyDictionary Vents { get; } - - protected void ConnectVents(int vent, int? left = null, int? center = null, int? right = null) - { - Vents[vent].Left = left != null ? Vents[left.Value] : null; - Vents[vent].Center = center != null ? Vents[center.Value] : null; - Vents[vent].Right = right != null ? Vents[right.Value] : null; - } - } -} diff --git a/src/Impostor.Api/Innersloth/Maps/MiraData.cs b/src/Impostor.Api/Innersloth/Maps/MiraData.cs index 41f2c61fe..37ed2451f 100644 --- a/src/Impostor.Api/Innersloth/Maps/MiraData.cs +++ b/src/Impostor.Api/Innersloth/Maps/MiraData.cs @@ -5,43 +5,33 @@ namespace Impostor.Api.Innersloth.Maps { - public class MiraData : MapData + public class MiraData : IMapData { + private readonly IReadOnlyDictionary _vents; + public MiraData() { - Vents = new[] + var vents = new[] { - new MiraVent(MiraVent.Ids.Balcony, new Vector2(23.77f, -1.94f)), - new MiraVent(MiraVent.Ids.Cafeteria, new Vector2(23.9f, 7.18f)), - new MiraVent(MiraVent.Ids.Reactor, new Vector2(0.4800001f, 10.697f)), - new MiraVent(MiraVent.Ids.Laboratory, new Vector2(11.606f, 13.816f)), - new MiraVent(MiraVent.Ids.Office, new Vector2(13.28f, 20.13f)), - new MiraVent(MiraVent.Ids.Admin, new Vector2(22.39f, 17.23f)), - new MiraVent(MiraVent.Ids.Greenhouse, new Vector2(17.85f, 25.23f)), - new MiraVent(MiraVent.Ids.Medbay, new Vector2(15.41f, -1.82f)), - new MiraVent(MiraVent.Ids.Decontamination, new Vector2(6.83f, 3.145f)), - new MiraVent(MiraVent.Ids.LockerRoom, new Vector2(4.29f, 0.5299997f)), - new MiraVent(MiraVent.Ids.Launchpad, new Vector2(-6.18f, 3.56f)), - }.ToDictionary(x => x.Id, x => (Vent)x); + new MiraVent(this, MiraVent.Ids.Balcony, new Vector2(23.77f, -1.94f), left: MiraVent.Ids.Medbay, right: MiraVent.Ids.Cafeteria), + new MiraVent(this, MiraVent.Ids.Cafeteria, new Vector2(23.9f, 7.18f), left: MiraVent.Ids.Admin, right: MiraVent.Ids.Balcony), + new MiraVent(this, MiraVent.Ids.Reactor, new Vector2(0.4800001f, 10.697f), left: MiraVent.Ids.Laboratory, center: MiraVent.Ids.Decontamination, right: MiraVent.Ids.Launchpad), + new MiraVent(this, MiraVent.Ids.Laboratory, new Vector2(11.606f, 13.816f), left: MiraVent.Ids.Reactor, center: MiraVent.Ids.Decontamination, right: MiraVent.Ids.Office), + new MiraVent(this, MiraVent.Ids.Office, new Vector2(13.28f, 20.13f), left: MiraVent.Ids.Laboratory, center: MiraVent.Ids.Admin, right: MiraVent.Ids.Greenhouse), + new MiraVent(this, MiraVent.Ids.Admin, new Vector2(22.39f, 17.23f), left: MiraVent.Ids.Greenhouse, center: MiraVent.Ids.Cafeteria, right: MiraVent.Ids.Office), + new MiraVent(this, MiraVent.Ids.Greenhouse, new Vector2(17.85f, 25.23f), left: MiraVent.Ids.Admin, right: MiraVent.Ids.Office), + new MiraVent(this, MiraVent.Ids.Medbay, new Vector2(15.41f, -1.82f), left: MiraVent.Ids.Balcony, right: MiraVent.Ids.LockerRoom), + new MiraVent(this, MiraVent.Ids.Decontamination, new Vector2(6.83f, 3.145f), left: MiraVent.Ids.Reactor, center: MiraVent.Ids.LockerRoom, right: MiraVent.Ids.Laboratory), + new MiraVent(this, MiraVent.Ids.LockerRoom, new Vector2(4.29f, 0.5299997f), left: MiraVent.Ids.Medbay, center: MiraVent.Ids.Launchpad, right: MiraVent.Ids.Decontamination), + new MiraVent(this, MiraVent.Ids.Launchpad, new Vector2(-6.18f, 3.56f), left: MiraVent.Ids.Reactor, right: MiraVent.Ids.LockerRoom), + }; - ConnectVents(MiraVent.Ids.Balcony, left: MiraVent.Ids.Medbay, right: MiraVent.Ids.Cafeteria); - ConnectVents(MiraVent.Ids.Cafeteria, left: MiraVent.Ids.Admin, right: MiraVent.Ids.Balcony); - ConnectVents(MiraVent.Ids.Reactor, left: MiraVent.Ids.Laboratory, center: MiraVent.Ids.Decontamination, right: MiraVent.Ids.Launchpad); - ConnectVents(MiraVent.Ids.Laboratory, left: MiraVent.Ids.Reactor, center: MiraVent.Ids.Decontamination, right: MiraVent.Ids.Office); - ConnectVents(MiraVent.Ids.Office, left: MiraVent.Ids.Laboratory, center: MiraVent.Ids.Admin, right: MiraVent.Ids.Greenhouse); - ConnectVents(MiraVent.Ids.Admin, left: MiraVent.Ids.Greenhouse, center: MiraVent.Ids.Cafeteria, right: MiraVent.Ids.Office); - ConnectVents(MiraVent.Ids.Greenhouse, left: MiraVent.Ids.Admin, right: MiraVent.Ids.Office); - ConnectVents(MiraVent.Ids.Medbay, left: MiraVent.Ids.Balcony, right: MiraVent.Ids.LockerRoom); - ConnectVents(MiraVent.Ids.Decontamination, left: MiraVent.Ids.Reactor, center: MiraVent.Ids.LockerRoom, right: MiraVent.Ids.Laboratory); - ConnectVents(MiraVent.Ids.LockerRoom, left: MiraVent.Ids.Medbay, center: MiraVent.Ids.Launchpad, right: MiraVent.Ids.Decontamination); - ConnectVents(MiraVent.Ids.Launchpad, left: MiraVent.Ids.Reactor, right: MiraVent.Ids.LockerRoom); + Vents = vents.ToDictionary(x => x.Id, x => x).AsReadOnly(); + _vents = vents.ToDictionary(x => (int)x.Id, x => (IVent)x).AsReadOnly(); } - public override IReadOnlyDictionary Vents { get; } + public IReadOnlyDictionary Vents { get; } - private void ConnectVents(MiraVent.Ids vent, MiraVent.Ids? left = null, MiraVent.Ids? center = null, MiraVent.Ids? right = null) - { - ConnectVents((int)vent, (int?)left, (int?)center, (int?)right); - } + IReadOnlyDictionary IMapData.Vents => _vents; } } diff --git a/src/Impostor.Api/Innersloth/Maps/PolusData.cs b/src/Impostor.Api/Innersloth/Maps/PolusData.cs index 5748d26f1..76bc97043 100644 --- a/src/Impostor.Api/Innersloth/Maps/PolusData.cs +++ b/src/Impostor.Api/Innersloth/Maps/PolusData.cs @@ -5,45 +5,34 @@ namespace Impostor.Api.Innersloth.Maps { - public class PolusData : MapData + public class PolusData : IMapData { + private readonly IReadOnlyDictionary _vents; + public PolusData() { - Vents = new[] + var vents = new[] { - new PolusVent(PolusVent.Ids.Security, new Vector2(1.929f, -9.558001f)), - new PolusVent(PolusVent.Ids.Electrical, new Vector2(6.9f, -14.41f)), - new PolusVent(PolusVent.Ids.O2, new Vector2(3.51f, -16.58f)), - new PolusVent(PolusVent.Ids.Communications, new Vector2(12.304f, -18.898f)), - new PolusVent(PolusVent.Ids.Office, new Vector2(16.379f, -19.599f)), - new PolusVent(PolusVent.Ids.Admin, new Vector2(20.089f, -25.517f)), - new PolusVent(PolusVent.Ids.Laboratory, new Vector2(32.963f, -9.526f)), - new PolusVent(PolusVent.Ids.Lava, new Vector2(30.907f, -11.86f)), - new PolusVent(PolusVent.Ids.Storage, new Vector2(22f, -12.19f)), - new PolusVent(PolusVent.Ids.RightStabilizer, new Vector2(24.02f, -8.39f)), - new PolusVent(PolusVent.Ids.LeftStabilizer, new Vector2(9.64f, -7.72f)), - new PolusVent(PolusVent.Ids.OutsideAdmin, new Vector2(18.93f, -24.85f)), - }.ToDictionary(x => x.Id, x => (Vent)x); + new PolusVent(this, PolusVent.Ids.Security, new Vector2(1.929f, -9.558001f), left: PolusVent.Ids.O2, right: PolusVent.Ids.Electrical), + new PolusVent(this, PolusVent.Ids.Electrical, new Vector2(6.9f, -14.41f), left: PolusVent.Ids.O2, right: PolusVent.Ids.Security), + new PolusVent(this, PolusVent.Ids.O2, new Vector2(3.51f, -16.58f), left: PolusVent.Ids.Electrical, right: PolusVent.Ids.Security), + new PolusVent(this, PolusVent.Ids.Communications, new Vector2(12.304f, -18.898f), left: PolusVent.Ids.Storage, right: PolusVent.Ids.Office), + new PolusVent(this, PolusVent.Ids.Office, new Vector2(16.379f, -19.599f), left: PolusVent.Ids.Communications, right: PolusVent.Ids.Storage), + new PolusVent(this, PolusVent.Ids.Admin, new Vector2(20.089f, -25.517f), left: PolusVent.Ids.OutsideAdmin, right: PolusVent.Ids.Lava), + new PolusVent(this, PolusVent.Ids.Laboratory, new Vector2(32.963f, -9.526f), right: PolusVent.Ids.Lava), + new PolusVent(this, PolusVent.Ids.Lava, new Vector2(30.907f, -11.86f), left: PolusVent.Ids.Laboratory, right: PolusVent.Ids.Admin), + new PolusVent(this, PolusVent.Ids.Storage, new Vector2(22f, -12.19f), left: PolusVent.Ids.Communications, right: PolusVent.Ids.Office), + new PolusVent(this, PolusVent.Ids.RightStabilizer, new Vector2(24.02f, -8.39f), left: PolusVent.Ids.LeftStabilizer), + new PolusVent(this, PolusVent.Ids.LeftStabilizer, new Vector2(9.64f, -7.72f), left: PolusVent.Ids.RightStabilizer), + new PolusVent(this, PolusVent.Ids.OutsideAdmin, new Vector2(18.93f, -24.85f), right: PolusVent.Ids.Admin), + }; - ConnectVents(PolusVent.Ids.Security, left: PolusVent.Ids.O2, right: PolusVent.Ids.Electrical); - ConnectVents(PolusVent.Ids.Electrical, left: PolusVent.Ids.O2, right: PolusVent.Ids.Security); - ConnectVents(PolusVent.Ids.O2, left: PolusVent.Ids.Electrical, right: PolusVent.Ids.Security); - ConnectVents(PolusVent.Ids.Communications, left: PolusVent.Ids.Storage, right: PolusVent.Ids.Office); - ConnectVents(PolusVent.Ids.Office, left: PolusVent.Ids.Communications, right: PolusVent.Ids.Storage); - ConnectVents(PolusVent.Ids.Admin, left: PolusVent.Ids.OutsideAdmin, right: PolusVent.Ids.Lava); - ConnectVents(PolusVent.Ids.Laboratory, right: PolusVent.Ids.Lava); - ConnectVents(PolusVent.Ids.Lava, left: PolusVent.Ids.Laboratory, right: PolusVent.Ids.Admin); - ConnectVents(PolusVent.Ids.Storage, left: PolusVent.Ids.Communications, right: PolusVent.Ids.Office); - ConnectVents(PolusVent.Ids.RightStabilizer, left: PolusVent.Ids.LeftStabilizer); - ConnectVents(PolusVent.Ids.LeftStabilizer, left: PolusVent.Ids.RightStabilizer); - ConnectVents(PolusVent.Ids.OutsideAdmin, right: PolusVent.Ids.Admin); + Vents = vents.ToDictionary(x => x.Id, x => x).AsReadOnly(); + _vents = vents.ToDictionary(x => (int)x.Id, x => (IVent)x).AsReadOnly(); } - public override IReadOnlyDictionary Vents { get; } + public IReadOnlyDictionary Vents { get; } - private void ConnectVents(PolusVent.Ids vent, PolusVent.Ids? left = null, PolusVent.Ids? center = null, PolusVent.Ids? right = null) - { - ConnectVents((int)vent, (int?)left, (int?)center, (int?)right); - } + IReadOnlyDictionary IMapData.Vents => _vents; } } diff --git a/src/Impostor.Api/Innersloth/Maps/SkeldData.cs b/src/Impostor.Api/Innersloth/Maps/SkeldData.cs index b0bb95d95..6555ba1b9 100644 --- a/src/Impostor.Api/Innersloth/Maps/SkeldData.cs +++ b/src/Impostor.Api/Innersloth/Maps/SkeldData.cs @@ -5,49 +5,36 @@ namespace Impostor.Api.Innersloth.Maps { - public class SkeldData : MapData + public class SkeldData : IMapData { + private readonly IReadOnlyDictionary _vents; + public SkeldData() { - Vents = new[] + var vents = new[] { - new SkeldVent(SkeldVent.Ids.Admin, new Vector2(2.544f, -9.955201f)), - new SkeldVent(SkeldVent.Ids.RightHallway, new Vector2(9.384f, -6.438f)), - new SkeldVent(SkeldVent.Ids.Cafeteria, new Vector2(4.2588f, -0.276f)), - new SkeldVent(SkeldVent.Ids.Electrical, new Vector2(-9.7764f, -8.034f)), - new SkeldVent(SkeldVent.Ids.UpperEngine, new Vector2(-15.288f, 2.52f)), - new SkeldVent(SkeldVent.Ids.Security, new Vector2(-12.534f, -6.9492f)), - new SkeldVent(SkeldVent.Ids.Medbay, new Vector2(-10.608f, -4.176f)), - new SkeldVent(SkeldVent.Ids.Weapons, new Vector2(8.820001f, 3.324f)), - new SkeldVent(SkeldVent.Ids.LowerReactor, new Vector2(-20.796f, -6.9528f)), - new SkeldVent(SkeldVent.Ids.LowerEngine, new Vector2(-15.2508f, -13.656f)), - new SkeldVent(SkeldVent.Ids.Shields, new Vector2(9.5232f, -14.3376f)), - new SkeldVent(SkeldVent.Ids.UpperReactor, new Vector2(-21.876f, -3.0516f)), - new SkeldVent(SkeldVent.Ids.UpperNavigation, new Vector2(16.008f, -3.168f)), - new SkeldVent(SkeldVent.Ids.LowerNavigation, new Vector2(16.008f, -6.384f)), - }.ToDictionary(x => x.Id, x => (Vent)x); + new SkeldVent(this, SkeldVent.Ids.Admin, new Vector2(2.544f, -9.955201f), left: SkeldVent.Ids.Cafeteria, right: SkeldVent.Ids.RightHallway), + new SkeldVent(this, SkeldVent.Ids.RightHallway, new Vector2(9.384f, -6.438f), left: SkeldVent.Ids.Admin, right: SkeldVent.Ids.Cafeteria), + new SkeldVent(this, SkeldVent.Ids.Cafeteria, new Vector2(4.2588f, -0.276f), left: SkeldVent.Ids.Admin, right: SkeldVent.Ids.RightHallway), + new SkeldVent(this, SkeldVent.Ids.Electrical, new Vector2(-9.7764f, -8.034f), left: SkeldVent.Ids.Security, right: SkeldVent.Ids.Medbay), + new SkeldVent(this, SkeldVent.Ids.UpperEngine, new Vector2(-15.288f, 2.52f), left: SkeldVent.Ids.UpperReactor), + new SkeldVent(this, SkeldVent.Ids.Security, new Vector2(-12.534f, -6.9492f), left: SkeldVent.Ids.Medbay, right: SkeldVent.Ids.Electrical), + new SkeldVent(this, SkeldVent.Ids.Medbay, new Vector2(-10.608f, -4.176f), left: SkeldVent.Ids.Security, right: SkeldVent.Ids.Electrical), + new SkeldVent(this, SkeldVent.Ids.Weapons, new Vector2(8.820001f, 3.324f), right: SkeldVent.Ids.UpperNavigation), + new SkeldVent(this, SkeldVent.Ids.LowerReactor, new Vector2(-20.796f, -6.9528f), left: SkeldVent.Ids.LowerEngine), + new SkeldVent(this, SkeldVent.Ids.LowerEngine, new Vector2(-15.2508f, -13.656f), left: SkeldVent.Ids.LowerReactor), + new SkeldVent(this, SkeldVent.Ids.Shields, new Vector2(9.5232f, -14.3376f), left: SkeldVent.Ids.LowerNavigation), + new SkeldVent(this, SkeldVent.Ids.UpperReactor, new Vector2(-21.876f, -3.0516f), left: SkeldVent.Ids.UpperEngine), + new SkeldVent(this, SkeldVent.Ids.UpperNavigation, new Vector2(16.008f, -3.168f), right: SkeldVent.Ids.Weapons), + new SkeldVent(this, SkeldVent.Ids.LowerNavigation, new Vector2(16.008f, -6.384f), right: SkeldVent.Ids.Shields), + }; - ConnectVents(SkeldVent.Ids.Admin, left: SkeldVent.Ids.Cafeteria, right: SkeldVent.Ids.RightHallway); - ConnectVents(SkeldVent.Ids.RightHallway, left: SkeldVent.Ids.Admin, right: SkeldVent.Ids.Cafeteria); - ConnectVents(SkeldVent.Ids.Cafeteria, left: SkeldVent.Ids.Admin, right: SkeldVent.Ids.RightHallway); - ConnectVents(SkeldVent.Ids.Electrical, left: SkeldVent.Ids.Security, right: SkeldVent.Ids.Medbay); - ConnectVents(SkeldVent.Ids.UpperEngine, left: SkeldVent.Ids.UpperReactor); - ConnectVents(SkeldVent.Ids.Security, left: SkeldVent.Ids.Medbay, right: SkeldVent.Ids.Electrical); - ConnectVents(SkeldVent.Ids.Medbay, left: SkeldVent.Ids.Security, right: SkeldVent.Ids.Electrical); - ConnectVents(SkeldVent.Ids.Weapons, right: SkeldVent.Ids.UpperNavigation); - ConnectVents(SkeldVent.Ids.LowerReactor, left: SkeldVent.Ids.LowerEngine); - ConnectVents(SkeldVent.Ids.LowerEngine, left: SkeldVent.Ids.LowerReactor); - ConnectVents(SkeldVent.Ids.Shields, left: SkeldVent.Ids.LowerNavigation); - ConnectVents(SkeldVent.Ids.UpperReactor, left: SkeldVent.Ids.UpperEngine); - ConnectVents(SkeldVent.Ids.UpperNavigation, right: SkeldVent.Ids.Weapons); - ConnectVents(SkeldVent.Ids.LowerNavigation, right: SkeldVent.Ids.Shields); + Vents = vents.ToDictionary(x => x.Id, x => x).AsReadOnly(); + _vents = vents.ToDictionary(x => (int)x.Id, x => (IVent)x).AsReadOnly(); } - public override IReadOnlyDictionary Vents { get; } + public IReadOnlyDictionary Vents { get; } - private void ConnectVents(SkeldVent.Ids vent, SkeldVent.Ids? left = null, SkeldVent.Ids? center = null, SkeldVent.Ids? right = null) - { - ConnectVents((int)vent, (int?)left, (int?)center, (int?)right); - } + IReadOnlyDictionary IMapData.Vents => _vents; } } diff --git a/src/Impostor.Api/Innersloth/Maps/Vents/AirshipVent.cs b/src/Impostor.Api/Innersloth/Maps/Vents/AirshipVent.cs index 7605504c8..331469244 100644 --- a/src/Impostor.Api/Innersloth/Maps/Vents/AirshipVent.cs +++ b/src/Impostor.Api/Innersloth/Maps/Vents/AirshipVent.cs @@ -1,11 +1,25 @@ +using System; using System.Numerics; namespace Impostor.Api.Innersloth.Maps.Vents { - public class AirshipVent : Vent + public class AirshipVent : IVent { - internal AirshipVent(Ids id, Vector2 position) : base((int)id, id.ToString(), position) + private readonly Lazy? _left; + + private readonly Lazy? _center; + + private readonly Lazy? _right; + + internal AirshipVent(AirshipData data, Ids id, Vector2 position, Ids? left = null, Ids? center = null, Ids? right = null) { + Id = id; + Name = id.ToString(); + Position = position; + + _left = left == null ? null : new Lazy(() => data.Vents[left.Value]); + _center = center == null ? null : new Lazy(() => data.Vents[center.Value]); + _right = right == null ? null : new Lazy(() => data.Vents[right.Value]); } public enum Ids @@ -23,5 +37,25 @@ public enum Ids Records = 10, CargoBay = 11, } + + public Ids Id { get; } + + int IVent.Id => (int)Id; + + public string Name { get; } + + public Vector2 Position { get; } + + public AirshipVent? Left => _left?.Value; + + IVent? IVent.Left => Left; + + public AirshipVent? Center => _center?.Value; + + IVent? IVent.Center => Center; + + public AirshipVent? Right => _right?.Value; + + IVent? IVent.Right => Right; } } diff --git a/src/Impostor.Api/Innersloth/Maps/Vents/MiraVent.cs b/src/Impostor.Api/Innersloth/Maps/Vents/MiraVent.cs index 775401a35..81daddb18 100644 --- a/src/Impostor.Api/Innersloth/Maps/Vents/MiraVent.cs +++ b/src/Impostor.Api/Innersloth/Maps/Vents/MiraVent.cs @@ -1,11 +1,25 @@ +using System; using System.Numerics; namespace Impostor.Api.Innersloth.Maps.Vents { - public class MiraVent : Vent + public class MiraVent : IVent { - internal MiraVent(Ids id, Vector2 position) : base((int)id, id.ToString(), position) + private readonly Lazy? _left; + + private readonly Lazy? _center; + + private readonly Lazy? _right; + + internal MiraVent(MiraData data, Ids id, Vector2 position, Ids? left = null, Ids? center = null, Ids? right = null) { + Id = id; + Name = id.ToString(); + Position = position; + + _left = left == null ? null : new Lazy(() => data.Vents[left.Value]); + _center = center == null ? null : new Lazy(() => data.Vents[center.Value]); + _right = right == null ? null : new Lazy(() => data.Vents[right.Value]); } public enum Ids @@ -22,5 +36,25 @@ public enum Ids LockerRoom = 10, Launchpad = 11, } + + public Ids Id { get; } + + int IVent.Id => (int)Id; + + public string Name { get; } + + public Vector2 Position { get; } + + public MiraVent? Left => _left?.Value; + + IVent? IVent.Left => Left; + + public MiraVent? Center => _center?.Value; + + IVent? IVent.Center => Center; + + public MiraVent? Right => _right?.Value; + + IVent? IVent.Right => Right; } } diff --git a/src/Impostor.Api/Innersloth/Maps/Vents/PolusVent.cs b/src/Impostor.Api/Innersloth/Maps/Vents/PolusVent.cs index 8310af07b..54b542aff 100644 --- a/src/Impostor.Api/Innersloth/Maps/Vents/PolusVent.cs +++ b/src/Impostor.Api/Innersloth/Maps/Vents/PolusVent.cs @@ -1,11 +1,25 @@ +using System; using System.Numerics; namespace Impostor.Api.Innersloth.Maps.Vents { - public class PolusVent : Vent + public class PolusVent : IVent { - internal PolusVent(Ids id, Vector2 position) : base((int)id, id.ToString(), position) + private readonly Lazy? _left; + + private readonly Lazy? _center; + + private readonly Lazy? _right; + + internal PolusVent(PolusData data, Ids id, Vector2 position, Ids? left = null, Ids? center = null, Ids? right = null) { + Id = id; + Name = id.ToString(); + Position = position; + + _left = left == null ? null : new Lazy(() => data.Vents[left.Value]); + _center = center == null ? null : new Lazy(() => data.Vents[center.Value]); + _right = right == null ? null : new Lazy(() => data.Vents[right.Value]); } public enum Ids @@ -23,5 +37,25 @@ public enum Ids LeftStabilizer = 10, OutsideAdmin = 11, } + + public Ids Id { get; } + + int IVent.Id => (int)Id; + + public string Name { get; } + + public Vector2 Position { get; } + + public PolusVent? Left => _left?.Value; + + IVent? IVent.Left => Left; + + public PolusVent? Center => _center?.Value; + + IVent? IVent.Center => Center; + + public PolusVent? Right => _right?.Value; + + IVent? IVent.Right => Right; } } diff --git a/src/Impostor.Api/Innersloth/Maps/Vents/SkeldVent.cs b/src/Impostor.Api/Innersloth/Maps/Vents/SkeldVent.cs index e670a8d3d..747b6fdf9 100644 --- a/src/Impostor.Api/Innersloth/Maps/Vents/SkeldVent.cs +++ b/src/Impostor.Api/Innersloth/Maps/Vents/SkeldVent.cs @@ -1,11 +1,25 @@ +using System; using System.Numerics; namespace Impostor.Api.Innersloth.Maps.Vents { - public class SkeldVent : Vent + public class SkeldVent : IVent { - internal SkeldVent(Ids id, Vector2 position) : base((int)id, id.ToString(), position) + private readonly Lazy? _left; + + private readonly Lazy? _center; + + private readonly Lazy? _right; + + internal SkeldVent(SkeldData data, Ids id, Vector2 position, Ids? left = null, Ids? center = null, Ids? right = null) { + Id = id; + Name = id.ToString(); + Position = position; + + _left = left == null ? null : new Lazy(() => data.Vents[left.Value]); + _center = center == null ? null : new Lazy(() => data.Vents[center.Value]); + _right = right == null ? null : new Lazy(() => data.Vents[right.Value]); } public enum Ids @@ -25,5 +39,25 @@ public enum Ids UpperNavigation = 12, LowerNavigation = 13, } + + public Ids Id { get; } + + int IVent.Id => (int)Id; + + public string Name { get; } + + public Vector2 Position { get; } + + public SkeldVent? Left => _left?.Value; + + IVent? IVent.Left => Left; + + public SkeldVent? Center => _center?.Value; + + IVent? IVent.Center => Center; + + public SkeldVent? Right => _right?.Value; + + IVent? IVent.Right => Right; } } diff --git a/src/Impostor.Api/Innersloth/Vent.cs b/src/Impostor.Api/Innersloth/Vent.cs deleted file mode 100644 index 723207b28..000000000 --- a/src/Impostor.Api/Innersloth/Vent.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Numerics; - -namespace Impostor.Api.Innersloth -{ - public abstract class Vent - { - internal Vent(int id, string name, Vector2 position) - { - Id = id; - Name = name; - Position = position; - } - - public int Id { get; } - - public string Name { get; } - - public Vector2 Position { get; } - - public Vent? Left { get; internal set; } - - public Vent? Center { get; internal set; } - - public Vent? Right { get; internal set; } - } -} diff --git a/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs b/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs index fbef0f40b..999cfc174 100644 --- a/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs +++ b/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs @@ -103,13 +103,13 @@ public void OnPlayerEnterVentEvent(IPlayerEnterVentEvent e) [EventListener] public void OnPlayerExitVentEvent(IPlayerExitVentEvent e) { - _logger.LogInformation("Player {player} exit the vent in {vent}", e.PlayerControl.PlayerInfo.PlayerName, e.Vent.Name); + _logger.LogInformation("Player {player} exited the vent in {vent}", e.PlayerControl.PlayerInfo.PlayerName, e.Vent.Name); } [EventListener] public void OnPlayerVentEvent(IPlayerVentEvent e) { - _logger.LogInformation("Player {player} vented to {vent}", e.PlayerControl.PlayerInfo.PlayerName, e.Vent.Name); + _logger.LogInformation("Player {player} vented to {vent}", e.PlayerControl.PlayerInfo.PlayerName, e.NewVent.Name); } } } diff --git a/src/Impostor.Server/Events/Game/Player/PlayerEnterVentEvent.cs b/src/Impostor.Server/Events/Game/Player/PlayerEnterVentEvent.cs index 8e22eb6df..b072dc799 100644 --- a/src/Impostor.Server/Events/Game/Player/PlayerEnterVentEvent.cs +++ b/src/Impostor.Server/Events/Game/Player/PlayerEnterVentEvent.cs @@ -8,7 +8,7 @@ namespace Impostor.Server.Events.Player { public class PlayerEnterVentEvent : IPlayerEnterVentEvent { - public PlayerEnterVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl innerPlayerPhysics, Vent vent) + public PlayerEnterVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl innerPlayerPhysics, IVent vent) { Game = game; ClientPlayer = sender; @@ -22,6 +22,6 @@ public PlayerEnterVentEvent(IGame game, IClientPlayer sender, IInnerPlayerContro public IInnerPlayerControl PlayerControl { get; } - public Vent Vent { get; } + public IVent Vent { get; } } } diff --git a/src/Impostor.Server/Events/Game/Player/PlayerExitVentEvent.cs b/src/Impostor.Server/Events/Game/Player/PlayerExitVentEvent.cs index 93842b225..2343c708d 100644 --- a/src/Impostor.Server/Events/Game/Player/PlayerExitVentEvent.cs +++ b/src/Impostor.Server/Events/Game/Player/PlayerExitVentEvent.cs @@ -8,7 +8,7 @@ namespace Impostor.Server.Events.Player { public class PlayerExitVentEvent : IPlayerExitVentEvent { - public PlayerExitVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl innerPlayerPhysics, Vent vent) + public PlayerExitVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl innerPlayerPhysics, IVent vent) { Game = game; ClientPlayer = sender; @@ -22,6 +22,6 @@ public PlayerExitVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl public IInnerPlayerControl PlayerControl { get; } - public Vent Vent { get; } + public IVent Vent { get; } } } diff --git a/src/Impostor.Server/Events/Game/Player/PlayerVentEvent.cs b/src/Impostor.Server/Events/Game/Player/PlayerVentEvent.cs index 82a99cdf6..7cfdcd027 100644 --- a/src/Impostor.Server/Events/Game/Player/PlayerVentEvent.cs +++ b/src/Impostor.Server/Events/Game/Player/PlayerVentEvent.cs @@ -8,12 +8,12 @@ namespace Impostor.Server.Events.Player { public class PlayerVentEvent : IPlayerVentEvent { - public PlayerVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl innerPlayerPhysics, Vent vent) + public PlayerVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl innerPlayerPhysics, IVent vent) { Game = game; ClientPlayer = sender; PlayerControl = innerPlayerPhysics; - Vent = vent; + NewVent = vent; } public IGame Game { get; } @@ -22,6 +22,6 @@ public PlayerVentEvent(IGame game, IClientPlayer sender, IInnerPlayerControl inn public IInnerPlayerControl PlayerControl { get; } - public Vent Vent { get; } + public IVent NewVent { get; } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs index 84861b1a4..3ed285c10 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs @@ -16,7 +16,7 @@ public InnerAirshipStatus(Game game) : base(game) { } - public override MapData Data => MapData.Maps[MapTypes.Airship]; + public override IMapData Data => IMapData.Maps[MapTypes.Airship]; public override Dictionary Doors { get; } = new Dictionary(21); diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs index 143c98f77..6f1879de0 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs @@ -15,7 +15,7 @@ public InnerMiraShipStatus(Game game) : base(game) { } - public override MapData Data => MapData.Maps[MapTypes.MiraHQ]; + public override IMapData Data => IMapData.Maps[MapTypes.MiraHQ]; public override Dictionary Doors { get; } = new Dictionary(0); diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs index 7301bc44c..3274727ed 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs @@ -15,7 +15,7 @@ public InnerPolusShipStatus(Game game) : base(game) { } - public override MapData Data => MapData.Maps[MapTypes.Polus]; + public override IMapData Data => IMapData.Maps[MapTypes.Polus]; public override Dictionary Doors { get; } = new Dictionary(12); diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs index 0f7a4edd8..3dd2d5413 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs @@ -26,7 +26,7 @@ protected InnerShipStatus(Game game) : base(game) Components.Add(this); } - public abstract MapData Data { get; } + public abstract IMapData Data { get; } public abstract Dictionary Doors { get; } diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs index 6d04f5bb2..6670aad68 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs @@ -15,7 +15,7 @@ public InnerSkeldShipStatus(Game game) : base(game) { } - public override MapData Data { get; } = MapData.Maps[MapTypes.Skeld]; + public override IMapData Data { get; } = IMapData.Maps[MapTypes.Skeld]; public override Dictionary Doors { get; } = new Dictionary(13); From e941796a4c8f03a680a2882104efd229b0e77541 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sat, 10 Apr 2021 22:55:40 +0200 Subject: [PATCH 65/72] Bump version --- README.md | 3 ++- src/Directory.Build.props | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a2d2810ba..878ff9bef 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ Impostor is one of the first **Among Us** private servers, written in C#. |-|-|-|-| | 1.1.0 | 2020.09.07 - 2020.09.22 | No | [![Download](https://img.shields.io/badge/Download-v1.1.0-blue?style=flat-square)](https://github.com/Impostor/Impostor/releases/tag/v1.1.0) | | 1.2.2 | 2020.09.22 - 2020.11.17 | No | [![Download](https://img.shields.io/badge/Download-v1.2.2-blue?style=flat-square)](https://github.com/Impostor/Impostor/releases/tag/v1.2.2) | -| 1.3.0 | 2021.3.5 | Yes | [![Download](https://img.shields.io/badge/Download-master-blue?style=flat-square)](https://ci.appveyor.com/project/Impostor/Impostor/branch/master/artifacts) | +| 1.3.0 | 2021.3.5 | No | [![Download](https://img.shields.io/badge/Download-v1.3.0-blue?style=flat-square)](https://github.com/Impostor/Impostor/releases/tag/v1.3.0) | +| 1.4.0 | 2021.3.31 - 2021.4.2 | Yes | [![Download](https://img.shields.io/badge/Download-master-blue?style=flat-square)](https://ci.appveyor.com/project/Impostor/Impostor/branch/master/artifacts) | ## Features diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 10f1890ab..ffebcb926 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,6 +1,6 @@ - 1.3.0 + 1.4.0 dev From 8d27016cb76597001cb3a3b7b1792863b338ac0d Mon Sep 17 00:00:00 2001 From: js6pak Date: Sat, 10 Apr 2021 23:00:34 +0200 Subject: [PATCH 66/72] Fix xmldoc warnings --- src/Impostor.Api/Extensions/DictionaryExtensions.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Impostor.Api/Extensions/DictionaryExtensions.cs b/src/Impostor.Api/Extensions/DictionaryExtensions.cs index b8b682feb..39a19ec95 100644 --- a/src/Impostor.Api/Extensions/DictionaryExtensions.cs +++ b/src/Impostor.Api/Extensions/DictionaryExtensions.cs @@ -5,8 +5,11 @@ namespace Impostor.Api { public static class DictionaryExtensions { - /// Returns a read-only wrapper for the dictionary. - /// An object that acts as a read-only wrapper around the . + /// Returns a read-only wrapper for the dictionary. + /// An to create a from. + /// The type of the keys of . + /// The type of the values of . + /// An object that acts as a read-only wrapper around the . public static ReadOnlyDictionary AsReadOnly(this IDictionary dictionary) where TKey : notnull { From a56eed2680d807987bd993a54bbd38e76a228ac3 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 11 Apr 2021 14:57:29 +0200 Subject: [PATCH 67/72] Use actual disconnect message in ClientBase#DisconnectAsync --- src/Impostor.Api/Net/IHazelConnection.cs | 3 +- .../Net/Messages/S2C/MessageDisconnect.cs | 53 +++++++++++++++++++ src/Impostor.Server/Net/ClientBase.cs | 11 ++-- .../Net/Hazel/HazelConnection.cs | 4 +- .../Mocks/MockHazelConnection.cs | 2 +- 5 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 src/Impostor.Api/Net/Messages/S2C/MessageDisconnect.cs diff --git a/src/Impostor.Api/Net/IHazelConnection.cs b/src/Impostor.Api/Net/IHazelConnection.cs index e2a9cfbf9..c3ce51e15 100644 --- a/src/Impostor.Api/Net/IHazelConnection.cs +++ b/src/Impostor.Api/Net/IHazelConnection.cs @@ -35,7 +35,8 @@ public interface IHazelConnection /// Disconnects the client and invokes the disconnect handler. /// /// A reason. + /// A message to send with disconnect packet. /// Task that must be awaited. - ValueTask DisconnectAsync(string? reason); + ValueTask DisconnectAsync(string? reason, IMessageWriter? writer = null); } } diff --git a/src/Impostor.Api/Net/Messages/S2C/MessageDisconnect.cs b/src/Impostor.Api/Net/Messages/S2C/MessageDisconnect.cs new file mode 100644 index 000000000..8dd5c7f94 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/S2C/MessageDisconnect.cs @@ -0,0 +1,53 @@ +using System; +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.S2C +{ + public class MessageDisconnect + { + public static void Serialize(IMessageWriter writer, bool hasReason, DisconnectReason? reason, string? message) + { + writer.Write(hasReason); + + if (hasReason) + { + if (reason == null) + { + throw new ArgumentNullException(nameof(reason)); + } + + writer.StartMessage(0); + writer.Write((byte)reason); + + if (reason == DisconnectReason.Custom) + { + if (message == null) + { + throw new ArgumentNullException(nameof(message)); + } + + writer.Write(message); + } + + writer.EndMessage(); + } + } + + public static void Deserialize(IMessageReader reader, out bool hasReason, out DisconnectReason? reason, out string? message) + { + hasReason = reader.ReadBoolean(); + + if (hasReason) + { + var inner = reader.ReadMessage(); + reason = (DisconnectReason)inner.ReadByte(); + message = reason == DisconnectReason.Custom ? inner.ReadString() : null; + } + else + { + reason = null; + message = null; + } + } + } +} diff --git a/src/Impostor.Server/Net/ClientBase.cs b/src/Impostor.Server/Net/ClientBase.cs index 9874a7171..b9488c246 100644 --- a/src/Impostor.Server/Net/ClientBase.cs +++ b/src/Impostor.Server/Net/ClientBase.cs @@ -52,15 +52,10 @@ public async ValueTask DisconnectAsync(DisconnectReason reason, string? message return; } - using var packet = MessageWriter.Get(MessageType.Reliable); - Message01JoinGameS2C.SerializeError(packet, false, reason, message); + using var writer = MessageWriter.Get(); + MessageDisconnect.Serialize(writer, true, reason, message); - await Connection.SendAsync(packet); - - // Need this to show the correct message, otherwise it shows a generic disconnect message. - await Task.Delay(TimeSpan.FromMilliseconds(250)); - - await Connection.DisconnectAsync(message ?? reason.ToString()); + await Connection.DisconnectAsync(message ?? reason.ToString(), writer); } } } diff --git a/src/Impostor.Server/Net/Hazel/HazelConnection.cs b/src/Impostor.Server/Net/Hazel/HazelConnection.cs index e663dec1b..c59a91c2d 100644 --- a/src/Impostor.Server/Net/Hazel/HazelConnection.cs +++ b/src/Impostor.Server/Net/Hazel/HazelConnection.cs @@ -32,9 +32,9 @@ public ValueTask SendAsync(IMessageWriter writer) return InnerConnection.SendAsync(writer); } - public ValueTask DisconnectAsync(string? reason) + public ValueTask DisconnectAsync(string? reason, IMessageWriter? writer = null) { - return InnerConnection.Disconnect(reason); + return InnerConnection.Disconnect(reason, writer as MessageWriter); } public void DisposeInnerConnection() diff --git a/src/Impostor.Tools.ServerReplay/Mocks/MockHazelConnection.cs b/src/Impostor.Tools.ServerReplay/Mocks/MockHazelConnection.cs index 327296f12..c611c2949 100644 --- a/src/Impostor.Tools.ServerReplay/Mocks/MockHazelConnection.cs +++ b/src/Impostor.Tools.ServerReplay/Mocks/MockHazelConnection.cs @@ -23,7 +23,7 @@ public ValueTask SendAsync(IMessageWriter writer) return ValueTask.CompletedTask; } - public ValueTask DisconnectAsync(string reason) + public ValueTask DisconnectAsync(string reason, IMessageWriter writer = null) { return ValueTask.CompletedTask; } From bed46284983360a23e3c430a7812ffea8e526c81 Mon Sep 17 00:00:00 2001 From: 112batman Date: Fri, 8 Jan 2021 13:28:27 +0100 Subject: [PATCH 68/72] Add hostchanged event --- .../Events/Game/IGameHostChangeEvent.cs | 9 +++++++++ .../Events/Game/GameHostChangeEvent.cs | 19 +++++++++++++++++++ src/Impostor.Server/Net/State/Game.State.cs | 4 +++- 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/Impostor.Api/Events/Game/IGameHostChangeEvent.cs create mode 100644 src/Impostor.Server/Events/Game/GameHostChangeEvent.cs diff --git a/src/Impostor.Api/Events/Game/IGameHostChangeEvent.cs b/src/Impostor.Api/Events/Game/IGameHostChangeEvent.cs new file mode 100644 index 000000000..bfb8442d1 --- /dev/null +++ b/src/Impostor.Api/Events/Game/IGameHostChangeEvent.cs @@ -0,0 +1,9 @@ +using Impostor.Api.Net; + +namespace Impostor.Api.Events +{ + public interface IGameHostChangeEvent : IGameEvent + { + IClientPlayer Host { get; } + } +} diff --git a/src/Impostor.Server/Events/Game/GameHostChangeEvent.cs b/src/Impostor.Server/Events/Game/GameHostChangeEvent.cs new file mode 100644 index 000000000..93ec987c3 --- /dev/null +++ b/src/Impostor.Server/Events/Game/GameHostChangeEvent.cs @@ -0,0 +1,19 @@ +using Impostor.Api.Events; +using Impostor.Api.Games; +using Impostor.Api.Net; + +namespace Impostor.Server.Events +{ + public class GameHostChangeEvent : IGameHostChangeEvent + { + public GameHostChangeEvent(IGame game, IClientPlayer host) + { + Game = game; + Host = host; + } + + public IGame Game { get; } + + public IClientPlayer Host { get; } + } +} diff --git a/src/Impostor.Server/Net/State/Game.State.cs b/src/Impostor.Server/Net/State/Game.State.cs index 9f9d90473..6ab3c97b6 100644 --- a/src/Impostor.Server/Net/State/Game.State.cs +++ b/src/Impostor.Server/Net/State/Game.State.cs @@ -30,7 +30,7 @@ private async ValueTask PlayerAdd(ClientPlayer player) await _eventManager.CallAsync(new GamePlayerJoinedEvent(this, player)); } - private async ValueTask PlayerRemove(int playerId, bool isBan = false) + private async ValueTask PlayerRemove(int playerId, bool isBan = false) { if (!_players.TryRemove(playerId, out var player)) { @@ -121,6 +121,8 @@ private async ValueTask MigrateHost() // Pull players out of limbo. await CheckLimboPlayers(); } + + await _eventManager.CallAsync(new GameHostChangeEvent(this, Host)); } private async ValueTask CheckLimboPlayers() From e3db17400e7ec368b9ddeccd7a1d09179562700b Mon Sep 17 00:00:00 2001 From: 112batman Date: Mon, 15 Mar 2021 09:16:34 +0100 Subject: [PATCH 69/72] Add OldHost property, change name and fix typo --- .../{IGameHostChangeEvent.cs => IGameHostChangedEvent.cs} | 4 +++- .../{GameHostChangeEvent.cs => GameHostChangedEvent.cs} | 7 +++++-- src/Impostor.Server/Net/State/Game.State.cs | 5 ++--- 3 files changed, 10 insertions(+), 6 deletions(-) rename src/Impostor.Api/Events/Game/{IGameHostChangeEvent.cs => IGameHostChangedEvent.cs} (53%) rename src/Impostor.Server/Events/Game/{GameHostChangeEvent.cs => GameHostChangedEvent.cs} (54%) diff --git a/src/Impostor.Api/Events/Game/IGameHostChangeEvent.cs b/src/Impostor.Api/Events/Game/IGameHostChangedEvent.cs similarity index 53% rename from src/Impostor.Api/Events/Game/IGameHostChangeEvent.cs rename to src/Impostor.Api/Events/Game/IGameHostChangedEvent.cs index bfb8442d1..2f8339767 100644 --- a/src/Impostor.Api/Events/Game/IGameHostChangeEvent.cs +++ b/src/Impostor.Api/Events/Game/IGameHostChangedEvent.cs @@ -2,8 +2,10 @@ namespace Impostor.Api.Events { - public interface IGameHostChangeEvent : IGameEvent + public interface IGameHostChangedEvent : IGameEvent { IClientPlayer Host { get; } + + IClientPlayer OldHost { get; } } } diff --git a/src/Impostor.Server/Events/Game/GameHostChangeEvent.cs b/src/Impostor.Server/Events/Game/GameHostChangedEvent.cs similarity index 54% rename from src/Impostor.Server/Events/Game/GameHostChangeEvent.cs rename to src/Impostor.Server/Events/Game/GameHostChangedEvent.cs index 93ec987c3..a57277409 100644 --- a/src/Impostor.Server/Events/Game/GameHostChangeEvent.cs +++ b/src/Impostor.Server/Events/Game/GameHostChangedEvent.cs @@ -4,16 +4,19 @@ namespace Impostor.Server.Events { - public class GameHostChangeEvent : IGameHostChangeEvent + public class GameHostChangedEvent : IGameHostChangedEvent { - public GameHostChangeEvent(IGame game, IClientPlayer host) + public GameHostChangedEvent(IGame game, IClientPlayer host, IClientPlayer oldHost) { Game = game; Host = host; + OldHost = oldHost; } public IGame Game { get; } public IClientPlayer Host { get; } + + public IClientPlayer OldHost { get; } } } diff --git a/src/Impostor.Server/Net/State/Game.State.cs b/src/Impostor.Server/Net/State/Game.State.cs index 6ab3c97b6..91316986b 100644 --- a/src/Impostor.Server/Net/State/Game.State.cs +++ b/src/Impostor.Server/Net/State/Game.State.cs @@ -30,7 +30,7 @@ private async ValueTask PlayerAdd(ClientPlayer player) await _eventManager.CallAsync(new GamePlayerJoinedEvent(this, player)); } - private async ValueTask PlayerRemove(int playerId, bool isBan = false) + private async ValueTask PlayerRemove(int playerId, bool isBan = false) { if (!_players.TryRemove(playerId, out var player)) { @@ -64,6 +64,7 @@ private async ValueTask PlayerRemove(int playerId, bool isBan = false) if (HostId == playerId) { await MigrateHost(); + await _eventManager.CallAsync(new GameHostChangedEvent(this, this.Host, player)); } if (isBan) @@ -121,8 +122,6 @@ private async ValueTask MigrateHost() // Pull players out of limbo. await CheckLimboPlayers(); } - - await _eventManager.CallAsync(new GameHostChangeEvent(this, Host)); } private async ValueTask CheckLimboPlayers() From 0dedb73b08a2ffeb21cfc349503d826bcab92295 Mon Sep 17 00:00:00 2001 From: 112batman Date: Tue, 16 Mar 2021 06:50:35 +0100 Subject: [PATCH 70/72] Style fix, Rename OldHost --> PreviousHost, Rename Host --> NewHost --- src/Impostor.Api/Events/Game/IGameHostChangedEvent.cs | 4 ++-- .../Events/Game/GameHostChangedEvent.cs | 10 +++++----- src/Impostor.Server/Net/State/Game.State.cs | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Impostor.Api/Events/Game/IGameHostChangedEvent.cs b/src/Impostor.Api/Events/Game/IGameHostChangedEvent.cs index 2f8339767..178202fdd 100644 --- a/src/Impostor.Api/Events/Game/IGameHostChangedEvent.cs +++ b/src/Impostor.Api/Events/Game/IGameHostChangedEvent.cs @@ -4,8 +4,8 @@ namespace Impostor.Api.Events { public interface IGameHostChangedEvent : IGameEvent { - IClientPlayer Host { get; } + IClientPlayer PreviousHost { get; } - IClientPlayer OldHost { get; } + IClientPlayer NewHost { get; } } } diff --git a/src/Impostor.Server/Events/Game/GameHostChangedEvent.cs b/src/Impostor.Server/Events/Game/GameHostChangedEvent.cs index a57277409..65e236d6b 100644 --- a/src/Impostor.Server/Events/Game/GameHostChangedEvent.cs +++ b/src/Impostor.Server/Events/Game/GameHostChangedEvent.cs @@ -6,17 +6,17 @@ namespace Impostor.Server.Events { public class GameHostChangedEvent : IGameHostChangedEvent { - public GameHostChangedEvent(IGame game, IClientPlayer host, IClientPlayer oldHost) + public GameHostChangedEvent(IGame game, IClientPlayer previousHost, IClientPlayer newHost) { Game = game; - Host = host; - OldHost = oldHost; + PreviousHost = previousHost; + NewHost = newHost; } public IGame Game { get; } - public IClientPlayer Host { get; } + public IClientPlayer PreviousHost { get; } - public IClientPlayer OldHost { get; } + public IClientPlayer NewHost { get; } } } diff --git a/src/Impostor.Server/Net/State/Game.State.cs b/src/Impostor.Server/Net/State/Game.State.cs index 91316986b..eeafb6463 100644 --- a/src/Impostor.Server/Net/State/Game.State.cs +++ b/src/Impostor.Server/Net/State/Game.State.cs @@ -64,7 +64,7 @@ private async ValueTask PlayerRemove(int playerId, bool isBan = false) if (HostId == playerId) { await MigrateHost(); - await _eventManager.CallAsync(new GameHostChangedEvent(this, this.Host, player)); + await _eventManager.CallAsync(new GameHostChangedEvent(this, player, this.Host)); } if (isBan) From d0a7e47bd0cd8220354e10cc14fb3a88c0740b69 Mon Sep 17 00:00:00 2001 From: 112batman Date: Mon, 5 Apr 2021 07:09:13 +0200 Subject: [PATCH 71/72] NewHost nullable + style changes --- src/Impostor.Api/Events/Game/IGameHostChangedEvent.cs | 2 +- src/Impostor.Server/Events/Game/GameHostChangedEvent.cs | 2 +- src/Impostor.Server/Net/State/Game.State.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Impostor.Api/Events/Game/IGameHostChangedEvent.cs b/src/Impostor.Api/Events/Game/IGameHostChangedEvent.cs index 178202fdd..44709783a 100644 --- a/src/Impostor.Api/Events/Game/IGameHostChangedEvent.cs +++ b/src/Impostor.Api/Events/Game/IGameHostChangedEvent.cs @@ -6,6 +6,6 @@ public interface IGameHostChangedEvent : IGameEvent { IClientPlayer PreviousHost { get; } - IClientPlayer NewHost { get; } + IClientPlayer? NewHost { get; } } } diff --git a/src/Impostor.Server/Events/Game/GameHostChangedEvent.cs b/src/Impostor.Server/Events/Game/GameHostChangedEvent.cs index 65e236d6b..a9e1905ad 100644 --- a/src/Impostor.Server/Events/Game/GameHostChangedEvent.cs +++ b/src/Impostor.Server/Events/Game/GameHostChangedEvent.cs @@ -17,6 +17,6 @@ public GameHostChangedEvent(IGame game, IClientPlayer previousHost, IClientPlaye public IClientPlayer PreviousHost { get; } - public IClientPlayer NewHost { get; } + public IClientPlayer? NewHost { get; } } } diff --git a/src/Impostor.Server/Net/State/Game.State.cs b/src/Impostor.Server/Net/State/Game.State.cs index eeafb6463..ff7c2d8f6 100644 --- a/src/Impostor.Server/Net/State/Game.State.cs +++ b/src/Impostor.Server/Net/State/Game.State.cs @@ -64,7 +64,7 @@ private async ValueTask PlayerRemove(int playerId, bool isBan = false) if (HostId == playerId) { await MigrateHost(); - await _eventManager.CallAsync(new GameHostChangedEvent(this, player, this.Host)); + await _eventManager.CallAsync(new GameHostChangedEvent(this, player, Host)); } if (isBan) From becbeb39a755686019728d88882d3fcc1a45a6ef Mon Sep 17 00:00:00 2001 From: js6pak Date: Mon, 12 Apr 2021 22:44:51 +0200 Subject: [PATCH 72/72] Call when host is set to null --- .../Handlers/GameEventListener.cs | 11 +++++++++++ .../Events/Game/GameHostChangedEvent.cs | 2 +- src/Impostor.Server/Net/State/Game.State.cs | 17 ++++++++--------- src/Impostor.Server/Net/State/Game.cs | 5 ----- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/Impostor.Plugins.Example/Handlers/GameEventListener.cs b/src/Impostor.Plugins.Example/Handlers/GameEventListener.cs index eabbdf149..0125a19a1 100644 --- a/src/Impostor.Plugins.Example/Handlers/GameEventListener.cs +++ b/src/Impostor.Plugins.Example/Handlers/GameEventListener.cs @@ -49,6 +49,17 @@ public void OnGameDestroyed(IGameDestroyedEvent e) _logger.LogInformation("Game {code} > destroyed", e.Game.Code); } + [EventListener] + public void OnGameHostChanged(IGameHostChangedEvent e) + { + _logger.LogInformation( + "Game {code} > changed host from {previous} to {new}", + e.Game.Code, + e.PreviousHost.Character?.PlayerInfo.PlayerName, + e.NewHost != null ? e.NewHost.Character?.PlayerInfo.PlayerName : "none" + ); + } + [EventListener] public void OnPlayerJoined(IGamePlayerJoinedEvent e) { diff --git a/src/Impostor.Server/Events/Game/GameHostChangedEvent.cs b/src/Impostor.Server/Events/Game/GameHostChangedEvent.cs index a9e1905ad..3aa00f225 100644 --- a/src/Impostor.Server/Events/Game/GameHostChangedEvent.cs +++ b/src/Impostor.Server/Events/Game/GameHostChangedEvent.cs @@ -6,7 +6,7 @@ namespace Impostor.Server.Events { public class GameHostChangedEvent : IGameHostChangedEvent { - public GameHostChangedEvent(IGame game, IClientPlayer previousHost, IClientPlayer newHost) + public GameHostChangedEvent(IGame game, IClientPlayer previousHost, IClientPlayer? newHost) { Game = game; PreviousHost = previousHost; diff --git a/src/Impostor.Server/Net/State/Game.State.cs b/src/Impostor.Server/Net/State/Game.State.cs index ff7c2d8f6..a2105f146 100644 --- a/src/Impostor.Server/Net/State/Game.State.cs +++ b/src/Impostor.Server/Net/State/Game.State.cs @@ -50,8 +50,15 @@ private async ValueTask PlayerRemove(int playerId, bool isBan = false) player.Client.Player = null; + // Host migration. + if (HostId == playerId) + { + await MigrateHost(); + await _eventManager.CallAsync(new GameHostChangedEvent(this, player, Host)); + } + // Game is empty, remove it. - if (_players.IsEmpty) + if (_players.IsEmpty || Host == null) { GameState = GameStates.Destroyed; @@ -60,13 +67,6 @@ private async ValueTask PlayerRemove(int playerId, bool isBan = false) return true; } - // Host migration. - if (HostId == playerId) - { - await MigrateHost(); - await _eventManager.CallAsync(new GameHostChangedEvent(this, player, Host)); - } - if (isBan) { BanIp(player.Client.Connection.EndPoint.Address); @@ -98,7 +98,6 @@ private async ValueTask MigrateHost() if (host == null) { - await EndAsync(); return; } diff --git a/src/Impostor.Server/Net/State/Game.cs b/src/Impostor.Server/Net/State/Game.cs index 20f6c01b2..2d28eeadd 100644 --- a/src/Impostor.Server/Net/State/Game.cs +++ b/src/Impostor.Server/Net/State/Game.cs @@ -96,11 +96,6 @@ public bool TryGetPlayer(int id, [MaybeNullWhen(false)] out ClientPlayer player) return _players.TryGetValue(clientId, out var clientPlayer) ? clientPlayer : null; } - public ValueTask EndAsync() - { - return _gameManager.RemoveAsync(Code); - } - internal async ValueTask StartedAsync() { if (GameState == GameStates.Starting)