Merge pull request #3759 from DIMMoon1/upstream

Upstream 10.01
This commit is contained in:
Dmitry 2026-10-05 21:49:23 +07:00 • committed by GitHub
commit 7ee42055d0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
1274 changed files with 19843 additions and 19283 deletions

View file

@ -6,6 +6,9 @@ labels: autogenerated
A test failure has been detected on the main branch. This should never occur.
Commit under test: {{ env.GITHUB_SHA }}
[Link to failing run]({{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }})
> [!NOTE]
> This issue is automatically generated by a github action and will be updated when this failure reoccurs.
> Do not edit the body of this issue.

View file

@ -17,7 +17,7 @@ jobs:
- name: Checkout Master
uses: actions/checkout@v6
with:
submodules: recursive
submodules: recursive
- name: Setup .NET Core
uses: actions/setup-dotnet@v4.1.0
@ -81,6 +81,10 @@ jobs:
FULLNAME: ${{ matrix.value.fullname }}
OUTPUT: ${{ matrix.value.output }}
FAILURE: ${{ matrix.value.failure }}
GITHUB_SERVER_URL: ${{ vars.GITHUB_SERVER_URL }}
GITHUB_REPOSITORY: ${{ vars.GITHUB_REPOSITORY }}
GITHUB_RUN_ID: ${{ vars.GITHUB_RUN_ID }}
GITHUB_SHA: ${{ vars.GITHUB_SHA }}
with:
filename: .github/ISSUE_TEMPLATE/heisentest_template.md
update_existing: true

View file

@ -1,6 +1,7 @@
using System.Text;
using Content.Client.Resources;
using Content.Shared.Access.Components;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.Enums;
@ -13,12 +14,12 @@ public sealed class AccessOverlay : Overlay
private const int TextFontSize = 12;
private readonly IEntityManager _entityManager;
private readonly SharedTransformSystem _transformSystem;
private readonly TransformSystem _transformSystem;
private readonly Font _font;
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
public AccessOverlay(IEntityManager entityManager, IResourceCache resourceCache, SharedTransformSystem transformSystem)
public AccessOverlay(IEntityManager entityManager, IResourceCache resourceCache, TransformSystem transformSystem)
{
_entityManager = entityManager;
_transformSystem = transformSystem;
@ -87,7 +88,7 @@ public sealed class AccessOverlay : Overlay
}
var accessInfoText = textBuffer.ToString();
var screenPos = args.ViewportControl.WorldToScreen(_transformSystem.GetWorldPosition(transform));
var screenPos = args.ViewportControl.WorldToScreen(_transformSystem.GetRenderWorldPosition((uid, transform)));
args.ScreenHandle.DrawString(_font, screenPos, accessInfoText, 1, Color.Gold, TextOutline.Default);
}
}

View file

