Markings overhaul (#35938)

* markings displacement setup

* ok i got it!

* fix map updating

* remove trackingLayers

* markings clean up and modernizize

* marking disabling displacements

* markings restriction

* dehihienize

* dehihiniezize 2

* aa

* nice
This commit is contained in:
Ed
2025-04-21 00:01:50 +03:00
committed by GitHub
parent f3a33fefc2
commit f6a29e24a2
14 changed files with 146 additions and 39 deletions

View File

@@ -334,8 +334,11 @@ public sealed class ClientClothingSystem : ClothingSystem
if (layerData.State is not null && inventory.SpeciesId is not null && layerData.State.EndsWith(inventory.SpeciesId))
continue;
if (_displacement.TryAddDisplacement(displacementData, sprite, index, key, revealedLayers))
if (_displacement.TryAddDisplacement(displacementData, sprite, index, key, out var displacementKey))
{
revealedLayers.Add(displacementKey);
index++;
}
}
}

View File

@@ -9,22 +9,36 @@ public sealed class DisplacementMapSystem : EntitySystem
{
[Dependency] private readonly ISerializationManager _serialization = default!;
public bool TryAddDisplacement(DisplacementData data, SpriteComponent sprite, int index, string key, HashSet<string> revealedLayers)
/// <summary>
/// Attempting to apply a displacement map to a specific layer of SpriteComponent
/// </summary>
/// <param name="data">Information package for applying the displacement map</param>
/// <param name="sprite">SpriteComponent</param>
/// <param name="index">Index of the layer where the new map layer will be added</param>
/// <param name="key">Unique layer key, which will determine which layer to apply displacement map to</param>
/// <param name="displacementKey">The key of the new displacement map layer added by this function.</param>
/// <returns></returns>
public bool TryAddDisplacement(DisplacementData data,
SpriteComponent sprite,
int index,
object key,
out string displacementKey)
{
displacementKey = $"{key}-displacement";
if (key.ToString() is null)
return false;
if (data.ShaderOverride != null)
sprite.LayerSetShader(index, data.ShaderOverride);
var displacementKey = $"{key}-displacement";
if (!revealedLayers.Add(displacementKey))
{
Log.Warning($"Duplicate key for DISPLACEMENT: {displacementKey}.");
return false;
}
if (sprite.LayerMapTryGet(displacementKey, out var oldIndex))
sprite.RemoveLayer(oldIndex);
//allows you not to write it every time in the YML
foreach (var pair in data.SizeMaps)
{
pair.Value.CopyToShaderParameters??= new()
pair.Value.CopyToShaderParameters ??= new()
{
LayerKey = "dummy",
ParameterTexture = "displacementMap",
@@ -45,21 +59,22 @@ public sealed class DisplacementMapSystem : EntitySystem
if (actualRSI is not null)
{
if (actualRSI.Size.X != actualRSI.Size.Y)
Log.Warning($"DISPLACEMENT: {displacementKey} has a resolution that is not 1:1, things can look crooked");
{
Log.Warning(
$"DISPLACEMENT: {displacementKey} has a resolution that is not 1:1, things can look crooked");
}
var layerSize = actualRSI.Size.X;
if (data.SizeMaps.ContainsKey(layerSize))
displacementDataLayer = data.SizeMaps[layerSize];
if (data.SizeMaps.TryGetValue(layerSize, out var map))
displacementDataLayer = map;
}
var displacementLayer = _serialization.CreateCopy(displacementDataLayer, notNullableOverride: true);
displacementLayer.CopyToShaderParameters!.LayerKey = key;
displacementLayer.CopyToShaderParameters!.LayerKey = key.ToString() ?? "this is impossible";
sprite.AddLayer(displacementLayer, index);
sprite.LayerMapSet(displacementKey, index);
revealedLayers.Add(displacementKey);
return true;
}
}

View File

@@ -348,14 +348,16 @@ namespace Content.Client.Hands.Systems
sprite.LayerSetData(index, layerData);
//Add displacement maps
if (hand.Location == HandLocation.Left && handComp.LeftHandDisplacement is not null)
_displacement.TryAddDisplacement(handComp.LeftHandDisplacement, sprite, index, key, revealedLayers);
else if (hand.Location == HandLocation.Right && handComp.RightHandDisplacement is not null)
_displacement.TryAddDisplacement(handComp.RightHandDisplacement, sprite, index, key, revealedLayers);
//Fallback to default displacement map
else if (handComp.HandDisplacement is not null)
_displacement.TryAddDisplacement(handComp.HandDisplacement, sprite, index, key, revealedLayers);
// Add displacement maps
var displacement = hand.Location switch
{
HandLocation.Left => handComp.LeftHandDisplacement,
HandLocation.Right => handComp.RightHandDisplacement,
_ => handComp.HandDisplacement
};
if (displacement is not null && _displacement.TryAddDisplacement(displacement, sprite, index, key, out var displacementKey))
revealedLayers.Add(displacementKey);
}
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers), true);

