Sex restriction for markings (#19894)

* Add sex restriction to markings

* Apply to existing systems
This commit is contained in:
Morb
2023-09-19 23:56:10 +03:00
committed by GitHub
parent 1b2fd313a0
commit 835bde4c6e
13 changed files with 169 additions and 20 deletions

View File

@@ -170,11 +170,11 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
var facialHair = new Marking(profile.Appearance.FacialHairStyleId, var facialHair = new Marking(profile.Appearance.FacialHairStyleId,
new[] { facialHairColor }); new[] { facialHairColor });
if (_markingManager.CanBeApplied(profile.Species, hair, _prototypeManager)) if (_markingManager.CanBeApplied(profile.Species, profile.Sex, hair, _prototypeManager))
{ {
markings.AddBack(MarkingCategories.Hair, hair); markings.AddBack(MarkingCategories.Hair, hair);
} }
if (_markingManager.CanBeApplied(profile.Species, facialHair, _prototypeManager)) if (_markingManager.CanBeApplied(profile.Species, profile.Sex, facialHair, _prototypeManager))
{ {
markings.AddBack(MarkingCategories.FacialHair, facialHair); markings.AddBack(MarkingCategories.FacialHair, facialHair);
} }
@@ -192,6 +192,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
} }
markings.EnsureSpecies(profile.Species, profile.Appearance.SkinColor, _markingManager, _prototypeManager); markings.EnsureSpecies(profile.Species, profile.Appearance.SkinColor, _markingManager, _prototypeManager);
markings.EnsureSexes(profile.Sex, _markingManager);
markings.EnsureDefault( markings.EnsureDefault(
profile.Appearance.SkinColor, profile.Appearance.SkinColor,
profile.Appearance.EyeColor, profile.Appearance.EyeColor,

View File

@@ -42,7 +42,7 @@ public sealed class HumanoidMarkingModifierBoundUserInterface : BoundUserInterfa
return; return;
} }
_window.SetState(cast.MarkingSet, cast.Species, cast.SkinColor, cast.CustomBaseLayers); _window.SetState(cast.MarkingSet, cast.Species, cast.Sex, cast.SkinColor, cast.CustomBaseLayers);
} }
private void SendMarkingSet(MarkingSet set) private void SendMarkingSet(MarkingSet set)

View File

@@ -63,6 +63,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
public void SetState( public void SetState(
MarkingSet markings, MarkingSet markings,
string species, string species,
Sex sex,
Color skinColor, Color skinColor,
Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> info Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> info
) )
@@ -84,7 +85,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
eyesColor = eyes.Color.Value; eyesColor = eyes.Color.Value;
} }
MarkingPickerWidget.SetData(markings, species, skinColor, eyesColor); MarkingPickerWidget.SetData(markings, species, sex, skinColor, eyesColor);
} }
private sealed class HumanoidBaseLayerModifier : BoxContainer private sealed class HumanoidBaseLayerModifier : BoxContainer

View File

