From 2603f34b898c5054a21c2d2003808829b4b670ca Mon Sep 17 00:00:00 2001 From: danbudworthmead Date: Sat, 5 Oct 2024 11:44:08 +0100 Subject: [PATCH] Bugfix/fix outfit RPCs (#653) * implemented the sequence ID * implemented the sequence ID for the player outfits the sequence ID in the set call must be greater than that stored on the client otherwise the client disregards the set call. * make sequence IDs internal * added space after closing brace * make the sequence ID addition +5 --- .../Innersloth/Customization/PlayerOutfit.cs | 10 ++-- .../Net/Messages/Rpcs/Rpc39SetHatStr.cs | 6 ++- .../Net/Messages/Rpcs/Rpc40SetSkinStr.cs | 6 ++- .../Net/Messages/Rpcs/Rpc41SetPetStr.cs | 6 ++- .../Net/Messages/Rpcs/Rpc42SetVisorStr.cs | 6 ++- .../Net/Messages/Rpcs/Rpc43SetNamePlateStr.cs | 6 ++- .../Inner/Objects/InnerPlayerControl.Api.cs | 30 +++++++++--- .../Net/Inner/Objects/InnerPlayerControl.cs | 47 ++++++++++--------- .../Net/Inner/Objects/InnerPlayerInfo.cs | 41 ++++++++++++++++ 9 files changed, 116 insertions(+), 42 deletions(-) diff --git a/src/Impostor.Api/Innersloth/Customization/PlayerOutfit.cs b/src/Impostor.Api/Innersloth/Customization/PlayerOutfit.cs index dbe698b..82f8ced 100644 --- a/src/Impostor.Api/Innersloth/Customization/PlayerOutfit.cs +++ b/src/Impostor.Api/Innersloth/Customization/PlayerOutfit.cs @@ -59,15 +59,15 @@ namespace Impostor.Api.Innersloth.Customization internal set => SetField(ref _namePlateId, value); } - private byte HatSequenceId { get; set; } = 0; + internal byte HatSequenceId { get; set; } = 0; - private byte PetSequenceId { get; set; } = 0; + internal byte PetSequenceId { get; set; } = 0; - private byte SkinSequenceId { get; set; } = 0; + internal byte SkinSequenceId { get; set; } = 0; - private byte VisorSequenceId { get; set; } = 0; + internal byte VisorSequenceId { get; set; } = 0; - private byte NamePlateSequenceId { get; set; } = 0; + internal byte NamePlateSequenceId { get; set; } = 0; /// /// Gets a value indicating whether a player outfit is complete or whether it needs to receive additional cosmetics. diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc39SetHatStr.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc39SetHatStr.cs index 1b5300a..35f1ffd 100644 --- a/src/Impostor.Api/Net/Messages/Rpcs/Rpc39SetHatStr.cs +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc39SetHatStr.cs @@ -2,14 +2,16 @@ namespace Impostor.Api.Net.Messages.Rpcs { public static class Rpc39SetHatStr { - public static void Serialize(IMessageWriter writer, string hat) + public static void Serialize(IMessageWriter writer, string hat, byte nextRpcSequenceId) { writer.Write(hat); + writer.Write(nextRpcSequenceId); } - public static void Deserialize(IMessageReader reader, out string hat) + public static void Deserialize(IMessageReader reader, out string hat, out byte nextRpcSequenceId) { hat = reader.ReadString(); + nextRpcSequenceId = reader.ReadByte(); } } } diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc40SetSkinStr.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc40SetSkinStr.cs index 796be7a..f09c580 100644 --- a/src/Impostor.Api/Net/Messages/Rpcs/Rpc40SetSkinStr.cs +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc40SetSkinStr.cs @@ -2,14 +2,16 @@ namespace Impostor.Api.Net.Messages.Rpcs { public static class Rpc40SetSkinStr { - public static void Serialize(IMessageWriter writer, string skin) + public static void Serialize(IMessageWriter writer, string skin, byte nextRpcSequenceId) { writer.Write(skin); + writer.Write(nextRpcSequenceId); } - public static void Deserialize(IMessageReader reader, out string skin) + public static void Deserialize(IMessageReader reader, out string skin, out byte nextRpcSequenceId) { skin = reader.ReadString(); + nextRpcSequenceId = reader.ReadByte(); } } } diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc41SetPetStr.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc41SetPetStr.cs index 03dfd3e..d511b8d 100644 --- a/src/Impostor.Api/Net/Messages/Rpcs/Rpc41SetPetStr.cs +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc41SetPetStr.cs @@ -2,14 +2,16 @@ namespace Impostor.Api.Net.Messages.Rpcs { public static class Rpc41SetPetStr { - public static void Serialize(IMessageWriter writer, string pet) + public static void Serialize(IMessageWriter writer, string pet, byte nextRpcSequenceId) { writer.Write(pet); + writer.Write(nextRpcSequenceId); } - public static void Deserialize(IMessageReader reader, out string pet) + public static void Deserialize(IMessageReader reader, out string pet, out byte nextRpcSequenceId) { pet = reader.ReadString(); + nextRpcSequenceId = reader.ReadByte(); } } } diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc42SetVisorStr.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc42SetVisorStr.cs index bffcd33..cd74db0 100644 --- a/src/Impostor.Api/Net/Messages/Rpcs/Rpc42SetVisorStr.cs +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc42SetVisorStr.cs @@ -2,14 +2,16 @@ namespace Impostor.Api.Net.Messages.Rpcs { public static class Rpc42SetVisorStr { - public static void Serialize(IMessageWriter writer, string visor) + public static void Serialize(IMessageWriter writer, string visor, byte nextRpcSequenceId) { writer.Write(visor); + writer.Write(nextRpcSequenceId); } - public static void Deserialize(IMessageReader reader, out string visor) + public static void Deserialize(IMessageReader reader, out string visor, out byte nextRpcSequenceId) { visor = reader.ReadString(); + nextRpcSequenceId = reader.ReadByte(); } } } diff --git a/src/Impostor.Api/Net/Messages/Rpcs/Rpc43SetNamePlateStr.cs b/src/Impostor.Api/Net/Messages/Rpcs/Rpc43SetNamePlateStr.cs index e685c9e..eaf8092 100644 --- a/src/Impostor.Api/Net/Messages/Rpcs/Rpc43SetNamePlateStr.cs +++ b/src/Impostor.Api/Net/Messages/Rpcs/Rpc43SetNamePlateStr.cs @@ -2,14 +2,16 @@ namespace Impostor.Api.Net.Messages.Rpcs { public static class Rpc43SetNamePlateStr { - public static void Serialize(IMessageWriter writer, string namePlate) + public static void Serialize(IMessageWriter writer, string namePlate, byte nextRpcSequenceId) { writer.Write(namePlate); + writer.Write(nextRpcSequenceId); } - public static void Deserialize(IMessageReader reader, out string namePlate) + public static void Deserialize(IMessageReader reader, out string namePlate, out byte nextRpcSequenceId) { namePlate = reader.ReadString(); + nextRpcSequenceId = reader.ReadByte(); } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs index 2d8a8f1..a4d280c 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs @@ -40,8 +40,8 @@ namespace Impostor.Server.Net.Inner.Objects { PlayerInfo.CurrentOutfit.HatId = hatId; - using var writer = Game.StartRpc(NetId, RpcCalls.SetHat); - Rpc39SetHatStr.Serialize(writer, hatId); + using var writer = Game.StartRpc(NetId, RpcCalls.SetHatStr); + Rpc39SetHatStr.Serialize(writer, hatId, PlayerInfo.GetNextRpcSequenceId(RpcCalls.SetHatStr)); await Game.FinishRpcAsync(writer); } @@ -49,8 +49,8 @@ namespace Impostor.Server.Net.Inner.Objects { PlayerInfo.CurrentOutfit.PetId = petId; - using var writer = Game.StartRpc(NetId, RpcCalls.SetPet); - Rpc41SetPetStr.Serialize(writer, petId); + using var writer = Game.StartRpc(NetId, RpcCalls.SetPetStr); + Rpc41SetPetStr.Serialize(writer, petId, PlayerInfo.GetNextRpcSequenceId(RpcCalls.SetPetStr)); await Game.FinishRpcAsync(writer); } @@ -58,8 +58,26 @@ namespace Impostor.Server.Net.Inner.Objects { PlayerInfo.CurrentOutfit.SkinId = skinId; - using var writer = Game.StartRpc(NetId, RpcCalls.SetSkin); - Rpc40SetSkinStr.Serialize(writer, skinId); + using var writer = Game.StartRpc(NetId, RpcCalls.SetSkinStr); + Rpc40SetSkinStr.Serialize(writer, skinId, PlayerInfo.GetNextRpcSequenceId(RpcCalls.SetSkinStr)); + await Game.FinishRpcAsync(writer); + } + + public async ValueTask SetVisorAsync(string visorId) + { + PlayerInfo.CurrentOutfit.VisorId = visorId; + + using var writer = Game.StartRpc(NetId, RpcCalls.SetVisorStr); + Rpc42SetVisorStr.Serialize(writer, visorId, PlayerInfo.GetNextRpcSequenceId(RpcCalls.SetVisorStr)); + await Game.FinishRpcAsync(writer); + } + + public async ValueTask SetNamePlateAsync(string nameplateId) + { + PlayerInfo.CurrentOutfit.NamePlateId = nameplateId; + + using var writer = Game.StartRpc(NetId, RpcCalls.SetNamePlateStr); + Rpc43SetNamePlateStr.Serialize(writer, nameplateId, PlayerInfo.GetNextRpcSequenceId(RpcCalls.SetNamePlateStr)); await Game.FinishRpcAsync(writer); } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs index 9aaeef7..6503ed4 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs @@ -203,8 +203,8 @@ namespace Impostor.Server.Net.Inner.Objects return false; } - Rpc39SetHatStr.Deserialize(reader, out var hat); - return await HandleSetHat(sender, hat); + Rpc39SetHatStr.Deserialize(reader, out var hat, out var nextRpcSequenceId); + return await HandleSetHat(sender, hat, nextRpcSequenceId); } case RpcCalls.SetSkinStr: @@ -215,8 +215,8 @@ namespace Impostor.Server.Net.Inner.Objects return false; } - Rpc40SetSkinStr.Deserialize(reader, out var skin); - return await HandleSetSkin(sender, skin); + Rpc40SetSkinStr.Deserialize(reader, out var skin, out var nextRpcSequenceId); + return await HandleSetSkin(sender, skin, nextRpcSequenceId); } case RpcCalls.SetVisorStr: @@ -227,8 +227,8 @@ namespace Impostor.Server.Net.Inner.Objects return false; } - Rpc42SetVisorStr.Deserialize(reader, out var visor); - return await HandleSetVisor(sender, visor); + Rpc42SetVisorStr.Deserialize(reader, out var visor, out var nextRpcSequenceId); + return await HandleSetVisor(sender, visor, nextRpcSequenceId); } case RpcCalls.SetNamePlateStr: @@ -238,8 +238,8 @@ namespace Impostor.Server.Net.Inner.Objects return false; } - Rpc43SetNamePlateStr.Deserialize(reader, out var namePlate); - return await HandleSetNamePlate(sender, namePlate); + Rpc43SetNamePlateStr.Deserialize(reader, out var namePlate, out var nextRpcSequenceId); + return await HandleSetNamePlate(sender, namePlate, nextRpcSequenceId); } case RpcCalls.SetLevel: @@ -335,8 +335,8 @@ namespace Impostor.Server.Net.Inner.Objects return false; } - Rpc41SetPetStr.Deserialize(reader, out var pet); - return await HandleSetPet(sender, pet); + Rpc41SetPetStr.Deserialize(reader, out var pet, out var nextRpcSequenceId); + return await HandleSetPet(sender, pet, nextRpcSequenceId); } case RpcCalls.SetStartCounter: @@ -848,54 +848,58 @@ namespace Impostor.Server.Net.Inner.Objects return true; } - private async ValueTask HandleSetHat(ClientPlayer sender, string hat) + private async ValueTask HandleSetHat(ClientPlayer sender, string hat, byte nextRpcSequenceId) { if (Game.GameState == GameStates.Started && - await sender.Client.ReportCheatAsync(RpcCalls.SetHat, CheatCategory.GameFlow, "Client tried to change hat while not in lobby")) + await sender.Client.ReportCheatAsync(RpcCalls.SetHatStr, CheatCategory.GameFlow, "Client tried to change hat while not in lobby")) { return false; } PlayerInfo.CurrentOutfit.HatId = hat; + PlayerInfo.CurrentOutfit.HatSequenceId = nextRpcSequenceId; return true; } - private async ValueTask HandleSetSkin(ClientPlayer sender, string skin) + private async ValueTask HandleSetSkin(ClientPlayer sender, string skin, byte nextRpcSequenceId) { if (Game.GameState == GameStates.Started && - await sender.Client.ReportCheatAsync(RpcCalls.SetSkin, CheatCategory.GameFlow, "Client tried to change skin while not in lobby")) + await sender.Client.ReportCheatAsync(RpcCalls.SetSkinStr, CheatCategory.GameFlow, "Client tried to change skin while not in lobby")) { return false; } PlayerInfo.CurrentOutfit.SkinId = skin; + PlayerInfo.CurrentOutfit.SkinSequenceId = nextRpcSequenceId; return true; } - private async ValueTask HandleSetVisor(ClientPlayer sender, string visor) + private async ValueTask HandleSetVisor(ClientPlayer sender, string visor, byte nextRpcSequenceId) { if (Game.GameState == GameStates.Started && - await sender.Client.ReportCheatAsync(RpcCalls.SetVisor, CheatCategory.GameFlow, "Client tried to change visor while not in lobby")) + await sender.Client.ReportCheatAsync(RpcCalls.SetVisorStr, CheatCategory.GameFlow, "Client tried to change visor while not in lobby")) { return false; } PlayerInfo.CurrentOutfit.VisorId = visor; + PlayerInfo.CurrentOutfit.VisorSequenceId = nextRpcSequenceId; return true; } - private async ValueTask HandleSetNamePlate(ClientPlayer sender, string skin) + private async ValueTask HandleSetNamePlate(ClientPlayer sender, string namePlate, byte nextRpcSequenceId) { if (Game.GameState == GameStates.Started && - await sender.Client.ReportCheatAsync(RpcCalls.SetNamePlate, CheatCategory.GameFlow, "Client tried to change skin while not in lobby")) + await sender.Client.ReportCheatAsync(RpcCalls.SetNamePlateStr, CheatCategory.GameFlow, "Client tried to change skin while not in lobby")) { return false; } - PlayerInfo.CurrentOutfit.NamePlateId = skin; + PlayerInfo.CurrentOutfit.NamePlateId = namePlate; + PlayerInfo.CurrentOutfit.NamePlateSequenceId = nextRpcSequenceId; return true; } @@ -1057,15 +1061,16 @@ namespace Impostor.Server.Net.Inner.Objects await _eventManager.CallAsync(new PlayerStartMeetingEvent(Game, Game.GetClientPlayer(this.OwnerId)!, this, deadPlayer)); } - private async ValueTask HandleSetPet(ClientPlayer sender, string pet) + private async ValueTask HandleSetPet(ClientPlayer sender, string pet, byte nextRpcSequenceId) { if (Game.GameState == GameStates.Started && - await sender.Client.ReportCheatAsync(RpcCalls.SetPet, CheatCategory.GameFlow, "Client tried to change pet while not in lobby")) + await sender.Client.ReportCheatAsync(RpcCalls.SetPetStr, CheatCategory.GameFlow, "Client tried to change pet while not in lobby")) { return false; } PlayerInfo.CurrentOutfit.PetId = pet; + PlayerInfo.CurrentOutfit.PetSequenceId = nextRpcSequenceId; return true; } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs index e449aae..8ce7071 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs @@ -215,5 +215,46 @@ namespace Impostor.Server.Net.Inner.Objects Tasks.Add(new TaskInfo(this, _eventManager, taskId++, taskType)); } } + + public byte GetNextRpcSequenceId(RpcCalls rpc) + { + var defaultOutfit = this.Outfits[PlayerOutfitType.Default]; + + byte nextRpcSequenceId = 0; + const byte SequenceIdAddition = 5; + + // ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault + switch (rpc) + { + case RpcCalls.SetHatStr: + defaultOutfit.HatSequenceId += SequenceIdAddition; + nextRpcSequenceId = defaultOutfit.HatSequenceId; + break; + case RpcCalls.SetSkinStr: + defaultOutfit.SkinSequenceId += SequenceIdAddition; + nextRpcSequenceId = defaultOutfit.SkinSequenceId; + break; + case RpcCalls.SetPetStr: + defaultOutfit.PetSequenceId += SequenceIdAddition; + nextRpcSequenceId = defaultOutfit.PetSequenceId; + break; + case RpcCalls.SetVisorStr: + defaultOutfit.VisorSequenceId += SequenceIdAddition; + nextRpcSequenceId = defaultOutfit.VisorSequenceId; + break; + case RpcCalls.SetNamePlateStr: + defaultOutfit.NamePlateSequenceId += SequenceIdAddition; + nextRpcSequenceId = defaultOutfit.NamePlateSequenceId; + break; + default: + _logger.LogError( + "{NextRpcSequenceIdName} was called for an RPC it doesn\'t know how to handle: {Rpc}", + nameof(GetNextRpcSequenceId), + rpc); + break; + } + + return nextRpcSequenceId; + } } } -- 2.39.5