@ -1,3 +1,4 @@
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.Console;
@ -8,7 +9,7 @@ public sealed partial class ShowAccessReadersCommand : LocalizedEntityCommands
{
[Dependency] private IOverlayManager _overlay = default!;
[Dependency] private IResourceCache _cache = default!;
[Dependency] private SharedTransformSystem _xform = default!;
[Dependency] private TransformSystem _xform = default!;
public override string Command => "showaccessreaders";

View file

@ -7,12 +7,13 @@ namespace Content.Client.Actions;
public sealed partial class ActionIconVisualsSystem : VisualizerSystem<ActionComponent>
{
/// <inheritdoc/>
protected override void OnAppearanceChange(EntityUid uid, ActionComponent comp, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
return;
if (AppearanceSystem.TryGetData<SpriteSpecifier>(uid, ActionState.DynamicIcon, out var icon, args.Component))
if (args.TryGetData<SpriteSpecifier>(ActionState.DynamicIcon, out var icon))
{
if (icon is SpriteSpecifier.EntityPrototype)
SpriteSystem.LayerSetTexture((uid, args.Sprite), ActionVisuals.Icon, SpriteSystem.Frame0(icon));
@ -20,7 +21,7 @@ public sealed partial class ActionIconVisualsSystem : VisualizerSystem<ActionCom
SpriteSystem.LayerSetSprite((uid, args.Sprite), ActionVisuals.Icon, icon);
}
if (AppearanceSystem.TryGetData<Color>(uid, ActionState.Color, out var color, args.Component))
if (args.TryGetData<Color>(ActionState.Color, out var color))
{
SpriteSystem.LayerSetColor((uid, args.Sprite), ActionVisuals.Icon, color);

View file

@ -42,7 +42,7 @@ public sealed partial class AdminMessagePopupWindow : Control
public void SetState(AdminMessageEuiState state)
{
Timer = (float) state.Time.TotalSeconds;
Timer = (float)state.Time.TotalSeconds;
MessageContainer.RemoveAllChildren();
@ -52,7 +52,7 @@ public sealed partial class AdminMessagePopupWindow : Control
}
Description.SetMessage(
FormattedMessage.FromMarkup(Loc.GetString("admin-notes-message-desc", ("count", state.Messages.Length))));
FormattedMessage.FromMarkupOrThrow(Loc.GetString("admin-notes-message-desc", ("count", state.Messages.Length))));
}
private void OnDismissButtonPressed(BaseButton.ButtonEventArgs obj)

View file

@ -154,7 +154,6 @@ public sealed partial class ExplosionDebugOverlay : Overlay
handle.SetTransform(SpaceMatrix);
DrawTiles(handle, gridBounds, SpaceTiles, SpaceTileSize);
handle.SetTransform(Matrix3x2.Identity);
}
private void DrawTiles(

View file

@ -8,23 +8,19 @@ namespace Content.Client.AlertLevel;
public sealed partial class AlertLevelDisplaySystem : EntitySystem
{
[Dependency] private SpriteSystem _sprite = default!;
[Dependency] private SharedAppearanceSystem _appearance = default!;
[SubscribeLocalEvent]
private void OnAppearanceChange(EntityUid uid, AlertLevelDisplayComponent alertLevelDisplay, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
{
return;
}
var layer = _sprite.LayerMapReserve((uid, args.Sprite), AlertLevelDisplay.Layer);
if (_appearance.TryGetData<bool>(uid, AlertLevelDisplay.Powered, out var powered, component: args.Component))
{
if (args.TryGetData<bool>(AlertLevelDisplay.Powered, out var powered))
_sprite.LayerSetVisible((uid, args.Sprite), layer, powered);
}
if (!_appearance.TryGetData<ProtoId<AlertLevelPrototype>>(uid, AlertLevelDisplay.CurrentLevel, out var level, component: args.Component))
if (!args.TryGetData<ProtoId<AlertLevelPrototype>>(AlertLevelDisplay.CurrentLevel, out var level))
{
_sprite.LayerSetRsiState((uid, args.Sprite), layer, alertLevelDisplay.AlertVisuals.Values.First());
return;

View file

@ -34,7 +34,7 @@ public sealed partial class AnomalyScannerSystem : SharedAnomalyScannerSystem
private void OnComponentInit(Entity<AnomalyScannerScreenComponent> ent, ref ComponentInit args)
{
if(!_sprite.TryGetLayer(ent.Owner, AnomalyScannerVisualLayers.Base, out var layer, true))
if (!_sprite.TryGetLayer(ent.Owner, AnomalyScannerVisualLayers.Base, out var layer, true))
return;
// Allocate the OwnedTexture
@ -70,9 +70,8 @@ public sealed partial class AnomalyScannerSystem : SharedAnomalyScannerSystem
if (args.Sprite is null || ent.Comp.ScreenTexture is null || ent.Comp.BarBuf is null)
return;
args.AppearanceData.TryGetValue(AnomalyScannerVisuals.AnomalySeverity, out var severityObj);
if (severityObj is not float severity)
severity = 0;
if (!args.TryGetData<float>(AnomalyScannerVisuals.AnomalySeverity, out var severity))
severity = 0.0f;
// Get the bar length
var barLength = (int)(severity * ent.Comp.Size.X);
@ -80,16 +79,16 @@ public sealed partial class AnomalyScannerSystem : SharedAnomalyScannerSystem
// Calculate the bar color
// Hue "angle" of two colors to interpolate between depending on severity
// Just a lerp from Green hue at severity = 0.5 to Red hue at 1.0
var hue = Math.Clamp(2*GreenHue * (1 - severity), RedHue, GreenHue);
var hue = Math.Clamp(2 * GreenHue * (1 - severity), RedHue, GreenHue);
var color = new Rgba32(Color.FromHsv(new Vector4(hue, 1f, 1f, 1f)).RGBA);
var transparent = new Rgba32(0, 0, 0, 255);
for(var y = 0; y < ent.Comp.Size.Y; y++)
for (var y = 0; y < ent.Comp.Size.Y; y++)
{
for (var x = 0; x < ent.Comp.Size.X; x++)
{
ent.Comp.BarBuf[y*ent.Comp.Size.X + x] = x < barLength ? color : transparent;
ent.Comp.BarBuf[y * ent.Comp.Size.X + x] = x < barLength ? color : transparent;
}
}

View file

@ -46,10 +46,10 @@ public sealed partial class AnomalySystem : SharedAnomalySystem
if (args.Sprite is not { } sprite)
return;
if (!Appearance.TryGetData<bool>(uid, AnomalyVisuals.IsPulsing, out var pulsing, args.Component))
if (!args.TryGetData<bool>(AnomalyVisuals.IsPulsing, out var pulsing))
pulsing = false;
if (Appearance.TryGetData<bool>(uid, AnomalyVisuals.Supercritical, out var super, args.Component) && super)
if (args.TryGetData<bool>(AnomalyVisuals.Supercritical, out var super) && super)
pulsing = super;
if (HasComp<AnomalySupercriticalComponent>(uid))

View file

@ -75,13 +75,13 @@ public sealed partial class AtmosPipeAppearanceSystem : SharedAtmosPipeAppearanc
var numberOfPipeLayers = GetNumberOfPipeLayers(uid, out var atmosPipeLayers);
if (!_appearance.TryGetData<int>(uid, PipeVisuals.VisualState, out var worldConnectedDirections, args.Component))
if (!args.TryGetData<int>(PipeVisuals.VisualState, out var worldConnectedDirections))
{
HideAllPipeConnection((uid, args.Sprite), atmosPipeLayers, numberOfPipeLayers);
return;
}
if (!_appearance.TryGetData<Color>(uid, PipeColorVisuals.Color, out var color, args.Component))
if (!args.TryGetData<Color>(PipeColorVisuals.Color, out var color))
color = Color.White;
for (byte i = 0; i < numberOfPipeLayers; i++)

View file

@ -14,30 +14,23 @@ namespace Content.Client.Atmos.EntitySystems;
/// </summary>
public sealed partial class AtmosPipeLayersSystem : SharedAtmosPipeLayersSystem
{
[Dependency] private SharedAppearanceSystem _appearance = default!;
[Dependency] private IReflectionManager _reflection = default!;
[Dependency] private IResourceCache _resourceCache = default!;
[Dependency] private SpriteSystem _sprite = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<AtmosPipeLayersComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
private void OnAppearanceChange(Entity<AtmosPipeLayersComponent> ent, ref AppearanceChangeEvent ev)
[SubscribeLocalEvent]
private void OnAppearanceChange(Entity<AtmosPipeLayersComponent> ent, ref AppearanceChangeEvent args)
{
if (!TryComp<SpriteComponent>(ent, out var sprite))
return;
if (_appearance.TryGetData<string>(ent, AtmosPipeLayerVisuals.Sprite, out var spriteRsi) &&
if (args.TryGetData<string>(AtmosPipeLayerVisuals.Sprite, out var spriteRsi) &&
_resourceCache.TryGetResource(SpriteSpecifierSerializer.TextureRoot / spriteRsi, out RSIResource? resource))
{
_sprite.SetBaseRsi((ent, sprite), resource.RSI);
}
if (_appearance.TryGetData<Dictionary<string, string>>(ent, AtmosPipeLayerVisuals.SpriteLayers, out var pipeState))
if (args.TryGetData<Dictionary<string, string>>(AtmosPipeLayerVisuals.SpriteLayers, out var pipeState))
{
foreach (var (layerKey, rsiPath) in pipeState)
{

View file

@ -5,13 +5,13 @@ using Robust.Client.GameObjects;
namespace Content.Client.Atmos.EntitySystems;
/// <summary>
/// Used to change the appearance of gas canisters.
/// Used to change the appearance of gas canisters when painted.
/// </summary>
public sealed partial class GasCanisterAppearanceSystem : VisualizerSystem<GasCanisterComponent>
{
protected override void OnAppearanceChange(EntityUid uid, GasCanisterComponent component, ref AppearanceChangeEvent args)
{
if (!AppearanceSystem.TryGetData<string>(uid, PaintableVisuals.Prototype, out var protoName, args.Component) || args.Sprite is not { } old)
if (!args.TryGetData<string>(PaintableVisuals.Prototype, out var protoName) || args.Sprite is null)
return;
if (!ProtoMan.HasIndex(protoName))

View file

@ -0,0 +1,65 @@
using Content.Client.Atmos.Overlays;
using Content.Shared.CCVar;
using JetBrains.Annotations;
using Robust.Client.Graphics;
using Robust.Shared.Configuration;
namespace Content.Client.Atmos.EntitySystems;
/// <summary>
/// System responsible for rendering vacuum effects using <see cref="GasTileVacuumOverlay"/>.
/// </summary>
[UsedImplicitly]
public sealed partial class GasTileVacuumOverlaySystem : EntitySystem
{
[Dependency] private IOverlayManager _overlayMan = default!;
[Dependency] private IConfigurationManager _cfgManager = default!;
private GasTileVacuumOverlay? _gasTileVacuumOverlay;
private bool _vacuumOverlayEnabledDueToCvar; // due to CVar being enabled
private bool _vacuumOverlayEnabledIntensity; // due to non zero intensity in setting
public override void Initialize()
{
base.Initialize();
_cfgManager.OnValueChanged(CCVars.VacuumOverlay, OnVacuumOverlayChanged, true);
_cfgManager.OnValueChanged(CCVars.VacuumOverlayIntensity, OnVacuumOverlayIntensityChanged, true);
}
public override void Shutdown()
{
base.Shutdown();
_cfgManager.UnsubValueChanged(CCVars.VacuumOverlay, OnVacuumOverlayChanged);
_cfgManager.UnsubValueChanged(CCVars.VacuumOverlayIntensity, OnVacuumOverlayIntensityChanged);
_overlayMan.RemoveOverlay<GasTileVacuumOverlay>();
}
private void OnVacuumOverlayChanged(bool enabled)
{
_vacuumOverlayEnabledDueToCvar = enabled;
UpdateOverlay();
}
private void OnVacuumOverlayIntensityChanged(float intensity)
{
_vacuumOverlayEnabledIntensity = intensity > 0f;
UpdateOverlay();
}
private void UpdateOverlay()
{
if (_vacuumOverlayEnabledDueToCvar && _vacuumOverlayEnabledIntensity)
{
_gasTileVacuumOverlay ??= new GasTileVacuumOverlay();
if (!_overlayMan.HasOverlay<GasTileVacuumOverlay>())
_overlayMan.AddOverlay(_gasTileVacuumOverlay);
}
else
{
_overlayMan.RemoveOverlay<GasTileVacuumOverlay>();
}
}
}

View file

@ -14,13 +14,7 @@ public sealed partial class MaxPressureVisualsSystem : EntitySystem
{
[Dependency] private SpriteSystem _sprite = default!;
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<MaxPressureVisualsComponent, ComponentInit>(OnMaxPressureInit);
SubscribeLocalEvent<MaxPressureVisualsComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
[SubscribeLocalEvent]
private void OnMaxPressureInit(Entity<MaxPressureVisualsComponent> entity, ref ComponentInit args)
{
if (!TryComp<SpriteComponent>(entity, out var sprite))
@ -28,28 +22,27 @@ public sealed partial class MaxPressureVisualsSystem : EntitySystem
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(entity.Comp.IntegritySteps);
if (_sprite.LayerMapTryGet((entity, sprite), MaxPressureVisualLayers.Base, out _, false))
if (_sprite.LayerMapTryGet((entity, sprite), MaxPressureVisualLayers.Base, out var layerIndex, false))
{
_sprite.LayerSetRsiState((entity, sprite), MaxPressureVisualLayers.Base, $"{entity.Comp.IntegrityMask}");
_sprite.LayerSetVisible((entity, sprite), MaxPressureVisualLayers.Base, false);
_sprite.LayerSetRsiState((entity, sprite), layerIndex, $"{entity.Comp.IntegrityMask}");
_sprite.LayerSetVisible((entity, sprite), layerIndex, false);
}
if (_sprite.LayerMapTryGet((entity, sprite), MaxPressureVisualLayers.BaseUnshaded, out _, false))
if (_sprite.LayerMapTryGet((entity, sprite), MaxPressureVisualLayers.BaseUnshaded, out layerIndex, false))
{
_sprite.LayerSetRsiState((entity, sprite), MaxPressureVisualLayers.BaseUnshaded, $"{entity.Comp.IntegrityState}-unshaded-0");
_sprite.LayerSetVisible((entity, sprite), MaxPressureVisualLayers.BaseUnshaded, false);
_sprite.LayerSetRsiState((entity, sprite), layerIndex, $"{entity.Comp.IntegrityState}-unshaded-0");
_sprite.LayerSetVisible((entity, sprite), layerIndex, false);
}
}
[SubscribeLocalEvent]
private void OnAppearanceChange(Entity<MaxPressureVisualsComponent> entity, ref AppearanceChangeEvent args)
{
if (args.Sprite is not { } sprite)
return;
if (!args.AppearanceData.TryGetValue(GasIntegrity.Integrity, out var obj) || obj is not float integrity)
return;
if (!args.AppearanceData.TryGetValue(GasIntegrity.MaxIntegrity, out obj) || obj is not float maxIntegrity)
if (!args.TryGetData<float>(GasIntegrity.Integrity, out var integrity)
|| !args.TryGetData<float>(GasIntegrity.MaxIntegrity, out var maxIntegrity))
return;
// We don't want visuals at max integrity, so we return if we're at max.

View file

@ -8,13 +8,15 @@ public sealed partial class PipeColorVisualizerSystem : VisualizerSystem<PipeCol
{
protected override void OnAppearanceChange(EntityUid uid, PipeColorVisualsComponent component, ref AppearanceChangeEvent args)
{
if (TryComp<SpriteComponent>(uid, out var sprite)
&& AppearanceSystem.TryGetData<Color>(uid, PipeColorVisuals.Color, out var color, args.Component))
{
// T-ray scanner / sub floor runs after this visualizer. Lets not bulldoze transparency.
var layer = sprite[PipeVisualLayers.Pipe];
layer.Color = color.WithAlpha(layer.Color.A);
}
if (args.Sprite == null)
return;
if (!args.TryGetData<Color>(PipeColorVisuals.Color, out var color))
return;
// T-ray scanner / sub floor runs after this visualizer. Lets not bulldoze transparency.
var layer = args.Sprite[PipeVisualLayers.Pipe];
layer.Color = color.WithAlpha(layer.Color.A);
}
}

View file

@ -12,11 +12,8 @@ public sealed partial class AtmosAlarmableVisualsSystem : VisualizerSystem<Atmos
if (args.Sprite == null || !SpriteSystem.LayerMapTryGet((uid, args.Sprite), component.LayerMap, out var layer, false))
return;
if (!args.AppearanceData.TryGetValue(PowerDeviceVisuals.Powered, out var poweredObject) ||
poweredObject is not bool powered)
{
if (!args.TryGetData<bool>(PowerDeviceVisuals.Powered, out var powered))
return;
}
if (component.HideOnDepowered != null)
{
@ -36,8 +33,7 @@ public sealed partial class AtmosAlarmableVisualsSystem : VisualizerSystem<Atmos
}
}
if (args.AppearanceData.TryGetValue(AtmosMonitorVisuals.AlarmType, out var alarmTypeObject)
&& alarmTypeObject is AtmosAlarmType alarmType
if (args.TryGetData<AtmosAlarmType>(AtmosMonitorVisuals.AlarmType, out var alarmType)
&& powered
&& component.AlarmStates.TryGetValue(alarmType, out var state))
{

View file

@ -65,8 +65,6 @@ public sealed partial class AtmosDebugOverlay : Overlay
handle.SetTransform(_transform.GetWorldMatrix(grid));
DrawData(msg, handle);
}
handle.SetTransform(Matrix3x2.Identity);
}
private void DrawData(DebugMessage msg,

View file

@ -222,8 +222,6 @@ public sealed partial class GasTileDangerousTemperatureOverlay : Overlay
},
new Color(0, 0, 0, 0));
drawHandle.SetTransform(Matrix3x2.Identity);
return true;
}
@ -233,7 +231,6 @@ public sealed partial class GasTileDangerousTemperatureOverlay : Overlay
if (res.TemperatureTarget != null)
args.WorldHandle.DrawTextureRect(res.TemperatureTarget.Texture, args.WorldBounds);
args.WorldHandle.SetTransform(Matrix3x2.Identity);
}
protected override void DisposeBehavior()

View file

@ -164,8 +164,5 @@ public sealed partial class GasTileFireOverlay : Overlay
return true;
});
drawHandle.UseShader(null);
drawHandle.SetTransform(Matrix3x2.Identity);
}
}

View file

@ -198,8 +198,6 @@ public sealed partial class GasTileHeatBlurOverlay : Overlay
// no distortion, no need to render
if (!anyDistortion)
{
args.WorldHandle.UseShader(null);
args.WorldHandle.SetTransform(Matrix3x2.Identity);
return false;
}
@ -218,9 +216,6 @@ public sealed partial class GasTileHeatBlurOverlay : Overlay
args.WorldHandle.UseShader(_shader);
args.WorldHandle.DrawTextureRect(res.HeatTarget.Texture, args.WorldBounds);
args.WorldHandle.UseShader(null);
args.WorldHandle.SetTransform(Matrix3x2.Identity);
}
protected override void DisposeBehavior()

View file

@ -0,0 +1,196 @@
using System.Numerics;
using Content.Client.Graphics;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Components;
using Content.Shared.Atmos.EntitySystems;
using Content.Shared.CCVar;
using Robust.Client.Graphics;
using Robust.Shared.Configuration;
using Robust.Shared.Enums;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Prototypes;
using Color = Robust.Shared.Maths.Color;
namespace Content.Client.Atmos.Overlays;
/// <summary>
/// Overlay responsible for rendering vacuum overlay.
/// </summary>
public sealed partial class GasTileVacuumOverlay : Overlay
{
public override bool RequestScreenTexture { get; set; } = true;
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
private static readonly ProtoId<ShaderPrototype> VacuumOverlayShader = "VacuumDesaturation";
private static readonly Color EmptyColor = new(0, 0, 0, 0);
private static readonly Color MarkerColor = new(255f, 0, 0);
[Dependency] private IEntityManager _entManager = default!;
[Dependency] private IPrototypeManager _proto = default!;
[Dependency] private IClyde _clyde = default!;
[Dependency] private IConfigurationManager _configManager = default!;
private readonly SharedMapSystem _maps;
private readonly SharedTransformSystem _xformSys;
private readonly ShaderInstance _unshader;
private readonly ShaderInstance _shader;
private List<Entity<MapGridComponent>> _intersectingGrids = new();
private readonly OverlayResourceCache<CachedResources> _resources = new();
// Overlay settings
private float _intensity; // overlay intensity. 0.0f = turned off, 1.0f = full grayscale
public override OverlaySpace Space => OverlaySpace.WorldSpace;
public GasTileVacuumOverlay()
{
IoCManager.InjectDependencies(this);
_maps = _entManager.System<SharedMapSystem>();
_xformSys = _entManager.System<SharedTransformSystem>();
_unshader = _proto.Index(UnshadedShader).Instance();
_shader = _proto.Index(VacuumOverlayShader).InstanceUnique();
_configManager.OnValueChanged(CCVars.VacuumOverlayIntensity, SetVacuumOverlayIntensity, invokeImmediately: true);
}
private void SetVacuumOverlayIntensity(float intensity)
{
_intensity = MathHelper.Clamp(intensity, 0f, 1f);
_shader.SetParameter("intensity", _intensity);
}
protected override bool BeforeDraw(in OverlayDrawArgs args)
{
if (args.MapId == MapId.Nullspace)
return false;
var res = _resources.GetForViewport(args.Viewport, static _ => new CachedResources());
var target = args.Viewport.RenderTarget;
// Probably the resolution of the game window changed, remake the textures.
if (res.VacuumTarget?.Texture.Size != target.Size)
{
res.VacuumTarget?.Dispose();
res.VacuumTarget = _clyde.CreateRenderTarget(
target.Size,
new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb),
name: $"{nameof(GasTileVacuumOverlay)}-blur");
}
var overlayQuery = _entManager.GetEntityQuery<GasTileOverlayComponent>();
args.WorldHandle.UseShader(_unshader);
var mapId = args.MapId;
var worldAABB = args.WorldAABB;
var worldBounds = args.WorldBounds;
var worldHandle = args.WorldHandle;
var worldToViewportLocal = args.Viewport.GetWorldToLocalMatrix();
// If there is no Vacuum after checking all visible tiles, we can bail early
var anyVacuum = false;
// We're rendering in the context of the vacuum target texture, which will encode data as to where vacuum effect will be
args.WorldHandle.RenderInRenderTarget(res.VacuumTarget,
() =>
{
_intersectingGrids.Clear();
_maps.FindGridsIntersecting(mapId, worldAABB, ref _intersectingGrids);
foreach (var grid in _intersectingGrids)
{
if (!overlayQuery.TryGetComponent(grid.Owner, out var comp))
continue;
var (_, _, gridEntToWorld, worldToGridLocal) = _xformSys.GetWorldPositionRotationMatrixWithInv(grid.Owner);
var gridEntToViewportLocal = gridEntToWorld * worldToViewportLocal;
if (!Matrix3x2.Invert(gridEntToViewportLocal, out _))
continue;
// Draw commands (like DrawRect) will be using grid coordinates from here
worldHandle.SetTransform(gridEntToViewportLocal);
// We only care about tiles that fit in these bounds
var floatBounds = worldToGridLocal.TransformBox(worldBounds).Enlarged(grid.Comp.TileSize);
var localBounds = new Box2i(
(int)MathF.Floor(floatBounds.Left),
(int)MathF.Floor(floatBounds.Bottom),
(int)MathF.Ceiling(floatBounds.Right),
(int)MathF.Ceiling(floatBounds.Top));
// for each tile and its gas --->
foreach (var chunk in comp.Chunks.Values)
{
var enumerator = new GasChunkEnumerator(chunk);
while (enumerator.MoveNext(out var tileGas))
{
// Check and make sure the tile is within the viewport/screen
var tilePosition = chunk.Origin + (enumerator.X, enumerator.Y);
if (!localBounds.Contains(tilePosition))
continue;
if (tileGas.ByteGasTemperature.Value != ThermalByte.StateVacuum)
continue;
// Encode the strength in the red channel
// alpha set to 1 as tile is active
worldHandle.DrawRect(Box2.CenteredAround(tilePosition + grid.Comp.TileSizeHalfVector,
grid.Comp.TileSizeVector),
MarkerColor);
anyVacuum = true;
}
}
}
},
// This clears the buffer to all zero first...
EmptyColor);
// no distortion, no need to render
if (!anyVacuum)
{
args.WorldHandle.UseShader(null);
args.WorldHandle.SetTransform(Matrix3x2.Identity);
return false;
}
return true;
}
protected override void Draw(in OverlayDrawArgs args)
{
var res = _resources.GetForViewport(args.Viewport, static _ => new CachedResources());
if (ScreenTexture is null || res.VacuumTarget is null)
return;
_shader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
args.WorldHandle.UseShader(_shader);
args.WorldHandle.DrawTextureRect(res.VacuumTarget.Texture, args.WorldBounds);
args.WorldHandle.UseShader(null);
args.WorldHandle.SetTransform(Matrix3x2.Identity);
}
protected override void DisposeBehavior()
{
_resources.Dispose();
_configManager.UnsubValueChanged(CCVars.VacuumOverlayIntensity, SetVacuumOverlayIntensity);
base.DisposeBehavior();
}
internal sealed class CachedResources : IDisposable
{
public IRenderTexture? VacuumTarget;
public void Dispose()
{
VacuumTarget?.Dispose();
}
}
}

View file

@ -204,9 +204,6 @@ public sealed partial class GasTileVisibleGasOverlay : Overlay
return true;
});
drawHandle.UseShader(null);
drawHandle.SetTransform(Matrix3x2.Identity);
}
private void DrawMapOverlay(

View file

@ -1,7 +1,8 @@
<DefaultWindow xmlns="https://spacestation14.io"
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
MinSize="270 420"
SetSize="360 420" Title="{Loc 'gas-analyzer-window-name'}">
<BoxContainer Orientation="Vertical" Margin="5 5 5 5">
<BoxContainer Orientation="Vertical" Margin="10">
<BoxContainer Name="CTopBox" Orientation="Horizontal"/>
<!-- Gas Mix Data, Populated by function -->
<TabContainer Name="CTabContainer" VerticalExpand="True" Margin="1 1 1 2">
@ -43,4 +44,4 @@
</ScrollContainer>
</TabContainer>
</BoxContainer>
</DefaultWindow>
</controls:FancyWindow>

View file

@ -15,7 +15,7 @@ using Direction = Robust.Shared.Maths.Direction;
namespace Content.Client.Atmos.UI
{
[GenerateTypedNameReferences]
public sealed partial class GasAnalyzerWindow : DefaultWindow
public sealed partial class GasAnalyzerWindow : FancyWindow
{
private readonly SharedAtmosphereSystem _atmosphere;
private NetEntity _currentEntity = NetEntity.Invalid;

View file

@ -1,8 +1,9 @@
<DefaultWindow xmlns="https://spacestation14.io"
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:Content.Client.Stylesheets"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
MinSize="480 400" Title="Canister">
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
<BoxContainer Orientation="Vertical" Margin="10" SeparationOverride="10">
<BoxContainer Orientation="Vertical" VerticalExpand="True">
<Label Text="{Loc comp-gas-canister-ui-canister-status}" StyleClasses="LabelHeading"/>
<BoxContainer Orientation="Horizontal">
@ -49,4 +50,4 @@
</BoxContainer>
</BoxContainer>
</BoxContainer>
</DefaultWindow>
</controls:FancyWindow>

View file

@ -1,4 +1,5 @@
using System;
using Content.Client.UserInterface.Controls;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
@ -13,7 +14,7 @@ namespace Content.Client.Atmos.UI
/// Client-side UI used to control a canister.
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class GasCanisterWindow : DefaultWindow
public sealed partial class GasCanisterWindow : FancyWindow
{
private readonly ButtonGroup _buttonGroup = new();

View file

@ -1,8 +1,8 @@
<DefaultWindow xmlns="https://spacestation14.io"
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
MinSize="480 400" Title="Filter">
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
<BoxContainer Orientation="Vertical" Margin="10" SeparationOverride="10">
<controls:SwitchButton
Name="ToggleStatusButton"
HorizontalAlignment="Left"
@ -25,4 +25,4 @@
<Button Name="SelectGasButton" Text="{Loc comp-gas-filter-ui-filter-gas-confirm}" HorizontalExpand="True" Disabled="True" />
</BoxContainer>
</BoxContainer>
</DefaultWindow>
</controls:FancyWindow>

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Content.Client.UserInterface.Controls;
using Content.Shared.Atmos.Prototypes;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
@ -14,7 +15,7 @@ namespace Content.Client.Atmos.UI
/// Client-side UI used to control a gas filter.
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class GasFilterWindow : DefaultWindow
public sealed partial class GasFilterWindow : FancyWindow
{
private readonly ButtonGroup _buttonGroup = new();

View file

@ -1,8 +1,8 @@
<DefaultWindow xmlns="https://spacestation14.io"
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
MinSize="200 200" Title="Gas Mixer">
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
Resizable="False" Title="Gas Mixer">
<BoxContainer Orientation="Vertical" Margin="10" SeparationOverride="10">
<controls:SwitchButton
Name="ToggleStatusButton"
HorizontalAlignment="Left"
@ -10,7 +10,7 @@
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Label Text="{Loc comp-gas-mixer-ui-mixer-output-pressure}"/>
<Control MinSize="5 0" />
<LineEdit Name="MixerPressureOutputInput" MinSize="70 0" />
<LineEdit Name="MixerPressureOutputInput" MinSize="80 0" />
<Control MinSize="5 0" />
<Button Name="SetMaxPressureButton" Text="{Loc comp-gas-mixer-ui-mixer-max}" />
<Control MinSize="5 0" />
@ -20,7 +20,7 @@
</BoxContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Control MinSize="0 5" />
<Label Text="{Loc comp-gas-mixer-ui-mixer-node-primary}"/>
<Label Text="{Loc comp-gas-mixer-ui-mixer-node-back}"/>
<Control MinSize="5 0" />
<LineEdit Name="MixerNodeOneInput" MinSize="60 0" />
<Label Text=" %"/>
@ -34,4 +34,4 @@
<Button Name="SetMixerPercentageButton" Text="{Loc comp-gas-mixer-ui-mixer-set}" HorizontalAlignment="Right" Disabled="True"/>
</BoxContainer>
</BoxContainer>
</DefaultWindow>
</controls:FancyWindow>

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using Content.Client.Atmos.EntitySystems;
using Content.Client.UserInterface.Controls;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Prototypes;
using Robust.Client.AutoGenerated;
@ -19,7 +20,7 @@ namespace Content.Client.Atmos.UI
/// Client-side UI used to control a gas mixer.
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class GasMixerWindow : DefaultWindow
public sealed partial class GasMixerWindow : FancyWindow
{
public event Action<bool>? ToggleStatusButtonPressed;
public event Action<string>? MixerOutputPressureChanged;

View file

@ -1,8 +1,8 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
SetSize="340 110" MinSize="340 110" Title="Pressure Pump">
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
MinSize="50 50" Resizable="False" Title="Pressure Pump">
<BoxContainer Orientation="Vertical" Margin="10" SeparationOverride="10">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<controls:SwitchButton
Name="ToggleStatusButton"
@ -14,7 +14,7 @@
</BoxContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Label Text="{Loc comp-gas-pump-ui-pump-output-pressure}"/>
<FloatSpinBox HorizontalExpand="True" Name="PumpPressureOutputInput" MinSize="70 0" />
<FloatSpinBox HorizontalExpand="True" Name="PumpPressureOutputInput" MinSize="155 0" />
</BoxContainer>
</BoxContainer>
</controls:FancyWindow>

View file

@ -2,7 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
MinSize="300 120" Title="{Loc comp-gas-thermomachine-ui-title-freezer}">
<BoxContainer Name="VboxContainer" Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
<BoxContainer Name="VboxContainer" Orientation="Vertical" Margin="10" SeparationOverride="10">
<controls:SwitchButton
Name="ToggleStatusButton"
HorizontalAlignment="Left"

View file

@ -1,8 +1,8 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
MinSize="200 120" Title="Volume Pump">
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
MinSize="50 50" Resizable="False" Title="Volume Pump">
<BoxContainer Orientation="Vertical" Margin="10" SeparationOverride="10">
<controls:SwitchButton
Name="ToggleStatusButton"
HorizontalAlignment="Left"

View file

@ -1,9 +1,9 @@
<DefaultWindow xmlns="https://spacestation14.io"
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
MinSize="280 160" Title="{Loc comp-space-heater-ui-title}">
MinSize="50 50" Resizable="False" Title="{Loc comp-space-heater-ui-title}">
<BoxContainer Name="VboxContainer" Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
<BoxContainer Name="VboxContainer" Orientation="Vertical" Margin="10" SeparationOverride="10">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<controls:SwitchButton
@ -22,7 +22,7 @@
</BoxContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" HorizontalAlignment="Right">
<Button Text="{Loc comp-space-heater-ui-decrease-temperature-range}" Access="Public" Name="DecreaseTempRange" StyleClasses="OpenRight"/>
<LineEdit Name ="Thermostat" MinSize="55 0"></LineEdit>
<LineEdit Name ="Thermostat" MinSize="55 0" CanKeyboardFocus="False"></LineEdit>
<Button Text="{Loc comp-space-heater-ui-increase-temperature-range}" Access="Public" Name="IncreaseTempRange" StyleClasses="OpenLeft"/>
</BoxContainer>
</BoxContainer>
@ -33,4 +33,4 @@
</BoxContainer>
</BoxContainer>
</DefaultWindow>
</controls:FancyWindow>

View file

@ -1,3 +1,4 @@
using Content.Client.UserInterface.Controls;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
@ -11,7 +12,7 @@ namespace Content.Client.Atmos.UI;
/// Client-side UI used to control a space heater.
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class SpaceHeaterWindow : DefaultWindow
public sealed partial class SpaceHeaterWindow : FancyWindow
{
// To account for a minimum delta temperature for atmos equalization to trigger we use a fixed step for target temperature increment/decrement
public int TemperatureChangeDelta = 5;

View file

@ -14,8 +14,8 @@ public sealed partial class PortableScrubberSystem : VisualizerSystem<PortableSc
if (args.Sprite == null)
return;
if (AppearanceSystem.TryGetData<bool>(uid, PortableScrubberVisuals.IsFull, out var isFull, args.Component)
&& AppearanceSystem.TryGetData<bool>(uid, PortableScrubberVisuals.IsRunning, out var isRunning, args.Component))
if (args.TryGetData<bool>(PortableScrubberVisuals.IsFull, out var isFull)
&& args.TryGetData<bool>(PortableScrubberVisuals.IsRunning, out var isRunning))
{
var runningState = isRunning ? component.RunningState : component.IdleState;
SpriteSystem.LayerSetRsiState((uid, args.Sprite), PortableScrubberVisualLayers.IsRunning, runningState);
@ -24,7 +24,7 @@ public sealed partial class PortableScrubberSystem : VisualizerSystem<PortableSc
SpriteSystem.LayerSetRsiState((uid, args.Sprite), PowerDeviceVisualLayers.Powered, fullState);
}
if (AppearanceSystem.TryGetData<bool>(uid, PortableScrubberVisuals.IsDraining, out var isDraining, args.Component))
if (args.TryGetData<bool>(PortableScrubberVisuals.IsDraining, out var isDraining))
{
SpriteSystem.LayerSetVisible((uid, args.Sprite), PortableScrubberVisualLayers.IsDraining, isDraining);
}

View file

@ -72,11 +72,8 @@ public sealed partial class JukeboxSystem : SharedJukeboxSystem
if (args.Sprite == null)
return;
if (!args.AppearanceData.TryGetValue(JukeboxVisuals.VisualState, out var visualStateObject) ||
visualStateObject is not JukeboxVisualState visualState)
{
if (!args.TryGetData<JukeboxVisualState>(JukeboxVisuals.VisualState, out var visualState))
visualState = JukeboxVisualState.On;
}
UpdateAppearance((uid, args.Sprite), visualState, component);
}

View file

@ -8,8 +8,8 @@ public sealed partial class BarSignVisualizerSystem : VisualizerSystem<BarSignCo
{
protected override void OnAppearanceChange(EntityUid uid, BarSignComponent component, ref AppearanceChangeEvent args)
{
AppearanceSystem.TryGetData<bool>(uid, PowerDeviceVisuals.Powered, out var powered, args.Component);
AppearanceSystem.TryGetData<string>(uid, BarSignVisuals.BarSignPrototype, out var currentSign, args.Component);
args.TryGetData<bool>(PowerDeviceVisuals.Powered, out var powered);
args.TryGetData<string>(BarSignVisuals.BarSignPrototype, out var currentSign);
if (powered
&& currentSign != null

View file

@ -12,11 +12,11 @@ public sealed partial class PotencyVisualsSystem : VisualizerSystem<PotencyVisua
if (args.Sprite == null)
return;
if (AppearanceSystem.TryGetData<float>(uid, ProduceVisuals.Potency, out var potency, args.Component))
{
var potencyRatio = Math.Clamp(potency / 100f, 0f, 1f);
var scale = MathHelper.Lerp(component.MinimumScale, component.MaximumScale, potencyRatio);
SpriteSystem.SetScale((uid, args.Sprite), new Vector2(scale, scale));
}
if (!args.TryGetData<float>(ProduceVisuals.Potency, out var potency))
return;
var potencyRatio = Math.Clamp(potency / 100f, 0f, 1f);
var scale = MathHelper.Lerp(component.MinimumScale, component.MaximumScale, potencyRatio);
SpriteSystem.SetScale((uid, args.Sprite), new Vector2(scale, scale));
}
}

View file

@ -12,13 +12,22 @@ internal sealed partial class BuckleSystem : SharedBuckleSystem
{
[Dependency] private RotationVisualizerSystem _rotationVisualizerSystem = default!;
[Dependency] private IEyeManager _eye = default!;
[Dependency] private SharedTransformSystem _xformSystem = default!;
[Dependency] private TransformSystem _xformSystem = default!;
[Dependency] private SpriteSystem _sprite = default!;
[Dependency] private EntityQuery<SpriteComponent> _spriteQuery = default!;
#region Event Handlers
protected override void AfterBuckleParentChanged(Entity<BuckleComponent> ent, ref EntParentChangedMessage args)
{
if (HasComp<StrapComponent>(args.Transform.ParentUid) ||
args.OldParent is { } oldParent && HasComp<StrapComponent>(oldParent))
{
_xformSystem.SnapRenderTransformAfterParentChange(ent, true);
}
}
[SubscribeLocalEvent]
private void OnStrapMoveEvent(Entity<StrapComponent> ent, ref MoveEvent args)
{
@ -90,6 +99,8 @@ internal sealed partial class BuckleSystem : SharedBuckleSystem
[SubscribeLocalEvent]
private void OnBuckledEvent(Entity<BuckleComponent> ent, ref BuckledEvent args)
{
_xformSystem.SnapRenderTransform(ent, true);
if (!args.Strap.Comp.ModifyBuckleDrawDepth)
return;
@ -114,6 +125,8 @@ internal sealed partial class BuckleSystem : SharedBuckleSystem
[SubscribeLocalEvent]
private void OnUnbuckledEvent(Entity<BuckleComponent> ent, ref UnbuckledEvent args)
{
_xformSystem.SnapRenderTransform(ent, true);
if (!args.Strap.Comp.ModifyBuckleDrawDepth)
return;
@ -133,7 +146,7 @@ internal sealed partial class BuckleSystem : SharedBuckleSystem
if (!TryComp<RotationVisualsComponent>(ent, out var rotVisuals))
return;
if (!Appearance.TryGetData<bool>(ent, BuckleVisuals.Buckled, out var buckled, args.Component) ||
if (!args.TryGetData<bool>(BuckleVisuals.Buckled, out var buckled) ||
!buckled ||
args.Sprite == null)
{

View file

@ -39,7 +39,7 @@ public sealed partial class TypingIndicatorVisualizerSystem : VisualizerSystem<T
args.Sprite.LayerSetShader(layer, proto.Shader);
SpriteSystem.LayerSetOffset((uid, args.Sprite), layer, proto.Offset);
AppearanceSystem.TryGetData<TypingIndicatorState>(uid, TypingIndicatorVisuals.State, out var state);
args.TryGetData<TypingIndicatorState>(TypingIndicatorVisuals.State, out var state);
SpriteSystem.LayerSetVisible((uid, args.Sprite), layer, state != TypingIndicatorState.None);
switch (state)
{

View file

@ -4,6 +4,7 @@ using Content.Shared.CCVar;
using Content.Shared.Chat;
using Content.Shared.Speech;
using Robust.Client.Graphics;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Configuration;
@ -18,7 +19,7 @@ namespace Content.Client.Chat.UI
[Dependency] private IEyeManager _eyeManager = default!;
[Dependency] private IEntityManager _entityManager = default!;
[Dependency] protected IConfigurationManager ConfigManager = default!;
private readonly SharedTransformSystem _transformSystem;
private readonly TransformSystem _transformSystem;
public enum SpeechType : byte
{
@ -89,7 +90,7 @@ namespace Content.Client.Chat.UI
{
IoCManager.InjectDependencies(this);
_senderEntity = senderEntity;
_transformSystem = _entityManager.System<SharedTransformSystem>();
_transformSystem = _entityManager.System<TransformSystem>();
// Use text clipping so new messages don't overlap old ones being pushed up.
RectClipContent = true;
@ -153,7 +154,7 @@ namespace Content.Client.Chat.UI
baseOffset = speech.SpeechBubbleOffset;
var offset = (-_eyeManager.CurrentEye.Rotation).ToWorldVec() * -(EntityVerticalOffset + baseOffset);
var worldPos = _transformSystem.GetWorldPosition(xform) + offset;
var worldPos = _transformSystem.GetRenderWorldPosition((_senderEntity, xform)) + offset;
var lowerCenter = _eyeManager.WorldToScreen(worldPos) / UIScale;
var screenPos = lowerCenter - new Vector2(ContentSize.X / 2, ContentSize.Y + _verticalOffsetAchieved);

View file

@ -15,7 +15,7 @@ public sealed partial class SmokeVisualizerSystem : VisualizerSystem<SmokeVisual
{
if (args.Sprite == null)
return;
if (!AppearanceSystem.TryGetData<Color>(uid, SmokeVisuals.Color, out var color))
if (!args.TryGetData<Color>(SmokeVisuals.Color, out var color))
return;
SpriteSystem.SetColor((uid, args.Sprite), color);
}

View file

@ -35,14 +35,11 @@ public sealed partial class SolutionContainerVisualsSystem : VisualizerSystem<So
// Check if the solution that was updated is the one set as represented
if (!string.IsNullOrEmpty(component.SolutionName)
&& AppearanceSystem.TryGetData(uid, SolutionContainerVisuals.SolutionName, out string name, args.Component)
&& args.TryGetData<string>(SolutionContainerVisuals.SolutionName, out var name)
&& name != component.SolutionName)
return;
if (!AppearanceSystem.TryGetData(uid,
SolutionContainerVisuals.FillFraction,
out float fraction,
args.Component))
if (!args.TryGetData<float>(SolutionContainerVisuals.FillFraction, out var fraction))
return;
// C# moment; setting it as nullable (even though it's not) avoids a
@ -100,8 +97,7 @@ public sealed partial class SolutionContainerVisualsSystem : VisualizerSystem<So
SpriteSystem.LayerSetRsiState(ent, fillLayer, fillBaseName + closestFillSprite);
if (changeColor
&& AppearanceSystem.TryGetData(uid, SolutionContainerVisuals.Color, out Color color, args.Component))
if (changeColor && args.TryGetData<Color>(SolutionContainerVisuals.Color, out var color))
SpriteSystem.LayerSetColor(ent, fillLayer, color);
else
SpriteSystem.LayerSetColor(ent, fillLayer, Color.White);
@ -127,10 +123,7 @@ public sealed partial class SolutionContainerVisualsSystem : VisualizerSystem<So
Entity<SpriteComponent?> ent,
int fillLayer)
{
if (!AppearanceSystem.TryGetData(uid,
SolutionContainerVisuals.BaseOverride,
out string baseOverride,
args.Component))
if (!args.TryGetData<string>(SolutionContainerVisuals.BaseOverride, out var baseOverride))
return null;
var reagentProto = ProtoMan.Index<ReagentPrototype>(baseOverride);

View file

@ -50,10 +50,8 @@ public sealed partial class VaporVisualizerSystem : VisualizerSystem<VaporVisual
/// </summary>
protected override void OnAppearanceChange(EntityUid uid, VaporVisualsComponent comp, ref AppearanceChangeEvent args)
{
if (AppearanceSystem.TryGetData<Color>(uid, VaporVisuals.Color, out var color, args.Component) && args.Sprite != null)
{
if (args.Sprite != null && args.TryGetData<Color>(VaporVisuals.Color, out var color))
SpriteSystem.SetColor((uid, args.Sprite), color);
}
}
}

View file

@ -1,9 +1,7 @@
using Content.Client.Clothing.Systems;
using Content.Shared.Clothing.Components;
using Content.Shared.Tag;
using Content.Shared.Prototypes;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Shared.Prototypes;
@ -54,7 +52,8 @@ public sealed partial class ChameleonBoundUserInterface : BoundUserInterface
newTargets.Add(target);
}
_menu?.UpdateState(newTargets, st.SelectedId);
} else
}
else
{
_menu?.UpdateState(targets, st.SelectedId);
}

View file

@ -27,7 +27,6 @@ namespace Content.Client.CombatMode
worldHandle.UseShader(_shader);
var viewport = args.WorldAABB;
worldHandle.DrawRect(viewport, Color.White);
worldHandle.UseShader(null);
}
}
}

View file

@ -21,10 +21,13 @@ public sealed partial class CommunicationsConsoleBoundUserInterface(EntityUid ow
[Dependency] private StationSystem _station = default!;
[Dependency] private AlertLevelSystem _alertLevel = default!;
[Dependency] private EntityQuery<AlertLevelComponent> _alertLevelQuery;
[ViewVariables]
private CommunicationsConsoleMenu? _menu;
private static readonly EntProtoId FallbackScreen = "Screen";
private static readonly ProtoId<AlertLevelPrototype> UnknownAlertLevel = "Unknown";
/// <inheritdoc/>
protected override void Open()
@ -81,21 +84,30 @@ public sealed partial class CommunicationsConsoleBoundUserInterface(EntityUid ow
{
base.UpdateState(state);
if (_menu == null)
return;
if (state is not CommunicationsConsoleInterfaceState commsState)
return;
var stationUid = _station.GetOwningStation(Owner);
if (!EntMan.TryGetComponent<AlertLevelComponent>(stationUid, out var alertComp))
return;
if (_menu != null)
ProtoId<AlertLevelPrototype> currentAlertLevel;
List<ProtoId<AlertLevelPrototype>> selectableAlertLevels;
bool canChangeAlertLevel;
if (_alertLevelQuery.TryGetComponent(stationUid, out var alertComp))
{
var currentAlertLevel = alertComp.CurrentAlertLevel;
var selectableAlertLevels = _alertLevel.GetSelectableAlertLevels((stationUid.Value, alertComp));
var canChangeAlertLevel = _alertLevel.CanChangeAlertLevel((stationUid.Value, alertComp));
_menu.UpdateState(commsState, currentAlertLevel, selectableAlertLevels, canChangeAlertLevel);
currentAlertLevel = alertComp.CurrentAlertLevel;
selectableAlertLevels = _alertLevel.GetSelectableAlertLevels((stationUid.Value, alertComp));
canChangeAlertLevel = _alertLevel.CanChangeAlertLevel((stationUid.Value, alertComp));
}
else
{
currentAlertLevel = UnknownAlertLevel;
selectableAlertLevels = new() { UnknownAlertLevel };
canChangeAlertLevel = false;
}
_menu.UpdateState(commsState, currentAlertLevel, selectableAlertLevels, canChangeAlertLevel);
}
}

View file

@ -22,7 +22,7 @@ public sealed partial class FlatpackSystem : SharedFlatpackSystem
private void OnAppearanceChange(Entity<FlatpackComponent> ent, ref AppearanceChangeEvent args)
{
var (_, comp) = ent;
if (!_appearance.TryGetData<string>(ent, FlatpackVisuals.Machine, out var machineBoardId) || args.Sprite == null)
if (args.Sprite == null || !args.TryGetData<string>(FlatpackVisuals.Machine, out var machineBoardId))
return;
if (!ProtoMan.TryIndex<EntityPrototype>(machineBoardId, out var machineBoardPrototype))

View file

@ -142,7 +142,7 @@ public sealed partial class EntityScreenshotGenerator
try
{
if (proto.HasComponent<SpriteComponent>(_entityManager.ComponentFactory))
if (proto.HasComp<SpriteComponent>(_entityManager.ComponentFactory))
{
entity = _entityManager.SpawnEntity(proto.ID, new EntityCoordinates(previewGrid.Owner, default));
@ -257,7 +257,7 @@ public sealed partial class EntityScreenshotGenerator
private bool HasExportableSprite(EntityPrototype prototype)
{
if (prototype.HasComponent<SpriteComponent>(_entityManager.ComponentFactory))
if (prototype.HasComp<SpriteComponent>(_entityManager.ComponentFactory))
return true;
return TryGetPrototypeIcon(prototype, out _);

View file

@ -13,20 +13,20 @@ using Robust.Shared.Utility;
namespace Content.Client.Damage;
/// <summary>
/// A simple visualizer for any entity with a DamageableComponent
/// to display the status of how damaged it is.
/// A simple visualizer for any entity with a DamageableComponent
/// to display the status of how damaged it is.
///
/// Can either be an overlay for an entity, or target multiple
/// layers on the same entity.
/// Can either be an overlay for an entity, or target multiple
/// layers on the same entity.
///
/// This can be disabled dynamically by passing into SetData,
/// key DamageVisualizerKeys.Disabled, value bool
/// (DamageVisualizerKeys lives in Content.Shared.Damage)
/// This can be disabled dynamically by passing into SetData,
/// key DamageVisualizerKeys.Disabled, value bool
/// (DamageVisualizerKeys lives in Content.Shared.Damage)
///
/// Damage layers, if targeting layers, can also be dynamically
/// disabled if needed by passing into SetData, the name/enum
/// of the sprite layer, and then passing in a bool value
/// (true to enable, false to disable).
/// Damage layers, if targeting layers, can also be dynamically
/// disabled if needed by passing into SetData, the name/enum
/// of the sprite layer, and then passing in a bool value
/// (true to enable, false to disable).
/// </summary>
public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponent>
{
@ -325,7 +325,7 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
}
/// <summary>
/// Adds a damage tracking layer to a given sprite component.
/// Adds a damage tracking layer to a given sprite component.
/// </summary>
private void AddDamageLayerToSprite(Entity<SpriteComponent?> spriteEnt, DamageVisualizerSprite sprite, string state, string mapKey, int? index = null)
{
@ -355,35 +355,34 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
// If this was passed into the component, we update
// the data to ensure that the current disabled
// bool matches.
if (AppearanceSystem.TryGetData<bool>(uid, DamageVisualizerKeys.Disabled, out var disabledStatus, args.Component))
if (args.TryGetData<bool>(DamageVisualizerKeys.Disabled, out var disabledStatus))
damageVisComp.Disabled = disabledStatus;
if (damageVisComp.Disabled)
return;
if (AppearanceSystem.TryGetData<string>(uid, DamageVisualizerKeys.Displacement, out var displacement, args.Component) &&
if (args.TryGetData<string>(DamageVisualizerKeys.Displacement, out var displacement) &&
ProtoMan.Resolve<DisplacementDataPrototype>(displacement, out var displacementProto))
damageVisComp.Displacement = displacementProto.Displacement;
else
damageVisComp.Displacement = null;
HandleDamage(uid, args.Component, damageVisComp);
HandleDamage(uid, args, damageVisComp);
}
private void HandleDamage(EntityUid uid, AppearanceComponent component, DamageVisualsComponent damageVisComp)
private void HandleDamage(EntityUid uid, AppearanceChangeEvent args, DamageVisualsComponent damageVisComp)
{
if (!TryComp(uid, out SpriteComponent? spriteComponent)
|| !TryComp(uid, out DamageableComponent? damageComponent))
return;
if (damageVisComp.TargetLayers != null && damageVisComp.DamageOverlayGroups != null)
UpdateDisabledLayers(uid, spriteComponent, component, damageVisComp);
UpdateDisabledLayers(uid, spriteComponent, args, damageVisComp);
if (damageVisComp.Overlay && damageVisComp.TargetLayers == null)
CheckOverlayOrdering((uid, spriteComponent), damageVisComp);
if (AppearanceSystem.TryGetData<bool>(uid, DamageVisualizerKeys.ForceUpdate, out var update, component)
&& update)
if (args.TryGetData<bool>(DamageVisualizerKeys.ForceUpdate, out var update) && update)
{
ForceUpdateLayers((uid, damageComponent, spriteComponent, damageVisComp));
return;
@ -395,8 +394,7 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
return;
}
if (!AppearanceSystem.TryGetData<DamageVisualizerGroupData>(uid, DamageVisualizerKeys.DamageUpdateGroups,
out var data, component))
if (!args.TryGetData<DamageVisualizerGroupData>(DamageVisualizerKeys.DamageUpdateGroups, out var data))
{
data = new DamageVisualizerGroupData(_damageable.GetDamagePerGroup(uid).Keys.ToList());
}
@ -405,18 +403,18 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
}
/// <summary>
/// Checks if any layers were disabled in the last
/// data update. Disabled layers mean that the
/// layer will no longer be visible, or obtain
/// any damage updates.
/// Checks if any layers were disabled in the last
/// data update. Disabled layers mean that the
/// layer will no longer be visible, or obtain
/// any damage updates.
/// </summary>
private void UpdateDisabledLayers(EntityUid uid, SpriteComponent spriteComponent, AppearanceComponent component, DamageVisualsComponent damageVisComp)
private void UpdateDisabledLayers(EntityUid uid, SpriteComponent spriteComponent, AppearanceChangeEvent args, DamageVisualsComponent damageVisComp)
{
foreach (var layer in damageVisComp.TargetLayerMapKeys)
{
// I assume this gets set by something like body system if limbs are missing???
// TODO is this actually used by anything anywhere?
AppearanceSystem.TryGetData(uid, layer, out bool disabled, component);
args.TryGetData(layer, out bool disabled);
if (damageVisComp.DisabledLayers[layer] == disabled)
continue;
@ -439,11 +437,11 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
}
/// <summary>
/// Checks the overlay ordering on the current
/// sprite component, compared to the
/// data for the visualizer. If the top
/// most layer doesn't match, the sprite
/// layers are recreated and placed on top.
/// Checks the overlay ordering on the current
/// sprite component, compared to the
/// data for the visualizer. If the top
/// most layer doesn't match, the sprite
/// layers are recreated and placed on top.
/// </summary>
private void CheckOverlayOrdering(Entity<SpriteComponent> spriteEnt, DamageVisualsComponent damageVisComp)
{
@ -494,8 +492,8 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
}
/// <summary>
/// Updates damage visuals without tracking
/// any damage groups.
/// Updates damage visuals without tracking
/// any damage groups.
/// </summary>
private void UpdateDamageVisuals(Entity<DamageableComponent, SpriteComponent, DamageVisualsComponent> entity)
{
@ -521,9 +519,9 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
}
/// <summary>
/// Updates damage visuals by damage group,
/// according to the list of damage groups
/// passed into it.
/// Updates damage visuals by damage group,
/// according to the list of damage groups
/// passed into it.
/// </summary>
private void UpdateDamageVisuals(List<ProtoId<DamageGroupPrototype>> delta, Entity<DamageableComponent, SpriteComponent, DamageVisualsComponent> entity)
{
@ -562,7 +560,7 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
}
/// <summary>
/// Checks if a threshold boundary was passed.
/// Checks if a threshold boundary was passed.
/// </summary>
private bool CheckThresholdBoundary(FixedPoint2 damageTotal, FixedPoint2 lastThreshold, DamageVisualsComponent damageVisComp, out FixedPoint2 threshold)
{
@ -587,10 +585,10 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
}
/// <summary>
/// This is the entry point for
/// forcing an update on all damage layers.
/// Does different things depending on
/// the configuration of the visualizer.
/// This is the entry point for
/// forcing an update on all damage layers.
/// Does different things depending on
/// the configuration of the visualizer.
/// </summary>
private void ForceUpdateLayers(Entity<DamageableComponent, SpriteComponent, DamageVisualsComponent> entity)
{
@ -611,9 +609,9 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
}
/// <summary>
/// Updates a target layer. Without a damage group passed in,
/// it assumes you're updating a layer that is tracking all
/// damage.
/// Updates a target layer. Without a damage group passed in,
/// it assumes you're updating a layer that is tracking all
/// damage.
/// </summary>
private void UpdateTargetLayer(Entity<SpriteComponent> spriteEnt, DamageVisualsComponent damageVisComp, object layerMapKey, FixedPoint2 threshold)
{
@ -647,7 +645,7 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
}
/// <summary>
/// Updates a target layer by damage group.
/// Updates a target layer by damage group.
/// </summary>
private void UpdateTargetLayer(Entity<SpriteComponent, DamageVisualsComponent> entity, object layerMapKey, string damageGroup, FixedPoint2 threshold)
{
@ -686,7 +684,7 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
}
/// <summary>
/// Updates an overlay that is tracking all damage.
/// Updates an overlay that is tracking all damage.
/// </summary>
private void UpdateOverlay(Entity<SpriteComponent> spriteEnt, FixedPoint2 threshold, DisplacementData? displacement = null)
{
@ -701,7 +699,7 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
}
/// <summary>
/// Updates an overlay based on damage group.
/// Updates an overlay based on damage group.
/// </summary>
private void UpdateOverlay(Entity<SpriteComponent, DamageVisualsComponent> entity, string damageGroup, FixedPoint2 threshold, DisplacementData? displacement = null)
{
@ -726,10 +724,10 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
}
/// <summary>
/// Updates a layer on the sprite by what
/// prefix it has (calculated by whatever
/// function calls it), and what threshold
/// was passed into it.
/// Updates a layer on the sprite by what
/// prefix it has (calculated by whatever
/// function calls it), and what threshold
/// was passed into it.
/// </summary>
private void UpdateDamageLayerState(Entity<SpriteComponent> spriteEnt, int spriteLayer, string statePrefix, FixedPoint2 threshold, string layerKey, DisplacementData? displacement)
{

View file

@ -254,8 +254,6 @@ public sealed partial class DamageOverlay : Overlay
handle.UseShader(_critShader);
handle.DrawRect(viewport, Color.White);
}
handle.UseShader(null);
}
private float GetDiff(float value, float lastFrameTime)

View file

@ -10,31 +10,27 @@ public sealed partial class DamageStateVisualizerSystem : VisualizerSystem<Damag
{
var sprite = args.Sprite;
if (sprite == null || !AppearanceSystem.TryGetData<MobState>(uid, MobStateVisuals.State, out var data, args.Component))
{
if (sprite == null || !args.TryGetData<MobState>(MobStateVisuals.State, out var data))
return;
}
if (!component.States.TryGetValue(data, out var layers))
{
return;
}
// Brain no worky rn so this was just easier.
foreach (var key in new[] { DamageStateVisualLayers.Base, DamageStateVisualLayers.BaseUnshaded })
{
if (!SpriteSystem.LayerMapTryGet((uid, sprite), key, out _, false)) continue;
if (!SpriteSystem.LayerMapTryGet((uid, sprite), key, out var layerIndex, false)) continue;
SpriteSystem.LayerSetVisible((uid, sprite), key, false);
SpriteSystem.LayerSetVisible((uid, sprite), layerIndex, false);
}
foreach (var (key, state) in layers)
{
// Inheritance moment.
if (!SpriteSystem.LayerMapTryGet((uid, sprite), key, out _, false)) continue;
if (!SpriteSystem.LayerMapTryGet((uid, sprite), key, out var layerIndex, false)) continue;
SpriteSystem.LayerSetVisible((uid, sprite), key, true);
SpriteSystem.LayerSetRsiState((uid, sprite), key, state);
SpriteSystem.LayerSetVisible((uid, sprite), layerIndex, true);
SpriteSystem.LayerSetRsiState((uid, sprite), layerIndex, state);
}
// So they don't draw over mobs anymore

View file

@ -115,8 +115,6 @@ namespace Content.Client.Decals.Overlays
else
handle.DrawTexture(cache.Texture, decal.Coordinates, angle, decal.Color);
}
handle.SetTransform(Matrix3x2.Identity);
}
private static int CompareDecalIndex(DecalIndex x, DecalIndex y)

View file

@ -64,6 +64,5 @@ public sealed partial class DecalPlacementOverlay : Overlay
var box = new Box2Rotated(aabb, rotation, localPos);
handle.DrawTextureRect(_sprite.Frame0(decal.Sprite), box, color);
handle.SetTransform(Matrix3x2.Identity);
}
}

View file

@ -7,8 +7,6 @@ namespace Content.Client.Delivery;
public sealed partial class DeliveryVisualizerSystem : VisualizerSystem<DeliveryComponent>
{
[Dependency] private SharedAppearanceSystem _appearance = default!;
private static readonly ProtoId<JobIconPrototype> UnknownIcon = "JobIconUnknown";
protected override void OnAppearanceChange(EntityUid uid, DeliveryComponent component, ref AppearanceChangeEvent args)
@ -16,7 +14,7 @@ public sealed partial class DeliveryVisualizerSystem : VisualizerSystem<Delivery
if (args.Sprite == null)
return;
_appearance.TryGetData(uid, DeliveryVisuals.JobIcon, out string job, args.Component);
args.TryGetData<string>(DeliveryVisuals.JobIcon, out var job);
if (string.IsNullOrEmpty(job))
job = UnknownIcon;

View file

@ -15,14 +15,6 @@ public sealed partial class DisposalUnitSystem : SharedDisposalUnitSystem
private const string AnimationKey = "disposal_unit_animation";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<DisposalUnitComponent, AfterAutoHandleStateEvent>(OnHandleState);
SubscribeLocalEvent<DisposalUnitComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
protected override void OnComponentInit(Entity<DisposalUnitComponent> ent, ref ComponentInit args)
{
base.OnComponentInit(ent, ref args);
@ -55,28 +47,19 @@ public sealed partial class DisposalUnitSystem : SharedDisposalUnitSystem
ent.Comp.FlushingAnimation = anim;
}
private void OnHandleState(EntityUid uid, DisposalUnitComponent component, ref AfterAutoHandleStateEvent args)
[SubscribeLocalEvent]
private void OnHandleState(Entity<DisposalUnitComponent> ent, ref AfterAutoHandleStateEvent args)
{
UpdateUI((uid, component));
UpdateUI(ent);
}
[SubscribeLocalEvent]
private void OnAppearanceChange(Entity<DisposalUnitComponent> ent, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
return;
UpdateState(ent, args.Sprite, args.Component);
}
/// <summary>
/// Updates the animation of a disposal unit.
/// </summary>
/// <param name="ent">The disposal unit.</param>
/// <param name="sprite">The disposal unit's sprite.</param>
/// <param name="appearance">The disposal unit's appearance.</param>
private void UpdateState(Entity<DisposalUnitComponent> ent, SpriteComponent sprite, AppearanceComponent appearance)
{
if (!_appearanceSystem.TryGetData<bool>(ent, DisposalUnitVisuals.IsFlushing, out var isFlushing, appearance))
if (!args.TryGetData<bool>(DisposalUnitVisuals.IsFlushing, out var isFlushing))
return;
// This is a transient state so not too worried about replaying in range.

View file

@ -19,7 +19,7 @@ public sealed class DoAfterOverlay : Overlay
private readonly IEntityManager _entManager;
private readonly IGameTiming _timing;
private readonly IPlayerManager _player;
private readonly SharedTransformSystem _transform;
private readonly TransformSystem _transform;
private readonly MetaDataSystem _meta;
private readonly ProgressColorSystem _progressColor;
private readonly SharedContainerSystem _container;
@ -53,7 +53,7 @@ public sealed class DoAfterOverlay : Overlay
_entManager = entManager;
_timing = timing;
_player = player;
_transform = _entManager.EntitySysManager.GetEntitySystem<SharedTransformSystem>();
_transform = _entManager.EntitySysManager.GetEntitySystem<TransformSystem>();
_meta = _entManager.EntitySysManager.GetEntitySystem<MetaDataSystem>();
_container = _entManager.EntitySysManager.GetEntitySystem<SharedContainerSystem>();
_progressColor = _entManager.System<ProgressColorSystem>();
@ -68,8 +68,6 @@ public sealed class DoAfterOverlay : Overlay
{
var handle = args.WorldHandle;
var rotation = args.Viewport.Eye?.Rotation ?? Angle.Zero;
var xformQuery = _entManager.GetEntityQuery<TransformComponent>();
// If you use the display UI scale then need to set max(1f, displayscale) because 0 is valid.
const float scale = 1f;
var scaleMatrix = Matrix3Helpers.CreateScale(new Vector2(scale, scale));
@ -90,7 +88,7 @@ public sealed class DoAfterOverlay : Overlay
if (comp.DoAfters.Count == 0)
continue;
var worldPosition = _transform.GetWorldPosition(xform, xformQuery);
var worldPosition = _transform.GetRenderWorldPosition((uid, xform));
if (!bounds.Contains(worldPosition))
continue;
@ -176,9 +174,6 @@ public sealed class DoAfterOverlay : Overlay
offset += _barTexture.Height / scale;
}
}
handle.UseShader(null);
handle.SetTransform(Matrix3x2.Identity);
}
public Color GetProgressColor(float progress, float alpha = 1f)

View file

@ -7,87 +7,82 @@ using Robust.Client.GameObjects;
namespace Content.Client.Doors;
/// <inheritdoc/>
public sealed partial class AirlockSystem : SharedAirlockSystem
{
[Dependency] private AppearanceSystem _appearanceSystem = default!;
[Dependency] private SpriteSystem _sprite = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<AirlockComponent, ComponentStartup>(OnComponentStartup);
SubscribeLocalEvent<AirlockComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
[Dependency] private EntityQuery<DoorComponent> _doorQuery;
private void OnComponentStartup(EntityUid uid, AirlockComponent comp, ComponentStartup args)
[SubscribeLocalEvent]
private void OnComponentStartup(Entity<AirlockComponent> ent, ref ComponentStartup args)
{
// Has to be on component startup because we don't know what order components initialize in and running this before DoorComponent inits _will_ crash.
if (!TryComp<DoorComponent>(uid, out var door))
if (!_doorQuery.TryComp(ent, out var door))
return;
if (comp.OpenUnlitVisible) // Otherwise there are flashes of the fallback sprite between clicking on the door and the door closing animation starting.
if (ent.Comp.OpenUnlitVisible) // Otherwise there are flashes of the fallback sprite between clicking on the door and the door closing animation starting.
{
door.OpenSpriteStates.Add((DoorVisualLayers.BaseUnlit, comp.OpenSpriteState));
door.ClosedSpriteStates.Add((DoorVisualLayers.BaseUnlit, comp.ClosedSpriteState));
door.OpenSpriteStates.Add((DoorVisualLayers.BaseUnlit, ent.Comp.OpenSpriteState));
door.ClosedSpriteStates.Add((DoorVisualLayers.BaseUnlit, ent.Comp.ClosedSpriteState));
}
((Animation)door.OpeningAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick()
((Animation)door.OpeningAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick
{
LayerKey = DoorVisualLayers.BaseUnlit,
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.OpeningSpriteState, 0f) },
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(ent.Comp.OpeningSpriteState, 0f) },
}
);
((Animation)door.ClosingAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick()
((Animation)door.ClosingAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick
{
LayerKey = DoorVisualLayers.BaseUnlit,
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.ClosingSpriteState, 0f) },
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(ent.Comp.ClosingSpriteState, 0f) },
}
);
door.DenyingAnimation = new Animation()
door.DenyingAnimation = new Animation
{
Length = TimeSpan.FromSeconds(comp.DenyAnimationTime),
Length = TimeSpan.FromSeconds(ent.Comp.DenyAnimationTime),
AnimationTracks =
{
new AnimationTrackSpriteFlick()
new AnimationTrackSpriteFlick
{
LayerKey = DoorVisualLayers.BaseUnlit,
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.DenySpriteState, 0f) },
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(ent.Comp.DenySpriteState, 0f) },
}
}
};
if (!comp.AnimatePanel)
if (!ent.Comp.AnimatePanel)
return;
// For some reason the open panel sprite is used for both open and
// closed sprites. I really don't get it.
door.OpenSpriteStates.Add((WiresVisualLayers.MaintenancePanel, comp.OpenPanelSpriteState));
door.ClosedSpriteStates.Add((WiresVisualLayers.MaintenancePanel, comp.OpenPanelSpriteState));
door.OpenSpriteStates.Add((WiresVisualLayers.MaintenancePanel, null));
door.ClosedSpriteStates.Add((WiresVisualLayers.MaintenancePanel, ent.Comp.OpenPanelSpriteState));
((Animation)door.OpeningAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick()
((Animation)door.OpeningAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick
{
LayerKey = WiresVisualLayers.MaintenancePanel,
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.OpeningPanelSpriteState, 0f) },
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(ent.Comp.OpeningPanelSpriteState, 0f) },
});
((Animation)door.ClosingAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick
{
LayerKey = WiresVisualLayers.MaintenancePanel,
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.ClosingPanelSpriteState, 0f) },
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(ent.Comp.ClosingPanelSpriteState, 0f) },
});
}
private void OnAppearanceChange(EntityUid uid, AirlockComponent comp, ref AppearanceChangeEvent args)
[SubscribeLocalEvent]
private void OnAppearanceChange(Entity<AirlockComponent> ent, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
return;
if (!_appearanceSystem.TryGetData<DoorState>(uid, DoorVisuals.State, out var state, args.Component))
if (!args.TryGetData<DoorState>(DoorVisuals.State, out var state))
state = DoorState.Closed;
_appearanceSystem.TryGetData<bool>(uid, PowerDeviceVisuals.Powered, out var hasPower, args.Component);
args.TryGetData<bool>(PowerDeviceVisuals.Powered, out var hasPower);
var showBaseUnlit = false;
var showBolted = false;
@ -95,10 +90,10 @@ public sealed partial class AirlockSystem : SharedAirlockSystem
if (hasPower)
{
_appearanceSystem.TryGetData<bool>(uid, DoorVisuals.BoltLights, out var boltedVisible, args.Component);
args.TryGetData<bool>(DoorVisuals.BoltLights, out var boltedVisible);
showBolted = boltedVisible && (state == DoorState.Closed || state == DoorState.Welded);
_appearanceSystem.TryGetData<bool>(uid, DoorVisuals.EmergencyLights, out var emergencyVisible, args.Component);
args.TryGetData<bool>(DoorVisuals.EmergencyLights, out var emergencyVisible);
showEmergency = emergencyVisible;
if (!showBolted && !showEmergency)
@ -106,33 +101,33 @@ public sealed partial class AirlockSystem : SharedAirlockSystem
if (state == DoorState.Closing || state == DoorState.Opening || state == DoorState.Denying || state == DoorState.Closed)
showBaseUnlit = true;
if (state == DoorState.Open && comp.OpenUnlitVisible)
if (state == DoorState.Open && ent.Comp.OpenUnlitVisible)
showBaseUnlit = true;
_appearanceSystem.TryGetData<bool>(uid, DoorVisuals.ClosedLights, out var closedLightsVisible, args.Component);
args.TryGetData<bool>(DoorVisuals.ClosedLights, out var closedLightsVisible);
if (state == DoorState.Closed && closedLightsVisible)
showBaseUnlit = true;
}
}
_sprite.LayerSetVisible((uid, args.Sprite), DoorVisualLayers.BaseUnlit, showBaseUnlit);
_sprite.LayerSetVisible((uid, args.Sprite), DoorVisualLayers.BaseBolted, showBolted);
if (comp.EmergencyAccessLayer)
_sprite.LayerSetVisible((ent, args.Sprite), DoorVisualLayers.BaseUnlit, showBaseUnlit);
_sprite.LayerSetVisible((ent, args.Sprite), DoorVisualLayers.BaseBolted, showBolted);
if (ent.Comp.EmergencyAccessLayer)
{
var isDoorIdle = state != DoorState.Open && state != DoorState.Opening && state != DoorState.Closing;
_sprite.LayerSetVisible((uid, args.Sprite), DoorVisualLayers.BaseEmergencyAccess,
_sprite.LayerSetVisible((ent, args.Sprite), DoorVisualLayers.BaseEmergencyAccess,
showEmergency && isDoorIdle && !showBolted);
}
if (comp.OpenUnlitVisible)
if (ent.Comp.OpenUnlitVisible)
{
switch (state)
{
case DoorState.Open:
_sprite.LayerSetRsiState((uid, args.Sprite), DoorVisualLayers.BaseUnlit, comp.OpenSpriteState);
_sprite.LayerSetRsiState((ent, args.Sprite), DoorVisualLayers.BaseUnlit, ent.Comp.OpenSpriteState);
break;
case DoorState.Closed:
_sprite.LayerSetRsiState((uid, args.Sprite), DoorVisualLayers.BaseUnlit, comp.ClosedSpriteState);
_sprite.LayerSetRsiState((ent, args.Sprite), DoorVisualLayers.BaseUnlit, ent.Comp.ClosedSpriteState);
break;
}
}

View file

@ -6,23 +6,19 @@ using Robust.Client.GameObjects;
namespace Content.Client.Doors;
/// <inheritdoc/>
public sealed partial class DoorSystem : SharedDoorSystem
{
[Dependency] private AnimationPlayerSystem _animationSystem = default!;
[Dependency] private SpriteSystem _sprite = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<DoorComponent, AppearanceChangeEvent>(OnAppearanceChange);
SubscribeLocalEvent<DoorComponent, AnimationCompletedEvent>(OnAnimationCompleted);
}
/// <inheritdoc/>
protected override void OnComponentInit(Entity<DoorComponent> ent, ref ComponentInit args)
{
// Base call deferred until end of function.
var comp = ent.Comp;
comp.OpenSpriteStates = new List<(Enum, string)>(2);
comp.ClosedSpriteStates = new List<(Enum, string)>(2);
comp.OpenSpriteStates = new(2);
comp.ClosedSpriteStates = new(2);
comp.OpenSpriteStates.Add((DoorVisualLayers.Base, comp.OpenSpriteState));
comp.ClosedSpriteStates.Add((DoorVisualLayers.Base, comp.ClosedSpriteState));
@ -74,8 +70,11 @@ public sealed partial class DoorSystem : SharedDoorSystem
},
},
};
base.OnComponentInit(ent, ref args);
}
[SubscribeLocalEvent]
private void OnAnimationCompleted(Entity<DoorComponent> ent, ref AnimationCompletedEvent args)
{
if (args.Key != DoorComponent.OpenKey && args.Key != DoorComponent.CloseKey)
@ -105,20 +104,20 @@ public sealed partial class DoorSystem : SharedDoorSystem
}
}
[SubscribeLocalEvent]
private void OnAppearanceChange(Entity<DoorComponent> entity, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
return;
if (!AppearanceSystem.TryGetData<DoorState>(entity, DoorVisuals.State, out var state, args.Component))
if (!args.TryGetData<DoorState>(DoorVisuals.State, out var state))
state = DoorState.Closed;
if (AppearanceSystem.TryGetData<string>(entity, PaintableVisuals.Prototype, out var prototype, args.Component))
if (args.TryGetData<string>(PaintableVisuals.Prototype, out var prototype))
UpdateSpriteLayers((entity.Owner, args.Sprite), prototype);
// We are checking beforehand since some doors may not have an emagging visual layer, and we don't want LayerSetVisible to throw an error.
if (_sprite.TryGetLayer(entity.Owner, DoorVisualLayers.BaseEmagging, out var _, false))
_sprite.LayerSetVisible(entity.Owner, DoorVisualLayers.BaseEmagging, state == DoorState.Emagging);
if (_sprite.LayerMapTryGet(entity.Owner, DoorVisualLayers.BaseEmagging, out var emaggingLayer, logMissing: false))
_sprite.LayerSetVisible(entity.Owner, emaggingLayer, state == DoorState.Emagging);
UpdateAppearanceForDoorState(entity, args.Sprite, state);
}

