Skip to content

Commit f8441b1

Browse files
authored
Merge branch 'space-wizards:master' into master
2 parents 1e5e97b + 4b9e735 commit f8441b1

164 files changed

Lines changed: 6558 additions & 3206 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Content.Client.Stylesheets;
22
using Content.Shared.Atmos;
33
using Content.Shared.Atmos.Components;
4+
using Content.Shared.Atmos.EntitySystems;
45
using Content.Shared.Atmos.Monitor;
56
using Content.Shared.FixedPoint;
67
using Content.Shared.Temperature;
@@ -22,6 +23,7 @@ public sealed partial class AtmosAlarmEntryContainer : BoxContainer
2223

2324
private readonly IEntityManager _entManager;
2425
private readonly IResourceCache _cache;
26+
private readonly SharedAtmosphereSystem _atmosphere;
2527

2628
private Dictionary<AtmosAlarmType, string> _alarmStrings = new Dictionary<AtmosAlarmType, string>()
2729
{
@@ -37,6 +39,7 @@ public AtmosAlarmEntryContainer(NetEntity uid, EntityCoordinates? coordinates)
3739

3840
_entManager = IoCManager.Resolve<IEntityManager>();
3941
_cache = IoCManager.Resolve<IResourceCache>();
42+
_atmosphere = _entManager.System<SharedAtmosphereSystem>();
4043

4144
NetEntity = uid;
4245
Coordinates = coordinates;
@@ -149,7 +152,7 @@ public void UpdateEntry(AtmosAlertsComputerEntry entry, bool isFocus, AtmosAlert
149152
foreach ((var gas, (var mol, var percent, var alert)) in keyValuePairs)
150153
{
151154
FixedPoint2 gasPercent = percent * 100f;
152-
var gasAbbreviation = Atmospherics.GasAbbreviations.GetValueOrDefault(gas, Loc.GetString("gas-unknown-abbreviation"));
155+
var gasAbbreviation = Loc.GetString(_atmosphere.GetGas(gas).Abbreviation);
153156

154157
var gasLabel = new Label()
155158
{

Content.Client/Atmos/Consoles/AtmosMonitoringEntryContainer.xaml.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Content.Client.Stylesheets;
22
using Content.Shared.Atmos;
33
using Content.Shared.Atmos.Components;
4+
using Content.Shared.Atmos.EntitySystems;
45
using Content.Shared.FixedPoint;
56
using Content.Shared.Temperature;
67
using Robust.Client.AutoGenerated;
@@ -19,12 +20,14 @@ public sealed partial class AtmosMonitoringEntryContainer : BoxContainer
1920

2021
private readonly IEntityManager _entManager;
2122
private readonly IResourceCache _cache;
23+
private readonly SharedAtmosphereSystem _atmosphere;
2224

2325
public AtmosMonitoringEntryContainer(AtmosMonitoringConsoleEntry data)
2426
{
2527
RobustXamlLoader.Load(this);
2628
_entManager = IoCManager.Resolve<IEntityManager>();
2729
_cache = IoCManager.Resolve<IResourceCache>();
30+
_atmosphere = _entManager.System<SharedAtmosphereSystem>();
2831

2932
Data = data;
3033

@@ -132,7 +135,7 @@ public void UpdateEntry(AtmosMonitoringConsoleEntry updatedData, bool isFocus)
132135
var gasPercent = (FixedPoint2)0f;
133136
gasPercent = percent * 100f;
134137

135-
var gasAbbreviation = Atmospherics.GasAbbreviations.GetValueOrDefault(gas, Loc.GetString("gas-unknown-abbreviation"));
138+
var gasAbbreviation = Loc.GetString(_atmosphere.GetGas(gas).Abbreviation);
136139

137140
var gasLabel = new Label()
138141
{

Content.Client/Atmos/EntitySystems/AtmosphereSystem.Gases.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ protected override float GetHeatCapacityCalculation(float[] moles, bool space)
5151
// though this isnt the hottest code path so it should be fine
5252
// the gc can eat a little as a treat
5353
var tmp = new float[moles.Length];
54-
NumericsHelpers.Multiply(moles, GasSpecificHeats, tmp);
54+
NumericsHelpers.Multiply(moles, GasMolarHeatCapacities, tmp);
5555
// Adjust heat capacity by speedup, because this is primarily what
5656
// determines how quickly gases heat up/cool.
5757
return MathF.Max(NumericsHelpers.HorizontalAdd(tmp), Atmospherics.MinimumHeatCapacity);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using Content.Client.Atmos.Overlays;
2+
using JetBrains.Annotations;
3+
using Robust.Client.Graphics;
4+
5+
namespace Content.Client.Atmos.EntitySystems;
6+
7+
/// <summary>
8+
/// System responsible for rendering heat distortion using <see cref="GasTileHeatBlurOverlay"/>.
9+
/// </summary>
10+
[UsedImplicitly]
11+
public sealed class GasTileHeatBlurOverlaySystem : EntitySystem
12+
{
13+
[Dependency] private readonly IOverlayManager _overlayMan = default!;
14+
15+
private GasTileHeatBlurOverlay _gasTileHeatBlurOverlay = default!;
16+
17+
public override void Initialize()
18+
{
19+
base.Initialize();
20+
21+
_gasTileHeatBlurOverlay = new GasTileHeatBlurOverlay();
22+
_overlayMan.AddOverlay(_gasTileHeatBlurOverlay);
23+
}
24+
25+
public override void Shutdown()
26+
{
27+
base.Shutdown();
28+
_overlayMan.RemoveOverlay<GasTileHeatBlurOverlay>();
29+
}
30+
}
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
using Content.Client.Atmos.EntitySystems;
2+
using Content.Client.Graphics;
3+
using Content.Client.Resources;
4+
using Content.Shared.Atmos;
5+
using Content.Shared.Atmos.Components;
6+
using Content.Shared.Atmos.EntitySystems;
7+
using Content.Shared.CCVar;
8+
using Robust.Client.Graphics;
9+
using Robust.Client.ResourceManagement;
10+
using Robust.Shared.Configuration;
11+
using Robust.Shared.Enums;
12+
using Robust.Shared.Map;
13+
using Robust.Shared.Map.Components;
14+
using Robust.Shared.Prototypes;
15+
using System.Numerics;
16+
using Color = Robust.Shared.Maths.Color;
17+
using Texture = Robust.Client.Graphics.Texture;
18+
19+
namespace Content.Client.Atmos.Overlays;
20+
21+
/// <summary>
22+
/// Overlay responsible for rendering heat distortion shader.
23+
/// </summary>
24+
public sealed class GasTileHeatBlurOverlay : Overlay
25+
{
26+
public override bool RequestScreenTexture { get; set; } = true;
27+
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
28+
private static readonly ProtoId<ShaderPrototype> HeatOverlayShader = "HeatBlur";
29+
30+
[Dependency] private readonly IEntityManager _entManager = default!;
31+
[Dependency] private readonly IMapManager _mapManager = default!;
32+
[Dependency] private readonly IPrototypeManager _proto = default!;
33+
[Dependency] private readonly IClyde _clyde = default!;
34+
[Dependency] private readonly IConfigurationManager _configManager = default!;
35+
[Dependency] private readonly IResourceCache _resourceCache = default!;
36+
37+
private readonly SharedTransformSystem _xformSys;
38+
private readonly ShaderInstance _shader;
39+
40+
private readonly Texture _noiseTexture;
41+
private readonly Texture _heatGradientTexture;
42+
private List<Entity<MapGridComponent>> _intersectingGrids = new();
43+
private readonly OverlayResourceCache<CachedResources> _resources = new();
44+
45+
// Overlay settings
46+
private const float
47+
ShaderSpilling = 2.5f; // for example 4f - spills shader one tile from hotspot, 2.5f - spills it half tile
48+
49+
private const float ShaderStrength = 0.04f; // Makes waves stronger
50+
private const float ShaderScale = 1f; // Makes more waves
51+
private const float ShaderSpeed = 0.4f; // Makes waves run faster
52+
53+
// Overlay settings for reduced motion setting
54+
private const float ShaderStrengthForReducedMotion = 0.01f;
55+
private const float ShaderScaleReducedMotion = 0.5f;
56+
private const float ShaderSpeedReducedMotion = 0.25f;
57+
58+
private const int MinDistortionTemp = 300; // Distortion starts to show up at this temperature in Kelvins
59+
private const int MaxDistortionTemp = 2000; // Maximum distortion strength at this temperature in Kelvins
60+
61+
public override OverlaySpace Space => OverlaySpace.WorldSpace;
62+
63+
public GasTileHeatBlurOverlay()
64+
{
65+
IoCManager.InjectDependencies(this);
66+
_xformSys = _entManager.System<SharedTransformSystem>();
67+
68+
_noiseTexture = _resourceCache.GetTexture("/Textures/Effects/HeatBlur/perlin_noise.png");
69+
_heatGradientTexture = _resourceCache.GetTexture("/Textures/Effects/HeatBlur/soft_circle.png");
70+
71+
_shader = _proto.Index(HeatOverlayShader).InstanceUnique();
72+
_configManager.OnValueChanged(CCVars.ReducedMotion, SetReducedMotion, invokeImmediately: true);
73+
}
74+
75+
private void SetReducedMotion(bool reducedMotion)
76+
{
77+
_shader.SetParameter("strength_scale", reducedMotion ? ShaderStrengthForReducedMotion : ShaderStrength);
78+
_shader.SetParameter("spatial_scale", reducedMotion ? ShaderScaleReducedMotion : ShaderScale);
79+
_shader.SetParameter("speed_scale", reducedMotion ? ShaderSpeedReducedMotion : ShaderSpeed);
80+
}
81+
82+
protected override bool BeforeDraw(in OverlayDrawArgs args)
83+
{
84+
if (args.MapId == MapId.Nullspace)
85+
return false;
86+
87+
var res = _resources.GetForViewport(args.Viewport, static _ => new CachedResources());
88+
89+
var target = args.Viewport.RenderTarget;
90+
91+
// Probably the resolution of the game window changed, remake the textures.
92+
if (res.HeatTarget?.Texture.Size != target.Size)
93+
{
94+
res.HeatTarget?.Dispose();
95+
res.HeatTarget = _clyde.CreateRenderTarget(
96+
target.Size,
97+
new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb),
98+
name: nameof(GasTileHeatBlurOverlaySystem));
99+
}
100+
101+
if (res.HeatBlurTarget?.Texture.Size != target.Size)
102+
{
103+
res.HeatBlurTarget?.Dispose();
104+
res.HeatBlurTarget = _clyde.CreateRenderTarget(
105+
target.Size,
106+
new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb),
107+
name: $"{nameof(GasTileHeatBlurOverlaySystem)}-blur");
108+
}
109+
110+
var overlayQuery = _entManager.GetEntityQuery<GasTileOverlayComponent>();
111+
112+
args.WorldHandle.UseShader(_proto.Index(UnshadedShader).Instance());
113+
114+
var mapId = args.MapId;
115+
var worldAABB = args.WorldAABB;
116+
var worldBounds = args.WorldBounds;
117+
var worldHandle = args.WorldHandle;
118+
var worldToViewportLocal = args.Viewport.GetWorldToLocalMatrix();
119+
120+
// If there is no distortion after checking all visible tiles, we can bail early
121+
var anyDistortion = false;
122+
123+
// We're rendering in the context of the heat target texture, which will encode data as to where and how strong
124+
// the heat distortion will be
125+
args.WorldHandle.RenderInRenderTarget(res.HeatTarget,
126+
() =>
127+
{
128+
_intersectingGrids.Clear();
129+
_mapManager.FindGridsIntersecting(mapId, worldAABB, ref _intersectingGrids);
130+
foreach (var grid in _intersectingGrids)
131+
{
132+
if (!overlayQuery.TryGetComponent(grid.Owner, out var comp))
133+
continue;
134+
135+
var gridEntToWorld = _xformSys.GetWorldMatrix(grid.Owner);
136+
var gridEntToViewportLocal = gridEntToWorld * worldToViewportLocal;
137+
138+
if (!Matrix3x2.Invert(gridEntToViewportLocal, out var viewportLocalToGridEnt))
139+
continue;
140+
141+
var uvToUi = Matrix3Helpers.CreateScale(res.HeatTarget.Size.X, -res.HeatTarget.Size.Y);
142+
var uvToGridEnt = uvToUi * viewportLocalToGridEnt;
143+
144+
// Because we want the actual distortion to be calculated based on the grid coordinates*, we need
145+
// to pass a matrix transformation to go from the viewport coordinates to grid coordinates.
146+
// * (why? because otherwise the effect would shimmer like crazy as you moved around, think
147+
// moving a piece of warped glass above a picture instead of placing the warped glass on the
148+
// paper and moving them together)
149+
_shader.SetParameter("grid_ent_from_viewport_local", uvToGridEnt);
150+
151+
// Draw commands (like DrawRect) will be using grid coordinates from here
152+
worldHandle.SetTransform(gridEntToViewportLocal);
153+
154+
// We only care about tiles that fit in these bounds
155+
var worldToGridLocal = _xformSys.GetInvWorldMatrix(grid.Owner);
156+
var floatBounds = worldToGridLocal.TransformBox(worldBounds).Enlarged(grid.Comp.TileSize);
157+
158+
var localBounds = new Box2i(
159+
(int)MathF.Floor(floatBounds.Left),
160+
(int)MathF.Floor(floatBounds.Bottom),
161+
(int)MathF.Ceiling(floatBounds.Right),
162+
(int)MathF.Ceiling(floatBounds.Top));
163+
164+
// for each tile and its gas --->
165+
foreach (var chunk in comp.Chunks.Values)
166+
{
167+
var enumerator = new GasChunkEnumerator(chunk);
168+
169+
while (enumerator.MoveNext(out var tileGas))
170+
{
171+
// Check and make sure the tile is within the viewport/screen
172+
var tilePosition = chunk.Origin + (enumerator.X, enumerator.Y);
173+
if (!localBounds.Contains(tilePosition))
174+
continue;
175+
176+
// Get the distortion strength from the temperature and bail if it's not hot enough
177+
var strength = GetHeatDistortionStrength(tileGas.ByteGasTemperature);
178+
if (strength <= 0f)
179+
continue;
180+
181+
anyDistortion = true;
182+
183+
// Encode the strength in the red channel
184+
// alpha set to 1 as tile is active
185+
worldHandle.DrawTextureRect(
186+
_heatGradientTexture,
187+
Box2.CenteredAround(tilePosition + grid.Comp.TileSizeHalfVector,
188+
grid.Comp.TileSizeVector * ShaderSpilling),
189+
new Color(strength, 0f, 0f));
190+
}
191+
}
192+
}
193+
},
194+
// This clears the buffer to all zero first...
195+
new Color(0, 0, 0, 0));
196+
197+
// no distortion, no need to render
198+
if (!anyDistortion)
199+
{
200+
args.WorldHandle.UseShader(null);
201+
args.WorldHandle.SetTransform(Matrix3x2.Identity);
202+
return false;
203+
}
204+
205+
return true;
206+
}
207+
208+
protected override void Draw(in OverlayDrawArgs args)
209+
{
210+
var res = _resources.GetForViewport(args.Viewport, static _ => new CachedResources());
211+
212+
if (ScreenTexture is null || res.HeatTarget is null || res.HeatBlurTarget is null)
213+
return;
214+
215+
_shader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
216+
_shader.SetParameter("NOISE_TEXTURE", _noiseTexture);
217+
218+
args.WorldHandle.UseShader(_shader);
219+
args.WorldHandle.DrawTextureRect(res.HeatTarget.Texture, args.WorldBounds);
220+
221+
args.WorldHandle.UseShader(null);
222+
args.WorldHandle.SetTransform(Matrix3x2.Identity);
223+
}
224+
225+
protected override void DisposeBehavior()
226+
{
227+
_resources.Dispose();
228+
229+
_configManager.UnsubValueChanged(CCVars.ReducedMotion, SetReducedMotion);
230+
base.DisposeBehavior();
231+
}
232+
233+
/// <summary>
234+
/// Gets the strength of the heat distortion effect based on the temperature of the tile.
235+
/// The strength is a value between 0 and 1, where 0 means no distortion and 1 means maximum distortion.
236+
/// </summary>
237+
/// <param name="temp">The temperature of the tile.</param>
238+
/// <returns>The strength of the heat distortion effect.</returns>
239+
/// <seealso cref="ThermalByte"/>
240+
private static float GetHeatDistortionStrength(ThermalByte temp)
241+
{
242+
if (!temp.TryGetTemperature(out var kelvinTemp))
243+
{
244+
return 0f;
245+
}
246+
247+
var strength = (kelvinTemp - MinDistortionTemp) / (MaxDistortionTemp - MinDistortionTemp);
248+
249+
return MathHelper.Clamp01(strength);
250+
}
251+
252+
internal sealed class CachedResources : IDisposable
253+
{
254+
public IRenderTexture? HeatTarget;
255+
public IRenderTexture? HeatBlurTarget;
256+
257+
public void Dispose()
258+
{
259+
HeatTarget?.Dispose();
260+
HeatBlurTarget?.Dispose();
261+
}
262+
}
263+
}

Content.Client/Atmos/Overlays/GasTileVisibleGasOverlay.cs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,7 @@ public GasTileVisibleGasOverlay()
7272
{
7373
var gasPrototype = _atmosphereSystem.GetGas(_gasTileOverlaySystem.VisibleGasId[i]);
7474

75-
SpriteSpecifier overlay;
76-
77-
if (!string.IsNullOrEmpty(gasPrototype.GasOverlaySprite) &&
78-
!string.IsNullOrEmpty(gasPrototype.GasOverlayState))
79-
overlay = new SpriteSpecifier.Rsi(new(gasPrototype.GasOverlaySprite), gasPrototype.GasOverlayState);
80-
else if (!string.IsNullOrEmpty(gasPrototype.GasOverlayTexture))
81-
overlay = new SpriteSpecifier.Texture(new(gasPrototype.GasOverlayTexture));
82-
else
83-
continue;
84-
85-
switch (overlay)
75+
switch (gasPrototype.GasOverlaySprite)
8676
{
8777
case SpriteSpecifier.Rsi animated:
8878
var rsi = _resourceCache.GetResource<RSIResource>(animated.RsiPath).RSI;

0 commit comments

Comments
 (0)