Sync Impostor with 6pak fork (#327)

Co-authored-by: DatGuy1 <datguysteam@gmail.com>
Co-authored-by: miniduikboot <5243971+miniduikboot@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2021-03-03 08:53:53 +00:00
1 parent f2d6531063
commit 87a062c1b3
123 files changed
+2472 -1405

No files matched your search

-17
View File
@@ -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
+2 -3
View File
@@ -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
+32 -58
View File
@@ -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\>(.*?)\<\/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>.*?<\/Version>", "<Version>" + buildVersion + "</Version>");
ReplaceRegexInFiles("./src/**/*.props", @"<Version>.*?<\/Version>", "<Version>" + buildVersion + "</Version>");
});
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);
// 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"
});
}
// API.
DotNetCorePack("./src/Impostor.Api/Impostor.Api.csproj", new DotNetCorePackSettings {
Configuration = configuration,
OutputDirectory = buildDir,
IncludeSource = true,
IncludeSymbols = true,
MSBuildSettings = msbuildSettings
});
});
Task("Test")
+2 -2
View File
@@ -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
-149
View File
@@ -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
+7
View File
@@ -0,0 +1,7 @@
<Project>
<PropertyGroup>
<VersionPrefix>1.2.2</VersionPrefix>
<VersionSuffix>dev</VersionSuffix>
</PropertyGroup>
</Project>
+20
View File
@@ -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());
}
}
@@ -0,0 +1,43 @@
using Impostor.Api.Innersloth;
namespace Impostor.Api.Events.Announcements
{
/// <summary>
/// Event fired after client requests a announcement.
/// </summary>
public interface IAnnouncementRequestEvent : IEvent
{
public interface IResponse
{
/// <summary>
/// Gets or sets FreeWeekendState, currently unused by the client.
/// </summary>
public FreeWeekendState FreeWeekendState { get; set; }
/// <summary>
/// Gets or sets a value indicating whether announcement should be loaded from client's cache, can save some bytes.
/// </summary>
public bool UseCached { get; set; }
/// <summary>
/// Gets or sets announcement, should be null when <see cref="UseCached"/> is set to true.
/// </summary>
public Announcement? Announcement { get; set; }
}
/// <summary>
/// Gets client's last announcement id.
/// </summary>
public int Id { get; }
/// <summary>
/// Gets client's language.
/// </summary>
public Language Language { get; }
/// <summary>
/// Gets or sets plugin made response.
/// </summary>
public IResponse Response { get; set; }
}
}
@@ -0,0 +1,6 @@
namespace Impostor.Api.Events.Player
{
public interface IPlayerMovementEvent : IPlayerEvent
{
}
}
@@ -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)
{
}
}
}
+3 -8
View File
@@ -4,7 +4,6 @@ using System.Threading.Tasks;
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 @@ namespace Impostor.Api.Games
IClientPlayer GetClientPlayer(int clientId);
T? FindObjectByNetId<T>(uint netId)
where T : IInnerNetObject;
/// <summary>
/// Adds an <see cref="IPAddress"/> to the ban list of this game.
/// Prevents all future joins from this <see cref="IPAddress"/>.
@@ -53,13 +55,6 @@ namespace Impostor.Api.Games
/// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns>
ValueTask SyncSettingsAsync();
/// <summary>
/// Sets the specified list as Impostor on all connected players.
/// </summary>
/// <param name="players">List of players to be Impostor.</param>
/// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns>
ValueTask SetInfectedAsync(IEnumerable<IInnerPlayerControl> players);
/// <summary>
/// Send the message to all players.
/// </summary>
+1 -3
View File
@@ -1,12 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
<CodeAnalysisRuleSet>ProjectRules.ruleset</CodeAnalysisRuleSet>
<LangVersion>9</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>enable</Nullable>
<Version>1.0.0</Version>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<AssemblyName>Impostor.Api</AssemblyName>
@@ -22,7 +21,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Bcl.HashCode" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
<PackageReference Include="Nullable" Version="1.3.0">
@@ -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;
}
}
}
@@ -1,6 +1,6 @@
namespace Impostor.Api.Innersloth.Customization
{
public enum HatType
public enum HatType : uint
{
NoHat = 0,
Astronaut = 1,
@@ -45,8 +45,8 @@
ThirdEyeHat = 40,
ToiletPaperHat = 41,
Toppat = 42,
Fedora = 43,
Goggles2 = 44,
BlackFedora = 43,
SkiGoggles = 44,
Headphones = 45,
MaskHat = 46,
PaperMask = 47,
@@ -58,7 +58,7 @@
Cheese = 53,
Cherry = 54,
Egg = 55,
Fedora2 = 56,
GreenFedora = 56,
Flamingo = 57,
FlowerPin = 58,
Helmet = 59,
@@ -95,6 +95,7 @@
MiniCrewmate = 90,
NinjaMask = 91,
RamHorns = 92,
Snowman2 = 93,
SnowCrewmate = 93,
GeoffHat = 94,
}
}
@@ -1,6 +1,6 @@
namespace Impostor.Api.Innersloth.Customization
{
public enum PetType
public enum PetType : uint
{
NoPet = 0,
Alien = 1,
@@ -1,6 +1,6 @@
namespace Impostor.Api.Innersloth.Customization
{
public enum SkinType : byte
public enum SkinType : uint
{
None = 0,
Astro = 1,
-22
View File
@@ -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);
}
}
@@ -0,0 +1,12 @@
using System;
namespace Impostor.Api.Innersloth
{
[Flags]
public enum FreeWeekendState : byte
{
NotFree,
FreeMIRA,
FreePolus,
}
}
@@ -161,7 +161,7 @@ namespace Impostor.Api.Innersloth
/// </summary>
/// <param name="writer">The stream to write the message to.</param>
/// <param name="version">The version of the game.</param>
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 @@ namespace Impostor.Api.Innersloth
}
}
public void Serialize(IMessageWriter writer)
{
using var memory = new MemoryStream();
using var writerBin = new BinaryWriter(memory);
Serialize(writerBin);
writer.WriteBytesAndSize(memory.ToArray());
}
/// <summary>
/// Deserialize a ReadOnlyMemory object to this instance of the GameOptionsData object.
/// </summary>
+11
View File
@@ -0,0 +1,11 @@
namespace Impostor.Api.Innersloth
{
public enum Language
{
English,
Spanish,
Portuguese,
Korean,
Russian,
}
}
+45
View File
@@ -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<MapTypes, MapSpawn> Maps { get; } = new Dictionary<MapTypes, MapSpawn>
{
[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));
}
}
}
+8
View File
@@ -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 @@ namespace Impostor.Api.Net
/// </remarks>
string Name { get; }
/// <summary>
/// Gets mods sent by client in modded handshake.
/// </summary>
ISet<Mod> Mods { get; }
/// <summary>
/// Gets the connection of the client.
/// </summary>
@@ -55,6 +61,8 @@ namespace Impostor.Api.Net
/// </summary>
IClientPlayer? Player { get; }
ValueTask<bool> ReportCheatAsync(CheatContext context, string message);
ValueTask HandleMessageAsync(IMessageReader message, MessageType messageType);
ValueTask HandleDisconnectAsync(string reason);
@@ -5,6 +5,16 @@ namespace Impostor.Api.Net.Inner.Objects.Components
{
public interface IInnerCustomNetworkTransform : IInnerNetObject
{
/// <summary>
/// Gets position where the object thinks it is (not interpolated).
/// </summary>
Vector2 Position { get; }
/// <summary>
/// Gets current object's velocity.
/// </summary>
Vector2 Velocity { get; }
/// <summary>
/// Snaps the current to the given position <see cref="IInnerPlayerControl"/>.
/// </summary>
@@ -41,48 +41,32 @@ namespace Impostor.Api.Net.Inner.Objects
/// Sets the color of the current <see cref="IInnerPlayerControl"/>.
/// Visible to all players.
/// </summary>
/// <param name="colorId">A color for the player.</param>
/// <returns>Task that must be awaited.</returns>
ValueTask SetColorAsync(byte colorId);
/// <param name="colorType">A color for the player.</param>
/// <inheritdoc cref="SetColorAsync(byte)" />
/// <returns>Task that must be awaited.</returns>
ValueTask SetColorAsync(ColorType colorType);
/// <summary>
/// Sets the hat of the current <see cref="IInnerPlayerControl"/>.
/// Visible to all players.
/// </summary>
/// <param name="hatId">An hat for the player.</param>
/// <returns>Task that must be awaited.</returns>
ValueTask SetHatAsync(uint hatId);
/// <param name="hatType">An hat for the player.</param>
/// <inheritdoc cref="SetHatAsync(uint)" />
/// <returns>Task that must be awaited.</returns>
ValueTask SetHatAsync(HatType hatType);
/// <summary>
/// Sets the pet of the current <see cref="IInnerPlayerControl"/>.
/// Visible to all players.
/// </summary>
/// <param name="petId">A pet for the player.</param>
/// <returns>Task that must be awaited.</returns>
ValueTask SetPetAsync(uint petId);
/// <param name="petType">A pet for the player.</param>
/// <inheritdoc cref="SetPetAsync(uint)" />
/// <returns>Task that must be awaited.</returns>
ValueTask SetPetAsync(PetType petType);
/// <summary>
/// Sets the skin of the current <see cref="IInnerPlayerControl"/>.
/// Visible to all players.
/// </summary>
/// <param name="skinId">A skin for the player.</param>
/// <returns>Task that must be awaited.</returns>
ValueTask SetSkinAsync(uint skinId);
/// <param name="skinType">A skin for the player.</param>
/// <inheritdoc cref="SetSkinAsync(uint)" />
/// <returns>Task that must be awaited.</returns>
ValueTask SetSkinAsync(SkinType skinType);
/// <summary>
@@ -106,11 +90,13 @@ namespace Impostor.Api.Net.Inner.Objects
ValueTask SendChatToPlayerAsync(string text, IInnerPlayerControl? player = null);
/// <summary>
/// Sets the current to be murdered by an impostor <see cref="IInnerPlayerControl"/>.
/// Visible to all players.
/// Murder <paramref name="target"/> player.
/// </summary>
/// /// <param name="impostor">The Impostor who kill.</param>
/// <param name="target">Target player to murder.</param>
/// <exception cref="ImpostorProtocolException">Thrown when player is not the impostor.</exception>
/// <exception cref="ImpostorProtocolException">Thrown when player is dead.</exception>
/// <exception cref="ImpostorProtocolException">Thrown when target is dead.</exception>
/// <returns>Task that must be awaited.</returns>
ValueTask SetMurderedByAsync(IClientPlayer impostor);
ValueTask MurderPlayerAsync(IInnerPlayerControl target);
}
}
@@ -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 @@ namespace Impostor.Api.Net.Inner.Objects
/// <summary>
/// Gets the color of the player.
/// </summary>
byte ColorId { get; }
ColorType Color { get; }
/// <summary>
/// Gets the hat of the player.
/// </summary>
uint HatId { get; }
HatType Hat { get; }
/// <summary>
/// Gets the pet of the player.
/// </summary>
uint PetId { get; }
PetType Pet { get; }
/// <summary>
/// Gets the skin of the player.
/// </summary>
uint SkinId { get; }
SkinType Skin { get; }
/// <summary>
/// Gets a value indicating whether the player is an impostor.
@@ -33,5 +33,6 @@
RepairSystem = 28,
SetTasks = 29,
UpdateGameData = 30,
CustomRpc = byte.MaxValue
}
}
@@ -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)
{
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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;
}
}
@@ -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 @@ namespace Impostor.Api.Net.Messages.C2S
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 @@ namespace Impostor.Api.Net.Messages.C2S
return GameOptionsData.DeserializeCreate(reader);
}
}
}
}
@@ -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 @@ namespace Impostor.Api.Net.Messages
float ReadSingle();
string ReadString(int length);
string ReadString();
ReadOnlyMemory<byte> ReadBytesAndSize();
@@ -64,5 +69,10 @@ namespace Impostor.Api.Net.Messages
void RemoveMessage(IMessageReader message);
IMessageReader Copy(int offset = 0);
T? ReadNetObject<T>(IGame game)
where T : IInnerNetObject;
Vector2 ReadVector2();
}
}
@@ -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 @@ namespace Impostor.Api.Net.Messages
void WriteBytesAndSize(byte[] bytes, int offset, int length);
void Write(IInnerNetObject innerNetObject);
void Write(Vector2 vector);
/// <summary>
/// Starts a new message.
/// </summary>
@@ -124,4 +130,4 @@ namespace Impostor.Api.Net.Messages
/// <param name="type">New type of the message.</param>
void Clear(MessageType type);
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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());
}
}
}
@@ -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<byte> infectedIds)
{
infectedIds = reader.ReadBytesAndSize();
}
}
}
@@ -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)
{
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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<IInnerPlayerControl>(game);
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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)
{
}
}
}
@@ -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<byte> states, out byte playerId, out bool tie)
{
states = reader.ReadBytesAndSize();
playerId = reader.ReadByte();
tie = reader.ReadBoolean();
}
}
}
@@ -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();
}
}
}
@@ -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)
{
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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<IInnerPlayerControl>(game);
amount = reader.ReadByte();
}
}
}
@@ -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<byte> taskTypeIds)
{
writer.Write(playerId);
writer.Write(taskTypeIds);
}
public static void Deserialize(IMessageReader reader, out byte playerId, out ReadOnlyMemory<byte> taskTypeIds)
{
playerId = reader.ReadByte();
taskTypeIds = reader.ReadBytesAndSize();
}
}
}
@@ -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();
}
}
}
+2 -1
View File
@@ -9,7 +9,8 @@
<Rule Id="SA1633" Action="None" />
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.ReadabilityRules">
<Rule Id="SA1101" Action="None" />
<Rule Id="SA1101" Action="None" />
<Rule Id="SA1111" Action="None" />
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.NamingRules">
<Rule Id="SA1309" Action="None" />
+21
View File
@@ -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})";
}
}
}
+24
View File
@@ -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<Mod> mods)
{
var length = reader.ReadPackedInt32();
mods = new HashSet<Mod>(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));
}
}
}
}
@@ -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<Mod>? mods)
{
clientVersion = reader.ReadInt32();
name = reader.ReadString();
if (reader.Length > reader.Position)
{
ModList.Deserialize(reader, out mods);
}
else
{
mods = null;
}
}
}
}
@@ -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();
}
}
}
+23
View File
@@ -0,0 +1,23 @@
namespace Impostor.Api.Reactor
{
/// <summary>
/// Plugin side used in modded handshake
/// </summary>
public enum PluginSide : byte
{
/// <summary>
/// Required by both sides, reject connection if missing on the other side
/// </summary>
Both,
/// <summary>
/// Required only by client
/// </summary>
ClientOnly,
/// <summary>
/// Required only by server
/// </summary>
ServerOnly,
}
}
+6 -1
View File
@@ -50,5 +50,10 @@
/// <para>The interpolated float result between the two float values.</para>
/// </returns>
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);
}
}
}
}
-1
View File
@@ -4,7 +4,6 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<TargetFramework>net5.0</TargetFramework>
<DefineConstants>HAZEL_BAG</DefineConstants>
<Version>1.0.0</Version>
</PropertyGroup>
<ItemGroup>
+25 -4
View File
@@ -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,12 +127,16 @@ namespace Impostor.Hazel
return output;
}
public string ReadString(int length)
{
var output = Encoding.UTF8.GetString(Buffer.AsSpan(ReadPosition, length));
Position += length;
return output;
}
public string ReadString()
{
var len = ReadPackedInt32();
var output = Encoding.UTF8.GetString(Buffer.AsSpan(ReadPosition, len));
Position += len;
return output;
return ReadString(ReadPackedInt32());
}
public ReadOnlyMemory<byte> ReadBytesAndSize()
@@ -239,6 +247,19 @@ namespace Impostor.Hazel
return reader;
}
public T ReadNetObject<T>(IGame game) where T : IInnerNetObject
{
return game.FindObjectByNetId<T>(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()
{
+21
View File
@@ -4,7 +4,10 @@ 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
{
@@ -89,6 +92,24 @@ namespace Impostor.Hazel
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)
{
@@ -309,9 +309,6 @@ namespace Impostor.Hazel.Udp
//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 @@ namespace Impostor.Hazel.Udp
* So...
*/
var result = true;
lock (reliableDataPacketsMissing)
{
//Calculate overwritePointer
@@ -379,12 +378,15 @@ namespace Impostor.Hazel.Udp
//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;
}
/// <summary>
@@ -143,7 +143,10 @@ namespace Impostor.Patcher.Shared
return false;
}
return WriteIp(ipAddress, port);
var result = WriteIp(ipAddress, port);
OnSaved(ip, port);
return result;
}
/// <summary>
@@ -176,7 +179,6 @@ namespace Impostor.Patcher.Shared
region.Serialize(writer);
OnSaved(ip, port);
return true;
}
}
@@ -2,7 +2,6 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<Version>1.0.0</Version>
</PropertyGroup>
<ItemGroup>
@@ -17,6 +17,7 @@ namespace Impostor.Plugins.Example
services.AddSingleton<IEventListener, GameEventListener>();
services.AddSingleton<IEventListener, PlayerEventListener>();
services.AddSingleton<IEventListener, MeetingEventListener>();
services.AddSingleton<IEventListener, AnnouncementsListener>();
}
}
}
@@ -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!");
}
}
}
}
@@ -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);
}
}
}
@@ -4,6 +4,8 @@
{
public const string Section = "AntiCheat";
public bool Enabled { get; set; } = true;
public bool BanIpFromGame { get; set; } = true;
}
}
}
@@ -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;
}
}
}
@@ -3,7 +3,6 @@ using System.Collections.Concurrent;
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 @@ namespace Impostor.Server.Events
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);
@@ -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 @@ namespace Impostor.Server.Events.Player
public IInnerPlayerControl PlayerControl { get; }
public string Message { get; }
public bool IsCancelled { get; set; }
}
}
@@ -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;
@@ -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<PlayerMovementEvent>
{
public PlayerMovementEvent Create()
{
return new PlayerMovementEvent();
}
public IInnerPlayerControl PlayerControl { get; }
public bool Return(PlayerMovementEvent obj)
{
obj.Reset();
return true;
}
}
}
}
@@ -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<T>(this IMessageReader reader, Game game)
where T : InnerNetObject
{
return game.FindObjectByNetId<T>(reader.ReadPackedUInt32());
}
}
}
@@ -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<ObjectPoolProvider>(new DefaultObjectPoolProvider());
services.AddSingleton(serviceProvider =>
{
var provider = serviceProvider.GetRequiredService<ObjectPoolProvider>();
var policy = ActivatorUtilities.CreateInstance<PlayerMovementEvent.PlayerMovementEventObjectPolicy>(serviceProvider);
return provider.Create(policy);
});
}
}
}
+3 -2
View File
@@ -16,7 +16,6 @@
<AssemblyTitle>Impostor.Server</AssemblyTitle>
<Product>Impostor.Server</Product>
<Copyright>Copyright © AeonLucid 2020</Copyright>
<Version>1.0.0</Version>
</PropertyGroup>
<ItemGroup>
@@ -35,6 +34,8 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<!-- HACK: Some plugins depend on System.IO.Pipelines and expect the version to be 5.0.0.0, but .NET 5 only ships version 5.0.0.1. It is pretty hard to convince MSBuild to build against the correct DLL, so we special case it here. Remove once we move past .NET 5 -->
<PackageReference Include="System.IO.Pipelines" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
@@ -55,4 +56,4 @@
</Content>
</ItemGroup>
</Project>
</Project>
@@ -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<MessageReader> _readerPool;
private readonly IEventManager _eventManager;
private UdpConnectionListener _connection;
public AnnouncementsService(IOptions<AnnouncementsServerConfig> config, ObjectPool<MessageReader> 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);
}
}
}
+37 -29
View File
@@ -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;
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 @@ namespace Impostor.Server.Net
private readonly ClientManager _clientManager;
private readonly GameManager _gameManager;
public Client(ILogger<Client> logger, IOptions<AntiCheatConfig> antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, IHazelConnection connection)
: base(name, connection)
public Client(ILogger<Client> logger, IOptions<AntiCheatConfig> antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, IHazelConnection connection, ISet<Mod> mods)
: base(name, connection, mods)
{
_logger = logger;
_antiCheatConfig = antiCheatOptions.Value;
@@ -31,6 +33,25 @@ namespace Impostor.Server.Net
_gameManager = gameManager;
}
public override async ValueTask<bool> 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 @@ namespace Impostor.Server.Net
// 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 @@ namespace Impostor.Server.Net
Message08EndGameC2S.Deserialize(
reader,
out var gameOverReason);
await Player.Game.HandleEndGame(reader, gameOverReason);
break;
}
+26 -1
View File
@@ -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<Mod> mods)
{
Name = name;
Connection = connection;
Mods = mods;
Items = new ConcurrentDictionary<object, object>();
ModIdMap = new Dictionary<int, string>();
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<Mod> Mods { get; }
public Dictionary<int, string> ModIdMap { get; }
public IHazelConnection Connection { get; }
public IDictionary<object, object> Items { get; }
@@ -32,6 +52,11 @@ namespace Impostor.Server.Net
IClientPlayer? IClient.Player => Player;
public virtual ValueTask<bool> ReportCheatAsync(CheatContext context, string message)
{
return new ValueTask<bool>(false);
}
public abstract ValueTask HandleMessageAsync(IMessageReader message, MessageType messageType);
public abstract ValueTask HandleDisconnectAsync(string reason);
@@ -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 @@ namespace Impostor.Server.Net.Factories
_serviceProvider = serviceProvider;
}
public ClientBase Create(IHazelConnection connection, string name, int clientVersion)
public ClientBase Create(IHazelConnection connection, string name, int clientVersion, ISet<Mod> mods)
{
var client = ActivatorUtilities.CreateInstance<TClient>(_serviceProvider, name, connection);
var client = ActivatorUtilities.CreateInstance<TClient>(_serviceProvider, name, connection, mods);
connection.Client = client;
return client;
}
@@ -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<Mod> mods);
}
}
@@ -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<bool> 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<bool> ValidateHost(CheatContext context, IClientPlayer sender)
{
if (!sender.IsHost)
{
if (await sender.Client.ReportCheatAsync(context, "Failed host check"))
{
return false;
}
}
return true;
}
protected async ValueTask<bool> 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<bool> 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<bool> 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<bool> 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<bool> UnregisteredCall(CheatContext context, IClientPlayer sender)
{
if (await sender.Client.ReportCheatAsync(context, "Client sent unregistered call"))
{
return false;
}
return true;
}
}
}
@@ -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 @@ using Impostor.Server.Net.State;
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 @@ namespace Impostor.Server.Net.Inner
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<bool> SerializeAsync(IMessageWriter writer, bool initialState);
public abstract ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState);
public abstract ValueTask<bool> HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader);
protected ValueTask<bool> 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);
}
}
}
}
@@ -11,12 +11,12 @@ namespace Impostor.Server.Net.Inner.Objects.Components
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);
}
@@ -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<InnerCustomNetworkTransform> _logger;
private readonly InnerPlayerControl _playerControl;
private readonly Game _game;
private readonly IEventManager _eventManager;
private readonly ObjectPool<PlayerMovementEvent> _pool;
private ushort _lastSequenceId;
private Vector2 _targetSyncPosition;
private Vector2 _targetSyncVelocity;
public InnerCustomNetworkTransform(ILogger<InnerCustomNetworkTransform> logger, InnerPlayerControl playerControl, Game game)
public Vector2 Position { get; private set; }
public Vector2 Velocity { get; private set; }
public InnerCustomNetworkTransform(ILogger<InnerCustomNetworkTransform> logger, InnerPlayerControl playerControl, Game game, IEventManager eventManager, ObjectPool<PlayerMovementEvent> 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<bool> 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<bool>(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<bool>(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 @@ namespace Impostor.Server.Net.Inner.Objects.Components
}
_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<bool> 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);
}
}
}
@@ -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 @@ namespace Impostor.Server.Net.Inner.Objects.Components
_game = game;
}
public override async ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader)
{
if (call != RpcCalls.EnterVent && call != RpcCalls.ExitVent)
{
_logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerPlayerPhysics), call);
return;
}
if (!sender.IsOwner(this))
{
throw new ImpostorCheatException($"Client sent {call} to an unowned {nameof(InnerPlayerControl)}");
}
if (target != null)
{
throw new ImpostorCheatException($"Client sent {call} to a specific player instead of broadcast");
}
if (!sender.Character.PlayerInfo.IsImpostor)
{
throw new ImpostorCheatException($"Client sent {call} as crewmate");
}
var ventId = reader.ReadPackedUInt32();
var ventEnter = call == RpcCalls.EnterVent;
await _eventManager.CallAsync(new PlayerVentEvent(_game, sender, _playerControl, (VentLocation)ventId, ventEnter));
return;
}
public override bool Serialize(IMessageWriter writer, bool initialState)
public override ValueTask<bool> SerializeAsync(IMessageWriter writer, bool initialState)
{
throw new NotImplementedException();
}
public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
public override ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
{
throw new NotImplementedException();
}
public override async ValueTask<bool> HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader)
{
if (!await ValidateOwnership(call, sender) || !await ValidateImpostor(RpcCalls.MurderPlayer, sender, _playerControl.PlayerInfo))
{
return false;
}
int ventId;
switch (call)
{
case RpcCalls.EnterVent:
Rpc19EnterVent.Deserialize(reader, out ventId);
break;
case RpcCalls.ExitVent:
Rpc19EnterVent.Deserialize(reader, out ventId);
break;
case RpcCalls.CustomRpc:
return await HandleCustomRpc(reader, _game);
default:
return await UnregisteredCall(call, sender);
}
await _eventManager.CallAsync(new PlayerVentEvent(_game, sender, _playerControl, (VentLocation)ventId, call == RpcCalls.EnterVent));
return true;
}
}
}
Loaded 100 of 123 files, more files were not shown because too many files have changed in this diff. Show more