diff --git a/Content.Benchmarks/ComponentQueryBenchmark.cs b/Content.Benchmarks/ComponentQueryBenchmark.cs index 11c7ab9d5f..49e9984c09 100644 --- a/Content.Benchmarks/ComponentQueryBenchmark.cs +++ b/Content.Benchmarks/ComponentQueryBenchmark.cs @@ -9,13 +9,14 @@ using Content.IntegrationTests.Pair; using Content.Shared.Clothing.Components; using Content.Shared.Doors.Components; using Content.Shared.Item; -using Robust.Server.GameObjects; using Robust.Shared; using Robust.Shared.Analyzers; +using Robust.Shared.EntitySerialization; +using Robust.Shared.EntitySerialization.Systems; using Robust.Shared.GameObjects; -using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Random; +using Robust.Shared.Utility; namespace Content.Benchmarks; @@ -32,7 +33,6 @@ public class ComponentQueryBenchmark private TestPair _pair = default!; private IEntityManager _entMan = default!; - private MapId _mapId = new(10); private EntityQuery _itemQuery; private EntityQuery _clothingQuery; private EntityQuery _mapQuery; @@ -54,10 +54,10 @@ public class ComponentQueryBenchmark _pair.Server.ResolveDependency().SetSeed(42); _pair.Server.WaitPost(() => { - var success = _entMan.System().TryLoad(_mapId, Map, out _); - if (!success) + var map = new ResPath(Map); + var opts = DeserializationOptions.Default with {InitializeMaps = true}; + if (!_entMan.System().TryLoadMap(map, out _, out _, opts)) throw new Exception("Map load failed"); - _pair.Server.MapMan.DoMapInitialize(_mapId); }).GetAwaiter().GetResult(); _items = new EntityUid[_entMan.Count()]; diff --git a/Content.Benchmarks/MapLoadBenchmark.cs b/Content.Benchmarks/MapLoadBenchmark.cs index 8182ba8ec6..2bb71bb59d 100644 --- a/Content.Benchmarks/MapLoadBenchmark.cs +++ b/Content.Benchmarks/MapLoadBenchmark.cs @@ -6,12 +6,13 @@ using BenchmarkDotNet.Attributes; using Content.IntegrationTests; using Content.IntegrationTests.Pair; using Content.Server.Maps; -using Robust.Server.GameObjects; using Robust.Shared; using Robust.Shared.Analyzers; +using Robust.Shared.EntitySerialization.Systems; using Robust.Shared.GameObjects; using Robust.Shared.Map; using Robust.Shared.Prototypes; +using Robust.Shared.Utility; namespace Content.Benchmarks; @@ -20,7 +21,7 @@ public class MapLoadBenchmark { private TestPair _pair = default!; private MapLoaderSystem _mapLoader = default!; - private IMapManager _mapManager = default!; + private SharedMapSystem _mapSys = default!; [GlobalSetup] public void Setup() @@ -36,7 +37,7 @@ public class MapLoadBenchmark .ToDictionary(x => x.ID, x => x.MapPath.ToString()); _mapLoader = server.ResolveDependency().GetEntitySystem(); - _mapManager = server.ResolveDependency(); + _mapSys = server.ResolveDependency().GetEntitySystem(); } [GlobalCleanup] @@ -52,17 +53,19 @@ public class MapLoadBenchmark public string Map; public Dictionary Paths; + private MapId _mapId; [Benchmark] public async Task LoadMap() { - var mapPath = Paths[Map]; + var mapPath = new ResPath(Paths[Map]); var server = _pair.Server; await server.WaitPost(() => { - var success = _mapLoader.TryLoad(new MapId(10), mapPath, out _); + var success = _mapLoader.TryLoadMap(mapPath, out var map, out _); if (!success) throw new Exception("Map load failed"); + _mapId = map.Value.Comp.MapId; }); } @@ -70,9 +73,7 @@ public class MapLoadBenchmark public void IterationCleanup() { var server = _pair.Server; - server.WaitPost(() => - { - _mapManager.DeleteMap(new MapId(10)); - }).Wait(); + server.WaitPost(() => _mapSys.DeleteMap(_mapId)) + .Wait(); } } diff --git a/Content.Benchmarks/PvsBenchmark.cs b/Content.Benchmarks/PvsBenchmark.cs index fa7f9d4542..2f87545426 100644 --- a/Content.Benchmarks/PvsBenchmark.cs +++ b/Content.Benchmarks/PvsBenchmark.cs @@ -7,13 +7,15 @@ using Content.IntegrationTests; using Content.IntegrationTests.Pair; using Content.Server.Mind; using Content.Server.Warps; -using Robust.Server.GameObjects; using Robust.Shared; using Robust.Shared.Analyzers; +using Robust.Shared.EntitySerialization; +using Robust.Shared.EntitySerialization.Systems; using Robust.Shared.GameObjects; using Robust.Shared.Map; using Robust.Shared.Player; using Robust.Shared.Random; +using Robust.Shared.Utility; namespace Content.Benchmarks; @@ -34,7 +36,6 @@ public class PvsBenchmark private TestPair _pair = default!; private IEntityManager _entMan = default!; - private MapId _mapId = new(10); private ICommonSession[] _players = default!; private EntityCoordinates[] _spawns = default!; public int _cycleOffset = 0; @@ -65,10 +66,10 @@ public class PvsBenchmark _pair.Server.ResolveDependency().SetSeed(42); await _pair.Server.WaitPost(() => { - var success = _entMan.System().TryLoad(_mapId, Map, out _); - if (!success) + var path = new ResPath(Map); + var opts = DeserializationOptions.Default with {InitializeMaps = true}; + if (!_entMan.System().TryLoadMap(path, out _, out _, opts)) throw new Exception("Map load failed"); - _pair.Server.MapMan.DoMapInitialize(_mapId); }); // Get list of ghost warp positions diff --git a/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs b/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs index 7c7d824ee9..4c3a583b2a 100644 --- a/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs +++ b/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs @@ -141,6 +141,11 @@ public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem { return _reagentSources.GetValueOrDefault(id) ?? new List(); } + + // Is handled on server and updated on client via ReagentGuideRegistryChangedEvent + public override void ReloadAllReagentPrototypes() + { + } } /// diff --git a/Content.Client/Construction/ConstructionGhostComponent.cs b/Content.Client/Construction/ConstructionGhostComponent.cs index 8f4fe3867e..45d1d618fc 100644 --- a/Content.Client/Construction/ConstructionGhostComponent.cs +++ b/Content.Client/Construction/ConstructionGhostComponent.cs @@ -7,6 +7,7 @@ namespace Content.Client.Construction [RegisterComponent] public sealed partial class ConstructionGhostComponent : Component { + public int GhostId { get; set; } [ViewVariables] public ConstructionPrototype? Prototype { get; set; } } } diff --git a/Content.Client/Construction/ConstructionSystem.cs b/Content.Client/Construction/ConstructionSystem.cs index f909b23423..17d6b05388 100644 --- a/Content.Client/Construction/ConstructionSystem.cs +++ b/Content.Client/Construction/ConstructionSystem.cs @@ -55,6 +55,12 @@ namespace Content.Client.Construction .Register(); SubscribeLocalEvent(HandleConstructionGhostExamined); + SubscribeLocalEvent(HandleGhostComponentShutdown); + } + + private void HandleGhostComponentShutdown(EntityUid uid, ConstructionGhostComponent component, ComponentShutdown args) + { + ClearGhost(component.GhostId); } private void OnConstructionGuideReceived(ResponseConstructionGuide ev) @@ -205,8 +211,9 @@ namespace Content.Client.Construction ghost = EntityManager.SpawnEntity("constructionghost", loc); var comp = EntityManager.GetComponent(ghost.Value); comp.Prototype = prototype; + comp.GhostId = ghost.GetHashCode(); EntityManager.GetComponent(ghost.Value).LocalRotation = dir.ToAngle(); - _ghosts.Add(ghost.GetHashCode(), ghost.Value); + _ghosts.Add(comp.GhostId, ghost.Value); var sprite = EntityManager.GetComponent(ghost.Value); sprite.Color = new Color(48, 255, 48, 128); diff --git a/Content.Client/CriminalRecords/CriminalRecordsConsoleWindow.xaml b/Content.Client/CriminalRecords/CriminalRecordsConsoleWindow.xaml index d36718cf08..179304a978 100644 --- a/Content.Client/CriminalRecords/CriminalRecordsConsoleWindow.xaml +++ b/Content.Client/CriminalRecords/CriminalRecordsConsoleWindow.xaml @@ -58,9 +58,7 @@ StyleClasses="LabelBig" /> - +public sealed class AfterLightTargetOverlay : Overlay +{ + public override OverlaySpace Space => OverlaySpace.BeforeLighting; + + [Dependency] private readonly IOverlayManager _overlay = default!; + + public const int ContentZIndex = LightBlurOverlay.ContentZIndex + 1; + + public AfterLightTargetOverlay() + { + IoCManager.InjectDependencies(this); + ZIndex = ContentZIndex; + } + + protected override void Draw(in OverlayDrawArgs args) + { + var viewport = args.Viewport; + var worldHandle = args.WorldHandle; + + if (viewport.Eye == null) + return; + + var lightOverlay = _overlay.GetOverlay(); + var bounds = args.WorldBounds; + + // at 1-1 render scale it's mostly fine but at 4x4 it's way too fkn big + var lightScale = viewport.LightRenderTarget.Size / (Vector2) viewport.Size; + var newScale = viewport.RenderScale / (Vector2.One / lightScale); + + var localMatrix = + viewport.LightRenderTarget.GetWorldToLocalMatrix(viewport.Eye, newScale); + var diff = (lightOverlay.EnlargedLightTarget.Size - viewport.LightRenderTarget.Size); + var halfDiff = diff / 2; + + // Pixels -> Metres -> Half distance. + // If we're zoomed in need to enlarge the bounds further. + args.WorldHandle.RenderInRenderTarget(viewport.LightRenderTarget, + () => + { + // We essentially need to draw the cropped version onto the lightrendertarget. + var subRegion = new UIBox2i(halfDiff.X, + halfDiff.Y, + viewport.LightRenderTarget.Size.X + halfDiff.X, + viewport.LightRenderTarget.Size.Y + halfDiff.Y); + + worldHandle.SetTransform(localMatrix); + worldHandle.DrawTextureRectRegion(lightOverlay.EnlargedLightTarget.Texture, bounds, subRegion: subRegion); + }, null); + } +} diff --git a/Content.Client/Light/BeforeLightTargetOverlay.cs b/Content.Client/Light/BeforeLightTargetOverlay.cs new file mode 100644 index 0000000000..8f1bd0e527 --- /dev/null +++ b/Content.Client/Light/BeforeLightTargetOverlay.cs @@ -0,0 +1,51 @@ +using System.Numerics; +using Robust.Client.Graphics; +using Robust.Shared.Enums; + +namespace Content.Client.Light; + +/// +/// Handles an enlarged lighting target so content can use large blur radii. +/// +public sealed class BeforeLightTargetOverlay : Overlay +{ + public override OverlaySpace Space => OverlaySpace.BeforeLighting; + + [Dependency] private readonly IClyde _clyde = default!; + + public IRenderTexture EnlargedLightTarget = default!; + public Box2Rotated EnlargedBounds; + + /// + /// In metres + /// + private float _skirting = 2f; + + public const int ContentZIndex = -10; + + public BeforeLightTargetOverlay() + { + IoCManager.InjectDependencies(this); + ZIndex = ContentZIndex; + } + + protected override void Draw(in OverlayDrawArgs args) + { + // Code is weird but I don't think engine should be enlarging the lighting render target arbitrarily either, maybe via cvar? + // The problem is the blur has no knowledge of pixels outside the viewport so with a large enough blur radius you get sampling issues. + var size = args.Viewport.LightRenderTarget.Size + (int) (_skirting * EyeManager.PixelsPerMeter); + EnlargedBounds = args.WorldBounds.Enlarged(_skirting / 2f); + + // This just exists to copy the lightrendertarget and write back to it. + if (EnlargedLightTarget?.Size != size) + { + EnlargedLightTarget = _clyde + .CreateRenderTarget(size, new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb), name: "enlarged-light-copy"); + } + + args.WorldHandle.RenderInRenderTarget(EnlargedLightTarget, + () => + { + }, _clyde.GetClearColor(args.MapUid)); + } +} diff --git a/Content.Client/Light/EntitySystems/PlanetLightSystem.cs b/Content.Client/Light/EntitySystems/PlanetLightSystem.cs new file mode 100644 index 0000000000..2da67137ed --- /dev/null +++ b/Content.Client/Light/EntitySystems/PlanetLightSystem.cs @@ -0,0 +1,36 @@ +using Robust.Client.Graphics; + +namespace Content.Client.Light.EntitySystems; + +public sealed class PlanetLightSystem : EntitySystem +{ + [Dependency] private readonly IOverlayManager _overlayMan = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnClearColor); + + _overlayMan.AddOverlay(new BeforeLightTargetOverlay()); + _overlayMan.AddOverlay(new RoofOverlay(EntityManager)); + _overlayMan.AddOverlay(new TileEmissionOverlay(EntityManager)); + _overlayMan.AddOverlay(new LightBlurOverlay()); + _overlayMan.AddOverlay(new AfterLightTargetOverlay()); + } + + private void OnClearColor(ref GetClearColorEvent ev) + { + ev.Color = Color.Transparent; + } + + public override void Shutdown() + { + base.Shutdown(); + _overlayMan.RemoveOverlay(); + _overlayMan.RemoveOverlay(); + _overlayMan.RemoveOverlay(); + _overlayMan.RemoveOverlay(); + _overlayMan.RemoveOverlay(); + } +} diff --git a/Content.Client/Light/EntitySystems/RoofSystem.cs b/Content.Client/Light/EntitySystems/RoofSystem.cs new file mode 100644 index 0000000000..559eea40fc --- /dev/null +++ b/Content.Client/Light/EntitySystems/RoofSystem.cs @@ -0,0 +1,9 @@ +using Content.Shared.Light.EntitySystems; + +namespace Content.Client.Light.EntitySystems; + +/// +public sealed class RoofSystem : SharedRoofSystem +{ + +} diff --git a/Content.Client/Light/LightBlurOverlay.cs b/Content.Client/Light/LightBlurOverlay.cs new file mode 100644 index 0000000000..4ce80946aa --- /dev/null +++ b/Content.Client/Light/LightBlurOverlay.cs @@ -0,0 +1,44 @@ +using Robust.Client.Graphics; +using Robust.Shared.Enums; + +namespace Content.Client.Light; + +/// +/// Essentially handles blurring for content-side light overlays. +/// +public sealed class LightBlurOverlay : Overlay +{ + public override OverlaySpace Space => OverlaySpace.BeforeLighting; + + [Dependency] private readonly IClyde _clyde = default!; + [Dependency] private readonly IOverlayManager _overlay = default!; + + public const int ContentZIndex = TileEmissionOverlay.ContentZIndex + 1; + + private IRenderTarget? _blurTarget; + + public LightBlurOverlay() + { + IoCManager.InjectDependencies(this); + ZIndex = ContentZIndex; + } + + protected override void Draw(in OverlayDrawArgs args) + { + if (args.Viewport.Eye == null) + return; + + var beforeOverlay = _overlay.GetOverlay(); + var size = beforeOverlay.EnlargedLightTarget.Size; + + if (_blurTarget?.Size != size) + { + _blurTarget = _clyde + .CreateRenderTarget(size, new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb), name: "enlarged-light-blur"); + } + + var target = beforeOverlay.EnlargedLightTarget; + // Yeah that's all this does keep walkin. + _clyde.BlurRenderTarget(args.Viewport, target, _blurTarget, args.Viewport.Eye, 14f * 5f); + } +} diff --git a/Content.Client/Light/LightCycleSystem.cs b/Content.Client/Light/LightCycleSystem.cs new file mode 100644 index 0000000000..9e19423cc3 --- /dev/null +++ b/Content.Client/Light/LightCycleSystem.cs @@ -0,0 +1,33 @@ +using Content.Client.GameTicking.Managers; +using Content.Shared; +using Content.Shared.Light.Components; +using Robust.Shared.Map.Components; +using Robust.Shared.Timing; + +namespace Content.Client.Light; + +/// +public sealed class LightCycleSystem : SharedLightCycleSystem +{ + [Dependency] private readonly ClientGameTicker _ticker = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Update(float frameTime) + { + base.Update(frameTime); + var mapQuery = AllEntityQuery(); + while (mapQuery.MoveNext(out var uid, out var cycle, out var map)) + { + if (!cycle.Running) + continue; + + var time = (float) _timing.CurTime + .Add(cycle.Offset) + .Subtract(_ticker.RoundStartTimeSpan) + .TotalSeconds; + + var color = GetColor((uid, cycle), cycle.OriginalColor, time); + map.AmbientLightColor = color; + } + } +} diff --git a/Content.Client/Light/RoofOverlay.cs b/Content.Client/Light/RoofOverlay.cs new file mode 100644 index 0000000000..5543103cdc --- /dev/null +++ b/Content.Client/Light/RoofOverlay.cs @@ -0,0 +1,122 @@ +using System.Numerics; +using Content.Shared.Light.Components; +using Content.Shared.Maps; +using Robust.Client.Graphics; +using Robust.Shared.Enums; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Physics; + +namespace Content.Client.Light; + +public sealed class RoofOverlay : Overlay +{ + private readonly IEntityManager _entManager; + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly IOverlayManager _overlay = default!; + + private readonly EntityLookupSystem _lookup; + private readonly SharedMapSystem _mapSystem; + private readonly SharedTransformSystem _xformSystem; + + private readonly HashSet> _occluders = new(); + private List> _grids = new(); + + public override OverlaySpace Space => OverlaySpace.BeforeLighting; + + public const int ContentZIndex = BeforeLightTargetOverlay.ContentZIndex + 1; + + public RoofOverlay(IEntityManager entManager) + { + _entManager = entManager; + IoCManager.InjectDependencies(this); + + _lookup = _entManager.System(); + _mapSystem = _entManager.System(); + _xformSystem = _entManager.System(); + + ZIndex = ContentZIndex; + } + + protected override void Draw(in OverlayDrawArgs args) + { + if (args.Viewport.Eye == null) + return; + + var viewport = args.Viewport; + var eye = args.Viewport.Eye; + + var worldHandle = args.WorldHandle; + var lightoverlay = _overlay.GetOverlay(); + var bounds = lightoverlay.EnlargedBounds; + var target = lightoverlay.EnlargedLightTarget; + + _grids.Clear(); + _mapManager.FindGridsIntersecting(args.MapId, bounds, ref _grids); + + for (var i = _grids.Count - 1; i >= 0; i--) + { + var grid = _grids[i]; + + if (_entManager.HasComponent(grid.Owner)) + continue; + + _grids.RemoveAt(i); + } + + if (_grids.Count == 0) + return; + + var lightScale = viewport.LightRenderTarget.Size / (Vector2) viewport.Size; + var scale = viewport.RenderScale / (Vector2.One / lightScale); + + worldHandle.RenderInRenderTarget(target, + () => + { + foreach (var grid in _grids) + { + if (!_entManager.TryGetComponent(grid.Owner, out RoofComponent? roof)) + continue; + + var invMatrix = target.GetWorldToLocalMatrix(eye, scale); + + var gridMatrix = _xformSystem.GetWorldMatrix(grid.Owner); + var matty = Matrix3x2.Multiply(gridMatrix, invMatrix); + + worldHandle.SetTransform(matty); + + var tileEnumerator = _mapSystem.GetTilesEnumerator(grid.Owner, grid, bounds); + + // Due to stencilling we essentially draw on unrooved tiles + while (tileEnumerator.MoveNext(out var tileRef)) + { + if ((tileRef.Tile.Flags & (byte) TileFlag.Roof) == 0x0) + { + // Check if the tile is occluded in which case hide it anyway. + // This is to avoid lit walls bleeding over to unlit tiles. + _occluders.Clear(); + _lookup.GetLocalEntitiesIntersecting(grid.Owner, tileRef.GridIndices, _occluders); + var found = false; + + foreach (var occluder in _occluders) + { + if (!occluder.Comp.Enabled) + continue; + + found = true; + break; + } + + if (!found) + continue; + } + + var local = _lookup.GetLocalBounds(tileRef, grid.Comp.TileSize); + worldHandle.DrawRect(local, roof.Color); + } + } + }, null); + + worldHandle.SetTransform(Matrix3x2.Identity); + } +} diff --git a/Content.Client/Light/TileEmissionOverlay.cs b/Content.Client/Light/TileEmissionOverlay.cs new file mode 100644 index 0000000000..2f4a1390ff --- /dev/null +++ b/Content.Client/Light/TileEmissionOverlay.cs @@ -0,0 +1,96 @@ +using System.Numerics; +using Content.Shared.Light.Components; +using Robust.Client.Graphics; +using Robust.Shared.Enums; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; + +namespace Content.Client.Light; + +public sealed class TileEmissionOverlay : Overlay +{ + public override OverlaySpace Space => OverlaySpace.BeforeLighting; + + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly IOverlayManager _overlay = default!; + + private SharedMapSystem _mapSystem; + private SharedTransformSystem _xformSystem; + + private readonly EntityLookupSystem _lookup; + + private readonly EntityQuery _xformQuery; + private readonly HashSet> _entities = new(); + + private List> _grids = new(); + + public const int ContentZIndex = RoofOverlay.ContentZIndex + 1; + + public TileEmissionOverlay(IEntityManager entManager) + { + IoCManager.InjectDependencies(this); + + _lookup = entManager.System(); + _mapSystem = entManager.System(); + _xformSystem = entManager.System(); + + _xformQuery = entManager.GetEntityQuery(); + ZIndex = ContentZIndex; + } + + protected override void Draw(in OverlayDrawArgs args) + { + if (args.Viewport.Eye == null) + return; + + var mapId = args.MapId; + var worldHandle = args.WorldHandle; + var lightoverlay = _overlay.GetOverlay(); + var bounds = lightoverlay.EnlargedBounds; + var target = lightoverlay.EnlargedLightTarget; + var viewport = args.Viewport; + _grids.Clear(); + _mapManager.FindGridsIntersecting(mapId, bounds, ref _grids, approx: true); + + if (_grids.Count == 0) + return; + + var lightScale = viewport.LightRenderTarget.Size / (Vector2) viewport.Size; + var scale = viewport.RenderScale / (Vector2.One / lightScale); + + args.WorldHandle.RenderInRenderTarget(target, + () => + { + var invMatrix = target.GetWorldToLocalMatrix(viewport.Eye, scale); + + foreach (var grid in _grids) + { + var gridInvMatrix = _xformSystem.GetInvWorldMatrix(grid); + var localBounds = gridInvMatrix.TransformBox(bounds); + _entities.Clear(); + _lookup.GetLocalEntitiesIntersecting(grid.Owner, localBounds, _entities); + + if (_entities.Count == 0) + continue; + + var gridMatrix = _xformSystem.GetWorldMatrix(grid.Owner); + + foreach (var ent in _entities) + { + var xform = _xformQuery.Comp(ent); + + var tile = _mapSystem.LocalToTile(grid.Owner, grid, xform.Coordinates); + var matty = Matrix3x2.Multiply(gridMatrix, invMatrix); + + worldHandle.SetTransform(matty); + + // Yes I am fully aware this leads to overlap. If you really want to have alpha then you'll need + // to turn the squares into polys. + // Additionally no shadows so if you make it too big it's going to go through a 1x wall. + var local = _lookup.GetLocalBounds(tile, grid.Comp.TileSize).Enlarged(ent.Comp.Range); + worldHandle.DrawRect(local, ent.Comp.Color); + } + } + }, null); + } +} diff --git a/Content.Client/Lobby/UI/Loadouts/LoadoutWindow.xaml b/Content.Client/Lobby/UI/Loadouts/LoadoutWindow.xaml index e4e44f75a9..1302ea9cc1 100644 --- a/Content.Client/Lobby/UI/Loadouts/LoadoutWindow.xaml +++ b/Content.Client/Lobby/UI/Loadouts/LoadoutWindow.xaml @@ -6,7 +6,7 @@ MinSize="800 128"> -