View File

@@ -1,3 +1,4 @@
using Content.Client.DisplacementMap;
using Content.Shared.CCVar;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings;
@@ -16,6 +17,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly MarkingManager _markingManager = default!;
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
[Dependency] private readonly DisplacementMapSystem _displacement = default!;
public override void Initialize()
{
@@ -369,6 +371,11 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
{
sprite.LayerSetColor(layerId, Color.White);
}
if (humanoid.MarkingsDisplacement.TryGetValue(markingPrototype.BodyPart, out var displacementData) && markingPrototype.CanBeDisplaced)
{
_displacement.TryAddDisplacement(displacementData, sprite, targetLayer + j + 1, layerId, out _);
}
}
}

View File

@@ -1,3 +1,4 @@
using Content.Shared.DisplacementMap;
using Content.Shared.Humanoid.Markings;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Inventory;
@@ -99,6 +100,12 @@ public sealed partial class HumanoidAppearanceComponent : Component
[DataField]
public ProtoId<MarkingPrototype>? UndergarmentBottom = new ProtoId<MarkingPrototype>("UndergarmentBottomBoxers");
/// <summary>
/// The displacement maps that will be applied to specific layers of the humanoid.
/// </summary>
[DataField]
public Dictionary<HumanoidVisualLayers, DisplacementData> MarkingsDisplacement = new();
}
[DataDefinition]

View File