View file

@ -1,3 +1,4 @@
using Content.Client.Wires.Visualizers;
using Content.Shared.Doors.Components;
using Content.Shared.Doors.Systems;
using Robust.Client.Animations;
@ -5,60 +6,103 @@ using Robust.Client.GameObjects;
namespace Content.Client.Doors;
// TODO: Consolidate redundant code from the AirlockSystem.
/// <inheritdoc/>
public sealed partial class FirelockSystem : SharedFirelockSystem
{
[Dependency] private SharedAppearanceSystem _appearanceSystem = default!;
[Dependency] private SpriteSystem _sprite = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<FirelockComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
[Dependency] private EntityQuery<DoorComponent> _doorQuery;
/// <inheritdoc/>
protected override void OnComponentStartup(Entity<FirelockComponent> ent, ref ComponentStartup args)
{
base.OnComponentStartup(ent, ref args);
if (!TryComp<DoorComponent>(ent.Owner, out var door))
if (!_doorQuery.TryComp(ent.Owner, out var door))
return;
door.ClosedSpriteStates.Add((DoorVisualLayers.BaseUnlit, ent.Comp.WarningLightSpriteState));
door.OpenSpriteStates.Add((DoorVisualLayers.BaseUnlit, ent.Comp.WarningLightSpriteState));
// Add animations if we have an unlit layer.
if (_sprite.LayerMapTryGet(ent.Owner, DoorVisualLayers.BaseUnlit, out _, logMissing: false))
{
door.ClosedSpriteStates.Add((DoorVisualLayers.BaseUnlit, ent.Comp.WarningLightSpriteState));
door.OpenSpriteStates.Add((DoorVisualLayers.BaseUnlit, ent.Comp.WarningLightSpriteState));
((Animation)door.OpeningAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick()
{
LayerKey = DoorVisualLayers.BaseUnlit,
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(ent.Comp.OpeningLightSpriteState, 0f) },
}
);
((Animation)door.OpeningAnimation).AnimationTracks.Add(
new AnimationTrackSpriteFlick
{
LayerKey = DoorVisualLayers.BaseUnlit,
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(ent.Comp.OpeningLightSpriteState, 0f) },
}
);
((Animation)door.ClosingAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick()
{
LayerKey = DoorVisualLayers.BaseUnlit,
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(ent.Comp.ClosingLightSpriteState, 0f) },
}
);
((Animation)door.ClosingAnimation).AnimationTracks.Add(
new AnimationTrackSpriteFlick
{
LayerKey = DoorVisualLayers.BaseUnlit,
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(ent.Comp.ClosingLightSpriteState, 0f) },
}
);
}
if (!ent.Comp.AnimatePanel)
return;
door.OpenSpriteStates.Add((WiresVisualLayers.MaintenancePanel, null));
door.ClosedSpriteStates.Add((WiresVisualLayers.MaintenancePanel, ent.Comp.OpenPanelSpriteState));
((Animation)door.OpeningAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick
{
LayerKey = WiresVisualLayers.MaintenancePanel,
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(ent.Comp.OpeningPanelSpriteState, 0f) },
});
((Animation)door.ClosingAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick
{
LayerKey = WiresVisualLayers.MaintenancePanel,
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(ent.Comp.ClosingPanelSpriteState, 0f) },
});
}
private void OnAppearanceChange(EntityUid uid, FirelockComponent comp, ref AppearanceChangeEvent args)
[SubscribeLocalEvent]
private void OnAppearanceChange(Entity<FirelockComponent> ent, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
return;
var boltedVisible = false;
var unlitVisible = false;
if (!_appearanceSystem.TryGetData<DoorState>(uid, DoorVisuals.State, out var state, args.Component))
if (!args.TryGetData<DoorState>(DoorVisuals.State, out var state))
state = DoorState.Closed;
boltedVisible = _appearanceSystem.TryGetData<bool>(uid, DoorVisuals.BoltLights, out var lights, args.Component) && lights;
unlitVisible =
var boltedVisible = args.TryGetData<bool>(DoorVisuals.BoltLights, out var lights) && lights;
var unlitVisible =
state == DoorState.Closing
|| state == DoorState.Opening
|| state == DoorState.Denying
|| (_appearanceSystem.TryGetData<bool>(uid, DoorVisuals.ClosedLights, out var closedLights, args.Component) && closedLights);
|| state == DoorState.Opening
|| state == DoorState.Denying
|| args.TryGetData<bool>(DoorVisuals.ClosedLights, out var closedLights) && closedLights;
_sprite.LayerSetVisible((uid, args.Sprite), DoorVisualLayers.BaseUnlit, unlitVisible && !boltedVisible);
_sprite.LayerSetVisible((uid, args.Sprite), DoorVisualLayers.BaseBolted, boltedVisible);
if (_sprite.LayerMapTryGet((ent, args.Sprite), DoorVisualLayers.BaseUnlit, out var unlitLayer, logMissing: false))
_sprite.LayerSetVisible((ent, args.Sprite), unlitLayer, unlitVisible && !boltedVisible);
if (_sprite.LayerMapTryGet((ent, args.Sprite), DoorVisualLayers.BaseBolted, out var boltedLayer, logMissing: false))
_sprite.LayerSetVisible((ent, args.Sprite), boltedLayer, boltedVisible);
var warningLightsVisible =
state == DoorState.Closed
|| state == DoorState.Welded
|| state == DoorState.Denying;
if (_sprite.LayerMapTryGet((ent, args.Sprite), FirelockVisualLayersPressure.Base, out var pressureLayerIndex, logMissing: false))
{
if (!args.TryGetData<bool>(FirelockVisuals.PressureWarning, out var pressure))
pressure = false;
_sprite.LayerSetVisible((ent, args.Sprite), pressureLayerIndex, pressure && warningLightsVisible);
}
if (_sprite.LayerMapTryGet((ent, args.Sprite), FirelockVisualLayersTemperature.Base, out var tempLayerIndex, logMissing: false))
{
if (!args.TryGetData<bool>(FirelockVisuals.TemperatureWarning, out var temp))
temp = false;
_sprite.LayerSetVisible((ent, args.Sprite), tempLayerIndex, temp && warningLightsVisible);
}
}
}

