From 7120e8736a39f04b51b5bffb62521002ba5d59f5 Mon Sep 17 00:00:00 2001 From: Errant <35878406+Errant-4@users.noreply.github.com> Date: Thu, 18 Apr 2024 05:27:11 +0200 Subject: [PATCH] Cleanup in HumanoidCharacterAppearance (#26974) * namespace * Tidy up the code for selecting random humanoid color --- .../Humanoid/HumanoidCharacterAppearance.cs | 446 +++++++++--------- 1 file changed, 219 insertions(+), 227 deletions(-) diff --git a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs index 1ffcd1870b..44fcef9c4f 100644 --- a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs +++ b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs @@ -5,248 +5,240 @@ using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Serialization; -namespace Content.Shared.Humanoid +namespace Content.Shared.Humanoid; + +[DataDefinition] +[Serializable, NetSerializable] +public sealed partial class HumanoidCharacterAppearance : ICharacterAppearance { - [DataDefinition] - [Serializable, NetSerializable] - public sealed partial class HumanoidCharacterAppearance : ICharacterAppearance + public HumanoidCharacterAppearance(string hairStyleId, + Color hairColor, + string facialHairStyleId, + Color facialHairColor, + Color eyeColor, + Color skinColor, + List markings) { - public HumanoidCharacterAppearance(string hairStyleId, - Color hairColor, - string facialHairStyleId, - Color facialHairColor, - Color eyeColor, - Color skinColor, - List markings) + HairStyleId = hairStyleId; + HairColor = ClampColor(hairColor); + FacialHairStyleId = facialHairStyleId; + FacialHairColor = ClampColor(facialHairColor); + EyeColor = ClampColor(eyeColor); + SkinColor = ClampColor(skinColor); + Markings = markings; + } + + [DataField("hair")] + public string HairStyleId { get; private set; } + + [DataField("hairColor")] + public Color HairColor { get; private set; } + + [DataField("facialHair")] + public string FacialHairStyleId { get; private set; } + + [DataField("facialHairColor")] + public Color FacialHairColor { get; private set; } + + [DataField("eyeColor")] + public Color EyeColor { get; private set; } + + [DataField("skinColor")] + public Color SkinColor { get; private set; } + + [DataField("markings")] + public List Markings { get; private set; } + + public HumanoidCharacterAppearance WithHairStyleName(string newName) + { + return new(newName, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, Markings); + } + + public HumanoidCharacterAppearance WithHairColor(Color newColor) + { + return new(HairStyleId, newColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, Markings); + } + + public HumanoidCharacterAppearance WithFacialHairStyleName(string newName) + { + return new(HairStyleId, HairColor, newName, FacialHairColor, EyeColor, SkinColor, Markings); + } + + public HumanoidCharacterAppearance WithFacialHairColor(Color newColor) + { + return new(HairStyleId, HairColor, FacialHairStyleId, newColor, EyeColor, SkinColor, Markings); + } + + public HumanoidCharacterAppearance WithEyeColor(Color newColor) + { + return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, newColor, SkinColor, Markings); + } + + public HumanoidCharacterAppearance WithSkinColor(Color newColor) + { + return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, newColor, Markings); + } + + public HumanoidCharacterAppearance WithMarkings(List newMarkings) + { + return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, newMarkings); + } + + public HumanoidCharacterAppearance() : this( + HairStyles.DefaultHairStyle, + Color.Black, + HairStyles.DefaultFacialHairStyle, + Color.Black, + Color.Black, + Humanoid.SkinColor.ValidHumanSkinTone, + new () + ) + { + } + + public static HumanoidCharacterAppearance DefaultWithSpecies(string species) + { + var speciesPrototype = IoCManager.Resolve().Index(species); + var skinColor = speciesPrototype.SkinColoration switch { - HairStyleId = hairStyleId; - HairColor = ClampColor(hairColor); - FacialHairStyleId = facialHairStyleId; - FacialHairColor = ClampColor(facialHairColor); - EyeColor = ClampColor(eyeColor); - SkinColor = ClampColor(skinColor); - Markings = markings; - } + HumanoidSkinColor.HumanToned => Humanoid.SkinColor.HumanSkinTone(speciesPrototype.DefaultHumanSkinTone), + HumanoidSkinColor.Hues => speciesPrototype.DefaultSkinTone, + HumanoidSkinColor.TintedHues => Humanoid.SkinColor.TintedHues(speciesPrototype.DefaultSkinTone), + _ => Humanoid.SkinColor.ValidHumanSkinTone + }; - [DataField("hair")] - public string HairStyleId { get; private set; } - - [DataField("hairColor")] - public Color HairColor { get; private set; } - - [DataField("facialHair")] - public string FacialHairStyleId { get; private set; } - - [DataField("facialHairColor")] - public Color FacialHairColor { get; private set; } - - [DataField("eyeColor")] - public Color EyeColor { get; private set; } - - [DataField("skinColor")] - public Color SkinColor { get; private set; } - - [DataField("markings")] - public List Markings { get; private set; } - - public HumanoidCharacterAppearance WithHairStyleName(string newName) - { - return new(newName, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, Markings); - } - - public HumanoidCharacterAppearance WithHairColor(Color newColor) - { - return new(HairStyleId, newColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, Markings); - } - - public HumanoidCharacterAppearance WithFacialHairStyleName(string newName) - { - return new(HairStyleId, HairColor, newName, FacialHairColor, EyeColor, SkinColor, Markings); - } - - public HumanoidCharacterAppearance WithFacialHairColor(Color newColor) - { - return new(HairStyleId, HairColor, FacialHairStyleId, newColor, EyeColor, SkinColor, Markings); - } - - public HumanoidCharacterAppearance WithEyeColor(Color newColor) - { - return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, newColor, SkinColor, Markings); - } - - public HumanoidCharacterAppearance WithSkinColor(Color newColor) - { - return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, newColor, Markings); - } - - public HumanoidCharacterAppearance WithMarkings(List newMarkings) - { - return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, newMarkings); - } - - public HumanoidCharacterAppearance() : this( + return new( HairStyles.DefaultHairStyle, Color.Black, HairStyles.DefaultFacialHairStyle, Color.Black, Color.Black, - Humanoid.SkinColor.ValidHumanSkinTone, + skinColor, new () - ) + ); + } + + private static IReadOnlyList RealisticEyeColors = new List + { + Color.Brown, + Color.Gray, + Color.Azure, + Color.SteelBlue, + Color.Black + }; + + public static HumanoidCharacterAppearance Random(string species, Sex sex) + { + var random = IoCManager.Resolve(); + var markingManager = IoCManager.Resolve(); + var hairStyles = markingManager.MarkingsByCategoryAndSpecies(MarkingCategories.Hair, species).Keys.ToList(); + var facialHairStyles = markingManager.MarkingsByCategoryAndSpecies(MarkingCategories.FacialHair, species).Keys.ToList(); + + var newHairStyle = hairStyles.Count > 0 + ? random.Pick(hairStyles) + : HairStyles.DefaultHairStyle; + + var newFacialHairStyle = facialHairStyles.Count == 0 || sex == Sex.Female + ? HairStyles.DefaultFacialHairStyle + : random.Pick(facialHairStyles); + + var newHairColor = random.Pick(HairStyles.RealisticHairColors); + newHairColor = newHairColor + .WithRed(RandomizeColor(newHairColor.R)) + .WithGreen(RandomizeColor(newHairColor.G)) + .WithBlue(RandomizeColor(newHairColor.B)); + + // TODO: Add random markings + + var newEyeColor = random.Pick(RealisticEyeColors); + + var skinType = IoCManager.Resolve().Index(species).SkinColoration; + + var newSkinColor = new Color(random.NextFloat(1), random.NextFloat(1), random.NextFloat(1), 1); + switch (skinType) { - } - - public static HumanoidCharacterAppearance DefaultWithSpecies(string species) - { - var speciesPrototype = IoCManager.Resolve().Index(species); - var skinColor = speciesPrototype.SkinColoration switch - { - HumanoidSkinColor.HumanToned => Humanoid.SkinColor.HumanSkinTone(speciesPrototype.DefaultHumanSkinTone), - HumanoidSkinColor.Hues => speciesPrototype.DefaultSkinTone, - HumanoidSkinColor.TintedHues => Humanoid.SkinColor.TintedHues(speciesPrototype.DefaultSkinTone), - _ => Humanoid.SkinColor.ValidHumanSkinTone - }; - - return new( - HairStyles.DefaultHairStyle, - Color.Black, - HairStyles.DefaultFacialHairStyle, - Color.Black, - Color.Black, - skinColor, - new () - ); - } - - private static IReadOnlyList RealisticEyeColors = new List - { - Color.Brown, - Color.Gray, - Color.Azure, - Color.SteelBlue, - Color.Black - }; - - public static HumanoidCharacterAppearance Random(string species, Sex sex) - { - var random = IoCManager.Resolve(); - var markingManager = IoCManager.Resolve(); - var hairStyles = markingManager.MarkingsByCategoryAndSpecies(MarkingCategories.Hair, species).Keys.ToList(); - var facialHairStyles = markingManager.MarkingsByCategoryAndSpecies(MarkingCategories.FacialHair, species).Keys.ToList(); - - var newHairStyle = hairStyles.Count > 0 - ? random.Pick(hairStyles) - : HairStyles.DefaultHairStyle; - - var newFacialHairStyle = facialHairStyles.Count == 0 || sex == Sex.Female - ? HairStyles.DefaultFacialHairStyle - : random.Pick(facialHairStyles); - - var newHairColor = random.Pick(HairStyles.RealisticHairColors); - newHairColor = newHairColor - .WithRed(RandomizeColor(newHairColor.R)) - .WithGreen(RandomizeColor(newHairColor.G)) - .WithBlue(RandomizeColor(newHairColor.B)); - - // TODO: Add random markings - - var newEyeColor = random.Pick(RealisticEyeColors); - - var skinType = IoCManager.Resolve().Index(species).SkinColoration; - - var newSkinColor = Humanoid.SkinColor.ValidHumanSkinTone; - switch (skinType) - { - case HumanoidSkinColor.HumanToned: - var tone = random.Next(0, 100); - newSkinColor = Humanoid.SkinColor.HumanSkinTone(tone); - break; - case HumanoidSkinColor.Hues: - case HumanoidSkinColor.TintedHues: - var rbyte = random.NextByte(); - var gbyte = random.NextByte(); - var bbyte = random.NextByte(); - newSkinColor = new Color(rbyte, gbyte, bbyte); - break; - } - - if (skinType == HumanoidSkinColor.TintedHues) - { + case HumanoidSkinColor.HumanToned: + var tone = Math.Round(Humanoid.SkinColor.HumanSkinToneFromColor(newSkinColor)); + newSkinColor = Humanoid.SkinColor.HumanSkinTone((int)tone); + break; + case HumanoidSkinColor.Hues: + break; + case HumanoidSkinColor.TintedHues: newSkinColor = Humanoid.SkinColor.ValidTintedHuesSkinTone(newSkinColor); - } - - return new HumanoidCharacterAppearance(newHairStyle, newHairColor, newFacialHairStyle, newHairColor, newEyeColor, newSkinColor, new ()); - - float RandomizeColor(float channel) - { - return MathHelper.Clamp01(channel + random.Next(-25, 25) / 100f); - } + break; } - public static Color ClampColor(Color color) + return new HumanoidCharacterAppearance(newHairStyle, newHairColor, newFacialHairStyle, newHairColor, newEyeColor, newSkinColor, new ()); + + float RandomizeColor(float channel) { - return new(color.RByte, color.GByte, color.BByte); - } - - public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance, string species, Sex sex) - { - var hairStyleId = appearance.HairStyleId; - var facialHairStyleId = appearance.FacialHairStyleId; - - var hairColor = ClampColor(appearance.HairColor); - var facialHairColor = ClampColor(appearance.FacialHairColor); - var eyeColor = ClampColor(appearance.EyeColor); - - var proto = IoCManager.Resolve(); - var markingManager = IoCManager.Resolve(); - - if (!markingManager.MarkingsByCategory(MarkingCategories.Hair).ContainsKey(hairStyleId)) - { - hairStyleId = HairStyles.DefaultHairStyle; - } - - if (!markingManager.MarkingsByCategory(MarkingCategories.FacialHair).ContainsKey(facialHairStyleId)) - { - facialHairStyleId = HairStyles.DefaultFacialHairStyle; - } - - var markingSet = new MarkingSet(); - var skinColor = appearance.SkinColor; - if (proto.TryIndex(species, out SpeciesPrototype? speciesProto)) - { - markingSet = new MarkingSet(appearance.Markings, speciesProto.MarkingPoints, markingManager, proto); - markingSet.EnsureValid(markingManager); - - if (!Humanoid.SkinColor.VerifySkinColor(speciesProto.SkinColoration, skinColor)) - { - skinColor = Humanoid.SkinColor.ValidSkinTone(speciesProto.SkinColoration, skinColor); - } - - markingSet.EnsureSpecies(species, skinColor, markingManager); - markingSet.EnsureSexes(sex, markingManager); - } - - return new HumanoidCharacterAppearance( - hairStyleId, - hairColor, - facialHairStyleId, - facialHairColor, - eyeColor, - skinColor, - markingSet.GetForwardEnumerator().ToList()); - } - - public bool MemberwiseEquals(ICharacterAppearance maybeOther) - { - if (maybeOther is not HumanoidCharacterAppearance other) return false; - if (HairStyleId != other.HairStyleId) return false; - if (!HairColor.Equals(other.HairColor)) return false; - if (FacialHairStyleId != other.FacialHairStyleId) return false; - if (!FacialHairColor.Equals(other.FacialHairColor)) return false; - if (!EyeColor.Equals(other.EyeColor)) return false; - if (!SkinColor.Equals(other.SkinColor)) return false; - if (!Markings.SequenceEqual(other.Markings)) return false; - return true; + return MathHelper.Clamp01(channel + random.Next(-25, 25) / 100f); } } + + public static Color ClampColor(Color color) + { + return new(color.RByte, color.GByte, color.BByte); + } + + public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance, string species, Sex sex) + { + var hairStyleId = appearance.HairStyleId; + var facialHairStyleId = appearance.FacialHairStyleId; + + var hairColor = ClampColor(appearance.HairColor); + var facialHairColor = ClampColor(appearance.FacialHairColor); + var eyeColor = ClampColor(appearance.EyeColor); + + var proto = IoCManager.Resolve(); + var markingManager = IoCManager.Resolve(); + + if (!markingManager.MarkingsByCategory(MarkingCategories.Hair).ContainsKey(hairStyleId)) + { + hairStyleId = HairStyles.DefaultHairStyle; + } + + if (!markingManager.MarkingsByCategory(MarkingCategories.FacialHair).ContainsKey(facialHairStyleId)) + { + facialHairStyleId = HairStyles.DefaultFacialHairStyle; + } + + var markingSet = new MarkingSet(); + var skinColor = appearance.SkinColor; + if (proto.TryIndex(species, out SpeciesPrototype? speciesProto)) + { + markingSet = new MarkingSet(appearance.Markings, speciesProto.MarkingPoints, markingManager, proto); + markingSet.EnsureValid(markingManager); + + if (!Humanoid.SkinColor.VerifySkinColor(speciesProto.SkinColoration, skinColor)) + { + skinColor = Humanoid.SkinColor.ValidSkinTone(speciesProto.SkinColoration, skinColor); + } + + markingSet.EnsureSpecies(species, skinColor, markingManager); + markingSet.EnsureSexes(sex, markingManager); + } + + return new HumanoidCharacterAppearance( + hairStyleId, + hairColor, + facialHairStyleId, + facialHairColor, + eyeColor, + skinColor, + markingSet.GetForwardEnumerator().ToList()); + } + + public bool MemberwiseEquals(ICharacterAppearance maybeOther) + { + if (maybeOther is not HumanoidCharacterAppearance other) return false; + if (HairStyleId != other.HairStyleId) return false; + if (!HairColor.Equals(other.HairColor)) return false; + if (FacialHairStyleId != other.FacialHairStyleId) return false; + if (!FacialHairColor.Equals(other.FacialHairColor)) return false; + if (!EyeColor.Equals(other.EyeColor)) return false; + if (!SkinColor.Equals(other.SkinColor)) return false; + if (!Markings.SequenceEqual(other.Markings)) return false; + return true; + } }