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
This commit is contained in:
danbudworthmead authored and GitHub committed 2024-10-05 12:44:08 +02:00
1 parent 9b27edbb11
commit 2603f34b89
9 files changed
+116 -42

No files matched your search

@@ -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;
/// <summary>
/// Gets a value indicating whether a player outfit is complete or whether it needs to receive additional cosmetics.
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -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);
}
@@ -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<bool> HandleSetHat(ClientPlayer sender, string hat)
private async ValueTask<bool> 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<bool> HandleSetSkin(ClientPlayer sender, string skin)
private async ValueTask<bool> 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<bool> HandleSetVisor(ClientPlayer sender, string visor)
private async ValueTask<bool> 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<bool> HandleSetNamePlate(ClientPlayer sender, string skin)
private async ValueTask<bool> 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<bool> HandleSetPet(ClientPlayer sender, string pet)
private async ValueTask<bool> 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;
}
@@ -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;
}
}
}