From: js6pak Date: Wed, 10 Nov 2021 19:46:56 +0000 (+0100) Subject: WIP X-Git-Tag: v1.7.0~17^2~18 X-Git-Url: https://git.deb.at/?a=commitdiff_plain;h=4d1aec9070bfe33d872ba852c50a7a92f56f8c9b;p=rhonda%2Fimpostor.git WIP --- diff --git a/src/Impostor.Api/Extensions/SpanReaderExtensions.cs b/src/Impostor.Api/Extensions/SpanReaderExtensions.cs index 05b891a..3b24c77 100644 --- a/src/Impostor.Api/Extensions/SpanReaderExtensions.cs +++ b/src/Impostor.Api/Extensions/SpanReaderExtensions.cs @@ -16,6 +16,13 @@ namespace Impostor.Api return original[0]; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short ReadInt16(this ref ReadOnlySpan input) + { + var original = Advance(ref input); + return BinaryPrimitives.ReadInt16LittleEndian(original); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ReadInt32(this ref ReadOnlySpan input) { diff --git a/src/Impostor.Api/Innersloth/Customization/HatType.cs b/src/Impostor.Api/Innersloth/Customization/HatType.cs deleted file mode 100644 index 28b481b..0000000 --- a/src/Impostor.Api/Innersloth/Customization/HatType.cs +++ /dev/null @@ -1,121 +0,0 @@ -namespace Impostor.Api.Innersloth.Customization -{ - public enum HatType : uint - { - 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, - BlackFedora = 43, - SkiGoggles = 44, - Headphones = 45, - MaskHat = 46, - PaperMask = 47, - Security = 48, - StrapHat = 49, - Banana = 50, - Beanie = 51, - Bear = 52, - Cheese = 53, - Cherry = 54, - Egg = 55, - GreenFedora = 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, - 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, - RightHandMan = 107, - AngryEyebrows = 108, - ChocolateIce = 109, - HeartPin = 110, - Ponytail = 111, - RubberGlove = 112, - UnicornHorn = 113, - Zipper = 114, - } -} diff --git a/src/Impostor.Api/Innersloth/Customization/PetType.cs b/src/Impostor.Api/Innersloth/Customization/PetType.cs deleted file mode 100644 index f8753f2..0000000 --- a/src/Impostor.Api/Innersloth/Customization/PetType.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Impostor.Api.Innersloth.Customization -{ - public enum PetType : uint - { - 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/src/Impostor.Api/Innersloth/Customization/PlayerOutfit.cs b/src/Impostor.Api/Innersloth/Customization/PlayerOutfit.cs new file mode 100644 index 0000000..a54b889 --- /dev/null +++ b/src/Impostor.Api/Innersloth/Customization/PlayerOutfit.cs @@ -0,0 +1,56 @@ +using Impostor.Api.Net.Messages; + +namespace Impostor.Api.Innersloth.Customization +{ + public class PlayerOutfit + { + public ColorType Color { get; internal set; } = (ColorType)(-1); + + public string HatId { get; internal set; } = "missing"; + + public string PetId { get; internal set; } = "missing"; + + public string SkinId { get; internal set; } = "missing"; + + public string VisorId { get; internal set; } = "missing"; + + public string NamePlateId { get; internal set; } = "missing"; + + public string PlayerName { get; internal set; } = "missing"; + + public bool IsIncomplete + { + get + { + if (!string.IsNullOrEmpty(PlayerName) && Color != (ColorType)(-1) && HatId != "missing" && PetId != "missing" && SkinId != "missing" && VisorId != "missing") + { + return NamePlateId == "missing"; + } + + return true; + } + } + + public void Serialize(IMessageWriter writer) + { + writer.Write(PlayerName); + writer.WritePacked((int)Color); + writer.Write(HatId); + writer.Write(PetId); + writer.Write(SkinId); + writer.Write(VisorId); + writer.Write(NamePlateId); + } + + public void Deserialize(IMessageReader reader) + { + PlayerName = reader.ReadString(); + Color = (ColorType)reader.ReadPackedInt32(); + HatId = reader.ReadString(); + PetId = reader.ReadString(); + SkinId = reader.ReadString(); + VisorId = reader.ReadString(); + NamePlateId = reader.ReadString(); + } + } +} diff --git a/src/Impostor.Api/Innersloth/Customization/PlayerOutfitType.cs b/src/Impostor.Api/Innersloth/Customization/PlayerOutfitType.cs new file mode 100644 index 0000000..55ba04c --- /dev/null +++ b/src/Impostor.Api/Innersloth/Customization/PlayerOutfitType.cs @@ -0,0 +1,8 @@ +namespace Impostor.Api.Innersloth.Customization +{ + public enum PlayerOutfitType + { + Default, + Shapeshifted, + } +} diff --git a/src/Impostor.Api/Innersloth/Customization/SkinType.cs b/src/Impostor.Api/Innersloth/Customization/SkinType.cs deleted file mode 100644 index efda42e..0000000 --- a/src/Impostor.Api/Innersloth/Customization/SkinType.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Impostor.Api.Innersloth.Customization -{ - public enum SkinType : uint - { - 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, - Prisoner = 16, - CCC = 17, - RightHandMan = 18, - } -} diff --git a/src/Impostor.Api/Innersloth/GameOptionsData.cs b/src/Impostor.Api/Innersloth/GameOptionsData.cs index 5530c88..3f01ca8 100644 --- a/src/Impostor.Api/Innersloth/GameOptionsData.cs +++ b/src/Impostor.Api/Innersloth/GameOptionsData.cs @@ -9,7 +9,7 @@ namespace Impostor.Api.Innersloth /// /// The latest major version of the game client. /// - public const int LatestVersion = 4; + public const int LatestVersion = 5; /// /// Gets or sets host's version of the game. @@ -124,6 +124,11 @@ namespace Impostor.Api.Innersloth /// public TaskBarUpdate TaskBarUpdate { get; set; } = TaskBarUpdate.Always; + /// + /// Gets or sets role options. + /// + public RoleOptionsData RoleOptions { get; set; } = new RoleOptionsData(); + /// /// Gets or sets a value indicating whether the GameOptions are the default ones. /// @@ -184,6 +189,11 @@ namespace Impostor.Api.Innersloth } if (version > 4) + { + RoleOptions.Serialize(writer); + } + + if (version > 5) { throw new ImpostorException($"Unknown GameOptionsData version {Version}."); } @@ -246,6 +256,11 @@ namespace Impostor.Api.Innersloth } if (Version > 4) + { + RoleOptions = RoleOptionsData.Deserialize(bytes); + } + + if (Version > 5) { throw new ImpostorException($"Unknown GameOptionsData version {Version}."); } diff --git a/src/Impostor.Api/Innersloth/PlatformSpecificData.cs b/src/Impostor.Api/Innersloth/PlatformSpecificData.cs new file mode 100644 index 0000000..807f626 --- /dev/null +++ b/src/Impostor.Api/Innersloth/PlatformSpecificData.cs @@ -0,0 +1,42 @@ +using System; +using Impostor.Api.Net.Messages; + +namespace Impostor.Api.Innersloth +{ + public class PlatformSpecificData + { + public PlatformSpecificData(IMessageReader reader) + { + Platform = (Platforms)reader.Tag; + PlatformName = reader.ReadString(); + + XboxPlatformId = Platform == Platforms.Xbox ? reader.ReadUInt64() : null; + PsnPlatformId = Platform == Platforms.Playstation ? reader.ReadUInt64() : null; + } + + public Platforms Platform { get; } + + public string PlatformName { get; } + + public ulong? XboxPlatformId { get; } + + public ulong? PsnPlatformId { get; } + + public void Serialize(IMessageWriter writer) + { + writer.StartMessage((byte)Platform); + writer.Write(PlatformName); + switch (Platform) + { + case Platforms.Xbox: + writer.Write(XboxPlatformId ?? throw new NullReferenceException($"{nameof(XboxPlatformId)} shouldn't be null when {nameof(Platform)} is Xbox")); + break; + case Platforms.Playstation: + writer.Write(PsnPlatformId ?? throw new NullReferenceException($"{nameof(PsnPlatformId)} shouldn't be null when {nameof(Platform)} is Playstation")); + break; + } + + writer.EndMessage(); + } + } +} diff --git a/src/Impostor.Api/Innersloth/Platforms.cs b/src/Impostor.Api/Innersloth/Platforms.cs index 2388e39..c1b3b09 100644 --- a/src/Impostor.Api/Innersloth/Platforms.cs +++ b/src/Impostor.Api/Innersloth/Platforms.cs @@ -11,5 +11,7 @@ namespace Impostor.Api.Innersloth IPhone = 6, Android = 7, Switch = 8, + Xbox = 9, + Playstation = 10, } } diff --git a/src/Impostor.Api/Innersloth/RoleOptionsData.cs b/src/Impostor.Api/Innersloth/RoleOptionsData.cs new file mode 100644 index 0000000..1d07854 --- /dev/null +++ b/src/Impostor.Api/Innersloth/RoleOptionsData.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Impostor.Api.Net.Messages; + +namespace Impostor.Api.Innersloth +{ + public class RoleOptionsData + { + public bool ShapeshifterLeaveSkin { get; set; } + + public float ShapeshifterCooldown { get; set; } = 10f; + + public float ShapeshifterDuration { get; set; } = 30f; + + public float ScientistCooldown { get; set; } = 15f; + + public float ScientistBatteryCharge { get; set; } = 5f; + + public float GuardianAngelCooldown { get; set; } = 60f; + + public bool ImpostorsCanSeeProtect { get; set; } + + public float ProtectionDurationSeconds { get; set; } = 10f; + + public float EngineerCooldown { get; set; } = 30f; + + public float EngineerInVentMaxTime { get; set; } = 15f; + + public Dictionary RoleRates { get; } = new Dictionary(); + + public static RoleOptionsData Deserialize(ReadOnlySpan span) + { + var roleOptionsData = new RoleOptionsData(); + var num = span.ReadInt32(); + for (var i = 0; i < num; i++) + { + var key = (RoleTypes)span.ReadInt16(); + var roleRate = new RoleRate(span.ReadByte(), span.ReadByte()); + roleOptionsData.RoleRates[key] = roleRate; + } + + roleOptionsData.ShapeshifterLeaveSkin = span.ReadBoolean(); + roleOptionsData.ShapeshifterCooldown = span.ReadByte(); + roleOptionsData.ShapeshifterDuration = span.ReadByte(); + roleOptionsData.ScientistCooldown = span.ReadByte(); + roleOptionsData.GuardianAngelCooldown = span.ReadByte(); + roleOptionsData.EngineerCooldown = span.ReadByte(); + roleOptionsData.EngineerInVentMaxTime = span.ReadByte(); + roleOptionsData.ScientistBatteryCharge = span.ReadByte(); + roleOptionsData.ProtectionDurationSeconds = span.ReadByte(); + roleOptionsData.ImpostorsCanSeeProtect = span.ReadBoolean(); + return roleOptionsData; + } + + public static RoleOptionsData Deserialize(IMessageReader reader) + { + var roleOptionsData = new RoleOptionsData(); + var num = reader.ReadPackedInt32(); + for (var i = 0; i < num; i++) + { + var key = (RoleTypes)reader.ReadInt16(); + var roleRate = new RoleRate(reader.ReadByte(), reader.ReadByte()); + roleOptionsData.RoleRates[key] = roleRate; + } + + roleOptionsData.ShapeshifterLeaveSkin = reader.ReadBoolean(); + roleOptionsData.ShapeshifterCooldown = reader.ReadByte(); + roleOptionsData.ShapeshifterDuration = reader.ReadByte(); + roleOptionsData.ScientistCooldown = reader.ReadByte(); + roleOptionsData.GuardianAngelCooldown = reader.ReadByte(); + roleOptionsData.EngineerCooldown = reader.ReadByte(); + roleOptionsData.EngineerInVentMaxTime = reader.ReadByte(); + roleOptionsData.ScientistBatteryCharge = reader.ReadByte(); + roleOptionsData.ProtectionDurationSeconds = reader.ReadByte(); + roleOptionsData.ImpostorsCanSeeProtect = reader.ReadBoolean(); + return roleOptionsData; + } + + public void Serialize(IMessageWriter writer) + { + writer.WritePacked(RoleRates.Count); + foreach (var roleRate in RoleRates) + { + writer.Write((ushort)roleRate.Key); + writer.Write((byte)roleRate.Value.MaxCount); + writer.Write((byte)roleRate.Value.Chance); + } + + writer.Write(ShapeshifterLeaveSkin); + writer.Write((byte)ShapeshifterCooldown); + writer.Write((byte)ShapeshifterDuration); + writer.Write((byte)ScientistCooldown); + writer.Write((byte)GuardianAngelCooldown); + writer.Write((byte)EngineerCooldown); + writer.Write((byte)EngineerInVentMaxTime); + writer.Write((byte)ScientistBatteryCharge); + writer.Write((byte)ProtectionDurationSeconds); + writer.Write(ImpostorsCanSeeProtect); + } + + public void Serialize(BinaryWriter writer) + { + writer.Write(RoleRates.Count); + foreach (var roleRate in RoleRates) + { + writer.Write((ushort)roleRate.Key); + writer.Write((byte)roleRate.Value.MaxCount); + writer.Write((byte)roleRate.Value.Chance); + } + + writer.Write(ShapeshifterLeaveSkin); + writer.Write((byte)ShapeshifterCooldown); + writer.Write((byte)ShapeshifterDuration); + writer.Write((byte)ScientistCooldown); + writer.Write((byte)GuardianAngelCooldown); + writer.Write((byte)EngineerCooldown); + writer.Write((byte)EngineerInVentMaxTime); + writer.Write((byte)ScientistBatteryCharge); + writer.Write((byte)ProtectionDurationSeconds); + writer.Write(ImpostorsCanSeeProtect); + } + + public readonly struct RoleRate + { + public readonly int MaxCount; + public readonly int Chance; + + public RoleRate(int maxCount, int chance) + { + MaxCount = maxCount; + Chance = chance; + } + } + } +} diff --git a/src/Impostor.Api/Innersloth/RoleTypes.cs b/src/Impostor.Api/Innersloth/RoleTypes.cs new file mode 100644 index 0000000..01b8778 --- /dev/null +++ b/src/Impostor.Api/Innersloth/RoleTypes.cs @@ -0,0 +1,12 @@ +namespace Impostor.Api.Innersloth +{ + public enum RoleTypes : ushort + { + Crewmate, + Impostor, + Scientist, + Engineer, + GuardianAngel, + Shapeshifter, + } +} diff --git a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs index 711f878..62beee0 100644 --- a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs +++ b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs @@ -45,29 +45,29 @@ namespace Impostor.Api.Net.Inner.Objects /// Task that must be awaited. ValueTask SetColorAsync(ColorType colorType); - /// - /// Sets the hat of the current . - /// Visible to all players. - /// - /// An hat for the player. - /// Task that must be awaited. - ValueTask SetHatAsync(HatType hatType); - - /// - /// Sets the pet of the current . - /// Visible to all players. - /// - /// A pet for the player. - /// Task that must be awaited. - ValueTask SetPetAsync(PetType petType); - - /// - /// Sets the skin of the current . - /// Visible to all players. - /// - /// A skin for the player. - /// Task that must be awaited. - ValueTask SetSkinAsync(SkinType skinType); + // /// + // /// Sets the hat of the current . + // /// Visible to all players. + // /// + // /// An hat for the player. + // /// Task that must be awaited. + // ValueTask SetHatAsync(string hatId); + // + // /// + // /// Sets the pet of the current . + // /// Visible to all players. + // /// + // /// A pet for the player. + // /// Task that must be awaited. + // ValueTask SetPetAsync(string petId); + // + // /// + // /// Sets the skin of the current . + // /// Visible to all players. + // /// + // /// A skin for the player. + // /// Task that must be awaited. + // ValueTask SetSkinAsync(string skinId); /// /// Send a chat message as the current . diff --git a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs index 310755e..6bf5c44 100644 --- a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs +++ b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs @@ -12,26 +12,6 @@ namespace Impostor.Api.Net.Inner.Objects /// string PlayerName { get; } - /// - /// Gets the color of the player. - /// - ColorType Color { get; } - - /// - /// Gets the hat of the player. - /// - HatType Hat { get; } - - /// - /// Gets the pet of the player. - /// - PetType Pet { get; } - - /// - /// Gets the skin of the player. - /// - SkinType Skin { get; } - /// /// Gets a value indicating whether the player is an impostor. /// @@ -42,6 +22,12 @@ namespace Impostor.Api.Net.Inner.Objects /// bool IsDead { get; } + Dictionary Outfits { get; } + + PlayerOutfitType CurrentOutfitType { get; set; } + + PlayerOutfit CurrentOutfit { get; } + /// /// Gets the reason why the player is dead in the current game. /// diff --git a/src/Impostor.Api/Net/Inner/RpcCalls.cs b/src/Impostor.Api/Net/Inner/RpcCalls.cs index 1fe2327..2067a5b 100644 --- a/src/Impostor.Api/Net/Inner/RpcCalls.cs +++ b/src/Impostor.Api/Net/Inner/RpcCalls.cs @@ -11,15 +11,12 @@ SetName = 6, CheckColor = 7, SetColor = 8, - SetHat = 9, - SetSkin = 10, ReportDeadBody = 11, MurderPlayer = 12, SendChat = 13, StartMeeting = 14, SetScanner = 15, SendChatNote = 16, - SetPet = 17, SetStartCounter = 18, EnterVent = 19, ExitVent = 20, @@ -37,5 +34,16 @@ SendQuickChat = 33, BootFromVent = 34, UpdateSystem = 35, + SetLevel = 38, + SetHat = 39, + SetSkin = 40, + SetPet = 41, + SetVisor = 42, + SetNamePlate = 43, + SetRole = 44, + ProtectPlayer = 45, + Shapeshift = 46, + CheckMurder = 47, + CheckProtect = 48, } } diff --git a/src/Impostor.Api/Net/Messages/C2S/HandshakeC2S.cs b/src/Impostor.Api/Net/Messages/C2S/HandshakeC2S.cs index 83fd647..60dd4e1 100644 --- a/src/Impostor.Api/Net/Messages/C2S/HandshakeC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/HandshakeC2S.cs @@ -4,18 +4,14 @@ 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, out Language language, out QuickChatModes chatMode) + public static void Deserialize(IMessageReader reader, out int clientVersion, out string name, out Language language, out QuickChatModes chatMode, out PlatformSpecificData? platformSpecificData) { clientVersion = reader.ReadInt32(); name = reader.ReadString(); if (clientVersion >= Version.V1) { - lastNonceReceived = reader.ReadUInt32(); - } - else - { - lastNonceReceived = null; + reader.ReadUInt32(); // lastNonceReceived, always 0 since 2021.11.9 } if (clientVersion >= Version.V2) @@ -28,6 +24,17 @@ namespace Impostor.Api.Net.Messages.C2S language = Language.English; chatMode = QuickChatModes.FreeChatOrQuickChat; } + + if (clientVersion >= Version.V3) + { + using var platformReader = reader.ReadMessage(); + platformSpecificData = new PlatformSpecificData(platformReader); + reader.ReadInt32(); // crossplayFlags, not used yet + } + else + { + platformSpecificData = null; + } } private static class Version @@ -35,6 +42,8 @@ namespace Impostor.Api.Net.Messages.C2S public static readonly int V1 = GameVersion.GetVersion(2021, 4, 25); public static readonly int V2 = GameVersion.GetVersion(2021, 6, 30); + + public static readonly int V3 = GameVersion.GetVersion(2021, 11, 9); } } } diff --git a/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs index 2a61a18..87f32e9 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs @@ -8,6 +8,7 @@ namespace Impostor.Api.Net.Messages.C2S { writer.StartMessage(MessageFlags.HostGame); gameOptionsData.Serialize(writer); + writer.Write(int.MaxValue); // crossplayFlags writer.EndMessage(); } @@ -15,12 +16,11 @@ namespace Impostor.Api.Net.Messages.C2S /// Deserialize a packet. /// /// with 0. - /// The chat type selected in the client of the player. /// Deserialized . - public static GameOptionsData Deserialize(IMessageReader reader, out QuickChatModes chatMode) + public static GameOptionsData Deserialize(IMessageReader reader) { var gameOptionsData = GameOptionsData.DeserializeCreate(reader); - chatMode = (QuickChatModes)reader.ReadByte(); + reader.ReadInt32(); // crossplayFlags, not used yet return gameOptionsData; } diff --git a/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs index e7771e7..9c91ac1 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs @@ -13,6 +13,7 @@ namespace Impostor.Api.Net.Messages.C2S public static void Deserialize(IMessageReader reader, out GameCode gameCode) { gameCode = reader.ReadInt32(); + reader.ReadBoolean(); // no crossplay } } } diff --git a/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs index 0123767..13c02ae 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs @@ -12,9 +12,15 @@ namespace Impostor.Api.Net.Messages.C2S public static void Deserialize(IMessageReader reader, out GameOptionsData options, out QuickChatModes chatMode) { - reader.ReadPackedInt32(); // Hardcoded 0. + var version = reader.ReadPackedInt32(); + if (version != 2) + { + throw new NotSupportedException($"Version {version} of {nameof(Message16GetGameListC2S)} is not supported"); + } + options = GameOptionsData.DeserializeCreate(reader); chatMode = (QuickChatModes)reader.ReadByte(); + reader.ReadInt32(); // crossplayFlags, not used yet } } } diff --git a/src/Impostor.Api/Net/Messages/IMessageReader.cs b/src/Impostor.Api/Net/Messages/IMessageReader.cs index 397ad5a..7d6c25d 100644 --- a/src/Impostor.Api/Net/Messages/IMessageReader.cs +++ b/src/Impostor.Api/Net/Messages/IMessageReader.cs @@ -48,6 +48,10 @@ namespace Impostor.Api.Net.Messages int ReadInt32(); + ulong ReadUInt64(); + + long ReadInt64(); + float ReadSingle(); string ReadString(int length); diff --git a/src/Impostor.Api/Net/Messages/IMessageWriter.cs b/src/Impostor.Api/Net/Messages/IMessageWriter.cs index 346e6e4..9ee85d0 100644 --- a/src/Impostor.Api/Net/Messages/IMessageWriter.cs +++ b/src/Impostor.Api/Net/Messages/IMessageWriter.cs @@ -68,6 +68,18 @@ namespace Impostor.Api.Net.Messages /// Value to write. void Write(int value); + /// + /// Writes an ulong to the message. + /// + /// Value to write. + public void Write(ulong value); + + /// + /// Writes an ulong to the message. + /// + /// Value to write. + public void Write(long value); + /// /// Writes a float to the message. /// diff --git a/src/Impostor.Api/Net/Messages/MessageFlags.cs b/src/Impostor.Api/Net/Messages/MessageFlags.cs index 2ebf475..a7f5272 100644 --- a/src/Impostor.Api/Net/Messages/MessageFlags.cs +++ b/src/Impostor.Api/Net/Messages/MessageFlags.cs @@ -16,7 +16,13 @@ public const byte WaitForHost = 12; public const byte Redirect = 13; public const byte ReselectServer = 14; - public const byte GetGameList = 9; public const byte GetGameListV2 = 16; + public const byte ReportPlayer = 17; + public const byte QuickMatch = 18; + public const byte QuickMatchHost = 19; + public const byte SetGameSession = 20; + public const byte SetActivePodType = 21; + public const byte QueryPlatformIds = 22; + public const byte QueryLobbyInfo = 23; } } diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc09SetHat.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc09SetHat.cs deleted file mode 100644 index caa9ff7..0000000 --- a/src/Impostor.Api/Net/Messages/Rpcs/Rpc09SetHat.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Impostor.Api.Innersloth.Customization; - -namespace Impostor.Api.Net.Messages.Rpcs -{ - public static class Rpc09SetHat - { - public static void Serialize(IMessageWriter writer, HatType hat) - { - writer.WritePacked((uint)hat); - } - - public static void Deserialize(IMessageReader reader, out HatType hat) - { - hat = (HatType)reader.ReadPackedUInt32(); - } - } -} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc10SetSkin.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc10SetSkin.cs deleted file mode 100644 index e57eeff..0000000 --- a/src/Impostor.Api/Net/Messages/Rpcs/Rpc10SetSkin.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Impostor.Api.Innersloth.Customization; - -namespace Impostor.Api.Net.Messages.Rpcs -{ - public static class Rpc10SetSkin - { - public static void Serialize(IMessageWriter writer, SkinType skin) - { - writer.WritePacked((uint)skin); - } - - public static void Deserialize(IMessageReader reader, out SkinType skin) - { - skin = (SkinType)reader.ReadPackedUInt32(); - } - } -} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc17SetPet.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc17SetPet.cs deleted file mode 100644 index be67df5..0000000 --- a/src/Impostor.Api/Net/Messages/Rpcs/Rpc17SetPet.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Impostor.Api.Innersloth.Customization; - -namespace Impostor.Api.Net.Messages.Rpcs -{ - public static class Rpc17SetPet - { - public static void Serialize(IMessageWriter writer, PetType pet) - { - writer.WritePacked((uint)pet); - } - - public static void Deserialize(IMessageReader reader, out PetType pet) - { - pet = (PetType)reader.ReadPackedUInt32(); - } - } -} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc39SetHat.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc39SetHat.cs new file mode 100644 index 0000000..6aa1399 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc39SetHat.cs @@ -0,0 +1,15 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc39SetHat + { + public static void Serialize(IMessageWriter writer, string hat) + { + writer.Write(hat); + } + + public static void Deserialize(IMessageReader reader, out string hat) + { + hat = reader.ReadString(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc40SetSkin.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc40SetSkin.cs new file mode 100644 index 0000000..929dab2 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc40SetSkin.cs @@ -0,0 +1,15 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc40SetSkin + { + public static void Serialize(IMessageWriter writer, string skin) + { + writer.Write(skin); + } + + public static void Deserialize(IMessageReader reader, out string skin) + { + skin = reader.ReadString(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc41SetPet.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc41SetPet.cs new file mode 100644 index 0000000..a3ddde1 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc41SetPet.cs @@ -0,0 +1,15 @@ +namespace Impostor.Api.Net.Messages.Rpcs +{ + public static class Rpc41SetPet + { + public static void Serialize(IMessageWriter writer, string pet) + { + writer.Write(pet); + } + + public static void Deserialize(IMessageReader reader, out string pet) + { + pet = reader.ReadString(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/S2C/MessageDisconnect.cs b/src/Impostor.Api/Net/Messages/S2C/MessageDisconnect.cs index 8dd5c7f..3e334bc 100644 --- a/src/Impostor.Api/Net/Messages/S2C/MessageDisconnect.cs +++ b/src/Impostor.Api/Net/Messages/S2C/MessageDisconnect.cs @@ -39,7 +39,7 @@ namespace Impostor.Api.Net.Messages.S2C if (hasReason) { - var inner = reader.ReadMessage(); + using var inner = reader.ReadMessage(); reason = (DisconnectReason)inner.ReadByte(); message = reason == DisconnectReason.Custom ? inner.ReadString() : null; } diff --git a/src/Impostor.Hazel b/src/Impostor.Hazel index 8de0274..74070b8 160000 --- a/src/Impostor.Hazel +++ b/src/Impostor.Hazel @@ -1 +1 @@ -Subproject commit 8de027461e59af67fb9dc0d9b925a88ad4a01d26 +Subproject commit 74070b8c0798f9a8889d65d3bf5b54f2ef55f4c3 diff --git a/src/Impostor.Server/Net/Client.cs b/src/Impostor.Server/Net/Client.cs index e755a1c..7e42f61 100644 --- a/src/Impostor.Server/Net/Client.cs +++ b/src/Impostor.Server/Net/Client.cs @@ -24,8 +24,8 @@ namespace Impostor.Server.Net private readonly GameManager _gameManager; private readonly ICustomMessageManager _customMessageManager; - public Client(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, GameManager gameManager, ICustomMessageManager customMessageManager, string name, int gameVersion, Language language, QuickChatModes chatMode, IHazelConnection connection) - : base(name, gameVersion, language, chatMode, connection) + public Client(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, GameManager gameManager, ICustomMessageManager customMessageManager, string name, int gameVersion, Language language, QuickChatModes chatMode, PlatformSpecificData platformSpecificData, IHazelConnection connection) + : base(name, gameVersion, language, chatMode, platformSpecificData, connection) { _logger = logger; _antiCheatConfig = antiCheatOptions.Value; @@ -64,7 +64,7 @@ namespace Impostor.Server.Net case MessageFlags.HostGame: { // Read game settings. - var gameInfo = Message00HostGameC2S.Deserialize(reader, out _); + var gameInfo = Message00HostGameC2S.Deserialize(reader); // Create game. var game = await _gameManager.CreateAsync(this, gameInfo); diff --git a/src/Impostor.Server/Net/ClientBase.cs b/src/Impostor.Server/Net/ClientBase.cs index c1a6382..74224fc 100644 --- a/src/Impostor.Server/Net/ClientBase.cs +++ b/src/Impostor.Server/Net/ClientBase.cs @@ -13,12 +13,13 @@ namespace Impostor.Server.Net { internal abstract class ClientBase : IClient { - protected ClientBase(string name, int gameVersion, Language language, QuickChatModes chatMode, IHazelConnection connection) + protected ClientBase(string name, int gameVersion, Language language, QuickChatModes chatMode, PlatformSpecificData platformSpecificData, IHazelConnection connection) { Name = name; GameVersion = gameVersion; Language = language; ChatMode = chatMode; + PlatformSpecificData = platformSpecificData; Connection = connection; Items = new ConcurrentDictionary(); } @@ -31,6 +32,8 @@ namespace Impostor.Server.Net public QuickChatModes ChatMode { get; } + public PlatformSpecificData PlatformSpecificData { get; } + public int GameVersion { get; } public IHazelConnection Connection { get; } diff --git a/src/Impostor.Server/Net/Factories/ClientFactory.cs b/src/Impostor.Server/Net/Factories/ClientFactory.cs index 09e55d9..5a7e666 100644 --- a/src/Impostor.Server/Net/Factories/ClientFactory.cs +++ b/src/Impostor.Server/Net/Factories/ClientFactory.cs @@ -15,9 +15,9 @@ namespace Impostor.Server.Net.Factories _serviceProvider = serviceProvider; } - public ClientBase Create(IHazelConnection connection, string name, int clientVersion, Language language, QuickChatModes chatMode) + public ClientBase Create(IHazelConnection connection, string name, int clientVersion, Language language, QuickChatModes chatMode, PlatformSpecificData platformSpecificData) { - var client = ActivatorUtilities.CreateInstance(_serviceProvider, name, clientVersion, language, chatMode, connection); + var client = ActivatorUtilities.CreateInstance(_serviceProvider, name, clientVersion, language, chatMode, platformSpecificData, connection); connection.Client = client; return client; } diff --git a/src/Impostor.Server/Net/Factories/IClientFactory.cs b/src/Impostor.Server/Net/Factories/IClientFactory.cs index d0d392d..ccccb33 100644 --- a/src/Impostor.Server/Net/Factories/IClientFactory.cs +++ b/src/Impostor.Server/Net/Factories/IClientFactory.cs @@ -5,6 +5,6 @@ namespace Impostor.Server.Net.Factories { internal interface IClientFactory { - ClientBase Create(IHazelConnection connection, string name, int clientVersion, Language language, QuickChatModes chatMode); + ClientBase Create(IHazelConnection connection, string name, int clientVersion, Language language, QuickChatModes chatMode, PlatformSpecificData platformSpecificData); } } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs index 86633e4..001ecf8 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerMeetingHud.cs @@ -125,6 +125,10 @@ namespace Impostor.Server.Net.Inner.Objects } Rpc23VotingComplete.Deserialize(reader, out var states, out var playerId, out var tie); + foreach (var messageReader in states) + { + messageReader.Dispose(); + } // This would be a nice place to implement an anti cheat. // But for whatever reason host sends VotingComplete before sending his vote. diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs index 8804bee..c2fb8ce 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs @@ -29,40 +29,13 @@ namespace Impostor.Server.Net.Inner.Objects public async ValueTask SetColorAsync(ColorType color) { - PlayerInfo.Color = color; + PlayerInfo.CurrentOutfit.Color = color; using var writer = Game.StartRpc(NetId, RpcCalls.SetColor); Rpc08SetColor.Serialize(writer, color); await Game.FinishRpcAsync(writer); } - public async ValueTask SetHatAsync(HatType hat) - { - PlayerInfo.Hat = hat; - - using var writer = Game.StartRpc(NetId, RpcCalls.SetHat); - Rpc09SetHat.Serialize(writer, hat); - await Game.FinishRpcAsync(writer); - } - - public async ValueTask SetPetAsync(PetType pet) - { - PlayerInfo.Pet = pet; - - using var writer = Game.StartRpc(NetId, RpcCalls.SetPet); - Rpc17SetPet.Serialize(writer, pet); - await Game.FinishRpcAsync(writer); - } - - public async ValueTask SetSkinAsync(SkinType skin) - { - PlayerInfo.Skin = skin; - - using var writer = Game.StartRpc(NetId, RpcCalls.SetSkin); - Rpc10SetSkin.Serialize(writer, skin); - await Game.FinishRpcAsync(writer); - } - public async ValueTask SendChatAsync(string text) { using var writer = Game.StartRpc(NetId, RpcCalls.SendChat); diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs index 8de79ed..8969d5e 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs @@ -182,8 +182,8 @@ namespace Impostor.Server.Net.Inner.Objects return false; } - Rpc09SetHat.Deserialize(reader, out var hat); - return await HandleSetHat(sender, hat); + Rpc39SetHat.Deserialize(reader, out var hat); + return true; } case RpcCalls.SetSkin: @@ -193,8 +193,41 @@ namespace Impostor.Server.Net.Inner.Objects return false; } - Rpc10SetSkin.Deserialize(reader, out var skin); - return await HandleSetSkin(sender, skin); + Rpc40SetSkin.Deserialize(reader, out var skin); + return true; + } + + case RpcCalls.SetVisor: + { + if (!await ValidateOwnership(call, sender)) + { + return false; + } + + // Rpc42SetVistor.Deserialize(reader, out var visor); + return true; + } + + case RpcCalls.SetNamePlate: + { + if (!await ValidateOwnership(call, sender)) + { + return false; + } + + // Rpc43SetNamePlate.Deserialize(reader, out var namePlate); + return true; + } + + case RpcCalls.SetLevel: + { + if (!await ValidateOwnership(call, sender)) + { + return false; + } + + // Rpc38SetLevel.Deserialize(reader, out var level); + return true; } case RpcCalls.ReportDeadBody: @@ -271,8 +304,9 @@ namespace Impostor.Server.Net.Inner.Objects return false; } - Rpc17SetPet.Deserialize(reader, out var pet); - return await HandleSetPet(sender, pet); + Rpc41SetPet.Deserialize(reader, out var pet); + return true; + // return await HandleSetPet(sender, pet); } case RpcCalls.SetStartCounter: @@ -343,7 +377,7 @@ namespace Impostor.Server.Net.Inner.Objects var player = Game.GameNet.GameData!.GetPlayerById(infectedIds.Span[i]); if (player != null) { - player.IsImpostor = true; + // player.IsImpostor = true; } } @@ -479,7 +513,7 @@ namespace Impostor.Server.Net.Inner.Objects if (sender.IsOwner(this)) { - if (Game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.Color == color)) + if (Game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.CurrentOutfit.Color == color)) { if (await sender.Client.ReportCheatAsync(RpcCalls.SetColor, "Client sent a color that is already used")) { @@ -497,7 +531,7 @@ namespace Impostor.Server.Net.Inner.Objects var expected = RequestedColorId.Dequeue(); - while (Game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.Color == expected)) + while (Game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.CurrentOutfit.Color == expected)) { expected = (ColorType)(((byte)expected + 1) % ColorsCount); } @@ -510,34 +544,34 @@ namespace Impostor.Server.Net.Inner.Objects } } - PlayerInfo.Color = color; - - return true; - } - - private async ValueTask HandleSetHat(ClientPlayer sender, HatType hat) - { - if (Game.GameState == GameStates.Started && await sender.Client.ReportCheatAsync(RpcCalls.SetHat, "Client tried to change hat while not in lobby")) - { - return false; - } - - PlayerInfo.Hat = hat; + PlayerInfo.CurrentOutfit.Color = color; return true; } - private async ValueTask HandleSetSkin(ClientPlayer sender, SkinType skin) - { - if (Game.GameState == GameStates.Started && await sender.Client.ReportCheatAsync(RpcCalls.SetSkin, "Client tried to change skin while not in lobby")) - { - return false; - } - - PlayerInfo.Skin = skin; - - return true; - } + // private async ValueTask HandleSetHat(ClientPlayer sender, HatType hat) + // { + // if (Game.GameState == GameStates.Started && await sender.Client.ReportCheatAsync(RpcCalls.SetHat, "Client tried to change hat while not in lobby")) + // { + // return false; + // } + // + // PlayerInfo.Hat = hat; + // + // return true; + // } + // + // private async ValueTask HandleSetSkin(ClientPlayer sender, SkinType skin) + // { + // if (Game.GameState == GameStates.Started && await sender.Client.ReportCheatAsync(RpcCalls.SetSkin, "Client tried to change skin while not in lobby")) + // { + // return false; + // } + // + // PlayerInfo.Skin = skin; + // + // return true; + // } private async ValueTask HandleMurderPlayer(ClientPlayer sender, IInnerPlayerControl? target) { @@ -582,17 +616,17 @@ namespace Impostor.Server.Net.Inner.Objects await _eventManager.CallAsync(new PlayerStartMeetingEvent(Game, Game.GetClientPlayer(this.OwnerId)!, this, deadPlayer)); } - private async ValueTask HandleSetPet(ClientPlayer sender, PetType pet) - { - if (Game.GameState == GameStates.Started && await sender.Client.ReportCheatAsync(RpcCalls.SetPet, "Client tried to change pet while not in lobby")) - { - return false; - } - - PlayerInfo.Pet = pet; - - return true; - } + // private async ValueTask HandleSetPet(ClientPlayer sender, PetType pet) + // { + // if (Game.GameState == GameStates.Started && await sender.Client.ReportCheatAsync(RpcCalls.SetPet, "Client tried to change pet while not in lobby")) + // { + // return false; + // } + // + // PlayerInfo.Pet = pet; + // + // return true; + // } private async ValueTask HandleSetStartCounter(ClientPlayer sender, int sequenceId, sbyte startCounter) { diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs index 28221cc..553ddda 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs @@ -21,17 +21,20 @@ namespace Impostor.Server.Net.Inner.Objects public string PlayerName { get; internal set; } = string.Empty; - public ColorType Color { get; internal set; } = (ColorType)(-1); + public Dictionary Outfits { get; } = new() + { + [PlayerOutfitType.Default] = new PlayerOutfit(), + }; - public HatType Hat { get; internal set; } + public PlayerOutfitType CurrentOutfitType { get; set; } = PlayerOutfitType.Default; - public PetType Pet { get; internal set; } + public PlayerOutfit CurrentOutfit => Outfits[CurrentOutfitType]; - public SkinType Skin { get; internal set; } + public RoleTypes RoleType { get; internal set; } public bool Disconnected { get; internal set; } - public bool IsImpostor { get; internal set; } + public bool IsImpostor => RoleType is RoleTypes.Impostor or RoleTypes.Shapeshifter; public bool IsDead { get; internal set; } @@ -58,16 +61,23 @@ namespace Impostor.Server.Net.Inner.Objects public void Deserialize(IMessageReader reader) { - PlayerName = reader.ReadString(); - Color = (ColorType)reader.ReadPackedInt32(); - Hat = (HatType)reader.ReadPackedUInt32(); - Pet = (PetType)reader.ReadPackedUInt32(); - Skin = (SkinType)reader.ReadPackedUInt32(); + Outfits.Clear(); + var b = reader.ReadByte(); + for (var i = 0; i < b; i++) + { + var key = (PlayerOutfitType)reader.ReadByte(); + Outfits[key] = new PlayerOutfit(); + Outfits[key].Deserialize(reader); + } + + var PlayerLevel = reader.ReadPackedUInt32(); var flag = reader.ReadByte(); - Disconnected = (flag & 1) > 0; - IsImpostor = (flag & 2) > 0; - IsDead = (flag & 4) > 0; + Disconnected = (flag & 1) != 0; + IsDead = (flag & 4) != 0; + + var roleType = (RoleTypes)reader.ReadUInt16(); + // Role = roleType; var taskCount = reader.ReadByte(); diff --git a/src/Impostor.Server/Net/Manager/ClientManager.cs b/src/Impostor.Server/Net/Manager/ClientManager.cs index 63e3498..0c1c2f1 100644 --- a/src/Impostor.Server/Net/Manager/ClientManager.cs +++ b/src/Impostor.Server/Net/Manager/ClientManager.cs @@ -22,7 +22,7 @@ namespace Impostor.Server.Net.Manager // NOTE: when updating this array, keep the versions ordered from old to new, otherwise the version compare logic doesn't work properly private static readonly int[] SupportedVersions = { - GameVersion.GetVersion(2021, 6, 30), // 2021.6.30 + GameVersion.GetVersion(2021, 11, 9), // 2021.11.9 }; private readonly ILogger _logger; @@ -65,10 +65,10 @@ namespace Impostor.Server.Net.Manager return clientId; } - public async ValueTask RegisterConnectionAsync(IHazelConnection connection, string name, int clientVersion, Language language, QuickChatModes chatMode) + public async ValueTask RegisterConnectionAsync(IHazelConnection connection, string name, int clientVersion, Language language, QuickChatModes chatMode, PlatformSpecificData? platformSpecificData) { var versionCompare = CompareVersion(clientVersion); - if (versionCompare != VersionCompareResult.Compatible) + if (versionCompare != VersionCompareResult.Compatible || platformSpecificData == null) { GameVersion.ParseVersion(clientVersion, out var year, out var month, out var day, out var revision); _logger.LogTrace("Client connected using unsupported version: {clientVersion} ({version})", clientVersion, $"{year}.{month}.{day}{(revision == 0 ? string.Empty : "." + revision)}"); @@ -105,7 +105,7 @@ namespace Impostor.Server.Net.Manager return; } - var client = _clientFactory.Create(connection, name, clientVersion, language, chatMode); + var client = _clientFactory.Create(connection, name, clientVersion, language, chatMode, platformSpecificData); var id = NextId(); client.Id = id; diff --git a/src/Impostor.Server/Net/Matchmaker.cs b/src/Impostor.Server/Net/Matchmaker.cs index 3e9b1d0..a8682bf 100644 --- a/src/Impostor.Server/Net/Matchmaker.cs +++ b/src/Impostor.Server/Net/Matchmaker.cs @@ -62,14 +62,14 @@ namespace Impostor.Server.Net private async ValueTask OnNewConnection(NewConnectionEventArgs e) { // Handshake. - HandshakeC2S.Deserialize(e.HandshakeData, out var clientVersion, out var name, out _, out var language, out var chatMode); + HandshakeC2S.Deserialize(e.HandshakeData, out var clientVersion, out var name, out var language, out var chatMode, out var platformSpecificData); var connection = new HazelConnection(e.Connection, _connectionLogger); await _eventManager.CallAsync(new ClientConnectionEvent(connection, e.HandshakeData)); // Register client - await _clientManager.RegisterConnectionAsync(connection, name, clientVersion, language, chatMode); + await _clientManager.RegisterConnectionAsync(connection, name, clientVersion, language, chatMode, platformSpecificData); } } } diff --git a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs index 4503648..a96ca73 100644 --- a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs +++ b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs @@ -24,11 +24,12 @@ namespace Impostor.Server.Net.Redirector int gameVersion, Language language, QuickChatModes chatMode, + PlatformSpecificData platformSpecificData, HazelConnection connection, ClientManager clientManager, INodeProvider nodeProvider, INodeLocator nodeLocator) - : base(name, gameVersion, language, chatMode, connection) + : base(name, gameVersion, language, chatMode, platformSpecificData, connection) { _clientManager = clientManager; _nodeProvider = nodeProvider; diff --git a/src/Impostor.Server/Recorder/ClientRecorder.cs b/src/Impostor.Server/Recorder/ClientRecorder.cs index 20fa59e..4acf2a5 100644 --- a/src/Impostor.Server/Recorder/ClientRecorder.cs +++ b/src/Impostor.Server/Recorder/ClientRecorder.cs @@ -18,8 +18,8 @@ namespace Impostor.Server.Recorder private bool _createdGame; private bool _recordAfter; - public ClientRecorder(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, ICustomMessageManager customMessageManager, GameManager gameManager, string name, int gameVersion, Language language, QuickChatModes chatMode, HazelConnection connection, PacketRecorder recorder) - : base(logger, antiCheatOptions, clientManager, gameManager, customMessageManager, name, gameVersion, language, chatMode, connection) + public ClientRecorder(ILogger logger, IOptions antiCheatOptions, ClientManager clientManager, ICustomMessageManager customMessageManager, GameManager gameManager, string name, int gameVersion, Language language, QuickChatModes chatMode, PlatformSpecificData platformSpecificData, HazelConnection connection, PacketRecorder recorder) + : base(logger, antiCheatOptions, clientManager, gameManager, customMessageManager, name, gameVersion, language, chatMode, platformSpecificData, connection) { _recorder = recorder; _isFirst = true;