View file

@ -75,6 +75,5 @@ public sealed partial class DrowsinessOverlay : Overlay
_drowsinessShader.SetParameter("Strength", _visualScale * Intensity);
handle.UseShader(_drowsinessShader);
handle.DrawRect(args.WorldBounds, Color.White);
handle.UseShader(null);
}
}

View file

@ -101,6 +101,5 @@ public sealed partial class RainbowOverlay : Overlay
_rainbowShader.SetParameter("phase", Phase);
handle.UseShader(_rainbowShader);
handle.DrawRect(args.WorldBounds, Color.White);
handle.UseShader(null);
}
}

View file

@ -103,7 +103,6 @@ public sealed partial class DrunkOverlay : Overlay
_drunkShader.SetParameter("phase", Phase);
handle.UseShader(_drunkShader);
handle.DrawRect(args.WorldBounds, Color.White);
handle.UseShader(null);
}
/// <summary>

View file

@ -79,7 +79,7 @@ public sealed partial class ElectrocutionHUDVisualizerSystem : VisualizerSystem<
if (args.Sprite == null)
return;
if (!AppearanceSystem.TryGetData<bool>(uid, ElectrifiedVisuals.IsElectrified, out var electrified, args.Component))
if (!args.TryGetData<bool>(ElectrifiedVisuals.IsElectrified, out var electrified))
return;
var player = _playerMan.LocalEntity;