@@ -35,6 +35,7 @@ public sealed partial class MarkingPicker : Control
private List<MarkingCategories> _markingCategories = Enum.GetValues<MarkingCategories>().ToList(); private List<MarkingCategories> _markingCategories = Enum.GetValues<MarkingCategories>().ToList();
private string _currentSpecies = SharedHumanoidAppearanceSystem.DefaultSpecies; private string _currentSpecies = SharedHumanoidAppearanceSystem.DefaultSpecies;
private Sex _currentSex = Sex.Unsexed;
public Color CurrentSkinColor = Color.White; public Color CurrentSkinColor = Color.White;
public Color CurrentEyeColor = Color.Black; public Color CurrentEyeColor = Color.Black;
public Marking? HairMarking; public Marking? HairMarking;
@@ -77,7 +78,7 @@ public sealed partial class MarkingPicker : Control
} }
} }
public void SetData(List<Marking> newMarkings, string species, Color skinColor, Color eyeColor) public void SetData(List<Marking> newMarkings, string species, Sex sex, Color skinColor, Color eyeColor)
{ {
var pointsProto = _prototypeManager var pointsProto = _prototypeManager
.Index<SpeciesPrototype>(species).MarkingPoints; .Index<SpeciesPrototype>(species).MarkingPoints;
@@ -89,6 +90,7 @@ public sealed partial class MarkingPicker : Control
} }
_currentSpecies = species; _currentSpecies = species;
_currentSex = sex;
CurrentSkinColor = skinColor; CurrentSkinColor = skinColor;
CurrentEyeColor = eyeColor; CurrentEyeColor = eyeColor;
@@ -96,7 +98,7 @@ public sealed partial class MarkingPicker : Control
PopulateUsed(); PopulateUsed();
} }
public void SetData(MarkingSet set, string species, Color skinColor, Color eyeColor) public void SetData(MarkingSet set, string species, Sex sex, Color skinColor, Color eyeColor)
{ {
_currentMarkings = set; _currentMarkings = set;
@@ -106,6 +108,7 @@ public sealed partial class MarkingPicker : Control
} }
_currentSpecies = species; _currentSpecies = species;
_currentSex = sex;
CurrentSkinColor = skinColor; CurrentSkinColor = skinColor;
CurrentEyeColor = eyeColor; CurrentEyeColor = eyeColor;
@@ -182,8 +185,8 @@ public sealed partial class MarkingPicker : Control
_selectedUnusedMarking = null; _selectedUnusedMarking = null;
var markings = IgnoreSpecies var markings = IgnoreSpecies
? _markingManager.MarkingsByCategory(_selectedMarkingCategory) ? _markingManager.MarkingsByCategoryAndSex(_selectedMarkingCategory, _currentSex)
: _markingManager.MarkingsByCategoryAndSpecies(_selectedMarkingCategory, _currentSpecies); : _markingManager.MarkingsByCategoryAndSpeciesAndSex(_selectedMarkingCategory, _currentSpecies, _currentSex);
var sortedMarkings = markings.Values.Where(m => var sortedMarkings = markings.Values.Where(m =>
m.ID.ToLower().Contains(filter.ToLower()) || m.ID.ToLower().Contains(filter.ToLower()) ||
@@ -319,6 +322,22 @@ public sealed partial class MarkingPicker : Control
_currentMarkings = new(markingList, speciesPrototype.MarkingPoints, _markingManager, _prototypeManager); _currentMarkings = new(markingList, speciesPrototype.MarkingPoints, _markingManager, _prototypeManager);
_currentMarkings.EnsureSpecies(species, null, _markingManager); _currentMarkings.EnsureSpecies(species, null, _markingManager);
_currentMarkings.EnsureSexes(_currentSex, _markingManager);
Populate(CMarkingSearch.Text);
PopulateUsed();
}
public void SetSex(Sex sex)
{
_currentSex = sex;
var markingList = _currentMarkings.GetForwardEnumerator().ToList();
var speciesPrototype = _prototypeManager.Index<SpeciesPrototype>(_currentSpecies);
_currentMarkings = new(markingList, speciesPrototype.MarkingPoints, _markingManager, _prototypeManager);
_currentMarkings.EnsureSpecies(_currentSpecies, null, _markingManager);
_currentMarkings.EnsureSexes(_currentSex, _markingManager);
Populate(CMarkingSearch.Text); Populate(CMarkingSearch.Text);
PopulateUsed(); PopulateUsed();

View File

@@ -748,6 +748,7 @@ namespace Content.Client.Preferences.UI
break; break;
} }
UpdateGenderControls(); UpdateGenderControls();
CMarkings.SetSex(newSex);
IsDirty = true; IsDirty = true;
} }
@@ -917,7 +918,7 @@ namespace Content.Client.Preferences.UI
} }
CMarkings.SetData(Profile.Appearance.Markings, Profile.Species, CMarkings.SetData(Profile.Appearance.Markings, Profile.Species,
Profile.Appearance.SkinColor, Profile.Appearance.EyeColor Profile.Sex, Profile.Appearance.SkinColor, Profile.Appearance.EyeColor
); );
} }
@@ -1002,7 +1003,7 @@ namespace Content.Client.Preferences.UI
_markingManager.Markings.TryGetValue(Profile.Appearance.HairStyleId, out var hairProto) _markingManager.Markings.TryGetValue(Profile.Appearance.HairStyleId, out var hairProto)
) )
{ {
if (_markingManager.CanBeApplied(Profile.Species, hairProto, _prototypeManager)) if (_markingManager.CanBeApplied(Profile.Species, Profile.Sex, hairProto, _prototypeManager))
{ {
if (_markingManager.MustMatchSkin(Profile.Species, HumanoidVisualLayers.Hair, out var _, _prototypeManager)) if (_markingManager.MustMatchSkin(Profile.Species, HumanoidVisualLayers.Hair, out var _, _prototypeManager))
{ {
@@ -1037,7 +1038,7 @@ namespace Content.Client.Preferences.UI
_markingManager.Markings.TryGetValue(Profile.Appearance.FacialHairStyleId, out var facialHairProto) _markingManager.Markings.TryGetValue(Profile.Appearance.FacialHairStyleId, out var facialHairProto)
) )
{ {
if (_markingManager.CanBeApplied(Profile.Species, facialHairProto, _prototypeManager)) if (_markingManager.CanBeApplied(Profile.Species, Profile.Sex, facialHairProto, _prototypeManager))
{ {
if (_markingManager.MustMatchSkin(Profile.Species, HumanoidVisualLayers.Hair, out var _, _prototypeManager)) if (_markingManager.MustMatchSkin(Profile.Species, HumanoidVisualLayers.Hair, out var _, _prototypeManager))
{ {

View File

@@ -37,6 +37,7 @@ public sealed partial class HumanoidAppearanceSystem
uid, uid,
HumanoidMarkingModifierKey.Key, HumanoidMarkingModifierKey.Key,
new HumanoidMarkingModifierState(component.MarkingSet, component.Species, new HumanoidMarkingModifierState(component.MarkingSet, component.Species,
component.Sex,
component.SkinColor, component.SkinColor,
component.CustomBaseLayers component.CustomBaseLayers
)); ));
@@ -70,6 +71,7 @@ public sealed partial class HumanoidAppearanceSystem
uid, uid,
HumanoidMarkingModifierKey.Key, HumanoidMarkingModifierKey.Key,
new HumanoidMarkingModifierState(component.MarkingSet, component.Species, new HumanoidMarkingModifierState(component.MarkingSet, component.Species,
component.Sex,
component.SkinColor, component.SkinColor,
component.CustomBaseLayers component.CustomBaseLayers
)); ));
@@ -94,6 +96,7 @@ public sealed partial class HumanoidAppearanceSystem
uid, uid,
HumanoidMarkingModifierKey.Key, HumanoidMarkingModifierKey.Key,
new HumanoidMarkingModifierState(component.MarkingSet, component.Species, new HumanoidMarkingModifierState(component.MarkingSet, component.Species,
component.Sex,
component.SkinColor, component.SkinColor,
component.CustomBaseLayers component.CustomBaseLayers
)); ));

View File

@@ -188,7 +188,7 @@ namespace Content.Shared.Humanoid
return new(color.RByte, color.GByte, color.BByte); return new(color.RByte, color.GByte, color.BByte);
} }
public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance, string species) public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance, string species, Sex sex)
{ {
var hairStyleId = appearance.HairStyleId; var hairStyleId = appearance.HairStyleId;
var facialHairStyleId = appearance.FacialHairStyleId; var facialHairStyleId = appearance.FacialHairStyleId;
@@ -223,6 +223,7 @@ namespace Content.Shared.Humanoid
} }
markingSet.EnsureSpecies(species, skinColor, markingManager); markingSet.EnsureSpecies(species, skinColor, markingManager);
markingSet.EnsureSexes(sex, markingManager);
} }
return new HumanoidCharacterAppearance( return new HumanoidCharacterAppearance(

View File

@@ -66,6 +66,74 @@ namespace Content.Shared.Humanoid.Markings
{ {
continue; continue;
} }
res.Add(key, marking);
}
return res;
}
/// <summary>
/// Markings by category and sex.
/// </summary>
/// <param name="category"></param>
/// <param name="sex"></param>
/// <remarks>
/// This is done per category, as enumerating over every single marking by species isn't useful.
/// Please make a pull request if you find a use case for that behavior.
/// </remarks>
/// <returns></returns>
public IReadOnlyDictionary<string, MarkingPrototype> MarkingsByCategoryAndSex(MarkingCategories category,
Sex sex)
{
var res = new Dictionary<string, MarkingPrototype>();
foreach (var (key, marking) in MarkingsByCategory(category))
{
if (marking.SexRestriction != null && marking.SexRestriction != sex)
{
continue;
}
res.Add(key, marking);
}
return res;
}
/// <summary>
/// Markings by category, species and sex.
/// </summary>
/// <param name="category"></param>
/// <param name="species"></param>
/// <param name="sex"></param>
/// <remarks>
/// This is done per category, as enumerating over every single marking by species isn't useful.
/// Please make a pull request if you find a use case for that behavior.
/// </remarks>
/// <returns></returns>
public IReadOnlyDictionary<string, MarkingPrototype> MarkingsByCategoryAndSpeciesAndSex(MarkingCategories category,
string species, Sex sex)
{
var speciesProto = _prototypeManager.Index<SpeciesPrototype>(species);
var onlyWhitelisted = _prototypeManager.Index<MarkingPointsPrototype>(speciesProto.MarkingPoints).OnlyWhitelisted;
var res = new Dictionary<string, MarkingPrototype>();
foreach (var (key, marking) in MarkingsByCategory(category))
{
if (onlyWhitelisted && marking.SpeciesRestrictions == null)
{
continue;
}
if (marking.SpeciesRestrictions != null && !marking.SpeciesRestrictions.Contains(species))
{
continue;
}
if (marking.SexRestriction != null && marking.SexRestriction != sex)
{
continue;
}
res.Add(key, marking); res.Add(key, marking);
} }
@@ -84,8 +152,9 @@ namespace Content.Shared.Humanoid.Markings
/// <param name="marking"></param> /// <param name="marking"></param>
/// <param name="category"></param> /// <param name="category"></param>
/// <param name="species"></param> /// <param name="species"></param>
/// <param name="sex"></param>
/// <returns></returns> /// <returns></returns>
public bool IsValidMarking(Marking marking, MarkingCategories category, string species) public bool IsValidMarking(Marking marking, MarkingCategories category, string species, Sex sex)
{ {
if (!TryGetMarking(marking, out var proto)) if (!TryGetMarking(marking, out var proto))
{ {
@@ -93,7 +162,8 @@ namespace Content.Shared.Humanoid.Markings
} }
if (proto.MarkingCategory != category || if (proto.MarkingCategory != category ||
proto.SpeciesRestrictions != null && !proto.SpeciesRestrictions.Contains(species)) proto.SpeciesRestrictions != null && !proto.SpeciesRestrictions.Contains(species) ||
proto.SexRestriction != null && proto.SexRestriction != sex)
{ {
return false; return false;
} }
@@ -121,7 +191,7 @@ namespace Content.Shared.Humanoid.Markings
} }
} }
public bool CanBeApplied(string species, Marking marking, IPrototypeManager? prototypeManager = null) public bool CanBeApplied(string species, Sex sex, Marking marking, IPrototypeManager? prototypeManager = null)
{ {
IoCManager.Resolve(ref prototypeManager); IoCManager.Resolve(ref prototypeManager);
@@ -143,10 +213,16 @@ namespace Content.Shared.Humanoid.Markings
{ {
return false; return false;
} }
if (prototype.SexRestriction != null && prototype.SexRestriction != sex)
{
return false;
}
return true; return true;
} }
public bool CanBeApplied(string species, MarkingPrototype prototype, IPrototypeManager? prototypeManager = null) public bool CanBeApplied(string species, Sex sex, MarkingPrototype prototype, IPrototypeManager? prototypeManager = null)
{ {
IoCManager.Resolve(ref prototypeManager); IoCManager.Resolve(ref prototypeManager);
@@ -163,6 +239,12 @@ namespace Content.Shared.Humanoid.Markings
{ {
return false; return false;
} }
if (prototype.SexRestriction != null && prototype.SexRestriction != sex)
{
return false;
}
return true; return true;
} }

