diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5e1b9d65fac225..25e75bdbf8cd5f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,6 +13,9 @@ jobs: runs-on: ubuntu-latest steps: + - name: Install dependencies + run: sudo apt-get install -y python3-paramiko + - uses: actions/checkout@v2 with: submodules: 'recursive' @@ -57,8 +60,13 @@ jobs: key: ${{ secrets.CENTCOMM_WIZARDS_BUILDS_PUSH_KEY }} script: /home/wizards-build-push/push.ps1 ${{ github.sha }} - - name: Publish changelog + - name: Publish changelog (Discord) run: Tools/actions_changelogs_since_last_run.py env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} DISCORD_WEBHOOK_URL: ${{ secrets.CHANGELOG_DISCORD_WEBHOOK }} + + - name: Publish changelog (RSS) + run: Tools/actions_changelog_rss.py + env: + CHANGELOG_RSS_KEY: ${{ secrets.CHANGELOG_RSS_KEY }} diff --git a/Content.Benchmarks/DeviceNetworkingBenchmark.cs b/Content.Benchmarks/DeviceNetworkingBenchmark.cs index 27e5000bc0eac1..7694c0f37f2538 100644 --- a/Content.Benchmarks/DeviceNetworkingBenchmark.cs +++ b/Content.Benchmarks/DeviceNetworkingBenchmark.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; using BenchmarkDotNet.Attributes; using Content.IntegrationTests; @@ -9,7 +8,6 @@ using Robust.Shared; using Robust.Shared.Analyzers; using Robust.Shared.GameObjects; -using Robust.Shared.IoC; using Robust.Shared.Map; namespace Content.Benchmarks; @@ -23,8 +21,8 @@ public class DeviceNetworkingBenchmark private DeviceNetworkSystem _deviceNetworkSystem = default!; private EntityUid _sourceEntity; private EntityUid _sourceWirelessEntity; - private List _targetEntities = new(); - private List _targetWirelessEntities = new(); + private readonly List _targetEntities = new(); + private readonly List _targetWirelessEntities = new(); private NetworkPayload _payload = default!; @@ -58,7 +56,7 @@ public class DeviceNetworkingBenchmark public async Task SetupAsync() { ProgramShared.PathOffset = "../../../../"; - _pair = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes}); + _pair = await PoolManager.GetServerClient(new PoolSettings { NoClient = true, ExtraPrototypes = Prototypes }); var server = _pair.Pair.Server; await server.WaitPost(() => diff --git a/Content.Benchmarks/DynamicTreeBenchmark.cs b/Content.Benchmarks/DynamicTreeBenchmark.cs index ab489966b7868e..4f3dad40738014 100644 --- a/Content.Benchmarks/DynamicTreeBenchmark.cs +++ b/Content.Benchmarks/DynamicTreeBenchmark.cs @@ -9,7 +9,7 @@ namespace Content.Benchmarks [Virtual] public class DynamicTreeBenchmark { - private static readonly Box2[] _aabbs1 = + private static readonly Box2[] Aabbs1 = { ((Box2) default).Enlarged(1), //2x2 square ((Box2) default).Enlarged(2), //4x4 square @@ -39,11 +39,11 @@ public class DynamicTreeBenchmark public void Setup() { _b2Tree = new B2DynamicTree(); - _tree = new DynamicTree((in int value) => _aabbs1[value], capacity: 16); + _tree = new DynamicTree((in int value) => Aabbs1[value], capacity: 16); - for (var i = 0; i < _aabbs1.Length; i++) + for (var i = 0; i < Aabbs1.Length; i++) { - var aabb = _aabbs1[i]; + var aabb = Aabbs1[i]; _b2Tree.CreateProxy(aabb, i); _tree.Add(i); } diff --git a/Content.Benchmarks/EntityFetchBenchmark.cs b/Content.Benchmarks/EntityFetchBenchmark.cs index d65b7faeddc4d2..63e6e777edc4f4 100644 --- a/Content.Benchmarks/EntityFetchBenchmark.cs +++ b/Content.Benchmarks/EntityFetchBenchmark.cs @@ -189,9 +189,7 @@ private abstract class EntityStorage : IEntityStorage { private (int generation, GenEntity entity)[] _entities = new (int, GenEntity)[1]; - private readonly List _availableSlots = new() {0}; + private readonly List _availableSlots = new() { 0 }; public override bool TryGetEntity(GenEntityUid entityUid, out GenEntity entity) { diff --git a/Content.Benchmarks/EntityManagerGetAllComponents.cs b/Content.Benchmarks/EntityManagerGetAllComponents.cs index 4266b9d708d96c..eb9b2c6a7136f3 100644 --- a/Content.Benchmarks/EntityManagerGetAllComponents.cs +++ b/Content.Benchmarks/EntityManagerGetAllComponents.cs @@ -48,7 +48,7 @@ public void Setup() var componentFactory = new Mock(); componentFactory.Setup(p => p.GetComponent()).Returns(new DummyComponent()); componentFactory.Setup(p => p.GetRegistration(It.IsAny())).Returns(dummyReg); - componentFactory.Setup(p => p.GetAllRefTypes()).Returns(new[] {CompIdx.Index()}); + componentFactory.Setup(p => p.GetAllRefTypes()).Returns(new[] { CompIdx.Index() }); IoCManager.RegisterInstance(componentFactory.Object); diff --git a/Content.Benchmarks/MapLoadBenchmark.cs b/Content.Benchmarks/MapLoadBenchmark.cs index f7a1e409a4872d..bd4213e4385960 100644 --- a/Content.Benchmarks/MapLoadBenchmark.cs +++ b/Content.Benchmarks/MapLoadBenchmark.cs @@ -45,9 +45,10 @@ public async Task Cleanup() public static IEnumerable MapsSource { get; set; } - [ParamsSource(nameof(MapsSource))] public string Map; + [ParamsSource(nameof(MapsSource))] + public string Map; - public static Dictionary Paths; + public Dictionary Paths; [Benchmark] public async Task LoadMap() diff --git a/Content.Benchmarks/NetSerializerIntBenchmark.cs b/Content.Benchmarks/NetSerializerIntBenchmark.cs index 98441852098cfb..42afc80a1b4d26 100644 --- a/Content.Benchmarks/NetSerializerIntBenchmark.cs +++ b/Content.Benchmarks/NetSerializerIntBenchmark.cs @@ -12,9 +12,9 @@ public class NetSerializerIntBenchmark { private MemoryStream _writeStream; private MemoryStream _readStream; - private ushort _x16 = 5; - private uint _x32 = 5; - private ulong _x64 = 5; + private readonly ushort _x16 = 5; + private readonly uint _x32 = 5; + private readonly ulong _x64 = 5; private ushort _read16; private uint _read32; private ulong _read64; @@ -24,7 +24,7 @@ public void Setup() { _writeStream = new MemoryStream(64); _readStream = new MemoryStream(); - _readStream.Write(new byte[]{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}); + _readStream.Write(new byte[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 }); } [Benchmark] diff --git a/Content.Benchmarks/NetSerializerStringBenchmark.cs b/Content.Benchmarks/NetSerializerStringBenchmark.cs index 2b1b143117b418..711d3395a77568 100644 --- a/Content.Benchmarks/NetSerializerStringBenchmark.cs +++ b/Content.Benchmarks/NetSerializerStringBenchmark.cs @@ -48,7 +48,7 @@ public void BenchWriteCore() public void BenchReadCore() { _inputStream.Position = 0; - ReadPrimitiveCore(_inputStream, out string _); + ReadPrimitiveCore(_inputStream, out _); } [Benchmark] @@ -62,7 +62,7 @@ public void BenchWriteUnsafe() public void BenchReadUnsafe() { _inputStream.Position = 0; - ReadPrimitiveUnsafe(_inputStream, out string _); + ReadPrimitiveUnsafe(_inputStream, out _); } [Benchmark] @@ -76,329 +76,356 @@ public void BenchWriteSlow() public void BenchReadSlow() { _inputStream.Position = 0; - ReadPrimitiveSlow(_inputStream, out string _); + ReadPrimitiveSlow(_inputStream, out _); } - public static void WritePrimitiveCore(Stream stream, string value) - { - if (value == null) - { - Primitives.WritePrimitive(stream, (uint)0); - return; - } - - if (value.Length == 0) - { - Primitives.WritePrimitive(stream, (uint)1); - return; - } - - Span buf = stackalloc byte[StringByteBufferLength]; - - var totalChars = value.Length; - var totalBytes = Encoding.UTF8.GetByteCount(value); - - Primitives.WritePrimitive(stream, (uint)totalBytes + 1); - Primitives.WritePrimitive(stream, (uint)totalChars); - - var totalRead = 0; - ReadOnlySpan span = value; - for (;;) - { - var finalChunk = totalRead + totalChars >= totalChars; - Utf8.FromUtf16(span, buf, out var read, out var wrote, isFinalBlock: finalChunk); - stream.Write(buf.Slice(0, wrote)); - totalRead += read; - if (read >= totalChars) - { - break; - } - - span = span[read..]; - totalChars -= read; - } - } - - private static readonly SpanAction _stringSpanRead = StringSpanRead; - - public static void ReadPrimitiveCore(Stream stream, out string value) - { - Primitives.ReadPrimitive(stream, out uint totalBytes); - - if (totalBytes == 0) - { - value = null; - return; - } - - if (totalBytes == 1) - { - value = string.Empty; - return; - } - - totalBytes -= 1; + public static void WritePrimitiveCore(Stream stream, string value) + { + if (value == null) + { + Primitives.WritePrimitive(stream, (uint) 0); + return; + } + + if (value.Length == 0) + { + Primitives.WritePrimitive(stream, (uint) 1); + return; + } + + Span buf = stackalloc byte[StringByteBufferLength]; + + var totalChars = value.Length; + var totalBytes = Encoding.UTF8.GetByteCount(value); + + Primitives.WritePrimitive(stream, (uint) totalBytes + 1); + Primitives.WritePrimitive(stream, (uint) totalChars); + + var totalRead = 0; + ReadOnlySpan span = value; + while (true) + { + var finalChunk = totalRead + totalChars >= totalChars; + Utf8.FromUtf16(span, buf, out var read, out var wrote, isFinalBlock: finalChunk); + stream.Write(buf[0..wrote]); + totalRead += read; + if (read >= totalChars) + { + break; + } + + span = span[read..]; + totalChars -= read; + } + } + + public static void ReadPrimitiveCore(Stream stream, out string value) + { + Primitives.ReadPrimitive(stream, out uint totalBytes); + + if (totalBytes == 0) + { + value = null; + return; + } + + if (totalBytes == 1) + { + value = string.Empty; + return; + } + + totalBytes -= 1; Primitives.ReadPrimitive(stream, out uint totalChars); - value = string.Create((int) totalChars, ((int) totalBytes, stream), _stringSpanRead); - } - - private static void StringSpanRead(Span span, (int totalBytes, Stream stream) tuple) - { - Span buf = stackalloc byte[StringByteBufferLength]; - - // ReSharper disable VariableHidesOuterVariable - var (totalBytes, stream) = tuple; - // ReSharper restore VariableHidesOuterVariable - - var totalBytesRead = 0; - var totalCharsRead = 0; - var writeBufStart = 0; - - while (totalBytesRead < totalBytes) - { - var bytesLeft = totalBytes - totalBytesRead; - var bytesReadLeft = Math.Min(buf.Length, bytesLeft); - var writeSlice = buf.Slice(writeBufStart, bytesReadLeft - writeBufStart); - var bytesInBuffer = stream.Read(writeSlice); - if (bytesInBuffer == 0) throw new EndOfStreamException(); - - var readFromStream = bytesInBuffer + writeBufStart; - var final = readFromStream == bytesLeft; - var status = Utf8.ToUtf16(buf[..readFromStream], span[totalCharsRead..], out var bytesRead, out var charsRead, isFinalBlock: final); - - totalBytesRead += bytesRead; - totalCharsRead += charsRead; - writeBufStart = 0; - - if (status == OperationStatus.DestinationTooSmall) - { - // Malformed data? - throw new InvalidDataException(); - } - - if (status == OperationStatus.NeedMoreData) - { - // We got cut short in the middle of a multi-byte UTF-8 sequence. - // So we need to move it to the bottom of the span, then read the next bit *past* that. - // This copy should be fine because we're only ever gonna be copying up to 4 bytes - // from the end of the buffer to the start. - // So no chance of overlap. - buf[bytesRead..].CopyTo(buf); - writeBufStart = bytesReadLeft - bytesRead; - continue; - } - - Debug.Assert(status == OperationStatus.Done); - } - } - - public static void WritePrimitiveSlow(Stream stream, string value) - { - if (value == null) - { - Primitives.WritePrimitive(stream, (uint)0); - return; - } - else if (value.Length == 0) - { - Primitives.WritePrimitive(stream, (uint)1); - return; - } - - var encoding = new UTF8Encoding(false, true); - - int len = encoding.GetByteCount(value); - - Primitives.WritePrimitive(stream, (uint)len + 1); - Primitives.WritePrimitive(stream, (uint)value.Length); - - var buf = new byte[len]; - - encoding.GetBytes(value, 0, value.Length, buf, 0); - - stream.Write(buf, 0, len); - } - - public static void ReadPrimitiveSlow(Stream stream, out string value) - { - uint len; - Primitives.ReadPrimitive(stream, out len); - - if (len == 0) - { - value = null; - return; - } - else if (len == 1) - { - value = string.Empty; - return; - } - - uint totalChars; - Primitives.ReadPrimitive(stream, out totalChars); - - len -= 1; - - var encoding = new UTF8Encoding(false, true); - - var buf = new byte[len]; - - int l = 0; - - while (l < len) - { - int r = stream.Read(buf, l, (int)len - l); - if (r == 0) - throw new EndOfStreamException(); - l += r; - } - - value = encoding.GetString(buf); - } - - sealed class StringHelper - { - public StringHelper() - { - this.Encoding = new UTF8Encoding(false, true); - } - - Encoder m_encoder; - Decoder m_decoder; - - byte[] m_byteBuffer; - char[] m_charBuffer; - - public UTF8Encoding Encoding { get; private set; } - public Encoder Encoder { get { if (m_encoder == null) m_encoder = this.Encoding.GetEncoder(); return m_encoder; } } - public Decoder Decoder { get { if (m_decoder == null) m_decoder = this.Encoding.GetDecoder(); return m_decoder; } } - - public byte[] ByteBuffer { get { if (m_byteBuffer == null) m_byteBuffer = new byte[StringByteBufferLength]; return m_byteBuffer; } } - public char[] CharBuffer { get { if (m_charBuffer == null) m_charBuffer = new char[StringCharBufferLength]; return m_charBuffer; } } - } - - [ThreadStatic] - static StringHelper s_stringHelper; - - public unsafe static void WritePrimitiveUnsafe(Stream stream, string value) - { - if (value == null) - { - Primitives.WritePrimitive(stream, (uint)0); - return; - } - else if (value.Length == 0) - { - Primitives.WritePrimitive(stream, (uint)1); - return; - } - - var helper = s_stringHelper; - if (helper == null) - s_stringHelper = helper = new StringHelper(); - - var encoder = helper.Encoder; - var buf = helper.ByteBuffer; - - int totalChars = value.Length; - int totalBytes; + value = string.Create((int) totalChars, ((int) totalBytes, stream), StringSpanRead); + } + + private static void StringSpanRead(Span span, (int totalBytes, Stream stream) tuple) + { + Span buf = stackalloc byte[StringByteBufferLength]; + + // ReSharper disable VariableHidesOuterVariable + var (totalBytes, stream) = tuple; + // ReSharper restore VariableHidesOuterVariable + + var totalBytesRead = 0; + var totalCharsRead = 0; + var writeBufStart = 0; + + while (totalBytesRead < totalBytes) + { + var bytesLeft = totalBytes - totalBytesRead; + var bytesReadLeft = Math.Min(buf.Length, bytesLeft); + var writeSlice = buf[writeBufStart..(bytesReadLeft - writeBufStart)]; + var bytesInBuffer = stream.Read(writeSlice); + if (bytesInBuffer == 0) throw new EndOfStreamException(); + + var readFromStream = bytesInBuffer + writeBufStart; + var final = readFromStream == bytesLeft; + var status = Utf8.ToUtf16(buf[..readFromStream], span[totalCharsRead..], out var bytesRead, out var charsRead, isFinalBlock: final); + + totalBytesRead += bytesRead; + totalCharsRead += charsRead; + writeBufStart = 0; + + if (status == OperationStatus.DestinationTooSmall) + { + // Malformed data? + throw new InvalidDataException(); + } + + if (status == OperationStatus.NeedMoreData) + { + // We got cut short in the middle of a multi-byte UTF-8 sequence. + // So we need to move it to the bottom of the span, then read the next bit *past* that. + // This copy should be fine because we're only ever gonna be copying up to 4 bytes + // from the end of the buffer to the start. + // So no chance of overlap. + buf[bytesRead..].CopyTo(buf); + writeBufStart = bytesReadLeft - bytesRead; + continue; + } + + Debug.Assert(status == OperationStatus.Done); + } + } + + public static void WritePrimitiveSlow(Stream stream, string value) + { + if (value == null) + { + Primitives.WritePrimitive(stream, (uint) 0); + return; + } + else if (value.Length == 0) + { + Primitives.WritePrimitive(stream, (uint) 1); + return; + } + + var encoding = new UTF8Encoding(false, true); + + var len = encoding.GetByteCount(value); + + Primitives.WritePrimitive(stream, (uint) len + 1); + Primitives.WritePrimitive(stream, (uint) value.Length); + + var buf = new byte[len]; + + encoding.GetBytes(value, 0, value.Length, buf, 0); + + stream.Write(buf, 0, len); + } + + public static void ReadPrimitiveSlow(Stream stream, out string value) + { + Primitives.ReadPrimitive(stream, out uint len); + + if (len == 0) + { + value = null; + return; + } + else if (len == 1) + { + value = string.Empty; + return; + } + + Primitives.ReadPrimitive(stream, out uint _); + + len -= 1; + + var encoding = new UTF8Encoding(false, true); + + var buf = new byte[len]; + + var l = 0; + + while (l < len) + { + var r = stream.Read(buf, l, (int) len - l); + if (r == 0) + throw new EndOfStreamException(); + l += r; + } + + value = encoding.GetString(buf); + } + + private sealed class StringHelper + { + public StringHelper() + { + Encoding = new UTF8Encoding(false, true); + } + + private Encoder _encoder; + private Decoder _decoder; + + private byte[] _byteBuffer; + private char[] _charBuffer; + + public UTF8Encoding Encoding { get; private set; } + public Encoder Encoder + { + get + { + _encoder ??= Encoding.GetEncoder(); + return _encoder; + } + } + public Decoder Decoder + { + get + { + _decoder ??= Encoding.GetDecoder(); + return _decoder; + } + } + + public byte[] ByteBuffer + { + get + { + _byteBuffer ??= new byte[StringByteBufferLength]; + return _byteBuffer; + } + } + public char[] CharBuffer + { + get + { + _charBuffer ??= new char[StringCharBufferLength]; + return _charBuffer; + } + } + } + + [ThreadStatic] + private static StringHelper _stringHelper; + + public static unsafe void WritePrimitiveUnsafe(Stream stream, string value) + { + if (value == null) + { + Primitives.WritePrimitive(stream, (uint) 0); + return; + } + else if (value.Length == 0) + { + Primitives.WritePrimitive(stream, (uint) 1); + return; + } + + var helper = _stringHelper; + if (helper == null) + _stringHelper = helper = new StringHelper(); + + var encoder = helper.Encoder; + var buf = helper.ByteBuffer; + + var totalChars = value.Length; + int totalBytes; + + fixed (char* ptr = value) + totalBytes = encoder.GetByteCount(ptr, totalChars, true); + + Primitives.WritePrimitive(stream, (uint) totalBytes + 1); + Primitives.WritePrimitive(stream, (uint) totalChars); + + var p = 0; + var completed = false; + + while (completed == false) + { + int charsConverted; + int bytesConverted; + + fixed (char* src = value) + fixed (byte* dst = buf) + { + encoder.Convert(src + p, totalChars - p, dst, buf.Length, true, + out charsConverted, out bytesConverted, out completed); + } + + stream.Write(buf, 0, bytesConverted); + + p += charsConverted; + } + } - fixed (char* ptr = value) - totalBytes = encoder.GetByteCount(ptr, totalChars, true); - - Primitives.WritePrimitive(stream, (uint)totalBytes + 1); - Primitives.WritePrimitive(stream, (uint)totalChars); - - int p = 0; - bool completed = false; - - while (completed == false) - { - int charsConverted; - int bytesConverted; - - fixed (char* src = value) - fixed (byte* dst = buf) - { - encoder.Convert(src + p, totalChars - p, dst, buf.Length, true, - out charsConverted, out bytesConverted, out completed); - } - - stream.Write(buf, 0, bytesConverted); - - p += charsConverted; - } - } - - public static void ReadPrimitiveUnsafe(Stream stream, out string value) - { - uint totalBytes; - Primitives.ReadPrimitive(stream, out totalBytes); - - if (totalBytes == 0) - { - value = null; - return; - } - else if (totalBytes == 1) - { - value = string.Empty; - return; - } - - totalBytes -= 1; - - uint totalChars; - Primitives.ReadPrimitive(stream, out totalChars); - - var helper = s_stringHelper; - if (helper == null) - s_stringHelper = helper = new StringHelper(); - - var decoder = helper.Decoder; - var buf = helper.ByteBuffer; - char[] chars; - if (totalChars <= StringCharBufferLength) - chars = helper.CharBuffer; - else - chars = new char[totalChars]; - - int streamBytesLeft = (int)totalBytes; - - int cp = 0; - - while (streamBytesLeft > 0) - { - int bytesInBuffer = stream.Read(buf, 0, Math.Min(buf.Length, streamBytesLeft)); - if (bytesInBuffer == 0) - throw new EndOfStreamException(); - - streamBytesLeft -= bytesInBuffer; - bool flush = streamBytesLeft == 0; - - bool completed = false; - - int p = 0; - - while (completed == false) - { - int charsConverted; - int bytesConverted; - - decoder.Convert(buf, p, bytesInBuffer - p, - chars, cp, (int)totalChars - cp, - flush, - out bytesConverted, out charsConverted, out completed); - - p += bytesConverted; - cp += charsConverted; - } - } + public static void ReadPrimitiveUnsafe(Stream stream, out string value) + { + Primitives.ReadPrimitive(stream, out uint totalBytes); - value = new string(chars, 0, (int)totalChars); - } + if (totalBytes == 0) + { + value = null; + return; + } + else if (totalBytes == 1) + { + value = string.Empty; + return; + } + + totalBytes -= 1; + + Primitives.ReadPrimitive(stream, out uint totalChars); + + var helper = _stringHelper; + if (helper == null) + _stringHelper = helper = new StringHelper(); + + var decoder = helper.Decoder; + var buf = helper.ByteBuffer; + char[] chars; + if (totalChars <= StringCharBufferLength) + chars = helper.CharBuffer; + else + chars = new char[totalChars]; + + var streamBytesLeft = (int) totalBytes; + + var cp = 0; + + while (streamBytesLeft > 0) + { + var bytesInBuffer = stream.Read(buf, 0, Math.Min(buf.Length, streamBytesLeft)); + if (bytesInBuffer == 0) + throw new EndOfStreamException(); + + streamBytesLeft -= bytesInBuffer; + var flush = streamBytesLeft == 0; + + var completed = false; + + var p = 0; + + while (completed == false) + { + decoder.Convert( + buf, + p, + bytesInBuffer - p, + chars, + cp, + (int) totalChars - cp, + flush, + out var bytesConverted, + out var charsConverted, + out completed + ); + + p += bytesConverted; + cp += charsConverted; + } + } + + value = new string(chars, 0, (int) totalChars); + } } } diff --git a/Content.Client/AME/AMEControllerVisualizerSystem.cs b/Content.Client/AME/AMEControllerVisualizerSystem.cs deleted file mode 100644 index c80963fc647f43..00000000000000 --- a/Content.Client/AME/AMEControllerVisualizerSystem.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Content.Client.AME.Components; -using Robust.Client.GameObjects; -using static Content.Shared.AME.SharedAMEControllerComponent; - -namespace Content.Client.AME; - -public sealed class AMEControllerVisualizerSystem : VisualizerSystem -{ - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnComponentInit); - } - - private void OnComponentInit(EntityUid uid, AMEControllerVisualsComponent component, ComponentInit args) - { - if (TryComp(uid, out var sprite)) - { - sprite.LayerMapSet(AMEControllerVisualLayers.Display, sprite.AddLayerState("control_on")); - sprite.LayerSetVisible(AMEControllerVisualLayers.Display, false); - } - } - - protected override void OnAppearanceChange(EntityUid uid, AMEControllerVisualsComponent component, ref AppearanceChangeEvent args) - { - base.OnAppearanceChange(uid, component, ref args); - - if (args.Sprite == null - || !AppearanceSystem.TryGetData(uid, AMEControllerVisuals.DisplayState, out var state, args.Component)) - { - return; - } - - switch (state) - { - case "on": - args.Sprite.LayerSetState(AMEControllerVisualLayers.Display, "control_on"); - args.Sprite.LayerSetVisible(AMEControllerVisualLayers.Display, true); - break; - case "critical": - args.Sprite.LayerSetState(AMEControllerVisualLayers.Display, "control_critical"); - args.Sprite.LayerSetVisible(AMEControllerVisualLayers.Display, true); - break; - case "fuck": - args.Sprite.LayerSetState(AMEControllerVisualLayers.Display, "control_fuck"); - args.Sprite.LayerSetVisible(AMEControllerVisualLayers.Display, true); - break; - case "off": - args.Sprite.LayerSetVisible(AMEControllerVisualLayers.Display, false); - break; - default: - args.Sprite.LayerSetVisible(AMEControllerVisualLayers.Display, false); - break; - } - } -} - -public enum AMEControllerVisualLayers : byte -{ - Display -} - diff --git a/Content.Client/AME/AMEShieldingVisualizerSystem.cs b/Content.Client/AME/AMEShieldingVisualizerSystem.cs deleted file mode 100644 index 7e225cc4ada2fe..00000000000000 --- a/Content.Client/AME/AMEShieldingVisualizerSystem.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Content.Client.AME.Components; -using Robust.Client.GameObjects; -using static Content.Shared.AME.SharedAMEShieldComponent; - -namespace Content.Client.AME; - -public sealed class AMEShieldingVisualizerSystem : VisualizerSystem -{ - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnComponentInit); - } - - private void OnComponentInit(EntityUid uid, AMEShieldingVisualsComponent component, ComponentInit args) - { - if (TryComp(uid, out var sprite)) - { - sprite.LayerMapSet(AMEShieldingVisualsLayer.Core, sprite.AddLayerState("core")); - sprite.LayerSetVisible(AMEShieldingVisualsLayer.Core, false); - sprite.LayerMapSet(AMEShieldingVisualsLayer.CoreState, sprite.AddLayerState("core_weak")); - sprite.LayerSetVisible(AMEShieldingVisualsLayer.CoreState, false); - } - } - - protected override void OnAppearanceChange(EntityUid uid, AMEShieldingVisualsComponent component, ref AppearanceChangeEvent args) - { - if (args.Sprite == null) - return; - - if (AppearanceSystem.TryGetData(uid, AMEShieldVisuals.Core, out var core, args.Component)) - { - if (core == "isCore") - { - args.Sprite.LayerSetState(AMEShieldingVisualsLayer.Core, "core"); - args.Sprite.LayerSetVisible(AMEShieldingVisualsLayer.Core, true); - - } - else - { - args.Sprite.LayerSetVisible(AMEShieldingVisualsLayer.Core, false); - } - } - - if (AppearanceSystem.TryGetData(uid, AMEShieldVisuals.CoreState, out var coreState, args.Component)) - { - switch (coreState) - { - case "weak": - args.Sprite.LayerSetState(AMEShieldingVisualsLayer.CoreState, "core_weak"); - args.Sprite.LayerSetVisible(AMEShieldingVisualsLayer.CoreState, true); - break; - case "strong": - args.Sprite.LayerSetState(AMEShieldingVisualsLayer.CoreState, "core_strong"); - args.Sprite.LayerSetVisible(AMEShieldingVisualsLayer.CoreState, true); - break; - case "off": - args.Sprite.LayerSetVisible(AMEShieldingVisualsLayer.CoreState, false); - break; - } - } - } -} - -public enum AMEShieldingVisualsLayer : byte -{ - Core, - CoreState, -} diff --git a/Content.Client/AME/Components/AMEControllerVisualsComponent.cs b/Content.Client/AME/Components/AMEControllerVisualsComponent.cs deleted file mode 100644 index 282ddb357601c2..00000000000000 --- a/Content.Client/AME/Components/AMEControllerVisualsComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using Robust.Shared.GameObjects; - -namespace Content.Client.AME.Components; - -[RegisterComponent] -public sealed class AMEControllerVisualsComponent : Component -{ -} diff --git a/Content.Client/AME/Components/AMEShieldingVisualsComponent.cs b/Content.Client/AME/Components/AMEShieldingVisualsComponent.cs deleted file mode 100644 index 4254d809f3c778..00000000000000 --- a/Content.Client/AME/Components/AMEShieldingVisualsComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using Robust.Shared.GameObjects; - -namespace Content.Client.AME.Components; - -[RegisterComponent] -public sealed class AMEShieldingVisualsComponent : Component -{ -} diff --git a/Content.Client/AME/UI/AMEControllerBoundUserInterface.cs b/Content.Client/Ame/UI/AmeControllerBoundUserInterface.cs similarity index 68% rename from Content.Client/AME/UI/AMEControllerBoundUserInterface.cs rename to Content.Client/Ame/UI/AmeControllerBoundUserInterface.cs index 45bcce40a24282..a99a69747f4889 100644 --- a/Content.Client/AME/UI/AMEControllerBoundUserInterface.cs +++ b/Content.Client/Ame/UI/AmeControllerBoundUserInterface.cs @@ -1,17 +1,15 @@ -using Content.Shared.Chemistry.Dispenser; +using Content.Shared.Ame; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Shared.GameObjects; -using static Content.Shared.AME.SharedAMEControllerComponent; -namespace Content.Client.AME.UI +namespace Content.Client.Ame.UI { [UsedImplicitly] - public sealed class AMEControllerBoundUserInterface : BoundUserInterface + public sealed class AmeControllerBoundUserInterface : BoundUserInterface { - private AMEWindow? _window; + private AmeWindow? _window; - public AMEControllerBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey) + public AmeControllerBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey) { } @@ -19,7 +17,7 @@ protected override void Open() { base.Open(); - _window = new AMEWindow(this); + _window = new AmeWindow(this); _window.OnClose += Close; _window.OpenCentered(); } @@ -35,11 +33,11 @@ protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); - var castState = (AMEControllerBoundUserInterfaceState) state; + var castState = (AmeControllerBoundUserInterfaceState) state; _window?.UpdateState(castState); //Update window state } - public void ButtonPressed(UiButton button, int dispenseIndex = -1) + public void ButtonPressed(UiButton button) { SendMessage(new UiButtonPressedMessage(button)); } diff --git a/Content.Client/AME/UI/AMEWindow.xaml b/Content.Client/Ame/UI/AmeWindow.xaml similarity index 100% rename from Content.Client/AME/UI/AMEWindow.xaml rename to Content.Client/Ame/UI/AmeWindow.xaml diff --git a/Content.Client/AME/UI/AMEWindow.xaml.cs b/Content.Client/Ame/UI/AmeWindow.xaml.cs similarity index 83% rename from Content.Client/AME/UI/AMEWindow.xaml.cs rename to Content.Client/Ame/UI/AmeWindow.xaml.cs index da7abc75878aac..0ad8880becab82 100644 --- a/Content.Client/AME/UI/AMEWindow.xaml.cs +++ b/Content.Client/Ame/UI/AmeWindow.xaml.cs @@ -1,20 +1,15 @@ using Content.Client.UserInterface; +using Content.Shared.Ame; using Robust.Client.AutoGenerated; -using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Localization; -using static Content.Shared.AME.SharedAMEControllerComponent; -namespace Content.Client.AME.UI +namespace Content.Client.Ame.UI { [GenerateTypedNameReferences] - public sealed partial class AMEWindow : DefaultWindow + public sealed partial class AmeWindow : DefaultWindow { - public AMEWindow(AMEControllerBoundUserInterface ui) + public AmeWindow(AmeControllerBoundUserInterface ui) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); @@ -31,7 +26,7 @@ public AMEWindow(AMEControllerBoundUserInterface ui) /// State data sent by the server. public void UpdateState(BoundUserInterfaceState state) { - var castState = (AMEControllerBoundUserInterfaceState) state; + var castState = (AmeControllerBoundUserInterfaceState) state; // Disable all buttons if not powered if (Contents.Children != null) diff --git a/Content.Client/Atmos/Components/MapAtmosphereComponent.cs b/Content.Client/Atmos/Components/MapAtmosphereComponent.cs new file mode 100644 index 00000000000000..2f59eae43901b3 --- /dev/null +++ b/Content.Client/Atmos/Components/MapAtmosphereComponent.cs @@ -0,0 +1,9 @@ +using Content.Shared.Atmos.Components; + +namespace Content.Client.Atmos.Components; + +[RegisterComponent] +public sealed class MapAtmosphereComponent : SharedMapAtmosphereComponent +{ + +} diff --git a/Content.Client/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Client/Atmos/EntitySystems/AtmosphereSystem.cs index d7f9d60d83a4ad..44759372f4e4b5 100644 --- a/Content.Client/Atmos/EntitySystems/AtmosphereSystem.cs +++ b/Content.Client/Atmos/EntitySystems/AtmosphereSystem.cs @@ -1,10 +1,24 @@ -using Content.Shared.Atmos.EntitySystems; -using JetBrains.Annotations; +using Content.Client.Atmos.Components; +using Content.Shared.Atmos.Components; +using Content.Shared.Atmos.EntitySystems; +using Robust.Shared.GameStates; -namespace Content.Client.Atmos.EntitySystems +namespace Content.Client.Atmos.EntitySystems; + +public sealed class AtmosphereSystem : SharedAtmosphereSystem { - [UsedImplicitly] - public sealed class AtmosphereSystem : SharedAtmosphereSystem + public override void Initialize() { + base.Initialize(); + SubscribeLocalEvent(OnMapHandleState); + } + + private void OnMapHandleState(EntityUid uid, MapAtmosphereComponent component, ref ComponentHandleState args) + { + if (args.Current is not MapAtmosphereComponentState state) + return; + + // Struct so should just copy by value. + component.OverlayData = state.Overlay; } } diff --git a/Content.Client/Atmos/Overlays/GasTileOverlay.cs b/Content.Client/Atmos/Overlays/GasTileOverlay.cs index 209b8ee6b0731d..d4e4e57d028fc1 100644 --- a/Content.Client/Atmos/Overlays/GasTileOverlay.cs +++ b/Content.Client/Atmos/Overlays/GasTileOverlay.cs @@ -1,3 +1,4 @@ +using Content.Client.Atmos.Components; using Content.Client.Atmos.EntitySystems; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; @@ -7,6 +8,7 @@ using Robust.Client.ResourceManagement; using Robust.Shared.Enums; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Prototypes; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -136,75 +138,126 @@ protected override void FrameUpdate(FrameEventArgs args) protected override void Draw(in OverlayDrawArgs args) { + if (args.MapId == MapId.Nullspace) + return; + var drawHandle = args.WorldHandle; var xformQuery = _entManager.GetEntityQuery(); var overlayQuery = _entManager.GetEntityQuery(); - - foreach (var mapGrid in _mapManager.FindGridsIntersecting(args.MapId, args.WorldBounds)) + var gridState = (args.WorldBounds, + args.WorldHandle, + _gasCount, + _frames, + _frameCounter, + _fireFrames, + _fireFrameCounter, + _shader, + overlayQuery, + xformQuery); + + var mapUid = _mapManager.GetMapEntityId(args.MapId); + + if (_entManager.TryGetComponent(mapUid, out var atmos)) { - if (!overlayQuery.TryGetComponent(mapGrid.Owner, out var comp) || - !xformQuery.TryGetComponent(mapGrid.Owner, out var gridXform)) - { - continue; - } + var bottomLeft = args.WorldAABB.BottomLeft.Floored(); + var topRight = args.WorldAABB.TopRight.Ceiled(); - var (_, _, worldMatrix, invMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(); - drawHandle.SetTransform(worldMatrix); - var floatBounds = invMatrix.TransformBox(in args.WorldBounds).Enlarged(mapGrid.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)); - - // Currently it would be faster to group drawing by gas rather than by chunk, but if the textures are - // ever moved to a single atlas, that should no longer be the case. So this is just grouping draw calls - // by chunk, even though its currently slower. - - drawHandle.UseShader(null); - foreach (var chunk in comp.Chunks.Values) + for (var x = bottomLeft.X; x <= topRight.X; x++) { - var enumerator = new GasChunkEnumerator(chunk); - - while (enumerator.MoveNext(out var gas)) + for (var y = bottomLeft.Y; y <= topRight.Y; y++) { - if (gas.Opacity == null!) - continue; + var tilePosition = new Vector2(x, y); - var tilePosition = chunk.Origin + (enumerator.X, enumerator.Y); - if (!localBounds.Contains(tilePosition)) - continue; - - for (var i = 0; i < _gasCount; i++) + for (var i = 0; i < atmos.OverlayData.Opacity.Length; i++) { - var opacity = gas.Opacity[i]; + var opacity = atmos.OverlayData.Opacity[i]; + if (opacity > 0) - drawHandle.DrawTexture(_frames[i][_frameCounter[i]], tilePosition, Color.White.WithAlpha(opacity)); + args.WorldHandle.DrawTexture(_frames[i][_frameCounter[i]], tilePosition, Color.White.WithAlpha(opacity)); } } } + } - // And again for fire, with the unshaded shader - drawHandle.UseShader(_shader); - foreach (var chunk in comp.Chunks.Values) + // TODO: WorldBounds callback. + _mapManager.FindGridsIntersecting(args.MapId, args.WorldAABB, ref gridState, + static (EntityUid uid, MapGridComponent grid, + ref (Box2Rotated WorldBounds, + DrawingHandleWorld drawHandle, + int gasCount, + Texture[][] frames, + int[] frameCounter, + Texture[][] fireFrames, + int[] fireFrameCounter, + ShaderInstance shader, + EntityQuery overlayQuery, + EntityQuery xformQuery) state) => { - var enumerator = new GasChunkEnumerator(chunk); + if (!state.overlayQuery.TryGetComponent(uid, out var comp) || + !state.xformQuery.TryGetComponent(uid, out var gridXform)) + { + return true; + } - while (enumerator.MoveNext(out var gas)) + var (_, _, worldMatrix, invMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(); + state.drawHandle.SetTransform(worldMatrix); + var floatBounds = invMatrix.TransformBox(in state.WorldBounds).Enlarged(grid.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)); + + // Currently it would be faster to group drawing by gas rather than by chunk, but if the textures are + // ever moved to a single atlas, that should no longer be the case. So this is just grouping draw calls + // by chunk, even though its currently slower. + + state.drawHandle.UseShader(null); + foreach (var chunk in comp.Chunks.Values) { - if (gas.FireState == 0) - continue; + var enumerator = new GasChunkEnumerator(chunk); - var index = chunk.Origin + (enumerator.X, enumerator.Y); - if (!localBounds.Contains(index)) - continue; + while (enumerator.MoveNext(out var gas)) + { + if (gas.Opacity == null!) + continue; + + var tilePosition = chunk.Origin + (enumerator.X, enumerator.Y); + if (!localBounds.Contains(tilePosition)) + continue; + + for (var i = 0; i < state.gasCount; i++) + { + var opacity = gas.Opacity[i]; + if (opacity > 0) + state.drawHandle.DrawTexture(state.frames[i][state.frameCounter[i]], tilePosition, Color.White.WithAlpha(opacity)); + } + } + } + + // And again for fire, with the unshaded shader + state.drawHandle.UseShader(state.shader); + foreach (var chunk in comp.Chunks.Values) + { + var enumerator = new GasChunkEnumerator(chunk); + + while (enumerator.MoveNext(out var gas)) + { + if (gas.FireState == 0) + continue; - var state = gas.FireState - 1; - var texture = _fireFrames[state][_fireFrameCounter[state]]; - drawHandle.DrawTexture(texture, index); + var index = chunk.Origin + (enumerator.X, enumerator.Y); + if (!localBounds.Contains(index)) + continue; + + var fireState = gas.FireState - 1; + var texture = state.fireFrames[fireState][state.fireFrameCounter[fireState]]; + state.drawHandle.DrawTexture(texture, index); + } } - } - } + + return true; + }); drawHandle.UseShader(null); drawHandle.SetTransform(Matrix3.Identity); diff --git a/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs b/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs index a0daf9c654accd..6c168812242912 100644 --- a/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs @@ -14,7 +14,6 @@ public sealed class GasFilterBoundUserInterface : BoundUserInterface { private GasFilterWindow? _window; - private const float MaxTransferRate = Atmospherics.MaxTransferRate; public GasFilterBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey) { @@ -49,7 +48,6 @@ private void OnToggleStatusButtonPressed() private void OnFilterTransferRatePressed(string value) { float rate = float.TryParse(value, out var parsed) ? parsed : 0f; - if (rate > MaxTransferRate) rate = MaxTransferRate; SendMessage(new GasFilterChangeRateMessage(rate)); } diff --git a/Content.Client/Atmos/UI/GasFilterWindow.xaml b/Content.Client/Atmos/UI/GasFilterWindow.xaml index 30333b07bd22e7..6963a71d3d476b 100644 --- a/Content.Client/Atmos/UI/GasFilterWindow.xaml +++ b/Content.Client/Atmos/UI/GasFilterWindow.xaml @@ -9,7 +9,7 @@