Puddles & spreader refactor (#15191)

This commit is contained in:
metalgearsloth
2023-04-10 15:37:03 +10:00
committed by GitHub
parent 3178ab83f6
commit 317a4013eb
141 changed files with 3046 additions and 3201 deletions

View File

@@ -5,7 +5,8 @@ using Robust.Client.UserInterface;
namespace Content.Client.Fluids;
public sealed class MoppingSystem : SharedMoppingSystem
/// <inheritdoc/>
public sealed class AbsorbentSystem : SharedAbsorbentSystem
{
public override void Initialize()
{

View File

@@ -0,0 +1,67 @@
using Content.Client.IconSmoothing;
using Content.Shared.Fluids;
using Content.Shared.Fluids.Components;
using Robust.Client.GameObjects;
namespace Content.Client.Fluids;
public sealed class PuddleSystem : SharedPuddleSystem
{
[Dependency] private readonly IconSmoothSystem _smooth = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PuddleComponent, AppearanceChangeEvent>(OnPuddleAppearance);
}
private void OnPuddleAppearance(EntityUid uid, PuddleComponent component, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
return;
float volume = 1f;
if (args.AppearanceData.TryGetValue(PuddleVisuals.CurrentVolume, out var volumeObj))
{
volume = (float) volumeObj;
}
// Update smoothing and sprite based on volume.
if (TryComp<IconSmoothComponent>(uid, out var smooth))
{
if (volume < LowThreshold)
{
args.Sprite.LayerSetState(0, $"{smooth.StateBase}a");
_smooth.SetEnabled(uid, false, smooth);
}
else if (volume < 0.6f)
{
args.Sprite.LayerSetState(0, $"{smooth.StateBase}b");
_smooth.SetEnabled(uid, false, smooth);
}
else
{
if (!smooth.Enabled)
{
args.Sprite.LayerSetState(0, $"{smooth.StateBase}0");
_smooth.SetEnabled(uid, true, smooth);
_smooth.DirtyNeighbours(uid);
}
}
}
var baseColor = Color.White;
if (args.AppearanceData.TryGetValue(PuddleVisuals.SolutionColor, out var colorObj))
{
var color = (Color) colorObj;
args.Sprite.Color = color * baseColor;
}
else
{
args.Sprite.Color *= baseColor;
}
}
}

View File

@@ -1,30 +0,0 @@
using Content.Shared.FixedPoint;
using Robust.Client.Graphics;
namespace Content.Client.Fluids
{
[RegisterComponent]
public sealed class PuddleVisualizerComponent : Component
{
// Whether the underlying solution color should be used. True in most cases.
[DataField("recolor")] public bool Recolor = true;
// Whether the puddle has a unique sprite we don't want to overwrite
[DataField("customPuddleSprite")] public bool CustomPuddleSprite;
// Puddles may change which RSI they use for their sprites (e.g. wet floor effects). This field will store the original RSI they used.
[DataField("originalRsi")] public RSI? OriginalRsi;
/// <summary>
/// Puddles with volume below this threshold are able to have their sprite changed to a wet floor effect, though this is not the only factor.
/// </summary>
[DataField("wetFloorEffectThreshold")]
public FixedPoint2 WetFloorEffectThreshold = FixedPoint2.New(5);
/// <summary>
/// Alpha (opacity) of the wet floor sparkle effect. Higher alpha = more opaque/visible.
/// </summary>
[DataField("wetFloorEffectAlpha")]
public float WetFloorEffectAlpha = 0.75f; //should be somewhat transparent by default.
}
}

View File

@@ -1,105 +0,0 @@
using System.Linq;
using Content.Shared.Fluids;
using Content.Shared.FixedPoint;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Random;
namespace Content.Client.Fluids
{
[UsedImplicitly]
public sealed class PuddleVisualizerSystem : VisualizerSystem<PuddleVisualizerComponent>
{
[Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PuddleVisualizerComponent, ComponentInit>(OnComponentInit);
}
private void OnComponentInit(EntityUid uid, PuddleVisualizerComponent puddleVisuals, ComponentInit args)
{
if (!TryComp(uid, out SpriteComponent? sprite))
{
return;
}
puddleVisuals.OriginalRsi = sprite.BaseRSI; //Back up the original RSI upon initialization
RandomizeState(sprite, puddleVisuals.OriginalRsi);
RandomizeRotation(sprite);
}
protected override void OnAppearanceChange(EntityUid uid, PuddleVisualizerComponent component, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
{
Logger.Warning($"Missing SpriteComponent for PuddleVisualizerSystem on entityUid = {uid}");
return;
}
if (!AppearanceSystem.TryGetData<float>(uid, PuddleVisuals.VolumeScale, out var volumeScale)
|| !AppearanceSystem.TryGetData<FixedPoint2>(uid, PuddleVisuals.CurrentVolume, out var currentVolume)
|| !AppearanceSystem.TryGetData<Color>(uid, PuddleVisuals.SolutionColor, out var solutionColor)
|| !AppearanceSystem.TryGetData<bool>(uid, PuddleVisuals.IsEvaporatingVisual, out var isEvaporating))
{
return;
}
// volumeScale is our opacity based on level of fullness to overflow. The lower bound is hard-capped for visibility reasons.
var cappedScale = Math.Min(1.0f, volumeScale * 0.75f + 0.25f);
var newColor = component.Recolor ? solutionColor.WithAlpha(cappedScale) : args.Sprite.Color.WithAlpha(cappedScale);
args.Sprite.LayerSetColor(0, newColor);
// Don't consider wet floor effects if we're using a custom sprite.
if (component.CustomPuddleSprite)
return;
if (isEvaporating && currentVolume <= component.WetFloorEffectThreshold)
{
// If we need the effect but don't already have it - start it
if (args.Sprite.LayerGetState(0) != "sparkles")
StartWetFloorEffect(args.Sprite, component.WetFloorEffectAlpha);
}
else
{
// If we have the effect but don't need it - end it
if (args.Sprite.LayerGetState(0) == "sparkles")
EndWetFloorEffect(args.Sprite, component.OriginalRsi);
}
}
private void StartWetFloorEffect(SpriteComponent sprite, float alpha)
{
sprite.LayerSetState(0, "sparkles", "Fluids/wet_floor_sparkles.rsi");
sprite.Color = sprite.Color.WithAlpha(alpha);
sprite.LayerSetAutoAnimated(0, false);
sprite.LayerSetAutoAnimated(0, true); //fixes a bug where the sparkle effect would sometimes freeze on a single frame.
}
private void EndWetFloorEffect(SpriteComponent sprite, RSI? originalRSI)
{
RandomizeState(sprite, originalRSI);
sprite.LayerSetAutoAnimated(0, false);
}
private void RandomizeState(SpriteComponent sprite, RSI? rsi)
{
var maxStates = rsi?.ToArray();
if (maxStates is not { Length: > 0 }) return;
var selectedState = _random.Next(0, maxStates.Length - 1); //randomly select an index for which RSI state to use.
sprite.LayerSetState(0, maxStates[selectedState].StateId, rsi); // sets the sprite's state via our randomly selected index.
}
private void RandomizeRotation(SpriteComponent sprite)
{
float rotationDegrees = _random.Next(0, 359); // randomly select a rotation for our puddle sprite.
sprite.Rotation = Angle.FromDegrees(rotationDegrees); // sets the sprite's rotation to the one we randomly selected.
}
}
}

View File

@@ -1,13 +1,4 @@
<Control xmlns="https://spacestation14.io">
<BoxContainer Orientation="Horizontal">
<ProgressBar
HorizontalExpand="True"
Name="PercentBar"
MinSize="20 20"
VerticalAlignment="Center"
Margin="2 8 4 2"
MaxValue="1.0"
MinValue="0.0">
</ProgressBar>
</BoxContainer>
</Control>
<controls:SplitBar xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Name="Bar">
</controls:SplitBar>

View File

@@ -1,16 +1,20 @@
using Content.Shared.Fluids;
using System.Linq;
using Content.Client.UserInterface.Controls;
using Content.Shared.Fluids;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client.Fluids.UI
{
[GenerateTypedNameReferences]
public sealed partial class AbsorbentItemStatus : Control
public sealed partial class AbsorbentItemStatus : SplitBar
{
private readonly IEntityManager _entManager;
private readonly EntityUid _uid;
private Dictionary<Color, float> _progress = new();
public AbsorbentItemStatus(EntityUid uid, IEntityManager entManager)
{
@@ -25,7 +29,23 @@ namespace Content.Client.Fluids.UI
if (!_entManager.TryGetComponent<AbsorbentComponent>(_uid, out var absorbent))
return;
PercentBar.Value = absorbent.Progress;
var oldProgress = _progress.ShallowClone();
_progress.Clear();
foreach (var item in absorbent.Progress)
{
_progress[item.Key] = item.Value;
}
if (oldProgress.OrderBy(x => x.Key.ToArgb()).SequenceEqual(_progress))
return;
Bar.Clear();
foreach (var (key, value) in absorbent.Progress)
{
Bar.AddEntry(value, key);
}
}
}
}