View file

@ -30,18 +30,18 @@ public sealed partial class EnsnareableSystem : SharedEnsnareableSystem
private void OnAppearanceChange(EntityUid uid, EnsnareableComponent component, ref AppearanceChangeEvent args)
{
if (component.Sprite == null)
return;
if (args.Sprite == null || !_sprite.LayerMapTryGet((uid, args.Sprite), EnsnaredVisualLayers.Ensnared, out var layer, false))
return;
if (_appearance.TryGetData<bool>(uid, EnsnareableVisuals.IsEnsnared, out var isEnsnared, args.Component))
{
if (component.Sprite != null)
{
_sprite.LayerSetRsi((uid, args.Sprite), layer, new ResPath(component.Sprite));
_sprite.LayerSetRsiState((uid, args.Sprite), layer, component.State);
_sprite.LayerSetVisible((uid, args.Sprite), layer, isEnsnared);
}
}
if (!args.TryGetData<bool>(EnsnareableVisuals.IsEnsnared, out var isEnsnared))
return;
_sprite.LayerSetRsi((uid, args.Sprite), layer, new ResPath(component.Sprite));
_sprite.LayerSetRsiState((uid, args.Sprite), layer, component.State);
_sprite.LayerSetVisible((uid, args.Sprite), layer, isEnsnared);
}
}