@@ -62,12 +62,12 @@ namespace Content.Shared.Humanoid.Markings
string species)
{
var speciesProto = _prototypeManager.Index<SpeciesPrototype>(species);
var onlyWhitelisted = _prototypeManager.Index(speciesProto.MarkingPoints).OnlyWhitelisted;
var markingPoints = _prototypeManager.Index(speciesProto.MarkingPoints);
var res = new Dictionary<string, MarkingPrototype>();
foreach (var (key, marking) in MarkingsByCategory(category))
{
if (onlyWhitelisted && marking.SpeciesRestrictions == null)
if ((markingPoints.OnlyWhitelisted || markingPoints.Points[category].OnlyWhitelisted) && marking.SpeciesRestrictions == null)
{
continue;
}

View File

@@ -1,6 +1,5 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Shared.Humanoid.Markings;
@@ -8,13 +7,23 @@ namespace Content.Shared.Humanoid.Markings;
[Serializable, NetSerializable]
public sealed partial class MarkingPoints
{
[DataField("points", required: true)]
[DataField(required: true)]
public int Points = 0;
[DataField("required", required: true)]
public bool Required = false;
[DataField(required: true)]
public bool Required;
/// <summary>
/// If the user of this marking point set is only allowed to
/// use whitelisted markings, and not globally usable markings.
/// Only used for validation and profile construction. Ignored anywhere else.
/// </summary>
[DataField]
public bool OnlyWhitelisted;
// Default markings for this layer.
[DataField("defaultMarkings", customTypeSerializer:typeof(PrototypeIdListSerializer<MarkingPrototype>))]
public List<string> DefaultMarkings = new();
[DataField]
public List<ProtoId<MarkingPrototype>> DefaultMarkings = new();
public static Dictionary<MarkingCategories, MarkingPoints> CloneMarkingPointDictionary(Dictionary<MarkingCategories, MarkingPoints> self)
{
@@ -26,6 +35,7 @@ public sealed partial class MarkingPoints
{
Points = points.Points,
Required = points.Required,
OnlyWhitelisted = points.OnlyWhitelisted,
DefaultMarkings = points.DefaultMarkings
};
}
@@ -44,8 +54,9 @@ public sealed partial class MarkingPointsPrototype : IPrototype
/// use whitelisted markings, and not globally usable markings.
/// Only used for validation and profile construction. Ignored anywhere else.
/// </summary>
[DataField("onlyWhitelisted")] public bool OnlyWhitelisted;
[DataField]
public bool OnlyWhitelisted;
[DataField("points", required: true)]
[DataField(required: true)]
public Dictionary<MarkingCategories, MarkingPoints> Points { get; private set; } = default!;
}

View File

@@ -32,6 +32,13 @@ namespace Content.Shared.Humanoid.Markings
[DataField("coloring")]
public MarkingColors Coloring { get; private set; } = new();
/// <summary>
/// Do we need to apply any displacement maps to this marking? Set to false if your marking is incompatible
/// with a standard human doll, and is used for some special races with unusual shapes
/// </summary>
[DataField]
public bool CanBeDisplaced { get; private set; } = true;
[DataField("sprites", required: true)]
public List<SpriteSpecifier> Sprites { get; private set; } = default!;

View File

@@ -2,6 +2,7 @@
id: VoxFacialHairBeard
bodyPart: FacialHair
markingCategory: FacialHair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_facial_hair.rsi
@@ -11,6 +12,7 @@
id: VoxFacialHairColonel
bodyPart: FacialHair
markingCategory: FacialHair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_facial_hair.rsi
@@ -20,6 +22,7 @@
id: VoxFacialHairFu
bodyPart: FacialHair
markingCategory: FacialHair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_facial_hair.rsi
@@ -29,6 +32,7 @@
id: VoxFacialHairMane
bodyPart: FacialHair
markingCategory: FacialHair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_facial_hair.rsi
@@ -38,6 +42,7 @@
id: VoxFacialHairManeSmall
bodyPart: FacialHair
markingCategory: FacialHair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_facial_hair.rsi
@@ -47,6 +52,7 @@
id: VoxFacialHairNeck
bodyPart: FacialHair
markingCategory: FacialHair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_facial_hair.rsi
@@ -56,6 +62,7 @@
id: VoxFacialHairTufts
bodyPart: FacialHair
markingCategory: FacialHair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_facial_hair.rsi

View File

@@ -2,6 +2,7 @@
id: VoxHairAfro
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -11,6 +12,7 @@
id: VoxHairBraids
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -20,6 +22,7 @@
id: VoxHairCrestedQuills
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -29,6 +32,7 @@
id: VoxHairEmperorQuills
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -38,6 +42,7 @@
id: VoxHairFlowing
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -47,6 +52,7 @@
id: VoxHairHawk
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -56,6 +62,7 @@
id: VoxHairHorns
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -65,6 +72,7 @@
id: VoxHairKeelQuills
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -74,6 +82,7 @@
id: VoxHairKeetQuills
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -83,6 +92,7 @@
id: VoxHairKingly
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -92,6 +102,7 @@
id: VoxHairLongBraid
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -101,6 +112,7 @@
id: VoxHairMange
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -110,6 +122,7 @@
id: VoxHairMohawk
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -119,6 +132,7 @@
id: VoxHairNights
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -128,6 +142,7 @@
id: VoxHairPony
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -137,6 +152,7 @@
id: VoxHairRazorClipped
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -146,6 +162,7 @@
id: VoxHairRazor
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -155,6 +172,7 @@
id: VoxHairSortBraid
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -164,6 +182,7 @@
id: VoxHairShortQuills
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -173,6 +192,7 @@
id: VoxHairSpotty
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -182,6 +202,7 @@
id: VoxHairSurf
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -191,6 +212,7 @@
id: VoxHairTielQuills
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -200,6 +222,7 @@
id: VoxHairWiseBraid
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi
@@ -209,6 +232,7 @@
id: VoxHairYasu
bodyPart: Hair
markingCategory: Hair
canBeDisplaced: false
speciesRestriction: [Vox]
sprites:
- sprite: Mobs/Customization/vox_hair.rsi

View File

@@ -11,10 +11,6 @@
- type: Body
prototype: Vox
requiredLegs: 2
- type: HumanoidAppearance
species: Vox
undergarmentTop: UndergarmentTopTanktopVox
undergarmentBottom: UndergarmentBottomBoxersVox
#- type: VoxAccent # Not yet coded
- type: Speech
speechVerb: Vox
@@ -108,6 +104,16 @@
sprite: "Effects/creampie.rsi"
state: "creampie_vox" # Not default
visible: false
- type: HumanoidAppearance
species: Vox
undergarmentTop: UndergarmentTopTanktopVox
undergarmentBottom: UndergarmentBottomBoxersVox
markingsDisplacement:
Hair:
sizeMaps:
32:
sprite: Mobs/Species/Vox/displacement.rsi
state: hair
- type: Inventory
speciesId: vox
displacements:
@@ -167,6 +173,12 @@
species: Vox
undergarmentTop: UndergarmentTopTanktopVox
undergarmentBottom: UndergarmentBottomBoxersVox
markingsDisplacement:
Hair:
sizeMaps:
32:
sprite: Mobs/Species/Vox/displacement.rsi
state: hair
- type: Body
prototype: Vox
- type: Inventory

View File

@@ -37,7 +37,6 @@
- type: markingPoints
id: MobVoxMarkingLimits
onlyWhitelisted: true
points:
Hair:
points: 1
@@ -45,34 +44,43 @@
FacialHair:
points: 1
required: false
onlyWhitelisted: true
Head:
points: 1
required: true
onlyWhitelisted: true
Snout:
points: 1
required: true
defaultMarkings: [ VoxBeak ]
onlyWhitelisted: true
Arms:
points: 4
required: true
defaultMarkings: [ VoxLArmScales, VoxRArmScales, VoxRHandScales, VoxLHandScales ]
onlyWhitelisted: true
Legs:
points: 4
required: true
defaultMarkings: [ VoxLLegScales, VoxRLegScales, VoxRFootScales, VoxLFootScales ]
onlyWhitelisted: true
UndergarmentTop:
points: 1
required: false
onlyWhitelisted: true
UndergarmentBottom:
points: 1
required: false
onlyWhitelisted: true
Chest:
points: 1
required: false
onlyWhitelisted: true
Tail:
points: 1
required: true
defaultMarkings: [ VoxTail ]
onlyWhitelisted: true
- type: humanoidBaseSprite
id: MobVoxEyes

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

View File

@@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "jumpsuit state made by PJB3005. back, hand, head, and eyes states made by Flareguy, ears, hand_l, hand_r and shoes made by TheShuEd",
"copyright": "jumpsuit state made by PJB3005. back, hand, head, and eyes states made by Flareguy, ears, hand_l, hand_r, hair and shoes made by TheShuEd",
"size": {
"x": 32,
"y": 32
@@ -38,6 +38,10 @@
"name": "shoes",
"directions": 4
},
{
"name": "hair",
"directions": 4
},
{
"name": "hand_l",
"directions": 4