Compare commits

...
49 Commits
Author SHA1 Message Date
miniduikboot b31e3bf1e3 Add network version for 2023.2.28 2023-03-02 20:04:40 +01:00
miniduikboot c9bb8323f4 Add missing game keywords
These have been added in 2021.6.30, but this has only now been
problematic because Impostor.Http requires this array to be accurate
2023-02-14 23:29:25 +01:00
miniduikboot 1521410e79 Add a warning for using the default PublicIp
This is a misconfiguration in most cases and it breaks Impostor.Http.
Throw a warning so that people know that they should return to the
install instructions.
2023-02-14 23:26:32 +01:00
miniduikboot be8e4a49f0 Merge pull request #512 from Impostor/fix/docs-n-docker
Various improvements to the Dockerfile and the docs
2023-02-14 23:26:09 +01:00
miniduikboot 631e994759 Prepare for 1.8.1
This will be a release focused on setup convenience
2023-01-30 00:06:18 +01:00
miniduikboot c06916084e Rewrite Running-the-server.md
- Multi-server is removed from the intro
- Add Impostor.Http stuff
- Stress the importance of public ip
2023-01-30 00:04:55 +01:00
miniduikboot c9c044365a Dockerfile: install Http plugin in separate folder
Some people mount a folder on the plugin directory. This is fine, but
our sneaky Impostor.Http install method won't work here. So put it in a
different folder and prepend our folder to the plugin search path.

