diff --git a/src/Impostor.Api/Innersloth/Customization/PlayerOutfit.cs b/src/Impostor.Api/Innersloth/Customization/PlayerOutfit.cs index 59686a43..5289ac0e 100644 --- a/src/Impostor.Api/Innersloth/Customization/PlayerOutfit.cs +++ b/src/Impostor.Api/Innersloth/Customization/PlayerOutfit.cs @@ -2,19 +2,57 @@ namespace Impostor.Api.Innersloth.Customization { public class PlayerOutfit { - public string PlayerName { get; internal set; } = string.Empty; + private string _playerName = string.Empty; + private ColorType _color = (ColorType)(-1); + private string _hatId = "missing"; + private string _petId = "missing"; + private string _skinId = "missing"; + private string _visorId = "missing"; + private string _namePlateId = "missing"; - public ColorType Color { get; internal set; } = (ColorType)(-1); + public bool IsDirty { get; internal set; } - public string HatId { get; internal set; } = "missing"; + public string PlayerName + { + get => _playerName; + set => SetField(ref _playerName, value); + } - public string PetId { get; internal set; } = "missing"; + public ColorType Color + { + get => _color; + set => SetField(ref _color, value); + } - public string SkinId { get; internal set; } = "missing"; + public string HatId + { + get => _hatId; + set => SetField(ref _hatId, value); + } - public string VisorId { get; internal set; } = "missing"; + public string PetId + { + get => _petId; + set => SetField(ref _petId, value); + } - public string NamePlateId { get; internal set; } = "missing"; + public string SkinId + { + get => _skinId; + set => SetField(ref _skinId, value); + } + + public string VisorId + { + get => _visorId; + set => SetField(ref _visorId, value); + } + + public string NamePlateId + { + get => _namePlateId; + set => SetField(ref _namePlateId, value); + } public byte HatSequenceId { get; internal set; } = 0; @@ -70,5 +108,11 @@ namespace Impostor.Api.Innersloth.Customization VisorSequenceId = reader.ReadByte(); NamePlateSequenceId = reader.ReadByte(); } + + private void SetField(ref T field, T value) + { + field = value; + IsDirty = true; + } } } diff --git a/src/Impostor.Server/Net/Inner/InnerNetObject.cs b/src/Impostor.Server/Net/Inner/InnerNetObject.cs index 1fde0068..c7115f74 100644 --- a/src/Impostor.Server/Net/Inner/InnerNetObject.cs +++ b/src/Impostor.Server/Net/Inner/InnerNetObject.cs @@ -29,6 +29,8 @@ namespace Impostor.Server.Net.Inner public SpawnFlags SpawnFlags { get; internal set; } + public virtual bool IsDirty { get; internal set; } + public bool IsOwnedBy(IClientPlayer player) { return OwnerId == player.Client.Id || diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs index bd711618..99f3ddec 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs @@ -20,8 +20,9 @@ namespace Impostor.Server.Net.Inner.Objects public async ValueTask SetNameAsync(string name) { - PlayerInfo.PlayerName = name; + PlayerInfo.CurrentOutfit.PlayerName = name; + // TODO check playerinfo ownership using var writer = Game.StartRpc(NetId, RpcCalls.SetName); writer.Write(name); 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 4c80bde1..771de88e 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs @@ -663,11 +663,12 @@ namespace Impostor.Server.Net.Inner.Objects if (name != expected) { - if (await sender.Client.ReportCheatAsync(RpcCalls.SetName, CheatCategory.NameLimits, "Client sent SetName with incorrect name")) - { - await SetNameAsync(expected); - return false; - } + // TODO fix + //if (await sender.Client.ReportCheatAsync(RpcCalls.SetName, CheatCategory.NameLimits, $"Client sent SetName with incorrect name, got '{name}', expected '{expected}'")) + //{ + // await SetNameAsync(expected); + // return false; + //} } } else @@ -679,7 +680,7 @@ namespace Impostor.Server.Net.Inner.Objects } } - PlayerInfo.PlayerName = name; + PlayerInfo.CurrentOutfit.PlayerName = name; return true; } diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs index 0171cf62..9817c82c 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerInfo.cs @@ -29,7 +29,7 @@ namespace Impostor.Server.Net.Inner.Objects public int ClientId { get; internal set; } - public string PlayerName { get; internal set; } = string.Empty; + public string PlayerName => CurrentOutfit.PlayerName; public Dictionary Outfits { get; } = new() { @@ -60,6 +60,12 @@ namespace Impostor.Server.Net.Inner.Objects public uint PlayerLevel { get; internal set; } + public override bool IsDirty + { + get => CurrentOutfit.IsDirty; + internal set => CurrentOutfit.IsDirty = value; + } + public bool CanMurder(IGame game, IDateTimeProvider dateTimeProvider) { if (!IsImpostor) diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index df62848c..621b4974 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -315,6 +315,19 @@ namespace Impostor.Server.Net.State } } + // Check for dirty netobjects + foreach (var netObject in _allObjectsFast.Values) + { + if (netObject.IsDirty && netObject.OwnerId == ServerOwned) + { + _logger.LogInformation("Sending over {Type} {NetId}", netObject.GetType(), netObject.NetId); + var writer = MessageWriter.Get(MessageType.Reliable); + await WriteObjectData(writer, netObject); + await SendToAllAsync(writer); + netObject.IsDirty = false; + } + } + return true; } @@ -451,7 +464,8 @@ namespace Impostor.Server.Net.State // Sync all server-owned objects foreach (var obj in _allObjectsFast.Values) { - if (obj.OwnerId == -4) { + if (obj.OwnerId == -4) + { _logger.LogTrace("Sharing {Type} {NetId}", obj.GetType(), obj.NetId); var writer = MessageWriter.Get(MessageType.Reliable); WriteObjectSpawn(writer, obj); @@ -482,8 +496,6 @@ namespace Impostor.Server.Net.State WriteObjectSpawn(writer, playerInfo); await SendToAllAsync(writer); } - - } private bool AddNetObject(InnerNetObject obj) diff --git a/src/Impostor.Server/Net/State/Game.Outgoing.cs b/src/Impostor.Server/Net/State/Game.Outgoing.cs index 6e8dee2f..4dd95bcf 100644 --- a/src/Impostor.Server/Net/State/Game.Outgoing.cs +++ b/src/Impostor.Server/Net/State/Game.Outgoing.cs @@ -133,5 +133,16 @@ namespace Impostor.Server.Net.State message.EndMessage(); message.EndMessage(); } + + private async ValueTask WriteObjectData(IMessageWriter message, InnerNetObject obj) + { + message.StartMessage(MessageFlags.GameData); + Code.Serialize(message); + message.StartMessage(GameDataTag.DataFlag); + message.WritePacked(obj.NetId); + await obj.SerializeAsync(message, false); + message.EndMessage(); + message.EndMessage(); + } } } diff --git a/src/Impostor.Server/Net/State/Game.State.cs b/src/Impostor.Server/Net/State/Game.State.cs index e5eeaa08..e260972f 100644 --- a/src/Impostor.Server/Net/State/Game.State.cs +++ b/src/Impostor.Server/Net/State/Game.State.cs @@ -103,7 +103,6 @@ namespace Impostor.Server.Net.State break; } - } return true;