summaryrefslogtreecommitdiff
path: root/Impostor-dev/src/Impostor.Api/Innersloth
diff options
context:
space:
mode:
Diffstat (limited to 'Impostor-dev/src/Impostor.Api/Innersloth')
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/AlterGameTags.cs7
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/ChatNoteType.cs7
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/Customization/ColorType.cs18
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/Customization/HatType.cs100
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/Customization/PetType.cs18
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/Customization/SkinType.cs22
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/DeathReason.cs9
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/DisconnectReason.cs54
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/FloatRange.cs22
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/GameCodeParser.cs142
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/GameKeywords.cs19
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/GameOptionsData.cs261
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/GameOverReason.cs15
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/GameStates.cs11
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/GameVersion.cs10
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/KillDistances.cs12
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/MapFlags.cs12
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/MapTypes.cs9
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/RegionInfo.cs48
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/ServerInfo.cs37
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/SystemTypeHelpers.cs28
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/SystemTypes.cs42
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/TaskBarUpdate.cs9
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/TaskTypes.cs49
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/TextBox.cs10
-rw-r--r--Impostor-dev/src/Impostor.Api/Innersloth/VentLocation.cs48
26 files changed, 1019 insertions, 0 deletions
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/AlterGameTags.cs b/Impostor-dev/src/Impostor.Api/Innersloth/AlterGameTags.cs
new file mode 100644
index 0000000..46d1b2e
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/AlterGameTags.cs
@@ -0,0 +1,7 @@
+namespace Impostor.Api.Innersloth
+{
+ public enum AlterGameTags : byte
+ {
+ ChangePrivacy = 1,
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/ChatNoteType.cs b/Impostor-dev/src/Impostor.Api/Innersloth/ChatNoteType.cs
new file mode 100644
index 0000000..c163601
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/ChatNoteType.cs
@@ -0,0 +1,7 @@
+namespace Impostor.Api.Innersloth
+{
+ public enum ChatNoteType : byte
+ {
+ DidVote = 0,
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/Customization/ColorType.cs b/Impostor-dev/src/Impostor.Api/Innersloth/Customization/ColorType.cs
new file mode 100644
index 0000000..fc7be4c
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/Customization/ColorType.cs
@@ -0,0 +1,18 @@
+namespace Impostor.Api.Innersloth.Customization
+{
+ public enum ColorType : byte
+ {
+ Red = 0,
+ Blue = 1,
+ Green = 2,
+ Pink = 3,
+ Orange = 4,
+ Yellow = 5,
+ Black = 6,
+ White = 7,
+ Purple = 8,
+ Brown = 9,
+ Cyan = 10,
+ Lime = 11,
+ }
+}
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/Customization/HatType.cs b/Impostor-dev/src/Impostor.Api/Innersloth/Customization/HatType.cs
new file mode 100644
index 0000000..5e0a3ef
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/Customization/HatType.cs
@@ -0,0 +1,100 @@
+namespace Impostor.Api.Innersloth.Customization
+{
+ public enum HatType
+ {
+ NoHat = 0,
+ Astronaut = 1,
+ BaseballCap = 2,
+ BrainSlug = 3,
+ BushHat = 4,
+ CaptainsHat = 5,
+ DoubleTopHat = 6,
+ Flowerpot = 7,
+ Goggles = 8,
+ HardHat = 9,
+ Military = 10,
+ PaperHat = 11,
+ PartyHat = 12,
+ Police = 13,
+ Stethescope = 14,
+ TopHat = 15,
+ TowelWizard = 16,
+ Ushanka = 17,
+ Viking = 18,
+ WallCap = 19,
+ Snowman = 20,
+ Reindeer = 21,
+ Lights = 22,
+ Santa = 23,
+ Tree = 24,
+ Present = 25,
+ Candycanes = 26,
+ ElfHat = 27,
+ NewYears2018 = 28,
+ WhiteHat = 29,
+ Crown = 30,
+ Eyebrows = 31,
+ HaloHat = 32,
+ HeroCap = 33,
+ PipCap = 34,
+ PlungerHat = 35,
+ ScubaHat = 36,
+ StickminHat = 37,
+ StrawHat = 38,
+ TenGallonHat = 39,
+ ThirdEyeHat = 40,
+ ToiletPaperHat = 41,
+ Toppat = 42,
+ Fedora = 43,
+ Goggles2 = 44,
+ Headphones = 45,
+ MaskHat = 46,
+ PaperMask = 47,
+ Security = 48,
+ StrapHat = 49,
+ Banana = 50,
+ Beanie = 51,
+ Bear = 52,
+ Cheese = 53,
+ Cherry = 54,
+ Egg = 55,
+ Fedora2 = 56,
+ Flamingo = 57,
+ FlowerPin = 58,
+ Helmet = 59,
+ Plant = 60,
+ BatEyes = 61,
+ BatWings = 62,
+ Horns = 63,
+ Mohawk = 64,
+ Pumpkin = 65,
+ ScaryBag = 66,
+ Witch = 67,
+ Wolf = 68,
+ Pirate = 69,
+ Plague = 70,
+ Machete = 71,
+ Fred = 72,
+ MinerCap = 73,
+ WinterHat = 74,
+ Archae = 75,
+ Antenna = 76,
+ Balloon = 77,
+ BirdNest = 78,
+ BlackBelt = 79,
+ Caution = 80,
+ Chef = 81,
+ CopHat = 82,
+ DoRag = 83,
+ DumSticker = 84,
+ Fez = 85,
+ GeneralHat = 86,
+ GreyThing = 87,
+ HunterCap = 88,
+ JungleHat = 89,
+ MiniCrewmate = 90,
+ NinjaMask = 91,
+ RamHorns = 92,
+ Snowman2 = 93,
+ }
+}
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/Customization/PetType.cs b/Impostor-dev/src/Impostor.Api/Innersloth/Customization/PetType.cs
new file mode 100644
index 0000000..456e327
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/Customization/PetType.cs
@@ -0,0 +1,18 @@
+namespace Impostor.Api.Innersloth.Customization
+{
+ public enum PetType
+ {
+ NoPet = 0,
+ Alien = 1,
+ Crewmate = 2,
+ Doggy = 3,
+ Stickmin = 4,
+ Hamster = 5,
+ Robot = 6,
+ Ufo = 7,
+ Ellie = 8,
+ Squig = 9,
+ Bedcrab = 10,
+ Glitch = 11,
+ }
+}
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/Customization/SkinType.cs b/Impostor-dev/src/Impostor.Api/Innersloth/Customization/SkinType.cs
new file mode 100644
index 0000000..35da312
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/Customization/SkinType.cs
@@ -0,0 +1,22 @@
+namespace Impostor.Api.Innersloth.Customization
+{
+ public enum SkinType : byte
+ {
+ None = 0,
+ Astro = 1,
+ Capt = 2,
+ Mech = 3,
+ Military = 4,
+ Police = 5,
+ Science = 6,
+ SuitB = 7,
+ SuitW = 8,
+ Wall = 9,
+ Hazmat = 10,
+ Security = 11,
+ Tarmac = 12,
+ Miner = 13,
+ Winter = 14,
+ Archae = 15,
+ }
+}
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/DeathReason.cs b/Impostor-dev/src/Impostor.Api/Innersloth/DeathReason.cs
new file mode 100644
index 0000000..a07ac05
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/DeathReason.cs
@@ -0,0 +1,9 @@
+namespace Impostor.Api.Innersloth
+{
+ public enum DeathReason
+ {
+ Exile = 0,
+ Kill = 1,
+ Disconnect = 2,
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/DisconnectReason.cs b/Impostor-dev/src/Impostor.Api/Innersloth/DisconnectReason.cs
new file mode 100644
index 0000000..9526f58
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/DisconnectReason.cs
@@ -0,0 +1,54 @@
+namespace Impostor.Api.Innersloth
+{
+ public enum DisconnectReason
+ {
+ ExitGame = 0,
+ // The game you tried to join is full.
+ // Check with the host to see if you can join next round.
+ GameFull = 1,
+ // The game you tried to join already started.
+ // Check with the host to see if you can join next round.
+ GameStarted = 2,
+ // Could not find the game you're looking for.
+ GameMissing = 3,
+ IncorrectGame = 18,
+ // For these a message can be given, specifying an empty message shows
+ // "An unknown error disconnected you from the server."
+ CustomMessage1 = 4,
+ Custom = 8,
+ // CustomMessage3 = 11,
+ // CustomMessage4 = 12,
+ // CustomMessage5 = 13,
+ // CustomMessage6 = 14,
+ // CustomMessage7 = 15,
+ // You are running an older version of the game.
+ // Please update to play with others.
+ IncorrectVersion = 5,
+ // You cannot rejoin that room.
+ // You were banned
+ Banned = 6,
+ // You can rejoin if the room hasn't started
+ // You were kicked
+ Kicked = 7,
+ // You were banned for hacking.
+ // Please stop.
+ Hacking = 10,
+ Destroy = 16,
+ // You disconnected from the host.
+ // If this happens often, check your WiFi strength.
+ //
+ // You disconnected from the server.
+ // If this happens often, check your network strength.
+ // This may also be a server issue.
+ Error = 17,
+ // The server stopped this game. Possibly due to inactivity.
+ ServerRequest = 19,
+ // The Among Us servers are overloaded.
+ // Sorry! Please try again later!
+ ServerFull = 20,
+ FocusLostBackground = 207,
+ IntentionalLeaving = 208,
+ FocusLost = 209,
+ NewConnection = 210,
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/FloatRange.cs b/Impostor-dev/src/Impostor.Api/Innersloth/FloatRange.cs
new file mode 100644
index 0000000..c8a0824
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/FloatRange.cs
@@ -0,0 +1,22 @@
+using Impostor.Api.Unity;
+
+namespace Impostor.Api.Innersloth
+{
+ public class FloatRange
+ {
+ private readonly float _min;
+ private readonly float _max;
+
+ public FloatRange(float min, float max)
+ {
+ _min = min;
+ _max = max;
+ }
+
+ public float Width => _max - _min;
+
+ public float Lerp(float v) => Mathf.Lerp(_min, _max, v);
+
+ public float ReverseLerp(float t) => Mathf.Clamp((t - _min) / Width, 0.0f, 1f);
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/GameCodeParser.cs b/Impostor-dev/src/Impostor.Api/Innersloth/GameCodeParser.cs
new file mode 100644
index 0000000..9717cff
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/GameCodeParser.cs
@@ -0,0 +1,142 @@
+using System;
+using System.Buffers.Binary;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace Impostor.Api.Innersloth
+{
+ public static class GameCodeParser
+ {
+ private const string V2 = "QWXRTYLPESDFGHUJKZOCVBINMA";
+ private static readonly int[] V2Map = {
+ 25,
+ 21,
+ 19,
+ 10,
+ 8,
+ 11,
+ 12,
+ 13,
+ 22,
+ 15,
+ 16,
+ 6,
+ 24,
+ 23,
+ 18,
+ 7,
+ 0,
+ 3,
+ 9,
+ 4,
+ 14,
+ 20,
+ 1,
+ 2,
+ 5,
+ 17
+ };
+ private static readonly RNGCryptoServiceProvider Random = new RNGCryptoServiceProvider();
+
+ public static string IntToGameName(int input)
+ {
+ // V2.
+ if (input < -1)
+ {
+ return IntToGameNameV2(input);
+ }
+
+ // V1.
+ Span<byte> code = stackalloc byte[4];
+ BinaryPrimitives.WriteInt32LittleEndian(code, input);
+#if NETSTANDARD2_0
+ return Encoding.UTF8.GetString(code.Slice(0, 4).ToArray());
+#else
+ return Encoding.UTF8.GetString(code.Slice(0, 4));
+#endif
+ }
+
+ private static string IntToGameNameV2(int input)
+ {
+ var a = input & 0x3FF;
+ var b = (input >> 10) & 0xFFFFF;
+
+ return new string(new []
+ {
+ V2[a % 26],
+ V2[a / 26],
+ V2[b % 26],
+ V2[b / 26 % 26],
+ V2[b / (26 * 26) % 26],
+ V2[b / (26 * 26 * 26) % 26]
+ });
+ }
+
+ public static int GameNameToInt(string code)
+ {
+ var upper = code.ToUpperInvariant();
+ if (upper.Any(x => !char.IsLetter(x)))
+ {
+ return -1;
+ }
+
+ var len = code.Length;
+ if (len == 6)
+ {
+ return GameNameToIntV2(upper);
+ }
+
+ if (len == 4)
+ {
+ return code[0] | ((code[1] | ((code[2] | (code[3] << 8)) << 8)) << 8);
+ }
+
+ return -1;
+ }
+
+ private static int GameNameToIntV2(string code)
+ {
+ var a = V2Map[code[0] - 65];
+ var b = V2Map[code[1] - 65];
+ var c = V2Map[code[2] - 65];
+ var d = V2Map[code[3] - 65];
+ var e = V2Map[code[4] - 65];
+ var f = V2Map[code[5] - 65];
+
+ var one = (a + 26 * b) & 0x3FF;
+ var two = (c + 26 * (d + 26 * (e + 26 * f)));
+
+ return (int) (one | ((two << 10) & 0x3FFFFC00) | 0x80000000);
+ }
+
+ public static int GenerateCode(int len)
+ {
+ if (len != 4 && len != 6)
+ {
+ throw new ArgumentException("should be 4 or 6", nameof(len));
+ }
+
+ // Generate random bytes.
+#if NETSTANDARD2_0
+ var data = new byte[len];
+#else
+ Span<byte> data = stackalloc byte[len];
+#endif
+ Random.GetBytes(data);
+
+ // Convert to their char representation.
+ Span<char> dataChar = stackalloc char[len];
+ for (var i = 0; i < len; i++)
+ {
+ dataChar[i] = V2[V2Map[data[i] % 26]];
+ }
+
+#if NETSTANDARD2_0
+ return GameNameToInt(new string(dataChar.ToArray()));
+#else
+ return GameNameToInt(new string(dataChar));
+#endif
+ }
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/GameKeywords.cs b/Impostor-dev/src/Impostor.Api/Innersloth/GameKeywords.cs
new file mode 100644
index 0000000..bbb463f
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/GameKeywords.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Impostor.Api.Innersloth
+{
+ [Flags]
+ public enum GameKeywords : uint
+ {
+ All = 0,
+ Other = 1,
+ Spanish = 2,
+ Korean = 4,
+ Russian = 8,
+ Portuguese = 16,
+ Arabic = 32,
+ Filipone = 64,
+ Polish = 128,
+ English = 256,
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/GameOptionsData.cs b/Impostor-dev/src/Impostor.Api/Innersloth/GameOptionsData.cs
new file mode 100644
index 0000000..d18efd8
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/GameOptionsData.cs
@@ -0,0 +1,261 @@
+using System;
+using System.IO;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Api.Innersloth
+{
+ public class GameOptionsData
+ {
+ /// <summary>
+ /// The latest major version of the game client.
+ /// </summary>
+ public const int LatestVersion = 4;
+
+ /// <summary>
+ /// Gets or sets host's version of the game.
+ /// </summary>
+ public byte Version { get; set; }
+
+ /// <summary>
+ /// Gets or sets the maximum amount of players for this lobby.
+ /// </summary>
+ public byte MaxPlayers { get; set; }
+
+ /// <summary>
+ /// Gets or sets the language of the lobby as per <see cref="GameKeywords"/> enum.
+ /// </summary>
+ public GameKeywords Keywords { get; set; }
+
+ /// <summary>
+ /// Gets or sets the MapId selected for this lobby
+ /// </summary>
+ /// <remarks>
+ /// Skeld = 0, MiraHQ = 1, Polus = 2.
+ /// </remarks>
+ internal byte MapId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the map selected for this lobby
+ /// </summary>
+ public MapTypes Map
+ {
+ get => (MapTypes)MapId;
+ set => MapId = (byte)value;
+ }
+
+ /// <summary>
+ /// Gets or sets the Player speed modifier.
+ /// </summary>
+ public float PlayerSpeedMod { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Light modifier for the players that are members of the crew as a multiplier value.
+ /// </summary>
+ public float CrewLightMod { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Light modifier for the players that are Impostors as a multiplier value.
+ /// </summary>
+ public float ImpostorLightMod { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Impostor cooldown to kill in seconds.
+ /// </summary>
+ public float KillCooldown { get; set; }
+
+ /// <summary>
+ /// Gets or sets the number of common tasks.
+ /// </summary>
+ public int NumCommonTasks { get; set; }
+
+ /// <summary>
+ /// Gets or sets the number of long tasks.
+ /// </summary>
+ public int NumLongTasks { get; set; }
+
+ /// <summary>
+ /// Gets or sets the number of short tasks.
+ /// </summary>
+ public int NumShortTasks { get; set; }
+
+ /// <summary>
+ /// Gets or sets the maximum amount of emergency meetings each player can call during the game in seconds.
+ /// </summary>
+ public int NumEmergencyMeetings { get; set; }
+
+ /// <summary>
+ /// Gets or sets the cooldown between each time any player can call an emergency meeting in seconds.
+ /// </summary>
+ public int EmergencyCooldown { get; set; }
+
+ /// <summary>
+ /// Gets or sets the number of impostors for this lobby.
+ /// </summary>
+ public int NumImpostors { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether ghosts (dead crew members) can do tasks.
+ /// </summary>
+ public bool GhostsDoTasks { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Kill as per values in <see cref="KillDistances"/>.
+ /// </summary>
+ /// <remarks>
+ /// Short = 0, Normal = 1, Long = 2.
+ /// </remarks>
+ public KillDistances KillDistance { get; set; }
+
+ /// <summary>
+ /// Gets or sets the time for discussion before voting time in seconds.
+ /// </summary>
+ public int DiscussionTime { get; set; }
+
+ /// <summary>
+ /// Gets or sets the time for voting in seconds.
+ /// </summary>
+ public int VotingTime { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether an ejected player is an impostor or not.
+ /// </summary>
+ public bool ConfirmImpostor { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether players are able to see tasks being performed by other players.
+ /// </summary>
+ /// <remarks>
+ /// By being set to true, tasks such as Empty Garbage, Submit Scan, Clear asteroids, Prime shields execution will be visible to other players.
+ /// </remarks>
+ public bool VisualTasks { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether the vote is anonymous.
+ /// </summary>
+ public bool AnonymousVotes { get; set; }
+
+ /// <summary>
+ /// Gets or sets the task bar update mode as per values in <see cref="Innersloth.TaskBarUpdate"/>.
+ /// </summary>
+ public TaskBarUpdate TaskBarUpdate { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether the GameOptions are the default ones.
+ /// </summary>
+ public bool IsDefaults { get; set; }
+
+ /// <summary>
+ /// Deserialize a packet/message to a new GameOptionsData object.
+ /// </summary>
+ /// <param name="reader">Message reader object containing the raw message.</param>
+ /// <returns>GameOptionsData object.</returns>
+ public static GameOptionsData DeserializeCreate(IMessageReader reader)
+ {
+ var options = new GameOptionsData();
+ options.Deserialize(reader.ReadBytesAndSize());
+ return options;
+ }
+
+ /// <summary>
+ /// Serializes this instance of GameOptionsData object to a specified BinaryWriter.
+ /// </summary>
+ /// <param name="writer">The stream to write the message to.</param>
+ /// <param name="version">The version of the game.</param>
+ public void Serialize(BinaryWriter writer, byte version)
+ {
+ writer.Write((byte)version);
+ writer.Write((byte)MaxPlayers);
+ writer.Write((uint)Keywords);
+ writer.Write((byte)MapId);
+ writer.Write((float)PlayerSpeedMod);
+ writer.Write((float)CrewLightMod);
+ writer.Write((float)ImpostorLightMod);
+ writer.Write((float)KillCooldown);
+ writer.Write((byte)NumCommonTasks);
+ writer.Write((byte)NumLongTasks);
+ writer.Write((byte)NumShortTasks);
+ writer.Write((int)NumEmergencyMeetings);
+ writer.Write((byte)NumImpostors);
+ writer.Write((byte)KillDistance);
+ writer.Write((uint)DiscussionTime);
+ writer.Write((uint)VotingTime);
+ writer.Write((bool)IsDefaults);
+
+ if (version > 1)
+ {
+ writer.Write((byte)EmergencyCooldown);
+ }
+
+ if (version > 2)
+ {
+ writer.Write((bool)ConfirmImpostor);
+ writer.Write((bool)VisualTasks);
+ }
+
+ if (version > 3)
+ {
+ writer.Write((bool)AnonymousVotes);
+ writer.Write((byte)TaskBarUpdate);
+ }
+
+ if (version > 4)
+ {
+ throw new ImpostorException($"Unknown GameOptionsData version {Version}.");
+ }
+ }
+
+ /// <summary>
+ /// Deserialize a ReadOnlyMemory object to this instance of the GameOptionsData object.
+ /// </summary>
+ /// <param name="memory">Memory containing the message/packet.</param>
+ public void Deserialize(ReadOnlyMemory<byte> memory)
+ {
+ var bytes = memory.Span;
+
+ Version = bytes.ReadByte();
+ MaxPlayers = bytes.ReadByte();
+ Keywords = (GameKeywords)bytes.ReadUInt32();
+ MapId = bytes.ReadByte();
+ PlayerSpeedMod = bytes.ReadSingle();
+
+ CrewLightMod = bytes.ReadSingle();
+ ImpostorLightMod = bytes.ReadSingle();
+ KillCooldown = bytes.ReadSingle();
+
+ NumCommonTasks = bytes.ReadByte();
+ NumLongTasks = bytes.ReadByte();
+ NumShortTasks = bytes.ReadByte();
+
+ NumEmergencyMeetings = bytes.ReadInt32();
+
+ NumImpostors = bytes.ReadByte();
+ KillDistance = (KillDistances)bytes.ReadByte();
+ DiscussionTime = bytes.ReadInt32();
+ VotingTime = bytes.ReadInt32();
+
+ IsDefaults = bytes.ReadBoolean();
+
+ if (Version > 1)
+ {
+ EmergencyCooldown = bytes.ReadByte();
+ }
+
+ if (Version > 2)
+ {
+ ConfirmImpostor = bytes.ReadBoolean();
+ VisualTasks = bytes.ReadBoolean();
+ }
+
+ if (Version > 3)
+ {
+ AnonymousVotes = bytes.ReadBoolean();
+ TaskBarUpdate = (TaskBarUpdate)bytes.ReadByte();
+ }
+
+ if (Version > 4)
+ {
+ throw new ImpostorException($"Unknown GameOptionsData version {Version}.");
+ }
+ }
+ }
+}
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/GameOverReason.cs b/Impostor-dev/src/Impostor.Api/Innersloth/GameOverReason.cs
new file mode 100644
index 0000000..6a95d37
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/GameOverReason.cs
@@ -0,0 +1,15 @@
+namespace Impostor.Api.Innersloth
+{
+ public enum GameOverReason : byte
+ {
+ HumansByVote = 0,
+ HumansByTask = 1,
+ ImpostorByVote = 2,
+ ImpostorByKill = 3,
+ ImpostorBySabotage = 4,
+
+ // Unused (?)
+ ImpostorDisconnect = 5,
+ HumansDisconnect = 6,
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/GameStates.cs b/Impostor-dev/src/Impostor.Api/Innersloth/GameStates.cs
new file mode 100644
index 0000000..f5aaa9c
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/GameStates.cs
@@ -0,0 +1,11 @@
+namespace Impostor.Api.Innersloth
+{
+ public enum GameStates : byte
+ {
+ NotStarted = 0,
+ Starting = 1,
+ Started = 2,
+ Ended = 3,
+ Destroyed = 4,
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/GameVersion.cs b/Impostor-dev/src/Impostor.Api/Innersloth/GameVersion.cs
new file mode 100644
index 0000000..c11933e
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/GameVersion.cs
@@ -0,0 +1,10 @@
+namespace Impostor.Api.Innersloth
+{
+ public class GameVersion
+ {
+ public static int GetVersion(int year, int month, int day, int rev = 0)
+ {
+ return (year * 25000) + (month * 1800) + (day * 50) + rev;
+ }
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/KillDistances.cs b/Impostor-dev/src/Impostor.Api/Innersloth/KillDistances.cs
new file mode 100644
index 0000000..b2ee5d9
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/KillDistances.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Impostor.Api.Innersloth
+{
+ [Flags]
+ public enum KillDistances : byte
+ {
+ Short = 0,
+ Normal = 1,
+ Long = 2,
+ }
+}
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/MapFlags.cs b/Impostor-dev/src/Impostor.Api/Innersloth/MapFlags.cs
new file mode 100644
index 0000000..ad462a2
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/MapFlags.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Impostor.Api.Innersloth
+{
+ [Flags]
+ public enum MapFlags
+ {
+ Skeld = 1,
+ MiraHQ = 2,
+ Polus = 4,
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/MapTypes.cs b/Impostor-dev/src/Impostor.Api/Innersloth/MapTypes.cs
new file mode 100644
index 0000000..8dc07b5
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/MapTypes.cs
@@ -0,0 +1,9 @@
+namespace Impostor.Api.Innersloth
+{
+ public enum MapTypes
+ {
+ Skeld = 0,
+ MiraHQ = 1,
+ Polus = 2,
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/RegionInfo.cs b/Impostor-dev/src/Impostor.Api/Innersloth/RegionInfo.cs
new file mode 100644
index 0000000..c78978b
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/RegionInfo.cs
@@ -0,0 +1,48 @@
+using System.Collections.Generic;
+using System.IO;
+
+namespace Impostor.Api.Innersloth
+{
+ public class RegionInfo
+ {
+ public RegionInfo(string name, string ping, IReadOnlyList<ServerInfo> servers)
+ {
+ Name = name;
+ Ping = ping;
+ Servers = servers;
+ }
+
+ public string Name { get; }
+ public string Ping { get; }
+ public IReadOnlyList<ServerInfo> Servers { get; }
+
+ public void Serialize(BinaryWriter writer)
+ {
+ writer.Write(0);
+ writer.Write(Name);
+ writer.Write(Ping);
+ writer.Write(Servers.Count);
+
+ foreach (var server in Servers)
+ {
+ server.Serialize(writer);
+ }
+ }
+
+ public static RegionInfo Deserialize(BinaryReader reader)
+ {
+ var unknown = reader.ReadInt32();
+ var name = reader.ReadString();
+ var ping = reader.ReadString();
+ var servers = new List<ServerInfo>();
+ var serverCount = reader.ReadInt32();
+
+ for (var i = 0; i < serverCount; i++)
+ {
+ servers.Add(ServerInfo.Deserialize(reader));
+ }
+
+ return new RegionInfo(name, ping, servers);
+ }
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/ServerInfo.cs b/Impostor-dev/src/Impostor.Api/Innersloth/ServerInfo.cs
new file mode 100644
index 0000000..7785823
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/ServerInfo.cs
@@ -0,0 +1,37 @@
+using System.IO;
+using System.Net;
+
+namespace Impostor.Api.Innersloth
+{
+ public class ServerInfo
+ {
+ public string Name { get; }
+ public string Ip { get; }
+ public ushort Port { get; }
+
+ public ServerInfo(string name, string ip, ushort port)
+ {
+ Name = name;
+ Ip = ip;
+ Port = port;
+ }
+
+ public void Serialize(BinaryWriter writer)
+ {
+ writer.Write(Name);
+ writer.Write(IPAddress.Parse(Ip).GetAddressBytes());
+ writer.Write(Port);
+ writer.Write(0);
+ }
+
+ public static ServerInfo Deserialize(BinaryReader reader)
+ {
+ var name = reader.ReadString();
+ var ip = new IPAddress(reader.ReadBytes(4)).ToString();
+ var port = reader.ReadUInt16();
+ var unknown = reader.ReadInt32();
+
+ return new ServerInfo(name, ip, port);
+ }
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/SystemTypeHelpers.cs b/Impostor-dev/src/Impostor.Api/Innersloth/SystemTypeHelpers.cs
new file mode 100644
index 0000000..ad88c28
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/SystemTypeHelpers.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Linq;
+
+namespace Impostor.Api.Innersloth
+{
+ internal class SystemTypeHelpers
+ {
+ public static readonly SystemTypes[] AllTypes;
+ public static readonly string[] Names;
+
+ static SystemTypeHelpers()
+ {
+ AllTypes = Enum.GetValues(typeof(SystemTypes)).Cast<SystemTypes>().ToArray();
+ Names = AllTypes.Select(x =>
+ {
+ return x switch
+ {
+ SystemTypes.UpperEngine => "Upper Engine",
+ SystemTypes.Nav => "Navigations",
+ SystemTypes.LifeSupp => "O2",
+ SystemTypes.LowerEngine => "Lower Engine",
+ SystemTypes.LockerRoom => "Locker Room",
+ _ => x.ToString()
+ };
+ }).ToArray();
+ }
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/SystemTypes.cs b/Impostor-dev/src/Impostor.Api/Innersloth/SystemTypes.cs
new file mode 100644
index 0000000..7f91718
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/SystemTypes.cs
@@ -0,0 +1,42 @@
+namespace Impostor.Api.Innersloth
+{
+ public enum SystemTypes : byte
+ {
+ Hallway = 0,
+ Storage = 1,
+ Cafeteria = 2,
+ Reactor = 3,
+ UpperEngine = 4,
+ Nav = 5,
+ Admin = 6,
+ Electrical = 7,
+ LifeSupp = 8,
+ Shields = 9,
+ MedBay = 10,
+ Security = 11,
+ Weapons = 12,
+ LowerEngine = 13,
+ Comms = 14,
+ ShipTasks = 15,
+ Doors = 16,
+ Sabotage = 17,
+ /// <summary>
+ /// Decontam on Mira and bottom decontam on Polus
+ /// </summary>
+ Decontamination = 18,
+ Launchpad = 19,
+ LockerRoom = 20,
+ Laboratory = 21,
+ Balcony = 22,
+ Office = 23,
+ Greenhouse = 24,
+ Dropship = 25,
+ /// <summary>
+ /// Top decontam on Polus
+ /// </summary>
+ Decontamination2 = 26,
+ Outside = 27,
+ Specimens = 28,
+ BoilerRoom = 29
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/TaskBarUpdate.cs b/Impostor-dev/src/Impostor.Api/Innersloth/TaskBarUpdate.cs
new file mode 100644
index 0000000..f4d7c1f
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/TaskBarUpdate.cs
@@ -0,0 +1,9 @@
+namespace Impostor.Api.Innersloth
+{
+ public enum TaskBarUpdate : byte
+ {
+ Always = 0,
+ Meetings = 1,
+ Never = 2
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/TaskTypes.cs b/Impostor-dev/src/Impostor.Api/Innersloth/TaskTypes.cs
new file mode 100644
index 0000000..8b15354
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/TaskTypes.cs
@@ -0,0 +1,49 @@
+namespace Impostor.Api.Innersloth
+{
+ public enum TaskTypes : uint
+ {
+ SubmitScan = 0,
+ PrimeShields = 1,
+ FuelEngines = 2,
+ ChartCourse = 3,
+ StartReactor = 4,
+ SwipeCard = 5,
+ ClearAsteroids = 6,
+ UploadData = 7,
+ InspectSample = 8,
+ EmptyChute = 9,
+ EmptyGarbage = 10,
+ AlignEngineOutput = 11,
+ FixWiring = 12,
+ CalibrateDistributor = 13,
+ DivertPower = 14,
+ UnlockManifolds = 15,
+ ResetReactor = 16,
+ FixLights = 17,
+ Filter = 18,
+ FixComms = 19,
+ RestoreOxy = 20,
+ StabilizeSteering = 21,
+ AssembleArtifact = 22,
+ SortSamples = 23,
+ MeasureWeather = 24,
+ EnterIdCode = 25,
+ BuyBeverage = 26,
+ ProcessData = 27,
+ RunDiagnostics = 28,
+ WaterPlants = 29,
+ MonitorOxygen = 30,
+ StoreArtifact = 31,
+ FillCanisters = 32,
+ ActivateWeatherNodes = 33,
+ InsertKeys = 34,
+ ResetSeismic = 35,
+ ScanBoardingPass = 36,
+ OpenWaterways = 37,
+ ReplaceWaterJug = 38,
+ RepairDrill = 39,
+ AlignTelescope = 40,
+ RecordTemperature = 41,
+ RebootWifi = 42,
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/TextBox.cs b/Impostor-dev/src/Impostor.Api/Innersloth/TextBox.cs
new file mode 100644
index 0000000..9533d83
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/TextBox.cs
@@ -0,0 +1,10 @@
+namespace Impostor.Api.Innersloth
+{
+ public static class TextBox
+ {
+ public static bool IsCharAllowed(char i)
+ {
+ return i == ' ' || (i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z') || (i >= '0' && i <= '9') || (i >= 'À' && i <= 'ÿ') || (i >= 'Ѐ' && i <= 'џ') || (i >= 'ㄱ' && i <= 'ㆎ') || (i >= '가' && i <= '힣');
+ }
+ }
+} \ No newline at end of file
diff --git a/Impostor-dev/src/Impostor.Api/Innersloth/VentLocation.cs b/Impostor-dev/src/Impostor.Api/Innersloth/VentLocation.cs
new file mode 100644
index 0000000..f9b8567
--- /dev/null
+++ b/Impostor-dev/src/Impostor.Api/Innersloth/VentLocation.cs
@@ -0,0 +1,48 @@
+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,
+ }
+}