View file

@ -1,4 +1,3 @@
using Content.Shared.Explosion;
using Content.Shared.Explosion.Components;
using Robust.Client.GameObjects;
@ -11,7 +10,7 @@ public sealed partial class ClusterGrenadeVisualizerSystem : VisualizerSystem<Cl
if (args.Sprite == null)
return;
if (AppearanceSystem.TryGetData<int>(uid, ClusterGrenadeVisuals.GrenadesCounter, out var grenadesCounter, args.Component))
if (args.TryGetData<int>(ClusterGrenadeVisuals.GrenadesCounter, out var grenadesCounter))
SpriteSystem.LayerSetRsiState((uid, args.Sprite), 0, $"{comp.State}-{grenadesCounter}");
}
}

View file

@ -52,9 +52,6 @@ public sealed partial class ExplosionOverlay : Overlay
index = Math.Min(index, visuals.Intensity.Count - 1);
DrawExplosion(drawHandle, args.WorldBounds, visuals, index, xforms, textures);
}
drawHandle.SetTransform(Matrix3x2.Identity);
drawHandle.UseShader(null);
}
private void DrawExplosion(

View file

@ -96,7 +96,6 @@ namespace Content.Client.Eye.Blinding
worldHandle.DrawRect(viewport, Color.White);
worldHandle.UseShader(_circleMaskShader);
worldHandle.DrawRect(viewport, Color.White);
worldHandle.UseShader(null);
}
}
}

View file

@ -100,7 +100,6 @@ namespace Content.Client.Eye.Blinding
worldHandle.UseShader(_circleMaskShader);
worldHandle.DrawRect(viewport, Color.White);
worldHandle.UseShader(null);
return;
}
@ -114,7 +113,6 @@ namespace Content.Client.Eye.Blinding
worldHandle.UseShader(_cataractsShader);
worldHandle.DrawRect(viewport, Color.White);
worldHandle.UseShader(null);
}
}
}

View file

@ -11,15 +11,8 @@ namespace Content.Client.Fax.System;
public sealed partial class FaxVisualsSystem : EntitySystem
{
[Dependency] private AnimationPlayerSystem _player = default!;
[Dependency] private SharedAppearanceSystem _appearance = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<FaxMachineComponent, AppearanceChangeEvent>(OnAppearanceChanged);
}
[SubscribeLocalEvent]
private void OnAppearanceChanged(EntityUid uid, FaxMachineComponent component, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
@ -28,26 +21,26 @@ public sealed partial class FaxVisualsSystem : EntitySystem
if (_player.HasRunningAnimation(uid, "faxecute"))
return;
if (_appearance.TryGetData(uid, FaxMachineVisuals.VisualState, out FaxMachineVisualState visuals) &&
visuals == FaxMachineVisualState.Inserting)
{
_player.Play(uid,
new Animation()
if (!args.TryGetData(FaxMachineVisuals.VisualState, out FaxMachineVisualState visuals)
|| visuals != FaxMachineVisualState.Inserting)
return;
_player.Play(uid,
new Animation()
{
Length = TimeSpan.FromSeconds(2.4),
AnimationTracks =
{
Length = TimeSpan.FromSeconds(2.4),
AnimationTracks =
new AnimationTrackSpriteFlick()
{
new AnimationTrackSpriteFlick()
LayerKey = FaxMachineVisuals.VisualState,
KeyFrames =
{
LayerKey = FaxMachineVisuals.VisualState,
KeyFrames =
{
new AnimationTrackSpriteFlick.KeyFrame(component.InsertingState, 0f)
},
new AnimationTrackSpriteFlick.KeyFrame(component.InsertingState, 0f)
},
},
},
"faxecute");
}
},
"faxecute");
}
}

View file

@ -96,7 +96,6 @@ public sealed partial class FlashOverlay : Overlay
_shader.SetParameter("percentComplete", PercentComplete);
worldHandle.UseShader(_shader);
worldHandle.DrawTextureRectRegion(ScreenshotTexture, args.WorldBounds);
worldHandle.UseShader(null);
}
}

View file

@ -75,8 +75,6 @@ public sealed partial class PuddleOverlay : Overlay
drawHandle.DrawRect(box, ColorMap(debugOverlayData.CurrentVolume));
}
}
drawHandle.SetTransform(Matrix3x2.Identity);
}
private void DrawScreen(in OverlayDrawArgs args)

View file

@ -24,12 +24,8 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
if (args.Sprite == null)
return;
var volume = 1f;
if (args.AppearanceData.TryGetValue(PuddleVisuals.CurrentVolume, out var volumeObj))
{
volume = (float)volumeObj;
}
if (!args.TryGetData<float>(PuddleVisuals.CurrentVolume, out var volume))
volume = 1.0f;
// Update smoothing and sprite based on volume.
if (TryComp<IconSmoothComponent>(uid, out var smooth))
@ -57,15 +53,10 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
var baseColor = Color.White;
if (args.AppearanceData.TryGetValue(PuddleVisuals.SolutionColor, out var colorObj))
{
var color = (Color)colorObj;
_sprite.SetColor((uid, args.Sprite), color * baseColor);
}
else
{
_sprite.SetColor((uid, args.Sprite), args.Sprite.Color * baseColor);
}
if (!args.TryGetData<Color>(PuddleVisuals.SolutionColor, out var color))
color = args.Sprite.Color;
_sprite.SetColor((uid, args.Sprite), color * baseColor);
}
#region Spill

View file