View File

@@ -20,6 +20,9 @@ namespace Content.Shared.Humanoid.Markings
[DataField("speciesRestriction")] [DataField("speciesRestriction")]
public List<string>? SpeciesRestrictions { get; private set; } public List<string>? SpeciesRestrictions { get; private set; }
[DataField("sexRestriction")]
public Sex? SexRestriction { get; private set; }
[DataField("followSkinColor")] [DataField("followSkinColor")]
public bool FollowSkinColor { get; private set; } = false; public bool FollowSkinColor { get; private set; } = false;

View File

@@ -199,6 +199,40 @@ public sealed partial class MarkingSet
} }
} }
/// <summary>
/// Filters markings based on sex and it's restrictions in the marking's prototype from this marking set.
/// </summary>
/// <param name="sex">The species to filter.</param>
/// <param name="markingManager">Marking manager.</param>
public void EnsureSexes(Sex sex, MarkingManager? markingManager = null)
{
IoCManager.Resolve(ref markingManager);
var toRemove = new List<(MarkingCategories category, string id)>();
foreach (var (category, list) in Markings)
{
foreach (var marking in list)
{
if (!markingManager.TryGetMarking(marking, out var prototype))
{
toRemove.Add((category, marking.MarkingId));
continue;
}
if (prototype.SexRestriction != null && prototype.SexRestriction != sex)
{
toRemove.Add((category, marking.MarkingId));
}
}
}
foreach (var remove in toRemove)
{
Remove(remove.category, remove.id);
}
}
/// <summary> /// <summary>
/// Ensures that all markings in this set are valid. /// Ensures that all markings in this set are valid.
/// </summary> /// </summary>

