Makes humanoid appearance component networked. (#13009)
Fixes https://github.com/space-wizards/space-station-14/issues/12248
This commit is contained in:
200
Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs
Normal file
200
Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Shared.Humanoid;
|
||||
|
||||
/// <summary>
|
||||
/// HumanoidSystem. Primarily deals with the appearance and visual data
|
||||
/// of a humanoid entity. HumanoidVisualizer is what deals with actually
|
||||
/// organizing the sprites and setting up the sprite component's layers.
|
||||
///
|
||||
/// This is a shared system, because while it is server authoritative,
|
||||
/// you still need a local copy so that players can set up their
|
||||
/// characters.
|
||||
/// </summary>
|
||||
public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly MarkingManager _markingManager = default!;
|
||||
|
||||
public const string DefaultSpecies = "Human";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<HumanoidAppearanceComponent, ComponentGetState>(OnGetState);
|
||||
}
|
||||
|
||||
private void OnGetState(EntityUid uid, HumanoidAppearanceComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new HumanoidAppearanceState(component.MarkingSet,
|
||||
component.PermanentlyHidden,
|
||||
component.HiddenLayers,
|
||||
component.CustomBaseLayers,
|
||||
component.Sex,
|
||||
component.Gender,
|
||||
component.Age,
|
||||
component.Species,
|
||||
component.SkinColor,
|
||||
component.EyeColor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles a humanoid's sprite layer visibility.
|
||||
/// </summary>
|
||||
/// <param name="uid">Humanoid mob's UID</param>
|
||||
/// <param name="layer">Layer to toggle visibility for</param>
|
||||
/// <param name="humanoid">Humanoid component of the entity</param>
|
||||
public void SetLayerVisibility(EntityUid uid,
|
||||
HumanoidVisualLayers layer,
|
||||
bool visible,
|
||||
bool permanent = false,
|
||||
HumanoidAppearanceComponent? humanoid = null)
|
||||
{
|
||||
if (!Resolve(uid, ref humanoid))
|
||||
return;
|
||||
|
||||
var dirty = false;
|
||||
SetLayerVisibility(uid, humanoid, layer, visible, permanent, ref dirty);
|
||||
if (dirty)
|
||||
Dirty(humanoid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the visibility for multiple layers at once on a humanoid's sprite.
|
||||
/// </summary>
|
||||
/// <param name="uid">Humanoid mob's UID</param>
|
||||
/// <param name="layers">An enumerable of all sprite layers that are going to have their visibility set</param>
|
||||
/// <param name="visible">The visibility state of the layers given</param>
|
||||
/// <param name="permanent">If this is a permanent change, or temporary. Permanent layers are stored in their own hash set.</param>
|
||||
/// <param name="humanoid">Humanoid component of the entity</param>
|
||||
public void SetLayersVisibility(EntityUid uid, IEnumerable<HumanoidVisualLayers> layers, bool visible, bool permanent = false,
|
||||
HumanoidAppearanceComponent? humanoid = null)
|
||||
{
|
||||
if (!Resolve(uid, ref humanoid))
|
||||
return;
|
||||
|
||||
var dirty = false;
|
||||
|
||||
foreach (var layer in layers)
|
||||
{
|
||||
SetLayerVisibility(uid, humanoid, layer, visible, permanent, ref dirty);
|
||||
}
|
||||
|
||||
if (dirty)
|
||||
Dirty(humanoid);
|
||||
}
|
||||
|
||||
protected virtual void SetLayerVisibility(
|
||||
EntityUid uid,
|
||||
HumanoidAppearanceComponent humanoid,
|
||||
HumanoidVisualLayers layer,
|
||||
bool visible,
|
||||
bool permanent,
|
||||
ref bool dirty)
|
||||
{
|
||||
if (visible)
|
||||
{
|
||||
if (permanent)
|
||||
dirty |= humanoid.PermanentlyHidden.Remove(layer);
|
||||
|
||||
dirty |= humanoid.HiddenLayers.Remove(layer);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (permanent)
|
||||
dirty |= humanoid.PermanentlyHidden.Add(layer);
|
||||
|
||||
dirty |= humanoid.HiddenLayers.Add(layer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set a humanoid mob's species. This will change their base sprites, as well as their current
|
||||
/// set of markings to fit against the mob's new species.
|
||||
/// </summary>
|
||||
/// <param name="uid">The humanoid mob's UID.</param>
|
||||
/// <param name="species">The species to set the mob to. Will return if the species prototype was invalid.</param>
|
||||
/// <param name="sync">Whether to immediately synchronize this to the humanoid mob, or not.</param>
|
||||
/// <param name="humanoid">Humanoid component of the entity</param>
|
||||
public void SetSpecies(EntityUid uid, string species, bool sync = true, HumanoidAppearanceComponent? humanoid = null)
|
||||
{
|
||||
if (!Resolve(uid, ref humanoid) || !_prototypeManager.TryIndex<SpeciesPrototype>(species, out var prototype))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
humanoid.Species = species;
|
||||
humanoid.MarkingSet.FilterSpecies(species, _markingManager);
|
||||
var oldMarkings = humanoid.MarkingSet.GetForwardEnumerator().ToList();
|
||||
humanoid.MarkingSet = new(oldMarkings, prototype.MarkingPoints, _markingManager, _prototypeManager);
|
||||
|
||||
if (sync)
|
||||
Dirty(humanoid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the skin color of this humanoid mob. Will only affect base layers that are not custom,
|
||||
/// custom base layers should use <see cref="SetBaseLayerColor"/> instead.
|
||||
/// </summary>
|
||||
/// <param name="uid">The humanoid mob's UID.</param>
|
||||
/// <param name="skinColor">Skin color to set on the humanoid mob.</param>
|
||||
/// <param name="sync">Whether to synchronize this to the humanoid mob, or not.</param>
|
||||
/// <param name="humanoid">Humanoid component of the entity</param>
|
||||
public virtual void SetSkinColor(EntityUid uid, Color skinColor, bool sync = true, HumanoidAppearanceComponent? humanoid = null)
|
||||
{
|
||||
if (!Resolve(uid, ref humanoid))
|
||||
return;
|
||||
|
||||
humanoid.SkinColor = skinColor;
|
||||
|
||||
if (sync)
|
||||
Dirty(humanoid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the base layer ID of this humanoid mob. A humanoid mob's 'base layer' is
|
||||
/// the skin sprite that is applied to the mob's sprite upon appearance refresh.
|
||||
/// </summary>
|
||||
/// <param name="uid">The humanoid mob's UID.</param>
|
||||
/// <param name="layer">The layer to target on this humanoid mob.</param>
|
||||
/// <param name="id">The ID of the sprite to use. See <see cref="HumanoidSpeciesSpriteLayer"/>.</param>
|
||||
/// <param name="sync">Whether to synchronize this to the humanoid mob, or not.</param>
|
||||
/// <param name="humanoid">Humanoid component of the entity</param>
|
||||
public void SetBaseLayerId(EntityUid uid, HumanoidVisualLayers layer, string id, bool sync = true,
|
||||
HumanoidAppearanceComponent? humanoid = null)
|
||||
{
|
||||
if (!Resolve(uid, ref humanoid))
|
||||
return;
|
||||
|
||||
if (humanoid.CustomBaseLayers.TryGetValue(layer, out var info))
|
||||
humanoid.CustomBaseLayers[layer] = info with { ID = id };
|
||||
else
|
||||
humanoid.CustomBaseLayers[layer] = new(id);
|
||||
|
||||
if (sync)
|
||||
Dirty(humanoid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the color of this humanoid mob's base layer. See <see cref="SetBaseLayerId"/> for a
|
||||
/// description of how base layers work.
|
||||
/// </summary>
|
||||
/// <param name="uid">The humanoid mob's UID.</param>
|
||||
/// <param name="layer">The layer to target on this humanoid mob.</param>
|
||||
/// <param name="color">The color to set this base layer to.</param>
|
||||
public void SetBaseLayerColor(EntityUid uid, HumanoidVisualLayers layer, Color? color, bool sync = true, HumanoidAppearanceComponent? humanoid = null)
|
||||
{
|
||||
if (!Resolve(uid, ref humanoid))
|
||||
return;
|
||||
|
||||
humanoid.CustomBaseLayers[layer] = humanoid.CustomBaseLayers[layer] with { Color = color };
|
||||
|
||||
if (sync)
|
||||
Dirty(humanoid);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user