The number 76 has been randomly picked using dice
2023-01-29 22:58:30 +01:00
miniduikboot 5ab4bf70da Dockerfile: [[ -> [
[[ is a bash extension and is not supported by posix sh, throwing an
error. [ is supported and does enough
2023-01-29 22:57:05 +01:00
bkloosterboer 58c8bdec26 systemd template and instructions (#508)
* systemd template and instructions

* clarify some intsructions, change a few systemd paramters

* change targets
2023-01-22 23:29:22 +01:00
miniduikboot 5e080b290b Add Impostor.Http to the Docker image (#509)
Adding plugins to the docker image is pretty hard as you need to install
ASP.Net Core and add the plugin. As Impostor.Http has become pretty much
mandatory, install the plugin by default.
2023-01-20 15:25:22 +01:00
miniduikbootandjs6pak 97390a0882 Automatically add ASP.NET Core to the library path (#507)
Currently Impostor.Http is becoming an almost mandatory plugin. Because
it depends on ASP.Net, many people who fail to add the required path to
their config will run into an error. Help them by automatically adding
ASP.NET Core.

Also .NET updates every now and then and updating the version number in
the config.json is annoying me.

This commit uses the fact that ASP.NET Core DLL's are in a sibling folder
to the .NET runtime and should therefore work on most setups unless
they've installed ASP.NET Core in a very weird way.

* Fix casing

Co-authored-by: js6pak <kubastaron@hotmail.com>
2023-01-20 15:23:33 +01:00
js6pak 23499929fb Merge pull request #504 from Impostor/fix/dead-impostor-sabotage 2023-01-07 15:47:41 +01:00
js6pak 579f618ac6 Merge pull request #503 from Impostor/fix-game-start 2023-01-07 15:47:28 +01:00
miniduikboot 6962d01dbd Allow sabotages by dead impostors
2021.12.8+ sets the role of dead players to {Crewmate,Impostor}Ghost, so
relax the anticheat to allow sabotages by ImpostorGhosts
2023-01-07 14:11:06 +01:00
js6pak 0fb6556365 Ignore the role in InnerPlayerInfo.Deserialize 2023-01-06 19:52:07 +01:00
js6pak 9cd5de6a36 Expose RoleType in api 2023-01-06 19:38:33 +01:00
js6pak 94015d475d Mark the game as started only after all players get their role 2023-01-06 19:38:19 +01:00
js6pak 11bb2dec47 Merge pull request #501 from Impostor/feature/2022.12.8 2022-12-29 18:02:15 +01:00
js6pak e7d745608e Fix xmldoc warnings 2022-12-29 17:49:15 +01:00
js6pak a1120f8468 Fix CrossplayFlags 2022-12-20 15:25:19 +01:00
js6pak 1fa684d843 Fix formatting 2022-12-20 14:36:31 +01:00
js6pak fac4103d70 Fix Message00HostGameS2C signature 2022-12-20 14:35:34 +01:00
AeonLucid 3b5b538b39 Correct api game manager interfaces 2022-12-19 22:44:36 +01:00
AeonLucid 62f8a7099d Lowercase rpc 2022-12-19 16:01:24 +01:00
AeonLucid f8b3bf7295 Log of correct reader 2022-12-19 15:59:14 +01:00
AeonLucid 4e5edcee49 Add warning when not consuming all bytes of a logic component 2022-12-19 15:55:27 +01:00
AeonLucid 5a8927e4c9 Clean up unused serialization and expose two HideAndSeek floats in api 2022-12-19 15:34:55 +01:00
AeonLucid 752b155152 Packages lock 2022-12-19 02:55:41 +01:00
AeonLucid 5a1f1c9d86 Add FilterOptions to Game and use in FindListings 2022-12-19 02:39:03 +01:00
AeonLucid adb74f628c Fix SyncSettingsAsync 2022-12-19 02:24:51 +01:00
AeonLucid c106695707 Fix incorrect data types for NormalGameOptions 2022-12-19 02:24:33 +01:00
AeonLucid a7fb2b8b19 Use DeserializeInto over Deserialize 2022-12-19 01:12:52 +01:00
AeonLucid d4ac24ae17 Added game manager net object and logic classes 2022-12-19 00:56:03 +01:00
AeonLucid e0b85c959b Log MessageFlag name instead of numbers 2022-12-18 23:52:01 +01:00
miniduikboot 980d172d4f Add Pet and CancelPet RPC's 2022-12-18 22:45:56 +01:00
js6pakandminiduikboot 8dfa38b4b5 Implement new GameOptions system
Co-authored-by: miniduikboot <mini@duikbo.at>
2022-12-18 22:45:56 +01:00
miniduikboot d1ac9301be Bump to 1.8.0 and drop backwards compatibility 2022-12-18 22:45:56 +01:00
js6pak d667f99c9f Remove redirector (#502) 2022-12-18 22:44:25 +01:00
AeonLucid 679bfecb42 Merge pull request #500 from Impostor/net7-nugethazel
Upgrade to net7.0 and move hazel to nuget
2022-12-18 21:55:41 +01:00
AeonLucid 519bae28b5 Update hazel package references to 1.0.0 2022-12-18 21:49:10 +01:00
js6pak e5db56317a Fix imports 2022-12-18 20:34:46 +01:00
js6pak ed89e00f3a Switch hazel from submodule to nuget 2022-12-18 20:34:45 +01:00
js6pak d5165a79f1 Upgrade to net7.0 2022-12-18 20:34:45 +01:00
miniduikboot 7bb7d2178b Correct location of Right Stabilizer vent on Polus
I've checked all game vents and this seems to be the only one that
changed.

Fixes: #495
2022-12-07 19:33:50 +01:00
miniduikboot 39b7d626dc Remove anticheat log when anticheat is disabled
Fixes #456
2022-11-01 08:03:53 +01:00
miniduikboot 116bb3cda4 Bump to 1.7.3
Because we can keep compatibility, only do a minor version bump
2022-10-23 16:53:02 +02:00
miniduikboot 8fe5c2205e Add 2022.10.25 2022-10-23 16:53:02 +02:00
miniduikboot a418e1f15a Add version id for 2022.10.18 2022-10-23 16:53:02 +02:00
miniduikboot a7cff4aef1 Add Airship to MapFlags
CC https://github.com/Impostor/Impostor.Http/pull/3
2022-09-14 21:30:05 +02:00
179 changed files with 3063 additions and 5056 deletions

No files matched your search

+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 6.x
dotnet-version: 7.x
- name: Run the Cake script
uses: cake-build/cake-action@v1
-3
View File
@@ -1,3 +0,0 @@
[submodule "src/Impostor.Hazel"]
path = src/Impostor.Hazel
url = https://github.com/Impostor/Impostor.Hazel
+15 -7
View File
@@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:6.0 AS build
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:7.0 AS build
# See for all possible platforms
# https://github.com/containerd/containerd/blob/master/platforms/platforms.go#L17
@@ -11,7 +11,6 @@ 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/Hazel/Hazel.csproj ./src/Impostor.Hazel/Hazel/Hazel.csproj
COPY src/Directory.Build.props ./src/Directory.Build.props
RUN case "$TARGETARCH" in \
@@ -21,8 +20,7 @@ RUN case "$TARGETARCH" in \
*) echo "unsupported architecture"; exit 1 ;; \
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/Hazel/Hazel.csproj
dotnet restore -r "$NETCORE_PLATFORM" ./src/Impostor.Api/Impostor.Api.csproj
# Copy everything else.
COPY src/. ./src/
@@ -32,12 +30,22 @@ RUN case "$TARGETARCH" in \
arm) NETCORE_PLATFORM='linux-arm';; \
*) echo "unsupported architecture"; exit 1 ;; \
esac && \
[[ $VERSIONSUFFIX = "none" ]] && VERSIONSUFFIX=; \
[ $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 --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/runtime:6.0
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:7.0
WORKDIR /app
COPY --from=build /app ./
EXPOSE 22023/udp
# Add Impostor.Http as a default built-in plugin
ADD https://github.com/Impostor/Impostor.Http/releases/download/v0.4.0/Impostor.Http.dll /app/builtin-plugins/
# Make it listen to 0.0.0.0 to expose it to the outside world.
ENV IMPOSTOR_HTTP_HttpServer__ListenIp=0.0.0.0
# Override ASPNETCORE_URLS to stop warning.
ENV ASPNETCORE_URLS=
# Enable the built-in plugin folder. Use a high number to prevent conflicts with existing configurations
ENV IMPOSTOR_PluginLoader__Paths__76=/app/builtin-plugins
EXPOSE 22000/tcp 22023/udp
ENTRYPOINT ["./Impostor.Server"]
+2 -2
View File
@@ -1,6 +1,6 @@
# Building from source
The solution contains the Impostor server and its dependencies, like Hazel and the plugin API. The server is built using [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0).
The solution contains the Impostor server and its dependencies, like Hazel and the plugin API. The server is built using [.NET 7](https://dotnet.microsoft.com/download/dotnet/7.0).
## Cloning Impostor
@@ -14,7 +14,7 @@ git clone https://github.com/Impostor/Impostor.git
### Dependencies
- [.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet/6.0)
- [.NET 7 SDK](https://dotnet.microsoft.com/download/dotnet/7.0)
- [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
+34 -75
View File
@@ -1,34 +1,50 @@
# Running the server
There are currently two modes to run the Impostor server. The first way, Single Server, is the simplest one, can handle up to a few hundred simultaneous players, and is the one you should probably use. Multi-Server mode will distribute players across other servers and is intended for advanced users.
There are currently two install methods for Impostor: You can install it normally or inside of a Docker container. If you do not have a particular preference, we recommend the normal installation over the Docker container method.
## Single server
## General remarks for both install methods
### Without Docker
This section applies to both the normal installation as well as the Docker (Compose) installation
1. Install the [.NET 6.0 runtime](https://dotnet.microsoft.com/download/dotnet/6.0). Installing the SDK also works, but is not necessary unless you plan on developing Impostor or Impostor plugins. If you're asked to pick between the normal, desktop or server runtime, the normal runtime is enough, but some plugins may require the ASP.NET Core Runtime as well.
2. Find the [latest release](https://github.com/Impostor/Impostor/releases) or the [latest CI build](https://nightly.link/Impostor/Impostor/workflows/ci/master).
3. Download the version for your OS (linux/win/osx). Impostor is built for multiple CPU-architectures, you most likely want the x64 version, unless you are running on a Raspberry Pi or another device with an ARM processor.
4. Extract the zip.
5. Modify `config.json` to your liking. Documentation can be found [here](Server-configuration.md) _(this step is mandatory if you want to expose this server to other devices)_
To connect to the server, you need to configure and install a region file on https://impostor.github.io/Impostor/
Depending on your host you may also need to port forward Impostor to the internet or pass Impostor traffic by your firewall. By default Impostor uses two ports:
- Port **22023** using the **UDP** protocol
- Port **22000** using the **TCP** protocol
As port forwarding changes per host or router configuration, port forwarding is not covered by this guide.
## Normal installation
1. Install [.NET 7.0](https://dotnet.microsoft.com/download/dotnet/7.0). We recommend either the ASP.NET Core Runtime or the SDK. The SDK is necessary in case you want to develop Impostor or Impostor plugins.
2. Download the [latest release](https://github.com/Impostor/Impostor/releases) or the [latest CI build](https://nightly.link/Impostor/Impostor/workflows/ci/master). Note that Impostor is built for multiple CPU-architectures and operating systems, you most likely want the x64 version, unless you are running on a Raspberry Pi or another device with an ARM processor.
3. Extract the zip.
4. Download the [Impostor.Http](https://github.com/Impostor/Impostor.Http) plugin and put it in your `plugins` folder.
5. Modify `config.json` to your liking. Documentation can be found [here](Server-configuration.md). You need to at least change `PublicIp` to the address people will connect to your server to.
6. Run `Impostor.Server` (Linux/macOS) or `Impostor.Server.exe` (Windows)
7. (OPTIONAL - Linux) Configure a systemd definition file and enable the service to start on boot - [systemd configuration](Server-configuration.md#systemd)
Depending on your host you may also need to port forward Impostor to the internet. By default Impostor uses port **22023** and the **UDP** protocol. As port forwarding changes per host or router configuration, port forwarding is not covered by this guide.
To connect to the server, you need to configure a region file on https://impostor.github.io/Impostor/
### Using Docker
## Using Docker
[![Docker Image](https://img.shields.io/docker/v/aeonlucid/impostor?sort=semver)](https://hub.docker.com/r/aeonlucid/impostor)
[![Docker Image](https://img.shields.io/docker/v/aeonlucid/impostor/nightly)](https://hub.docker.com/r/aeonlucid/impostor)
Docker is a program that allows you to run programs like Impostor in a container.
After installing Docker, you can just start a Docker container with `docker run`:
```
docker run -p 22023:22023/udp aeonlucid/impostor:nightly
docker run -p 22000:22000/tcp -p 22023:22023/udp -e IMPOSTOR_Server__PublicIp=your.public.ip.here aeonlucid/impostor:nightly
```
### Using Docker Compose
Please replace `your.public.ip.here` with the public IP address of your server. This is the address Among Us will try to reach your client at.
To configure the docker container, either use environment variables or mount config.json in your container.
## Using Docker Compose
Docker Compose allows you to start a Docker container using a prefined configuration. This is an example configuration you can continue on:
```
version: '3.4'
@@ -38,69 +54,12 @@ services:
image: aeonlucid/impostor:nightly
container_name: impostor
ports:
- 22000:22000/tcp
- 22023:22023/udp
environment: # Either configure Impostor using environment variables or mount a copy of config.json
- IMPOSTOR_Server__PublicIp=your.public.ip.here
volumes:
- /path/to/local/config.json:/app/config.json # For easy editing of the config
- /path/to/local/plugins:/app/plugins # Only needed if using plugins
- /path/to/local/libraries:/app/libraries # Only needed if using external libraries
```
## Multiple servers
Follow the steps from the single server on two or more servers. You should only need to set this up if you have a very large server and can no longer fit everyone on one server: if this is your first time installing Impostor, use a single server.
### Master server
The master server will accept client connections and redirect them to the other servers listed in the configuration. It will not host any games itself.
Example configuration:
```json
{
"Server": {
"PublicIp": "127.0.0.1",
"PublicPort": 22023,
"ListenIp": "0.0.0.0",
"ListenPort": 22023
},
"ServerRedirector": {
"Enabled": true,
"Master": true,
"Locator": {
"Redis": "",
"UdpMasterEndpoint": "127.0.0.1:22024"
},
"Nodes": [
{
"Ip": "127.0.0.1",
"Port": 22025
}
]
}
}
```
### Node servers
The node server should have `ServerRedirector` enabled too, but `Master` **must be disabled**. Nodes do not need to be aware of each other.
Example configuration:
```json
{
"Server": {
"PublicIp": "127.0.0.1",
"PublicPort": 22025,
"ListenIp": "0.0.0.0",
"ListenPort": 22025
},
"ServerRedirector": {
"Enabled": true,
"Master": false,
"Locator": {
"Redis": "",
"UdpMasterEndpoint": "127.0.0.1:22024"
}
}
}
```
+66 -21
View File
@@ -40,19 +40,6 @@ The Debug configuration is used to enable the game recorder. This is mostly usef
| **GameRecorderEnabled** | `false` | Enables the Game Recorder. |
| **GameRecorderPath** | _empty_ | Path where the recorded games will be saved. |
### ServerRedirector
In a multi-node setup these values need to be specified. Note that most people do not need to run a Multi-node setup.
| Key | Default | Value |
| ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Enabled** | `false` | Whether the server runs in multi-node setup. If this is `false`, all other options in this section do not have any effect. |
| **Master** | `false` | Whether the current server is a master. A master is responsible for redirecting clients to nodes |
| **Locator** | | Fill in either `Redis` or `UdpMasterEndpoint` to choose which method to use for locating other nodes. This must be the same across all servers. |
| **>Redis** | | Format `127.0.0.1.6379`, you can also use a password like so: `127.0.0.1.6379,password=value`. |
| **>UdpMasterEndpoint** | | On the master, this value acts as a listen ip and port. On a node, this should be the public ip and port of the master. Format `127.0.0.1:32320`. |
| **Nodes** | | An array containing public ips and ports of nodes. Only needs to be set on the master. See above for an example. |
### Serilog (Logging)
Impostor's log framework, Serilog, can be configured in the config file. You can change its default log level and you can add additional sinks.
@@ -105,12 +92,70 @@ 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
IMPOSTOR_ServerRedirector__Locator__Redis=127.0.0.1.6379
IMPOSTOR_ServerRedirector__Locator__UdpMasterEndpoint=127.0.0.1:32320
IMPOSTOR_ServerRedirector__Nodes__0__Ip=127.0.0.1
IMPOSTOR_ServerRedirector__Nodes__0__Port=22024
IMPOSTOR_ServerRedirector__Nodes__1__Ip=127.0.0.1
IMPOSTOR_ServerRedirector__Nodes__1__Port=22025
```
# systemd
Linux users will likely want to create a systemd service definition to manage running the Impostor application. Benefits to using a systemd service include the following:
- The server process can automatically restart if the process dies
- Impostor can be set to start on boot (handy if you do system updates regularly)
- You can use systemd targets to ensure the process doesn't start until the system dependencies are met
Using your favorite text editor, create the following service file:
```
sudoedit /etc/systemd/system/impostor.service
```
Modify the following template to your needs and populate the service file.
```
[Unit]
Description=Impostor private Among Us server - https://github.com/Impostor/Impostor
[Service]
# Directory where Impostor is installed
WorkingDirectory=/opt/impostor
# Path to Impostor binary
ExecStart=/opt/impostor/Impostor.Server
Restart=always
# Restart service after 10 seconds if the dotnet service crashes
RestartSec=10
KillSignal=SIGTERM
SyslogIdentifier=impostor
# User and group that will run the Impostor server process -- ensure that user is allowed to execute the binary
User=impostor
Group=impostor
TimeoutStopSec=10
[Install]
# Wait until most system services have started before starting Impostor
After=multi-user.target
WantedBy=multi-user.target
```
Reload all systemd unit files to source in the new file you've created.
```
sudo systemctl daemon-reload
```
Start the service.
```
sudo systemctl start impostor.service
```
Check the log for the service and verify it has started correctly -- Hint: Use the Q key to quit out of journalctl.
```
sudo journalctl -u impostor.service
```
If everything has started correctly, ensure the service is set to start on boot.
```
sudo systemctl enable impostor.service
```
+6 -6
View File
@@ -27,23 +27,24 @@ https://dotnet.microsoft.com/download
## 2. Create a C# project
The first step is creating a new C# project, it must be a **Class Library (.NET Standard)**. The target framework can be any of those compatible with .NET 6, which includes:
The first step is creating a new C# project, it must be a **Class Library (.NET Standard)**. The target framework can be any of those compatible with .NET 7, which includes:
- .NET Standard 2.0
- .NET Standard 2.1
- .NET 5
- .NET 6
- .NET 7
For more information about compatibility, see https://docs.microsoft.com/en-us/dotnet/standard/net-standard.
> At the moment of writing this document, I recommend you to use **.NET Standard 2.1**. This should give you enough functionality. If not, upgrade to .NET 6.
> At the moment of writing this document, I recommend you to use **.NET 7.0**.
When the project has been created, you should have `Class.cs` and `Project.csproj` files. Your `Project.csproj` should look something like this.
```xml
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
</Project>
```
@@ -269,7 +270,7 @@ Now your plugin is ready to be tested.
1. Right click your project and press `Build`.
2. Right click your project and press `Open Folder in File Explorer`.
3. Go to `bin/Debug/netstandard2.1/`.
3. Go to `bin/Debug/net7.0/`.
4. In this directory, you should find your plugin named `Project.dll`.
5. Copy the `Project.dll` to the `plugins` directory in your Impostor server directory.
6. (Re)start your Impostor server.
@@ -292,7 +293,6 @@ Some extra information that might be useful for those developing plugins.
- `IEventManager`
- `IClientManager`
- `IOptions<ServerConfig>`
- `IOptions<ServerRedirectorConfig>`
- You can add your own classes and `EventListener` implementation to the `IServiceProvider` by creating a new class and implementing `IPluginStartup`. Make sure to register them as a singleton `services.AddSingleton<IEventListener, GameEventListener>();`.
### Server configuration
@@ -309,7 +309,7 @@ Constantly copying the plugin dll to your server directory can be pretty annoyin
},
"PluginLoader": {
"Paths": [
"D:\\Projects\\Impostor\\src\\Impostor.Plugins.Example\\bin\\Debug\\netstandard2.1"
"D:\\Projects\\Impostor\\src\\Impostor.Plugins.Example\\bin\\Debug\\net7.0"
],
"LibraryPaths": []
}
+3 -2
View File
@@ -1,7 +1,8 @@
<Project>
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<VersionPrefix>1.7.2</VersionPrefix>
<TargetFramework>net7.0</TargetFramework>
<LangVersion>11</LangVersion>
<VersionPrefix>1.8.1</VersionPrefix>
<VersionSuffix>dev</VersionSuffix>
<EnforceCodeStyleInBuild Condition="$(MSBuildProjectName)!='Hazel'">true</EnforceCodeStyleInBuild>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
@@ -14,9 +14,6 @@
public const string Destroyed = "The game you tried to join is being destroyed. " +
"Please create a new game.";
public const string NotImplemented = "Game listing has not been implemented in Impostor yet for servers " +
"running in server redirection mode.";
public const string UsernameLength = "Your username is too long, please make it shorter.";
public const string UsernameIllegalCharacters = "Your username contains illegal characters, please remove them.";
@@ -1,27 +0,0 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Impostor.Api.Config
{
public class ServerRedirectorConfig
{
public const string Section = "ServerRedirector";
public bool Enabled { get; set; }
public bool Master { get; set; }
public NodeLocator? Locator { get; set; }
public List<ServerRedirectorNode>? Nodes { get; set; }
public class NodeLocator
{
[AllowNull]
public string Redis { get; set; }
[AllowNull]
public string UdpMasterEndpoint { get; set; }
}
}
}
@@ -1,13 +0,0 @@
using System.Diagnostics.CodeAnalysis;
namespace Impostor.Api.Config
{
public class ServerRedirectorNode
{
[AllowNull]
public string Ip { get; set; }
[AllowNull]
public ushort Port { get; set; }
}
}
@@ -1,5 +1,4 @@
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Events.Client
{
@@ -1,7 +1,6 @@
using System;
using System.Threading.Tasks;
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Games
{
+5 -3
View File
@@ -2,15 +2,17 @@
using System.Net;
using System.Threading.Tasks;
using Impostor.Api.Innersloth;
using Impostor.Api.Innersloth.GameOptions;
using Impostor.Api.Net;
using Impostor.Api.Net.Inner;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Games
{
public interface IGame
{
GameOptionsData Options { get; }
IGameOptions Options { get; }
GameFilterOptions FilterOptions { get; }
GameCode Code { get; }
@@ -53,7 +55,7 @@ namespace Impostor.Api.Games
void BanIp(IPAddress ipAddress);
/// <summary>
/// Syncs the internal <see cref="GameOptionsData" /> to all players.
/// Syncs the internal <see cref="IGameOptions" /> to all players.
/// Necessary to do if you modified it, otherwise it won't be used.
/// </summary>
/// <returns>A <see cref="ValueTask" /> representing the asynchronous operation.</returns>
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Impostor.Api.Innersloth;
using Impostor.Api.Innersloth.GameOptions;
namespace Impostor.Api.Games.Managers
{
@@ -14,8 +15,9 @@ namespace Impostor.Api.Games.Managers
/// Creates a new game.
/// </summary>
/// <param name="options">Game options.</param>
/// <param name="filterOptions">Filter options.</param>
/// <returns>Created game or null if creation was cancelled by a plugin.</returns>
/// <exception cref="ImpostorException">Thrown when game creation failed.</exception>
ValueTask<IGame?> CreateAsync(GameOptionsData options);
ValueTask<IGame?> CreateAsync(IGameOptions options, GameFilterOptions filterOptions);
}
}
+1
View File
@@ -0,0 +1 @@
global using Impostor.Hazel.Abstractions;
+4 -12
View File
@@ -1,9 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<CodeAnalysisRuleSet>../ProjectRules.ruleset</CodeAnalysisRuleSet>
<LangVersion>9</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>enable</Nullable>
<IncludeSymbols>true</IncludeSymbols>
@@ -27,16 +25,10 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<PackageReference Include="Nullable" Version="1.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="all" />
<PackageReference Include="Impostor.Hazel.Abstractions" Version="1.0.0" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
namespace Impostor.Api.Innersloth;
public enum CrossplayFlags
{
Unknown = 0,
StandaloneEpicPC = 1 << 1,
StandaloneSteamPC = 1 << 2,
StandaloneMac = 1 << 3,
StandaloneWin10 = 1 << 4,
StandaloneItch = 1 << 5,
IPhone = 1 << 6,
Android = 1 << 7,
Switch = 1 << 8,
Xbox = 1 << 9,
Playstation = 1 << 10,
All = int.MaxValue,
}
@@ -1,5 +1,3 @@
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Innersloth.Customization
{
public class PlayerOutfit
@@ -12,8 +12,6 @@ namespace Impostor.Api.Innersloth
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.
@@ -67,7 +65,7 @@ namespace Impostor.Api.Innersloth
#else
Span<byte> data = stackalloc byte[len];
#endif
Random.GetBytes(data);
RandomNumberGenerator.Fill(data);
// Convert to their char representation.
Span<char> dataChar = stackalloc char[len];
@@ -0,0 +1,41 @@
using System.Collections.Generic;
namespace Impostor.Api.Innersloth;
public class GameFilterOptions
{
public HashSet<string> FilterTags { get; } = new HashSet<string>();
public static GameFilterOptions CreateDefault()
{
return new GameFilterOptions
{
FilterTags =
{
"Beginner",
},
};
}
public static GameFilterOptions Deserialize(IMessageReader reader)
{
var options = new GameFilterOptions();
var count = reader.ReadPackedInt32();
for (var i = 0; i < count; i++)
{
options.FilterTags.Add(reader.ReadString());
}
return options;
}
public void Serialize(IMessageWriter writer)
{
writer.WritePacked(FilterTags.Count);
foreach (var filterTag in FilterTags)
{
writer.Write(filterTag);
}
}
}
@@ -21,6 +21,9 @@ namespace Impostor.Api.Innersloth
SpanishEU = 1024,
Arabic = 32,
Polish = 128,
SChinese = 65536,
TChinese = 131072,
Irish = 262144,
Other = 1,
}
}
+9
View File
@@ -0,0 +1,9 @@
namespace Impostor.Api.Innersloth
{
public enum GameModes : byte
{
None,
Normal,
HideNSeek,
}
}
@@ -0,0 +1,74 @@
using System;
namespace Impostor.Api.Innersloth.GameOptions;
public static class GameOptionsFactory
{
public const byte ModularOptionsDataVersion = 7;
public static void Serialize(IMessageWriter writer, IGameOptions gameOptions)
{
if (gameOptions.Version < ModularOptionsDataVersion)
{
throw new NotSupportedException();
}
// In theory we should use WriteBytesAndSize here, but it's costly and requires computing the size
// Base game does similar hacks and completely ignores this value for modular game options so we can just write 0 here
writer.WritePacked(0);
writer.Write(gameOptions.Version);
writer.StartMessage(0);
writer.Write((byte)gameOptions.GameMode);
gameOptions.Serialize(writer);
writer.EndMessage();
}
public static IGameOptions Deserialize(IMessageReader reader)
{
reader.ReadPackedInt32();
var version = reader.ReadByte();
if (version < ModularOptionsDataVersion)
{
return LegacyGameOptionsData.Deserialize(reader, version);
}
var optionsReader = reader.ReadMessage();
var gameMode = (GameModes)optionsReader.ReadByte();
return gameMode switch
{
GameModes.Normal => NormalGameOptions.Deserialize(optionsReader, version),
GameModes.HideNSeek => HideNSeekGameOptions.Deserialize(optionsReader, version),
_ => throw new ArgumentOutOfRangeException(),
};
}
public static void DeserializeInto(IMessageReader reader, IGameOptions gameOptions)
{
reader.ReadPackedInt32();
var version = reader.ReadByte();
if (version < ModularOptionsDataVersion)
{
((LegacyGameOptionsData)gameOptions).Deserialize(reader);
return;
}
var optionsReader = reader.ReadMessage();
var gameMode = (GameModes)optionsReader.ReadByte();
switch (gameMode)
{
case GameModes.Normal:
((NormalGameOptions)gameOptions).Deserialize(optionsReader);
break;
case GameModes.HideNSeek:
((HideNSeekGameOptions)gameOptions).Deserialize(optionsReader);
break;
default:
throw new ArgumentOutOfRangeException(nameof(gameMode), gameMode, null);
}
}
}
@@ -0,0 +1,162 @@
namespace Impostor.Api.Innersloth.GameOptions;
public class HideNSeekGameOptions : IGameOptions
{
public const int LatestVersion = 7;
public HideNSeekGameOptions(byte version = LatestVersion)
{
Version = version;
IGameOptions.EnsureVersionIsModular<HideNSeekGameOptions>(version);
}
/// <inheritdoc />
public byte Version { get; }
/// <inheritdoc />
public GameModes GameMode => GameModes.HideNSeek;
/// <inheritdoc />
public byte MaxPlayers { get; set; } = 15;
/// <inheritdoc />
public GameKeywords Keywords { get; set; } = GameKeywords.English;
/// <inheritdoc />
public MapTypes Map { get; set; } = MapTypes.Skeld;
/// <inheritdoc />
public int NumImpostors { get; set; } = 1;
/// <inheritdoc />
public bool IsDefaults { get; set; } = true;
/// <summary>
/// Gets or sets the Player speed modifier.
/// </summary>
public float PlayerSpeedMod { get; set; } = 1f;
/// <summary>
/// Gets or sets the Light modifier for the players that are members of the crew as a multiplier value.
/// </summary>
public float CrewLightMod { get; set; } = 1f;
/// <summary>
/// Gets or sets the Light modifier for the players that are Impostors as a multiplier value.
/// </summary>
public float ImpostorLightMod { get; set; } = 1f;
/// <summary>
/// Gets or sets the number of common tasks.
/// </summary>
public int NumCommonTasks { get; set; } = 1;
/// <summary>
/// Gets or sets the number of long tasks.
/// </summary>
public int NumLongTasks { get; set; } = 1;
/// <summary>
/// Gets or sets the number of short tasks.
/// </summary>
public int NumShortTasks { get; set; } = 2;
public int CrewmateVentUses { get; set; } = 1;
public float CrewmateTimeInVent { get; set; } = 3f;
public float HidingTime { get; set; } = 200f;
public float CrewmateFlashlightSize { get; set; } = 0.35f;
public float ImpostorFlashlightSize { get; set; } = 0.25f;
public bool UseFlashlight { get; set; } = true;
public bool FinalHideSeekMap { get; set; } = true;
public float FinalHideTime { get; set; } = 50f;
public float FinalSeekerSpeed { get; set; } = 1.2f;
public bool FinalHidePings { get; set; } = true;
public bool ShowNames { get; set; } = true;
public uint SeekerPlayerId { get; set; } = 0xFFFFFFFF;
public float MaxPingTime { get; set; } = 6f;
public static HideNSeekGameOptions Deserialize(IMessageReader reader, byte version)
{
var options = new HideNSeekGameOptions(version);
options.Deserialize(reader);
return options;
}
public void Deserialize(IMessageReader reader)
{
MaxPlayers = reader.ReadByte();
Keywords = (GameKeywords)reader.ReadInt32();
Map = (MapTypes)reader.ReadByte();
PlayerSpeedMod = reader.ReadSingle();
CrewLightMod = reader.ReadSingle();
ImpostorLightMod = reader.ReadSingle();
NumCommonTasks = reader.ReadByte();
NumLongTasks = reader.ReadByte();
NumShortTasks = reader.ReadByte();
IsDefaults = reader.ReadBoolean();
CrewmateVentUses = reader.ReadInt32();
HidingTime = reader.ReadSingle();
CrewmateFlashlightSize = reader.ReadSingle();
ImpostorFlashlightSize = reader.ReadSingle();
UseFlashlight = reader.ReadBoolean();
FinalHideSeekMap = reader.ReadBoolean();
FinalHideTime = reader.ReadSingle();
FinalSeekerSpeed = reader.ReadSingle();
FinalHidePings = reader.ReadBoolean();
ShowNames = reader.ReadBoolean();
SeekerPlayerId = reader.ReadUInt32();
MaxPingTime = reader.ReadSingle();
CrewmateTimeInVent = reader.ReadSingle();
if (Version > 7)
{
IGameOptions.ThrowUnknownVersion<HideNSeekGameOptions>(Version);
}
}
public void Serialize(IMessageWriter writer)
{
writer.Write(MaxPlayers);
writer.Write((uint)Keywords);
writer.Write((byte)Map);
writer.Write(PlayerSpeedMod);
writer.Write(CrewLightMod);
writer.Write(ImpostorLightMod);
writer.Write((byte)NumCommonTasks);
writer.Write((byte)NumLongTasks);
writer.Write((byte)NumShortTasks);
writer.Write(IsDefaults);
writer.Write(CrewmateVentUses);
writer.Write(HidingTime);
writer.Write(CrewmateFlashlightSize);
writer.Write(ImpostorFlashlightSize);
writer.Write(UseFlashlight);
writer.Write(FinalHideSeekMap);
writer.Write(FinalHideTime);
writer.Write(FinalSeekerSpeed);
writer.Write(FinalHidePings);
writer.Write(ShowNames);
writer.Write(SeekerPlayerId);
writer.Write(MaxPingTime);
writer.Write(CrewmateTimeInVent);
if (Version > 7)
{
IGameOptions.ThrowUnknownVersion<HideNSeekGameOptions>(Version);
}
}
}
@@ -0,0 +1,57 @@
using System.Diagnostics.CodeAnalysis;
namespace Impostor.Api.Innersloth.GameOptions;
public interface IGameOptions
{
/// <summary>
/// Gets the version.
/// </summary>
public byte Version { get; }
/// <summary>
/// Gets the currently active gamemode.
/// </summary>
public GameModes GameMode { get; }
/// <summary>
/// Gets or sets the maximum amount of players for this lobby.
/// </summary>
public byte MaxPlayers { get; set; }
/// <summary>
/// Gets or sets the language of the lobby as per <see cref="GameKeywords" /> enum.
/// </summary>
public GameKeywords Keywords { get; set; }
/// <summary>
/// Gets or sets the Map selected for this lobby.
/// </summary>
public MapTypes Map { get; set; }
/// <summary>
/// Gets or sets the number of impostors for this lobby.
/// </summary>
public int NumImpostors { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the GameOptions are the default ones.
/// </summary>
public bool IsDefaults { get; set; }
public void Serialize(IMessageWriter writer);
public static void EnsureVersionIsModular<TCaller>(byte version)
{
if (version < GameOptionsFactory.ModularOptionsDataVersion)
{
throw new ImpostorException($"{typeof(TCaller).Name} didn't exist before version 7, did you mean {nameof(LegacyGameOptionsData)}?");
}
}
[DoesNotReturn]
public static void ThrowUnknownVersion<TCaller>(byte version)
{
throw new ImpostorException($"Unknown {typeof(TCaller).Name} version {version}");
}
}
@@ -0,0 +1,263 @@
using Impostor.Api.Innersloth.GameOptions.RoleOptions;
namespace Impostor.Api.Innersloth.GameOptions;
public class LegacyGameOptionsData : IGameOptions
{
/// <summary>
/// The latest major version of the game client.
/// </summary>
public const int LatestVersion = 5;
public LegacyGameOptionsData(byte version = LatestVersion)
{
Version = version;
}
/// <summary>
/// Gets or sets host's version of the game.
/// </summary>
public byte Version { get; set; }
public GameModes GameMode => GameModes.Normal;
/// <summary>
/// Gets or sets the maximum amount of players for this lobby.
/// </summary>
public byte MaxPlayers { get; set; } = 10;
/// <summary>
/// Gets or sets the language of the lobby as per <see cref="GameKeywords" /> enum.
/// </summary>
public GameKeywords Keywords { get; set; } = GameKeywords.English;
/// <summary>
/// Gets or sets the Map selected for this lobby.
/// </summary>
public MapTypes Map { get; set; } = MapTypes.Skeld;
/// <summary>
/// Gets or sets the Player speed modifier.
/// </summary>
public float PlayerSpeedMod { get; set; } = 1f;
/// <summary>
/// Gets or sets the Light modifier for the players that are members of the crew as a multiplier value.
/// </summary>
public float CrewLightMod { get; set; } = 1f;
/// <summary>
/// Gets or sets the Light modifier for the players that are Impostors as a multiplier value.
/// </summary>
public float ImpostorLightMod { get; set; } = 1f;
/// <summary>
/// Gets or sets the Impostor cooldown to kill in seconds.
/// </summary>
public float KillCooldown { get; set; } = 15f;
/// <summary>
/// Gets or sets the number of common tasks.
/// </summary>
public int NumCommonTasks { get; set; } = 1;
/// <summary>
/// Gets or sets the number of long tasks.
/// </summary>
public int NumLongTasks { get; set; } = 1;
/// <summary>
/// Gets or sets the number of short tasks.
/// </summary>
public int NumShortTasks { get; set; } = 2;
/// <summary>
/// Gets or sets the maximum amount of emergency meetings each player can call during the game in seconds.
/// </summary>
public int NumEmergencyMeetings { get; set; } = 1;
/// <summary>
/// Gets or sets the cooldown between each time any player can call an emergency meeting in seconds.
/// </summary>
public int EmergencyCooldown { get; set; } = 15;
/// <summary>
/// Gets or sets the number of impostors for this lobby.
/// </summary>
public int NumImpostors { get; set; } = 1;
/// <summary>
/// Gets or sets a value indicating whether ghosts (dead crew members) can do tasks.
/// </summary>
public bool GhostsDoTasks { get; set; } = true;
/// <summary>
/// Gets or sets the Kill as per values in <see cref="KillDistances" />.
/// </summary>
public KillDistances KillDistance { get; set; } = KillDistances.Normal;
/// <summary>
/// Gets or sets the time for discussion before voting time in seconds.
/// </summary>
public int DiscussionTime { get; set; } = 15;
/// <summary>
/// Gets or sets the time for voting in seconds.
/// </summary>
public int VotingTime { get; set; } = 120;
/// <summary>
/// Gets or sets a value indicating whether an ejected player is an impostor or not.
/// </summary>
public bool ConfirmImpostor { get; set; } = true;
/// <summary>
/// Gets or sets a value indicating whether players are able to see tasks being performed by other players.
/// </summary>
/// <remarks>
/// By being set to true, tasks such as Empty Garbage, Submit Scan, Clear asteroids, Prime shields execution will be visible to other players.
/// </remarks>
public bool VisualTasks { get; set; } = true;
/// <summary>
/// Gets or sets a value indicating whether the vote is anonymous.
/// </summary>
public bool AnonymousVotes { get; set; }
/// <summary>
/// Gets or sets the task bar update mode as per values in <see cref="Innersloth.TaskBarUpdate" />.
/// </summary>
public TaskBarUpdate TaskBarUpdate { get; set; } = TaskBarUpdate.Always;
/// <summary>
/// Gets or sets role options.
/// </summary>
public LegacyRoleOptionsData RoleOptions { get; set; } = new LegacyRoleOptionsData();
/// <summary>
/// Gets or sets a value indicating whether the GameOptions are the default ones.
/// </summary>
public bool IsDefaults { get; set; } = true;
public static LegacyGameOptionsData Deserialize(IMessageReader reader, byte version)
{
var options = new LegacyGameOptionsData(version);
options.Deserialize(reader);
return options;
}
public void Deserialize(IMessageReader reader)
{
Version = reader.ReadByte();
MaxPlayers = reader.ReadByte();
Keywords = (GameKeywords)reader.ReadUInt32();
Map = (MapTypes)reader.ReadByte();
PlayerSpeedMod = reader.ReadSingle();
CrewLightMod = reader.ReadSingle();
ImpostorLightMod = reader.ReadSingle();
KillCooldown = reader.ReadSingle();
NumCommonTasks = reader.ReadByte();
NumLongTasks = reader.ReadByte();
NumShortTasks = reader.ReadByte();
NumEmergencyMeetings = reader.ReadInt32();
NumImpostors = reader.ReadByte();
KillDistance = (KillDistances)reader.ReadByte();
DiscussionTime = reader.ReadInt32();
VotingTime = reader.ReadInt32();
IsDefaults = reader.ReadBoolean();
if (Version >= 2)
{
EmergencyCooldown = reader.ReadByte();
}
if (Version >= 3)
{
ConfirmImpostor = reader.ReadBoolean();
VisualTasks = reader.ReadBoolean();
}
if (Version >= 4)
{
AnonymousVotes = reader.ReadBoolean();
TaskBarUpdate = (TaskBarUpdate)reader.ReadByte();
}
if (Version >= 5)
{
RoleOptions = LegacyRoleOptionsData.Deserialize(reader);
}
if (Version >= 6)
{
// Nothing was changed in V6
}
if (Version > 6)
{
IGameOptions.ThrowUnknownVersion<LegacyGameOptionsData>(Version);
}
}
/// <summary>
/// Serializes this instance of GameOptionsData object to a specified BinaryWriter.
/// </summary>
/// <param name="writer">The stream to write the message to.</param>
public void Serialize(IMessageWriter writer)
{
writer.Write((byte)Version);
writer.Write((byte)MaxPlayers);
writer.Write((uint)Keywords);
writer.Write((byte)Map);
writer.Write((float)PlayerSpeedMod);
writer.Write((float)CrewLightMod);
writer.Write((float)ImpostorLightMod);
writer.Write((float)KillCooldown);
writer.Write((byte)NumCommonTasks);
writer.Write((byte)NumLongTasks);
writer.Write((byte)NumShortTasks);
writer.Write((int)NumEmergencyMeetings);
writer.Write((byte)NumImpostors);
writer.Write((byte)KillDistance);
writer.Write((uint)DiscussionTime);
writer.Write((uint)VotingTime);
writer.Write((bool)IsDefaults);
if (Version >= 2)
{
writer.Write((byte)EmergencyCooldown);
}
if (Version >= 3)
{
writer.Write((bool)ConfirmImpostor);
writer.Write((bool)VisualTasks);
}
if (Version >= 4)
{
writer.Write((bool)AnonymousVotes);
writer.Write((byte)TaskBarUpdate);
}
if (Version >= 5)
{
RoleOptions.Serialize(writer);
}
if (Version >= 6)
{
// Nothing was changed in V6
}
if (Version > 6)
{
throw new ImpostorException($"Unknown {nameof(LegacyGameOptionsData)} version {Version}");
}
}
}
@@ -0,0 +1,209 @@
using Impostor.Api.Innersloth.GameOptions.RoleOptions;
namespace Impostor.Api.Innersloth.GameOptions;
public class NormalGameOptions : IGameOptions
{
public const int LatestVersion = 7;
public NormalGameOptions(byte version = LatestVersion)
{
Version = version;
IGameOptions.EnsureVersionIsModular<NormalGameOptions>(version);
RoleOptions = new RoleOptionsCollection(version);
}
/// <inheritdoc />
public byte Version { get; }
/// <inheritdoc />
public GameModes GameMode => GameModes.Normal;
/// <inheritdoc />
public byte MaxPlayers { get; set; } = 10;
/// <inheritdoc />
public GameKeywords Keywords { get; set; } = GameKeywords.English;
/// <inheritdoc />
public MapTypes Map { get; set; } = MapTypes.Skeld;
/// <inheritdoc />
public int NumImpostors { get; set; } = 1;
/// <inheritdoc />
public bool IsDefaults { get; set; } = true;
/// <summary>
/// Gets or sets the Player speed modifier.
/// </summary>
public float PlayerSpeedMod { get; set; } = 1f;
/// <summary>
/// Gets or sets the Light modifier for the players that are members of the crew as a multiplier value.
/// </summary>
public float CrewLightMod { get; set; } = 1f;
/// <summary>
/// Gets or sets the Light modifier for the players that are Impostors as a multiplier value.
/// </summary>
public float ImpostorLightMod { get; set; } = 1f;
/// <summary>
/// Gets or sets the Impostor cooldown to kill in seconds.
/// </summary>
public float KillCooldown { get; set; } = 15f;
/// <summary>
/// Gets or sets the number of common tasks.
/// </summary>
public int NumCommonTasks { get; set; } = 1;
/// <summary>
/// Gets or sets the number of long tasks.
/// </summary>
public int NumLongTasks { get; set; } = 1;
/// <summary>
/// Gets or sets the number of short tasks.
/// </summary>
public int NumShortTasks { get; set; } = 2;
/// <summary>
/// Gets or sets the maximum amount of emergency meetings each player can call during the game in seconds.
/// </summary>
public int NumEmergencyMeetings { get; set; } = 1;
/// <summary>
/// Gets or sets the cooldown between each time any player can call an emergency meeting in seconds.
/// </summary>
public int EmergencyCooldown { get; set; } = 15;
/// <summary>
/// Gets or sets a value indicating whether ghosts (dead crew members) can do tasks.
/// </summary>
public bool GhostsDoTasks { get; set; } = true;
/// <summary>
/// Gets or sets the Kill as per values in <see cref="KillDistances" />.
/// </summary>
public KillDistances KillDistance { get; set; } = KillDistances.Normal;
/// <summary>
/// Gets or sets the time for discussion before voting time in seconds.
/// </summary>
public int DiscussionTime { get; set; } = 15;
/// <summary>
/// Gets or sets the time for voting in seconds.
/// </summary>
public int VotingTime { get; set; } = 120;
/// <summary>
/// Gets or sets a value indicating whether an ejected player is an impostor or not.
/// </summary>
public bool ConfirmImpostor { get; set; } = true;
/// <summary>
/// Gets or sets a value indicating whether players are able to see tasks being performed by other players.
/// </summary>
/// <remarks>
/// By being set to true, tasks such as Empty Garbage, Submit Scan, Clear asteroids, Prime shields execution will be visible to other players.
/// </remarks>
public bool VisualTasks { get; set; } = true;
/// <summary>
/// Gets or sets a value indicating whether the vote is anonymous.
/// </summary>
public bool AnonymousVotes { get; set; }
/// <summary>
/// Gets or sets the task bar update mode as per values in <see cref="Innersloth.TaskBarUpdate" />.
/// </summary>
public TaskBarUpdate TaskBarUpdate { get; set; } = TaskBarUpdate.Always;
public RoleOptionsCollection RoleOptions { get; set; }
public static NormalGameOptions Deserialize(IMessageReader reader, byte version)
{
var options = new NormalGameOptions(version);
options.Deserialize(reader);
return options;
}
public void Deserialize(IMessageReader reader)
{
MaxPlayers = reader.ReadByte();
Keywords = (GameKeywords)reader.ReadUInt32();
Map = (MapTypes)reader.ReadByte();
PlayerSpeedMod = reader.ReadSingle();
CrewLightMod = reader.ReadSingle();
ImpostorLightMod = reader.ReadSingle();
KillCooldown = reader.ReadSingle();
NumCommonTasks = reader.ReadByte();
NumLongTasks = reader.ReadByte();
NumShortTasks = reader.ReadByte();
NumEmergencyMeetings = reader.ReadInt32();
NumImpostors = reader.ReadByte();
KillDistance = (KillDistances)reader.ReadByte();
DiscussionTime = reader.ReadInt32();
VotingTime = reader.ReadInt32();
IsDefaults = reader.ReadBoolean();
EmergencyCooldown = reader.ReadByte();
ConfirmImpostor = reader.ReadBoolean();
VisualTasks = reader.ReadBoolean();
AnonymousVotes = reader.ReadBoolean();
TaskBarUpdate = (TaskBarUpdate)reader.ReadByte();
RoleOptions.Deserialize(reader);
if (Version > 7)
{
IGameOptions.ThrowUnknownVersion<NormalGameOptions>(Version);
}
}
public void Serialize(IMessageWriter writer)
{
writer.Write(MaxPlayers);
writer.Write((uint)Keywords);
writer.Write((byte)Map);
writer.Write(PlayerSpeedMod);
writer.Write(CrewLightMod);
writer.Write(ImpostorLightMod);
writer.Write(KillCooldown);
writer.Write((byte)NumCommonTasks);
writer.Write((byte)NumLongTasks);
writer.Write((byte)NumShortTasks);
writer.Write(NumEmergencyMeetings);
writer.Write((byte)NumImpostors);
writer.Write((byte)KillDistance);
writer.Write(DiscussionTime);
writer.Write(VotingTime);
writer.Write(IsDefaults);
writer.Write((byte)EmergencyCooldown);
writer.Write(ConfirmImpostor);
writer.Write(VisualTasks);
writer.Write(AnonymousVotes);
writer.Write((byte)TaskBarUpdate);
RoleOptions.Serialize(writer);
if (Version > 7)
{
IGameOptions.ThrowUnknownVersion<NormalGameOptions>(Version);
}
}
}
@@ -0,0 +1,33 @@
namespace Impostor.Api.Innersloth.GameOptions.RoleOptions;
public class EngineerRoleOptions : IRoleOptions
{
public EngineerRoleOptions(byte version)
{
Version = version;
}
public byte Version { get; }
public RoleTypes Type => RoleTypes.Engineer;
public byte Cooldown { get; set; } = 30;
public byte InVentMaxTime { get; set; } = 15;
public static EngineerRoleOptions Deserialize(IMessageReader reader, byte version)
{
var options = new EngineerRoleOptions(version);
options.Cooldown = reader.ReadByte();
options.InVentMaxTime = reader.ReadByte();
return options;
}
public void Serialize(IMessageWriter writer)
{
writer.Write(Cooldown);
writer.Write(InVentMaxTime);
}
}
@@ -0,0 +1,37 @@
namespace Impostor.Api.Innersloth.GameOptions.RoleOptions;
public class GuardianAngelRoleOptions : IRoleOptions
{
public GuardianAngelRoleOptions(byte version)
{
Version = version;
}
public byte Version { get; }
public RoleTypes Type => RoleTypes.GuardianAngel;
public byte Cooldown { get; set; } = 60;
public byte ProtectionDurationSeconds { get; set; } = 10;
public bool ImpostorsCanSeeProtect { get; set; }
public static GuardianAngelRoleOptions Deserialize(IMessageReader reader, byte version)
{
var options = new GuardianAngelRoleOptions(version);
options.Cooldown = reader.ReadByte();
options.ProtectionDurationSeconds = reader.ReadByte();
options.ImpostorsCanSeeProtect = reader.ReadBoolean();
return options;
}
public void Serialize(IMessageWriter writer)
{
writer.Write(Cooldown);
writer.Write(ProtectionDurationSeconds);
writer.Write(ImpostorsCanSeeProtect);
}
}
@@ -0,0 +1,8 @@
namespace Impostor.Api.Innersloth.GameOptions.RoleOptions;
public interface IRoleOptions
{
RoleTypes Type { get; }
void Serialize(IMessageWriter writer);
}
@@ -0,0 +1,73 @@
using System.Collections.Generic;
namespace Impostor.Api.Innersloth.GameOptions.RoleOptions;
public class LegacyRoleOptionsData
{
public bool ShapeshifterLeaveSkin { get; set; }
public byte ShapeshifterCooldown { get; set; } = 10;
public byte ShapeshifterDuration { get; set; } = 30;
public byte ScientistCooldown { get; set; } = 15;
public byte ScientistBatteryCharge { get; set; } = 5;
public byte GuardianAngelCooldown { get; set; } = 60;
public bool ImpostorsCanSeeProtect { get; set; }
public byte ProtectionDurationSeconds { get; set; } = 10;
public byte EngineerCooldown { get; set; } = 30;
public byte EngineerInVentMaxTime { get; set; } = 15;
public Dictionary<RoleTypes, RoleRate> RoleRates { get; } = new Dictionary<RoleTypes, RoleRate>();
public static LegacyRoleOptionsData Deserialize(IMessageReader reader)
{
var roleOptionsData = new LegacyRoleOptionsData();
var num = reader.ReadPackedInt32();
for (var i = 0; i < num; i++)
{
var key = (RoleTypes)reader.ReadInt16();
var roleRate = RoleRate.Deserialize(reader);
roleOptionsData.RoleRates[key] = roleRate;
}
roleOptionsData.ShapeshifterLeaveSkin = reader.ReadBoolean();
roleOptionsData.ShapeshifterCooldown = reader.ReadByte();
roleOptionsData.ShapeshifterDuration = reader.ReadByte();
roleOptionsData.ScientistCooldown = reader.ReadByte();
roleOptionsData.GuardianAngelCooldown = reader.ReadByte();
roleOptionsData.EngineerCooldown = reader.ReadByte();
roleOptionsData.EngineerInVentMaxTime = reader.ReadByte();
roleOptionsData.ScientistBatteryCharge = reader.ReadByte();
roleOptionsData.ProtectionDurationSeconds = reader.ReadByte();
roleOptionsData.ImpostorsCanSeeProtect = reader.ReadBoolean();
return roleOptionsData;
}
public void Serialize(IMessageWriter writer)
{
writer.WritePacked(RoleRates.Count);
foreach (var roleRate in RoleRates)
{
writer.Write((ushort)roleRate.Key);
roleRate.Value.Serialize(writer);
}
writer.Write(ShapeshifterLeaveSkin);
writer.Write(ShapeshifterCooldown);
writer.Write(ShapeshifterDuration);
writer.Write(ScientistCooldown);
writer.Write(GuardianAngelCooldown);
writer.Write(EngineerCooldown);
writer.Write(EngineerInVentMaxTime);
writer.Write(ScientistBatteryCharge);
writer.Write(ProtectionDurationSeconds);
writer.Write(ImpostorsCanSeeProtect);
}
}
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
namespace Impostor.Api.Innersloth.GameOptions.RoleOptions;
public class RoleOptionsCollection
{
public RoleOptionsCollection(byte version)
{
Version = version;
}
public byte Version { get; }
public Dictionary<RoleTypes, RoleData> Roles { get; } = new Dictionary<RoleTypes, RoleData>();
public void Deserialize(IMessageReader reader)
{
Roles.Clear();
var count = reader.ReadPackedInt32();
Roles.EnsureCapacity(count);
for (var i = 0; i < count; i++)
{
var roleType = (RoleTypes)reader.ReadInt16();
var roleRate = RoleRate.Deserialize(reader);
var roleOptionsReader = reader.ReadMessage();
IRoleOptions roleOptions = roleType switch
{
RoleTypes.Scientist => ScientistRoleOptions.Deserialize(roleOptionsReader, Version),
RoleTypes.Engineer => EngineerRoleOptions.Deserialize(roleOptionsReader, Version),
RoleTypes.GuardianAngel => GuardianAngelRoleOptions.Deserialize(roleOptionsReader, Version),
RoleTypes.Shapeshifter => ShapeshifterRoleOptions.Deserialize(roleOptionsReader, Version),
_ => throw new ArgumentOutOfRangeException(nameof(roleType), roleType, null),
};
Roles.Add(roleType, new RoleData(roleType, roleOptions, roleRate));
}
}
public void Serialize(IMessageWriter writer)
{
writer.WritePacked(Roles.Count);
foreach (var (key, roleData) in Roles)
{
writer.Write((ushort)key);
roleData.Rate.Serialize(writer);
writer.StartMessage(0);
roleData.RoleOptions.Serialize(writer);
writer.EndMessage();
}
}
public readonly record struct RoleData(RoleTypes Type, IRoleOptions RoleOptions, RoleRate Rate);
}
@@ -0,0 +1,15 @@
namespace Impostor.Api.Innersloth.GameOptions.RoleOptions;
public readonly record struct RoleRate(byte MaxCount, byte Chance)
{
public static RoleRate Deserialize(IMessageReader reader)
{
return new RoleRate(reader.ReadByte(), reader.ReadByte());
}
public void Serialize(IMessageWriter writer)
{
writer.Write(MaxCount);
writer.Write(Chance);
}
}
@@ -0,0 +1,33 @@
namespace Impostor.Api.Innersloth.GameOptions.RoleOptions;
public class ScientistRoleOptions : IRoleOptions
{
public ScientistRoleOptions(byte version)
{
Version = version;
}
public byte Version { get; }
public RoleTypes Type => RoleTypes.Scientist;
public byte Cooldown { get; set; } = 15;
public byte BatteryCharge { get; set; } = 5;
public static ScientistRoleOptions Deserialize(IMessageReader reader, byte version)
{
var options = new ScientistRoleOptions(version);
options.Cooldown = reader.ReadByte();
options.BatteryCharge = reader.ReadByte();
return options;
}
public void Serialize(IMessageWriter writer)
{
writer.Write(Cooldown);
writer.Write(BatteryCharge);
}
}
@@ -0,0 +1,37 @@
namespace Impostor.Api.Innersloth.GameOptions.RoleOptions;
public class ShapeshifterRoleOptions : IRoleOptions
{
public ShapeshifterRoleOptions(byte version)
{
Version = version;
}
public byte Version { get; }
public RoleTypes Type => RoleTypes.Shapeshifter;
public bool LeaveSkin { get; set; }
public byte Cooldown { get; set; } = 10;
public byte Duration { get; set; } = 30;
public static ShapeshifterRoleOptions Deserialize(IMessageReader reader, byte version)
{
var options = new ShapeshifterRoleOptions(version);
options.LeaveSkin = reader.ReadBoolean();
options.Cooldown = reader.ReadByte();
options.Duration = reader.ReadByte();
return options;
}
public void Serialize(IMessageWriter writer)
{
writer.Write(LeaveSkin);
writer.Write(Cooldown);
writer.Write(Duration);
}
}
@@ -1,279 +0,0 @@
using System;
using System.IO;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Innersloth
{
public class GameOptionsData
{
/// <summary>
/// The latest major version of the game client.
/// </summary>
public const int LatestVersion = 5;
/// <summary>
/// Gets or sets host's version of the game.
/// </summary>
public byte Version { get; set; } = LatestVersion;
/// <summary>
/// Gets or sets the maximum amount of players for this lobby.
/// </summary>
public byte MaxPlayers { get; set; } = 10;
/// <summary>
/// Gets or sets the language of the lobby as per <see cref="GameKeywords" /> enum.
/// </summary>
public GameKeywords Keywords { get; set; } = GameKeywords.English;
/// <summary>
/// Gets or sets the Map selected for this lobby.
/// </summary>
public MapTypes Map { get; set; } = MapTypes.Skeld;
/// <summary>
/// Gets or sets the Player speed modifier.
/// </summary>
public float PlayerSpeedMod { get; set; } = 1f;
/// <summary>
/// Gets or sets the Light modifier for the players that are members of the crew as a multiplier value.
/// </summary>
public float CrewLightMod { get; set; } = 1f;
/// <summary>
/// Gets or sets the Light modifier for the players that are Impostors as a multiplier value.
/// </summary>
public float ImpostorLightMod { get; set; } = 1f;
/// <summary>
/// Gets or sets the Impostor cooldown to kill in seconds.
/// </summary>
public float KillCooldown { get; set; } = 15f;
/// <summary>
/// Gets or sets the number of common tasks.
/// </summary>
public int NumCommonTasks { get; set; } = 1;
/// <summary>
/// Gets or sets the number of long tasks.
/// </summary>
public int NumLongTasks { get; set; } = 1;
/// <summary>
/// Gets or sets the number of short tasks.
/// </summary>
public int NumShortTasks { get; set; } = 2;
/// <summary>
/// Gets or sets the maximum amount of emergency meetings each player can call during the game in seconds.
/// </summary>
public int NumEmergencyMeetings { get; set; } = 1;
/// <summary>
/// Gets or sets the cooldown between each time any player can call an emergency meeting in seconds.
/// </summary>
public int EmergencyCooldown { get; set; } = 15;
/// <summary>
/// Gets or sets the number of impostors for this lobby.
/// </summary>
public int NumImpostors { get; set; } = 1;
/// <summary>
/// Gets or sets a value indicating whether ghosts (dead crew members) can do tasks.
/// </summary>
public bool GhostsDoTasks { get; set; } = true;
/// <summary>
/// Gets or sets the Kill as per values in <see cref="KillDistances" />.
/// </summary>
public KillDistances KillDistance { get; set; } = KillDistances.Normal;
/// <summary>
/// Gets or sets the time for discussion before voting time in seconds.
/// </summary>
public int DiscussionTime { get; set; } = 15;
/// <summary>
/// Gets or sets the time for voting in seconds.
/// </summary>
public int VotingTime { get; set; } = 120;
/// <summary>
/// Gets or sets a value indicating whether an ejected player is an impostor or not.
/// </summary>
public bool ConfirmImpostor { get; set; } = true;
/// <summary>
/// Gets or sets a value indicating whether players are able to see tasks being performed by other players.
/// </summary>
/// <remarks>
/// By being set to true, tasks such as Empty Garbage, Submit Scan, Clear asteroids, Prime shields execution will be visible to other players.
/// </remarks>
public bool VisualTasks { get; set; } = true;
/// <summary>
/// Gets or sets a value indicating whether the vote is anonymous.
/// </summary>
public bool AnonymousVotes { get; set; }
/// <summary>
/// Gets or sets the task bar update mode as per values in <see cref="Innersloth.TaskBarUpdate" />.
/// </summary>
public TaskBarUpdate TaskBarUpdate { get; set; } = TaskBarUpdate.Always;
/// <summary>
/// Gets or sets role options.
/// </summary>
public RoleOptionsData RoleOptions { get; set; } = new RoleOptionsData();
/// <summary>
/// Gets or sets a value indicating whether the GameOptions are the default ones.
/// </summary>
public bool IsDefaults { get; set; } = true;
/// <summary>
/// Deserialize a packet/message to a new GameOptionsData object.
/// </summary>
/// <param name="reader">Message reader object containing the raw message.</param>
/// <returns>GameOptionsData object.</returns>
public static GameOptionsData DeserializeCreate(IMessageReader reader)
{
var options = new GameOptionsData();
options.Deserialize(reader.ReadBytesAndSize());
return options;
}
/// <summary>
/// Serializes this instance of GameOptionsData object to a specified BinaryWriter.
/// </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 = LatestVersion)
{
writer.Write((byte)version);
writer.Write((byte)MaxPlayers);
writer.Write((uint)Keywords);
writer.Write((byte)Map);
writer.Write((float)PlayerSpeedMod);
writer.Write((float)CrewLightMod);
writer.Write((float)ImpostorLightMod);
writer.Write((float)KillCooldown);
writer.Write((byte)NumCommonTasks);
writer.Write((byte)NumLongTasks);
writer.Write((byte)NumShortTasks);
writer.Write((int)NumEmergencyMeetings);
writer.Write((byte)NumImpostors);
writer.Write((byte)KillDistance);
writer.Write((uint)DiscussionTime);
writer.Write((uint)VotingTime);
writer.Write((bool)IsDefaults);
if (version >= 2)
{
writer.Write((byte)EmergencyCooldown);
}
if (version >= 3)
{
writer.Write((bool)ConfirmImpostor);
writer.Write((bool)VisualTasks);
}
if (version >= 4)
{
writer.Write((bool)AnonymousVotes);
writer.Write((byte)TaskBarUpdate);
}
if (version >= 5)
{
RoleOptions.Serialize(writer);
}
if (version >= 6)
{
// Nothing was changed in V6
}
if (version > 6)
{
throw new ImpostorException($"Unknown GameOptionsData version {Version}.");
}
}
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>
/// <param name="memory">Memory containing the message/packet.</param>
public void Deserialize(ReadOnlyMemory<byte> memory)
{
var bytes = memory.Span;
Version = bytes.ReadByte();
MaxPlayers = bytes.ReadByte();
Keywords = (GameKeywords)bytes.ReadUInt32();
Map = (MapTypes)bytes.ReadByte();
PlayerSpeedMod = bytes.ReadSingle();
CrewLightMod = bytes.ReadSingle();
ImpostorLightMod = bytes.ReadSingle();
KillCooldown = bytes.ReadSingle();
NumCommonTasks = bytes.ReadByte();
NumLongTasks = bytes.ReadByte();
NumShortTasks = bytes.ReadByte();
NumEmergencyMeetings = bytes.ReadInt32();
NumImpostors = bytes.ReadByte();
KillDistance = (KillDistances)bytes.ReadByte();
DiscussionTime = bytes.ReadInt32();
VotingTime = bytes.ReadInt32();
IsDefaults = bytes.ReadBoolean();
if (Version >= 2)
{
EmergencyCooldown = bytes.ReadByte();
}
if (Version >= 3)
{
ConfirmImpostor = bytes.ReadBoolean();
VisualTasks = bytes.ReadBoolean();
}
if (Version >= 4)
{
AnonymousVotes = bytes.ReadBoolean();
TaskBarUpdate = (TaskBarUpdate)bytes.ReadByte();
}
if (Version >= 5)
{
RoleOptions = RoleOptionsData.Deserialize(bytes);
}
if (Version >= 6)
{
// Nothing was changed in V6
}
if (Version > 6)
{
throw new ImpostorException($"Unknown GameOptionsData version {Version}.");
}
}
}
}
+3
View File
@@ -8,5 +8,8 @@ namespace Impostor.Api.Innersloth
Skeld = 1,
MiraHQ = 2,
Polus = 4,
Airship = 16,
// 8 is taken by Dleks
}
}
@@ -24,7 +24,7 @@ namespace Impostor.Api.Innersloth.Maps
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.RightStabilizer, new Vector2(23.72f, -7.82f), 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),
};
@@ -1,5 +1,4 @@
using System;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Innersloth
{
@@ -1,136 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Innersloth
{
public class RoleOptionsData
{
public bool ShapeshifterLeaveSkin { get; set; }
public byte ShapeshifterCooldown { get; set; } = 10;
public byte ShapeshifterDuration { get; set; } = 30;
public byte ScientistCooldown { get; set; } = 15;
public byte ScientistBatteryCharge { get; set; } = 5;
public byte GuardianAngelCooldown { get; set; } = 60;
public bool ImpostorsCanSeeProtect { get; set; }
public byte ProtectionDurationSeconds { get; set; } = 10;
public byte EngineerCooldown { get; set; } = 30;
public byte EngineerInVentMaxTime { get; set; } = 15;
public Dictionary<RoleTypes, RoleRate> RoleRates { get; } = new Dictionary<RoleTypes, RoleRate>();
public static RoleOptionsData Deserialize(ReadOnlySpan<byte> span)
{
var roleOptionsData = new RoleOptionsData();
var num = span.ReadInt32();
for (var i = 0; i < num; i++)
{
var key = (RoleTypes)span.ReadInt16();
var roleRate = new RoleRate(span.ReadByte(), span.ReadByte());
roleOptionsData.RoleRates[key] = roleRate;
}
roleOptionsData.ShapeshifterLeaveSkin = span.ReadBoolean();
roleOptionsData.ShapeshifterCooldown = span.ReadByte();
roleOptionsData.ShapeshifterDuration = span.ReadByte();
roleOptionsData.ScientistCooldown = span.ReadByte();
roleOptionsData.GuardianAngelCooldown = span.ReadByte();
roleOptionsData.EngineerCooldown = span.ReadByte();
roleOptionsData.EngineerInVentMaxTime = span.ReadByte();
roleOptionsData.ScientistBatteryCharge = span.ReadByte();
roleOptionsData.ProtectionDurationSeconds = span.ReadByte();
roleOptionsData.ImpostorsCanSeeProtect = span.ReadBoolean();
return roleOptionsData;
}
public static RoleOptionsData Deserialize(IMessageReader reader)
{
var roleOptionsData = new RoleOptionsData();
var num = reader.ReadPackedInt32();
for (var i = 0; i < num; i++)
{
var key = (RoleTypes)reader.ReadInt16();
var roleRate = new RoleRate(reader.ReadByte(), reader.ReadByte());
roleOptionsData.RoleRates[key] = roleRate;
}
roleOptionsData.ShapeshifterLeaveSkin = reader.ReadBoolean();
roleOptionsData.ShapeshifterCooldown = reader.ReadByte();
roleOptionsData.ShapeshifterDuration = reader.ReadByte();
roleOptionsData.ScientistCooldown = reader.ReadByte();
roleOptionsData.GuardianAngelCooldown = reader.ReadByte();
roleOptionsData.EngineerCooldown = reader.ReadByte();
roleOptionsData.EngineerInVentMaxTime = reader.ReadByte();
roleOptionsData.ScientistBatteryCharge = reader.ReadByte();
roleOptionsData.ProtectionDurationSeconds = reader.ReadByte();
roleOptionsData.ImpostorsCanSeeProtect = reader.ReadBoolean();
return roleOptionsData;
}
public void Serialize(IMessageWriter writer)
{
writer.WritePacked(RoleRates.Count);
foreach (var roleRate in RoleRates)
{
writer.Write((ushort)roleRate.Key);
writer.Write((byte)roleRate.Value.MaxCount);
writer.Write((byte)roleRate.Value.Chance);
}
writer.Write(ShapeshifterLeaveSkin);
writer.Write(ShapeshifterCooldown);
writer.Write(ShapeshifterDuration);
writer.Write(ScientistCooldown);
writer.Write(GuardianAngelCooldown);
writer.Write(EngineerCooldown);
writer.Write(EngineerInVentMaxTime);
writer.Write(ScientistBatteryCharge);
writer.Write(ProtectionDurationSeconds);
writer.Write(ImpostorsCanSeeProtect);
}
public void Serialize(BinaryWriter writer)
{
writer.Write(RoleRates.Count);
foreach (var roleRate in RoleRates)
{
writer.Write((ushort)roleRate.Key);
writer.Write((byte)roleRate.Value.MaxCount);
writer.Write((byte)roleRate.Value.Chance);
}
writer.Write(ShapeshifterLeaveSkin);
writer.Write(ShapeshifterCooldown);
writer.Write(ShapeshifterDuration);
writer.Write(ScientistCooldown);
writer.Write(GuardianAngelCooldown);
writer.Write(EngineerCooldown);
writer.Write(EngineerInVentMaxTime);
writer.Write(ScientistBatteryCharge);
writer.Write(ProtectionDurationSeconds);
writer.Write(ImpostorsCanSeeProtect);
}
public readonly struct RoleRate
{
public readonly int MaxCount;
public readonly int Chance;
public RoleRate(int maxCount, int chance)
{
MaxCount = maxCount;
Chance = chance;
}
}
}
}
+2
View File
@@ -8,5 +8,7 @@ namespace Impostor.Api.Innersloth
Engineer,
GuardianAngel,
Shapeshifter,
CrewmateGhost,
ImpostorGhost,
}
}
+2 -6
View File
@@ -38,9 +38,7 @@
Sabotage = 17,
/// <summary>
/// Decontam on Mira and bottom decontam on Polus
/// </summary>
/// <remarks>The only decontamination on Mira and bottom decontamination on Polus.</remarks>
Decontamination = 18,
Launchpad = 19,
@@ -57,9 +55,7 @@
Dropship = 25,
/// <summary>
/// Top decontam on Polus
/// </summary>
/// <remarks>Top decontamination on Polus.</remarks>
Decontamination2 = 26,
Outside = 27,
@@ -1,5 +1,4 @@
using System.Threading.Tasks;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Net.Custom
{
@@ -1,6 +1,5 @@
using System.Threading.Tasks;
using Impostor.Api.Net.Inner;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Net.Custom
{
-1
View File
@@ -1,7 +1,6 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Impostor.Api.Innersloth;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Net
{
-1
View File
@@ -1,6 +1,5 @@
using System.Net;
using System.Threading.Tasks;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Net
{
+3
View File
@@ -1,4 +1,5 @@
using Impostor.Api.Net.Inner.Objects;
using Impostor.Api.Net.Inner.Objects.GameManager;
using Impostor.Api.Net.Inner.Objects.ShipStatus;
namespace Impostor.Api.Net.Inner
@@ -8,6 +9,8 @@ namespace Impostor.Api.Net.Inner
/// </summary>
public interface IGameNet
{
IInnerGameManager? GameManager { get; }
IInnerLobbyBehaviour? LobbyBehaviour { get; }
IInnerGameData? GameData { get; }
@@ -0,0 +1,5 @@
namespace Impostor.Api.Net.Inner.Objects.GameManager;
public interface IInnerGameManager
{
}
@@ -0,0 +1,8 @@
using Impostor.Api.Net.Inner.Objects.GameManager.Logic.HideAndSeek;
namespace Impostor.Api.Net.Inner.Objects.GameManager;
public interface IInnerHideAndSeekManager : IInnerGameManager
{
ILogicGameFlowHnS LogicFlowHnS { get; }
}
@@ -0,0 +1,5 @@
namespace Impostor.Api.Net.Inner.Objects.GameManager;
public interface IInnerNormalGameManager : IInnerGameManager
{
}
@@ -0,0 +1,8 @@
namespace Impostor.Api.Net.Inner.Objects.GameManager.Logic.HideAndSeek;
public interface ILogicGameFlowHnS
{
float CurrentFinalHideTime { get; }
float CurrentHideTime { get; }
}
@@ -12,6 +12,11 @@ namespace Impostor.Api.Net.Inner.Objects
/// </summary>
string PlayerName { get; }
/// <summary>
/// Gets the role type of the player.
/// </summary>
RoleTypes? RoleType { get; }
/// <summary>
/// Gets a value indicating whether the player is an impostor.
/// </summary>
+2
View File
@@ -45,5 +45,7 @@
Shapeshift = 46,
CheckMurder = 47,
CheckProtect = 48,
Pet = 49,
CancelPet = 50,
}
}
@@ -0,0 +1,25 @@
using System.Numerics;
using Impostor.Api.Games;
using Impostor.Api.Net.Inner;
using Impostor.Api.Unity;
namespace Impostor.Api.Net;
public static class MessageReaderExtensions
{
public static T? ReadNetObject<T>(this IMessageReader reader, IGame game)
where T : IInnerNetObject
{
return game.FindObjectByNetId<T>(reader.ReadPackedUInt32());
}
public static Vector2 ReadVector2(this IMessageReader reader)
{
const float range = 50f;
var x = reader.ReadUInt16() / (float)ushort.MaxValue;
var y = reader.ReadUInt16() / (float)ushort.MaxValue;
return new Vector2(Mathf.Lerp(-range, range, x), Mathf.Lerp(-range, range, y));
}
}
@@ -0,0 +1,32 @@
using System.Numerics;
using Impostor.Api.Games;
using Impostor.Api.Net.Inner;
using Impostor.Api.Unity;
namespace Impostor.Api.Net;
public static class MessageWriterExtensions
{
public static void Serialize(this GameCode gameCode, IMessageWriter writer)
{
writer.Write(gameCode.Value);
}
public static void Write(this IMessageWriter writer, IInnerNetObject? innerNetObject)
{
if (innerNetObject == null)
{
writer.Write(0);
}
else
{
writer.WritePacked(innerNetObject.NetId);
}
}
public static void Write(this IMessageWriter writer, Vector2 vector)
{
writer.Write((ushort)(Mathf.ReverseLerp(vector.X) * (double)ushort.MaxValue));
writer.Write((ushort)(Mathf.ReverseLerp(vector.Y) * (double)ushort.MaxValue));
}
}
@@ -1,28 +1,24 @@
using Impostor.Api.Innersloth;
using Impostor.Api.Innersloth.GameOptions;
namespace Impostor.Api.Net.Messages.C2S
{
public static class Message00HostGameC2S
{
public static void Serialize(IMessageWriter writer, GameOptionsData gameOptionsData)
public static void Serialize(IMessageWriter writer, IGameOptions gameOptions, CrossplayFlags crossplayFlags, GameFilterOptions gameFilterOptions)
{
writer.StartMessage(MessageFlags.HostGame);
gameOptionsData.Serialize(writer);
writer.Write(int.MaxValue); // crossplayFlags
GameOptionsFactory.Serialize(writer, gameOptions);
writer.Write((int)crossplayFlags);
gameFilterOptions.Serialize(writer);
writer.EndMessage();
}
/// <summary>
/// Deserialize a packet.
/// </summary>
/// <param name="reader"><see cref="IMessageReader" /> with <see cref="IMessageReader.Tag" /> 0.</param>
/// <returns>Deserialized <see cref="GameOptionsData" />.</returns>
public static GameOptionsData Deserialize(IMessageReader reader)
public static void Deserialize(IMessageReader reader, out IGameOptions gameOptions, out CrossplayFlags crossplayFlags, out GameFilterOptions gameFilterOptions)
{
var gameOptionsData = GameOptionsData.DeserializeCreate(reader);
reader.ReadInt32(); // crossplayFlags, not used yet
return gameOptionsData;
gameOptions = GameOptionsFactory.Deserialize(reader);
crossplayFlags = (CrossplayFlags)reader.ReadInt32();
gameFilterOptions = GameFilterOptions.Deserialize(reader);
}
}
}
@@ -1,5 +1,6 @@
using System;
using Impostor.Api.Innersloth;
using Impostor.Api.Innersloth.GameOptions;
namespace Impostor.Api.Net.Messages.C2S
{
@@ -10,7 +11,7 @@ namespace Impostor.Api.Net.Messages.C2S
throw new NotImplementedException();
}
public static void Deserialize(IMessageReader reader, out GameOptionsData options, out QuickChatModes chatMode)
public static void Deserialize(IMessageReader reader, out IGameOptions options, out QuickChatModes chatMode, out CrossplayFlags crossplayFlags, out GameFilterOptions gameFilterOptions)
{
var version = reader.ReadPackedInt32();
if (version != 2)
@@ -18,9 +19,10 @@ namespace Impostor.Api.Net.Messages.C2S
throw new NotSupportedException($"Version {version} of {nameof(Message16GetGameListC2S)} is not supported");
}
options = GameOptionsData.DeserializeCreate(reader);
options = GameOptionsFactory.Deserialize(reader);
chatMode = (QuickChatModes)reader.ReadByte();
reader.ReadInt32(); // crossplayFlags, not used yet
crossplayFlags = (CrossplayFlags)reader.ReadInt32();
gameFilterOptions = GameFilterOptions.Deserialize(reader);
}
}
}
@@ -1,82 +0,0 @@
using System;
using System.Numerics;
using Impostor.Api.Games;
using Impostor.Api.Net.Inner;
namespace Impostor.Api.Net.Messages
{
public interface IMessageReader : IDisposable
{
/// <summary>
/// Gets the tag of the message.
/// </summary>
byte Tag { get; }
/// <summary>
/// Gets the buffer of the message.
/// </summary>
byte[] Buffer { get; }
/// <summary>
/// Gets the offset of our current <see cref="IMessageReader" /> in the entire <see cref="Buffer" />.
/// </summary>
int Offset { get; }
/// <summary>
/// Gets the current position of the reader.
/// </summary>
int Position { get; }
/// <summary>
/// Gets the length of the buffer.
/// </summary>
int Length { get; }
IMessageReader ReadMessage();
bool ReadBoolean();
sbyte ReadSByte();
byte ReadByte();
ushort ReadUInt16();
short ReadInt16();
uint ReadUInt32();
int ReadInt32();
ulong ReadUInt64();
long ReadInt64();
float ReadSingle();
string ReadString(int length);
string ReadString();
ReadOnlyMemory<byte> ReadBytesAndSize();
ReadOnlyMemory<byte> ReadBytes(int length);
int ReadPackedInt32();
uint ReadPackedUInt32();
void CopyTo(IMessageWriter writer);
void Seek(int position);
void RemoveMessage(IMessageReader message);
IMessageReader Copy(int offset = 0);
T? ReadNetObject<T>(IGame game)
where T : IInnerNetObject;
Vector2 ReadVector2();
}
}
@@ -1,152 +0,0 @@
using System;
using System.Net;
using System.Numerics;
using Impostor.Api.Games;
using Impostor.Api.Net.Inner;
namespace Impostor.Api.Net.Messages
{
/// <summary>
/// Base message writer.
/// </summary>
public interface IMessageWriter : IDisposable
{
public byte[] Buffer { get; }
public int Length { get; set; }
public int Position { get; set; }
public MessageType SendOption { get; }
/// <summary>
/// Copies the contents of this writer into a new array.
/// </summary>
/// <param name="includeHeader">Whether to include message header in the array.</param>
/// <returns>An array containing the data in the current writer.</returns>
byte[] ToByteArray(bool includeHeader);
/// <summary>
/// Writes a boolean to the message.
/// </summary>
/// <param name="value">Value to write.</param>
void Write(bool value);
/// <summary>
/// Writes a sbyte to the message.
/// </summary>
/// <param name="value">Value to write.</param>
void Write(sbyte value);
/// <summary>
/// Writes a byte to the message.
/// </summary>
/// <param name="value">Value to write.</param>
void Write(byte value);
/// <summary>
/// Writes a short to the message.
/// </summary>
/// <param name="value">Value to write.</param>
void Write(short value);
/// <summary>
/// Writes an ushort to the message.
/// </summary>
/// <param name="value">Value to write.</param>
void Write(ushort value);
/// <summary>
/// Writes an uint to the message.
/// </summary>
/// <param name="value">Value to write.</param>
void Write(uint value);
/// <summary>
/// Writes an int to the message.
/// </summary>
/// <param name="value">Value to write.</param>
void Write(int value);
/// <summary>
/// Writes an ulong to the message.
/// </summary>
/// <param name="value">Value to write.</param>
void Write(ulong value);
/// <summary>
/// Writes an ulong to the message.
/// </summary>
/// <param name="value">Value to write.</param>
void Write(long value);
/// <summary>
/// Writes a float to the message.
/// </summary>
/// <param name="value">Value to write.</param>
void Write(float value);
/// <summary>
/// Writes a string to the message.
/// </summary>
/// <param name="value">Value to write.</param>
void Write(string value);
/// <summary>
/// Writes a <see cref="IPAddress" /> to the message.
/// </summary>
/// <param name="value">Value to write.</param>
void Write(IPAddress value);
/// <summary>
/// Writes an packed int to the message.
/// </summary>
/// <param name="value">Value to write.</param>
void WritePacked(int value);
/// <summary>
/// Writes an packed uint to the message.
/// </summary>
/// <param name="value">Value to write.</param>
void WritePacked(uint value);
/// <summary>
/// Writes raw bytes to the message.
/// </summary>
/// <param name="data">Bytes to write.</param>
void Write(ReadOnlyMemory<byte> data);
/// <summary>
/// Writes a game code to the message.
/// </summary>
/// <param name="value">Value to write.</param>
void Write(GameCode value);
void WriteBytesAndSize(byte[] bytes);
void WriteBytesAndSize(byte[] bytes, int length);
void WriteBytesAndSize(byte[] bytes, int offset, int length);
void Write(IInnerNetObject innerNetObject);
void Write(Vector2 vector);
/// <summary>
/// Starts a new message.
/// </summary>
/// <param name="typeFlag">Message flag header.</param>
void StartMessage(byte typeFlag);
/// <summary>
/// Mark the end of the message.
/// </summary>
void EndMessage();
/// <summary>
/// Clear the message writer.
/// </summary>
/// <param name="type">New type of the message.</param>
void Clear(MessageType type);
}
}
@@ -1,16 +0,0 @@
namespace Impostor.Api.Net.Messages
{
public interface IMessageWriterProvider
{
/// <summary>
/// Retrieves a <see cref="IMessageWriter" /> from the internal pool.
/// Make sure to call <see cref="System.IDisposable.Dispose" /> when you are done!.
/// </summary>
/// <param name="sendOption">
/// Whether to send the message as <see cref="MessageType.Reliable" /> or <see cref="MessageType.Unreliable" />.
/// Reliable packets will ensure delivery while unreliable packets may be lost.
/// </param>
/// <returns>A <see cref="IMessageWriter" /> from the pool.</returns>
IMessageWriter Get(MessageType sendOption = MessageType.Unreliable);
}
}
+20 -1
View File
@@ -1,4 +1,8 @@
namespace Impostor.Api.Net.Messages
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Impostor.Api.Net.Messages
{
public static class MessageFlags
{
@@ -24,5 +28,20 @@
public const byte SetActivePodType = 21;
public const byte QueryPlatformIds = 22;
public const byte QueryLobbyInfo = 23;
private static readonly Dictionary<byte, string> FlagCache;
static MessageFlags()
{
FlagCache = typeof(MessageFlags)
.GetFields(BindingFlags.Public | BindingFlags.Static)
.Where(fi => fi.IsLiteral && !fi.IsInitOnly)
.ToDictionary(x => (byte)x.GetValue(null)!, y => y.Name);
}
public static string FlagToString(byte flag)
{
return FlagCache[flag];
}
}
}
@@ -1,32 +0,0 @@
using System;
namespace Impostor.Api.Net.Messages
{
/// <summary>
/// Specifies how a message should be sent between connections.
/// </summary>
[Flags]
public enum MessageType : byte
{
/// <summary>
/// Requests unreliable delivery with no fragmentation.
/// </summary>
/// <remarks>
/// Sending data using unreliable delivery means that data is not guaranteed to arrive at it's destination nor is
/// it guaranteed to arrive only once. However, unreliable delivery can be faster than other methods and it
/// typically requires a smaller number of protocol bytes than other methods. There is also typically less
/// processing involved and less memory needed as packets are not stored once sent.
/// </remarks>
Unreliable,
/// <summary>
/// Requests data be sent reliably but with no fragmentation.
/// </summary>
/// <remarks>
/// Sending data reliably means that data is guaranteed to arrive and to arrive only once. Reliable delivery
/// typically requires more processing, more memory (as packets need to be stored in case they need resending),
/// a larger number of protocol bytes and can be slower than unreliable delivery.
/// </remarks>
Reliable,
}
}
@@ -1,17 +1,22 @@
using Impostor.Api.Innersloth;
using Impostor.Api.Innersloth.GameOptions;
namespace Impostor.Api.Net.Messages.Rpcs
{
public static class Rpc02SyncSettings
{
public static void Serialize(IMessageWriter writer, GameOptionsData gameOptionsData)
public static void Serialize(IMessageWriter writer, IGameOptions gameOptionsData)
{
gameOptionsData.Serialize(writer);
GameOptionsFactory.Serialize(writer, gameOptionsData);
}
public static void Deserialize(IMessageReader reader, GameOptionsData gameOptionsData)
public static void Deserialize(IMessageReader reader, out IGameOptions gameOptionsData)
{
gameOptionsData.Deserialize(reader.ReadBytesAndSize());
gameOptionsData = GameOptionsFactory.Deserialize(reader);
}
public static void DeserializeInto(IMessageReader reader, IGameOptions gameOptionsData)
{
GameOptionsFactory.DeserializeInto(reader, gameOptionsData);
}
}
}
@@ -0,0 +1,19 @@
using System.Numerics;
namespace Impostor.Api.Net.Messages.Rpcs
{
public static class Rpc49Pet
{
public static void Serialize(IMessageWriter writer, Vector2 position, Vector2 petPosition)
{
writer.Write(position);
writer.Write(petPosition);
}
public static void Deserialize(IMessageReader reader, out Vector2 position, out Vector2 petPosition)
{
position = reader.ReadVector2();
petPosition = reader.ReadVector2();
}
}
}
@@ -0,0 +1,13 @@
namespace Impostor.Api.Net.Messages.Rpcs
{
public static class Rpc50CancelPet
{
public static void Serialize(IMessageWriter writer)
{
}
public static void Deserialize(IMessageReader reader)
{
}
}
}
@@ -1,20 +1,19 @@
using System;
using Impostor.Api.Innersloth;
using Impostor.Api.Games;
namespace Impostor.Api.Net.Messages.S2C
{
public static class Message00HostGameS2C
{
public static void Serialize(IMessageWriter writer, int gameCode)
public static void Serialize(IMessageWriter writer, GameCode gameCode)
{
writer.StartMessage(MessageFlags.HostGame);
writer.Write(gameCode);
gameCode.Serialize(writer);
writer.EndMessage();
}
public static GameOptionsData Deserialize(IMessageReader reader)
public static void Deserialize(IMessageReader reader, out GameCode gameCode)
{
throw new NotImplementedException();
gameCode = reader.ReadInt32();
}
}
}
@@ -18,7 +18,7 @@ namespace Impostor.Api.Net.Messages.S2C
writer.StartMessage(0);
writer.Write(game.PublicIp.Address);
writer.Write((ushort)game.PublicIp.Port);
writer.Write(game.Code);
game.Code.Serialize(writer);
writer.Write(game.DisplayName ?? game.Host?.Client.Name ?? string.Empty);
writer.Write((byte)game.PlayerCount);
writer.WritePacked(1); // TODO: What does Age do?
@@ -10,7 +10,7 @@ namespace Impostor.Api.Net.Messages.S2C
public static void Serialize(IMessageWriter writer, GameCode gameCode, IEnumerable<PlatformSpecificData> playerSpecificDatas)
{
writer.StartMessage(MessageFlags.QueryPlatformIds);
writer.Write(gameCode);
gameCode.Serialize(writer);
foreach (var playerSpecificData in playerSpecificDatas)
{
playerSpecificData.Serialize(writer);
+35 -60
View File
@@ -1,94 +1,69 @@
{
"version": 1,
"dependencies": {
".NETStandard,Version=v2.1": {
"net7.0": {
"Impostor.Hazel.Abstractions": {
"type": "Direct",
"requested": "[1.0.0, )",
"resolved": "1.0.0",
"contentHash": "x56AEsY5fKU2Z5O7ZrzEqKfr62kq/C05Aevcciwz5yMfOQlpwuFI1awgNGJsoe+bcx+XnFc3+l+eadtY72aZsg=="
},
"Microsoft.Extensions.Hosting.Abstractions": {
"type": "Direct",
"requested": "[6.0.0, )",
"resolved": "6.0.0",
"contentHash": "GcT5l2CYXL6Sa27KCSh0TixsRfADUgth+ojQSD5EkzisZxmGFh7CwzkcYuGwvmXLjr27uWRNrJ2vuuEjMhU05Q==",
"requested": "[7.0.0, )",
"resolved": "7.0.0",
"contentHash": "43n9Je09z0p/7ViPxfRqs5BUItRLNVh5b6JH40F2Agkh2NBsY/jpNYTtbCcxrHCsA3oRmbR6RJBzUutB4VZvNQ==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "6.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
"Microsoft.Extensions.FileProviders.Abstractions": "6.0.0"
"Microsoft.Extensions.Configuration.Abstractions": "7.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
"Microsoft.Extensions.FileProviders.Abstractions": "7.0.0"
}
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Direct",
"requested": "[6.0.1, )",
"resolved": "6.0.1",
"contentHash": "dzB2Cgg+JmrouhjkcQGzSFjjvpwlq353i8oBQO2GWNjCXSzhbtBRUf28HSauWe7eib3wYOdb3tItdjRwAdwCSg==",
"dependencies": {
"System.Buffers": "4.5.1",
"System.Memory": "4.5.4"
}
},
"Nullable": {
"type": "Direct",
"requested": "[1.3.0, )",
"resolved": "1.3.0",
"contentHash": "xHAviTdTY3n+t1nEPN4JPRQR5lI124qRKVw+U9H7dO5sDNPpzoWeo/MQy7dSUmv9eD3k/CJVKokz1tFK+JOzRw=="
"requested": "[7.0.0, )",
"resolved": "7.0.0",
"contentHash": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw=="
},
"StyleCop.Analyzers": {
"type": "Direct",
"requested": "[1.1.118, )",
"resolved": "1.1.118",
"contentHash": "Onx6ovGSqXSK07n/0eM3ZusiNdB6cIlJdabQhWGgJp3Vooy9AaLS/tigeybOJAobqbtggTamoWndz72JscZBvw=="
"requested": "[1.2.0-beta.435, )",
"resolved": "1.2.0-beta.435",
"contentHash": "TADk7vdGXtfTnYCV7GyleaaRTQjfoSfZXprQrVMm7cSJtJbFc1QIbWPyLvrgrfGdfHbGmUPvaN4ODKNxg2jgPQ==",
"dependencies": {
"StyleCop.Analyzers.Unstable": "1.2.0.435"
}
},
"Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "qWzV9o+ZRWq+pGm+1dF+R7qTgTYoXvbyowRoBxQJGfqTpqDun2eteerjRQhq5PQ/14S+lqto3Ft4gYaRyl4rdQ==",
"resolved": "7.0.0",
"contentHash": "f34u2eaqIjNO9YLHBz8rozVZ+TcFiFs0F3r7nUJd7FRkVSxk8u4OpoK226mi49MwexHOR2ibP9MFvRUaLilcQQ==",
"dependencies": {
"Microsoft.Extensions.Primitives": "6.0.0"
"Microsoft.Extensions.Primitives": "7.0.0"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg=="
"resolved": "7.0.0",
"contentHash": "h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw=="
},
"Microsoft.Extensions.FileProviders.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "0pd4/fho0gC12rQswaGQxbU34jOS1TPS8lZPpkFCH68ppQjHNHYle9iRuHeev1LhrJ94YPvzcRd8UmIuFk23Qw==",
"resolved": "7.0.0",
"contentHash": "NyawiW9ZT/liQb34k9YqBSNPLuuPkrjMgQZ24Y/xXX1RoiBkLUdPMaQTmxhZ5TYu8ZKZ9qayzil75JX95vGQUg==",
"dependencies": {
"Microsoft.Extensions.Primitives": "6.0.0"
"Microsoft.Extensions.Primitives": "7.0.0"
}
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ==",
"dependencies": {
"System.Memory": "4.5.4",
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
"resolved": "7.0.0",
"contentHash": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q=="
},
"System.Buffers": {
"StyleCop.Analyzers.Unstable": {
"type": "Transitive",
"resolved": "4.5.1",
"contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
},
"System.Memory": {
"type": "Transitive",
"resolved": "4.5.4",
"contentHash": "1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==",
"dependencies": {
"System.Buffers": "4.5.1",
"System.Numerics.Vectors": "4.4.0",
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
}
},
"System.Numerics.Vectors": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ=="
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
"resolved": "1.2.0.435",
"contentHash": "ouwPWZxbOV3SmCZxIRqHvljkSzkCyi1tDoMzQtDb/bRP8ctASV/iRJr+A2Gdj0QLaLmWnqTWDrH82/iP+X80Lg=="
}
}
}
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Net;
using System.Text;
using Impostor.Api.Games;
using Impostor.Api.Net.Messages;
using Impostor.Hazel.Abstractions;
namespace Impostor.Benchmarks.Data
{
@@ -6,7 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
<PackageReference Include="BenchmarkDotNet" Version="0.13.2" />
</ItemGroup>
<ItemGroup>
File diff suppressed because it is too large. Load diff
@@ -9,7 +9,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
</ItemGroup>
</Project>
+4 -3
View File
@@ -2,9 +2,10 @@
using System.Threading;
using System.Threading.Tasks;
using Impostor.Api.Innersloth;
using Impostor.Api.Net.Messages;
using Impostor.Api.Innersloth.GameOptions;
using Impostor.Api.Net.Messages.C2S;
using Impostor.Hazel;
using Impostor.Hazel.Abstractions;
using Impostor.Hazel.Udp;
using Serilog;
@@ -27,11 +28,11 @@ namespace Impostor.Client.App
var writeGameCreate = MessageWriter.Get(MessageType.Reliable);
Message00HostGameC2S.Serialize(writeGameCreate, new GameOptionsData
Message00HostGameC2S.Serialize(writeGameCreate, new LegacyGameOptionsData
{
MaxPlayers = 4,
NumImpostors = 2,
});
}, CrossplayFlags.All, GameFilterOptions.CreateDefault());
// TODO: ObjectPool for MessageReaders
using (var connection = new UdpClientConnection(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 22023), null))
+46 -45
View File
@@ -1,95 +1,96 @@
{
"version": 1,
"dependencies": {
"net6.0": {
"net7.0": {
"Serilog.Sinks.Console": {
"type": "Direct",
"requested": "[4.0.1, )",
"resolved": "4.0.1",
"contentHash": "apLOvSJQLlIbKlbx+Y2UDHSP05kJsV7mou+fvJoRGs/iR+jC22r8cuFVMjjfVxz/AD4B2UCltFhE1naRLXwKNw==",
"requested": "[4.1.0, )",
"resolved": "4.1.0",
"contentHash": "K6N5q+5fetjnJPvCmkWOpJ/V8IEIoMIB1s86OzBrbxwTyHxdx3pmz4H+8+O/Dc/ftUX12DM1aynx/dDowkwzqg==",
"dependencies": {
"Serilog": "2.10.0"
}
},
"Impostor.Hazel": {
"type": "Transitive",
"resolved": "1.0.0",
"contentHash": "FgVKuIWK+o6Q+wOPFoZZTeoSuVh4giAhrS8Zvs6O0++Bg8RxH4Lw51uSwnexLiwosXveUCIXICzgGHmRyguVSA==",
"dependencies": {
"Impostor.Hazel.Abstractions": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
"Microsoft.Extensions.ObjectPool": "7.0.1",
"Serilog": "2.12.0"
}
},
"Impostor.Hazel.Abstractions": {
"type": "Transitive",
"resolved": "1.0.0",
"contentHash": "x56AEsY5fKU2Z5O7ZrzEqKfr62kq/C05Aevcciwz5yMfOQlpwuFI1awgNGJsoe+bcx+XnFc3+l+eadtY72aZsg=="
},
"Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "qWzV9o+ZRWq+pGm+1dF+R7qTgTYoXvbyowRoBxQJGfqTpqDun2eteerjRQhq5PQ/14S+lqto3Ft4gYaRyl4rdQ==",
"resolved": "7.0.0",
"contentHash": "f34u2eaqIjNO9YLHBz8rozVZ+TcFiFs0F3r7nUJd7FRkVSxk8u4OpoK226mi49MwexHOR2ibP9MFvRUaLilcQQ==",
"dependencies": {
"Microsoft.Extensions.Primitives": "6.0.0"
"Microsoft.Extensions.Primitives": "7.0.0"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg=="
"resolved": "7.0.0",
"contentHash": "h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw=="
},
"Microsoft.Extensions.FileProviders.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "0pd4/fho0gC12rQswaGQxbU34jOS1TPS8lZPpkFCH68ppQjHNHYle9iRuHeev1LhrJ94YPvzcRd8UmIuFk23Qw==",
"resolved": "7.0.0",
"contentHash": "NyawiW9ZT/liQb34k9YqBSNPLuuPkrjMgQZ24Y/xXX1RoiBkLUdPMaQTmxhZ5TYu8ZKZ9qayzil75JX95vGQUg==",
"dependencies": {
"Microsoft.Extensions.Primitives": "6.0.0"
"Microsoft.Extensions.Primitives": "7.0.0"
}
},
"Microsoft.Extensions.Hosting.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "GcT5l2CYXL6Sa27KCSh0TixsRfADUgth+ojQSD5EkzisZxmGFh7CwzkcYuGwvmXLjr27uWRNrJ2vuuEjMhU05Q==",
"resolved": "7.0.0",
"contentHash": "43n9Je09z0p/7ViPxfRqs5BUItRLNVh5b6JH40F2Agkh2NBsY/jpNYTtbCcxrHCsA3oRmbR6RJBzUutB4VZvNQ==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "6.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
"Microsoft.Extensions.FileProviders.Abstractions": "6.0.0"
"Microsoft.Extensions.Configuration.Abstractions": "7.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
"Microsoft.Extensions.FileProviders.Abstractions": "7.0.0"
}
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Transitive",
"resolved": "6.0.1",
"contentHash": "dzB2Cgg+JmrouhjkcQGzSFjjvpwlq353i8oBQO2GWNjCXSzhbtBRUf28HSauWe7eib3wYOdb3tItdjRwAdwCSg=="
"resolved": "7.0.0",
"contentHash": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw=="
},
"Microsoft.Extensions.ObjectPool": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "mOhbL7mbV9sEMQ0G+MUOR9mx+cLTL25jcTXaFYe14hX/4+VuchVgNi7FqSQyLYLPNuGJOm/Puc1ZsSgjr+0LVA=="
"resolved": "7.0.1",
"contentHash": "dDFItid/TGJljAnqbUQ0PkAl6ShIG0htwRR8J0cG/5Il6lIZPfkIZMwrZTWiF23AiQcqt6suPaUy2ih6dsCB9Q=="
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ==",
"dependencies": {
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
"resolved": "7.0.0",
"contentHash": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q=="
},
"Serilog": {
"type": "Transitive",
"resolved": "2.10.0",
"contentHash": "+QX0hmf37a0/OZLxM3wL7V6/ADvC1XihXN4Kq/p6d8lCPfgkRdiuhbWlMaFjR9Av0dy5F0+MBeDmDdRZN/YwQA=="
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
},
"hazel": {
"type": "Project",
"dependencies": {
"Impostor.Api": "1.7.1-dev",
"Microsoft.Extensions.ObjectPool": "5.0.0",
"Serilog": "2.10.0"
}
"resolved": "2.12.0",
"contentHash": "xaiJLIdu6rYMKfQMYUZgTy8YK7SMZjB4Yk50C/u//Z4OsvxkUfSPJy4nknfvwAC34yr13q7kcyh4grbwhSxyZg=="
},
"impostor.api": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Hosting.Abstractions": "6.0.0",
"Microsoft.Extensions.Logging.Abstractions": "6.0.1"
"Impostor.Hazel.Abstractions": "[1.0.0, )",
"Microsoft.Extensions.Hosting.Abstractions": "[7.0.0, )",
"Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )"
}
},
"impostor.client": {
"type": "Project",
"dependencies": {
"Hazel": "1.7.1-dev",
"Impostor.Api": "1.7.1-dev"
"Impostor.Api": "[1.7.3-dev, )",
"Impostor.Hazel": "[1.0.0, )"
}
}
}
+1 -1
View File
@@ -2,7 +2,7 @@
<ItemGroup>
<ProjectReference Include="..\Impostor.Api\Impostor.Api.csproj" />
<ProjectReference Include="..\Impostor.Hazel\Hazel\Hazel.csproj" />
<PackageReference Include="Impostor.Hazel" Version="1.0.0" />
</ItemGroup>
</Project>
+42 -40
View File
@@ -1,79 +1,81 @@
{
"version": 1,
"dependencies": {
"net6.0": {
"net7.0": {
"Impostor.Hazel": {
"type": "Direct",
"requested": "[1.0.0, )",
"resolved": "1.0.0",
"contentHash": "FgVKuIWK+o6Q+wOPFoZZTeoSuVh4giAhrS8Zvs6O0++Bg8RxH4Lw51uSwnexLiwosXveUCIXICzgGHmRyguVSA==",
"dependencies": {
"Impostor.Hazel.Abstractions": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
"Microsoft.Extensions.ObjectPool": "7.0.1",
"Serilog": "2.12.0"
}
},
"Impostor.Hazel.Abstractions": {
"type": "Transitive",
"resolved": "1.0.0",
"contentHash": "x56AEsY5fKU2Z5O7ZrzEqKfr62kq/C05Aevcciwz5yMfOQlpwuFI1awgNGJsoe+bcx+XnFc3+l+eadtY72aZsg=="
},
"Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "qWzV9o+ZRWq+pGm+1dF+R7qTgTYoXvbyowRoBxQJGfqTpqDun2eteerjRQhq5PQ/14S+lqto3Ft4gYaRyl4rdQ==",
"resolved": "7.0.0",
"contentHash": "f34u2eaqIjNO9YLHBz8rozVZ+TcFiFs0F3r7nUJd7FRkVSxk8u4OpoK226mi49MwexHOR2ibP9MFvRUaLilcQQ==",
"dependencies": {
"Microsoft.Extensions.Primitives": "6.0.0"
"Microsoft.Extensions.Primitives": "7.0.0"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg=="
"resolved": "7.0.0",
"contentHash": "h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw=="
},
"Microsoft.Extensions.FileProviders.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "0pd4/fho0gC12rQswaGQxbU34jOS1TPS8lZPpkFCH68ppQjHNHYle9iRuHeev1LhrJ94YPvzcRd8UmIuFk23Qw==",
"resolved": "7.0.0",
"contentHash": "NyawiW9ZT/liQb34k9YqBSNPLuuPkrjMgQZ24Y/xXX1RoiBkLUdPMaQTmxhZ5TYu8ZKZ9qayzil75JX95vGQUg==",
"dependencies": {
"Microsoft.Extensions.Primitives": "6.0.0"
"Microsoft.Extensions.Primitives": "7.0.0"
}
},
"Microsoft.Extensions.Hosting.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "GcT5l2CYXL6Sa27KCSh0TixsRfADUgth+ojQSD5EkzisZxmGFh7CwzkcYuGwvmXLjr27uWRNrJ2vuuEjMhU05Q==",
"resolved": "7.0.0",
"contentHash": "43n9Je09z0p/7ViPxfRqs5BUItRLNVh5b6JH40F2Agkh2NBsY/jpNYTtbCcxrHCsA3oRmbR6RJBzUutB4VZvNQ==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "6.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
"Microsoft.Extensions.FileProviders.Abstractions": "6.0.0"
"Microsoft.Extensions.Configuration.Abstractions": "7.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
"Microsoft.Extensions.FileProviders.Abstractions": "7.0.0"
}
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Transitive",
"resolved": "6.0.1",
"contentHash": "dzB2Cgg+JmrouhjkcQGzSFjjvpwlq353i8oBQO2GWNjCXSzhbtBRUf28HSauWe7eib3wYOdb3tItdjRwAdwCSg=="
"resolved": "7.0.0",
"contentHash": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw=="
},
"Microsoft.Extensions.ObjectPool": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "mOhbL7mbV9sEMQ0G+MUOR9mx+cLTL25jcTXaFYe14hX/4+VuchVgNi7FqSQyLYLPNuGJOm/Puc1ZsSgjr+0LVA=="
"resolved": "7.0.1",
"contentHash": "dDFItid/TGJljAnqbUQ0PkAl6ShIG0htwRR8J0cG/5Il6lIZPfkIZMwrZTWiF23AiQcqt6suPaUy2ih6dsCB9Q=="
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ==",
"dependencies": {
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
"resolved": "7.0.0",
"contentHash": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q=="
},
"Serilog": {
"type": "Transitive",
"resolved": "2.10.0",
"contentHash": "+QX0hmf37a0/OZLxM3wL7V6/ADvC1XihXN4Kq/p6d8lCPfgkRdiuhbWlMaFjR9Av0dy5F0+MBeDmDdRZN/YwQA=="
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
},
"hazel": {
"type": "Project",
"dependencies": {
"Impostor.Api": "1.7.1-dev",
"Microsoft.Extensions.ObjectPool": "5.0.0",
"Serilog": "2.10.0"
}
"resolved": "2.12.0",
"contentHash": "xaiJLIdu6rYMKfQMYUZgTy8YK7SMZjB4Yk50C/u//Z4OsvxkUfSPJy4nknfvwAC34yr13q7kcyh4grbwhSxyZg=="
},
"impostor.api": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Hosting.Abstractions": "6.0.0",
"Microsoft.Extensions.Logging.Abstractions": "6.0.1"
"Impostor.Hazel.Abstractions": "[1.0.0, )",
"Microsoft.Extensions.Hosting.Abstractions": "[7.0.0, )",
"Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )"
}
}
}
@@ -1,61 +1,59 @@
{
"version": 1,
"dependencies": {
"net6.0": {
"net7.0": {
"Impostor.Hazel.Abstractions": {
"type": "Transitive",
"resolved": "1.0.0",
"contentHash": "x56AEsY5fKU2Z5O7ZrzEqKfr62kq/C05Aevcciwz5yMfOQlpwuFI1awgNGJsoe+bcx+XnFc3+l+eadtY72aZsg=="
},
"Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "qWzV9o+ZRWq+pGm+1dF+R7qTgTYoXvbyowRoBxQJGfqTpqDun2eteerjRQhq5PQ/14S+lqto3Ft4gYaRyl4rdQ==",
"resolved": "7.0.0",
"contentHash": "f34u2eaqIjNO9YLHBz8rozVZ+TcFiFs0F3r7nUJd7FRkVSxk8u4OpoK226mi49MwexHOR2ibP9MFvRUaLilcQQ==",
"dependencies": {
"Microsoft.Extensions.Primitives": "6.0.0"
"Microsoft.Extensions.Primitives": "7.0.0"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg=="
"resolved": "7.0.0",
"contentHash": "h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw=="
},
"Microsoft.Extensions.FileProviders.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "0pd4/fho0gC12rQswaGQxbU34jOS1TPS8lZPpkFCH68ppQjHNHYle9iRuHeev1LhrJ94YPvzcRd8UmIuFk23Qw==",
"resolved": "7.0.0",
"contentHash": "NyawiW9ZT/liQb34k9YqBSNPLuuPkrjMgQZ24Y/xXX1RoiBkLUdPMaQTmxhZ5TYu8ZKZ9qayzil75JX95vGQUg==",
"dependencies": {
"Microsoft.Extensions.Primitives": "6.0.0"
"Microsoft.Extensions.Primitives": "7.0.0"
}
},
"Microsoft.Extensions.Hosting.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "GcT5l2CYXL6Sa27KCSh0TixsRfADUgth+ojQSD5EkzisZxmGFh7CwzkcYuGwvmXLjr27uWRNrJ2vuuEjMhU05Q==",
"resolved": "7.0.0",
"contentHash": "43n9Je09z0p/7ViPxfRqs5BUItRLNVh5b6JH40F2Agkh2NBsY/jpNYTtbCcxrHCsA3oRmbR6RJBzUutB4VZvNQ==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "6.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
"Microsoft.Extensions.FileProviders.Abstractions": "6.0.0"
"Microsoft.Extensions.Configuration.Abstractions": "7.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
"Microsoft.Extensions.FileProviders.Abstractions": "7.0.0"
}
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Transitive",
"resolved": "6.0.1",
"contentHash": "dzB2Cgg+JmrouhjkcQGzSFjjvpwlq353i8oBQO2GWNjCXSzhbtBRUf28HSauWe7eib3wYOdb3tItdjRwAdwCSg=="
"resolved": "7.0.0",
"contentHash": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw=="
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ==",
"dependencies": {
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
"resolved": "7.0.0",
"contentHash": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q=="
},
"impostor.api": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Hosting.Abstractions": "6.0.0",
"Microsoft.Extensions.Logging.Abstractions": "6.0.1"
"Impostor.Hazel.Abstractions": "[1.0.0, )",
"Microsoft.Extensions.Hosting.Abstractions": "[7.0.0, )",
"Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )"
}
}
}
@@ -1,6 +1,7 @@
using System.Threading.Tasks;
using Impostor.Api.Games.Managers;
using Impostor.Api.Innersloth;
using Impostor.Api.Innersloth.GameOptions;
using Impostor.Api.Plugins;
using Microsoft.Extensions.Logging;
@@ -22,7 +23,7 @@ namespace Impostor.Plugins.Example
{
_logger.LogInformation("Example is being enabled.");
var game = await _gameManager.CreateAsync(new GameOptionsData());
var game = await _gameManager.CreateAsync(new NormalGameOptions(), GameFilterOptions.CreateDefault());
if (game == null)
{
_logger.LogWarning("Example game creation was cancelled");
@@ -19,21 +19,16 @@ namespace Impostor.Plugins.Example.Handlers
{
_logger.LogInformation("Game creation requested by {client}", e.Client == null ? "a plugin" : e.Client.Name);
if (e.Client != null)
{
var gameCode = GameCode.From(e.Client.Name);
if (!gameCode.IsInvalid)
{
e.GameCode = gameCode;
}
if (e.Client.Name == "dima")
{
e.IsCancelled = true;
e.Client.DisconnectAsync(DisconnectReason.Custom, "No you dont >:(");
}
}
// TODO: Code below causes the lobby to stop loading and close after 5 secs.
// if (e.Client != null)
// {
// var gameCode = GameCode.From(e.Client.Name);
//
// if (!gameCode.IsInvalid)
// {
// e.GameCode = gameCode;
// }
// }
}
[EventListener]
@@ -57,7 +52,7 @@ namespace Impostor.Plugins.Example.Handlers
{
var info = player.Character!.PlayerInfo;
_logger.LogInformation("- {player} is {role}", info.PlayerName, info.IsImpostor ? "an impostor" : "a crewmate");
_logger.LogInformation("- {player} is {role}", info.PlayerName, info.RoleType);
}
}
@@ -4,6 +4,7 @@ using System.Threading.Tasks;
using Impostor.Api.Events;
using Impostor.Api.Events.Player;
using Impostor.Api.Innersloth.Customization;
using Impostor.Api.Innersloth.GameOptions;
using Microsoft.Extensions.Logging;
namespace Impostor.Plugins.Example.Handlers
@@ -65,9 +66,13 @@ namespace Impostor.Plugins.Example.Handlers
if (e.Message == "test")
{
e.Game.Options.KillCooldown = 0;
e.Game.Options.NumImpostors = 2;
e.Game.Options.PlayerSpeedMod = 5;
if (e.Game.Options is NormalGameOptions normalGameOptions)
{
normalGameOptions.KillCooldown = 0;
normalGameOptions.PlayerSpeedMod = 5;
}
await e.Game.SyncSettingsAsync();
}
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<Version>1.0.0</Version>
<AssemblyTitle>Example</AssemblyTitle>
+26 -53
View File
@@ -1,86 +1,59 @@
{
"version": 1,
"dependencies": {
".NETStandard,Version=v2.1": {
"net7.0": {
"Impostor.Hazel.Abstractions": {
"type": "Transitive",
"resolved": "1.0.0",
"contentHash": "x56AEsY5fKU2Z5O7ZrzEqKfr62kq/C05Aevcciwz5yMfOQlpwuFI1awgNGJsoe+bcx+XnFc3+l+eadtY72aZsg=="
},
"Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "qWzV9o+ZRWq+pGm+1dF+R7qTgTYoXvbyowRoBxQJGfqTpqDun2eteerjRQhq5PQ/14S+lqto3Ft4gYaRyl4rdQ==",
"resolved": "7.0.0",
"contentHash": "f34u2eaqIjNO9YLHBz8rozVZ+TcFiFs0F3r7nUJd7FRkVSxk8u4OpoK226mi49MwexHOR2ibP9MFvRUaLilcQQ==",
"dependencies": {
"Microsoft.Extensions.Primitives": "6.0.0"
"Microsoft.Extensions.Primitives": "7.0.0"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg=="
"resolved": "7.0.0",
"contentHash": "h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw=="
},
"Microsoft.Extensions.FileProviders.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "0pd4/fho0gC12rQswaGQxbU34jOS1TPS8lZPpkFCH68ppQjHNHYle9iRuHeev1LhrJ94YPvzcRd8UmIuFk23Qw==",
"resolved": "7.0.0",
"contentHash": "NyawiW9ZT/liQb34k9YqBSNPLuuPkrjMgQZ24Y/xXX1RoiBkLUdPMaQTmxhZ5TYu8ZKZ9qayzil75JX95vGQUg==",
"dependencies": {
"Microsoft.Extensions.Primitives": "6.0.0"
"Microsoft.Extensions.Primitives": "7.0.0"
}
},
"Microsoft.Extensions.Hosting.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "GcT5l2CYXL6Sa27KCSh0TixsRfADUgth+ojQSD5EkzisZxmGFh7CwzkcYuGwvmXLjr27uWRNrJ2vuuEjMhU05Q==",
"resolved": "7.0.0",
"contentHash": "43n9Je09z0p/7ViPxfRqs5BUItRLNVh5b6JH40F2Agkh2NBsY/jpNYTtbCcxrHCsA3oRmbR6RJBzUutB4VZvNQ==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "6.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
"Microsoft.Extensions.FileProviders.Abstractions": "6.0.0"
"Microsoft.Extensions.Configuration.Abstractions": "7.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
"Microsoft.Extensions.FileProviders.Abstractions": "7.0.0"
}
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Transitive",
"resolved": "6.0.1",
"contentHash": "dzB2Cgg+JmrouhjkcQGzSFjjvpwlq353i8oBQO2GWNjCXSzhbtBRUf28HSauWe7eib3wYOdb3tItdjRwAdwCSg==",
"dependencies": {
"System.Buffers": "4.5.1",
"System.Memory": "4.5.4"
}
"resolved": "7.0.0",
"contentHash": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw=="
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ==",
"dependencies": {
"System.Memory": "4.5.4",
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"System.Buffers": {
"type": "Transitive",
"resolved": "4.5.1",
"contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
},
"System.Memory": {
"type": "Transitive",
"resolved": "4.5.4",
"contentHash": "1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==",
"dependencies": {
"System.Buffers": "4.5.1",
"System.Numerics.Vectors": "4.4.0",
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
}
},
"System.Numerics.Vectors": {
"type": "Transitive",
"resolved": "4.4.0",
"contentHash": "UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ=="
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
"resolved": "7.0.0",
"contentHash": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q=="
},
"impostor.api": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Hosting.Abstractions": "6.0.0",
"Microsoft.Extensions.Logging.Abstractions": "6.0.1"
"Impostor.Hazel.Abstractions": "[1.0.0, )",
"Microsoft.Extensions.Hosting.Abstractions": "[7.0.0, )",
"Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )"
}
}
}
@@ -1,6 +1,5 @@
using Impostor.Api.Events.Client;
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
namespace Impostor.Server.Events.Client
{
@@ -1,13 +0,0 @@
using System.Threading.Tasks;
using Impostor.Server.Net.Redirector;
namespace Impostor.Server
{
public static class NodeLocatorExtensions
{
public static async ValueTask<bool> ExistsAsync(this INodeLocator nodeLocator, string gameCode)
{
return await nodeLocator.FindAsync(gameCode) != null;
}
}
}
+1
View File
@@ -0,0 +1 @@
global using Impostor.Hazel.Abstractions;
+7 -10
View File
@@ -20,23 +20,20 @@
<ItemGroup>
<ProjectReference Include="..\Impostor.Api\Impostor.Api.csproj" />
<ProjectReference Include="..\Impostor.Hazel\Hazel\Hazel.csproj" />
<PackageReference Include="Impostor.Hazel" Version="1.0.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="6.0.5" />
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="6.0.5" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="4.2.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="7.0.1" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="5.0.1" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.435">
<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 6.0.0.0, but Hazel still depends on version 5.0.0.0. Figure out why this happens. -->
<PackageReference Include="System.IO.Pipelines" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
+12 -13
View File
@@ -5,6 +5,7 @@ using Impostor.Api;
using Impostor.Api.Config;
using Impostor.Api.Games;
using Impostor.Api.Innersloth;
using Impostor.Api.Innersloth.GameOptions;
using Impostor.Api.Net;
using Impostor.Api.Net.Custom;
using Impostor.Api.Net.Messages;
@@ -37,13 +38,13 @@ namespace Impostor.Server.Net
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;
}
_logger.LogWarning("Client {Name} ({Id}) was caught cheating: [{Context}] {Message}", Name, Id, context.Name, message);
if (_antiCheatConfig.BanIpFromGame)
{
Player?.Game.BanIp(Connection.EndPoint.Address);
@@ -58,17 +59,17 @@ namespace Impostor.Server.Net
{
var flag = reader.Tag;
_logger.LogTrace("[{0}] Server got {1}.", Id, flag);
_logger.LogTrace("[{0}] Server got {1}.", Id, MessageFlags.FlagToString(flag));
switch (flag)
{
case MessageFlags.HostGame:
{
// Read game settings.
var gameInfo = Message00HostGameC2S.Deserialize(reader);
Message00HostGameC2S.Deserialize(reader, out var gameOptions, out _, out var gameFilterOptions);
// Create game.
var game = await _gameManager.CreateAsync(this, gameInfo);
var game = await _gameManager.CreateAsync(this, gameOptions, gameFilterOptions);
if (game == null)
{
@@ -259,8 +260,8 @@ namespace Impostor.Server.Net
case MessageFlags.GetGameListV2:
{
Message16GetGameListC2S.Deserialize(reader, out var options, out _);
await OnRequestGameListAsync(options);
Message16GetGameListC2S.Deserialize(reader, out var options, out _, out _, out var filterOptions);
await OnRequestGameListAsync(options, filterOptions);
break;
}
@@ -354,15 +355,13 @@ namespace Impostor.Server.Net
/// <summary>
/// Triggered when the connected client requests the game listing.
/// </summary>
/// <param name="options">
/// All options given.
/// At this moment, the client can only specify the map, impostor count and chat language.
/// </param>
private ValueTask OnRequestGameListAsync(GameOptionsData options)
/// <param name="options">Options specific to the game mode. At this moment, the client can only specify the map, impostor count and chat language.</param>
/// <param name="filterOptions">Filter options not specific to the game mode.</param>
private ValueTask OnRequestGameListAsync(IGameOptions options, GameFilterOptions filterOptions)
{
using var message = MessageWriter.Get(MessageType.Reliable);
var games = _gameManager.FindListings((MapFlags)options.Map, options.NumImpostors, options.Keywords, this.GameVersion);
var games = _gameManager.FindListings((MapFlags)options.Map, options.NumImpostors, options.Keywords, this.GameVersion, filterOptions.FilterTags);
Message16GetGameListS2C.Serialize(message, games);
-1
View File
@@ -4,7 +4,6 @@ using System.Threading.Tasks;
using Impostor.Api;
using Impostor.Api.Innersloth;
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
using Impostor.Server.Net.State;
namespace Impostor.Server.Net
@@ -1,7 +1,6 @@
using System.Net;
using System.Threading.Tasks;
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
using Impostor.Hazel;
using Microsoft.Extensions.Logging;
@@ -3,7 +3,6 @@ using Impostor.Api.Games;
using Impostor.Api.Net;
using Impostor.Api.Net.Custom;
using Impostor.Api.Net.Inner;
using Impostor.Api.Net.Messages;
using Impostor.Server.Net.State;
namespace Impostor.Server.Net.Inner
@@ -1,5 +1,6 @@
using System.Numerics;
using System.Threading.Tasks;
using Impostor.Api.Net;
using Impostor.Api.Net.Inner;
using Impostor.Api.Net.Inner.Objects.Components;
@@ -6,7 +6,6 @@ using Impostor.Api.Events.Managers;
using Impostor.Api.Net;
using Impostor.Api.Net.Custom;
using Impostor.Api.Net.Inner;
using Impostor.Api.Net.Messages;
using Impostor.Api.Net.Messages.Rpcs;
using Impostor.Server.Events.Player;
using Impostor.Server.Net.Inner.Objects.ShipStatus;
@@ -4,7 +4,6 @@ using Impostor.Api.Events.Managers;
using Impostor.Api.Net;
using Impostor.Api.Net.Custom;
using Impostor.Api.Net.Inner;
using Impostor.Api.Net.Messages;
using Impostor.Api.Net.Messages.Rpcs;
using Impostor.Server.Events.Player;
using Impostor.Server.Net.State;
@@ -109,6 +108,18 @@ namespace Impostor.Server.Net.Inner.Objects.Components
Rpc31ClimbLadder.Deserialize(reader, out var ladderId, out var lastClimbLadderSid);
break;
case RpcCalls.Pet:
{
Rpc49Pet.Deserialize(reader, out var position, out var petPosition);
break;
}
case RpcCalls.CancelPet:
{
Rpc50CancelPet.Deserialize(reader);
break;
}
default:
return await base.HandleRpcAsync(sender, target, call, reader);
}
@@ -6,7 +6,6 @@ using Impostor.Api.Net;
using Impostor.Api.Net.Custom;
using Impostor.Api.Net.Inner;
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;
@@ -0,0 +1,98 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Impostor.Api.Net;
using Impostor.Api.Net.Custom;
using Impostor.Api.Net.Inner;
using Impostor.Api.Net.Inner.Objects.GameManager;
using Impostor.Server.Net.Inner.Objects.GameManager.Logic;
using Impostor.Server.Net.State;
using Microsoft.Extensions.Logging;
namespace Impostor.Server.Net.Inner.Objects.GameManager;
internal abstract class InnerGameManager : InnerNetObject, IInnerGameManager
{
private readonly ILogger<InnerGameManager> _logger;
private readonly List<GameLogicComponent> _logicComponents = new();
public InnerGameManager(ICustomMessageManager<ICustomRpc> customMessageManager, Game game, ILogger<InnerGameManager> logger) : base(customMessageManager, game)
{
_logger = logger;
Components.Add(this);
}
public LogicGameFlow LogicFlow { get; protected init; } = null!;
public LogicMinigame LogicMinigame { get; protected init; } = null!;
public LogicRoleSelection LogicRoleSelection { get; protected init; } = null!;
public LogicUsables LogicUsables { get; protected init; } = null!;
public LogicOptions LogicOptions { get; protected init; } = null!;
protected T AddGameLogic<T>(T logic)
where T : GameLogicComponent
{
_logicComponents.Add(logic);
return logic;
}
/// <summary>
/// Finds the tag of the registered <see cref="GameLogicComponent"/>.
/// </summary>
/// <param name="logic">Instance to search for.</param>
/// <typeparam name="T">Intance type to search for.</typeparam>
/// <returns>Tag of the registered <see cref="GameLogicComponent"/>, or -1 if not found.</returns>
internal int GetGameLogicTag<T>(T logic)
where T : GameLogicComponent
{
return _logicComponents.IndexOf(logic);
}
public override ValueTask<bool> HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader)
{
foreach (var logicComponent in _logicComponents)
{
logicComponent.HandleRpc(call, reader);
}
return ValueTask.FromResult(true);
}
public override ValueTask<bool> SerializeAsync(IMessageWriter writer, bool initialState)
{
throw new System.NotImplementedException();
}
public override ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
{
while (reader.Position < reader.Length)
{
var innerReader = reader.ReadMessage();
var tag = (int)innerReader.Tag;
if (tag < 0 || tag > this._logicComponents.Count)
{
_logger.LogError("Out of bounds in DeserializeAsync of InnerGameManager");
continue;
}
var component = this._logicComponents[tag];
component.Deserialize(innerReader, initialState);
if (innerReader.Position < innerReader.Length)
{
_logger.LogWarning(
"Server did not consume all bytes from {0} component {1} ({2} < {3}).",
nameof(InnerGameManager),
component.GetType().FullName,
innerReader.Position,
innerReader.Length);
}
}
return ValueTask.CompletedTask;
}
}
@@ -0,0 +1,9 @@
using Impostor.Api.Net.Inner.Objects.GameManager;
using Impostor.Api.Net.Inner.Objects.GameManager.Logic.HideAndSeek;
namespace Impostor.Server.Net.Inner.Objects.GameManager;
internal partial class InnerHideAndSeekManager
{
ILogicGameFlowHnS IInnerHideAndSeekManager.LogicFlowHnS => LogicFlowHnS;
}
@@ -0,0 +1,37 @@
using Impostor.Api.Net.Custom;
using Impostor.Api.Net.Inner.Objects.GameManager;
using Impostor.Server.Net.Inner.Objects.GameManager.Logic.HideAndSeek;
using Impostor.Server.Net.State;
using Microsoft.Extensions.Logging;
namespace Impostor.Server.Net.Inner.Objects.GameManager;
internal partial class InnerHideAndSeekManager : InnerGameManager, IInnerHideAndSeekManager
{
public InnerHideAndSeekManager(ICustomMessageManager<ICustomRpc> customMessageManager, Game game, ILogger<InnerGameManager> logger) : base(customMessageManager, game, logger)
{
LogicMusic = AddGameLogic(new LogicHnSMusic());
LogicMinigame = AddGameLogic(new LogicMinigameHnS());
LogicFlowHnS = new LogicGameFlowHnS();
LogicFlow = AddGameLogic(LogicFlowHnS);
LogicUsables = AddGameLogic(new LogicUsablesHnS());
LogicRoleSelection = AddGameLogic(new LogicRoleSelectionHnS());
LogicOptionsHnS = new LogicOptionsHnS(game);
LogicOptions = AddGameLogic(this.LogicOptionsHnS);
LogicDangerLevel = AddGameLogic(new LogicHnSDangerLevel());
LogicPing = AddGameLogic(new LogicPingsHnS());
LogicDeathPopup = AddGameLogic(new LogicHnSDeathPopup());
}
public LogicHnSMusic LogicMusic { get; private set; }
public LogicGameFlowHnS LogicFlowHnS { get; private set; }
public LogicOptionsHnS LogicOptionsHnS { get; private set; }
public LogicHnSDangerLevel LogicDangerLevel { get; private set; }
public LogicPingsHnS LogicPing { get; private set; }
public LogicHnSDeathPopup LogicDeathPopup { get; private set; }
}
Loaded 100 of 179 files, more files were not shown because too many files have changed in this diff. Show more