View File

@@ -254,6 +254,7 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
var oldSex = humanoid.Sex; var oldSex = humanoid.Sex;
humanoid.Sex = sex; humanoid.Sex = sex;
humanoid.MarkingSet.EnsureSexes(sex, _markingManager);
RaiseLocalEvent(uid, new SexChangedEvent(oldSex, sex)); RaiseLocalEvent(uid, new SexChangedEvent(oldSex, sex));
if (sync) if (sync)
@@ -308,13 +309,13 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
? profile.Appearance.SkinColor.WithAlpha(facialHairAlpha) : profile.Appearance.FacialHairColor; ? profile.Appearance.SkinColor.WithAlpha(facialHairAlpha) : profile.Appearance.FacialHairColor;
if (_markingManager.Markings.TryGetValue(profile.Appearance.HairStyleId, out var hairPrototype) && if (_markingManager.Markings.TryGetValue(profile.Appearance.HairStyleId, out var hairPrototype) &&
_markingManager.CanBeApplied(profile.Species, hairPrototype, _prototypeManager)) _markingManager.CanBeApplied(profile.Species, profile.Sex, hairPrototype, _prototypeManager))
{ {
AddMarking(uid, profile.Appearance.HairStyleId, hairColor, false); AddMarking(uid, profile.Appearance.HairStyleId, hairColor, false);
} }
if (_markingManager.Markings.TryGetValue(profile.Appearance.FacialHairStyleId, out var facialHairPrototype) && if (_markingManager.Markings.TryGetValue(profile.Appearance.FacialHairStyleId, out var facialHairPrototype) &&
_markingManager.CanBeApplied(profile.Species, facialHairPrototype, _prototypeManager)) _markingManager.CanBeApplied(profile.Species, profile.Sex, facialHairPrototype, _prototypeManager))
{ {
AddMarking(uid, profile.Appearance.FacialHairStyleId, facialHairColor, false); AddMarking(uid, profile.Appearance.FacialHairStyleId, facialHairColor, false);
} }

