diff --git a/Content.IntegrationTests/Tests/Lobby/CharacterCreationTest.cs b/Content.IntegrationTests/Tests/Lobby/CharacterCreationTest.cs new file mode 100644 index 0000000000..afc4cbd6a9 --- /dev/null +++ b/Content.IntegrationTests/Tests/Lobby/CharacterCreationTest.cs @@ -0,0 +1,125 @@ +using System.Threading.Tasks; +using Content.Client; +using Content.Client.Interfaces; +using Content.Client.State; +using Content.Server.GameTicking; +using Content.Server.Interfaces; +using Content.Server.Interfaces.GameTicking; +using Content.Server.Preferences; +using Content.Shared; +using Content.Shared.Preferences; +using NUnit.Framework; +using Robust.Client.Interfaces.State; +using Robust.Shared.Interfaces.Configuration; +using Robust.Shared.Interfaces.Network; + +namespace Content.IntegrationTests.Tests.Lobby +{ + [TestFixture] + [TestOf(typeof(ClientPreferencesManager))] + [TestOf(typeof(ServerPreferencesManager))] + public class CharacterCreationTest : ContentIntegrationTest + { + [Test] + public async Task CreateDeleteCreateTest() + { + var (client, server) = await StartConnectedServerClientPair(); + + var clientNetManager = client.ResolveDependency(); + var clientStateManager = client.ResolveDependency(); + var clientPrefManager = client.ResolveDependency(); + + var serverConfig = server.ResolveDependency(); + var serverTicker = server.ResolveDependency(); + var serverPrefManager = server.ResolveDependency(); + + await server.WaitIdleAsync(); + await client.WaitIdleAsync(); + + await server.WaitAssertion(() => + { + var lobbyCvar = CCVars.GameLobbyEnabled; + serverConfig.SetCVar(lobbyCvar.Name, true); + + serverTicker.RestartRound(); + }); + + Assert.That(serverTicker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby)); + + await WaitUntil(client, () => clientStateManager.CurrentState is LobbyState, maxTicks: 60); + + Assert.NotNull(clientNetManager.ServerChannel); + + var clientNetId = clientNetManager.ServerChannel.UserId; + HumanoidCharacterProfile profile = null; + + await client.WaitAssertion(() => + { + clientPrefManager.SelectCharacter(0); + + var clientCharacters = clientPrefManager.Preferences.Characters; + Assert.That(clientCharacters.Count, Is.EqualTo(1)); + + Assert.That(clientStateManager.CurrentState, Is.TypeOf()); + + profile = HumanoidCharacterProfile.Random(); + clientPrefManager.CreateCharacter(profile); + + clientCharacters = clientPrefManager.Preferences.Characters; + + Assert.That(clientCharacters.Count, Is.EqualTo(2)); + Assert.That(clientCharacters[1].MemberwiseEquals(profile)); + }); + + await WaitUntil(server, () => serverPrefManager.GetPreferences(clientNetId).Characters.Count == 2, maxTicks: 60); + + await server.WaitAssertion(() => + { + var serverCharacters = serverPrefManager.GetPreferences(clientNetId).Characters; + + Assert.That(serverCharacters.Count, Is.EqualTo(2)); + Assert.That(serverCharacters[1].MemberwiseEquals(profile)); + }); + + await client.WaitAssertion(() => + { + clientPrefManager.DeleteCharacter(1); + + var clientCharacters = clientPrefManager.Preferences.Characters.Count; + Assert.That(clientCharacters, Is.EqualTo(1)); + }); + + await WaitUntil(server, () => serverPrefManager.GetPreferences(clientNetId).Characters.Count == 1, maxTicks: 60); + + await server.WaitAssertion(() => + { + var serverCharacters = serverPrefManager.GetPreferences(clientNetId).Characters.Count; + Assert.That(serverCharacters, Is.EqualTo(1)); + }); + + await client.WaitIdleAsync(); + + await client.WaitAssertion(() => + { + profile = HumanoidCharacterProfile.Random(); + + clientPrefManager.CreateCharacter(profile); + + var clientCharacters = clientPrefManager.Preferences.Characters; + + Assert.That(clientCharacters.Count, Is.EqualTo(2)); + Assert.That(clientCharacters[1].MemberwiseEquals(profile)); + }); + + await WaitUntil(server, () => serverPrefManager.GetPreferences(clientNetId).Characters.Count == 2, maxTicks: 60); + + await server.WaitAssertion(() => + { + var serverCharacters = serverPrefManager.GetPreferences(clientNetId).Characters; + + Assert.That(serverCharacters.Count, Is.EqualTo(2)); + Assert.That(serverCharacters[1].MemberwiseEquals(profile)); + }); + } + } +} diff --git a/Content.Shared/Preferences/HumanoidCharacterAppearance.cs b/Content.Shared/Preferences/HumanoidCharacterAppearance.cs index 694a500604..6e04371213 100644 --- a/Content.Shared/Preferences/HumanoidCharacterAppearance.cs +++ b/Content.Shared/Preferences/HumanoidCharacterAppearance.cs @@ -20,11 +20,11 @@ namespace Content.Shared.Preferences Color skinColor) { HairStyleName = hairStyleName; - HairColor = hairColor; + HairColor = ClampColor(hairColor); FacialHairStyleName = facialHairStyleName; - FacialHairColor = facialHairColor; - EyeColor = eyeColor; - SkinColor = skinColor; + FacialHairColor = ClampColor(facialHairColor); + EyeColor = ClampColor(eyeColor); + SkinColor = ClampColor(skinColor); } public string HairStyleName { get; } @@ -102,6 +102,11 @@ namespace Content.Shared.Preferences } } + public static Color ClampColor(Color color) + { + return new Color(color.RByte, color.GByte, color.BByte); + } + public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance) { string hairStyleName; @@ -136,22 +141,17 @@ namespace Content.Shared.Preferences facialHairColor, eyeColor, skinColor); - - static Color ClampColor(Color color) - { - return new Color(color.RByte, color.GByte, color.BByte); - } } public bool MemberwiseEquals(ICharacterAppearance maybeOther) { if (!(maybeOther is HumanoidCharacterAppearance other)) return false; if (HairStyleName != other.HairStyleName) return false; - if (HairColor != other.HairColor) return false; + if (!HairColor.Equals(other.HairColor)) return false; if (FacialHairStyleName != other.FacialHairStyleName) return false; - if (FacialHairColor != other.FacialHairColor) return false; - if (EyeColor != other.EyeColor) return false; - if (SkinColor != other.SkinColor) return false; + if (!FacialHairColor.Equals(other.FacialHairColor)) return false; + if (!EyeColor.Equals(other.EyeColor)) return false; + if (!SkinColor.Equals(other.SkinColor)) return false; return true; } } diff --git a/Content.Shared/Preferences/HumanoidCharacterProfile.cs b/Content.Shared/Preferences/HumanoidCharacterProfile.cs index 4601c33cdc..83800e4baf 100644 --- a/Content.Shared/Preferences/HumanoidCharacterProfile.cs +++ b/Content.Shared/Preferences/HumanoidCharacterProfile.cs @@ -1,3 +1,4 @@ +#nullable enable using System; using System.Collections.Generic; using System.Linq; @@ -243,5 +244,22 @@ namespace Content.Shared.Preferences if (!_antagPreferences.SequenceEqual(other._antagPreferences)) return false; return Appearance.MemberwiseEquals(other.Appearance); } + + public override bool Equals(object? obj) + { + return obj is HumanoidCharacterProfile other && MemberwiseEquals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine( + Name, + Age, + Sex, + PreferenceUnavailable, + _jobPriorities, + _antagPreferences, + Appearance); + } } }