@ -24,7 +24,7 @@ public sealed partial class GravitySystem : SharedGravitySystem
if (args.Sprite == null)
return;
if (_appearanceSystem.TryGetData<PowerChargeStatus>(uid, PowerChargeVisuals.State, out var state, args.Component))
if (args.TryGetData<PowerChargeStatus>(PowerChargeVisuals.State, out var state))
{
if (comp.SpriteMap.TryGetValue(state, out var spriteState))
{
@ -33,7 +33,7 @@ public sealed partial class GravitySystem : SharedGravitySystem
}
}
if (_appearanceSystem.TryGetData<float>(uid, PowerChargeVisuals.Charge, out var charge, args.Component))
if (args.TryGetData<float>(PowerChargeVisuals.Charge, out var charge))
{
var layer = _sprite.LayerMapGet((uid, args.Sprite), GravityGeneratorVisualLayers.Core);
switch (charge)

View file

@ -39,10 +39,10 @@ public sealed partial class GuideMicrowaveEmbed : PanelContainer, IDocumentTag,
public GuideMicrowaveEmbed(string recipe) : this()
{
GenerateControl(_prototype.Index<FoodRecipePrototype>(recipe));
GenerateControl(_prototype.Index<MicrowaveMealRecipePrototype>(recipe));
}
public GuideMicrowaveEmbed(FoodRecipePrototype recipe) : this()
public GuideMicrowaveEmbed(MicrowaveMealRecipePrototype recipe) : this()
{
GenerateControl(recipe);
}
@ -66,7 +66,7 @@ public sealed partial class GuideMicrowaveEmbed : PanelContainer, IDocumentTag,
return false;
}
if (!_prototype.TryIndex<FoodRecipePrototype>(id, out var recipe))
if (!_prototype.TryIndex<MicrowaveMealRecipePrototype>(id, out var recipe))
{
_sawmill.Error($"Specified recipe prototype \"{id}\" is not a valid recipe prototype");
return false;
@ -78,7 +78,7 @@ public sealed partial class GuideMicrowaveEmbed : PanelContainer, IDocumentTag,
return true;
}
private void GenerateHeader(FoodRecipePrototype recipe)
private void GenerateHeader(MicrowaveMealRecipePrototype recipe)
{
var entity = _prototype.Index<EntityPrototype>(recipe.Result);
@ -89,9 +89,9 @@ public sealed partial class GuideMicrowaveEmbed : PanelContainer, IDocumentTag,
ResultDescription.SetMarkup(entity.Description);
}
private void GenerateSolidIngredients(FoodRecipePrototype recipe)
private void GenerateSolidIngredients(MicrowaveMealRecipePrototype recipe)
{
foreach (var (product, amount) in recipe.IngredientsSolids.OrderByDescending(p => p.Value))
foreach (var (product, amount) in recipe.Ingredients.Solids.OrderByDescending(p => p.Value))
{
var ingredient = _prototype.Index<EntityPrototype>(product);
@ -122,9 +122,9 @@ public sealed partial class GuideMicrowaveEmbed : PanelContainer, IDocumentTag,
}
}
private void GenerateLiquidIngredients(FoodRecipePrototype recipe)
private void GenerateLiquidIngredients(MicrowaveMealRecipePrototype recipe)
{
foreach (var (product, amount) in recipe.IngredientsReagents.OrderByDescending(p => p.Value))
foreach (var (product, amount) in recipe.Ingredients.Reagents.OrderByDescending(p => p.Value))
{
var reagent = _prototype.Index<ReagentPrototype>(product);
@ -165,22 +165,58 @@ public sealed partial class GuideMicrowaveEmbed : PanelContainer, IDocumentTag,
}
}
private void GenerateIngredients(FoodRecipePrototype recipe)
private void GenerateStackIngredients(MicrowaveMealRecipePrototype recipe)
{
foreach (var (product, amount) in recipe.Ingredients.Stacks.OrderByDescending(p => p.Value))
{
var stack = _prototype.Index(product);
// stack icon
IngredientsGrid.AddChild(new GuideEntityEmbed(stack.Spawn, false, false));
// stack name
var stackName = Loc.GetString(stack.Name);
var stackNameMsg = new FormattedMessage();
stackNameMsg.AddMarkupOrThrow(Loc.GetString("guidebook-microwave-stack-name-display", ("stack", stackName)));
stackNameMsg.Pop();
var stackNameLabel = new RichTextLabel();
stackNameLabel.SetMessage(stackNameMsg);
IngredientsGrid.AddChild(stackNameLabel);
// stack quantity
var stackQuantityMsg = new FormattedMessage();
stackQuantityMsg.AddMarkupOrThrow(Loc.GetString("guidebook-microwave-stack-quantity-display", ("amount", amount)));
stackQuantityMsg.Pop();
var stackQuantityLabel = new RichTextLabel();
stackQuantityLabel.SetMessage(stackQuantityMsg);
IngredientsGrid.AddChild(stackQuantityLabel);
}
}
private void GenerateIngredients(MicrowaveMealRecipePrototype recipe)
{
GenerateLiquidIngredients(recipe);
GenerateStackIngredients(recipe);
GenerateSolidIngredients(recipe);
}
private void GenerateCookTime(FoodRecipePrototype recipe)
private void GenerateCookTime(MicrowaveMealRecipePrototype recipe)
{
var msg = new FormattedMessage();
msg.AddMarkupOrThrow(Loc.GetString("guidebook-microwave-cook-time", ("time", recipe.CookTime)));
msg.AddMarkupOrThrow(Loc.GetString("guidebook-microwave-cook-time", ("time", recipe.Time)));
msg.Pop();
CookTimeLabel.SetMessage(msg);
}
private void GenerateControl(FoodRecipePrototype recipe)
private void GenerateControl(MicrowaveMealRecipePrototype recipe)
{
GenerateHeader(recipe);
GenerateIngredients(recipe);

View file

@ -50,7 +50,7 @@ public sealed partial class GuideMicrowaveGroupEmbed : BoxContainer, IDocumentTa
private void CreateEntries(string group)
{
var prototypes = _prototype.EnumeratePrototypes<FoodRecipePrototype>()
var prototypes = _prototype.EnumeratePrototypes<MicrowaveMealRecipePrototype>()
.Where(p => p.Group.Equals(group))
.OrderBy(p => p.Name);

View file

@ -29,6 +29,7 @@ namespace Content.Client.Hands.Systems
[Dependency] private StrippableSystem _stripSys = default!;
[Dependency] private SpriteSystem _sprite = default!;
[Dependency] private TransformSystem _renderTransforms = default!;
[Dependency] private ExamineSystem _examine = default!;
[Dependency] private DisplacementMapSystem _displacement = default!;
@ -112,9 +113,15 @@ namespace Content.Client.Hands.Systems
EntityCoordinates? targetDropLocation = null
)
{
TryGetHeldItem(ent, handId, out var held);
base.DoDrop(ent, handId, doDropInteraction, log, targetDropLocation);
if (TryGetHeldItem(ent, handId, out var held) && TryComp(held, out SpriteComponent? sprite))
if (held == null || IsHolding(ent, held.Value))
return;
_renderTransforms.SnapRenderTransform(held.Value, true);
if (TryComp(held, out SpriteComponent? sprite))
sprite.RenderOrder = EntityManager.CurrentTick.Value;
}

View file

@ -21,7 +21,7 @@ public sealed partial class HolidaySystem : EntitySystem
private void OnAppearanceChange(Entity<HolidayRsiSwapComponent> ent, ref AppearanceChangeEvent args)
{
if (!_appearance.TryGetData<string>(ent, HolidayVisuals.Holiday, out var data, args.Component))
if (!args.TryGetData<string>(HolidayVisuals.Holiday, out var data))
return;
var comp = ent.Comp;

View file

@ -1,9 +1,7 @@
using System.Linq;
using Content.Shared.Body;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
@ -14,9 +12,7 @@ namespace Content.Client.Humanoid;
public sealed partial class OrganMarkingPicker : Control
{
[Dependency] private MarkingManager _marking = default!;
[Dependency] private IEntityManager _entity = default!;
private readonly SpriteSystem _sprite;
[Dependency] private ILocalizationManager _loc = default!;
private readonly MarkingsViewModel _markingsModel;
private readonly HashSet<HumanoidVisualLayers> _layers;
@ -33,8 +29,6 @@ public sealed partial class OrganMarkingPicker : Control
_group = group;
_organ = organ;
_sprite = _entity.System<SpriteSystem>();
UpdateMarkings();
}
@ -79,10 +73,10 @@ public sealed partial class OrganMarkingPicker : Control
var control = new LayerMarkingPicker(_markingsModel, _organ, layer, allMarkings);
LayerTabs.AddChild(control);
if (Loc.TryGetString($"markings-layer-{layer}-{_group.Id}", out var layerTitle))
if (_loc.TryGetString($"markings-layer-{layer}-{_group.Id}", out var layerTitle))
LayerTabs.SetTabTitle(i, layerTitle);
else
LayerTabs.SetTabTitle(i, Loc.GetString($"markings-layer-{layer}"));
LayerTabs.SetTabTitle(i, _loc.GetString($"markings-layer-{layer}"));
i++;
}

View file

@ -6,21 +6,14 @@ namespace Content.Client.IconSmoothing;
public sealed partial class ClientRandomIconSmoothSystem : SharedRandomIconSmoothSystem
{
[Dependency] private IconSmoothSystem _iconSmooth = default!;
[Dependency] private AppearanceSystem _appearance = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RandomIconSmoothComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
[SubscribeLocalEvent]
private void OnAppearanceChange(Entity<RandomIconSmoothComponent> ent, ref AppearanceChangeEvent args)
{
if (!TryComp<IconSmoothComponent>(ent, out var smooth))
return;
if (!_appearance.TryGetData<string>(ent, RandomIconSmoothState.State, out var state, args.Component))
if (!args.TryGetData<string>(RandomIconSmoothState.State, out var state))
return;
smooth.StateBase = state;

View file

@ -1,9 +1,24 @@
using System.Numerics;
using Content.Shared.Interaction;
using Content.Shared.Storage;
using Robust.Client.GameObjects;
using Robust.Shared.Containers;
namespace Content.Client.Interactable
{
// TODO Remove Shared prefix
public sealed partial class InteractionSystem : SharedInteractionSystem;
public sealed partial class InteractionSystem : SharedInteractionSystem
{
[Dependency] private TransformSystem _clientTransform = default!;
protected override bool TryFaceInteraction(EntityUid user, Vector2 coordinates)
{
var faced = base.TryFaceInteraction(user, coordinates);
if (faced)
_clientTransform.SnapRenderRotation(user);
return faced;
}
}
}

View file

@ -0,0 +1,52 @@
using Content.Shared.Kitchen.Components;
using Content.Shared.Kitchen.EntitySystems;
using Robust.Client.Player;
namespace Content.Client.Kitchen.EntitySystems;
/// <inheritdoc />
public sealed partial class ClientMicrowaveSystem : MicrowaveSystem
{
[Dependency] private IPlayerManager _player = default!;
[Dependency] private SharedUserInterfaceSystem _userInterface = default!;
public override void UpdateUI(Entity<MicrowaveComponent?> microwave)
{
base.UpdateUI(microwave);
if (!MicrowaveQuery.Resolve(microwave.Owner, ref microwave.Comp))
return;
if (_userInterface.TryGetOpenUi(microwave.Owner, MicrowaveUiKey.Key, out var bui))
bui.Update();
}
protected override void ActivateMicrowaveCycle(Entity<MicrowaveComponent> ent)
{
base.ActivateMicrowaveCycle(ent);
if (!Timing.IsFirstTimePredicted)
return;
var audioParams = ent.Comp.LoopingSound.Params;
audioParams = audioParams.WithLoop(true).WithMaxDistance(5);
ent.Comp.PlayingStream ??= Audio.PlayLocal(ent.Comp.LoopingSound, ent, _player.LocalEntity, audioParams)?.Entity;
}
protected override void DeactivateMicrowaveCycle(Entity<MicrowaveComponent> ent)
{
base.DeactivateMicrowaveCycle(ent);
// We have this check here so Audio.Stop doesn't mistakenly tell us that the entity has been deleted when it hasn't been!!!
if (!Timing.IsFirstTimePredicted)
return;
ent.Comp.PlayingStream = Audio.Stop(ent.Comp.PlayingStream);
foreach (var solid in GetMicrowaveContents(ent.AsNullable()))
{
RemComp<ActivelyMicrowavedComponent>(solid);
}
}
}

View file

@ -1,151 +1,128 @@
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Kitchen.Components;
using Content.Shared.Kitchen.EntitySystems;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Timing;
namespace Content.Client.Kitchen.UI
namespace Content.Client.Kitchen.UI;
[UsedImplicitly]
public sealed partial class MicrowaveBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey)
{
[UsedImplicitly]
public sealed class MicrowaveBoundUserInterface : BoundUserInterface
[Dependency] private SpriteSystem _sprite = default!;
[Dependency] private MicrowaveSystem _microwave = default!;
[ViewVariables]
private MicrowaveMenu? _menu;
[ViewVariables]
private readonly Dictionary<int, EntityUid> _solids = new();
protected override void Open()
{
[ViewVariables]
private MicrowaveMenu? _menu;
base.Open();
[ViewVariables]
private readonly Dictionary<int, EntityUid> _solids = new();
[ViewVariables]
private readonly Dictionary<int, ReagentQuantity> _reagents = new();
public MicrowaveBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
_menu = this.CreateWindow<MicrowaveMenu>();
_menu.StartButton.OnPressed += _ => SendPredictedMessage(new MicrowaveStartCookMessage());
_menu.EjectButton.OnPressed += _ => SendPredictedMessage(new MicrowaveEjectMessage());
_menu.IngredientsList.OnItemSelected += args =>
{
}
SendPredictedMessage(new MicrowaveEjectSolidIndexedMessage(EntMan.GetNetEntity(_solids[args.ItemIndex])));
};
protected override void Open()
_menu.OnCookTimeSelected += (name, index, cookTime) =>
{
base.Open();
_menu = this.CreateWindow<MicrowaveMenu>();
_menu.StartButton.OnPressed += _ => SendPredictedMessage(new MicrowaveStartCookMessage());
_menu.EjectButton.OnPressed += _ => SendPredictedMessage(new MicrowaveEjectMessage());
_menu.IngredientsList.OnItemSelected += args =>
{
SendPredictedMessage(new MicrowaveEjectSolidIndexedMessage(EntMan.GetNetEntity(_solids[args.ItemIndex])));
};
_menu.OnCookTimeSelected += (args, buttonIndex) =>
{
var selectedCookTime = (uint) 0;
if (args.Button is MicrowaveMenu.MicrowaveCookTimeButton microwaveCookTimeButton)
{
// args.Button is a MicrowaveCookTimeButton
var actualButton = (MicrowaveMenu.MicrowaveCookTimeButton) args.Button;
selectedCookTime = actualButton.CookTime == 0 ? 0 : actualButton.CookTime;
// SendMessage(new MicrowaveSelectCookTimeMessage((int) selectedCookTime / 5, actualButton.CookTime));
SendPredictedMessage(new MicrowaveSelectCookTimeMessage((int) selectedCookTime / 5, actualButton.CookTime));
_menu.CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label",
("time", selectedCookTime));
}
else
{
// args.Button is a normal button aka instant cook button
SendPredictedMessage(new MicrowaveSelectCookTimeMessage((int) selectedCookTime, 0));
_menu.CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label",
("time", Loc.GetString("microwave-menu-instant-button")));
}
};
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (state is not MicrowaveUpdateUserInterfaceState cState || _menu == null)
{
return;
}
_menu.IsBusy = cState.IsMicrowaveBusy;
_menu.CurrentCooktimeEnd = cState.CurrentCookTimeEnd;
_menu.ToggleBusyDisableOverlayPanel(cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0);
// TODO move this to a component state and ensure the net ids.
RefreshContentsDisplay(EntMan.GetEntityArray(cState.ContainedSolids));
//Set the cook time info label
var cookTime = cState.ActiveButtonIndex == 0
? Loc.GetString("microwave-menu-instant-button")
: cState.CurrentCookTime.ToString();
SendPredictedMessage(new MicrowaveSelectCookTimeMessage(index, cookTime));
_menu.CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label",
("time", cookTime));
_menu.StartButton.Disabled = cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0;
_menu.EjectButton.Disabled = cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0;
("time", name));
};
Update();
}
//Set the correct button active button
if (cState.ActiveButtonIndex == 0)
{
_menu.InstantCookButton.Pressed = true;
}
else
{
var currentlySelectedTimeButton = (Button) _menu.CookTimeButtonVbox.GetChild(cState.ActiveButtonIndex - 1);
currentlySelectedTimeButton.Pressed = true;
}
public override void Update()
{
base.Update();
//Set the "micowave light" ui color to indicate if the microwave is busy or not
if (cState.IsMicrowaveBusy && cState.ContainedSolids.Length > 0)
{
_menu.IngredientsPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = Color.FromHex("#947300") };
}
else
{
_menu.IngredientsPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = Color.FromHex("#1B1B1E") };
}
}
if (_menu is null || !EntMan.TryGetComponent<MicrowaveComponent>(Owner, out var comp))
return;
private void RefreshContentsDisplay(EntityUid[] containedSolids)
RefreshContentsDisplay();
UpdateActiveDisplay(comp);
// Update the currently-selected cook time label and button
var buttonIndex = comp.CurrentCookTimeButtonIndex;
if (_menu.TryGetCookTimeButton(buttonIndex, out var button))
button.Pressed = true;
var timeLabel = buttonIndex == 0
? Loc.GetString("microwave-menu-instant-button")
: comp.CurrentCookTimerTime.ToString();
_menu.CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label",
("time", timeLabel));
}
/// <summary>
/// Update the state of various controls in this menu based on the active / empty status of the microwave.
/// </summary>
private void UpdateActiveDisplay(MicrowaveComponent? comp)
{
if (_menu is null)
return;
// Disable various UI controls if the microwave is active or empty
var isActive = EntMan.TryGetComponent<ActiveMicrowaveComponent>(Owner, out var activeComp);
var isEmpty = !_microwave.HasContents((Owner, comp));
_menu.IsBusy = isActive;
_menu.ToggleBusyDisableOverlayPanel(isActive);
_menu.StartButton.Disabled = isActive || isEmpty;
_menu.EjectButton.Disabled = isActive || isEmpty;
if (activeComp != null)
_menu.CurrentCooktimeEnd = activeComp.CookTimeEnd;
// Set the "microwave light" panel color
_menu.SetIngredientPanelLight(isActive && !isEmpty);
}
/// <summary>
/// Update the panel containing all of the microwave's contents.
/// </summary>
private void RefreshContentsDisplay()
{
if (_menu == null)
return;
_solids.Clear();
_menu.IngredientsList.Clear();
foreach (var entity in _microwave.GetMicrowaveContents(Owner))
{
_reagents.Clear();
if (EntMan.Deleted(entity))
continue;
if (_menu == null) return;
_solids.Clear();
_menu.IngredientsList.Clear();
foreach (var entity in containedSolids)
{
if (EntMan.Deleted(entity))
{
return;
}
// TODO just use sprite view
Texture? texture;
if (EntMan.TryGetComponent<IconComponent>(entity, out var iconComponent))
{
texture = EntMan.System<SpriteSystem>().GetIcon(iconComponent);
}
else if (EntMan.TryGetComponent<SpriteComponent>(entity, out var spriteComponent))
{
texture = spriteComponent.Icon?.Default;
}
else
{
continue;
}
var solidItem = _menu.IngredientsList.AddItem(EntMan.GetComponent<MetaDataComponent>(entity).EntityName, texture);
var solidIndex = _menu.IngredientsList.IndexOf(solidItem);
_solids.Add(solidIndex, entity);
}
// TODO just use sprite view
var itemIcon = GetEntityIcon(entity);
var itemName = EntMan.GetComponent<MetaDataComponent>(entity).EntityName;
var solidItem = _menu.IngredientsList.AddItem(itemName, itemIcon);
var solidIndex = _menu.IngredientsList.IndexOf(solidItem);
_solids.Add(solidIndex, entity);
}
}
/// <summary>
/// Get the texture associated with an ingredient.
/// </summary>
/// <param name="uid">The ingredient entity.</param>
private Texture? GetEntityIcon(EntityUid uid)
{
if (EntMan.TryGetComponent<IconComponent>(uid, out var icon))
return _sprite.GetIcon(icon);
if (EntMan.TryGetComponent<SpriteComponent>(uid, out var sprite))
return sprite.Icon?.Default;
return null;
}
}

View file

@ -0,0 +1,9 @@
<Button xmlns="https://spacestation14.io"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
TextAlign="Center"
ToggleMode="True"
HorizontalExpand="True">
<Button.StyleClasses>
<system:String>OpenBoth</system:String>
</Button.StyleClasses>
</Button>

View file

@ -0,0 +1,39 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Kitchen.UI;
[GenerateTypedNameReferences]
public sealed partial class MicrowaveCookTimeButton : Button
{
public event Action<string, uint>? OnCookTimeSelected;
private uint _cookTime = 0;
public uint CookTime
{
get => _cookTime;
set
{
_cookTime = value;
UpdateLabel();
}
}
public MicrowaveCookTimeButton()
{
RobustXamlLoader.Load(this);
UpdateLabel();
OnPressed += _ => OnCookTimeSelected?.Invoke(Text ?? string.Empty, _cookTime);
}
private void UpdateLabel()
{
var labelText = _cookTime == 0
? Loc.GetString("microwave-menu-instant-button")
: _cookTime.ToString();
Text = labelText;
}
}

View file

@ -2,6 +2,7 @@
xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:kitchen="clr-namespace:Content.Client.Kitchen.UI"
Title="{Loc 'microwave-menu-title'}"
MinWidth="512"
MinSize="512 256">
@ -49,15 +50,11 @@
Align="Center"
Modulate="#FFFFFF"
VAlign="Center" />
<BoxContainer Orientation="Vertical">
<Button
<BoxContainer Orientation="Vertical" SeparationOverride="1">
<kitchen:MicrowaveCookTimeButton
Name="InstantCookButton"
Access="Public"
Text="{Loc 'microwave-menu-instant-button'}"
StyleClasses="OpenLeft"
ToggleMode="True"
Margin="0 0 2 0"
TextAlign="Center" />
CookTime="0"
StyleClasses="OpenBoth"/>
<GridContainer
Name="CookTimeButtonVbox"
HSeparationOverride="1"
@ -71,6 +68,7 @@
<BoxContainer
Orientation="Vertical"
Align="Center"
SeparationOverride="1"
SizeFlagsStretchRatio="3">
<Control MinSize="0 15" />
<Button

View file

