mirror of
https://github.com/Impostor/Impostor.git
synced 2026-10-20 01:46:11 +00:00
Compare commits
26
Commits
pluginmanager
...
v1.5.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66b4d860a9 | ||
|
|
dca26cff59 | ||
|
|
3437c86bff | ||
|
|
66fb8426a6 | ||
|
|
4c839e2dd8 | ||
|
|
c6aa596e3b | ||
|
|
d8843db3eb | ||
|
|
b918f25443 | ||
|
|
824359f93b | ||
|
|
046d09b5fa | ||
|
|
5410c71280 | ||
|
|
241e867343 | ||
|
|
11f2ffd24d | ||
|
|
9df01d2cf7 | ||
|
|
d2720442e9 | ||
|
|
ddedffd121 | ||
|
|
2f04f6ea98 | ||
|
|
5f4c40bf36 | ||
|
|
ef4cc5646b | ||
|
|
d894e9adc3 | ||
|
|
c086cf80b1 | ||
|
|
1118a59167 | ||
|
|
5154dd9aa5 | ||
|
|
a621225fcd | ||
|
|
73a5463848 | ||
|
|
02d25a290f |
No files matched your search
@@ -3,14 +3,11 @@
|
||||
[](https://discord.gg/Mk3w6Tb)
|
||||
[](https://ci.appveyor.com/project/Impostor/Impostor/branch/master)
|
||||
|
||||
Impostor is one of the first **Among Us** private servers, written in C#.
|
||||
Impostor is the first working **Among Us** private server, written in C#.
|
||||
|
||||
| Impostor version | Among Us version | Experimental | Download |
|
||||
|-|-|-|-|
|
||||
| 1.1.0 | 2020.09.07 - 2020.09.22 | No | [](https://github.com/Impostor/Impostor/releases/tag/v1.1.0) |
|
||||
| 1.2.2 | 2020.09.22 - 2020.11.17 | No | [](https://github.com/Impostor/Impostor/releases/tag/v1.2.2) |
|
||||
| 1.3.0 | 2021.3.5 | No | [](https://github.com/Impostor/Impostor/releases/tag/v1.3.0) |
|
||||
| 1.4.0 | 2021.3.31 - 2021.4.2 | Yes | [](https://ci.appveyor.com/project/Impostor/Impostor/branch/master/artifacts) |
|
||||
As Among Us is actively updated, you may want to use the latest build from the master branch if you want to play on the latest version of Among Us that supported by Impostor.
|
||||
|
||||
If you want to play on an older version of Among Us, you can download old releases from [here](https://github.com/Impostor/Impostor/releases/), however these versions are less supported.
|
||||
|
||||
## Features
|
||||
|
||||
@@ -22,34 +19,7 @@ Impostor is one of the first **Among Us** private servers, written in C#.
|
||||
|
||||
### Client
|
||||
|
||||
If you just want to play on a server hosted by someone else, you need to follow these instructions.
|
||||
|
||||
#### Windows
|
||||
|
||||
1. Find the [latest release](https://github.com/AeonLucid/Impostor/releases/latest).
|
||||
2. Download `Impostor-Patcher-win-x64.zip`.
|
||||
3. Extract the zip.
|
||||
4. Run `Impostor.Patcher.exe`.
|
||||
5. Follow the instructions inside the application.
|
||||
|
||||

|
||||
|
||||
If you do not wish to execute any programs. Follow the instructions in [this website](https://impostor.github.io/Impostor)
|
||||
|
||||
#### Android
|
||||
|
||||
##### Android 10 and below.
|
||||
1. Go to [this website](https://impostor.github.io/Impostor) **(ON YOUR MOBILE DEVICE)**
|
||||
2. Follow the instructions listed there.
|
||||
|
||||
##### Android 11.
|
||||
1. Connect your phone to a computer. Go to [this website](https://impostor.github.io/Impostor) on the computer and follow the steps 1 and 2 to generate a `regionInfo.dat` file.
|
||||
2. Instead of following the next steps, open the phone's internal storage on your computer and navigate to `/sdcard/Android/data/com.innersloth.spacemafia/files`.
|
||||
3. Copy the generated `regionInfo.dat` file into the `files` folder you just navigated to.
|
||||
|
||||
#### iOS
|
||||
|
||||
iOS devices need to be jailbroken in order to connect to Impostor servers.
|
||||
If you just want to play on a server hosted by someone else, you need to configure your client to connect to an Impostor server. Please go to [this website](https://impostor.github.io/Impostor) to set up your client by following the instructions for your OS there.
|
||||
|
||||
### Server
|
||||
|
||||
@@ -57,7 +27,7 @@ See the [docs](docs/Running-the-server.md) for instructions on how to set it up.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
See [TROUBLESHOOTING](docs/TROUBLESHOOTING.md) to solve issues the Impostor client or the server.
|
||||
See [TROUBLESHOOTING](docs/TROUBLESHOOTING.md) to solve issues with the Impostor client or the server.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -114,13 +114,6 @@ Task("Build")
|
||||
DotNetCoreBuild("./src/Impostor.Tests/Impostor.Tests.csproj", new DotNetCoreBuildSettings {
|
||||
Configuration = configuration,
|
||||
});
|
||||
|
||||
// Client.
|
||||
ImpostorPublishNF("Impostor-Patcher", "./src/Impostor.Patcher/Impostor.Patcher.WinForms/Impostor.Patcher.WinForms.csproj");
|
||||
|
||||
ImpostorPublish("Impostor-Patcher-Cli", "./src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj", "win-x64");
|
||||
ImpostorPublish("Impostor-Patcher-Cli", "./src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj", "osx-x64");
|
||||
ImpostorPublish("Impostor-Patcher-Cli", "./src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj", "linux-x64");
|
||||
|
||||
// Server.
|
||||
ImpostorPublish("Impostor-Server", "./src/Impostor.Server/Impostor.Server.csproj", "win-x64", true);
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
# Building from source
|
||||
|
||||
The solution contains two main projects, the Impostor server and patcher. The server is built using [.NET 5](https://dotnet.microsoft.com/download/dotnet/5.0) and the winforms patcher is with [.NET Framework 4.7.2](https://dotnet.microsoft.com/download/dotnet-framework/net472).
|
||||
|
||||
## Cloning Impostor
|
||||
|
||||
You need to clone Impostor using git.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/AeonLucid/Impostor.git
|
||||
git clone https://github.com/Impostor/Impostor.git
|
||||
```
|
||||
|
||||
## Building the server
|
||||
@@ -23,14 +21,3 @@ cd src/Impostor.Server/
|
||||
dotnet build
|
||||
```
|
||||
To setup the server, please look at [Running the server](Running-the-server.md).
|
||||
|
||||
## Building the winforms patcher
|
||||
|
||||
### Dependencies
|
||||
* [.NET Framework 4.7.2 Developer Pack](https://dotnet.microsoft.com/download/dotnet-framework/thank-you/net472-developer-pack-offline-installer) or [Mono](https://www.mono-project.com/download/)
|
||||
|
||||
### Build using the CLI
|
||||
```bash
|
||||
cd src/Impostor.Patcher/Impostor.Patcher.WinForms
|
||||
dotnet build
|
||||
```
|
||||
@@ -6,14 +6,14 @@ There are currently two modes to run the Impostor server in. The first way is th
|
||||
|
||||
### Without docker
|
||||
1. Install the **.NET 5.0 runtime**.
|
||||
- [Windows x64](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-5.0.0-windows-x64-installer)
|
||||
- [Windows x64](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-5.0.7-windows-x64-installer)
|
||||
- [Linux x64](https://docs.microsoft.com/en-us/dotnet/core/install/linux)
|
||||
- [macOS x64](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-5.0.0-macos-x64-installer)
|
||||
2. Find the [latest master release](https://ci.appveyor.com/project/Impostor/Impostor/branch/master/artifacts).
|
||||
3. Download either the Windows or the Linux version.
|
||||
- [macOS x64](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-5.0.7-macos-x64-installer)
|
||||
2. Find the [latest release](https://github.com/Impostor/Impostor/releases) or the [latest CI build](https://ci.appveyor.com/project/Impostor/Impostor/branch/master/artifacts).
|
||||
3. Download the version for your OS (linux/win/osx) and your architecture (x64/arm/arm64).
|
||||
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)*
|
||||
6. Run `Impostor.Server.exe` (Windows) / `Impostor.Server` (Linux)
|
||||
6. Run `Impostor.Server` (Linux/macOS) or `Impostor.Server.exe` (Windows)
|
||||
|
||||
### Using docker
|
||||
|
||||
|
||||
@@ -31,12 +31,11 @@ The first step is creating a new C# project, it must be a **Class Library (.NET
|
||||
|
||||
- .NET Standard 2.0
|
||||
- .NET Standard 2.1
|
||||
- .NET Core 3.1
|
||||
- .NET 5
|
||||
|
||||
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** until .NET 5 is released officially. This should give you enough functionality. If not, upgrade to .NET Core 3.1.
|
||||
> 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 5.
|
||||
|
||||
When the project has been created, you should have `Class.cs` and `Project.csproj` files. Your `Project.csproj` should look something like this.
|
||||
|
||||
@@ -62,16 +61,13 @@ Make sure to get a prerelease if you are writing a plugin for a dev release of t
|
||||
1. Right click your project.
|
||||
2. Click `Manage NuGet Packages`.
|
||||
3. Click `Browse`.
|
||||
4. Next to the search bar, enable `Include prerelease`.
|
||||
5. Search for `Impostor.Api`.
|
||||
6. Click the `Impostor.Api` result and press install on the right side.
|
||||
4. Search for `Impostor.Api`.
|
||||
5. Click the `Impostor.Api` result and press install on the right side.
|
||||
|
||||
### Dotnet CLI
|
||||
|
||||
> Make sure to grab the latest (pre-)release version from NuGet [here](https://www.nuget.org/packages/Impostor.Api).
|
||||
|
||||
1. Open your project folder in command prompt / bash.
|
||||
2. Run `dotnet add package Impostor.Api -v "1.2.0-ci.58"`.
|
||||
2. Run `dotnet add package Impostor.Api`.
|
||||
|
||||
## 4. The plugin class
|
||||
|
||||
|
||||
@@ -144,6 +144,12 @@ dotnet_naming_style.end_in_async.word_separator =
|
||||
# error RS2008: Enable analyzer release tracking for the analyzer project containing rule '{0}'
|
||||
dotnet_diagnostic.RS2008.severity = none
|
||||
|
||||
# IDE0005: Remove unnecessary import
|
||||
dotnet_diagnostic.IDE0005.severity = warning
|
||||
|
||||
# IDE0007: Use `var` instead of explicit type
|
||||
dotnet_diagnostic.IDE0007.severity = warning
|
||||
|
||||
# IDE0035: Remove unreachable code
|
||||
dotnet_diagnostic.IDE0035.severity = warning
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>1.4.0</VersionPrefix>
|
||||
<VersionPrefix>1.5.0</VersionPrefix>
|
||||
<VersionSuffix>dev</VersionSuffix>
|
||||
<EnforceCodeStyleInBuild Condition="$(MSBuildProjectName)!='Hazel'">true</EnforceCodeStyleInBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -9,11 +9,6 @@ namespace Impostor.Api.Events.Announcements
|
||||
{
|
||||
public interface IResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets FreeWeekendState, currently unused by the client.
|
||||
/// </summary>
|
||||
public FreeWeekendState FreeWeekendState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether announcement should be loaded from client's cache, can save some bytes.
|
||||
/// </summary>
|
||||
|
||||
@@ -2,10 +2,12 @@ using Impostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Impostor.Api.Events.Player
|
||||
{
|
||||
public enum VoteType : sbyte
|
||||
public enum VoteType : byte
|
||||
{
|
||||
ForceSkip = -2,
|
||||
Skip = -1,
|
||||
HasNotVoted = 255,
|
||||
Missed = 254,
|
||||
Skipped = 253,
|
||||
Dead = 252,
|
||||
Player = 0,
|
||||
}
|
||||
|
||||
|
||||
@@ -14,5 +14,11 @@
|
||||
Brown = 9,
|
||||
Cyan = 10,
|
||||
Lime = 11,
|
||||
Maroon = 12,
|
||||
Rose = 13,
|
||||
Banana = 14,
|
||||
Gray = 15,
|
||||
Tan = 16,
|
||||
Coral = 17,
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Impostor.Api.Innersloth.Customization
|
||||
namespace Impostor.Api.Innersloth.Customization
|
||||
{
|
||||
public enum HatType : uint
|
||||
{
|
||||
@@ -109,13 +109,13 @@
|
||||
ToppatHenry = 104,
|
||||
ToppatEllie = 105,
|
||||
GeoffreyPlumb = 106,
|
||||
AngryEyebrows = 107,
|
||||
ChocolateIce = 108,
|
||||
HeartPin = 109,
|
||||
Ponytail = 110,
|
||||
RubberGlove = 111,
|
||||
UnicornHorn = 112,
|
||||
Zipper = 113,
|
||||
RightHandMan = 114,
|
||||
RightHandMan = 107,
|
||||
AngryEyebrows = 108,
|
||||
ChocolateIce = 109,
|
||||
HeartPin = 110,
|
||||
Ponytail = 111,
|
||||
RubberGlove = 112,
|
||||
UnicornHorn = 113,
|
||||
Zipper = 114,
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Impostor.Api.Innersloth
|
||||
{
|
||||
[Flags]
|
||||
public enum FreeWeekendState : byte
|
||||
{
|
||||
NotFree,
|
||||
FreeMIRA,
|
||||
FreePolus,
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,21 @@ namespace Impostor.Api.Innersloth
|
||||
public enum GameKeywords : uint
|
||||
{
|
||||
All = 0,
|
||||
Other = 1,
|
||||
Spanish = 2,
|
||||
English = 256,
|
||||
SpanishLA = 2,
|
||||
Brazilian = 2048,
|
||||
Portuguese = 16,
|
||||
Korean = 4,
|
||||
Russian = 8,
|
||||
Portuguese = 16,
|
||||
Dutch = 4096,
|
||||
Filipino = 64,
|
||||
French = 8192,
|
||||
German = 16384,
|
||||
Italian = 32768,
|
||||
Japanese = 512,
|
||||
SpanishEU = 1024,
|
||||
Arabic = 32,
|
||||
Filipone = 64,
|
||||
Polish = 128,
|
||||
English = 256,
|
||||
Other = 1,
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,20 @@
|
||||
namespace Impostor.Api.Innersloth
|
||||
{
|
||||
public class GameVersion
|
||||
public static class GameVersion
|
||||
{
|
||||
public static int GetVersion(int year, int month, int day, int rev = 0)
|
||||
public static int GetVersion(int year, int month, int day, int revision = 0)
|
||||
{
|
||||
return (year * 25000) + (month * 1800) + (day * 50) + rev;
|
||||
return (year * 25000) + (month * 1800) + (day * 50) + revision;
|
||||
}
|
||||
|
||||
public static void ParseVersion(int version, out int year, out int month, out int day, out int revision)
|
||||
{
|
||||
year = version / 25000;
|
||||
version %= 25000;
|
||||
month = version / 1800;
|
||||
version %= 1800;
|
||||
day = version / 50;
|
||||
revision = version % 50;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,17 @@ namespace Impostor.Api.Innersloth
|
||||
public enum Language
|
||||
{
|
||||
English,
|
||||
Spanish,
|
||||
SpanishLA,
|
||||
Brazilian,
|
||||
Portuguese,
|
||||
Korean,
|
||||
Russian,
|
||||
Dutch,
|
||||
Filipino,
|
||||
French,
|
||||
German,
|
||||
Italian,
|
||||
Japanese,
|
||||
SpanishEU,
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Impostor.Api.Innersloth
|
||||
{
|
||||
public class RegionInfo
|
||||
{
|
||||
public RegionInfo(string name, string ping, IReadOnlyList<ServerInfo> servers)
|
||||
{
|
||||
Name = name;
|
||||
Ping = ping;
|
||||
Servers = servers;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public string Ping { get; }
|
||||
|
||||
public IReadOnlyList<ServerInfo> Servers { get; }
|
||||
|
||||
public static RegionInfo Deserialize(BinaryReader reader)
|
||||
{
|
||||
var unknown = reader.ReadInt32();
|
||||
var name = reader.ReadString();
|
||||
var ping = reader.ReadString();
|
||||
var servers = new List<ServerInfo>();
|
||||
var serverCount = reader.ReadInt32();
|
||||
|
||||
for (var i = 0; i < serverCount; i++)
|
||||
{
|
||||
servers.Add(ServerInfo.Deserialize(reader));
|
||||
}
|
||||
|
||||
return new RegionInfo(name, ping, servers);
|
||||
}
|
||||
|
||||
public void Serialize(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(0);
|
||||
writer.Write(Name);
|
||||
writer.Write(Ping);
|
||||
writer.Write(Servers.Count);
|
||||
|
||||
foreach (var server in Servers)
|
||||
{
|
||||
server.Serialize(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace Impostor.Api.Innersloth
|
||||
{
|
||||
public class ServerInfo
|
||||
{
|
||||
public ServerInfo(string name, string ip, ushort port)
|
||||
{
|
||||
Name = name;
|
||||
Ip = ip;
|
||||
Port = port;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public string Ip { get; }
|
||||
|
||||
public ushort Port { get; }
|
||||
|
||||
public static ServerInfo Deserialize(BinaryReader reader)
|
||||
{
|
||||
var name = reader.ReadString();
|
||||
var ip = new IPAddress(reader.ReadBytes(4)).ToString();
|
||||
var port = reader.ReadUInt16();
|
||||
var unknown = reader.ReadInt32();
|
||||
|
||||
return new ServerInfo(name, ip, port);
|
||||
}
|
||||
|
||||
public void Serialize(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(Name);
|
||||
writer.Write(IPAddress.Parse(Ip).GetAddressBytes());
|
||||
writer.Write(Port);
|
||||
writer.Write(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,5 +34,6 @@
|
||||
SetTasks = 29,
|
||||
ClimbLadder = 31,
|
||||
UsePlatform = 32,
|
||||
SendQuickChat = 33,
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using Impostor.Api.Innersloth;
|
||||
|
||||
namespace Impostor.Api.Net.Messages.Announcements
|
||||
{
|
||||
public static class Message02SetFreeWeekend
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, FreeWeekendState state)
|
||||
{
|
||||
writer.StartMessage(AnnouncementsMessageFlags.SetFreeWeekend);
|
||||
writer.Write((byte)state);
|
||||
writer.EndMessage();
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out FreeWeekendState state)
|
||||
{
|
||||
state = (FreeWeekendState)reader.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Impostor.Api.Net.Messages.Announcements
|
||||
{
|
||||
public static class Message04AddLanguages
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, Dictionary<string, uint> languages)
|
||||
{
|
||||
writer.StartMessage(AnnouncementsMessageFlags.AddLanguages);
|
||||
|
||||
writer.Write((byte)languages.Count);
|
||||
foreach (var (name, id) in languages)
|
||||
{
|
||||
writer.Write(name);
|
||||
writer.Write(id);
|
||||
}
|
||||
|
||||
writer.EndMessage();
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out Dictionary<string, uint> languages)
|
||||
{
|
||||
var length = reader.ReadByte();
|
||||
languages = new Dictionary<string, uint>(length);
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
languages[reader.ReadString()] = reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,6 @@ namespace Impostor.Api.Net.Messages
|
||||
{
|
||||
public const byte UseCache = 0;
|
||||
public const byte SetUpdate = 1;
|
||||
public const byte SetFreeWeekend = 2;
|
||||
public const byte AddLanguages = 4;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
using System;
|
||||
|
||||
namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc23VotingComplete
|
||||
@@ -11,9 +9,15 @@ namespace Impostor.Api.Net.Messages.Rpcs
|
||||
writer.Write(tie);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out ReadOnlyMemory<byte> states, out byte playerId, out bool tie)
|
||||
public static void Deserialize(IMessageReader reader, out IMessageReader[] states, out byte playerId, out bool tie)
|
||||
{
|
||||
states = reader.ReadBytesAndSize();
|
||||
var length = reader.ReadPackedInt32();
|
||||
states = new IMessageReader[length];
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
states[i] = reader.ReadMessage();
|
||||
}
|
||||
|
||||
playerId = reader.ReadByte();
|
||||
tie = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ namespace Impostor.Api.Net.Messages.Rpcs
|
||||
writer.Write(suspectPlayerId);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out byte playerId, out sbyte suspectPlayerId)
|
||||
public static void Deserialize(IMessageReader reader, out byte playerId, out byte suspectPlayerId)
|
||||
{
|
||||
playerId = reader.ReadByte();
|
||||
suspectPlayerId = reader.ReadSByte();
|
||||
suspectPlayerId = reader.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace Impostor.Benchmarks.Data
|
||||
{
|
||||
public class MessageReader_Bytes_Pooled
|
||||
{
|
||||
private static ConcurrentQueue<MessageReader_Bytes_Pooled> _readers;
|
||||
private static readonly ConcurrentQueue<MessageReader_Bytes_Pooled> _readers;
|
||||
|
||||
static MessageReader_Bytes_Pooled()
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Impostor.Benchmarks.Data
|
||||
{
|
||||
public MessageType SendOption { get; private set; }
|
||||
|
||||
private Stack<int> messageStarts = new Stack<int>();
|
||||
private readonly Stack<int> _messageStarts = new Stack<int>();
|
||||
|
||||
public MessageWriter(byte[] buffer)
|
||||
{
|
||||
@@ -78,7 +78,7 @@ namespace Impostor.Benchmarks.Data
|
||||
///
|
||||
public void StartMessage(byte typeFlag)
|
||||
{
|
||||
messageStarts.Push(this.Position);
|
||||
_messageStarts.Push(this.Position);
|
||||
this.Position += 2; // Skip for size
|
||||
this.Write(typeFlag);
|
||||
}
|
||||
@@ -86,7 +86,7 @@ namespace Impostor.Benchmarks.Data
|
||||
///
|
||||
public void EndMessage()
|
||||
{
|
||||
var lastMessageStart = messageStarts.Pop();
|
||||
var lastMessageStart = _messageStarts.Pop();
|
||||
var length = (ushort)(this.Position - lastMessageStart - 3); // Minus length and type byte
|
||||
this.Buffer[lastMessageStart] = (byte)length;
|
||||
this.Buffer[lastMessageStart + 1] = (byte)(length >> 8);
|
||||
@@ -95,13 +95,13 @@ namespace Impostor.Benchmarks.Data
|
||||
///
|
||||
public void CancelMessage()
|
||||
{
|
||||
this.Position = this.messageStarts.Pop();
|
||||
this.Position = this._messageStarts.Pop();
|
||||
this.Length = this.Position;
|
||||
}
|
||||
|
||||
public void Clear(MessageType sendOption)
|
||||
{
|
||||
this.messageStarts.Clear();
|
||||
this._messageStarts.Clear();
|
||||
this.SendOption = sendOption;
|
||||
this.Buffer[0] = (byte)sendOption;
|
||||
switch (sendOption)
|
||||
@@ -293,7 +293,7 @@ namespace Impostor.Benchmarks.Data
|
||||
this.Write(msg.Buffer, offset, msg.Length - offset);
|
||||
}
|
||||
|
||||
public unsafe static bool IsLittleEndian()
|
||||
public static unsafe bool IsLittleEndian()
|
||||
{
|
||||
byte b;
|
||||
unsafe
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<AssemblyTitle>Impostor</AssemblyTitle>
|
||||
<Product>Impostor</Product>
|
||||
<Copyright>Copyright © AeonLucid 2020</Copyright>
|
||||
<Version>1.0.0</Version>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,19 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>Impostor.Cli</AssemblyName>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;linux-arm;linux-arm64;osx-x64</RuntimeIdentifiers>
|
||||
<OutputType>Exe</OutputType>
|
||||
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Impostor.Patcher.Shared\Impostor.Patcher.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20478.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,88 +0,0 @@
|
||||
using System;
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Patcher.Shared;
|
||||
using Impostor.Patcher.Shared.Events;
|
||||
|
||||
namespace Impostor.Patcher.Cli
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
private static readonly AmongUsModifier Modifier = new AmongUsModifier();
|
||||
|
||||
internal static Task<int> Main(string[] args)
|
||||
{
|
||||
var rootCommand = new RootCommand
|
||||
{
|
||||
new Option<string>(
|
||||
"--address",
|
||||
"IP Address of the server, will prompt if not specified"
|
||||
),
|
||||
new Option<string>(
|
||||
"--name",
|
||||
() => AmongUsModifier.DefaultRegionName,
|
||||
"Name for server region"
|
||||
),
|
||||
};
|
||||
|
||||
rootCommand.Handler = CommandHandler.Create<string, string>((address, name) =>
|
||||
{
|
||||
Modifier.RegionName = name;
|
||||
Modifier.Error += ModifierOnError;
|
||||
Modifier.Saved += ModifierOnSaved;
|
||||
|
||||
Console.WriteLine("Welcome to Impostor");
|
||||
|
||||
if (Modifier.TryLoadRegionInfo(out var regionInfo))
|
||||
{
|
||||
Console.WriteLine($"Currently selected region: {regionInfo.Name} ({regionInfo.Ping}, {regionInfo.Servers.Count} server(s))");
|
||||
}
|
||||
|
||||
if (address != null)
|
||||
{
|
||||
return Modifier.SaveIpAsync(address);
|
||||
}
|
||||
|
||||
return PromptAsync();
|
||||
});
|
||||
|
||||
return rootCommand.InvokeAsync(args);
|
||||
}
|
||||
|
||||
private static void ModifierOnSaved(object sender, SavedEventArgs e)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
Console.WriteLine("The IP Address was saved, please (re)start Among Us.");
|
||||
Console.ResetColor();
|
||||
}
|
||||
|
||||
private static void WriteError(string message)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine(message);
|
||||
Console.ResetColor();
|
||||
}
|
||||
|
||||
private static void ModifierOnError(object sender, ErrorEventArgs e)
|
||||
{
|
||||
WriteError(e.Message);
|
||||
}
|
||||
|
||||
private static async Task PromptAsync()
|
||||
{
|
||||
Console.WriteLine("Please enter in the IP Address of the server you would like to use for Among Us");
|
||||
Console.WriteLine("If you want to stop playing on the server, simply select another region");
|
||||
|
||||
while (true)
|
||||
{
|
||||
Console.Write("> ");
|
||||
|
||||
if (await Modifier.SaveIpAsync(Console.ReadLine()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Gameloop.Vdf;
|
||||
using Gameloop.Vdf.Linq;
|
||||
using Impostor.Patcher.Shared.Events;
|
||||
using Impostor.Patcher.Shared.Innersloth;
|
||||
using ErrorEventArgs = Impostor.Patcher.Shared.Events.ErrorEventArgs;
|
||||
|
||||
namespace Impostor.Patcher.Shared
|
||||
{
|
||||
public class AmongUsModifier
|
||||
{
|
||||
private const uint AppId = 945360;
|
||||
public const string DefaultRegionName = "Impostor";
|
||||
public const ushort DefaultPort = 22023;
|
||||
|
||||
private readonly string _amongUsDir;
|
||||
private readonly string _regionFile;
|
||||
|
||||
public string RegionName { get; set; } = DefaultRegionName;
|
||||
|
||||
public AmongUsModifier()
|
||||
{
|
||||
var appData = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "..", "LocalLow");
|
||||
|
||||
if (!Directory.Exists(appData))
|
||||
{
|
||||
appData = FindProtonAppData();
|
||||
}
|
||||
|
||||
if (appData == null)
|
||||
return;
|
||||
|
||||
_amongUsDir = Path.Combine(appData, "Innersloth", "Among Us");
|
||||
_regionFile = Path.Combine(_amongUsDir, "regionInfo.dat");
|
||||
}
|
||||
|
||||
private string FindProtonAppData()
|
||||
{
|
||||
string steamApps;
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
steamApps = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".steam", "steam", "steamapps");
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
steamApps = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "Steam", "steamapps");
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(steamApps))
|
||||
return null;
|
||||
|
||||
var libraries = new List<string>
|
||||
{
|
||||
steamApps,
|
||||
};
|
||||
|
||||
var vdf = Path.Combine(steamApps, "libraryfolders.vdf");
|
||||
if (File.Exists(vdf))
|
||||
{
|
||||
var libraryFolders = VdfConvert.Deserialize(File.ReadAllText(vdf));
|
||||
|
||||
foreach (var libraryFolder in libraryFolders.Value.Children<VProperty>())
|
||||
{
|
||||
if (!int.TryParse(libraryFolder.Key, out _))
|
||||
continue;
|
||||
|
||||
libraries.Add(Path.Combine(libraryFolder.Value.Value<string>(), "steamapps"));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var library in libraries)
|
||||
{
|
||||
var path = Path.Combine(library, "compatdata", AppId.ToString(), "pfx", "drive_c", "users", "steamuser", "AppData", "LocalLow");
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<bool> SaveIpAsync(string input)
|
||||
{
|
||||
// Filter out whitespace.
|
||||
input = input.Trim();
|
||||
|
||||
// Split port from ip.
|
||||
// Only IPv4 is supported so just do it simple.
|
||||
var ip = string.Empty;
|
||||
var port = DefaultPort;
|
||||
|
||||
var parts = input.Split(':');
|
||||
if (parts.Length >= 1)
|
||||
{
|
||||
ip = parts[0];
|
||||
}
|
||||
|
||||
if (parts.Length >= 2)
|
||||
{
|
||||
ushort.TryParse(parts[1], out port);
|
||||
}
|
||||
|
||||
// Check if a valid IP address was entered.
|
||||
if (!IPAddress.TryParse(ip, out var ipAddress))
|
||||
{
|
||||
// Attempt to resolve DNS.
|
||||
try
|
||||
{
|
||||
var hostAddresses = await Dns.GetHostAddressesAsync(ip);
|
||||
if (hostAddresses.Length == 0)
|
||||
{
|
||||
OnError("Invalid IP Address entered");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use first IPv4 result.
|
||||
ipAddress = hostAddresses.First(x => x.AddressFamily == AddressFamily.InterNetwork);
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
OnError("Failed to resolve hostname.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Only IPv4.
|
||||
if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
{
|
||||
OnError("Invalid IP Address entered, only IPv4 is allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var result = WriteIp(ipAddress, port);
|
||||
OnSaved(ip, port);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an IP Address to the Among Us region file.
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">The IPv4 address to write.</param>
|
||||
/// <param name="port"></param>
|
||||
private bool WriteIp(IPAddress ipAddress, ushort port)
|
||||
{
|
||||
if (ipAddress == null ||
|
||||
ipAddress.AddressFamily != AddressFamily.InterNetwork)
|
||||
{
|
||||
throw new ArgumentException(nameof(ipAddress));
|
||||
}
|
||||
|
||||
if (!Directory.Exists(_amongUsDir))
|
||||
{
|
||||
OnError("Among Us directory was not found, is it installed? Try running it once.");
|
||||
return false;
|
||||
}
|
||||
|
||||
using (var file = File.Open(_regionFile, FileMode.Create, FileAccess.Write))
|
||||
using (var writer = new BinaryWriter(file))
|
||||
{
|
||||
var ip = ipAddress.ToString();
|
||||
var region = new RegionInfo(RegionName, ip, new[]
|
||||
{
|
||||
new ServerInfo($"{RegionName}-Master-1", ip, port),
|
||||
});
|
||||
|
||||
region.Serialize(writer);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the existing region info from the Among Us.
|
||||
/// </summary>
|
||||
public bool TryLoadRegionInfo(out RegionInfo regionInfo)
|
||||
{
|
||||
regionInfo = null;
|
||||
|
||||
if (!File.Exists(_regionFile))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using (var file = File.Open(_regionFile, FileMode.Open, FileAccess.Read))
|
||||
using (var reader = new BinaryReader(file))
|
||||
{
|
||||
try
|
||||
{
|
||||
regionInfo = RegionInfo.Deserialize(reader);
|
||||
return true;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
OnError("Couldn't parse region info\n" + exception);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the existing IP Address from the Among Us region file
|
||||
/// if it was set by Impostor before.
|
||||
/// </summary>
|
||||
public bool TryLoadIp(out string ipAddress)
|
||||
{
|
||||
ipAddress = null;
|
||||
|
||||
if (!TryLoadRegionInfo(out var regionInfo))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((regionInfo.Name == RegionName || regionInfo.Name == DefaultRegionName) && regionInfo.Servers.Count >= 1)
|
||||
{
|
||||
ipAddress = regionInfo.Servers.ElementAt(0).Ip;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnError(string message)
|
||||
{
|
||||
Error?.Invoke(this, new ErrorEventArgs(message));
|
||||
}
|
||||
|
||||
private void OnSaved(string ipAddress, ushort port)
|
||||
{
|
||||
Saved?.Invoke(this, new SavedEventArgs(ipAddress, port));
|
||||
}
|
||||
|
||||
public event EventHandler<ErrorEventArgs> Error;
|
||||
public event EventHandler<SavedEventArgs> Saved;
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Impostor.Patcher.Shared
|
||||
{
|
||||
public class Configuration
|
||||
{
|
||||
private const string FileRecentIps = @"recent_ips.txt";
|
||||
private const int MaxRecentIps = 5;
|
||||
|
||||
private readonly string _baseDir;
|
||||
private readonly string _recentIpsPath;
|
||||
private readonly List<string> _recentIps;
|
||||
|
||||
public Configuration()
|
||||
{
|
||||
var appData = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData));
|
||||
|
||||
_baseDir = Path.Combine(appData, "Impostor");
|
||||
_recentIpsPath = Path.Combine(_baseDir, FileRecentIps);
|
||||
_recentIps = new List<string>();
|
||||
}
|
||||
|
||||
public IReadOnlyList<string> RecentIps => _recentIps;
|
||||
|
||||
public void Load()
|
||||
{
|
||||
if (File.Exists(_recentIpsPath))
|
||||
{
|
||||
_recentIps.AddRange(File.ReadAllLines(_recentIpsPath));
|
||||
}
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
Directory.CreateDirectory(_baseDir);
|
||||
|
||||
if (!Directory.Exists(_baseDir))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_recentIps.Count > 0)
|
||||
{
|
||||
File.WriteAllLines(_recentIpsPath, _recentIps);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddIp(string ip)
|
||||
{
|
||||
if (_recentIps.Contains(ip))
|
||||
{
|
||||
_recentIps.Remove(ip);
|
||||
}
|
||||
|
||||
_recentIps.Insert(0, ip);
|
||||
|
||||
if (_recentIps.Count > MaxRecentIps)
|
||||
{
|
||||
_recentIps.RemoveAt(MaxRecentIps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Impostor.Patcher.Shared.Events
|
||||
{
|
||||
public class ErrorEventArgs : EventArgs
|
||||
{
|
||||
public ErrorEventArgs(string message)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
|
||||
public string Message { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Impostor.Patcher.Shared.Events
|
||||
{
|
||||
public class SavedEventArgs : EventArgs
|
||||
{
|
||||
public SavedEventArgs(string ipAddress, ushort port)
|
||||
{
|
||||
IpAddress = ipAddress;
|
||||
Port = port;
|
||||
}
|
||||
|
||||
public string IpAddress { get; }
|
||||
public ushort Port { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Gameloop.Vdf" Version="0.6.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,48 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Impostor.Patcher.Shared.Innersloth
|
||||
{
|
||||
public class RegionInfo
|
||||
{
|
||||
public RegionInfo(string name, string ping, IReadOnlyList<ServerInfo> servers)
|
||||
{
|
||||
Name = name;
|
||||
Ping = ping;
|
||||
Servers = servers;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string Ping { get; }
|
||||
public IReadOnlyList<ServerInfo> Servers { get; }
|
||||
|
||||
public void Serialize(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(0);
|
||||
writer.Write(Name);
|
||||
writer.Write(Ping);
|
||||
writer.Write(Servers.Count);
|
||||
|
||||
foreach (var server in Servers)
|
||||
{
|
||||
server.Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public static RegionInfo Deserialize(BinaryReader reader)
|
||||
{
|
||||
var unknown = reader.ReadInt32();
|
||||
var name = reader.ReadString();
|
||||
var ping = reader.ReadString();
|
||||
var servers = new List<ServerInfo>();
|
||||
var serverCount = reader.ReadInt32();
|
||||
|
||||
for (var i = 0; i < serverCount; i++)
|
||||
{
|
||||
servers.Add(ServerInfo.Deserialize(reader));
|
||||
}
|
||||
|
||||
return new RegionInfo(name, ping, servers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace Impostor.Patcher.Shared.Innersloth
|
||||
{
|
||||
public class ServerInfo
|
||||
{
|
||||
public string Name { get; }
|
||||
public string Ip { get; }
|
||||
public ushort Port { get; }
|
||||
|
||||
public ServerInfo(string name, string ip, ushort port)
|
||||
{
|
||||
Name = name;
|
||||
Ip = ip;
|
||||
Port = port;
|
||||
}
|
||||
|
||||
public void Serialize(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(Name);
|
||||
writer.Write(IPAddress.Parse(Ip).GetAddressBytes());
|
||||
writer.Write(Port);
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public static ServerInfo Deserialize(BinaryReader reader)
|
||||
{
|
||||
var name = reader.ReadString();
|
||||
var ip = new IPAddress(reader.ReadBytes(4)).ToString();
|
||||
var port = reader.ReadUInt16();
|
||||
var unknown = reader.ReadInt32();
|
||||
|
||||
return new ServerInfo(name, ip, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
</startup>
|
||||
</configuration>
|
||||
@@ -1,141 +0,0 @@
|
||||
namespace Impostor.Patcher.WinForms.Forms
|
||||
{
|
||||
partial class FrmMain
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmMain));
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.buttonLaunch = new System.Windows.Forms.Button();
|
||||
this.lblUrl = new System.Windows.Forms.Label();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.comboIp = new System.Windows.Forms.ComboBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.label1.Location = new System.Drawing.Point(28, 139);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(60, 13);
|
||||
this.label1.TabIndex = 1;
|
||||
this.label1.Text = "IP Address";
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.label2.Location = new System.Drawing.Point(28, 23);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(225, 91);
|
||||
this.label2.TabIndex = 0;
|
||||
this.label2.Text = "Welcome to Impostor\r\n\r\nPlease enter in the IP Address of the \r\nserver you would l" +
|
||||
"ike to use for Among Us\r\n\r\nIf you want to stop playing on the server, \r\nsimply s" +
|
||||
"elect another region";
|
||||
//
|
||||
// buttonLaunch
|
||||
//
|
||||
this.buttonLaunch.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.buttonLaunch.Location = new System.Drawing.Point(179, 155);
|
||||
this.buttonLaunch.Name = "buttonLaunch";
|
||||
this.buttonLaunch.Size = new System.Drawing.Size(74, 22);
|
||||
this.buttonLaunch.TabIndex = 3;
|
||||
this.buttonLaunch.Text = "Save";
|
||||
this.buttonLaunch.UseVisualStyleBackColor = true;
|
||||
this.buttonLaunch.Click += new System.EventHandler(this.buttonLaunch_Click);
|
||||
//
|
||||
// lblUrl
|
||||
//
|
||||
this.lblUrl.AutoSize = true;
|
||||
this.lblUrl.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.lblUrl.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Underline, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lblUrl.ForeColor = System.Drawing.SystemColors.Highlight;
|
||||
this.lblUrl.Location = new System.Drawing.Point(39, 232);
|
||||
this.lblUrl.Name = "lblUrl";
|
||||
this.lblUrl.Size = new System.Drawing.Size(212, 13);
|
||||
this.lblUrl.TabIndex = 5;
|
||||
this.lblUrl.Text = "https://github.com/Impostor/Impostor";
|
||||
this.lblUrl.Click += new System.EventHandler(this.lblUrl_Click);
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.label3.Location = new System.Drawing.Point(54, 216);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(182, 13);
|
||||
this.label3.TabIndex = 6;
|
||||
this.label3.Text = "Source code and latest versions at\r\n";
|
||||
//
|
||||
// comboIp
|
||||
//
|
||||
this.comboIp.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.comboIp.FormattingEnabled = true;
|
||||
this.comboIp.Location = new System.Drawing.Point(31, 155);
|
||||
this.comboIp.Name = "comboIp";
|
||||
this.comboIp.Size = new System.Drawing.Size(141, 21);
|
||||
this.comboIp.TabIndex = 2;
|
||||
this.comboIp.KeyDown += new System.Windows.Forms.KeyEventHandler(this.textIp_KeyDown);
|
||||
//
|
||||
// FrmMain
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(283, 262);
|
||||
this.Controls.Add(this.comboIp);
|
||||
this.Controls.Add(this.label3);
|
||||
this.Controls.Add(this.lblUrl);
|
||||
this.Controls.Add(this.buttonLaunch);
|
||||
this.Controls.Add(this.label2);
|
||||
this.Controls.Add(this.label1);
|
||||
this.ForeColor = System.Drawing.SystemColors.ControlText;
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "FrmMain";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Impostor";
|
||||
this.Load += new System.EventHandler(this.FrmMain_Load);
|
||||
this.Shown += new System.EventHandler(this.FrmMain_Shown);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Button buttonLaunch;
|
||||
private System.Windows.Forms.Label lblUrl;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.ComboBox comboIp;
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
using Impostor.Patcher.Shared;
|
||||
using Impostor.Patcher.Shared.Events;
|
||||
|
||||
namespace Impostor.Patcher.WinForms.Forms
|
||||
{
|
||||
public partial class FrmMain : Form
|
||||
{
|
||||
private readonly Configuration _config;
|
||||
private readonly AmongUsModifier _modifier;
|
||||
|
||||
public FrmMain()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
AcceptButton = buttonLaunch;
|
||||
|
||||
_config = new Configuration();
|
||||
_modifier = new AmongUsModifier();
|
||||
_modifier.Error += ModifierOnError;
|
||||
_modifier.Saved += ModifierOnSaved;
|
||||
}
|
||||
|
||||
private void ModifierOnError(object sender, ErrorEventArgs e)
|
||||
{
|
||||
MessageBox.Show(e.Message, "Error",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Error);
|
||||
|
||||
comboIp.Text = string.Empty;
|
||||
comboIp.Focus();
|
||||
|
||||
comboIp.Enabled = true;
|
||||
buttonLaunch.Enabled = true;
|
||||
}
|
||||
|
||||
private void ModifierOnSaved(object sender, SavedEventArgs e)
|
||||
{
|
||||
MessageBox.Show("The IP Address was saved, please (re)start Among Us.", "Success",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Information);
|
||||
|
||||
var ipText = e.Port == AmongUsModifier.DefaultPort
|
||||
? e.IpAddress
|
||||
: $"{e.IpAddress}:{e.Port}";
|
||||
|
||||
comboIp.Text = ipText;
|
||||
comboIp.Enabled = true;
|
||||
buttonLaunch.Enabled = true;
|
||||
|
||||
_config.AddIp(ipText);
|
||||
_config.Save();
|
||||
|
||||
RefreshComboIps();
|
||||
}
|
||||
|
||||
private void FrmMain_Load(object sender, EventArgs e)
|
||||
{
|
||||
_config.Load();
|
||||
|
||||
RefreshComboIps();
|
||||
|
||||
if (_modifier.TryLoadIp(out var ipAddress))
|
||||
{
|
||||
comboIp.Text = ipAddress;
|
||||
}
|
||||
}
|
||||
|
||||
private void FrmMain_Shown(object sender, EventArgs e)
|
||||
{
|
||||
comboIp.Focus();
|
||||
}
|
||||
|
||||
private void textIp_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode != Keys.Enter)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
|
||||
buttonLaunch_Click(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private async void buttonLaunch_Click(object sender, EventArgs e)
|
||||
{
|
||||
comboIp.Enabled = false;
|
||||
buttonLaunch.Enabled = false;
|
||||
|
||||
await _modifier.SaveIpAsync(comboIp.Text);
|
||||
}
|
||||
|
||||
private void lblUrl_Click(object sender, EventArgs e)
|
||||
{
|
||||
Process.Start("https://github.com/Impostor/Impostor");
|
||||
}
|
||||
|
||||
private void RefreshComboIps()
|
||||
{
|
||||
comboIp.Items.Clear();
|
||||
|
||||
if (_config.RecentIps.Count > 0)
|
||||
{
|
||||
foreach (var ip in _config.RecentIps)
|
||||
{
|
||||
comboIp.Items.Add(ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,22 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>Impostor</AssemblyName>
|
||||
<ProjectGuid>{804CF172-0C87-4423-9688-BD97D549891E}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<Copyright>Copyright © AeonLucid 2020</Copyright>
|
||||
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<GenerateResourceUsePreserializedResources>true</GenerateResourceUsePreserializedResources>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Impostor.Patcher.Shared\Impostor.Patcher.Shared.csproj" />
|
||||
<PackageReference Include="System.Resources.Extensions" Version="5.0.0" />
|
||||
<Reference Include="System.Runtime.InteropServices.RuntimeInformation" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,17 +0,0 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using Impostor.Patcher.WinForms.Forms;
|
||||
|
||||
namespace Impostor.Patcher.WinForms
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
[STAThread]
|
||||
private static void Main()
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(new FrmMain());
|
||||
}
|
||||
}
|
||||
}
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Impostor.Patcher.WinForms.Properties
|
||||
{
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder",
|
||||
"4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources
|
||||
{
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance",
|
||||
"CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState
|
||||
.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((resourceMan == null))
|
||||
{
|
||||
global::System.Resources.ResourceManager temp =
|
||||
new global::System.Resources.ResourceManager("Impostor.Client.WinForms.Properties.Resources",
|
||||
typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState
|
||||
.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture
|
||||
{
|
||||
get { return resourceCulture; }
|
||||
set { resourceCulture = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Impostor.Patcher.Properties
|
||||
{
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(
|
||||
"Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||
{
|
||||
private static Settings defaultInstance =
|
||||
((Settings) (global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default
|
||||
{
|
||||
get { return defaultInstance; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 130 KiB |
@@ -4,7 +4,7 @@
|
||||
{
|
||||
public const string Error = "There was an internal server error. " +
|
||||
"Check the server console for more information. " +
|
||||
"Please report the issue on the AmongUsServer GitHub if it keeps happening.";
|
||||
"Please report the issue on the Impostor GitHub if it keeps happening.";
|
||||
|
||||
public const string Destroyed = "The game you tried to join is being destroyed. " +
|
||||
"Please create a new game.";
|
||||
@@ -15,5 +15,11 @@
|
||||
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.";
|
||||
|
||||
public const string VersionClientTooOld = "Please update your game to play on this server.";
|
||||
|
||||
public const string VersionServerTooOld = "Your client is too new, please update your Impostor server to play.";
|
||||
|
||||
public const string VersionUnsupported = "Your client version is unsupported, please update your Game and/or Impostor server.";
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,6 @@ namespace Impostor.Server.Events.Announcements
|
||||
|
||||
public class AnnouncementResponse : IAnnouncementRequestEvent.IResponse
|
||||
{
|
||||
public FreeWeekendState FreeWeekendState { get; set; } = FreeWeekendState.NotFree;
|
||||
|
||||
public bool UseCached { get; set; } = false;
|
||||
|
||||
public Announcement? Announcement { get; set; } = null;
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api.Events.Managers;
|
||||
using Impostor.Api.Innersloth;
|
||||
using Impostor.Api.Net.Messages;
|
||||
using Impostor.Api.Net.Messages.Announcements;
|
||||
using Impostor.Hazel;
|
||||
@@ -101,15 +100,6 @@ namespace Impostor.Server.Net
|
||||
_logger.LogDebug("Sent ({Id}) {Message}", announcement.Id, announcement.Message);
|
||||
}
|
||||
|
||||
if (response.FreeWeekendState != FreeWeekendState.NotFree)
|
||||
{
|
||||
using var writer = MessageWriter.Get(MessageType.Reliable);
|
||||
Message02SetFreeWeekend.Serialize(writer, response.FreeWeekendState);
|
||||
await e.Connection.SendAsync(writer);
|
||||
|
||||
_logger.LogDebug("Sent {FreeWeekendState} weekend state", response.FreeWeekendState);
|
||||
}
|
||||
|
||||
await e.Connection.Disconnect(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Impostor.Server.Net.Inner.Objects.Components
|
||||
private readonly ObjectPool<PlayerMovementEvent> _pool;
|
||||
|
||||
private ushort _lastSequenceId;
|
||||
private bool _spawnSnapAllowed;
|
||||
private AirshipSpawnState _spawnState;
|
||||
|
||||
public InnerCustomNetworkTransform(ICustomMessageManager<ICustomRpc> customMessageManager, Game game, ILogger<InnerCustomNetworkTransform> logger, InnerPlayerControl playerControl, IEventManager eventManager, ObjectPool<PlayerMovementEvent> pool) : base(customMessageManager, game)
|
||||
{
|
||||
@@ -36,6 +36,13 @@ namespace Impostor.Server.Net.Inner.Objects.Components
|
||||
_pool = pool;
|
||||
}
|
||||
|
||||
private enum AirshipSpawnState : byte
|
||||
{
|
||||
PreSpawn,
|
||||
SelectingSpawn,
|
||||
Spawned,
|
||||
}
|
||||
|
||||
public Vector2 Position { get; private set; }
|
||||
|
||||
public Vector2 Velocity { get; private set; }
|
||||
@@ -98,15 +105,17 @@ namespace Impostor.Server.Net.Inner.Objects.Components
|
||||
|
||||
if (Game.GameNet.ShipStatus is InnerAirshipStatus airshipStatus)
|
||||
{
|
||||
// As part of airship spawning, clients are sending snap to -25 40 for no reason(?), cancelling it works just fine
|
||||
if (Approximately(position, airshipStatus.PreSpawnLocation))
|
||||
// As part of airship spawning, clients are sending snap to -25 40 to move themself out of view
|
||||
if (_spawnState == AirshipSpawnState.PreSpawn && Approximately(position, airshipStatus.PreSpawnLocation))
|
||||
{
|
||||
return false;
|
||||
_spawnState = AirshipSpawnState.SelectingSpawn;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_spawnSnapAllowed && airshipStatus.SpawnLocations.Any(location => Approximately(position, location)))
|
||||
// Once the spawn has been selected, the client sends a second snap to the select spawn location
|
||||
if (_spawnState == AirshipSpawnState.SelectingSpawn && airshipStatus.SpawnLocations.Any(location => Approximately(position, location)))
|
||||
{
|
||||
_spawnSnapAllowed = false;
|
||||
_spawnState = AirshipSpawnState.Spawned;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -152,7 +161,7 @@ namespace Impostor.Server.Net.Inner.Objects.Components
|
||||
|
||||
internal void OnPlayerSpawn()
|
||||
{
|
||||
_spawnSnapAllowed = true;
|
||||
_spawnState = AirshipSpawnState.PreSpawn;
|
||||
}
|
||||
|
||||
private static bool SidGreaterThan(ushort newSid, ushort prevSid)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api.Events.Managers;
|
||||
using Impostor.Api.Innersloth;
|
||||
using Impostor.Api.Net;
|
||||
using Impostor.Api.Net.Custom;
|
||||
using Impostor.Api.Net.Inner;
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api;
|
||||
using Impostor.Api.Events.Managers;
|
||||
using Impostor.Api.Innersloth.Maps;
|
||||
using Impostor.Api.Net;
|
||||
using Impostor.Api.Net.Custom;
|
||||
using Impostor.Api.Net.Inner;
|
||||
|
||||
@@ -9,32 +9,27 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
public class PlayerVoteArea : IInnerMeetingHud.IPlayerVoteArea
|
||||
{
|
||||
private const byte VoteMask = 15;
|
||||
private const byte ReportedBit = 32;
|
||||
private const byte VotedBit = 64;
|
||||
private const byte DeadBit = 128;
|
||||
|
||||
private sbyte _votedForId;
|
||||
private byte _votedForId;
|
||||
|
||||
public PlayerVoteArea(InnerMeetingHud parent, InnerPlayerInfo targetPlayer, bool isDead)
|
||||
{
|
||||
Parent = parent;
|
||||
TargetPlayer = targetPlayer;
|
||||
|
||||
IsDead = isDead;
|
||||
VotedForId = (byte)(isDead ? TVoteType.Dead : TVoteType.HasNotVoted);
|
||||
}
|
||||
|
||||
public InnerMeetingHud Parent { get; }
|
||||
|
||||
public InnerPlayerInfo TargetPlayer { get; }
|
||||
|
||||
public bool IsDead { get; private set; }
|
||||
public bool IsDead => VoteType == TVoteType.Dead;
|
||||
|
||||
public bool DidVote { get; private set; }
|
||||
public bool DidVote => VoteType != TVoteType.HasNotVoted;
|
||||
|
||||
public bool DidReport { get; private set; }
|
||||
|
||||
public sbyte VotedForId
|
||||
public byte VotedForId
|
||||
{
|
||||
get => _votedForId;
|
||||
|
||||
@@ -42,25 +37,22 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
_votedForId = value;
|
||||
|
||||
if (DidVote)
|
||||
switch ((VoteType)value)
|
||||
{
|
||||
switch ((VoteType)value)
|
||||
{
|
||||
case TVoteType.ForceSkip:
|
||||
case TVoteType.Skip:
|
||||
VoteType = (VoteType)value;
|
||||
break;
|
||||
case TVoteType.Dead:
|
||||
VoteType = TVoteType.Dead;
|
||||
break;
|
||||
|
||||
default:
|
||||
VoteType = TVoteType.Player;
|
||||
VotedFor = Parent.Game.GameNet.GameData!.GetPlayerById((byte)value)?.Controller;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VoteType = null;
|
||||
VotedFor = null;
|
||||
case TVoteType.HasNotVoted:
|
||||
case TVoteType.Missed:
|
||||
case TVoteType.Skipped:
|
||||
VoteType = (VoteType)value;
|
||||
break;
|
||||
|
||||
default:
|
||||
VoteType = TVoteType.Player;
|
||||
VotedFor = Parent.Game.GameNet.GameData!.GetPlayerById(value)?.Controller;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,39 +65,20 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
internal void Deserialize(IMessageReader reader, bool updateVote)
|
||||
{
|
||||
var state = reader.ReadByte();
|
||||
DeserializeState(state, out var votedForId, out var isDead, out var didVote, out var didReport);
|
||||
|
||||
IsDead = isDead;
|
||||
DidReport = didReport;
|
||||
var votedForId = reader.ReadByte();
|
||||
|
||||
if (updateVote)
|
||||
{
|
||||
DidVote = didVote;
|
||||
VotedForId = votedForId;
|
||||
}
|
||||
|
||||
DidReport = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
internal void SetVotedFor(sbyte votedFor)
|
||||
internal void SetVotedFor(byte votedFor)
|
||||
{
|
||||
DidVote = true;
|
||||
VotedForId = votedFor;
|
||||
}
|
||||
|
||||
private static void DeserializeState(byte state, out sbyte votedForId, out bool isDead, out bool didVote, out bool didReport)
|
||||
{
|
||||
votedForId = (sbyte)((state & VoteMask) - 1);
|
||||
|
||||
// Among Us's meeting system is really scuffed, we need this to ensure that ForceSkip state is correct (this will break any 14+ players game)
|
||||
if (votedForId == ((sbyte)TVoteType.ForceSkip + 1 & 14))
|
||||
{
|
||||
votedForId = (sbyte)TVoteType.ForceSkip;
|
||||
}
|
||||
|
||||
isDead = (state & DeadBit) > 0;
|
||||
didVote = (state & VotedBit) > 0;
|
||||
didReport = (state & ReportedBit) > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using Impostor.Api.Net.Messages;
|
||||
|
||||
namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
internal partial class InnerMeetingHud
|
||||
{
|
||||
public class VoterState
|
||||
{
|
||||
public VoterState(byte voterId, byte votedForId)
|
||||
{
|
||||
VoterId = voterId;
|
||||
VotedForId = votedForId;
|
||||
}
|
||||
|
||||
public byte VoterId { get; }
|
||||
|
||||
public byte VotedForId { get; }
|
||||
|
||||
public static VoterState Deserialize(IMessageReader reader)
|
||||
{
|
||||
return new VoterState(reader.Tag, reader.ReadByte());
|
||||
}
|
||||
|
||||
public void Serialize(IMessageWriter writer)
|
||||
{
|
||||
writer.StartMessage(this.VoterId);
|
||||
writer.Write(this.VotedForId);
|
||||
writer.EndMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
@@ -42,7 +43,8 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(Game.Options.DiscussionTime + Game.Options.VotingTime), _timerToken.Token);
|
||||
const float AnimationTime = 0.25f + 0.5f + 0.4f + 3f + 0.75f + 5f;
|
||||
await Task.Delay(TimeSpan.FromSeconds(AnimationTime + Game.Options.DiscussionTime + Game.Options.VotingTime), _timerToken.Token);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
@@ -70,37 +72,31 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
if (initialState)
|
||||
{
|
||||
PopulateButtons();
|
||||
|
||||
foreach (var playerState in _playerStates)
|
||||
{
|
||||
playerState.Deserialize(reader, false);
|
||||
|
||||
if (playerState.DidReport)
|
||||
{
|
||||
Reporter = playerState.TargetPlayer;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
var length = reader.ReadPackedUInt32();
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
var num = reader.ReadPackedUInt32();
|
||||
var inner = reader.ReadMessage();
|
||||
var playerVoteArea = _playerStates.SingleOrDefault(x => x.TargetPlayer.PlayerId == inner.Tag);
|
||||
|
||||
for (var i = 0; i < _playerStates.Length; i++)
|
||||
if (playerVoteArea != null)
|
||||
{
|
||||
if ((num & 1 << i) != 0)
|
||||
var clientPlayer = Game.Players.SingleOrDefault(x => x.Character?.PlayerId == playerVoteArea.TargetPlayer.PlayerId);
|
||||
var updateVote = !playerVoteArea.DidVote && (clientPlayer?.IsHost ?? false) && playerVoteArea.VoteType != VoteType.Missed;
|
||||
|
||||
playerVoteArea.Deserialize(inner, updateVote);
|
||||
|
||||
if (updateVote)
|
||||
{
|
||||
var playerVoteArea = _playerStates[i];
|
||||
await HandleVoteAsync(playerVoteArea);
|
||||
await CheckForEndVotingAsync();
|
||||
}
|
||||
|
||||
var clientPlayer = Game.Players.SingleOrDefault(x => x.Character?.PlayerId == playerVoteArea.TargetPlayer.PlayerId);
|
||||
var isHost = (clientPlayer?.IsHost ?? false) && playerVoteArea.VoteType != VoteType.ForceSkip;
|
||||
|
||||
playerVoteArea.Deserialize(reader, isHost);
|
||||
|
||||
if (isHost)
|
||||
{
|
||||
await HandleVoteAsync(playerVoteArea);
|
||||
await CheckForEndVotingAsync();
|
||||
}
|
||||
if (initialState && playerVoteArea.DidReport)
|
||||
{
|
||||
Reporter = playerVoteArea.TargetPlayer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -177,7 +173,7 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleCastVoteAsync(ClientPlayer sender, ClientPlayer? target, byte playerId, sbyte suspectPlayerId)
|
||||
private async ValueTask<bool> HandleCastVoteAsync(ClientPlayer sender, ClientPlayer? target, byte playerId, byte suspectPlayerId)
|
||||
{
|
||||
if (sender.IsHost)
|
||||
{
|
||||
@@ -221,48 +217,47 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] CalculateVotes()
|
||||
private KeyValuePair<byte, int> MaxPair(Dictionary<byte, int> self, out bool tie)
|
||||
{
|
||||
byte[] array = new byte[_playerStates.Max(x => x.TargetPlayer.PlayerId) + 2];
|
||||
foreach (var playerVoteArea in _playerStates)
|
||||
tie = true;
|
||||
var result = new KeyValuePair<byte, int>(byte.MaxValue, int.MinValue);
|
||||
foreach (var keyValuePair in self)
|
||||
{
|
||||
if (playerVoteArea.DidVote)
|
||||
if (keyValuePair.Value > result.Value)
|
||||
{
|
||||
var index = playerVoteArea.VotedForId + 1;
|
||||
if (index >= 0 && index < array.Length)
|
||||
{
|
||||
array[index] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
private int IndexOfMax<T>(T[] self, Func<T, int> comparer, out bool tie)
|
||||
{
|
||||
tie = false;
|
||||
var num = int.MinValue;
|
||||
var result = -1;
|
||||
for (var i = 0; i < self.Length; i++)
|
||||
{
|
||||
var num2 = comparer.Invoke(self[i]);
|
||||
if (num2 > num)
|
||||
{
|
||||
result = i;
|
||||
num = num2;
|
||||
result = keyValuePair;
|
||||
tie = false;
|
||||
}
|
||||
else if (num2 == num)
|
||||
else if (keyValuePair.Value == result.Value)
|
||||
{
|
||||
tie = true;
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Dictionary<byte, int> CalculateVotes()
|
||||
{
|
||||
var players = new Dictionary<byte, int>();
|
||||
foreach (var playerVoteArea in _playerStates)
|
||||
{
|
||||
if (!playerVoteArea.IsDead && playerVoteArea.DidVote && playerVoteArea.VoteType != VoteType.Missed)
|
||||
{
|
||||
if (players.TryGetValue(playerVoteArea.VotedForId, out var current))
|
||||
{
|
||||
players[playerVoteArea.VotedForId] = current + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
players[playerVoteArea.VotedForId] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return players;
|
||||
}
|
||||
|
||||
private async ValueTask HandleVotingCompleteAsync()
|
||||
{
|
||||
_timerToken.Cancel();
|
||||
@@ -271,14 +266,14 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
if (!playerVoteArea.DidVote)
|
||||
{
|
||||
playerVoteArea.SetVotedFor((sbyte)VoteType.ForceSkip);
|
||||
playerVoteArea.SetVotedFor((byte)VoteType.Missed);
|
||||
await HandleVoteAsync(playerVoteArea);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] self = this.CalculateVotes();
|
||||
var maxIdx = IndexOfMax(self, p => p, out var tie) - 1;
|
||||
var exiled = Game.GameNet.GameData!.GetPlayerById((byte)maxIdx)?.Controller;
|
||||
var self = this.CalculateVotes();
|
||||
var max = MaxPair(self, out var tie);
|
||||
var exiled = tie ? null : Game.GameNet.GameData!.GetPlayerById(max.Key)?.Controller;
|
||||
|
||||
if (exiled != null)
|
||||
{
|
||||
|
||||
@@ -297,6 +297,17 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
break;
|
||||
}
|
||||
|
||||
case RpcCalls.SendQuickChat:
|
||||
{
|
||||
if (!await ValidateOwnership(call, sender))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: deserialize and expose the result in an API
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return await base.HandleRpcAsync(sender, target, call, reader);
|
||||
}
|
||||
@@ -416,7 +427,7 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
var i = 1;
|
||||
while (true)
|
||||
{
|
||||
string text = expected + " " + i;
|
||||
var text = expected + " " + i;
|
||||
|
||||
if (Game.Players.All(x => x.Character == null || x.Character == this || x.Character.PlayerInfo.PlayerName != text))
|
||||
{
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Impostor.Api.Events.Managers;
|
||||
using Impostor.Api.Games;
|
||||
using Impostor.Api.Innersloth;
|
||||
using Impostor.Api.Innersloth.Customization;
|
||||
using Impostor.Api.Net.Messages;
|
||||
using Impostor.Api.Utils;
|
||||
using Impostor.Server.Net.State;
|
||||
|
||||
namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
|
||||
@@ -24,9 +24,9 @@ namespace Impostor.Server.Net.Inner.Objects.ShipStatus
|
||||
|
||||
public override Vector2 InitialSpawnCenter { get; } = new Vector2(16.64f, -2.46f);
|
||||
|
||||
public override Vector2 MeetingSpawnCenter { get; } = new Vector2(17.726f, -16.286f);
|
||||
public override Vector2 MeetingSpawnCenter { get; } = new Vector2(17.4f, -16.286f);
|
||||
|
||||
public Vector2 MeetingSpawnCenter2 { get; } = new Vector2(-17.7f, -17.5f);
|
||||
public Vector2 MeetingSpawnCenter2 { get; } = new Vector2(17.4f, -17.515f);
|
||||
|
||||
public override Vector2 GetSpawnLocation(InnerPlayerControl player, int numPlayers, bool initialSpawn)
|
||||
{
|
||||
@@ -35,17 +35,16 @@ namespace Impostor.Server.Net.Inner.Objects.ShipStatus
|
||||
return base.GetSpawnLocation(player, numPlayers, initialSpawn);
|
||||
}
|
||||
|
||||
Vector2 position;
|
||||
if (player.PlayerId < 5)
|
||||
var halfPlayers = numPlayers / 2; // floored intentionally
|
||||
var spawnId = player.PlayerId % 15;
|
||||
if (player.PlayerId < halfPlayers)
|
||||
{
|
||||
position = this.MeetingSpawnCenter + (new Vector2(1, 0) * player.PlayerId);
|
||||
return this.MeetingSpawnCenter + (new Vector2(0.6f, 0) * spawnId);
|
||||
}
|
||||
else
|
||||
{
|
||||
position = this.MeetingSpawnCenter2 + (new Vector2(1, 0) * (player.PlayerId - 5));
|
||||
return this.MeetingSpawnCenter2 + (new Vector2(0.6f, 0) * (spawnId - halfPlayers));
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
protected override void AddSystems(Dictionary<SystemTypes, ISystemType> systems)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
@@ -18,10 +19,10 @@ namespace Impostor.Server.Net.Manager
|
||||
{
|
||||
internal partial class ClientManager
|
||||
{
|
||||
private static readonly HashSet<int> SupportedVersions = new HashSet<int>
|
||||
// NOTE: when updating this array, keep the versions ordered from old to new, otherwise the version compare logic doesn't work properly
|
||||
private static readonly int[] SupportedVersions =
|
||||
{
|
||||
GameVersion.GetVersion(2021, 3, 25), // 2021.3.31s
|
||||
GameVersion.GetVersion(2021, 4, 2), // 2021.4.2a
|
||||
GameVersion.GetVersion(2021, 4, 25), // 2021.6.15
|
||||
};
|
||||
|
||||
private readonly ILogger<ClientManager> _logger;
|
||||
@@ -38,6 +39,14 @@ namespace Impostor.Server.Net.Manager
|
||||
_clients = new ConcurrentDictionary<int, ClientBase>();
|
||||
}
|
||||
|
||||
private enum VersionCompareResult
|
||||
{
|
||||
Compatible,
|
||||
ClientTooOld,
|
||||
ServerTooOld,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
public IEnumerable<ClientBase> Clients => _clients.Values;
|
||||
|
||||
public int NextId()
|
||||
@@ -58,10 +67,24 @@ namespace Impostor.Server.Net.Manager
|
||||
|
||||
public async ValueTask RegisterConnectionAsync(IHazelConnection connection, string name, int clientVersion)
|
||||
{
|
||||
if (!SupportedVersions.Contains(clientVersion))
|
||||
var versionCompare = CompareVersion(clientVersion);
|
||||
if (versionCompare != VersionCompareResult.Compatible)
|
||||
{
|
||||
GameVersion.ParseVersion(clientVersion, out var year, out var month, out var day, out var revision);
|
||||
_logger.LogTrace("Client connected using unsupported version: {clientVersion} ({version})", clientVersion, $"{year}.{month}.{day}{(revision == 0 ? string.Empty : "." + revision)}");
|
||||
|
||||
using var packet = MessageWriter.Get(MessageType.Reliable);
|
||||
Message01JoinGameS2C.SerializeError(packet, false, DisconnectReason.IncorrectVersion);
|
||||
|
||||
var message = versionCompare switch
|
||||
{
|
||||
VersionCompareResult.ClientTooOld => DisconnectMessages.VersionClientTooOld,
|
||||
VersionCompareResult.ServerTooOld => DisconnectMessages.VersionServerTooOld,
|
||||
VersionCompareResult.Unknown => DisconnectMessages.VersionUnsupported,
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
|
||||
Message01JoinGameS2C.SerializeError(packet, false, DisconnectReason.Custom, message);
|
||||
|
||||
await connection.SendAsync(packet);
|
||||
return;
|
||||
}
|
||||
@@ -104,5 +127,29 @@ namespace Impostor.Server.Net.Manager
|
||||
&& _clients.TryGetValue(client.Id, out var registeredClient)
|
||||
&& ReferenceEquals(client, registeredClient);
|
||||
}
|
||||
|
||||
private VersionCompareResult CompareVersion(int clientVersion)
|
||||
{
|
||||
foreach (var serverVersion in SupportedVersions)
|
||||
{
|
||||
if (clientVersion == serverVersion)
|
||||
{
|
||||
return VersionCompareResult.Compatible;
|
||||
}
|
||||
}
|
||||
|
||||
if (clientVersion < SupportedVersions[0])
|
||||
{
|
||||
return VersionCompareResult.ClientTooOld;
|
||||
}
|
||||
|
||||
if (clientVersion > SupportedVersions.Last())
|
||||
{
|
||||
return VersionCompareResult.ServerTooOld;
|
||||
}
|
||||
|
||||
// This may happen in the very rare case that version X is supported, X+2 is as well, but X+1 is not.
|
||||
return VersionCompareResult.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,14 +13,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Impostor.Server", "Impostor
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Impostor.Api", "Impostor.Api\Impostor.Api.csproj", "{E096A7D7-D693-4A13-A526-38CC574D84F8}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "patcher", "patcher", "{94FAED42-15BB-40CF-BE64-5D5C3B4ABC8F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Impostor.Patcher.Shared", "Impostor.Patcher\Impostor.Patcher.Shared\Impostor.Patcher.Shared.csproj", "{7C3EB599-2292-4532-B280-D5BED1094DD4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Impostor.Patcher.WinForms", "Impostor.Patcher\Impostor.Patcher.WinForms\Impostor.Patcher.WinForms.csproj", "{804CF172-0C87-4423-9688-BD97D549891E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Impostor.Patcher.Cli", "Impostor.Patcher\Impostor.Patcher.Cli\Impostor.Patcher.Cli.csproj", "{82B36C4C-4EBD-49B7-A2DB-0B3308FBEF69}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugins", "plugins", "{36AA9913-E6EA-4A6C-90E6-2FD3CC2E3124}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Impostor.Plugins.Debugger", "Impostor.Plugins.Debugger\Impostor.Plugins.Debugger.csproj", "{ECBCAA3B-B974-41CF-AFFC-6F5AA4C42FA7}"
|
||||
@@ -71,11 +63,6 @@ Global
|
||||
{D16B8DE9-8EE2-4F6A-9352-305D5AB0233D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D16B8DE9-8EE2-4F6A-9352-305D5AB0233D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D16B8DE9-8EE2-4F6A-9352-305D5AB0233D}.Release|x86.Build.0 = Release|Any CPU
|
||||
{804CF172-0C87-4423-9688-BD97D549891E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{804CF172-0C87-4423-9688-BD97D549891E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{804CF172-0C87-4423-9688-BD97D549891E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{804CF172-0C87-4423-9688-BD97D549891E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{804CF172-0C87-4423-9688-BD97D549891E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E096A7D7-D693-4A13-A526-38CC574D84F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E096A7D7-D693-4A13-A526-38CC574D84F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E096A7D7-D693-4A13-A526-38CC574D84F8}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
@@ -84,22 +71,6 @@ Global
|
||||
{E096A7D7-D693-4A13-A526-38CC574D84F8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E096A7D7-D693-4A13-A526-38CC574D84F8}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E096A7D7-D693-4A13-A526-38CC574D84F8}.Release|x86.Build.0 = Release|Any CPU
|
||||
{7C3EB599-2292-4532-B280-D5BED1094DD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7C3EB599-2292-4532-B280-D5BED1094DD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7C3EB599-2292-4532-B280-D5BED1094DD4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{7C3EB599-2292-4532-B280-D5BED1094DD4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{7C3EB599-2292-4532-B280-D5BED1094DD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7C3EB599-2292-4532-B280-D5BED1094DD4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7C3EB599-2292-4532-B280-D5BED1094DD4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{7C3EB599-2292-4532-B280-D5BED1094DD4}.Release|x86.Build.0 = Release|Any CPU
|
||||
{82B36C4C-4EBD-49B7-A2DB-0B3308FBEF69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{82B36C4C-4EBD-49B7-A2DB-0B3308FBEF69}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{82B36C4C-4EBD-49B7-A2DB-0B3308FBEF69}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{82B36C4C-4EBD-49B7-A2DB-0B3308FBEF69}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{82B36C4C-4EBD-49B7-A2DB-0B3308FBEF69}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{82B36C4C-4EBD-49B7-A2DB-0B3308FBEF69}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{82B36C4C-4EBD-49B7-A2DB-0B3308FBEF69}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{82B36C4C-4EBD-49B7-A2DB-0B3308FBEF69}.Release|x86.Build.0 = Release|Any CPU
|
||||
{ECBCAA3B-B974-41CF-AFFC-6F5AA4C42FA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ECBCAA3B-B974-41CF-AFFC-6F5AA4C42FA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ECBCAA3B-B974-41CF-AFFC-6F5AA4C42FA7}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
@@ -165,9 +136,6 @@ Global
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{D16B8DE9-8EE2-4F6A-9352-305D5AB0233D} = {56DD9707-D811-4056-9E2C-8A9CC2479B07}
|
||||
{804CF172-0C87-4423-9688-BD97D549891E} = {94FAED42-15BB-40CF-BE64-5D5C3B4ABC8F}
|
||||
{7C3EB599-2292-4532-B280-D5BED1094DD4} = {94FAED42-15BB-40CF-BE64-5D5C3B4ABC8F}
|
||||
{82B36C4C-4EBD-49B7-A2DB-0B3308FBEF69} = {94FAED42-15BB-40CF-BE64-5D5C3B4ABC8F}
|
||||
{ECBCAA3B-B974-41CF-AFFC-6F5AA4C42FA7} = {36AA9913-E6EA-4A6C-90E6-2FD3CC2E3124}
|
||||
{BE44C4A8-A202-4B63-A3BA-AC0AB5E7A0EB} = {9F1919B0-915B-4749-9944-697DF7E7F67F}
|
||||
{3DF86F12-7099-44F6-B98B-A148213D60B1} = {9F1919B0-915B-4749-9944-697DF7E7F67F}
|
||||
|
||||
Reference in new issue
Block a user