| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- using System.Collections.Frozen;
- using System.Diagnostics.CodeAnalysis;
- using System.Linq;
- using Content.Shared.Humanoid.Prototypes;
- using Robust.Shared.Prototypes;
- namespace Content.Shared.Humanoid.Markings
- {
- public sealed class MarkingManager
- {
- [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
- private readonly List<MarkingPrototype> _index = new();
- public FrozenDictionary<MarkingCategories, FrozenDictionary<string, MarkingPrototype>> CategorizedMarkings = default!;
- public FrozenDictionary<string, MarkingPrototype> Markings = default!;
- public void Initialize()
- {
- _prototypeManager.PrototypesReloaded += OnPrototypeReload;
- CachePrototypes();
- }
- private void CachePrototypes()
- {
- _index.Clear();
- var markingDict = new Dictionary<MarkingCategories, Dictionary<string, MarkingPrototype>>();
- foreach (var category in Enum.GetValues<MarkingCategories>())
- {
- markingDict.Add(category, new());
- }
- foreach (var prototype in _prototypeManager.EnumeratePrototypes<MarkingPrototype>())
- {
- _index.Add(prototype);
- markingDict[prototype.MarkingCategory].Add(prototype.ID, prototype);
- }
- Markings = _prototypeManager.EnumeratePrototypes<MarkingPrototype>().ToFrozenDictionary(x => x.ID);
- CategorizedMarkings = markingDict.ToFrozenDictionary(
- x => x.Key,
- x => x.Value.ToFrozenDictionary());
- }
- public FrozenDictionary<string, MarkingPrototype> MarkingsByCategory(MarkingCategories category)
- {
- // all marking categories are guaranteed to have a dict entry
- return CategorizedMarkings[category];
- }
- /// <summary>
- /// Markings by category and species.
- /// </summary>
- /// <param name="category"></param>
- /// <param name="species"></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> MarkingsByCategoryAndSpecies(MarkingCategories category,
- string species)
- {
- 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;
- }
- 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);
- }
- return res;
- }
- public bool TryGetMarking(Marking marking, [NotNullWhen(true)] out MarkingPrototype? markingResult)
- {
- return Markings.TryGetValue(marking.MarkingId, out markingResult);
- }
- /// <summary>
- /// Check if a marking is valid according to the category, species, and current data this marking has.
- /// </summary>
- /// <param name="marking"></param>
- /// <param name="category"></param>
- /// <param name="species"></param>
- /// <param name="sex"></param>
- /// <returns></returns>
- public bool IsValidMarking(Marking marking, MarkingCategories category, string species, Sex sex)
- {
- if (!TryGetMarking(marking, out var proto))
- {
- return false;
- }
- if (proto.MarkingCategory != category ||
- proto.SpeciesRestrictions != null && !proto.SpeciesRestrictions.Contains(species) ||
- proto.SexRestriction != null && proto.SexRestriction != sex)
- {
- return false;
- }
- if (marking.MarkingColors.Count != proto.Sprites.Count)
- {
- return false;
- }
- return true;
- }
- private void OnPrototypeReload(PrototypesReloadedEventArgs args)
- {
- if (args.WasModified<MarkingPrototype>())
- CachePrototypes();
- }
- public bool CanBeApplied(string species, Sex sex, Marking marking, IPrototypeManager? prototypeManager = null)
- {
- IoCManager.Resolve(ref prototypeManager);
- var speciesProto = prototypeManager.Index<SpeciesPrototype>(species);
- var onlyWhitelisted = prototypeManager.Index<MarkingPointsPrototype>(speciesProto.MarkingPoints).OnlyWhitelisted;
- if (!TryGetMarking(marking, out var prototype))
- {
- return false;
- }
- if (onlyWhitelisted && prototype.SpeciesRestrictions == null)
- {
- return false;
- }
- if (prototype.SpeciesRestrictions != null
- && !prototype.SpeciesRestrictions.Contains(species))
- {
- return false;
- }
- if (prototype.SexRestriction != null && prototype.SexRestriction != sex)
- {
- return false;
- }
- return true;
- }
- public bool CanBeApplied(string species, Sex sex, MarkingPrototype prototype, IPrototypeManager? prototypeManager = null)
- {
- IoCManager.Resolve(ref prototypeManager);
- var speciesProto = prototypeManager.Index<SpeciesPrototype>(species);
- var onlyWhitelisted = prototypeManager.Index<MarkingPointsPrototype>(speciesProto.MarkingPoints).OnlyWhitelisted;
- if (onlyWhitelisted && prototype.SpeciesRestrictions == null)
- {
- return false;
- }
- if (prototype.SpeciesRestrictions != null &&
- !prototype.SpeciesRestrictions.Contains(species))
- {
- return false;
- }
- if (prototype.SexRestriction != null && prototype.SexRestriction != sex)
- {
- return false;
- }
- return true;
- }
- public bool MustMatchSkin(string species, HumanoidVisualLayers layer, out float alpha, IPrototypeManager? prototypeManager = null)
- {
- IoCManager.Resolve(ref prototypeManager);
- var speciesProto = prototypeManager.Index<SpeciesPrototype>(species);
- if (
- !prototypeManager.TryIndex(speciesProto.SpriteSet, out HumanoidSpeciesBaseSpritesPrototype? baseSprites) ||
- !baseSprites.Sprites.TryGetValue(layer, out var spriteName) ||
- !prototypeManager.TryIndex(spriteName, out HumanoidSpeciesSpriteLayer? sprite) ||
- sprite == null ||
- !sprite.MarkingsMatchSkin
- )
- {
- alpha = 1f;
- return false;
- }
- alpha = sprite.LayerAlpha;
- return true;
- }
- }
- }
|