@ -1,83 +1,118 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using FancyWindow = Content.Client.UserInterface.Controls.FancyWindow;
using System.Diagnostics.CodeAnalysis;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
namespace Content.Client.Kitchen.UI
namespace Content.Client.Kitchen.UI;
[GenerateTypedNameReferences]
public sealed partial class MicrowaveMenu : FancyWindow
{
[GenerateTypedNameReferences]
public sealed partial class MicrowaveMenu : FancyWindow
[Dependency] private IGameTiming _timing = default!;
public event Action<string, int, uint>? OnCookTimeSelected;
public ButtonGroup CookTimeButtonGroup { get; }
public bool IsBusy;
public TimeSpan CurrentCooktimeEnd;
private readonly StyleBoxFlat _ingredientsStylebox = new();
public MicrowaveMenu()
{
[Dependency] private IGameTiming _timing = default!;
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
public event Action<BaseButton.ButtonEventArgs, int>? OnCookTimeSelected;
IngredientsPanel.PanelOverride = _ingredientsStylebox;
public ButtonGroup CookTimeButtonGroup { get; }
CookTimeButtonGroup = new ButtonGroup();
InstantCookButton.Group = CookTimeButtonGroup;
InstantCookButton.OnCookTimeSelected += (name, cookTime) => OnCookTimeButtonPressed(name, 0, cookTime);
public bool IsBusy;
public TimeSpan CurrentCooktimeEnd;
public MicrowaveMenu()
for (var i = 1; i <= 6; i++)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
CookTimeButtonGroup = new ButtonGroup();
InstantCookButton.Group = CookTimeButtonGroup;
InstantCookButton.OnPressed += args =>
var cookTime = i * 5;
var newButton = new MicrowaveCookTimeButton
{
OnCookTimeSelected?.Invoke(args, 0);
CookTime = (uint)cookTime,
Group = CookTimeButtonGroup
};
for (var i = 1; i <= 6; i++)
{
var newButton = new MicrowaveCookTimeButton
{
Text = (i * 5).ToString(),
TextAlign = Label.AlignMode.Center,
ToggleMode = true,
CookTime = (uint) (i * 5),
Group = CookTimeButtonGroup,
HorizontalExpand = true,
};
if (i == 4)
{
newButton.StyleClasses.Add("OpenRight");
}
else
{
newButton.StyleClasses.Add("OpenBoth");
}
CookTimeButtonVbox.AddChild(newButton);
newButton.OnPressed += args =>
{
OnCookTimeSelected?.Invoke(args, i);
};
}
}
public void ToggleBusyDisableOverlayPanel(bool shouldDisable)
{
DisableCookingPanelOverlay.Visible = shouldDisable;
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (!IsBusy)
return;
if (CurrentCooktimeEnd > _timing.CurTime)
{
CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label",
("time", CurrentCooktimeEnd.Subtract(_timing.CurTime).Seconds));
}
}
public sealed class MicrowaveCookTimeButton : Button
{
public uint CookTime;
newButton.OnCookTimeSelected += (name, cookTime) => OnCookTimeButtonPressed(name, i, cookTime);
CookTimeButtonVbox.AddChild(newButton);
}
}
private void OnCookTimeButtonPressed(string name, int index, uint cookTime)
{
OnCookTimeSelected?.Invoke(name, index, cookTime);
}
/// <summary>
/// Set the visibility of the "busy overlay panel" over the microwave's ingredients,
/// indicating to the player that the ingredients list cannot be interacted with
/// (namely while the microwave is active.)
/// </summary>
/// <param name="shouldDisable">Whether or not this microwave is "busy".</param>
public void ToggleBusyDisableOverlayPanel(bool shouldDisable)
{
DisableCookingPanelOverlay.Visible = shouldDisable;
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (!IsBusy)
return;
var remaining = CurrentCooktimeEnd - _timing.CurTime;
if (remaining > TimeSpan.Zero)
{
CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label",
("time", Math.Ceiling(remaining.TotalSeconds)));
}
}
/// <summary>
/// Set the "color light" state of the ingredient panel's ingredient box.
/// </summary>
/// <param name="value">Wheether or not the panel is "lit" (yellow) or "unlit" (gray).</param>
public void SetIngredientPanelLight(bool value)
{
var panelColor = value
? Color.DarkGoldenrod
: Color.FromHex("#1B1B1E");
_ingredientsStylebox.BackgroundColor = panelColor;
}
/// <summary>
/// Attempt to get the cook time button at the given index.
/// </summary>
/// <param name="index">The index to select.</param>
/// <param name="button">The cook time button, if found.</param>
/// <returns>Whether or not this operation was successful.</returns>
public bool TryGetCookTimeButton(int index,
[NotNullWhen(true)] out Button? button)
{
button = null;
if (index == 0)
button = InstantCookButton;
else
{
if (index <= CookTimeButtonVbox.ChildCount)
{
var control = CookTimeButtonVbox.GetChild(index - 1);
if (control is Button timeButton)
button = timeButton;
}
}
return button != null;
}
}

View file

@ -7,14 +7,12 @@ public sealed partial class KudzuVisualsSystem : VisualizerSystem<KudzuVisualsCo
{
protected override void OnAppearanceChange(EntityUid uid, KudzuVisualsComponent component, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
if (args.Sprite == null
|| !args.TryGetData<int>(KudzuVisuals.Variant, out var variant)
|| !args.TryGetData<int>(KudzuVisuals.GrowthLevel, out var level))
return;
if (AppearanceSystem.TryGetData<int>(uid, KudzuVisuals.Variant, out var var, args.Component)
&& AppearanceSystem.TryGetData<int>(uid, KudzuVisuals.GrowthLevel, out var level, args.Component))
{
var index = SpriteSystem.LayerMapReserve((uid, args.Sprite), $"{component.Layer}");
SpriteSystem.LayerSetRsiState((uid, args.Sprite), index, $"kudzu_{level}{var}");
}
var index = SpriteSystem.LayerMapReserve((uid, args.Sprite), $"{component.Layer}");
SpriteSystem.LayerSetRsiState((uid, args.Sprite), index, $"kudzu_{level}{variant}");
}
}

View file

@ -24,7 +24,7 @@ public sealed partial class LatheSystem : SharedLatheSystem
return;
// Lathe specific stuff
if (_appearance.TryGetData<bool>(uid, LatheVisuals.IsRunning, out var isRunning, args.Component))
if (args.TryGetData<bool>(LatheVisuals.IsRunning, out var isRunning))
{
if (_sprite.LayerMapTryGet((uid, args.Sprite), LatheVisualLayers.IsRunning, out var runningLayer, false) &&
component.RunningState != null &&
@ -35,7 +35,7 @@ public sealed partial class LatheSystem : SharedLatheSystem
}
}
if (_appearance.TryGetData<bool>(uid, PowerDeviceVisuals.Powered, out var powered, args.Component) &&
if (args.TryGetData<bool>(PowerDeviceVisuals.Powered, out var powered) &&
_sprite.LayerMapTryGet((uid, args.Sprite), PowerDeviceVisualLayers.Powered, out var powerLayer, false))
{
_sprite.LayerSetVisible((uid, args.Sprite), powerLayer, powered);

View file

@ -127,9 +127,6 @@ public sealed partial class AmbientOcclusionOverlay : Overlay
worldHandle.UseShader(_proto.Index(StencilEqualDrawShader).Instance());
worldHandle.DrawTextureRect(res.AOTarget!.Texture, worldBounds, color);
args.WorldHandle.SetTransform(Matrix3x2.Identity);
args.WorldHandle.UseShader(null);
}
private void OnColorChanged(string value)

View file

@ -11,13 +11,13 @@ public sealed partial class EmergencyLightSystem : VisualizerSystem<EmergencyLig
if (args.Sprite == null)
return;
if (!AppearanceSystem.TryGetData<bool>(uid, EmergencyLightVisuals.On, out var on, args.Component))
if (!args.TryGetData<bool>(EmergencyLightVisuals.On, out var on))
on = false;
SpriteSystem.LayerSetVisible((uid, args.Sprite), EmergencyLightVisualLayers.LightOff, !on);
SpriteSystem.LayerSetVisible((uid, args.Sprite), EmergencyLightVisualLayers.LightOn, on);
if (AppearanceSystem.TryGetData<Color>(uid, EmergencyLightVisuals.Color, out var color, args.Component))
if (args.TryGetData<Color>(EmergencyLightVisuals.Color, out var color))
{
SpriteSystem.LayerSetColor((uid, args.Sprite), EmergencyLightVisualLayers.LightOn, color);
SpriteSystem.LayerSetColor((uid, args.Sprite), EmergencyLightVisualLayers.LightOff, color);

View file

@ -28,7 +28,7 @@ public sealed partial class ExpendableLightSystem : VisualizerSystem<ExpendableL
if (args.Sprite == null)
return;
if (AppearanceSystem.TryGetData<string>(uid, ExpendableLightVisuals.Behavior, out var lightBehaviourID, args.Component)
if (args.TryGetData<string>(ExpendableLightVisuals.Behavior, out var lightBehaviourID)
&& TryComp<LightBehaviourComponent>(uid, out var lightBehaviour))
{
_lightBehavior.StopLightBehaviour((uid, lightBehaviour));
@ -43,7 +43,7 @@ public sealed partial class ExpendableLightSystem : VisualizerSystem<ExpendableL
}
}
if (!AppearanceSystem.TryGetData<ExpendableLightState>(uid, ExpendableLightVisuals.State, out var state, args.Component))
if (!args.TryGetData<ExpendableLightState>(ExpendableLightVisuals.State, out var state))
return;
switch (state)

View file

@ -6,41 +6,35 @@ namespace Content.Client.Light.EntitySystems;
public sealed partial class LightBulbSystem : SharedLightBulbSystem
{
[Dependency] private AppearanceSystem _appearance = default!;
[Dependency] private SpriteSystem _sprite = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<LightBulbComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
private void OnAppearanceChange(EntityUid uid, LightBulbComponent comp, ref AppearanceChangeEvent args)
[SubscribeLocalEvent]
private void OnAppearanceChange(Entity<LightBulbComponent> ent, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
return;
// update sprite state
if (_appearance.TryGetData<LightBulbState>(uid, LightBulbVisuals.State, out var state, args.Component))
if (args.TryGetData<LightBulbState>(LightBulbVisuals.State, out var state))
{
switch (state)
{
case LightBulbState.Normal:
_sprite.LayerSetRsiState((uid, args.Sprite), LightBulbVisualLayers.Base, comp.NormalSpriteState);
_sprite.LayerSetRsiState((ent, args.Sprite), LightBulbVisualLayers.Base, ent.Comp.NormalSpriteState);
break;
case LightBulbState.Broken:
_sprite.LayerSetRsiState((uid, args.Sprite), LightBulbVisualLayers.Base, comp.BrokenSpriteState);
_sprite.LayerSetRsiState((ent, args.Sprite), LightBulbVisualLayers.Base, ent.Comp.BrokenSpriteState);
break;
case LightBulbState.Burned:
_sprite.LayerSetRsiState((uid, args.Sprite), LightBulbVisualLayers.Base, comp.BurnedSpriteState);
_sprite.LayerSetRsiState((ent, args.Sprite), LightBulbVisualLayers.Base, ent.Comp.BurnedSpriteState);
break;
}
}
// also update sprites color
if (_appearance.TryGetData<Color>(uid, LightBulbVisuals.Color, out var color, args.Component))
if (args.TryGetData<Color>(LightBulbVisuals.Color, out var color))
{
_sprite.SetColor((uid, args.Sprite), color);
_sprite.SetColor((ent, args.Sprite), color);
}
}
}

View file

@ -39,9 +39,7 @@ public sealed partial class PlanetLightSystem : EntitySystem
{
base.Initialize();
SubscribeLocalEvent<GetClearColorEvent>(OnClearColor);
_cfgManager.OnValueChanged(CCVars.AmbientOcclusion, val =>
Subs.CVar(_cfgManager, CCVars.AmbientOcclusion, val =>
{
AmbientOcclusion = val;
}, true);
@ -54,11 +52,6 @@ public sealed partial class PlanetLightSystem : EntitySystem
_overlayMan.AddOverlay(new AfterLightTargetOverlay());
}
private void OnClearColor(ref GetClearColorEvent ev)
{
ev.Color = Color.Transparent;
}
public override void Shutdown()
{
base.Shutdown();
@ -70,4 +63,10 @@ public sealed partial class PlanetLightSystem : EntitySystem
_overlayMan.RemoveOverlay<AfterLightTargetOverlay>();
_overlayMan.RemoveOverlay<AmbientOcclusionOverlay>();
}
[SubscribeLocalEvent]
private void OnClearColor(ref GetClearColorEvent ev)
{
ev.Color = Color.Transparent;
}
}

View file

@ -39,40 +39,34 @@ public sealed partial class HandheldLightSystem : SharedHandheldLightSystem
private void OnAppearanceChange(EntityUid uid, HandheldLightComponent component, ref AppearanceChangeEvent args)
{
if (!_appearance.TryGetData<bool>(uid, ToggleableVisuals.Enabled, out var enabled, args.Component))
{
if (!args.TryGetData<bool>(ToggleableVisuals.Enabled, out var enabled))
return;
if (!args.TryGetData<HandheldLightPowerStates>(HandheldLightVisuals.Power, out var state))
return;
if (!TryComp<LightBehaviourComponent>(uid, out var lightBehaviour))
return;
// Reset any running behaviour to reset the animated properties back to the original value, to avoid conflicts between resets
if (_lightBehavior.HasRunningBehaviours((uid, lightBehaviour)))
{
_lightBehavior.StopLightBehaviour((uid, lightBehaviour), resetToOriginalSettings: true);
}
if (!_appearance.TryGetData<HandheldLightPowerStates>(uid, HandheldLightVisuals.Power, out var state, args.Component))
{
if (!enabled)
return;
}
if (TryComp<LightBehaviourComponent>(uid, out var lightBehaviour))
switch (state)
{
// Reset any running behaviour to reset the animated properties back to the original value, to avoid conflicts between resets
if (_lightBehavior.HasRunningBehaviours((uid, lightBehaviour)))
{
_lightBehavior.StopLightBehaviour((uid, lightBehaviour), resetToOriginalSettings: true);
}
if (!enabled)
{
return;
}
switch (state)
{
case HandheldLightPowerStates.FullPower:
break; // We just needed to reset all behaviours
case HandheldLightPowerStates.LowPower:
_lightBehavior.StartLightBehaviour((uid, lightBehaviour), component.RadiatingBehaviourId);
break;
case HandheldLightPowerStates.Dying:
_lightBehavior.StartLightBehaviour((uid, lightBehaviour), component.BlinkingBehaviourId);
break;
}
case HandheldLightPowerStates.FullPower:
break; // We just needed to reset all behaviours
case HandheldLightPowerStates.LowPower:
_lightBehavior.StartLightBehaviour((uid, lightBehaviour), component.RadiatingBehaviourId);
break;
case HandheldLightPowerStates.Dying:
_lightBehavior.StartLightBehaviour((uid, lightBehaviour), component.BlinkingBehaviourId);
break;
}
}
}

View file

@ -132,7 +132,5 @@ public sealed partial class RoofOverlay : Overlay
}
}
}, null);
worldHandle.SetTransform(Matrix3x2.Identity);
}
}

View file

@ -1,6 +1,7 @@
using System.Numerics;
using Content.Client.Graphics;
using Content.Shared.Light.Components;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Enums;
using Robust.Shared.Map;
@ -21,7 +22,7 @@ public sealed partial class SunShadowOverlay : Overlay
[Dependency] private IPrototypeManager _protoManager = default!;
private readonly EntityLookupSystem _lookup;
private readonly SharedMapSystem _mapSys;
private readonly SharedTransformSystem _xformSys;
private readonly TransformSystem _xformSys;
private readonly HashSet<Entity<SunShadowCastComponent>> _shadows = new();
@ -30,7 +31,7 @@ public sealed partial class SunShadowOverlay : Overlay
public SunShadowOverlay()
{
IoCManager.InjectDependencies(this);
_xformSys = _entManager.System<SharedTransformSystem>();
_xformSys = _entManager.System<TransformSystem>();
_mapSys = _entManager.System<SharedMapSystem>();
_lookup = _entManager.System<EntityLookupSystem>();
ZIndex = AfterLightTargetOverlay.ContentZIndex + 1;
@ -119,7 +120,7 @@ public sealed partial class SunShadowOverlay : Overlay
foreach (var ent in _shadows)
{
var xform = _entManager.GetComponent<TransformComponent>(ent.Owner);
var (worldPos, worldRot) = _xformSys.GetWorldPositionRotation(xform);
var (worldPos, worldRot) = _xformSys.GetRenderWorldPositionRotation((ent.Owner, xform));
// Need no rotation on matrix as sun shadow direction doesn't care.
var worldMatrix = Matrix3x2.CreateTranslation(worldPos);
var renderMatrix = Matrix3x2.Multiply(worldMatrix, invMatrix);

View file

@ -23,7 +23,7 @@ public sealed partial class PoweredLightVisualizerSystem : VisualizerSystem<Powe
if (args.Sprite == null)
return;
if (!AppearanceSystem.TryGetData<PoweredLightState>(uid, PoweredLightVisuals.BulbState, out var state, args.Component))
if (!args.TryGetData<PoweredLightState>(PoweredLightVisuals.BulbState, out var state))
return;
if (comp.SpriteStateMap.TryGetValue(state, out var spriteState))
@ -42,7 +42,7 @@ public sealed partial class PoweredLightVisualizerSystem : VisualizerSystem<Powe
SetBlinkingAnimation(
uid,
state == PoweredLightState.On
&& (AppearanceSystem.TryGetData<bool>(uid, PoweredLightVisuals.Blinking, out var isBlinking, args.Component) && isBlinking),
&& (args.TryGetData<bool>(PoweredLightVisuals.Blinking, out var isBlinking) && isBlinking),
comp
);
}

Some files were not shown because too many files have changed in this diff Show more