View File

@@ -45,18 +45,21 @@ public sealed class HumanoidMarkingModifierState : BoundUserInterfaceState
public HumanoidMarkingModifierState( public HumanoidMarkingModifierState(
MarkingSet markingSet, MarkingSet markingSet,
string species, string species,
Sex sex,
Color skinColor, Color skinColor,
Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> customBaseLayers Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> customBaseLayers
) )
{ {
MarkingSet = markingSet; MarkingSet = markingSet;
Species = species; Species = species;
Sex = sex;
SkinColor = skinColor; SkinColor = skinColor;
CustomBaseLayers = customBaseLayers; CustomBaseLayers = customBaseLayers;
} }
public MarkingSet MarkingSet { get; } public MarkingSet MarkingSet { get; }
public string Species { get; } public string Species { get; }
public Sex Sex { get; }
public Color SkinColor { get; } public Color SkinColor { get; }
public Color EyeColor { get; } public Color EyeColor { get; }
public Color? HairColor { get; } public Color? HairColor { get; }

View File

@@ -433,7 +433,7 @@ namespace Content.Shared.Preferences
flavortext = FormattedMessage.RemoveMarkup(FlavorText); flavortext = FormattedMessage.RemoveMarkup(FlavorText);
} }
var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species); var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species, Sex);
var prefsUnavailableMode = PreferenceUnavailable switch var prefsUnavailableMode = PreferenceUnavailable switch
{ {