mirror of
https://github.com/Impostor/Impostor.git
synced 2026-10-20 01:46:11 +00:00
Merge pull request #442 from Impostor/2021.11.9
2021.11.9 and 2021.12.14 support
This commit is contained in:
77 files changed
+819
-872
No files matched your search
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>1.6.0</VersionPrefix>
|
||||
<VersionPrefix>1.7.0</VersionPrefix>
|
||||
<VersionSuffix>dev</VersionSuffix>
|
||||
<EnforceCodeStyleInBuild Condition="$(MSBuildProjectName)!='Hazel'">true</EnforceCodeStyleInBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
using Impostor.Api.Innersloth;
|
||||
|
||||
namespace Impostor.Api.Events.Announcements
|
||||
{
|
||||
/// <summary>
|
||||
/// Event fired after client requests a announcement.
|
||||
/// </summary>
|
||||
public interface IAnnouncementRequestEvent : IEvent
|
||||
{
|
||||
public interface IResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether announcement should be loaded from client's cache, can save some bytes.
|
||||
/// </summary>
|
||||
public bool UseCached { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets announcement, should be null when <see cref="UseCached" /> is set to true.
|
||||
/// </summary>
|
||||
public Announcement? Announcement { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets client's last announcement id.
|
||||
/// </summary>
|
||||
public int Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets client's language.
|
||||
/// </summary>
|
||||
public Language Language { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets plugin made response.
|
||||
/// </summary>
|
||||
public IResponse Response { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,13 @@ namespace Impostor.Api
|
||||
return original[0];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static short ReadInt16(this ref ReadOnlySpan<byte> input)
|
||||
{
|
||||
var original = Advance<short>(ref input);
|
||||
return BinaryPrimitives.ReadInt16LittleEndian(original);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int ReadInt32(this ref ReadOnlySpan<byte> input)
|
||||
{
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
namespace Impostor.Api.Innersloth
|
||||
{
|
||||
public readonly struct Announcement
|
||||
{
|
||||
public readonly int Id;
|
||||
public readonly string Message;
|
||||
|
||||
public Announcement(int id, string message)
|
||||
{
|
||||
Id = id;
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Impostor.Api.Innersloth.Customization
|
||||
{
|
||||
public enum PlayerOutfitType
|
||||
{
|
||||
Default,
|
||||
Shapeshifted,
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace Impostor.Api.Innersloth
|
||||
/// <summary>
|
||||
/// The latest major version of the game client.
|
||||
/// </summary>
|
||||
public const int LatestVersion = 4;
|
||||
public const int LatestVersion = 5;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets host's version of the game.
|
||||
@@ -124,6 +124,11 @@ namespace Impostor.Api.Innersloth
|
||||
/// </summary>
|
||||
public TaskBarUpdate TaskBarUpdate { get; set; } = TaskBarUpdate.Always;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets role options.
|
||||
/// </summary>
|
||||
public RoleOptionsData RoleOptions { get; set; } = new RoleOptionsData();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the GameOptions are the default ones.
|
||||
/// </summary>
|
||||
@@ -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}.");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using Impostor.Api.Net.Messages;
|
||||
|
||||
namespace Impostor.Api.Innersloth
|
||||
{
|
||||
public class PlatformSpecificData
|
||||
{
|
||||
public PlatformSpecificData(Platforms platform, string platformName, ulong? xboxPlatformId = null, ulong? psnPlatformId = null)
|
||||
{
|
||||
Platform = platform;
|
||||
PlatformName = platformName;
|
||||
XboxPlatformId = xboxPlatformId;
|
||||
PsnPlatformId = psnPlatformId;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,5 +11,7 @@ namespace Impostor.Api.Innersloth
|
||||
IPhone = 6,
|
||||
Android = 7,
|
||||
Switch = 8,
|
||||
Xbox = 9,
|
||||
Playstation = 10,
|
||||
}
|
||||
}
|
||||
@@ -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 byte ShapeshifterCooldown { get; set; } = 10;
|
||||
|
||||
public byte ShapeshifterDuration { get; set; } = 30;
|
||||
|
||||
public byte ScientistCooldown { get; set; } = 15;
|
||||
|
||||
public byte ScientistBatteryCharge { get; set; } = 5;
|
||||
|
||||
public byte GuardianAngelCooldown { get; set; } = 60;
|
||||
|
||||
public bool ImpostorsCanSeeProtect { get; set; }
|
||||
|
||||
public byte ProtectionDurationSeconds { get; set; } = 10;
|
||||
|
||||
public byte EngineerCooldown { get; set; } = 30;
|
||||
|
||||
public byte EngineerInVentMaxTime { get; set; } = 15;
|
||||
|
||||
public Dictionary<RoleTypes, RoleRate> RoleRates { get; } = new Dictionary<RoleTypes, RoleRate>();
|
||||
|
||||
public static RoleOptionsData Deserialize(ReadOnlySpan<byte> span)
|
||||
{
|
||||
var roleOptionsData = new RoleOptionsData();
|
||||
var num = span.ReadInt32();
|
||||
for (var i = 0; i < num; i++)
|
||||
{
|
||||
var key = (RoleTypes)span.ReadInt16();
|
||||
var roleRate = new RoleRate(span.ReadByte(), span.ReadByte());
|
||||
roleOptionsData.RoleRates[key] = roleRate;
|
||||
}
|
||||
|
||||
roleOptionsData.ShapeshifterLeaveSkin = span.ReadBoolean();
|
||||
roleOptionsData.ShapeshifterCooldown = span.ReadByte();
|
||||
roleOptionsData.ShapeshifterDuration = span.ReadByte();
|
||||
roleOptionsData.ScientistCooldown = span.ReadByte();
|
||||
roleOptionsData.GuardianAngelCooldown = span.ReadByte();
|
||||
roleOptionsData.EngineerCooldown = span.ReadByte();
|
||||
roleOptionsData.EngineerInVentMaxTime = span.ReadByte();
|
||||
roleOptionsData.ScientistBatteryCharge = span.ReadByte();
|
||||
roleOptionsData.ProtectionDurationSeconds = span.ReadByte();
|
||||
roleOptionsData.ImpostorsCanSeeProtect = span.ReadBoolean();
|
||||
return roleOptionsData;
|
||||
}
|
||||
|
||||
public static RoleOptionsData Deserialize(IMessageReader reader)
|
||||
{
|
||||
var roleOptionsData = new RoleOptionsData();
|
||||
var num = reader.ReadPackedInt32();
|
||||
for (var i = 0; i < num; i++)
|
||||
{
|
||||
var key = (RoleTypes)reader.ReadInt16();
|
||||
var roleRate = new RoleRate(reader.ReadByte(), reader.ReadByte());
|
||||
roleOptionsData.RoleRates[key] = roleRate;
|
||||
}
|
||||
|
||||
roleOptionsData.ShapeshifterLeaveSkin = reader.ReadBoolean();
|
||||
roleOptionsData.ShapeshifterCooldown = reader.ReadByte();
|
||||
roleOptionsData.ShapeshifterDuration = reader.ReadByte();
|
||||
roleOptionsData.ScientistCooldown = reader.ReadByte();
|
||||
roleOptionsData.GuardianAngelCooldown = reader.ReadByte();
|
||||
roleOptionsData.EngineerCooldown = reader.ReadByte();
|
||||
roleOptionsData.EngineerInVentMaxTime = reader.ReadByte();
|
||||
roleOptionsData.ScientistBatteryCharge = reader.ReadByte();
|
||||
roleOptionsData.ProtectionDurationSeconds = reader.ReadByte();
|
||||
roleOptionsData.ImpostorsCanSeeProtect = reader.ReadBoolean();
|
||||
return roleOptionsData;
|
||||
}
|
||||
|
||||
public void Serialize(IMessageWriter writer)
|
||||
{
|
||||
writer.WritePacked(RoleRates.Count);
|
||||
foreach (var roleRate in RoleRates)
|
||||
{
|
||||
writer.Write((ushort)roleRate.Key);
|
||||
writer.Write((byte)roleRate.Value.MaxCount);
|
||||
writer.Write((byte)roleRate.Value.Chance);
|
||||
}
|
||||
|
||||
writer.Write(ShapeshifterLeaveSkin);
|
||||
writer.Write(ShapeshifterCooldown);
|
||||
writer.Write(ShapeshifterDuration);
|
||||
writer.Write(ScientistCooldown);
|
||||
writer.Write(GuardianAngelCooldown);
|
||||
writer.Write(EngineerCooldown);
|
||||
writer.Write(EngineerInVentMaxTime);
|
||||
writer.Write(ScientistBatteryCharge);
|
||||
writer.Write(ProtectionDurationSeconds);
|
||||
writer.Write(ImpostorsCanSeeProtect);
|
||||
}
|
||||
|
||||
public void Serialize(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(RoleRates.Count);
|
||||
foreach (var roleRate in RoleRates)
|
||||
{
|
||||
writer.Write((ushort)roleRate.Key);
|
||||
writer.Write((byte)roleRate.Value.MaxCount);
|
||||
writer.Write((byte)roleRate.Value.Chance);
|
||||
}
|
||||
|
||||
writer.Write(ShapeshifterLeaveSkin);
|
||||
writer.Write(ShapeshifterCooldown);
|
||||
writer.Write(ShapeshifterDuration);
|
||||
writer.Write(ScientistCooldown);
|
||||
writer.Write(GuardianAngelCooldown);
|
||||
writer.Write(EngineerCooldown);
|
||||
writer.Write(EngineerInVentMaxTime);
|
||||
writer.Write(ScientistBatteryCharge);
|
||||
writer.Write(ProtectionDurationSeconds);
|
||||
writer.Write(ImpostorsCanSeeProtect);
|
||||
}
|
||||
|
||||
public readonly struct RoleRate
|
||||
{
|
||||
public readonly int MaxCount;
|
||||
public readonly int Chance;
|
||||
|
||||
public RoleRate(int maxCount, int chance)
|
||||
{
|
||||
MaxCount = maxCount;
|
||||
Chance = chance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Impostor.Api.Innersloth
|
||||
{
|
||||
public enum RoleTypes : ushort
|
||||
{
|
||||
Crewmate,
|
||||
Impostor,
|
||||
Scientist,
|
||||
Engineer,
|
||||
GuardianAngel,
|
||||
Shapeshifter,
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api.Innersloth;
|
||||
using Impostor.Api.Net.Messages;
|
||||
@@ -65,6 +65,11 @@ namespace Impostor.Api.Net
|
||||
/// </summary>
|
||||
IClientPlayer? Player { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets platform specific data of the <see cref="IClient" />.
|
||||
/// </summary>
|
||||
PlatformSpecificData PlatformSpecificData { get; }
|
||||
|
||||
ValueTask<bool> ReportCheatAsync(CheatContext context, string message);
|
||||
|
||||
ValueTask HandleMessageAsync(IMessageReader message, MessageType messageType);
|
||||
|
||||
@@ -49,25 +49,25 @@ namespace Impostor.Api.Net.Inner.Objects
|
||||
/// Sets the hat of the current <see cref="IInnerPlayerControl" />.
|
||||
/// Visible to all players.
|
||||
/// </summary>
|
||||
/// <param name="hatType">An hat for the player.</param>
|
||||
/// <param name="hatId">An hat for the player.</param>
|
||||
/// <returns>Task that must be awaited.</returns>
|
||||
ValueTask SetHatAsync(HatType hatType);
|
||||
ValueTask SetHatAsync(string hatId);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the pet of the current <see cref="IInnerPlayerControl" />.
|
||||
/// Visible to all players.
|
||||
/// </summary>
|
||||
/// <param name="petType">A pet for the player.</param>
|
||||
/// <param name="petId">A pet for the player.</param>
|
||||
/// <returns>Task that must be awaited.</returns>
|
||||
ValueTask SetPetAsync(PetType petType);
|
||||
ValueTask SetPetAsync(string petId);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the skin of the current <see cref="IInnerPlayerControl" />.
|
||||
/// Visible to all players.
|
||||
/// </summary>
|
||||
/// <param name="skinType">A skin for the player.</param>
|
||||
/// <param name="skinId">A skin for the player.</param>
|
||||
/// <returns>Task that must be awaited.</returns>
|
||||
ValueTask SetSkinAsync(SkinType skinType);
|
||||
ValueTask SetSkinAsync(string skinId);
|
||||
|
||||
/// <summary>
|
||||
/// Send a chat message as the current <see cref="IInnerPlayerControl" />.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Impostor.Api.Innersloth;
|
||||
using Impostor.Api.Innersloth.Customization;
|
||||
@@ -12,26 +12,6 @@ namespace Impostor.Api.Net.Inner.Objects
|
||||
/// </summary>
|
||||
string PlayerName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the color of the player.
|
||||
/// </summary>
|
||||
ColorType Color { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hat of the player.
|
||||
/// </summary>
|
||||
HatType Hat { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pet of the player.
|
||||
/// </summary>
|
||||
PetType Pet { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the skin of the player.
|
||||
/// </summary>
|
||||
SkinType Skin { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the player is an impostor.
|
||||
/// </summary>
|
||||
@@ -42,6 +22,12 @@ namespace Impostor.Api.Net.Inner.Objects
|
||||
/// </summary>
|
||||
bool IsDead { get; }
|
||||
|
||||
Dictionary<PlayerOutfitType, PlayerOutfit> Outfits { get; }
|
||||
|
||||
PlayerOutfitType CurrentOutfitType { get; set; }
|
||||
|
||||
PlayerOutfit CurrentOutfit { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reason why the player is dead in the current game.
|
||||
/// </summary>
|
||||
@@ -50,5 +36,7 @@ namespace Impostor.Api.Net.Inner.Objects
|
||||
IEnumerable<ITaskInfo> Tasks { get; }
|
||||
|
||||
DateTimeOffset LastMurder { get; }
|
||||
|
||||
uint PlayerLevel { get; }
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
namespace Impostor.Api.Net.Messages.Announcements
|
||||
{
|
||||
public static class Message00UseCache
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer)
|
||||
{
|
||||
writer.StartMessage(AnnouncementsMessageFlags.UseCache);
|
||||
writer.EndMessage();
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
namespace Impostor.Api.Net.Messages.Announcements
|
||||
{
|
||||
public static class Message01Update
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, int id, string message)
|
||||
{
|
||||
writer.StartMessage(AnnouncementsMessageFlags.SetUpdate);
|
||||
writer.WritePacked(id);
|
||||
writer.Write(message);
|
||||
writer.EndMessage();
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out int id, out string message)
|
||||
{
|
||||
id = reader.ReadPackedInt32();
|
||||
message = reader.ReadString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Impostor.Api.Net.Messages.Announcements
|
||||
{
|
||||
public static class Message04AddLanguages
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, Dictionary<string, uint> languages)
|
||||
{
|
||||
writer.StartMessage(AnnouncementsMessageFlags.AddLanguages);
|
||||
|
||||
writer.Write((byte)languages.Count);
|
||||
foreach (var (name, id) in languages)
|
||||
{
|
||||
writer.Write(name);
|
||||
writer.Write(id);
|
||||
}
|
||||
|
||||
writer.EndMessage();
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out Dictionary<string, uint> languages)
|
||||
{
|
||||
var length = reader.ReadByte();
|
||||
languages = new Dictionary<string, uint>(length);
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
languages[reader.ReadString()] = reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using Impostor.Api.Innersloth;
|
||||
|
||||
namespace Impostor.Api.Net.Messages.Announcements
|
||||
{
|
||||
public class MessageHello
|
||||
{
|
||||
public static void Deserialize(IMessageReader reader, out int announcementVersion, out int id, out Language language)
|
||||
{
|
||||
reader.ReadByte(); // SendOption header, probably added by accident
|
||||
announcementVersion = reader.ReadPackedInt32();
|
||||
id = reader.ReadPackedInt32();
|
||||
language = (Language)reader.ReadPackedInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace Impostor.Api.Net.Messages
|
||||
{
|
||||
public class AnnouncementsMessageFlags
|
||||
{
|
||||
public const byte UseCache = 0;
|
||||
public const byte SetUpdate = 1;
|
||||
public const byte AddLanguages = 4;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,22 @@ 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;
|
||||
}
|
||||
|
||||
if (clientVersion >= Version.V4)
|
||||
{
|
||||
reader.ReadByte(); // purpose unknown, seems hardcoded to 0
|
||||
}
|
||||
}
|
||||
|
||||
private static class Version
|
||||
@@ -35,6 +47,10 @@ 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);
|
||||
|
||||
public static readonly int V4 = GameVersion.GetVersion(2021, 12, 14);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
/// </summary>
|
||||
/// <param name="reader"><see cref="IMessageReader" /> with <see cref="IMessageReader.Tag" /> 0.</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 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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace Impostor.Api.Net.Messages.C2S
|
||||
{
|
||||
public class Message21SetActivePodType
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out string podType)
|
||||
{
|
||||
podType = reader.ReadString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,10 @@ namespace Impostor.Api.Net.Messages
|
||||
|
||||
int ReadInt32();
|
||||
|
||||
ulong ReadUInt64();
|
||||
|
||||
long ReadInt64();
|
||||
|
||||
float ReadSingle();
|
||||
|
||||
string ReadString(int length);
|
||||
|
||||
@@ -68,6 +68,18 @@ namespace Impostor.Api.Net.Messages
|
||||
/// <param name="value">Value to write.</param>
|
||||
void Write(int value);
|
||||
|
||||
/// <summary>
|
||||
/// Writes an ulong to the message.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to write.</param>
|
||||
void Write(ulong value);
|
||||
|
||||
/// <summary>
|
||||
/// Writes an ulong to the message.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to write.</param>
|
||||
void Write(long value);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a float to the message.
|
||||
/// </summary>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Impostor.Api.Innersloth;
|
||||
|
||||
namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc44SetRole
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, RoleTypes role)
|
||||
{
|
||||
writer.Write((ushort)role);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out RoleTypes role)
|
||||
{
|
||||
role = (RoleTypes)reader.ReadUInt16();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Impostor.Api.Games;
|
||||
using Impostor.Api.Innersloth.Customization;
|
||||
using Impostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc45ProtectPlayer
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, IInnerPlayerControl playerControl, ColorType color)
|
||||
{
|
||||
writer.Write(playerControl.NetId);
|
||||
writer.Write((byte)color);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, IGame game, out IInnerPlayerControl? playerControl, out ColorType color)
|
||||
{
|
||||
playerControl = reader.ReadNetObject<IInnerPlayerControl>(game);
|
||||
color = (ColorType)reader.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Impostor.Api.Games;
|
||||
using Impostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc46Shapeshift
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, IInnerPlayerControl playerControl, bool shouldAnimate)
|
||||
{
|
||||
writer.Write(playerControl.NetId);
|
||||
writer.Write(shouldAnimate);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, IGame game, out IInnerPlayerControl? playerControl, out bool shouldAnimate)
|
||||
{
|
||||
playerControl = reader.ReadNetObject<IInnerPlayerControl>(game);
|
||||
shouldAnimate = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Impostor.Api.Games;
|
||||
using Impostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc47CheckMurder
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, IInnerPlayerControl playerControl)
|
||||
{
|
||||
writer.Write(playerControl.NetId);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, IGame game, out IInnerPlayerControl? playerControl)
|
||||
{
|
||||
playerControl = reader.ReadNetObject<IInnerPlayerControl>(game);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Impostor.Api.Games;
|
||||
using Impostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc48CheckProtect
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, IInnerPlayerControl playerControl)
|
||||
{
|
||||
writer.Write(playerControl.NetId);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, IGame game, out IInnerPlayerControl? playerControl)
|
||||
{
|
||||
playerControl = reader.ReadNetObject<IInnerPlayerControl>(game);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System;
|
||||
using Impostor.Api.Innersloth;
|
||||
|
||||
namespace Impostor.Api.Net.Messages.S2C
|
||||
{
|
||||
public class Message01JoinGameS2C
|
||||
{
|
||||
public static void SerializeJoin(IMessageWriter writer, bool clear, int gameCode, int playerId, int hostId)
|
||||
public static void SerializeJoin(IMessageWriter writer, bool clear, int gameCode, IClientPlayer player, int hostId)
|
||||
{
|
||||
if (clear)
|
||||
{
|
||||
@@ -14,8 +14,11 @@ namespace Impostor.Api.Net.Messages.S2C
|
||||
|
||||
writer.StartMessage(MessageFlags.JoinGame);
|
||||
writer.Write(gameCode);
|
||||
writer.Write(playerId);
|
||||
writer.Write(player.Client.Id);
|
||||
writer.Write(hostId);
|
||||
writer.Write(player.Client.Name);
|
||||
player.Client.PlatformSpecificData.Serialize(writer);
|
||||
writer.WritePacked(player.Character?.PlayerInfo.PlayerLevel ?? 1);
|
||||
writer.EndMessage();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System;
|
||||
|
||||
namespace Impostor.Api.Net.Messages.S2C
|
||||
{
|
||||
public static class Message07JoinedGameS2C
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, bool clear, int gameCode, int playerId, int hostId, int[] otherPlayerIds)
|
||||
public static void Serialize(IMessageWriter writer, bool clear, int gameCode, int playerId, int hostId, IClientPlayer[] otherPlayers)
|
||||
{
|
||||
if (clear)
|
||||
{
|
||||
@@ -15,11 +15,14 @@ namespace Impostor.Api.Net.Messages.S2C
|
||||
writer.Write(gameCode);
|
||||
writer.Write(playerId);
|
||||
writer.Write(hostId);
|
||||
writer.WritePacked(otherPlayerIds.Length);
|
||||
writer.WritePacked(otherPlayers.Length);
|
||||
|
||||
foreach (var id in otherPlayerIds)
|
||||
foreach (var ply in otherPlayers)
|
||||
{
|
||||
writer.WritePacked(id);
|
||||
writer.WritePacked(ply.Client.Id);
|
||||
writer.Write(ply.Client.Name);
|
||||
ply.Client.PlatformSpecificData.Serialize(writer);
|
||||
writer.WritePacked(ply.Character?.PlayerInfo.PlayerLevel ?? 1);
|
||||
}
|
||||
|
||||
writer.EndMessage();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Impostor.Api.Games;
|
||||
|
||||
@@ -25,6 +25,9 @@ namespace Impostor.Api.Net.Messages.S2C
|
||||
writer.Write((byte)game.Options.Map);
|
||||
writer.Write((byte)game.Options.NumImpostors);
|
||||
writer.Write((byte)game.Options.MaxPlayers);
|
||||
var platform = game.Host?.Client.PlatformSpecificData;
|
||||
writer.Write((byte)(platform?.Platform ?? 0));
|
||||
writer.Write(platform?.PlatformName ?? string.Empty);
|
||||
writer.EndMessage();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+1
-1
Submodule src/Impostor.Hazel updated: 8de027461e...74070b8c07.
@@ -18,7 +18,6 @@ namespace Impostor.Plugins.Example
|
||||
services.AddSingleton<IEventListener, ClientEventListener>();
|
||||
services.AddSingleton<IEventListener, PlayerEventListener>();
|
||||
services.AddSingleton<IEventListener, MeetingEventListener>();
|
||||
services.AddSingleton<IEventListener, AnnouncementsListener>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using Impostor.Api.Events;
|
||||
using Impostor.Api.Events.Announcements;
|
||||
using Impostor.Api.Innersloth;
|
||||
|
||||
namespace Impostor.Plugins.Example.Handlers
|
||||
{
|
||||
public class AnnouncementsListener : IEventListener
|
||||
{
|
||||
private const int Id = 50;
|
||||
|
||||
[EventListener]
|
||||
public void OnAnnouncementRequestEvent(IAnnouncementRequestEvent e)
|
||||
{
|
||||
if (e.Id == Id)
|
||||
{
|
||||
// Client already has announcement cached, lets just use that
|
||||
e.Response.UseCached = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Client is receiving this announcement for the first time, window will popup
|
||||
e.Response.Announcement = new Announcement(Id, "Hello!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,9 +40,10 @@ namespace Impostor.Plugins.Example.Handlers
|
||||
{
|
||||
// Modify player properties.
|
||||
await playerControl.SetColorAsync((ColorType)_random.Next(1, 9));
|
||||
await playerControl.SetHatAsync((HatType)_random.Next(1, 9));
|
||||
await playerControl.SetSkinAsync((SkinType)_random.Next(1, 9));
|
||||
await playerControl.SetPetAsync((PetType)_random.Next(1, 9));
|
||||
// TODO Rewrite using cosmetics source generator
|
||||
// await playerControl.SetHatAsync((HatType)_random.Next(1, 9));
|
||||
// await playerControl.SetSkinAsync((SkinType)_random.Next(1, 9));
|
||||
// await playerControl.SetPetAsync((PetType)_random.Next(1, 9));
|
||||
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(5000));
|
||||
}
|
||||
@@ -74,9 +75,9 @@ namespace Impostor.Plugins.Example.Handlers
|
||||
if (e.Message == "look")
|
||||
{
|
||||
await e.PlayerControl.SetColorAsync(ColorType.Pink);
|
||||
await e.PlayerControl.SetHatAsync(HatType.Cheese);
|
||||
await e.PlayerControl.SetSkinAsync(SkinType.Police);
|
||||
await e.PlayerControl.SetPetAsync(PetType.Ufo);
|
||||
await e.PlayerControl.SetHatAsync("hat_pk05_Cheese");
|
||||
await e.PlayerControl.SetSkinAsync("skin_Police");
|
||||
await e.PlayerControl.SetPetAsync("pet_alien1");
|
||||
}
|
||||
|
||||
if (e.Message == "snap")
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
using Impostor.Server.Utils;
|
||||
|
||||
namespace Impostor.Server.Config
|
||||
{
|
||||
internal class AnnouncementsServerConfig
|
||||
{
|
||||
public const string Section = "AnnouncementsServer";
|
||||
|
||||
private string? _resolvedListenIp;
|
||||
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
public string ListenIp { get; set; } = "0.0.0.0";
|
||||
|
||||
public ushort ListenPort { get; set; } = 22024;
|
||||
|
||||
public string ResolveListenIp()
|
||||
{
|
||||
return _resolvedListenIp ??= IpUtils.ResolveIp(ListenIp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using System.IO;
|
||||
using Impostor.Server.Utils;
|
||||
|
||||
namespace Impostor.Server.Config
|
||||
{
|
||||
internal class AuthServerConfig
|
||||
{
|
||||
public const string Section = "AuthServer";
|
||||
|
||||
private string? _resolvedListenIp;
|
||||
|
||||
public bool Enabled { get; set; } = false;
|
||||
|
||||
public string ListenIp { get; set; } = "0.0.0.0";
|
||||
|
||||
public ushort ListenPort { get; set; } = 22025;
|
||||
|
||||
public string Certificate { get; set; } = Path.Combine("dtls", "certificate.pem");
|
||||
|
||||
public string PrivateKey { get; set; } = Path.Combine("dtls", "key.pem");
|
||||
|
||||
public string ResolveListenIp()
|
||||
{
|
||||
return _resolvedListenIp ??= IpUtils.ResolveIp(ListenIp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using Impostor.Api.Events.Announcements;
|
||||
using Impostor.Api.Innersloth;
|
||||
|
||||
namespace Impostor.Server.Events.Announcements
|
||||
{
|
||||
public class AnnouncementRequestEvent : IAnnouncementRequestEvent
|
||||
{
|
||||
public AnnouncementRequestEvent(int id, Language language)
|
||||
{
|
||||
Id = id;
|
||||
Language = language;
|
||||
}
|
||||
|
||||
public int Id { get; }
|
||||
|
||||
public Language Language { get; }
|
||||
|
||||
public IAnnouncementRequestEvent.IResponse Response { get; set; } = new AnnouncementResponse();
|
||||
|
||||
public class AnnouncementResponse : IAnnouncementRequestEvent.IResponse
|
||||
{
|
||||
public bool UseCached { get; set; } = false;
|
||||
|
||||
public Announcement? Announcement { get; set; } = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api.Events.Managers;
|
||||
using Impostor.Api.Net.Messages;
|
||||
using Impostor.Api.Net.Messages.Announcements;
|
||||
using Impostor.Hazel;
|
||||
using Impostor.Hazel.Udp;
|
||||
using Impostor.Server.Config;
|
||||
using Impostor.Server.Events.Announcements;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Impostor.Server.Net
|
||||
{
|
||||
internal class AnnouncementsService : IHostedService
|
||||
{
|
||||
private readonly ILogger<AnnouncementsService> _logger;
|
||||
private readonly AnnouncementsServerConfig _config;
|
||||
private readonly ObjectPool<MessageReader> _readerPool;
|
||||
private readonly IEventManager _eventManager;
|
||||
private UdpConnectionListener? _connection;
|
||||
|
||||
public AnnouncementsService(ILogger<AnnouncementsService> logger, IOptions<AnnouncementsServerConfig> config, ObjectPool<MessageReader> readerPool, IEventManager eventManager)
|
||||
{
|
||||
_logger = logger;
|
||||
_config = config.Value;
|
||||
_readerPool = readerPool;
|
||||
_eventManager = eventManager;
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var endpoint = new IPEndPoint(IPAddress.Parse(_config.ResolveListenIp()), _config.ListenPort);
|
||||
|
||||
var mode = endpoint.AddressFamily switch
|
||||
{
|
||||
AddressFamily.InterNetwork => IPMode.IPv4,
|
||||
AddressFamily.InterNetworkV6 => IPMode.IPv6,
|
||||
_ => throw new InvalidOperationException(),
|
||||
};
|
||||
|
||||
_connection = new UdpConnectionListener(endpoint, _readerPool, mode)
|
||||
{
|
||||
NewConnection = OnNewConnection,
|
||||
};
|
||||
|
||||
await _connection.StartAsync();
|
||||
|
||||
_logger.LogInformation("Announcements server is listening on {Address}:{Port}", endpoint.Address, endpoint.Port);
|
||||
}
|
||||
|
||||
public async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogWarning("Announcements server is shutting down!");
|
||||
|
||||
if (_connection != null)
|
||||
{
|
||||
await _connection.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnNewConnection(NewConnectionEventArgs e)
|
||||
{
|
||||
MessageHello.Deserialize(e.HandshakeData, out var announcementVersion, out var id, out var language);
|
||||
|
||||
_logger.LogDebug("Client requested announcement (version: {Version}, id: {Id}, language: {Language})", announcementVersion, id, language);
|
||||
|
||||
if (announcementVersion != 2)
|
||||
{
|
||||
await e.Connection.Disconnect("Unsupported announcement version");
|
||||
return;
|
||||
}
|
||||
|
||||
var @event = new AnnouncementRequestEvent(id, language);
|
||||
await _eventManager.CallAsync(@event);
|
||||
|
||||
var response = @event.Response;
|
||||
|
||||
if (response.UseCached)
|
||||
{
|
||||
using var writer = MessageWriter.Get(MessageType.Reliable);
|
||||
Message00UseCache.Serialize(writer);
|
||||
await e.Connection.SendAsync(writer);
|
||||
|
||||
_logger.LogDebug("Sent UseCache response");
|
||||
}
|
||||
|
||||
if (response.Announcement != null)
|
||||
{
|
||||
using var writer = MessageWriter.Get(MessageType.Reliable);
|
||||
var announcement = response.Announcement.Value;
|
||||
Message01Update.Serialize(writer, announcement.Id, announcement.Message);
|
||||
await e.Connection.SendAsync(writer);
|
||||
|
||||
_logger.LogDebug("Sent ({Id}) {Message}", announcement.Id, announcement.Message);
|
||||
}
|
||||
|
||||
await e.Connection.Disconnect(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api.Events.Managers;
|
||||
using Impostor.Api.Net.Messages;
|
||||
using Impostor.Api.Net.Messages.Auth;
|
||||
using Impostor.Hazel;
|
||||
using Impostor.Hazel.Dtls;
|
||||
using Impostor.Server.Config;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Impostor.Server.Net
|
||||
{
|
||||
internal class AuthService : IHostedService
|
||||
{
|
||||
private readonly ILogger<AuthService> _logger;
|
||||
private readonly AuthServerConfig _config;
|
||||
private readonly ObjectPool<MessageReader> _readerPool;
|
||||
private readonly IEventManager _eventManager;
|
||||
private DtlsConnectionListener? _connection;
|
||||
|
||||
public AuthService(ILogger<AuthService> logger, IOptions<AuthServerConfig> config, ObjectPool<MessageReader> readerPool, IEventManager eventManager)
|
||||
{
|
||||
_logger = logger;
|
||||
_config = config.Value;
|
||||
_readerPool = readerPool;
|
||||
_eventManager = eventManager;
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var endpoint = new IPEndPoint(IPAddress.Parse(_config.ResolveListenIp()), _config.ListenPort);
|
||||
|
||||
var mode = endpoint.AddressFamily switch
|
||||
{
|
||||
AddressFamily.InterNetwork => IPMode.IPv4,
|
||||
AddressFamily.InterNetworkV6 => IPMode.IPv6,
|
||||
_ => throw new InvalidOperationException(),
|
||||
};
|
||||
|
||||
var rsa = RSA.Create();
|
||||
rsa.ImportPkcs8PrivateKey(Convert.FromBase64String(string.Join(string.Empty, (await File.ReadAllLinesAsync(_config.PrivateKey, cancellationToken)).Where(x => !x.StartsWith("-----")))), out _);
|
||||
var cert = new X509Certificate2(_config.Certificate).CopyWithPrivateKey(rsa);
|
||||
|
||||
_connection = new DtlsConnectionListener(endpoint, _readerPool, mode);
|
||||
_connection.SetCertificate(cert);
|
||||
_connection.NewConnection = ConnectionOnNewConnection;
|
||||
|
||||
await _connection.StartAsync();
|
||||
|
||||
_logger.LogInformation("Auth server is listening on {Address}:{Port}", endpoint.Address, endpoint.Port);
|
||||
}
|
||||
|
||||
public async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogWarning("Auth server is shutting down!");
|
||||
|
||||
if (_connection != null)
|
||||
{
|
||||
await _connection.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private ValueTask ConnectionOnNewConnection(NewConnectionEventArgs e)
|
||||
{
|
||||
MessageHandshake.Deserialize(e.HandshakeData, out var clientVersion, out var platform, out var clientId);
|
||||
|
||||
_logger.LogTrace("New authentication request: {clientVersion}, {platform}, {clientId}", clientVersion, platform, clientId);
|
||||
|
||||
using var writer = MessageWriter.Get(MessageType.Reliable);
|
||||
|
||||
writer.StartMessage(1);
|
||||
Message01Complete.Serialize(writer, (uint)RandomNumberGenerator.GetInt32(int.MinValue, int.MaxValue));
|
||||
writer.EndMessage();
|
||||
|
||||
return e.Connection.SendAsync(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,8 +24,8 @@ namespace Impostor.Server.Net
|
||||
private readonly GameManager _gameManager;
|
||||
private readonly ICustomMessageManager<ICustomRootMessage> _customMessageManager;
|
||||
|
||||
public Client(ILogger<Client> logger, IOptions<AntiCheatConfig> antiCheatOptions, ClientManager clientManager, GameManager gameManager, ICustomMessageManager<ICustomRootMessage> customMessageManager, string name, int gameVersion, Language language, QuickChatModes chatMode, IHazelConnection connection)
|
||||
: base(name, gameVersion, language, chatMode, connection)
|
||||
public Client(ILogger<Client> logger, IOptions<AntiCheatConfig> antiCheatOptions, ClientManager clientManager, GameManager gameManager, ICustomMessageManager<ICustomRootMessage> 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);
|
||||
@@ -257,6 +257,12 @@ namespace Impostor.Server.Net
|
||||
break;
|
||||
}
|
||||
|
||||
case MessageFlags.SetActivePodType:
|
||||
{
|
||||
Message21SetActivePodType.Deserialize(reader, out _);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (_customMessageManager.TryGet(flag, out var customRootMessage))
|
||||
{
|
||||
|
||||
@@ -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<object, object>();
|
||||
}
|
||||
@@ -31,6 +32,8 @@ namespace Impostor.Server.Net
|
||||
|
||||
public QuickChatModes ChatMode { get; }
|
||||
|
||||
public PlatformSpecificData PlatformSpecificData { get; }
|
||||
|
||||
public int GameVersion { get; }
|
||||
|
||||
public IHazelConnection Connection { get; }
|
||||
|
||||
@@ -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<TClient>(_serviceProvider, name, clientVersion, language, chatMode, connection);
|
||||
var client = ActivatorUtilities.CreateInstance<TClient>(_serviceProvider, name, clientVersion, language, chatMode, platformSpecificData, connection);
|
||||
connection.Client = client;
|
||||
return client;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api;
|
||||
using Impostor.Api.Innersloth;
|
||||
using Impostor.Api.Net;
|
||||
using Impostor.Server.Net.Inner.Objects;
|
||||
|
||||
@@ -85,6 +86,32 @@ namespace Impostor.Server.Net.Inner
|
||||
return true;
|
||||
}
|
||||
|
||||
protected async ValueTask<bool> ValidateCanVent(CheatContext context, IClientPlayer sender, InnerPlayerInfo playerInfo, bool value = true)
|
||||
{
|
||||
if (playerInfo.CanVent != value)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(context, "Failed can vent check"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected async ValueTask<bool> ValidateRole(CheatContext context, IClientPlayer sender, InnerPlayerInfo playerInfo, RoleTypes role)
|
||||
{
|
||||
if (playerInfo.RoleType != role)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(context, $"Failed role = {role} check"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected async ValueTask<bool> UnregisteredCall(CheatContext context, IClientPlayer sender)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(context, "Client sent unregistered call"))
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Impostor.Server.Net.Inner.Objects.Components
|
||||
case RpcCalls.EnterVent:
|
||||
case RpcCalls.ExitVent:
|
||||
{
|
||||
if (!await ValidateImpostor(call, sender, _playerControl.PlayerInfo))
|
||||
if (!await ValidateCanVent(call, sender, _playerControl.PlayerInfo))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -59,16 +59,18 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return;
|
||||
}
|
||||
|
||||
if (initialState)
|
||||
while (reader.Position < reader.Length)
|
||||
{
|
||||
var num = reader.ReadPackedInt32();
|
||||
|
||||
for (var i = 0; i < num; i++)
|
||||
var inner = reader.ReadMessage();
|
||||
var playerInfo = this.GetPlayerById(inner.Tag);
|
||||
if (playerInfo != null)
|
||||
{
|
||||
var playerId = reader.ReadByte();
|
||||
var playerInfo = new InnerPlayerInfo(playerId);
|
||||
|
||||
playerInfo.Deserialize(reader);
|
||||
playerInfo.Deserialize(inner);
|
||||
}
|
||||
else
|
||||
{
|
||||
playerInfo = new InnerPlayerInfo(inner.Tag);
|
||||
playerInfo.Deserialize(inner);
|
||||
|
||||
if (!_allPlayers.TryAdd(playerInfo.PlayerId, playerInfo))
|
||||
{
|
||||
@@ -76,28 +78,6 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (reader.Position < reader.Length)
|
||||
{
|
||||
var inner = reader.ReadMessage();
|
||||
var playerInfo = this.GetPlayerById(inner.Tag);
|
||||
if (playerInfo != null)
|
||||
{
|
||||
playerInfo.Deserialize(inner);
|
||||
}
|
||||
else
|
||||
{
|
||||
playerInfo = new InnerPlayerInfo(inner.Tag);
|
||||
playerInfo.Deserialize(inner);
|
||||
|
||||
if (!_allPlayers.TryAdd(playerInfo.PlayerId, playerInfo))
|
||||
{
|
||||
throw new ImpostorException("Failed to add player to InnerGameData.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override async ValueTask<bool> HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -29,37 +29,37 @@ 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)
|
||||
public async ValueTask SetHatAsync(string hatId)
|
||||
{
|
||||
PlayerInfo.Hat = hat;
|
||||
PlayerInfo.CurrentOutfit.HatId = hatId;
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetHat);
|
||||
Rpc09SetHat.Serialize(writer, hat);
|
||||
Rpc39SetHat.Serialize(writer, hatId);
|
||||
await Game.FinishRpcAsync(writer);
|
||||
}
|
||||
|
||||
public async ValueTask SetPetAsync(PetType pet)
|
||||
public async ValueTask SetPetAsync(string petId)
|
||||
{
|
||||
PlayerInfo.Pet = pet;
|
||||
PlayerInfo.CurrentOutfit.PetId = petId;
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetPet);
|
||||
Rpc17SetPet.Serialize(writer, pet);
|
||||
Rpc41SetPet.Serialize(writer, petId);
|
||||
await Game.FinishRpcAsync(writer);
|
||||
}
|
||||
|
||||
public async ValueTask SetSkinAsync(SkinType skin)
|
||||
public async ValueTask SetSkinAsync(string skinId)
|
||||
{
|
||||
PlayerInfo.Skin = skin;
|
||||
PlayerInfo.CurrentOutfit.SkinId = skinId;
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetSkin);
|
||||
Rpc10SetSkin.Serialize(writer, skin);
|
||||
Rpc40SetSkin.Serialize(writer, skinId);
|
||||
await Game.FinishRpcAsync(writer);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,9 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
internal Queue<ColorType> RequestedColorId { get; } = new Queue<ColorType>();
|
||||
|
||||
/// <summary> Gets or sets target that was set by the last CheckMurder RPC. </summary>
|
||||
internal IInnerPlayerControl? IsMurdering { get; set; } = null;
|
||||
|
||||
public override ValueTask<bool> SerializeAsync(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
@@ -182,8 +185,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 +196,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:
|
||||
@@ -210,7 +246,7 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
case RpcCalls.MurderPlayer:
|
||||
{
|
||||
if (!await ValidateOwnership(call, sender) || !await ValidateImpostor(call, sender, PlayerInfo))
|
||||
if (!await ValidateHost(call, sender))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -271,7 +307,7 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc17SetPet.Deserialize(reader, out var pet);
|
||||
Rpc41SetPet.Deserialize(reader, out var pet);
|
||||
return await HandleSetPet(sender, pet);
|
||||
}
|
||||
|
||||
@@ -308,6 +344,65 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
break;
|
||||
}
|
||||
|
||||
case RpcCalls.SetRole:
|
||||
{
|
||||
if (!await ValidateHost(call, sender))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc44SetRole.Deserialize(reader, out var role);
|
||||
PlayerInfo.RoleType = role;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case RpcCalls.ProtectPlayer:
|
||||
{
|
||||
if (!await ValidateHost(call, sender))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc45ProtectPlayer.Deserialize(reader, Game, out _, out _);
|
||||
break;
|
||||
}
|
||||
|
||||
case RpcCalls.Shapeshift:
|
||||
{
|
||||
if (!await ValidateRole(call, sender, PlayerInfo, RoleTypes.Shapeshifter))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc46Shapeshift.Deserialize(reader, Game, out _, out _);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case RpcCalls.CheckMurder:
|
||||
{
|
||||
if (!await ValidateImpostor(call, sender, PlayerInfo))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc47CheckMurder.Deserialize(reader, Game, out var murdered);
|
||||
return await HandleCheckMurder(sender, murdered);
|
||||
}
|
||||
|
||||
case RpcCalls.CheckProtect:
|
||||
{
|
||||
if (!await ValidateRole(call, sender, PlayerInfo, RoleTypes.GuardianAngel))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc48CheckProtect.Deserialize(reader, Game, out _);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return await base.HandleRpcAsync(sender, target, call, reader);
|
||||
}
|
||||
@@ -343,7 +438,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 +574,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 +592,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,45 +605,62 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
}
|
||||
}
|
||||
|
||||
PlayerInfo.Color = color;
|
||||
PlayerInfo.CurrentOutfit.Color = color;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleSetHat(ClientPlayer sender, HatType hat)
|
||||
private async ValueTask<bool> HandleSetHat(ClientPlayer sender, string 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.HatId = hat;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleSetSkin(ClientPlayer sender, SkinType skin)
|
||||
private async ValueTask<bool> HandleSetSkin(ClientPlayer sender, string 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;
|
||||
PlayerInfo.CurrentOutfit.SkinId = skin;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleCheckMurder(ClientPlayer sender, IInnerPlayerControl? target)
|
||||
{
|
||||
if (!PlayerInfo.CanMurder(Game, _dateTimeProvider))
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.CheckMurder, "Client tried to murder too fast"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
PlayerInfo.LastMurder = _dateTimeProvider.UtcNow - TimeSpan.FromMilliseconds(sender.Client.Connection.AveragePing);
|
||||
|
||||
if (target == null || target.PlayerInfo.IsImpostor)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.CheckMurder, "Client tried to murder invalid target"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
IsMurdering = target;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleMurderPlayer(ClientPlayer sender, IInnerPlayerControl? target)
|
||||
{
|
||||
if (!PlayerInfo.CanMurder(Game, _dateTimeProvider))
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.MurderPlayer, "Client tried to murder too fast"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (target == null || target.PlayerInfo.IsImpostor)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.MurderPlayer, "Client tried to murder invalid target"))
|
||||
@@ -557,7 +669,14 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
}
|
||||
}
|
||||
|
||||
PlayerInfo.LastMurder = _dateTimeProvider.UtcNow - TimeSpan.FromMilliseconds(sender.Client.Connection.AveragePing);
|
||||
// If the host is also the impostor that committed the murder, CheckMurder is actually sent *after* the MurderPlayer RPC
|
||||
if (sender.Character != this && target != IsMurdering)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.MurderPlayer, "Host tried to murder incorrect target"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (target != null && !target.PlayerInfo.IsDead)
|
||||
{
|
||||
@@ -565,6 +684,8 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
await _eventManager.CallAsync(new PlayerMurderEvent(Game, sender, this, target));
|
||||
}
|
||||
|
||||
IsMurdering = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -582,14 +703,14 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
await _eventManager.CallAsync(new PlayerStartMeetingEvent(Game, Game.GetClientPlayer(this.OwnerId)!, this, deadPlayer));
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleSetPet(ClientPlayer sender, PetType pet)
|
||||
private async ValueTask<bool> HandleSetPet(ClientPlayer sender, string 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;
|
||||
PlayerInfo.CurrentOutfit.PetId = pet;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -21,17 +21,22 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
public string PlayerName { get; internal set; } = string.Empty;
|
||||
|
||||
public ColorType Color { get; internal set; } = (ColorType)(-1);
|
||||
public Dictionary<PlayerOutfitType, PlayerOutfit> 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 CanVent => RoleType is RoleTypes.Impostor or RoleTypes.Shapeshifter or RoleTypes.Engineer;
|
||||
|
||||
public bool IsDead { get; internal set; }
|
||||
|
||||
@@ -41,6 +46,8 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
public DateTimeOffset LastMurder { get; set; }
|
||||
|
||||
public uint PlayerLevel { get; internal set; }
|
||||
|
||||
public bool CanMurder(IGame game, IDateTimeProvider dateTimeProvider)
|
||||
{
|
||||
if (!IsImpostor)
|
||||
@@ -58,16 +65,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);
|
||||
}
|
||||
|
||||
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();
|
||||
RoleType = roleType;
|
||||
|
||||
var taskCount = reader.ReadByte();
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ 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
|
||||
GameVersion.GetVersion(2021, 12, 14), // 2021.12.14
|
||||
};
|
||||
|
||||
private readonly ILogger<ClientManager> _logger;
|
||||
@@ -65,10 +66,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 +106,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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api.Innersloth;
|
||||
using Impostor.Api.Net;
|
||||
@@ -78,12 +78,12 @@ namespace Impostor.Server.Net.State
|
||||
|
||||
private void WriteJoinedGameMessage(IMessageWriter message, bool clear, IClientPlayer player)
|
||||
{
|
||||
var playerIds = _players
|
||||
var players = _players
|
||||
.Where(x => x.Value != player)
|
||||
.Select(x => x.Key)
|
||||
.Select(x => x.Value)
|
||||
.ToArray();
|
||||
|
||||
Message07JoinedGameS2C.Serialize(message, clear, Code, player.Client.Id, HostId, playerIds);
|
||||
Message07JoinedGameS2C.Serialize(message, clear, Code, player.Client.Id, HostId, players);
|
||||
}
|
||||
|
||||
private void WriteAlterGameMessage(IMessageWriter message, bool clear, bool isPublic)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
@@ -114,7 +114,7 @@ namespace Impostor.Server.Net.State
|
||||
|
||||
private ValueTask BroadcastJoinMessage(IMessageWriter message, bool clear, ClientPlayer player)
|
||||
{
|
||||
Message01JoinGameS2C.SerializeJoin(message, clear, Code, player.Client.Id, HostId);
|
||||
Message01JoinGameS2C.SerializeJoin(message, clear, Code, player, HostId);
|
||||
|
||||
return SendToAllExceptAsync(message, player.Client.Id);
|
||||
}
|
||||
|
||||
@@ -116,14 +116,6 @@ namespace Impostor.Server
|
||||
.GetSection(ServerRedirectorConfig.Section)
|
||||
.Get<ServerRedirectorConfig>() ?? new ServerRedirectorConfig();
|
||||
|
||||
var announcementsServer = host.Configuration
|
||||
.GetSection(AnnouncementsServerConfig.Section)
|
||||
.Get<AnnouncementsServerConfig>() ?? new AnnouncementsServerConfig();
|
||||
|
||||
var authServer = host.Configuration
|
||||
.GetSection(AuthServerConfig.Section)
|
||||
.Get<AuthServerConfig>() ?? new AuthServerConfig();
|
||||
|
||||
services.AddSingleton<ServerEnvironment>();
|
||||
services.AddSingleton<IServerEnvironment>(p => p.GetRequiredService<ServerEnvironment>());
|
||||
services.AddSingleton<IDateTimeProvider, RealDateTimeProvider>();
|
||||
@@ -131,8 +123,6 @@ namespace Impostor.Server
|
||||
services.Configure<DebugConfig>(host.Configuration.GetSection(DebugConfig.Section));
|
||||
services.Configure<AntiCheatConfig>(host.Configuration.GetSection(AntiCheatConfig.Section));
|
||||
services.Configure<ServerConfig>(host.Configuration.GetSection(ServerConfig.Section));
|
||||
services.Configure<AnnouncementsServerConfig>(host.Configuration.GetSection(AnnouncementsServerConfig.Section));
|
||||
services.Configure<AuthServerConfig>(host.Configuration.GetSection(AuthServerConfig.Section));
|
||||
services.Configure<ServerRedirectorConfig>(host.Configuration.GetSection(ServerRedirectorConfig.Section));
|
||||
|
||||
if (redirector.Enabled)
|
||||
@@ -218,16 +208,6 @@ namespace Impostor.Server
|
||||
services.AddSingleton<IEventManager, EventManager>();
|
||||
services.AddSingleton<Matchmaker>();
|
||||
services.AddHostedService<MatchmakerService>();
|
||||
|
||||
if (announcementsServer.Enabled)
|
||||
{
|
||||
services.AddHostedService<AnnouncementsService>();
|
||||
}
|
||||
|
||||
if (authServer.Enabled)
|
||||
{
|
||||
services.AddHostedService<AuthService>();
|
||||
}
|
||||
})
|
||||
.UseSerilog()
|
||||
.UseConsoleLifetime()
|
||||
|
||||
@@ -18,8 +18,8 @@ namespace Impostor.Server.Recorder
|
||||
private bool _createdGame;
|
||||
private bool _recordAfter;
|
||||
|
||||
public ClientRecorder(ILogger<Client> logger, IOptions<AntiCheatConfig> antiCheatOptions, ClientManager clientManager, ICustomMessageManager<ICustomRootMessage> 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<Client> logger, IOptions<AntiCheatConfig> antiCheatOptions, ClientManager clientManager, ICustomMessageManager<ICustomRootMessage> 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;
|
||||
|
||||
@@ -5,11 +5,6 @@
|
||||
"ListenIp": "0.0.0.0",
|
||||
"ListenPort": 22023
|
||||
},
|
||||
"AnnouncementsServer": {
|
||||
"Enabled": true,
|
||||
"ListenIp": "0.0.0.0",
|
||||
"ListenPort": 22024
|
||||
},
|
||||
"AntiCheat": {
|
||||
"Enabled": true,
|
||||
"BanIpFromGame": true
|
||||
|
||||
@@ -170,7 +170,7 @@ namespace Impostor.Tools.ServerReplay
|
||||
// Create and register connection.
|
||||
var connection = new MockHazelConnection(address);
|
||||
|
||||
await _clientManager.RegisterConnectionAsync(connection, name, gameVersion, Language.English, QuickChatModes.FreeChatOrQuickChat);
|
||||
await _clientManager.RegisterConnectionAsync(connection, name, gameVersion, Language.English, QuickChatModes.FreeChatOrQuickChat, new PlatformSpecificData(Platforms.Unknown, "ServerReplay"));
|
||||
|
||||
// Store reference for ourselfs.
|
||||
Connections.Add(clientId, connection);
|
||||
@@ -200,7 +200,7 @@ namespace Impostor.Tools.ServerReplay
|
||||
|
||||
if (tag == MessageFlags.HostGame)
|
||||
{
|
||||
GameOptions.Add(clientId, Message00HostGameC2S.Deserialize(message, out _));
|
||||
GameOptions.Add(clientId, Message00HostGameC2S.Deserialize(message));
|
||||
}
|
||||
else if (Connections.TryGetValue(clientId, out var client))
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user