Compare commits

...
57 Commits
Author SHA1 Message Date
js6pak 3e857ed555 Fix plugin host disposal 2021-06-13 21:35:04 +02:00
js6pak 9d31752bf0 Add PluginManager 2021-06-12 15:51:39 +02:00
ced530b83a Added player voted event (#181)
Co-authored-by: AeonLucid <aeonlucid@outlook.com>
Co-authored-by: js6pak <kubastaron@hotmail.com>
2021-06-11 12:33:38 +00:00
8f1cba8429 Using MapData for Tasks (#395)
Co-authored-by: John Tran <john.tran.84@live.com.au>
Co-authored-by: js6pak <kubastaron@hotmail.com>
2021-06-10 18:54:34 +00:00
js6pak 9009bac883 Merge pull request #417 from miniduikboot/fix/initialize-color 2021-06-10 18:38:17 +00:00
miniduikboot f3460f05bc Initialize Color to -1 instead of Red
This could lead to an AC disconnect if the host picked red and waited
for other players to rejoin before joining back himself. Before this
commit, the host would SetColor himself to Red, but this would be
flagged as all other players would have been set to Red as enums
initialize to 0 (= Red) by default.

After the host SetColor'd himself, the host will send over the color
array, which initializes player colors to -1. This commit follows AU by
also initializing the color to -1, preventing the AC from flagging the
duplicate colors.
2021-05-30 18:30:47 +02:00
miniduikboot a13fee108f Fix KeyNotFoundException for nonexistent vents (#413)
Some mods add extra vents that don't yet exist, this commit checks if a
given vent exists and if it doesn't, throw an AC violation instead of
disconnecting the player

One downside is that the Enter/ExitVent events are no longer called, but
this would require the vent in that event to become nullable
2021-05-17 17:13:54 +00:00
js6pak adc0e6fe9b Don't broadcast packets of kicked players 2021-05-12 18:49:20 +02:00
js6pak ce62815dc5 Add custom message support (#404) 2021-05-10 11:08:26 +00:00
js6pak b1a0adaa28 Merge pull request #389 from Impostor/plugin-info-from-csproj 2021-04-27 17:54:53 +00:00
js6pak fe697b1b63 Deprecate old ImpostorPluginAttribute constructor 2021-04-27 14:58:16 +02:00
js6pak 55e6d38f9f Merge pull request #400 from HarmHoog/skin-hat-types 2021-04-26 12:48:16 +00:00
cchudant b73a46ff56 [skip ci] Rename dev branch in Running-the-server.md (#402) 2021-04-26 12:47:03 +00:00
js6pak 901deeff59 Remove ownership check from InnerVoteBanSystem 2021-04-21 22:01:01 +02:00
Harm Hoogeveen f2126fd4c6 Add new skin types 2021-04-20 14:24:06 +02:00
Harm Hoogeveen 9aa6109b3a Add new hat types 2021-04-20 14:23:02 +02:00
js6pak e1a6fdda98 Make it possible to read plugin information from csproj attributes 2021-04-13 23:13:52 +02:00
Harm Hoogeveenandjs6pak 283f59b51f Allow plugins to set dependencies, softdependencies and loadbefores to determine the load order of plugins (#385)
Co-authored-by: js6pak <kubastaron@hotmail.com>
2021-04-13 20:28:24 +00:00
Minorusamaandjs6pak d47343df08 BeforeGameCreatedEvent (#266)
Co-authored-by: js6pak <kubastaron@hotmail.com>
2021-04-13 16:29:44 +00:00
js6pak 0bb5442a3a Merge pull request #387 from Impostor/murder-check-ping
Add simple ping toleration to murder player check
2021-04-13 15:17:20 +00:00
js6pak 7ac6c32b5d Set configuration's BasePath to CurrentDirectory 2021-04-13 11:29:08 +02:00
112batman fbd9f12f9e Add GameHostChange event (#277) 2021-04-12 20:53:14 +00:00
js6pak f43577b745 Add simple ping toleration to murder player check 2021-04-11 16:05:08 +02:00
js6pak a56eed2680 Use actual disconnect message in ClientBase#DisconnectAsync 2021-04-11 14:57:29 +02:00
js6pak f0434f071c Merge pull request #377 from Impostor/airship 2021-04-11 12:04:31 +00:00
js6pak 8d27016cb7 Fix xmldoc warnings 2021-04-10 23:00:34 +02:00
js6pak e941796a4c Bump version 2021-04-10 22:55:40 +02:00
js6pak 1d66f07906 Make vent data initialization much cleaner 2021-04-10 17:14:17 +02:00
js6pak 7764987f91 Specify enum values for Platforms 2021-04-09 23:51:50 +02:00
js6pak bfba4385fd Make PlayerVentEvent an actual PlayerVentEvent 2021-04-06 21:10:53 +02:00
js6pak f03e72206e Update example plugin 2021-04-06 20:51:06 +02:00
js6pak 304b4bb7bf Rework vent api 2021-04-06 20:51:06 +02:00
970f826dc8 Allow Android Versions (#375)
Co-authored-by: js6pak <kubastaron@hotmail.com>
Co-authored-by: John Tran <john.tran.84@live.com.au>
2021-04-06 18:50:50 +00:00
js6pak 4866a350f8 Implement airship spawning, closes #376 2021-04-04 23:27:39 +02:00
js6pak 13bddeb7bd Split ShipStatus to multiple classes, implement new door types 2021-04-04 23:27:39 +02:00
js6pak 225b56e71f Fix cheatcontext in ValidateImpostor calls 2021-04-04 23:27:39 +02:00
js6pak 60bf6b5f58 Fix namespaces 2021-04-04 23:27:39 +02:00
b5cee48242 Airship Vent Enums (#373)
Co-authored-by: miniduikboot <5243971+miniduikboot@users.noreply.github.com>
Co-authored-by: John Tran <john.tran.84@live.com.au>
2021-04-04 10:31:28 +00:00
js6pak c750c65481 Merge pull request #372 from miniduikboot/2021.3.31 2021-04-04 10:26:07 +00:00
miniduikboot d801a36af8 Rename things for 6pak 2021-04-04 10:35:00 +02:00
miniduikboot 441d9c300c Move PlayerVentEvent call to applicable RPC's 2021-04-03 00:46:34 +02:00
miniduikboot 7fd68e31e6 Fix Docker container build 2021-04-03 00:37:12 +02:00
miniduikboot 47aebe7b7b Fix InnerShipStatus deserializing
3.31 now distributes them as multiple messages

This also explains the two weird bytes in HeliSabotage, so these can be
removed too
2021-04-03 00:29:05 +02:00
miniduikboot 66c2434320 Implement HeliSabotageSystemType
It works, although I'm not completely sure why.
2021-04-03 00:29:05 +02:00
miniduikboot c01062ed65 implement rpc 32: use platform 2021-04-03 00:29:05 +02:00
miniduikboot d5ae007d1c implement rpc 31: climb ladder 2021-04-03 00:29:05 +02:00
miniduikboot 16a2b0aac6 I counted the doors on Airship
and I hope I counted correctly
2021-04-03 00:29:05 +02:00
miniduikboot 4c1bd4a578 editorconfig: Don't indent blocks in case contents
This is more in line with the existing codebase
2021-04-03 00:29:05 +02:00
miniduikboot d311150967 API: update enums for airship 2021-04-03 00:29:05 +02:00
miniduikboot 92e3506f51 First attempt at getting some airship stuff online 2021-04-03 00:29:05 +02:00
miniduikboot a63fc40099 Gamedata packets are now have initial state false
I managed to get into a lobby with this
2021-04-03 00:29:05 +02:00
js6pak 4f53d3f4e6 Hopefully fix the submodule 2021-04-03 00:14:33 +02:00
js6pak a39fae3325 Initial auth implementation 2021-04-03 00:12:15 +02:00
js6pak 7c34836d50 Remove reactor stuff 2021-04-03 00:12:15 +02:00
js6pak 989b06d04c Use BitConverter.Int32BitsToSingle in SpanReaderExtensions 2021-04-03 00:12:15 +02:00
js6pak 11e87e51db Update airship constants 2021-04-03 00:12:15 +02:00
js6pak b90e5b2c88 Switch back hazel to submodule 2021-04-03 00:11:55 +02:00
210 changed files with 3902 additions and 5026 deletions

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
[submodule "src/Impostor.Hazel"]
path = src/Impostor.Hazel
url = https://github.com/Impostor/Impostor.Hazel
+2 -2
View File
@@ -11,7 +11,7 @@ WORKDIR /source
# Copy csproj and restore.
COPY src/Impostor.Server/Impostor.Server.csproj ./src/Impostor.Server/Impostor.Server.csproj
COPY src/Impostor.Api/Impostor.Api.csproj ./src/Impostor.Api/Impostor.Api.csproj
COPY src/Impostor.Hazel/Impostor.Hazel.csproj ./src/Impostor.Hazel/Impostor.Hazel.csproj
COPY src/Impostor.Hazel/Hazel/Hazel.csproj ./src/Impostor.Hazel/Hazel/Hazel.csproj
RUN case "$TARGETARCH" in \
amd64) NETCORE_PLATFORM='linux-x64';; \
@@ -21,7 +21,7 @@ RUN case "$TARGETARCH" in \
esac && \
dotnet restore -r "$NETCORE_PLATFORM" ./src/Impostor.Server/Impostor.Server.csproj && \
dotnet restore -r "$NETCORE_PLATFORM" ./src/Impostor.Api/Impostor.Api.csproj && \
dotnet restore -r "$NETCORE_PLATFORM" ./src/Impostor.Hazel/Impostor.Hazel.csproj
dotnet restore -r "$NETCORE_PLATFORM" ./src/Impostor.Hazel/Hazel/Hazel.csproj
# Copy everything else.
COPY src/. ./src/
+2 -1
View File
@@ -9,7 +9,8 @@ Impostor is one of the first **Among Us** private servers, written in C#.
|-|-|-|-|
| 1.1.0 | 2020.09.07 - 2020.09.22 | No | [![Download](https://img.shields.io/badge/Download-v1.1.0-blue?style=flat-square)](https://github.com/Impostor/Impostor/releases/tag/v1.1.0) |
| 1.2.2 | 2020.09.22 - 2020.11.17 | No | [![Download](https://img.shields.io/badge/Download-v1.2.2-blue?style=flat-square)](https://github.com/Impostor/Impostor/releases/tag/v1.2.2) |
| 1.3.0 | 2021.3.5 | Yes | [![Download](https://img.shields.io/badge/Download-master-blue?style=flat-square)](https://ci.appveyor.com/project/Impostor/Impostor/branch/master/artifacts) |
| 1.3.0 | 2021.3.5 | No | [![Download](https://img.shields.io/badge/Download-v1.3.0-blue?style=flat-square)](https://github.com/Impostor/Impostor/releases/tag/v1.3.0) |
| 1.4.0 | 2021.3.31 - 2021.4.2 | Yes | [![Download](https://img.shields.io/badge/Download-master-blue?style=flat-square)](https://ci.appveyor.com/project/Impostor/Impostor/branch/master/artifacts) |
## Features
+1 -1
View File
@@ -9,7 +9,7 @@ There are currently two modes to run the Impostor server in. The first way is th
- [Windows x64](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-5.0.0-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 dev release](https://ci.appveyor.com/project/Impostor/Impostor/branch/dev/artifacts).
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.
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)*
+1 -1
View File
@@ -171,7 +171,7 @@ csharp_new_line_between_query_expression_clauses = true
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_case_contents_when_block = false
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
+1 -1
View File
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<VersionPrefix>1.3.0</VersionPrefix>
<VersionPrefix>1.4.0</VersionPrefix>
<VersionSuffix>dev</VersionSuffix>
</PropertyGroup>
+1 -1
View File
@@ -1,4 +1,4 @@
using Impostor.Server.Net.Inner;
using Impostor.Api.Net.Inner;
namespace Impostor.Api
{
@@ -0,0 +1,12 @@
using Impostor.Api.Net;
namespace Impostor.Api.Events.Client
{
/// <summary>
/// Called just after a <see cref="IClient"/> is created and connected.
/// </summary>
public interface IClientConnectedEvent : IClientEvent
{
IClient Client { get; }
}
}
@@ -0,0 +1,13 @@
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Events.Client
{
/// <summary>
/// Called just before a <see cref="IHazelConnection"/> is registered.
/// </summary>
public interface IClientConnectionEvent : IClientEvent
{
IMessageReader HandshakeData { get; }
}
}
@@ -0,0 +1,9 @@
using Impostor.Api.Net;
namespace Impostor.Api.Events.Client
{
public interface IClientEvent : IEvent
{
IHazelConnection Connection { get; }
}
}
@@ -0,0 +1,25 @@
using Impostor.Api.Games;
using Impostor.Api.Net;
namespace Impostor.Api.Events
{
/// <summary>
/// Called just before a new <see cref="IGame"/> is created.
/// </summary>
public interface IGameCreationEvent : IEventCancelable
{
/// <summary>
/// Gets the client that requested creation of the game.
/// </summary>
/// <remarks>
/// Will be null if game creation was requested by a plugin.
/// </remarks>
IClient? Client { get; }
/// <summary>
/// Gets or sets the desired <see cref="Games.GameCode"/>.
/// </summary>
/// <exception cref="ImpostorException">If the GameCode is invalid or already used in another game.</exception>
GameCode? GameCode { get; set; }
}
}
@@ -0,0 +1,11 @@
using Impostor.Api.Net;
namespace Impostor.Api.Events
{
public interface IGameHostChangedEvent : IGameEvent
{
IClientPlayer PreviousHost { get; }
IClientPlayer? NewHost { get; }
}
}
@@ -1,6 +1,9 @@
namespace Impostor.Api.Events
using Impostor.Api.Net;
namespace Impostor.Api.Events
{
public interface IGamePlayerJoinedEvent : IGameEvent
{
IClientPlayer Player { get; }
}
}
@@ -0,0 +1,15 @@
using Impostor.Api.Games;
using Impostor.Api.Net;
namespace Impostor.Api.Events
{
/// <summary>
/// Called just before a <see cref="IClientPlayer"/> joins a game.
/// </summary>
public interface IGamePlayerJoiningEvent : IGameEvent
{
IClientPlayer Player { get; }
GameJoinResult? JoinResult { get; set; }
}
}
@@ -1,6 +1,11 @@
namespace Impostor.Api.Events
using Impostor.Api.Net;
namespace Impostor.Api.Events
{
public interface IGamePlayerLeftEvent : IGameEvent
{
IClientPlayer Player { get; }
bool IsBan { get; }
}
}
@@ -1,6 +1,17 @@
namespace Impostor.Api.Events.Meeting
using Impostor.Api.Net.Inner.Objects;
namespace Impostor.Api.Events.Meeting
{
public interface IMeetingEndedEvent : IMeetingEvent
{
/// <summary>
/// Gets the exiled player.
/// </summary>
IInnerPlayerControl? Exiled { get; }
/// <summary>
/// Gets a value indicating whether meeting result is a tie.
/// </summary>
bool IsTie { get; }
}
}
@@ -0,0 +1,15 @@
using Impostor.Api.Innersloth;
namespace Impostor.Api.Events.Player
{
/// <summary>
/// Called whenever a player enters a vent.
/// </summary>
public interface IPlayerEnterVentEvent : IPlayerEvent
{
/// <summary>
/// Gets the entered vent.
/// </summary>
public IVent Vent { get; }
}
}
@@ -0,0 +1,15 @@
using Impostor.Api.Innersloth;
namespace Impostor.Api.Events.Player
{
/// <summary>
/// Called whenever a player exits a vent.
/// </summary>
public interface IPlayerExitVentEvent : IPlayerEvent
{
/// <summary>
/// Gets the exited vent.
/// </summary>
public IVent Vent { get; }
}
}
@@ -2,16 +2,14 @@ using Impostor.Api.Innersloth;
namespace Impostor.Api.Events.Player
{
/// <summary>
/// Called whenever a player moves to another vent.
/// </summary>
public interface IPlayerVentEvent : IPlayerEvent
{
/// <summary>
/// Gets get the id of the used vent.
/// Gets the vent player moved to.
/// </summary>
public VentLocation VentId { get; }
/// <summary>
/// Gets a value indicating whether the vent was entered or exited.
/// </summary>
public bool VentEnter { get; }
public IVent NewVent { get; }
}
}
@@ -0,0 +1,24 @@
using Impostor.Api.Net.Inner.Objects;
namespace Impostor.Api.Events.Player
{
public enum VoteType : sbyte
{
ForceSkip = -2,
Skip = -1,
Player = 0,
}
public interface IPlayerVotedEvent : IPlayerEvent
{
/// <summary>
/// Gets the player he voted for.
/// </summary>
IInnerPlayerControl? VotedFor { get; }
/// <summary>
/// Gets the Vote type.
/// </summary>
VoteType VoteType { get; }
}
}
@@ -1,12 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Impostor.Server.Events
namespace Impostor.Api.Events
{
/// <summary>
/// Disposes multiple <see cref="IDisposable" />.
/// </summary>
internal class MultiDisposable : IDisposable
public class MultiDisposable : IDisposable
{
private readonly IEnumerable<IDisposable> _disposables;
@@ -15,6 +16,10 @@ namespace Impostor.Server.Events
_disposables = disposables;
}
public MultiDisposable(params IDisposable[] disposables) : this(disposables.AsEnumerable())
{
}
public void Dispose()
{
foreach (var disposable in _disposables)
@@ -0,0 +1,19 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Impostor.Api
{
public static class DictionaryExtensions
{
/// <summary>Returns a read-only <see cref="ReadOnlyDictionary{TKey,TValue}" /> wrapper for the dictionary.</summary>
/// <param name="dictionary">An <see cref="IDictionary{TKey,TValue}" /> to create a <see cref="ReadOnlyDictionary{TKey,TValue}" /> from.</param>
/// <typeparam name="TKey">The type of the keys of <paramref name="dictionary" />.</typeparam>
/// <typeparam name="TValue">The type of the values of <paramref name="dictionary" />.</typeparam>
/// <returns>An object that acts as a read-only wrapper around the <see cref="IDictionary{TKey,TValue}" />.</returns>
public static ReadOnlyDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(this IDictionary<TKey, TValue> dictionary)
where TKey : notnull
{
return new ReadOnlyDictionary<TKey, TValue>(dictionary);
}
}
}
@@ -35,9 +35,7 @@ namespace Impostor.Api
{
var original = Advance<float>(ref input);
// BitConverter.Int32BitsToSingle
// Doesn't exist in net 2.0 for some reason
return Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(original));
return BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(original));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -46,12 +44,6 @@ namespace Impostor.Api
return input.ReadByte() != 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe float Int32BitsToSingle(int value)
{
return *((float*)&value);
}
/// <summary>
/// Advances the position of <paramref name="input" /> by the size of <typeparamref name="T" />.
/// </summary>
+4 -2
View File
@@ -1,4 +1,4 @@
using System;
using System;
using Impostor.Api.Innersloth;
namespace Impostor.Api.Games
@@ -14,13 +14,15 @@ namespace Impostor.Api.Games
public GameCode(string code)
{
Value = GameCodeParser.GameNameToInt(code);
Code = code;
Code = code.ToUpperInvariant();
}
public string Code { get; }
public int Value { get; }
public bool IsInvalid => Value == -1;
public static implicit operator string(GameCode code) => code.Code;
public static implicit operator int(GameCode code) => code.Value;
+19
View File
@@ -90,5 +90,24 @@ namespace Impostor.Api.Games
/// <param name="id">ID of the client.</param>
/// <returns>A <see cref="ValueTask" /> representing the asynchronous operation.</returns>
ValueTask SendToAsync(IMessageWriter writer, int id);
/// <summary>
/// Creates a MessageWriter with GameData header.
/// </summary>
/// <remarks>Use with caution, recommended only for advanced developers.</remarks>
/// <param name="targetNetId">Net id of the InnerNetObject.</param>
/// <param name="callId">Rpc id of the message.</param>
/// <param name="targetClientId">Client id of GameDataTo's target.</param>
/// <param name="type">Message type of the message.</param>
/// <returns>A <see cref="IMessageWriter" /> that you can fill with rpc data and send using <see cref="FinishRpcAsync"/>.</returns>
IMessageWriter StartRpc(uint targetNetId, RpcCalls callId, int? targetClientId, MessageType type = MessageType.Reliable);
/// <summary>
/// Finishes rpc message and sends it to the target.
/// </summary>
/// <param name="writer">Message writer of the rpc.</param>
/// <param name="targetClientId">Id of the receiving client.</param>
/// <returns>A <see cref="ValueTask" /> representing the asynchronous operation.</returns>
ValueTask FinishRpcAsync(IMessageWriter writer, int? targetClientId = null);
}
}
@@ -10,6 +10,12 @@ namespace Impostor.Api.Games.Managers
IGame? Find(GameCode code);
ValueTask<IGame> CreateAsync(GameOptionsData options);
/// <summary>
/// Creates a new game.
/// </summary>
/// <param name="options">Game 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);
}
}
@@ -1,6 +1,6 @@
namespace Impostor.Api.Innersloth.Customization
{
public enum ColorType : byte
public enum ColorType
{
Red = 0,
Blue = 1,
@@ -97,5 +97,25 @@
RamHorns = 92,
SnowCrewmate = 93,
GeoffHat = 94,
DaveCap = 95,
EllieRose = 96,
SvenHat = 97,
BurtHat = 98,
EllryMohawk = 99,
ThomasMonoc = 100,
Wizard = 101,
Fredrick = 102,
MrMacbeth = 103,
ToppatHenry = 104,
ToppatEllie = 105,
GeoffreyPlumb = 106,
AngryEyebrows = 107,
ChocolateIce = 108,
HeartPin = 109,
Ponytail = 110,
RubberGlove = 111,
UnicornHorn = 112,
Zipper = 113,
RightHandMan = 114,
}
}
@@ -18,5 +18,8 @@
Miner = 13,
Winter = 14,
Archae = 15,
Prisoner = 16,
CCC = 17,
RightHandMan = 18,
}
}
+15
View File
@@ -0,0 +1,15 @@
namespace Impostor.Api.Innersloth
{
public interface ITask
{
int Id { get; }
string Name { get; }
TaskTypes Type { get; }
TaskCategories Category { get; }
bool IsVisual { get; }
}
}
+19
View File
@@ -0,0 +1,19 @@
using System.Numerics;
namespace Impostor.Api.Innersloth
{
public interface IVent
{
int Id { get; }
string Name { get; }
Vector2 Position { get; }
IVent? Left { get; }
IVent? Center { get; }
IVent? Right { get; }
}
}
-45
View File
@@ -1,45 +0,0 @@
using System;
using System.Collections.Generic;
using System.Numerics;
namespace Impostor.Api.Innersloth
{
public class MapSpawn
{
private MapSpawn(float spawnRadius, Vector2 initialSpawnCenter, Vector2 meetingSpawnCenter)
{
SpawnRadius = spawnRadius;
InitialSpawnCenter = initialSpawnCenter;
MeetingSpawnCenter = meetingSpawnCenter;
}
public static Dictionary<MapTypes, MapSpawn> Maps { get; } = new Dictionary<MapTypes, MapSpawn>
{
[MapTypes.Skeld] = new MapSpawn(1.6f, new Vector2(-0.72f, 0.62f), new Vector2(-0.72f, 0.62f)),
[MapTypes.MiraHQ] = new MapSpawn(1.55f, new Vector2(-4.4f, 2.2f), new Vector2(24.043f, 1.72f)),
[MapTypes.Polus] = new MapSpawn(1f, new Vector2(16.64f, -2.46f), new Vector2(17.726f, -16.286f)),
};
public float SpawnRadius { get; }
public Vector2 InitialSpawnCenter { get; }
public Vector2 MeetingSpawnCenter { get; }
public Vector2 GetSpawnLocation(int playerId, int numPlayer, bool initialSpawn)
{
var vector = new Vector2(0, 1);
vector = Rotate(vector, (playerId - 1) * (360f / numPlayer));
vector *= this.SpawnRadius;
return (initialSpawn ? this.InitialSpawnCenter : this.MeetingSpawnCenter) + vector + new Vector2(0f, 0.3636f);
}
private static Vector2 Rotate(Vector2 self, float degrees)
{
var f = 0.017453292f * degrees;
var num = (float)Math.Cos(f);
var num2 = (float)Math.Sin(f);
return new Vector2((self.X * num) - (num2 * self.Y), (self.X * num2) + (num * self.Y));
}
}
}
+1
View File
@@ -5,5 +5,6 @@
Skeld = 0,
MiraHQ = 1,
Polus = 2,
Airship = 4,
}
}
@@ -0,0 +1,91 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Impostor.Api.Innersloth.Maps.Tasks;
using Impostor.Api.Innersloth.Maps.Vents;
namespace Impostor.Api.Innersloth.Maps
{
public class AirshipData : IMapData
{
private readonly IReadOnlyDictionary<int, IVent> _vents;
private readonly IReadOnlyDictionary<int, ITask> _tasks;
internal AirshipData()
{
var vents = new[]
{
new AirshipVent(this, AirshipVent.Ids.Vault, new Vector2(-12.6322f, 8.4735f), left: AirshipVent.Ids.Cockpit),
new AirshipVent(this, AirshipVent.Ids.Cockpit, new Vector2(-22.099f, -1.512f), left: AirshipVent.Ids.Vault, right: AirshipVent.Ids.ViewingDeck),
new AirshipVent(this, AirshipVent.Ids.ViewingDeck, new Vector2(-15.659f, -11.6991f), left: AirshipVent.Ids.Cockpit),
new AirshipVent(this, AirshipVent.Ids.EngineRoom, new Vector2(0.203f, -2.5361f), left: AirshipVent.Ids.Kitchen, right: AirshipVent.Ids.MainHallBottom),
new AirshipVent(this, AirshipVent.Ids.Kitchen, new Vector2(-2.6019f, -9.338f), left: AirshipVent.Ids.EngineRoom, right: AirshipVent.Ids.MainHallBottom),
new AirshipVent(this, AirshipVent.Ids.MainHallBottom, new Vector2(7.021f, -3.730999f), left: AirshipVent.Ids.EngineRoom, right: AirshipVent.Ids.Kitchen),
new AirshipVent(this, AirshipVent.Ids.GapRight, new Vector2(9.814f, 3.206f), left: AirshipVent.Ids.MainHallTop, right: AirshipVent.Ids.GapLeft),
new AirshipVent(this, AirshipVent.Ids.GapLeft, new Vector2(12.663f, 5.922f), left: AirshipVent.Ids.MainHallTop, right: AirshipVent.Ids.GapRight),
new AirshipVent(this, AirshipVent.Ids.MainHallTop, new Vector2(3.605f, 6.923f), left: AirshipVent.Ids.GapLeft, right: AirshipVent.Ids.GapRight),
new AirshipVent(this, AirshipVent.Ids.Showers, new Vector2(23.9869f, -1.386f), left: AirshipVent.Ids.Records, right: AirshipVent.Ids.CargoBay),
new AirshipVent(this, AirshipVent.Ids.Records, new Vector2(23.2799f, 8.259998f), left: AirshipVent.Ids.Showers, right: AirshipVent.Ids.CargoBay),
new AirshipVent(this, AirshipVent.Ids.CargoBay, new Vector2(30.4409f, -3.577f), left: AirshipVent.Ids.Showers, right: AirshipVent.Ids.Records),
};
Vents = vents.ToDictionary(x => x.Id, x => x).AsReadOnly();
_vents = vents.ToDictionary(x => (int)x.Id, x => (IVent)x).AsReadOnly();
var tasks = new[]
{
new AirshipTask(AirshipTask.Ids.ElectricalFixWiring, TaskTypes.FixWiring, TaskCategories.CommonTask),
new AirshipTask(AirshipTask.Ids.MeetingRoomEnterIDCode, TaskTypes.EnterIdCode, TaskCategories.CommonTask),
new AirshipTask(AirshipTask.Ids.ElectricalResetBreakers, TaskTypes.ResetBreakers, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.VaultRoomDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.BrigDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.CargoBayDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.GapRoomDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.RecordsDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.CargoBayUnlockSafe, TaskTypes.UnlockSafe, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.VentilationStartFans, TaskTypes.StartFans, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.MainHallEmptyGarbage, TaskTypes.EmptyGarbage, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.MedicalEmptyGarbage, TaskTypes.EmptyGarbage, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.KitchenEmptyGarbage, TaskTypes.EmptyGarbage, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.MainHallDevelopPhotos, TaskTypes.DevelopPhotos, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.CargoBayFuelEngines, TaskTypes.FuelEngines, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.SecurityRewindTapes, TaskTypes.RewindTapes, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.VaultRoomPolishRuby, TaskTypes.PolishRuby, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ElectricalCalibrateDistributor, TaskTypes.CalibrateDistributor, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.CockpitStabilizeSteering, TaskTypes.StabilizeSteering, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ArmoryDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.CockpitDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.CommsDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.MedicalDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.ViewingDeckDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.ElectricalDivertPowerToArmory, TaskTypes.DivertPower, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ElectricalDivertPowerToCockpit, TaskTypes.DivertPower, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ElectricalDivertPowerToGapRoom, TaskTypes.DivertPower, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ElectricalDivertPowerToMainHall, TaskTypes.DivertPower, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ElectricalDivertPowerToMeetingRoom, TaskTypes.DivertPower, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ElectricalDivertPowerToShowers, TaskTypes.DivertPower, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ElectricalDivertPowerToEngine, TaskTypes.DivertPower, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ShowersPickUpTowels, TaskTypes.PickUpTowels, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.LoungeCleanToilet, TaskTypes.CleanToilet, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.VaultRoomDressMannequin, TaskTypes.DressMannequin, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.RecordsSortRecords, TaskTypes.SortRecords, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ArmoryPutAwayPistols, TaskTypes.PutAwayPistols, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ArmoryPutAwayRifles, TaskTypes.PutAwayRifles, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.MainHallDecontaminate, TaskTypes.Decontaminate, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.KitchenMakeBurger, TaskTypes.MakeBurger, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ShowersFixShower, TaskTypes.FixShower, TaskCategories.ShortTask),
};
Tasks = tasks.ToDictionary(x => x.Id, x => x).AsReadOnly();
_tasks = tasks.ToDictionary(x => (int)x.Id, x => (ITask)x).AsReadOnly();
}
public IReadOnlyDictionary<AirshipVent.Ids, AirshipVent> Vents { get; }
IReadOnlyDictionary<int, IVent> IMapData.Vents => _vents;
public IReadOnlyDictionary<AirshipTask.Ids, AirshipTask> Tasks { get; }
IReadOnlyDictionary<int, ITask> IMapData.Tasks => _tasks;
}
}
@@ -0,0 +1,19 @@
using System.Collections.Generic;
namespace Impostor.Api.Innersloth.Maps
{
public interface IMapData
{
public static IReadOnlyDictionary<MapTypes, IMapData> Maps { get; } = new Dictionary<MapTypes, IMapData>
{
[MapTypes.Skeld] = new SkeldData(),
[MapTypes.MiraHQ] = new MiraData(),
[MapTypes.Polus] = new PolusData(),
[MapTypes.Airship] = new AirshipData(),
}.AsReadOnly();
IReadOnlyDictionary<int, IVent> Vents { get; }
IReadOnlyDictionary<int, ITask> Tasks { get; }
}
}
@@ -0,0 +1,76 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Impostor.Api.Innersloth.Maps.Tasks;
using Impostor.Api.Innersloth.Maps.Vents;
namespace Impostor.Api.Innersloth.Maps
{
public class MiraData : IMapData
{
private readonly IReadOnlyDictionary<int, IVent> _vents;
private readonly IReadOnlyDictionary<int, ITask> _tasks;
internal MiraData()
{
var vents = new[]
{
new MiraVent(this, MiraVent.Ids.Balcony, new Vector2(23.77f, -1.94f), left: MiraVent.Ids.Medbay, right: MiraVent.Ids.Cafeteria),
new MiraVent(this, MiraVent.Ids.Cafeteria, new Vector2(23.9f, 7.18f), left: MiraVent.Ids.Admin, right: MiraVent.Ids.Balcony),
new MiraVent(this, MiraVent.Ids.Reactor, new Vector2(0.4800001f, 10.697f), left: MiraVent.Ids.Laboratory, center: MiraVent.Ids.Decontamination, right: MiraVent.Ids.Launchpad),
new MiraVent(this, MiraVent.Ids.Laboratory, new Vector2(11.606f, 13.816f), left: MiraVent.Ids.Reactor, center: MiraVent.Ids.Decontamination, right: MiraVent.Ids.Office),
new MiraVent(this, MiraVent.Ids.Office, new Vector2(13.28f, 20.13f), left: MiraVent.Ids.Laboratory, center: MiraVent.Ids.Admin, right: MiraVent.Ids.Greenhouse),
new MiraVent(this, MiraVent.Ids.Admin, new Vector2(22.39f, 17.23f), left: MiraVent.Ids.Greenhouse, center: MiraVent.Ids.Cafeteria, right: MiraVent.Ids.Office),
new MiraVent(this, MiraVent.Ids.Greenhouse, new Vector2(17.85f, 25.23f), left: MiraVent.Ids.Admin, right: MiraVent.Ids.Office),
new MiraVent(this, MiraVent.Ids.Medbay, new Vector2(15.41f, -1.82f), left: MiraVent.Ids.Balcony, right: MiraVent.Ids.LockerRoom),
new MiraVent(this, MiraVent.Ids.Decontamination, new Vector2(6.83f, 3.145f), left: MiraVent.Ids.Reactor, center: MiraVent.Ids.LockerRoom, right: MiraVent.Ids.Laboratory),
new MiraVent(this, MiraVent.Ids.LockerRoom, new Vector2(4.29f, 0.5299997f), left: MiraVent.Ids.Medbay, center: MiraVent.Ids.Launchpad, right: MiraVent.Ids.Decontamination),
new MiraVent(this, MiraVent.Ids.Launchpad, new Vector2(-6.18f, 3.56f), left: MiraVent.Ids.Reactor, right: MiraVent.Ids.LockerRoom),
};
Vents = vents.ToDictionary(x => x.Id, x => x).AsReadOnly();
_vents = vents.ToDictionary(x => (int)x.Id, x => (IVent)x).AsReadOnly();
var tasks = new[]
{
new MiraTask(MiraTask.Ids.HallwayFixWiring, TaskTypes.FixWiring, TaskCategories.CommonTask),
new MiraTask(MiraTask.Ids.AdminEnterIDCode, TaskTypes.EnterIdCode, TaskCategories.CommonTask),
new MiraTask(MiraTask.Ids.MedbaySubmitScan, TaskTypes.SubmitScan, TaskCategories.LongTask, true),
new MiraTask(MiraTask.Ids.BalconyClearAsteroids, TaskTypes.ClearAsteroids, TaskCategories.LongTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToAdmin, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToCafeteria, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToCommunications, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToLaunchpad, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToMedbay, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToOffice, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.StorageWaterPlants, TaskTypes.WaterPlants, TaskCategories.LongTask),
new MiraTask(MiraTask.Ids.ReactorStartReactor, TaskTypes.StartReactor, TaskCategories.LongTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToGreenhouse, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.AdminChartCourse, TaskTypes.ChartCourse, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.GreenhouseCleanO2Filter, TaskTypes.Filter, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.LaunchpadFuelEngines, TaskTypes.FuelEngines, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.LaboratoryAssembleArtifact, TaskTypes.AssembleArtifact, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.LaboratorySortSamples, TaskTypes.SortSamples, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.AdminPrimeShields, TaskTypes.PrimeShields, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.CafeteriaEmptyGarbage, TaskTypes.EmptyGarbage, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.BalconyMeasureWeather, TaskTypes.MeasureWeather, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToLaboratory, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.CafeteriaBuyBeverage, TaskTypes.BuyBeverage, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.OfficeProcessData, TaskTypes.ProcessData, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.LaunchpadRunDiagnostics, TaskTypes.RunDiagnostics, TaskCategories.LongTask),
new MiraTask(MiraTask.Ids.ReactorUnlockManifolds, TaskTypes.UnlockManifolds, TaskCategories.ShortTask),
};
Tasks = tasks.ToDictionary(x => x.Id, x => x).AsReadOnly();
_tasks = tasks.ToDictionary(x => (int)x.Id, x => (ITask)x).AsReadOnly();
}
public IReadOnlyDictionary<MiraVent.Ids, MiraVent> Vents { get; }
IReadOnlyDictionary<int, IVent> IMapData.Vents => _vents;
public IReadOnlyDictionary<MiraTask.Ids, MiraTask> Tasks { get; }
IReadOnlyDictionary<int, ITask> IMapData.Tasks => _tasks;
}
}
@@ -0,0 +1,84 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Impostor.Api.Innersloth.Maps.Tasks;
using Impostor.Api.Innersloth.Maps.Vents;
namespace Impostor.Api.Innersloth.Maps
{
public class PolusData : IMapData
{
private readonly IReadOnlyDictionary<int, IVent> _vents;
private readonly IReadOnlyDictionary<int, ITask> _tasks;
internal PolusData()
{
var vents = new[]
{
new PolusVent(this, PolusVent.Ids.Security, new Vector2(1.929f, -9.558001f), left: PolusVent.Ids.O2, right: PolusVent.Ids.Electrical),
new PolusVent(this, PolusVent.Ids.Electrical, new Vector2(6.9f, -14.41f), left: PolusVent.Ids.O2, right: PolusVent.Ids.Security),
new PolusVent(this, PolusVent.Ids.O2, new Vector2(3.51f, -16.58f), left: PolusVent.Ids.Electrical, right: PolusVent.Ids.Security),
new PolusVent(this, PolusVent.Ids.Communications, new Vector2(12.304f, -18.898f), left: PolusVent.Ids.Storage, right: PolusVent.Ids.Office),
new PolusVent(this, PolusVent.Ids.Office, new Vector2(16.379f, -19.599f), left: PolusVent.Ids.Communications, right: PolusVent.Ids.Storage),
new PolusVent(this, PolusVent.Ids.Admin, new Vector2(20.089f, -25.517f), left: PolusVent.Ids.OutsideAdmin, right: PolusVent.Ids.Lava),
new PolusVent(this, PolusVent.Ids.Laboratory, new Vector2(32.963f, -9.526f), right: PolusVent.Ids.Lava),
new PolusVent(this, PolusVent.Ids.Lava, new Vector2(30.907f, -11.86f), left: PolusVent.Ids.Laboratory, right: PolusVent.Ids.Admin),
new PolusVent(this, PolusVent.Ids.Storage, new Vector2(22f, -12.19f), left: PolusVent.Ids.Communications, right: PolusVent.Ids.Office),
new PolusVent(this, PolusVent.Ids.RightStabilizer, new Vector2(24.02f, -8.39f), left: PolusVent.Ids.LeftStabilizer),
new PolusVent(this, PolusVent.Ids.LeftStabilizer, new Vector2(9.64f, -7.72f), left: PolusVent.Ids.RightStabilizer),
new PolusVent(this, PolusVent.Ids.OutsideAdmin, new Vector2(18.93f, -24.85f), right: PolusVent.Ids.Admin),
};
Vents = vents.ToDictionary(x => x.Id, x => x).AsReadOnly();
_vents = vents.ToDictionary(x => (int)x.Id, x => (IVent)x).AsReadOnly();
var tasks = new[]
{
new PolusTask(PolusTask.Ids.OfficeSwipeCard, TaskTypes.SwipeCard, TaskCategories.CommonTask),
new PolusTask(PolusTask.Ids.DropshipInsertKeys, TaskTypes.InsertKeys, TaskCategories.CommonTask),
new PolusTask(PolusTask.Ids.OfficeScanBoardingPass, TaskTypes.ScanBoardingPass, TaskCategories.CommonTask),
new PolusTask(PolusTask.Ids.ElectricalFixWiring, TaskTypes.FixWiring, TaskCategories.CommonTask),
new PolusTask(PolusTask.Ids.WeaponsDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.OfficeDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.ElectricalDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.SpecimenRoomDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.O2DownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.SpecimenRoomStartReactor, TaskTypes.StartReactor, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.StorageFuelEngines, TaskTypes.FuelEngines, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.BoilerRoomOpenWaterways, TaskTypes.OpenWaterways, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.MedbayInspectSample, TaskTypes.InspectSample, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.BoilerRoomReplaceWaterJug, TaskTypes.ReplaceWaterJug, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.OutsideFixWeatherNodeNode_GI, TaskTypes.ActivateWeatherNodes, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.OutsideFixWeatherNodeNode_IRO, TaskTypes.ActivateWeatherNodes, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.OutsideFixWeatherNodeNode_PD, TaskTypes.ActivateWeatherNodes, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.OutsideFixWeatherNodeNode_TB, TaskTypes.ActivateWeatherNodes, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.CommunicationsRebootWiFi, TaskTypes.RebootWifi, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.O2MonitorTree, TaskTypes.MonitorOxygen, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.SpecimenRoomUnlockManifolds, TaskTypes.UnlockManifolds, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.SpecimenRoomStoreArtifacts, TaskTypes.StoreArtifact, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.O2FillCanisters, TaskTypes.FillCanisters, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.O2EmptyGarbage, TaskTypes.EmptyGarbage, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.DropshipChartCourse, TaskTypes.ChartCourse, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.MedbaySubmitScan, TaskTypes.SubmitScan, TaskCategories.ShortTask, true),
new PolusTask(PolusTask.Ids.WeaponsClearAsteroids, TaskTypes.ClearAsteroids, TaskCategories.ShortTask, true),
new PolusTask(PolusTask.Ids.OutsideFixWeatherNodeNode_CA, TaskTypes.ActivateWeatherNodes, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.OutsideFixWeatherNodeNode_MLG, TaskTypes.ActivateWeatherNodes, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.LaboratoryAlignTelescope, TaskTypes.AlignTelescope, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.LaboratoryRepairDrill, TaskTypes.RepairDrill, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.LaboratoryRecordTemperature, TaskTypes.RecordTemperature, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.OutsideRecordTemperature, TaskTypes.RecordTemperature, TaskCategories.ShortTask),
};
Tasks = tasks.ToDictionary(x => x.Id, x => x).AsReadOnly();
_tasks = tasks.ToDictionary(x => (int)x.Id, x => (ITask)x).AsReadOnly();
}
public IReadOnlyDictionary<PolusVent.Ids, PolusVent> Vents { get; }
IReadOnlyDictionary<int, IVent> IMapData.Vents => _vents;
public IReadOnlyDictionary<PolusTask.Ids, PolusTask> Tasks { get; }
IReadOnlyDictionary<int, ITask> IMapData.Tasks => _tasks;
}
}
@@ -0,0 +1,82 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Impostor.Api.Innersloth.Maps.Tasks;
using Impostor.Api.Innersloth.Maps.Vents;
namespace Impostor.Api.Innersloth.Maps
{
public class SkeldData : IMapData
{
private readonly IReadOnlyDictionary<int, IVent> _vents;
private readonly IReadOnlyDictionary<int, ITask> _tasks;
internal SkeldData()
{
var vents = new[]
{
new SkeldVent(this, SkeldVent.Ids.Admin, new Vector2(2.544f, -9.955201f), left: SkeldVent.Ids.Cafeteria, right: SkeldVent.Ids.RightHallway),
new SkeldVent(this, SkeldVent.Ids.RightHallway, new Vector2(9.384f, -6.438f), left: SkeldVent.Ids.Admin, right: SkeldVent.Ids.Cafeteria),
new SkeldVent(this, SkeldVent.Ids.Cafeteria, new Vector2(4.2588f, -0.276f), left: SkeldVent.Ids.Admin, right: SkeldVent.Ids.RightHallway),
new SkeldVent(this, SkeldVent.Ids.Electrical, new Vector2(-9.7764f, -8.034f), left: SkeldVent.Ids.Security, right: SkeldVent.Ids.Medbay),
new SkeldVent(this, SkeldVent.Ids.UpperEngine, new Vector2(-15.288f, 2.52f), left: SkeldVent.Ids.UpperReactor),
new SkeldVent(this, SkeldVent.Ids.Security, new Vector2(-12.534f, -6.9492f), left: SkeldVent.Ids.Medbay, right: SkeldVent.Ids.Electrical),
new SkeldVent(this, SkeldVent.Ids.Medbay, new Vector2(-10.608f, -4.176f), left: SkeldVent.Ids.Security, right: SkeldVent.Ids.Electrical),
new SkeldVent(this, SkeldVent.Ids.Weapons, new Vector2(8.820001f, 3.324f), right: SkeldVent.Ids.UpperNavigation),
new SkeldVent(this, SkeldVent.Ids.LowerReactor, new Vector2(-20.796f, -6.9528f), left: SkeldVent.Ids.LowerEngine),
new SkeldVent(this, SkeldVent.Ids.LowerEngine, new Vector2(-15.2508f, -13.656f), left: SkeldVent.Ids.LowerReactor),
new SkeldVent(this, SkeldVent.Ids.Shields, new Vector2(9.5232f, -14.3376f), left: SkeldVent.Ids.LowerNavigation),
new SkeldVent(this, SkeldVent.Ids.UpperReactor, new Vector2(-21.876f, -3.0516f), left: SkeldVent.Ids.UpperEngine),
new SkeldVent(this, SkeldVent.Ids.UpperNavigation, new Vector2(16.008f, -3.168f), right: SkeldVent.Ids.Weapons),
new SkeldVent(this, SkeldVent.Ids.LowerNavigation, new Vector2(16.008f, -6.384f), right: SkeldVent.Ids.Shields),
};
Vents = vents.ToDictionary(x => x.Id, x => x).AsReadOnly();
_vents = vents.ToDictionary(x => (int)x.Id, x => (IVent)x).AsReadOnly();
var tasks = new[]
{
new SkeldTask(SkeldTask.Ids.AdminSwipeCard, TaskTypes.SwipeCard, TaskCategories.CommonTask),
new SkeldTask(SkeldTask.Ids.ElectricalFixWiring, TaskTypes.FixWiring, TaskCategories.CommonTask),
new SkeldTask(SkeldTask.Ids.WeaponsClearAsteroids, TaskTypes.ClearAsteroids, TaskCategories.LongTask, true),
new SkeldTask(SkeldTask.Ids.EnginesAlignEngineOutput, TaskTypes.AlignEngineOutput, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.MedbaySubmitScan, TaskTypes.SubmitScan, TaskCategories.LongTask, true),
new SkeldTask(SkeldTask.Ids.MedbayInspectSample, TaskTypes.InspectSample, TaskCategories.LongTask),
new SkeldTask(SkeldTask.Ids.StorageFuelEngines, TaskTypes.FuelEngines, TaskCategories.LongTask),
new SkeldTask(SkeldTask.Ids.ReactorStartReactor, TaskTypes.StartReactor, TaskCategories.LongTask),
new SkeldTask(SkeldTask.Ids.O2EmptyChute, TaskTypes.EmptyChute, TaskCategories.LongTask, true),
new SkeldTask(SkeldTask.Ids.CafeteriaEmptyGarbage, TaskTypes.EmptyGarbage, TaskCategories.LongTask, true),
new SkeldTask(SkeldTask.Ids.CommunicationsDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalCalibrateDistributor, TaskTypes.CalibrateDistributor, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.NavigationChartCourse, TaskTypes.ChartCourse, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.O2CleanO2Filter, TaskTypes.Filter, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ReactorUnlockManifolds, TaskTypes.UnlockManifolds, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.NavigationStabilizeSteering, TaskTypes.StabilizeSteering, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.WeaponsDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ShieldsPrimeShields, TaskTypes.PrimeShields, TaskCategories.ShortTask, true),
new SkeldTask(SkeldTask.Ids.CafeteriaDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.NavigationDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToShields, TaskTypes.DivertPower, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToWeapons, TaskTypes.DivertPower, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToCommunications, TaskTypes.DivertPower, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToUpperEngine, TaskTypes.DivertPower, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToO2, TaskTypes.DivertPower, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToNavigation, TaskTypes.DivertPower, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToLowerEngine, TaskTypes.DivertPower, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToSecurity, TaskTypes.DivertPower, TaskCategories.ShortTask),
};
Tasks = tasks.ToDictionary(x => x.Id, x => x).AsReadOnly();
_tasks = tasks.ToDictionary(x => (int)x.Id, x => (ITask)x).AsReadOnly();
}
public IReadOnlyDictionary<SkeldVent.Ids, SkeldVent> Vents { get; }
IReadOnlyDictionary<int, IVent> IMapData.Vents => _vents;
public IReadOnlyDictionary<SkeldTask.Ids, SkeldTask> Tasks { get; }
IReadOnlyDictionary<int, ITask> IMapData.Tasks => _tasks;
}
}
@@ -0,0 +1,70 @@
namespace Impostor.Api.Innersloth.Maps.Tasks
{
public class AirshipTask : ITask
{
internal AirshipTask(Ids id, TaskTypes type, TaskCategories category, bool isVisual = false)
{
Id = id;
Name = id.ToString();
Type = type;
Category = category;
IsVisual = isVisual;
}
public enum Ids
{
ElectricalFixWiring = 0,
MeetingRoomEnterIDCode = 1,
ElectricalResetBreakers = 2,
VaultRoomDownloadData = 3,
BrigDownloadData = 4,
CargoBayDownloadData = 5,
GapRoomDownloadData = 6,
RecordsDownloadData = 7,
CargoBayUnlockSafe = 8,
VentilationStartFans = 9,
MainHallEmptyGarbage = 10,
MedicalEmptyGarbage = 11,
KitchenEmptyGarbage = 12,
MainHallDevelopPhotos = 13,
CargoBayFuelEngines = 14,
SecurityRewindTapes = 15,
VaultRoomPolishRuby = 16,
ElectricalCalibrateDistributor = 17,
CockpitStabilizeSteering = 18,
ArmoryDownloadData = 19,
CockpitDownloadData = 20,
CommsDownloadData = 21,
MedicalDownloadData = 22,
ViewingDeckDownloadData = 23,
ElectricalDivertPowerToArmory = 24,
ElectricalDivertPowerToCockpit = 25,
ElectricalDivertPowerToGapRoom = 26,
ElectricalDivertPowerToMainHall = 27,
ElectricalDivertPowerToMeetingRoom = 28,
ElectricalDivertPowerToShowers = 29,
ElectricalDivertPowerToEngine = 30,
ShowersPickUpTowels = 31,
LoungeCleanToilet = 32,
VaultRoomDressMannequin = 33,
RecordsSortRecords = 34,
ArmoryPutAwayPistols = 35,
ArmoryPutAwayRifles = 36,
MainHallDecontaminate = 37,
KitchenMakeBurger = 38,
ShowersFixShower = 39,
}
public Ids Id { get; }
int ITask.Id => (int)Id;
public string Name { get; }
public TaskTypes Type { get; }
public TaskCategories Category { get; }
public bool IsVisual { get; }
}
}
@@ -0,0 +1,56 @@
namespace Impostor.Api.Innersloth.Maps.Tasks
{
public class MiraTask : ITask
{
internal MiraTask(Ids id, TaskTypes type, TaskCategories category, bool isVisual = false)
{
Id = id;
Name = id.ToString();
Type = type;
Category = category;
IsVisual = isVisual;
}
public enum Ids
{
HallwayFixWiring = 0,
AdminEnterIDCode = 1,
MedbaySubmitScan = 2,
BalconyClearAsteroids = 3,
ElectricalDivertPowerToAdmin = 4,
ElectricalDivertPowerToCafeteria = 5,
ElectricalDivertPowerToCommunications = 6,
ElectricalDivertPowerToLaunchpad = 7,
ElectricalDivertPowerToMedbay = 8,
ElectricalDivertPowerToOffice = 9,
StorageWaterPlants = 10,
ReactorStartReactor = 11,
ElectricalDivertPowerToGreenhouse = 12,
AdminChartCourse = 13,
GreenhouseCleanO2Filter = 14,
LaunchpadFuelEngines = 15,
LaboratoryAssembleArtifact = 16,
LaboratorySortSamples = 17,
AdminPrimeShields = 18,
CafeteriaEmptyGarbage = 19,
BalconyMeasureWeather = 20,
ElectricalDivertPowerToLaboratory = 21,
CafeteriaBuyBeverage = 22,
OfficeProcessData = 23,
LaunchpadRunDiagnostics = 24,
ReactorUnlockManifolds = 25,
}
public Ids Id { get; }
int ITask.Id => (int)Id;
public string Name { get; }
public TaskTypes Type { get; }
public TaskCategories Category { get; }
public bool IsVisual { get; }
}
}
@@ -0,0 +1,63 @@
namespace Impostor.Api.Innersloth.Maps.Tasks
{
public class PolusTask : ITask
{
internal PolusTask(Ids id, TaskTypes type, TaskCategories category, bool isVisual = false)
{
Id = id;
Name = id.ToString();
Type = type;
Category = category;
IsVisual = isVisual;
}
public enum Ids
{
OfficeSwipeCard = 0,
DropshipInsertKeys = 1,
OfficeScanBoardingPass = 2,
ElectricalFixWiring = 3,
WeaponsDownloadData = 4,
OfficeDownloadData = 5,
ElectricalDownloadData = 6,
SpecimenRoomDownloadData = 7,
O2DownloadData = 8,
SpecimenRoomStartReactor = 9,
StorageFuelEngines = 10,
BoilerRoomOpenWaterways = 11,
MedbayInspectSample = 12,
BoilerRoomReplaceWaterJug = 13,
OutsideFixWeatherNodeNode_GI = 14,
OutsideFixWeatherNodeNode_IRO = 15,
OutsideFixWeatherNodeNode_PD = 16,
OutsideFixWeatherNodeNode_TB = 17,
CommunicationsRebootWiFi = 18,
O2MonitorTree = 19,
SpecimenRoomUnlockManifolds = 20,
SpecimenRoomStoreArtifacts = 21,
O2FillCanisters = 22,
O2EmptyGarbage = 23,
DropshipChartCourse = 24,
MedbaySubmitScan = 25,
WeaponsClearAsteroids = 26,
OutsideFixWeatherNodeNode_CA = 27,
OutsideFixWeatherNodeNode_MLG = 28,
LaboratoryAlignTelescope = 29,
LaboratoryRepairDrill = 30,
LaboratoryRecordTemperature = 31,
OutsideRecordTemperature = 32,
}
public Ids Id { get; }
int ITask.Id => (int)Id;
public string Name { get; }
public TaskTypes Type { get; }
public TaskCategories Category { get; }
public bool IsVisual { get; }
}
}
@@ -0,0 +1,59 @@
namespace Impostor.Api.Innersloth.Maps.Tasks
{
public class SkeldTask : ITask
{
internal SkeldTask(Ids id, TaskTypes type, TaskCategories category, bool isVisual = false)
{
Id = id;
Name = id.ToString();
Type = type;
Category = category;
IsVisual = isVisual;
}
public enum Ids
{
AdminSwipeCard = 0,
ElectricalFixWiring = 1,
WeaponsClearAsteroids = 2,
EnginesAlignEngineOutput = 3,
MedbaySubmitScan = 4,
MedbayInspectSample = 5,
StorageFuelEngines = 6,
ReactorStartReactor = 7,
O2EmptyChute = 8,
CafeteriaEmptyGarbage = 9,
CommunicationsDownloadData = 10,
ElectricalCalibrateDistributor = 11,
NavigationChartCourse = 12,
O2CleanO2Filter = 13,
ReactorUnlockManifolds = 14,
ElectricalDownloadData = 15,
NavigationStabilizeSteering = 16,
WeaponsDownloadData = 17,
ShieldsPrimeShields = 18,
CafeteriaDownloadData = 19,
NavigationDownloadData = 20,
ElectricalDivertPowerToShields = 21,
ElectricalDivertPowerToWeapons = 22,
ElectricalDivertPowerToCommunications = 23,
ElectricalDivertPowerToUpperEngine = 24,
ElectricalDivertPowerToO2 = 25,
ElectricalDivertPowerToNavigation = 26,
ElectricalDivertPowerToLowerEngine = 27,
ElectricalDivertPowerToSecurity = 28,
}
public Ids Id { get; }
int ITask.Id => (int)Id;
public string Name { get; }
public TaskTypes Type { get; }
public TaskCategories Category { get; }
public bool IsVisual { get; }
}
}
@@ -0,0 +1,61 @@
using System;
using System.Numerics;
namespace Impostor.Api.Innersloth.Maps.Vents
{
public class AirshipVent : IVent
{
private readonly Lazy<AirshipVent>? _left;
private readonly Lazy<AirshipVent>? _center;
private readonly Lazy<AirshipVent>? _right;
internal AirshipVent(AirshipData data, Ids id, Vector2 position, Ids? left = null, Ids? center = null, Ids? right = null)
{
Id = id;
Name = id.ToString();
Position = position;
_left = left == null ? null : new Lazy<AirshipVent>(() => data.Vents[left.Value]);
_center = center == null ? null : new Lazy<AirshipVent>(() => data.Vents[center.Value]);
_right = right == null ? null : new Lazy<AirshipVent>(() => data.Vents[right.Value]);
}
public enum Ids
{
Vault = 0,
Cockpit = 1,
ViewingDeck = 2,
EngineRoom = 3,
Kitchen = 4,
MainHallBottom = 5,
GapRight = 6,
GapLeft = 7,
MainHallTop = 8,
Showers = 9,
Records = 10,
CargoBay = 11,
}
public Ids Id { get; }
int IVent.Id => (int)Id;
public string Name { get; }
public Vector2 Position { get; }
public AirshipVent? Left => _left?.Value;
IVent? IVent.Left => Left;
public AirshipVent? Center => _center?.Value;
IVent? IVent.Center => Center;
public AirshipVent? Right => _right?.Value;
IVent? IVent.Right => Right;
}
}
@@ -0,0 +1,60 @@
using System;
using System.Numerics;
namespace Impostor.Api.Innersloth.Maps.Vents
{
public class MiraVent : IVent
{
private readonly Lazy<MiraVent>? _left;
private readonly Lazy<MiraVent>? _center;
private readonly Lazy<MiraVent>? _right;
internal MiraVent(MiraData data, Ids id, Vector2 position, Ids? left = null, Ids? center = null, Ids? right = null)
{
Id = id;
Name = id.ToString();
Position = position;
_left = left == null ? null : new Lazy<MiraVent>(() => data.Vents[left.Value]);
_center = center == null ? null : new Lazy<MiraVent>(() => data.Vents[center.Value]);
_right = right == null ? null : new Lazy<MiraVent>(() => data.Vents[right.Value]);
}
public enum Ids
{
Balcony = 1,
Cafeteria = 2,
Reactor = 3,
Laboratory = 4,
Office = 5,
Admin = 6,
Greenhouse = 7,
Medbay = 8,
Decontamination = 9,
LockerRoom = 10,
Launchpad = 11,
}
public Ids Id { get; }
int IVent.Id => (int)Id;
public string Name { get; }
public Vector2 Position { get; }
public MiraVent? Left => _left?.Value;
IVent? IVent.Left => Left;
public MiraVent? Center => _center?.Value;
IVent? IVent.Center => Center;
public MiraVent? Right => _right?.Value;
IVent? IVent.Right => Right;
}
}
@@ -0,0 +1,61 @@
using System;
using System.Numerics;
namespace Impostor.Api.Innersloth.Maps.Vents
{
public class PolusVent : IVent
{
private readonly Lazy<PolusVent>? _left;
private readonly Lazy<PolusVent>? _center;
private readonly Lazy<PolusVent>? _right;
internal PolusVent(PolusData data, Ids id, Vector2 position, Ids? left = null, Ids? center = null, Ids? right = null)
{
Id = id;
Name = id.ToString();
Position = position;
_left = left == null ? null : new Lazy<PolusVent>(() => data.Vents[left.Value]);
_center = center == null ? null : new Lazy<PolusVent>(() => data.Vents[center.Value]);
_right = right == null ? null : new Lazy<PolusVent>(() => data.Vents[right.Value]);
}
public enum Ids
{
Security = 0,
Electrical = 1,
O2 = 2,
Communications = 3,
Office = 4,
Admin = 5,
Laboratory = 6,
Lava = 7,
Storage = 8,
RightStabilizer = 9,
LeftStabilizer = 10,
OutsideAdmin = 11,
}
public Ids Id { get; }
int IVent.Id => (int)Id;
public string Name { get; }
public Vector2 Position { get; }
public PolusVent? Left => _left?.Value;
IVent? IVent.Left => Left;
public PolusVent? Center => _center?.Value;
IVent? IVent.Center => Center;
public PolusVent? Right => _right?.Value;
IVent? IVent.Right => Right;
}
}
@@ -0,0 +1,63 @@
using System;
using System.Numerics;
namespace Impostor.Api.Innersloth.Maps.Vents
{
public class SkeldVent : IVent
{
private readonly Lazy<SkeldVent>? _left;
private readonly Lazy<SkeldVent>? _center;
private readonly Lazy<SkeldVent>? _right;
internal SkeldVent(SkeldData data, Ids id, Vector2 position, Ids? left = null, Ids? center = null, Ids? right = null)
{
Id = id;
Name = id.ToString();
Position = position;
_left = left == null ? null : new Lazy<SkeldVent>(() => data.Vents[left.Value]);
_center = center == null ? null : new Lazy<SkeldVent>(() => data.Vents[center.Value]);
_right = right == null ? null : new Lazy<SkeldVent>(() => data.Vents[right.Value]);
}
public enum Ids
{
Admin = 0,
RightHallway = 1,
Cafeteria = 2,
Electrical = 3,
UpperEngine = 4,
Security = 5,
Medbay = 6,
Weapons = 7,
LowerReactor = 8,
LowerEngine = 9,
Shields = 10,
UpperReactor = 11,
UpperNavigation = 12,
LowerNavigation = 13,
}
public Ids Id { get; }
int IVent.Id => (int)Id;
public string Name { get; }
public Vector2 Position { get; }
public SkeldVent? Left => _left?.Value;
IVent? IVent.Left => Left;
public SkeldVent? Center => _center?.Value;
IVent? IVent.Center => Center;
public SkeldVent? Right => _right?.Value;
IVent? IVent.Right => Right;
}
}
+15
View File
@@ -0,0 +1,15 @@
namespace Impostor.Api.Innersloth
{
public enum Platforms
{
Unknown = 0,
StandaloneEpicPC = 1,
StandaloneSteamPC = 2,
StandaloneMac = 3,
StandaloneWin10 = 4,
StandaloneItch = 5,
IPhone = 6,
Android = 7,
Switch = 8,
}
}
@@ -1,6 +1,6 @@
namespace Impostor.Api.Innersloth
{
public enum ChatType
public enum QuickChatModes
{
FreeChatOrQuickChat = 1,
QuickChatOnly = 2,
@@ -67,5 +67,39 @@
Specimens = 28,
BoilerRoom = 29,
VaultRoom = 30,
Cockpit = 31,
Armory = 32,
Kitchen = 33,
ViewingDeck = 34,
HallOfPortraits = 35,
CargoBay = 36,
Ventilation = 37,
Showers = 38,
Engine = 39,
Brig = 40,
MeetingRoom = 41,
Records = 42,
Lounge = 43,
GapRoom = 44,
MainHall = 45,
Medical = 46,
}
}
@@ -0,0 +1,9 @@
namespace Impostor.Api.Innersloth
{
public enum TaskCategories : byte
{
CommonTask,
LongTask,
ShortTask,
}
}
+18 -1
View File
@@ -1,4 +1,4 @@
namespace Impostor.Api.Innersloth
namespace Impostor.Api.Innersloth
{
public enum TaskTypes : uint
{
@@ -45,5 +45,22 @@
AlignTelescope = 40,
RecordTemperature = 41,
RebootWifi = 42,
PolishRuby = 43,
ResetBreakers = 44,
Decontaminate = 45,
MakeBurger = 46,
UnlockSafe = 47,
SortRecords = 48,
PutAwayPistols = 49,
FixShower = 50,
CleanToilet = 51,
DressMannequin = 52,
PickUpTowels = 53,
RewindTapes = 54,
StartFans = 55,
DevelopPhotos = 56,
GetBiggolSword = 57,
PutAwayRifles = 58,
StopCharles = 59,
}
}
@@ -1,48 +0,0 @@
namespace Impostor.Api.Innersloth
{
public enum VentLocation : uint
{
// Skeld
SkeldAdmin = 0,
SkeldRightHallway = 1,
SkeldCafeteria = 2,
SkeldElectrical = 3,
SkeldUpperEngine = 4,
SkeldSecurity = 5,
SkeldMedbay = 6,
SkeldWeapons = 7,
SkeldLowerReactor = 8,
SkeldLowerEngine = 9,
SkeldShields = 10,
SkeldUpperReactor = 11,
SkeldUpperNavigation = 12,
SkeldLowerNavigation = 13,
// Mira HQ
MiraBalcony = 1,
MiraCafeteria = 2,
MiraReactor = 3,
MiraLaboratory = 4,
MiraOffice = 5,
MiraAdmin = 6,
MiraGreenhouse = 7,
MiraMedbay = 8,
MiraDecontamination = 9,
MiraLockerRoom = 10,
MiraLaunchpad = 11,
// Polus
PolusSecurity = 0,
PolusElectrical = 1,
PolusO2 = 2,
PolusCommunications = 3,
PolusOffice = 4,
PolusAdmin = 5,
PolusLaboratory = 6,
PolusLava = 7,
PolusStorage = 8,
PolusRightStabilizer = 9,
PolusLeftStabilizer = 10,
PolusOutsideAdmin = 11,
}
}
@@ -0,0 +1,7 @@
namespace Impostor.Api.Net.Custom
{
public interface ICustomMessage
{
byte Id { get; }
}
}
@@ -0,0 +1,18 @@
using System;
using System.Diagnostics.CodeAnalysis;
namespace Impostor.Api.Net.Custom
{
public interface ICustomMessageManager<T>
where T : ICustomMessage
{
bool TryGet(byte id, [MaybeNullWhen(false)] out T message);
/// <summary>
/// Register a custom message.
/// </summary>
/// <param name="message"><typeparamref name="T"/> message.</param>
/// <returns>Disposable that unregisters the message.</returns>
IDisposable Register(T message);
}
}
@@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Net.Custom
{
public interface ICustomRootMessage : ICustomMessage
{
ValueTask HandleMessageAsync(IClient client, IMessageReader reader, MessageType messageType);
}
}
+11
View File
@@ -0,0 +1,11 @@
using System.Threading.Tasks;
using Impostor.Api.Net.Inner;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Net.Custom
{
public interface ICustomRpc : ICustomMessage
{
ValueTask<bool> HandleRpcAsync(IInnerNetObject innerNetObject, IClientPlayer sender, IClientPlayer? target, IMessageReader reader);
}
}
-6
View File
@@ -2,7 +2,6 @@
using System.Threading.Tasks;
using Impostor.Api.Innersloth;
using Impostor.Api.Net.Messages;
using Impostor.Api.Reactor;
namespace Impostor.Api.Net
{
@@ -28,11 +27,6 @@ namespace Impostor.Api.Net
/// </remarks>
string Name { get; }
/// <summary>
/// Gets mods sent by client in modded handshake.
/// </summary>
ISet<Mod> Mods { get; }
/// <summary>
/// Gets the connection of the client.
/// </summary>
+7 -1
View File
@@ -24,6 +24,11 @@ namespace Impostor.Api.Net
/// </summary>
IClient? Client { get; set; }
/// <summary>
/// Gets the average ping of the client.
/// </summary>
float AveragePing { get; }
/// <summary>
/// Sends a message writer to the connection.
/// </summary>
@@ -35,7 +40,8 @@ namespace Impostor.Api.Net
/// Disconnects the client and invokes the disconnect handler.
/// </summary>
/// <param name="reason">A reason.</param>
/// <param name="writer">A message to send with disconnect packet.</param>
/// <returns>Task that must be awaited.</returns>
ValueTask DisconnectAsync(string? reason);
ValueTask DisconnectAsync(string? reason, IMessageWriter? writer = null);
}
}
+1
View File
@@ -1,4 +1,5 @@
using Impostor.Api.Net.Inner.Objects;
using Impostor.Api.Net.Inner.Objects.ShipStatus;
namespace Impostor.Api.Net.Inner
{
@@ -1,9 +1,13 @@
namespace Impostor.Api.Net.Inner
using Impostor.Api.Games;
namespace Impostor.Api.Net.Inner
{
public interface IInnerNetObject
{
public uint NetId { get; }
public int OwnerId { get; }
public IGame Game { get; }
}
}
@@ -1,6 +1,59 @@
namespace Impostor.Api.Net.Inner.Objects
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Impostor.Api.Events.Player;
namespace Impostor.Api.Net.Inner.Objects
{
public interface IInnerMeetingHud : IInnerNetObject
{
public interface IPlayerVoteArea
{
/// <summary>
/// Gets the player info of this vote state.
/// </summary>
IInnerPlayerInfo TargetPlayer { get; }
/// <summary>
/// Gets a value indicating whether the player is a dead.
/// </summary>
bool IsDead { get; }
/// <summary>
/// Gets a value indicating whether the player started this meeting.
/// </summary>
bool DidReport { get; }
/// <summary>
/// Gets a value indicating whether the player voted.
/// </summary>
bool DidVote { get; }
/// <summary>
/// Gets the vote type.
/// </summary>
/// <remarks>
/// Null when <see cref="DidVote" /> is false.
/// </remarks>
[MemberNotNullWhen(true, nameof(DidVote))]
public VoteType? VoteType { get; }
/// <summary>
/// Gets the player voted for.
/// </summary>
/// <remarks>
/// Null when <see cref="VoteType" /> isn't <see cref="F:Impostor.Api.Events.Player.VoteType.Player"/>.
/// </remarks>
public IInnerPlayerControl? VotedFor { get; }
}
/// <summary>
/// Gets states of players taking part in this meeting.
/// </summary>
IReadOnlyCollection<IPlayerVoteArea> PlayerStates { get; }
/// <summary>
/// Gets the player that started the meeting.
/// </summary>
IInnerPlayerInfo? Reporter { get; }
}
}
@@ -1,4 +1,5 @@
using Impostor.Api.Innersloth;
using System.Threading.Tasks;
using Impostor.Api.Innersloth;
namespace Impostor.Api.Net.Inner.Objects
{
@@ -6,8 +7,14 @@ namespace Impostor.Api.Net.Inner.Objects
{
uint Id { get; }
TaskTypes Type { get; }
ITask Task { get; }
bool Complete { get; }
/// <summary>
/// Sets the task as complete.
/// </summary>
/// <returns>Task that must be awaited.</returns>
ValueTask CompleteAsync();
}
}
@@ -0,0 +1,6 @@
namespace Impostor.Api.Net.Inner.Objects.ShipStatus
{
public interface IInnerAirshipStatus : IInnerShipStatus
{
}
}
@@ -0,0 +1,6 @@
namespace Impostor.Api.Net.Inner.Objects.ShipStatus
{
public interface IInnerMiraShipStatus : IInnerShipStatus
{
}
}
@@ -0,0 +1,6 @@
namespace Impostor.Api.Net.Inner.Objects.ShipStatus
{
public interface IInnerPolusShipStatus : IInnerShipStatus
{
}
}
@@ -1,4 +1,4 @@
namespace Impostor.Api.Net.Inner.Objects
namespace Impostor.Api.Net.Inner.Objects.ShipStatus
{
public interface IInnerShipStatus : IInnerNetObject
{
@@ -0,0 +1,6 @@
namespace Impostor.Api.Net.Inner.Objects.ShipStatus
{
public interface IInnerSkeldShipStatus : IInnerShipStatus
{
}
}
+3 -3
View File
@@ -1,4 +1,4 @@
namespace Impostor.Server.Net.Inner
namespace Impostor.Api.Net.Inner
{
public enum RpcCalls : byte
{
@@ -32,7 +32,7 @@
CloseDoorsOfType = 27,
RepairSystem = 28,
SetTasks = 29,
UpdateGameData = 30,
CustomRpc = byte.MaxValue,
ClimbLadder = 31,
UsePlatform = 32,
}
}
@@ -0,0 +1,15 @@
namespace Impostor.Api.Net.Messages.Auth
{
public static class Message01Complete
{
public static void Serialize(IMessageWriter writer, uint nonce)
{
writer.WritePacked(nonce);
}
public static void Deserialize(IMessageReader reader, out uint nonce)
{
nonce = reader.ReadUInt32();
}
}
}
@@ -0,0 +1,14 @@
using Impostor.Api.Innersloth;
namespace Impostor.Api.Net.Messages.Auth
{
public static class MessageHandshake
{
public static void Deserialize(IMessageReader reader, out int clientVersion, out Platforms platform, out string clientId)
{
clientVersion = reader.ReadInt32();
platform = (Platforms)reader.ReadByte();
clientId = reader.ReadString();
}
}
}
@@ -0,0 +1,12 @@
namespace Impostor.Api.Net.Messages.C2S
{
public static class HandshakeC2S
{
public static void Deserialize(IMessageReader reader, out int clientVersion, out string name, out uint lastNonceReceived)
{
clientVersion = reader.ReadInt32();
name = reader.ReadString();
lastNonceReceived = reader.ReadUInt32();
}
}
}
@@ -15,12 +15,12 @@ namespace Impostor.Api.Net.Messages.C2S
/// Deserialize a packet.
/// </summary>
/// <param name="reader"><see cref="IMessageReader" /> with <see cref="IMessageReader.Tag" /> 0.</param>
/// <param name="chatType">The chat type selected in the client of the player.</param>
/// <param name="chatMode">The chat type selected in the client of the player.</param>
/// <returns>Deserialized <see cref="GameOptionsData" />.</returns>
public static GameOptionsData Deserialize(IMessageReader reader, out ChatType chatType)
public static GameOptionsData Deserialize(IMessageReader reader, out QuickChatModes chatMode)
{
var gameOptionsData = GameOptionsData.DeserializeCreate(reader);
chatType = (ChatType)reader.ReadByte();
chatMode = (QuickChatModes)reader.ReadByte();
return gameOptionsData;
}
@@ -10,11 +10,11 @@ namespace Impostor.Api.Net.Messages.C2S
throw new NotImplementedException();
}
public static void Deserialize(IMessageReader reader, out GameOptionsData options, out ChatType chatType)
public static void Deserialize(IMessageReader reader, out GameOptionsData options, out QuickChatModes chatMode)
{
reader.ReadPackedInt32(); // Hardcoded 0.
options = GameOptionsData.DeserializeCreate(reader);
chatType = (ChatType)reader.ReadByte();
chatMode = (QuickChatModes)reader.ReadByte();
}
}
}
@@ -19,6 +19,13 @@ namespace Impostor.Api.Net.Messages
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>
@@ -0,0 +1,17 @@
namespace Impostor.Api.Net.Messages.Rpcs
{
public static class Rpc31ClimbLadder
{
public static void Serialize(IMessageWriter writer, byte ladderId, byte lastClimbLadderSid)
{
writer.Write(ladderId);
writer.Write(lastClimbLadderSid);
}
public static void Deserialize(IMessageReader reader, out byte ladderId, out byte lastClimbLadderSid)
{
ladderId = reader.ReadByte();
lastClimbLadderSid = reader.ReadByte();
}
}
}
@@ -0,0 +1,13 @@
namespace Impostor.Api.Net.Messages.Rpcs
{
public static class Rpc32UsePlatform
{
public static void Serialize(IMessageWriter writer)
{
}
public static void Deserialize(IMessageReader reader)
{
}
}
}
@@ -0,0 +1,53 @@
using System;
using Impostor.Api.Innersloth;
namespace Impostor.Api.Net.Messages.S2C
{
public class MessageDisconnect
{
public static void Serialize(IMessageWriter writer, bool hasReason, DisconnectReason? reason, string? message)
{
writer.Write(hasReason);
if (hasReason)
{
if (reason == null)
{
throw new ArgumentNullException(nameof(reason));
}
writer.StartMessage(0);
writer.Write((byte)reason);
if (reason == DisconnectReason.Custom)
{
if (message == null)
{
throw new ArgumentNullException(nameof(message));
}
writer.Write(message);
}
writer.EndMessage();
}
}
public static void Deserialize(IMessageReader reader, out bool hasReason, out DisconnectReason? reason, out string? message)
{
hasReason = reader.ReadBoolean();
if (hasReason)
{
var inner = reader.ReadMessage();
reason = (DisconnectReason)inner.ReadByte();
message = reason == DisconnectReason.Custom ? inner.ReadString() : null;
}
else
{
reason = null;
message = null;
}
}
}
}
@@ -0,0 +1,9 @@
namespace Impostor.Api.Plugins
{
public enum DependencyType
{
HardDependency,
SoftDependency,
LoadBefore,
}
}
@@ -0,0 +1,42 @@
using System;
namespace Impostor.Api.Plugins
{
public interface IPluginInformation
{
/// <summary>
/// Gets the unique id of this plugin.
/// </summary>
string Id { get; }
/// <summary>
/// Gets the human readable name of this plugin.
/// </summary>
string Name { get; }
/// <summary>
/// Gets the author of this plugin.
/// </summary>
string Author { get; }
/// <summary>
/// Gets the version of this plugin.
/// </summary>
string Version { get; }
/// <summary>
/// Gets the optional startup object of this plugin.
/// </summary>
IPluginStartup? Startup { get; }
/// <summary>
/// Gets the instance of this plugin.
/// </summary>
IPlugin? Instance { get; }
/// <summary>
/// Gets the instance type of this plugin.
/// </summary>
Type PluginType { get; }
}
}
@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Impostor.Api.Plugins
{
public interface IPluginManager
{
IReadOnlyList<IPluginInformation> Plugins { get; }
}
}
@@ -0,0 +1,18 @@
using System;
namespace Impostor.Api.Plugins
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ImpostorDependencyAttribute : Attribute
{
public ImpostorDependencyAttribute(string id, DependencyType type)
{
Id = id;
DependencyType = type;
}
public string Id { get; }
public DependencyType DependencyType { get; }
}
}
@@ -5,20 +5,26 @@ namespace Impostor.Api.Plugins
[AttributeUsage(AttributeTargets.Class)]
public class ImpostorPluginAttribute : Attribute
{
public ImpostorPluginAttribute(string package, string name, string author, string version)
public ImpostorPluginAttribute(string id)
{
Package = package;
Id = id;
}
[Obsolete("Use (string id) constructor to avoid redundancy")]
public ImpostorPluginAttribute(string id, string name, string author, string version)
{
Id = id;
Name = name;
Author = author;
Version = version;
}
public string Package { get; }
public string Id { get; }
public string Name { get; }
public string? Name { get; }
public string Author { get; }
public string? Author { get; }
public string Version { get; }
public string? Version { get; }
}
}
-21
View File
@@ -1,21 +0,0 @@
namespace Impostor.Api.Reactor
{
public readonly struct Mod
{
public readonly string Id;
public readonly string Version;
public readonly PluginSide Side;
public Mod(string id, string version, PluginSide side)
{
Id = id;
Version = version;
Side = side;
}
public override string ToString()
{
return $"{Id} ({Version})";
}
}
}
-24
View File
@@ -1,24 +0,0 @@
using System.Collections.Generic;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Reactor
{
public static class ModList
{
public static void Deserialize(IMessageReader reader, out ISet<Mod> mods)
{
var length = reader.ReadPackedInt32();
mods = new HashSet<Mod>(length);
for (var i = 0; i < length; i++)
{
var id = reader.ReadString();
var version = reader.ReadString();
var pluginSide = (PluginSide)reader.ReadByte();
mods.Add(new Mod(id, version, pluginSide));
}
}
}
}
@@ -1,23 +0,0 @@
using System.Collections.Generic;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Reactor
{
public static class ModdedHandshakeC2S
{
public static void Deserialize(IMessageReader reader, out int clientVersion, out string name, out ISet<Mod>? mods)
{
clientVersion = reader.ReadInt32();
name = reader.ReadString();
if (reader.Length > reader.Position)
{
ModList.Deserialize(reader, out mods);
}
else
{
mods = null;
}
}
}
}
@@ -1,14 +0,0 @@
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Reactor
{
public static class ModdedHandshakeS2C
{
public static void Serialize(IMessageWriter writer, string serverBrand)
{
writer.StartMessage(byte.MaxValue);
writer.Write(serverBrand);
writer.EndMessage();
}
}
}
-23
View File
@@ -1,23 +0,0 @@
namespace Impostor.Api.Reactor
{
/// <summary>
/// Plugin side used in modded handshake.
/// </summary>
public enum PluginSide : byte
{
/// <summary>
/// Required by both sides, reject connection if missing on the other side
/// </summary>
Both,
/// <summary>
/// Required only by client
/// </summary>
ClientOnly,
/// <summary>
/// Required only by server
/// </summary>
ServerOnly,
}
}
@@ -1,6 +1,6 @@
using System;
namespace Impostor.Api
namespace Impostor.Api.Utils
{
public interface IDateTimeProvider
{
@@ -0,0 +1,7 @@
namespace Impostor.Api.Utils
{
public interface IServerEnvironment
{
string Version { get; }
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
<ItemGroup>
<ProjectReference Include="..\Impostor.Api\Impostor.Api.csproj" />
<ProjectReference Include="..\Impostor.Hazel\Impostor.Hazel.csproj" />
<ProjectReference Include="..\Impostor.Hazel\Hazel\Hazel.csproj" />
</ItemGroup>
</Project>
Submodule src/Impostor.Hazel added at 8de027461e.
-249
View File
@@ -1,249 +0,0 @@
using System;
using System.Net;
using System.Threading.Tasks;
using Impostor.Api.Net.Messages;
using Serilog;
namespace Impostor.Hazel
{
/// <summary>
/// Base class for all connections.
/// </summary>
/// <remarks>
/// <para>
/// Connection is the base class for all connections that Hazel can make. It provides common functionality and a
/// standard interface to allow connections to be swapped easily.
/// </para>
/// <para>
/// Any class inheriting from Connection should provide the 3 standard guarantees that Hazel provides:
/// <list type="bullet">
/// <item>
/// <description>Thread Safe</description>
/// </item>
/// <item>
/// <description>Connection Orientated</description>
/// </item>
/// <item>
/// <description>Packet/Message Based</description>
/// </item>
/// </list>
/// </para>
/// </remarks>
/// <threadsafety static="true" instance="true"/>
public abstract class Connection : IDisposable
{
private static readonly ILogger Logger = Log.ForContext<Connection>();
/// <summary>
/// Called when a message has been received.
/// </summary>
/// <remarks>
/// <para>
/// DataReceived is invoked everytime a message is received from the end point of this connection, the message
/// that was received can be found in the <see cref="DataReceivedEventArgs"/> alongside other information from the
/// event.
/// </para>
/// <include file="DocInclude/common.xml" path="docs/item[@name='Event_Thread_Safety_Warning']/*" />
/// </remarks>
/// <example>
/// <code language="C#" source="DocInclude/TcpClientExample.cs"/>
/// </example>
public Func<DataReceivedEventArgs, ValueTask> DataReceived;
public int TestLagMs = -1;
public int TestDropRate = 0;
protected int testDropCount = 0;
/// <summary>
/// Called when the end point disconnects or an error occurs.
/// </summary>
/// <remarks>
/// <para>
/// Disconnected is invoked when the connection is closed due to an exception occuring or because the remote
/// end point disconnected. If it was invoked due to an exception occuring then the exception is available
/// in the <see cref="DisconnectedEventArgs"/> passed with the event.
/// </para>
/// <include file="DocInclude/common.xml" path="docs/item[@name='Event_Thread_Safety_Warning']/*" />
/// </remarks>
/// <example>
/// <code language="C#" source="DocInclude/TcpClientExample.cs"/>
/// </example>
public Func<DisconnectedEventArgs, ValueTask> Disconnected;
/// <summary>
/// The remote end point of this Connection.
/// </summary>
/// <remarks>
/// This is the end point that this connection is connected to (i.e. the other device). This returns an abstract
/// <see cref="ConnectionEndPoint"/> which can then be cast to an appropriate end point depending on the
/// connection type.
/// </remarks>
public IPEndPoint EndPoint { get; protected set; }
public IPMode IPMode { get; protected set; }
/// <summary>
/// The traffic statistics about this Connection.
/// </summary>
/// <remarks>
/// Contains statistics about the number of messages and bytes sent and received by this connection.
/// </remarks>
public ConnectionStatistics Statistics { get; protected set; }
/// <summary>
/// The state of this connection.
/// </summary>
/// <remarks>
/// All implementers should be aware that when this is set to ConnectionState.Connected it will
/// release all threads that are blocked on <see cref="WaitOnConnect"/>.
/// </remarks>
public ConnectionState State
{
get
{
return this._state;
}
protected set
{
this._state = value;
this.SetState(value);
}
}
protected ConnectionState _state;
protected virtual void SetState(ConnectionState state) { }
/// <summary>
/// Constructor that initializes the ConnecitonStatistics object.
/// </summary>
/// <remarks>
/// This constructor initialises <see cref="Statistics"/> with empty statistics and sets <see cref="State"/> to
/// <see cref="ConnectionState.NotConnected"/>.
/// </remarks>
protected Connection()
{
this.Statistics = new ConnectionStatistics();
this.State = ConnectionState.NotConnected;
}
/// <summary>
/// Sends a number of bytes to the end point of the connection using the specified <see cref="MessageType"/>.
/// </summary>
/// <param name="msg">The message to send.</param>
/// <remarks>
/// <include file="DocInclude/common.xml" path="docs/item[@name='Connection_SendBytes_General']/*" />
/// <para>
/// The messageType parameter is only a request to use those options and the actual method used to send the
/// data is up to the implementation. There are circumstances where this parameter may be ignored but in
/// general any implementer should aim to always follow the user's request.
/// </para>
/// </remarks>
public abstract ValueTask SendAsync(IMessageWriter msg);
/// <summary>
/// Sends a number of bytes to the end point of the connection using the specified <see cref="MessageType"/>.
/// </summary>
/// <param name="bytes">The bytes of the message to send.</param>
/// <param name="messageType">The option specifying how the message should be sent.</param>
/// <remarks>
/// <include file="DocInclude/common.xml" path="docs/item[@name='Connection_SendBytes_General']/*" />
/// <para>
/// The messageType parameter is only a request to use those options and the actual method used to send the
/// data is up to the implementation. There are circumstances where this parameter may be ignored but in
/// general any implementer should aim to always follow the user's request.
/// </para>
/// </remarks>
public abstract ValueTask SendBytes(byte[] bytes, MessageType messageType = MessageType.Unreliable);
/// <summary>
/// Connects the connection to a server and begins listening.
/// This method does not block.
/// </summary>
/// <param name="bytes">The bytes of data to send in the handshake.</param>
public abstract ValueTask ConnectAsync(byte[] bytes = null);
/// <summary>
/// Invokes the DataReceived event.
/// </summary>
/// <param name="msg">The bytes received.</param>
/// <param name="messageType">The <see cref="MessageType"/> the message was received with.</param>
/// <remarks>
/// Invokes the <see cref="DataReceived"/> event on this connection to alert subscribers a new message has been
/// received. The bytes and the send option that the message was sent with should be passed in to give to the
/// subscribers.
/// </remarks>
protected async ValueTask InvokeDataReceived(IMessageReader msg, MessageType messageType)
{
// Make a copy to avoid race condition between null check and invocation
var handler = DataReceived;
if (handler != null)
{
try
{
await handler(new DataReceivedEventArgs(this, msg, messageType));
}
catch (Exception e)
{
Logger.Error(e, "Invoking data received failed");
await Disconnect("Invoking data received failed");
}
}
}
/// <summary>
/// Invokes the Disconnected event.
/// </summary>
/// <param name="e">The exception, if any, that occurred to cause this.</param>
/// <param name="reader">Extra disconnect data</param>
/// <remarks>
/// Invokes the <see cref="Disconnected"/> event to alert subscribres this connection has been disconnected either
/// by the end point or because an error occurred. If an error occurred the error should be passed in in order to
/// pass to the subscribers, otherwise null can be passed in.
/// </remarks>
protected async ValueTask InvokeDisconnected(string e, IMessageReader reader)
{
// Make a copy to avoid race condition between null check and invocation
var handler = Disconnected;
if (handler != null)
{
try
{
await handler(new DisconnectedEventArgs(e, reader));
}
catch (Exception ex)
{
Logger.Error(ex, "Error in InvokeDisconnected");
}
}
}
/// <summary>
/// For times when you want to force the disconnect handler to fire as well as close it.
/// If you only want to close it, just use Dispose.
/// </summary>
public abstract ValueTask Disconnect(string reason, MessageWriter writer = null);
/// <summary>
/// Disposes of this NetworkConnection.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Disposes of this NetworkConnection.
/// </summary>
/// <param name="disposing">Are we currently disposing?</param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
this.DataReceived = null;
this.Disconnected = null;
}
}
}
}
-100
View File
@@ -1,100 +0,0 @@
using System;
using System.Threading.Tasks;
using Impostor.Api.Net.Messages;
using Serilog;
namespace Impostor.Hazel
{
/// <summary>
/// Base class for all connection listeners.
/// </summary>
/// <remarks>
/// <para>
/// ConnectionListeners are server side objects that listen for clients and create matching server side connections
/// for each client in a similar way to TCP does. These connections should be ready for communication immediately.
/// </para>
/// <para>
/// Each time a client connects the <see cref="NewConnection"/> event will be invoked to alert all subscribers to
/// the new connection. A disconnected event is then present on the <see cref="Connection"/> that is passed to the
/// subscribers.
/// </para>
/// </remarks>
/// <threadsafety static="true" instance="true"/>
public abstract class ConnectionListener : IAsyncDisposable
{
private static readonly ILogger Logger = Log.ForContext<ConnectionListener>();
/// <summary>
/// Invoked when a new client connects.
/// </summary>
/// <remarks>
/// <para>
/// NewConnection is invoked each time a client connects to the listener. The
/// <see cref="NewConnectionEventArgs"/> contains the new <see cref="Connection"/> for communication with this
/// client.
/// </para>
/// <para>
/// Hazel may or may not store connections so it is your responsibility to keep track and properly Dispose of
/// connections to your server.
/// </para>
/// <include file="DocInclude/common.xml" path="docs/item[@name='Event_Thread_Safety_Warning']/*" />
/// </remarks>
/// <example>
/// <code language="C#" source="DocInclude/TcpListenerExample.cs"/>
/// </example>
public Func<NewConnectionEventArgs, ValueTask> NewConnection;
/// <summary>
/// Makes this connection listener begin listening for connections.
/// </summary>
/// <remarks>
/// <para>
/// This instructs the listener to begin listening for new clients connecting to the server. When a new client
/// connects the <see cref="NewConnection"/> event will be invoked containing the connection to the new client.
/// </para>
/// <para>
/// To stop listening you should call <see cref="DisposeAsync()"/>.
/// </para>
/// </remarks>
/// <example>
/// <code language="C#" source="DocInclude/TcpListenerExample.cs"/>
/// </example>
public abstract Task StartAsync();
/// <summary>
/// Invokes the NewConnection event with the supplied connection.
/// </summary>
/// <param name="msg">The user sent bytes that were received as part of the handshake.</param>
/// <param name="connection">The connection to pass in the arguments.</param>
/// <remarks>
/// Implementers should call this to invoke the <see cref="NewConnection"/> event before data is received so that
/// subscribers do not miss any data that may have been sent immediately after connecting.
/// </remarks>
internal async Task InvokeNewConnection(IMessageReader msg, Connection connection)
{
// Make a copy to avoid race condition between null check and invocation
var handler = NewConnection;
if (handler != null)
{
try
{
await handler(new NewConnectionEventArgs(msg, connection));
}
catch (Exception e)
{
Logger.Error(e, "Accepting connection failed");
await connection.Disconnect("Accepting connection failed");
}
}
}
/// <summary>
/// Call to dispose of the connection listener.
/// </summary>
public virtual ValueTask DisposeAsync()
{
this.NewConnection = null;
return ValueTask.CompletedTask;
}
}
}
-23
View File
@@ -1,23 +0,0 @@
namespace Impostor.Hazel
{
/// <summary>
/// Represents the state a <see cref="Connection"/> is currently in.
/// </summary>
public enum ConnectionState
{
/// <summary>
/// The Connection has either not been established yet or has been disconnected.
/// </summary>
NotConnected,
/// <summary>
/// The Connection is currently connecting to an endpoint.
/// </summary>
Connecting,
/// <summary>
/// The Connection is connected and data can be transfered.
/// </summary>
Connected,
}
}
-566
View File
@@ -1,566 +0,0 @@
using System.Runtime.CompilerServices;
using System.Threading;
[assembly: InternalsVisibleTo("Hazel.Tests")]
namespace Impostor.Hazel
{
/// <summary>
/// Holds statistics about the traffic through a <see cref="Connection"/>.
/// </summary>
/// <threadsafety static="true" instance="true"/>
public class ConnectionStatistics
{
private const int ExpectedMTU = 1200;
/// <summary>
/// The total number of messages sent.
/// </summary>
public int MessagesSent
{
get
{
return UnreliableMessagesSent + ReliableMessagesSent + FragmentedMessagesSent + AcknowledgementMessagesSent + HelloMessagesSent;
}
}
/// <summary>
/// The number of messages sent larger than 576 bytes. This is smaller than most default MTUs.
/// </summary>
/// <remarks>
/// This is the number of unreliable messages that were sent from the <see cref="Connection"/>, incremented
/// each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not
/// counted and messages are only counted once all other operations in the send are complete.
/// </remarks>
public int FragmentableMessagesSent
{
get
{
return fragmentableMessagesSent;
}
}
/// <summary>
/// The number of messages sent larger than 576 bytes.
/// </summary>
int fragmentableMessagesSent;
/// <summary>
/// The number of unreliable messages sent.
/// </summary>
/// <remarks>
/// This is the number of unreliable messages that were sent from the <see cref="Connection"/>, incremented
/// each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not
/// counted and messages are only counted once all other operations in the send are complete.
/// </remarks>
public int UnreliableMessagesSent
{
get
{
return unreliableMessagesSent;
}
}
/// <summary>
/// The number of unreliable messages sent.
/// </summary>
int unreliableMessagesSent;
/// <summary>
/// The number of reliable messages sent.
/// </summary>
/// <remarks>
/// This is the number of reliable messages that were sent from the <see cref="Connection"/>, incremented
/// each time that LogReliableSend is called by the Connection. Messages that caused an error are not
/// counted and messages are only counted once all other operations in the send are complete.
/// </remarks>
public int ReliableMessagesSent
{
get
{
return reliableMessagesSent;
}
}
/// <summary>
/// The number of unreliable messages sent.
/// </summary>
int reliableMessagesSent;
/// <summary>
/// The number of fragmented messages sent.
/// </summary>
/// <remarks>
/// This is the number of fragmented messages that were sent from the <see cref="Connection"/>, incremented
/// each time that LogFragmentedSend is called by the Connection. Messages that caused an error are not
/// counted and messages are only counted once all other operations in the send are complete.
/// </remarks>
public int FragmentedMessagesSent
{
get
{
return fragmentedMessagesSent;
}
}
/// <summary>
/// The number of fragmented messages sent.
/// </summary>
int fragmentedMessagesSent;
/// <summary>
/// The number of acknowledgement messages sent.
/// </summary>
/// <remarks>
/// This is the number of acknowledgements that were sent from the <see cref="Connection"/>, incremented
/// each time that LogAcknowledgementSend is called by the Connection. Messages that caused an error are not
/// counted and messages are only counted once all other operations in the send are complete.
/// </remarks>
public int AcknowledgementMessagesSent
{
get
{
return acknowledgementMessagesSent;
}
}
/// <summary>
/// The number of acknowledgement messages sent.
/// </summary>
int acknowledgementMessagesSent;
/// <summary>
/// The number of hello messages sent.
/// </summary>
/// <remarks>
/// This is the number of hello messages that were sent from the <see cref="Connection"/>, incremented
/// each time that LogHelloSend is called by the Connection. Messages that caused an error are not
/// counted and messages are only counted once all other operations in the send are complete.
/// </remarks>
public int HelloMessagesSent
{
get
{
return helloMessagesSent;
}
}
/// <summary>
/// The number of hello messages sent.
/// </summary>
int helloMessagesSent;
/// <summary>
/// The number of bytes of data sent.
/// </summary>
/// <remarks>
/// <para>
/// This is the number of bytes of data (i.e. user bytes) that were sent from the <see cref="Connection"/>,
/// accumulated each time that LogSend is called by the Connection. Messages that caused an error are not
/// counted and messages are only counted once all other operations in the send are complete.
/// </para>
/// <para>
/// For the number of bytes including protocol bytes see <see cref="TotalBytesSent"/>.
/// </para>
/// </remarks>
public long DataBytesSent
{
get
{
return Interlocked.Read(ref dataBytesSent);
}
}
/// <summary>
/// The number of bytes of data sent.
/// </summary>
long dataBytesSent;
/// <summary>
/// The number of bytes sent in total.
/// </summary>
/// <remarks>
/// <para>
/// This is the total number of bytes (the data bytes plus protocol bytes) that were sent from the
/// <see cref="Connection"/>, accumulated each time that LogSend is called by the Connection. Messages that
/// caused an error are not counted and messages are only counted once all other operations in the send are
/// complete.
/// </para>
/// <para>
/// For the number of data bytes excluding protocol bytes see <see cref="DataBytesSent"/>.
/// </para>
/// </remarks>
public long TotalBytesSent
{
get
{
return Interlocked.Read(ref totalBytesSent);
}
}
/// <summary>
/// The number of bytes sent in total.
/// </summary>
long totalBytesSent;
/// <summary>
/// The total number of messages received.
/// </summary>
public int MessagesReceived
{
get
{
return UnreliableMessagesReceived + ReliableMessagesReceived + FragmentedMessagesReceived + AcknowledgementMessagesReceived + helloMessagesReceived;
}
}
/// <summary>
/// The number of unreliable messages received.
/// </summary>
/// <remarks>
/// This is the number of unreliable messages that were received by the <see cref="Connection"/>, incremented
/// each time that LogUnreliableReceive is called by the Connection. Messages are counted before the receive event is invoked.
/// </remarks>
public int UnreliableMessagesReceived
{
get
{
return unreliableMessagesReceived;
}
}
/// <summary>
/// The number of unreliable messages received.
/// </summary>
int unreliableMessagesReceived;
/// <summary>
/// The number of reliable messages received.
/// </summary>
/// <remarks>
/// This is the number of reliable messages that were received by the <see cref="Connection"/>, incremented
/// each time that LogReliableReceive is called by the Connection. Messages are counted before the receive event is invoked.
/// </remarks>
public int ReliableMessagesReceived
{
get
{
return reliableMessagesReceived;
}
}
/// <summary>
/// The number of reliable messages received.
/// </summary>
int reliableMessagesReceived;
/// <summary>
/// The number of fragmented messages received.
/// </summary>
/// <remarks>
/// This is the number of fragmented messages that were received by the <see cref="Connection"/>, incremented
/// each time that LogFragmentedReceive is called by the Connection. Messages are counted before the receive event is invoked.
/// </remarks>
public int FragmentedMessagesReceived
{
get
{
return fragmentedMessagesReceived;
}
}
/// <summary>
/// The number of fragmented messages received.
/// </summary>
int fragmentedMessagesReceived;
/// <summary>
/// The number of acknowledgement messages received.
/// </summary>
/// <remarks>
/// This is the number of acknowledgement messages that were received by the <see cref="Connection"/>, incremented
/// each time that LogAcknowledgemntReceive is called by the Connection. Messages are counted before the receive event is invoked.
/// </remarks>
public int AcknowledgementMessagesReceived
{
get
{
return acknowledgementMessagesReceived;
}
}
/// <summary>
/// The number of acknowledgement messages received.
/// </summary>
int acknowledgementMessagesReceived;
/// <summary>
/// The number of ping messages received.
/// </summary>
/// <remarks>
/// This is the number of hello messages that were received by the <see cref="Connection"/>, incremented
/// each time that LogHelloReceive is called by the Connection. Messages are counted before the receive event is invoked.
/// </remarks>
public int PingMessagesReceived
{
get
{
return pingMessagesReceived;
}
}
/// <summary>
/// The number of hello messages received.
/// </summary>
int pingMessagesReceived;
/// <summary>
/// The number of hello messages received.
/// </summary>
/// <remarks>
/// This is the number of hello messages that were received by the <see cref="Connection"/>, incremented
/// each time that LogHelloReceive is called by the Connection. Messages are counted before the receive event is invoked.
/// </remarks>
public int HelloMessagesReceived
{
get
{
return helloMessagesReceived;
}
}
/// <summary>
/// The number of hello messages received.
/// </summary>
int helloMessagesReceived;
/// <summary>
/// The number of bytes of data received.
/// </summary>
/// <remarks>
/// <para>
/// This is the number of bytes of data (i.e. user bytes) that were received by the <see cref="Connection"/>,
/// accumulated each time that LogReceive is called by the Connection. Messages are counted before the receive
/// event is invoked.
/// </para>
/// <para>
/// For the number of bytes including protocol bytes see <see cref="TotalBytesReceived"/>.
/// </para>
/// </remarks>
public long DataBytesReceived
{
get
{
return Interlocked.Read(ref dataBytesReceived);
}
}
/// <summary>
/// The number of bytes of data received.
/// </summary>
long dataBytesReceived;
/// <summary>
/// The number of bytes received in total.
/// </summary>
/// <remarks>
/// <para>
/// This is the total number of bytes (the data bytes plus protocol bytes) that were received by the
/// <see cref="Connection"/>, accumulated each time that LogReceive is called by the Connection. Messages are
/// counted before the receive event is invoked.
/// </para>
/// <para>
/// For the number of data bytes excluding protocol bytes see <see cref="DataBytesReceived"/>.
/// </para>
/// </remarks>
public long TotalBytesReceived
{
get
{
return Interlocked.Read(ref totalBytesReceived);
}
}
/// <summary>
/// The number of bytes received in total.
/// </summary>
long totalBytesReceived;
public int MessagesResent { get { return messagesResent; } }
int messagesResent;
/// <summary>
/// Logs the sending of an unreliable data packet in the statistics.
/// </summary>
/// <param name="dataLength">The number of bytes of data sent.</param>
/// <param name="totalLength">The total number of bytes sent.</param>
/// <remarks>
/// This should be called after the data has been sent and should only be called for data that is sent sucessfully.
/// </remarks>
internal void LogUnreliableSend(int dataLength, int totalLength)
{
Interlocked.Increment(ref unreliableMessagesSent);
Interlocked.Add(ref dataBytesSent, dataLength);
Interlocked.Add(ref totalBytesSent, totalLength);
if (totalLength > ExpectedMTU)
{
Interlocked.Increment(ref fragmentableMessagesSent);
}
}
/// <summary>
/// Logs the sending of a reliable data packet in the statistics.
/// </summary>
/// <param name="dataLength">The number of bytes of data sent.</param>
/// <param name="totalLength">The total number of bytes sent.</param>
/// <remarks>
/// This should be called after the data has been sent and should only be called for data that is sent sucessfully.
/// </remarks>
internal void LogReliableSend(int dataLength, int totalLength)
{
Interlocked.Increment(ref reliableMessagesSent);
Interlocked.Add(ref dataBytesSent, dataLength);
Interlocked.Add(ref totalBytesSent, totalLength);
if (totalLength > ExpectedMTU)
{
Interlocked.Increment(ref fragmentableMessagesSent);
}
}
/// <summary>
/// Logs the sending of a fragmented data packet in the statistics.
/// </summary>
/// <param name="dataLength">The number of bytes of data sent.</param>
/// <param name="totalLength">The total number of bytes sent.</param>
/// <remarks>
/// This should be called after the data has been sent and should only be called for data that is sent sucessfully.
/// </remarks>
internal void LogFragmentedSend(int dataLength, int totalLength)
{
Interlocked.Increment(ref fragmentedMessagesSent);
Interlocked.Add(ref dataBytesSent, dataLength);
Interlocked.Add(ref totalBytesSent, totalLength);
if (totalLength > ExpectedMTU)
{
Interlocked.Increment(ref fragmentableMessagesSent);
}
}
/// <summary>
/// Logs the sending of a acknowledgement data packet in the statistics.
/// </summary>
/// <param name="totalLength">The total number of bytes sent.</param>
/// <remarks>
/// This should be called after the data has been sent and should only be called for data that is sent sucessfully.
/// </remarks>
internal void LogAcknowledgementSend(int totalLength)
{
Interlocked.Increment(ref acknowledgementMessagesSent);
Interlocked.Add(ref totalBytesSent, totalLength);
}
/// <summary>
/// Logs the sending of a hellp data packet in the statistics.
/// </summary>
/// <param name="totalLength">The total number of bytes sent.</param>
/// <remarks>
/// This should be called after the data has been sent and should only be called for data that is sent sucessfully.
/// </remarks>
internal void LogHelloSend(int totalLength)
{
Interlocked.Increment(ref helloMessagesSent);
Interlocked.Add(ref totalBytesSent, totalLength);
}
/// <summary>
/// Logs the receiving of an unreliable data packet in the statistics.
/// </summary>
/// <param name="dataLength">The number of bytes of data received.</param>
/// <param name="totalLength">The total number of bytes received.</param>
/// <remarks>
/// This should be called before the received event is invoked so it is up to date for subscribers to that event.
/// </remarks>
internal void LogUnreliableReceive(int dataLength, int totalLength)
{
Interlocked.Increment(ref unreliableMessagesReceived);
Interlocked.Add(ref dataBytesReceived, dataLength);
Interlocked.Add(ref totalBytesReceived, totalLength);
}
/// <summary>
/// Logs the receiving of a reliable data packet in the statistics.
/// </summary>
/// <param name="dataLength">The number of bytes of data received.</param>
/// <param name="totalLength">The total number of bytes received.</param>
/// <remarks>
/// This should be called before the received event is invoked so it is up to date for subscribers to that event.
/// </remarks>
internal void LogReliableReceive(int dataLength, int totalLength)
{
Interlocked.Increment(ref reliableMessagesReceived);
Interlocked.Add(ref dataBytesReceived, dataLength);
Interlocked.Add(ref totalBytesReceived, totalLength);
}
/// <summary>
/// Logs the receiving of a fragmented data packet in the statistics.
/// </summary>
/// <param name="dataLength">The number of bytes of data received.</param>
/// <param name="totalLength">The total number of bytes received.</param>
/// <remarks>
/// This should be called before the received event is invoked so it is up to date for subscribers to that event.
/// </remarks>
internal void LogFragmentedReceive(int dataLength, int totalLength)
{
Interlocked.Increment(ref fragmentedMessagesReceived);
Interlocked.Add(ref dataBytesReceived, dataLength);
Interlocked.Add(ref totalBytesReceived, totalLength);
}
/// <summary>
/// Logs the receiving of an acknowledgement data packet in the statistics.
/// </summary>
/// <param name="totalLength">The total number of bytes received.</param>
/// <remarks>
/// This should be called before the received event is invoked so it is up to date for subscribers to that event.
/// </remarks>
internal void LogAcknowledgementReceive(int totalLength)
{
Interlocked.Increment(ref acknowledgementMessagesReceived);
Interlocked.Add(ref totalBytesReceived, totalLength);
}
/// <summary>
/// Logs the receiving of a hello data packet in the statistics.
/// </summary>
/// <param name="totalLength">The total number of bytes received.</param>
/// <remarks>
/// This should be called before the received event is invoked so it is up to date for subscribers to that event.
/// </remarks>
internal void LogPingReceive(int totalLength)
{
Interlocked.Increment(ref pingMessagesReceived);
Interlocked.Add(ref totalBytesReceived, totalLength);
}
/// <summary>
/// Logs the receiving of a hello data packet in the statistics.
/// </summary>
/// <param name="totalLength">The total number of bytes received.</param>
/// <remarks>
/// This should be called before the received event is invoked so it is up to date for subscribers to that event.
/// </remarks>
internal void LogHelloReceive(int totalLength)
{
Interlocked.Increment(ref helloMessagesReceived);
Interlocked.Add(ref totalBytesReceived, totalLength);
}
internal void LogMessageResent()
{
Interlocked.Increment(ref messagesResent);
}
}
}
@@ -1,26 +0,0 @@
using Impostor.Api.Net.Messages;
namespace Impostor.Hazel
{
public struct DataReceivedEventArgs
{
public readonly Connection Sender;
/// <summary>
/// The bytes received from the client.
/// </summary>
public readonly IMessageReader Message;
/// <summary>
/// The <see cref="Type"/> the data was sent with.
/// </summary>
public readonly MessageType Type;
public DataReceivedEventArgs(Connection sender, IMessageReader msg, MessageType type)
{
this.Sender = sender;
this.Message = msg;
this.Type = type;
}
}
}
@@ -1,25 +0,0 @@
using System;
using Impostor.Api.Net.Messages;
namespace Impostor.Hazel
{
public class DisconnectedEventArgs : EventArgs
{
/// <summary>
/// Optional disconnect reason. May be null.
/// </summary>
public readonly string Reason;
/// <summary>
/// Optional data sent with a disconnect message. May be null.
/// You must not recycle this. If you need the message outside of a callback, you should copy it.
/// </summary>
public readonly IMessageReader Message;
public DisconnectedEventArgs(string reason, IMessageReader message)
{
this.Reason = reason;
this.Message = message;
}
}
}
@@ -1,21 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.ObjectPool;
namespace Impostor.Hazel.Extensions
{
public static class ServiceProviderExtensions
{
public static void AddHazel(this IServiceCollection services)
{
services.TryAddSingleton<ObjectPoolProvider>(new DefaultObjectPoolProvider());
services.AddSingleton(serviceProvider =>
{
var provider = serviceProvider.GetRequiredService<ObjectPoolProvider>();
var policy = ActivatorUtilities.CreateInstance<MessageReaderPolicy>(serviceProvider);
return provider.Create(policy);
});
}
}
}
-21
View File
@@ -1,21 +0,0 @@
using System;
namespace Impostor.Hazel
{
/// <summary>
/// Wrapper for exceptions thrown from Hazel.
/// </summary>
[Serializable]
public class HazelException : Exception
{
internal HazelException(string msg) : base (msg)
{
}
internal HazelException(string msg, Exception e) : base (msg, e)
{
}
}
}
-24
View File
@@ -1,24 +0,0 @@
namespace Impostor.Hazel
{
/// <summary>
/// Represents the IP version that a connection or listener will use.
/// </summary>
/// <remarks>
/// If you wand a client to connect or be able to connect using IPv6 then you should use <see cref="IPv4AndIPv6"/>,
/// this sets the underlying sockets to use IPv6 but still allow IPv4 sockets to connect for backwards compatability
/// and hence it is the default IPMode in most cases.
/// </remarks>
public enum IPMode
{
/// <summary>
/// Instruction to use IPv4 only, IPv6 connections will not be able to connect.
/// </summary>
IPv4,
/// <summary>
/// Instruction to use IPv6 only, IPv4 connections will not be able to connect. IPv4 addresses can be connected
/// by converting to IPv6 addresses.
/// </summary>
IPv6
}
}
Loaded 100 of 210 files, more files were not shown because too many files have changed in this diff. Show more