mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Remove almost all allocations from F3 menu. (#2923)
This commit is contained in:
committed by
GitHub
parent
8d5fa58e1a
commit
776669b789
@@ -1,9 +1,11 @@
|
||||
using Robust.Client.Graphics;
|
||||
using System;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Profiling;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.Profiling;
|
||||
|
||||
@@ -14,26 +16,33 @@ public sealed class LiveProfileViewControl : Control
|
||||
|
||||
public int MaxDepth { get; set; } = 2;
|
||||
|
||||
private readonly Font? _font;
|
||||
private readonly char[] _sampleBuffer = new char[32];
|
||||
|
||||
public LiveProfileViewControl()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
if (!_resourceCache.TryGetResource<FontResource>("/Fonts/NotoSans/NotoSans-Regular.ttf", out var font))
|
||||
return;
|
||||
|
||||
_font = font.MakeDefault();
|
||||
}
|
||||
|
||||
protected internal override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
base.Draw(handle);
|
||||
|
||||
if (!_profManager.IsEnabled)
|
||||
if (!_profManager.IsEnabled || _font == null)
|
||||
return;
|
||||
|
||||
var font = _resourceCache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Regular.ttf").MakeDefault();
|
||||
var baseLine = new Vector2(0, font.GetAscent(UIScale));
|
||||
var baseLine = new Vector2(0, _font.GetAscent(UIScale));
|
||||
|
||||
ref readonly var buffer = ref _profManager.Buffer;
|
||||
ref readonly var index = ref buffer.Index(buffer.IndexWriteOffset - 1);
|
||||
|
||||
DrawData drawData = default;
|
||||
drawData.Font = font;
|
||||
drawData.Font = _font;
|
||||
drawData.Buffer = buffer;
|
||||
drawData.Index = index;
|
||||
drawData.Handle = handle;
|
||||
@@ -79,13 +88,13 @@ public sealed class LiveProfileViewControl : Control
|
||||
var str = value.Type switch
|
||||
{
|
||||
ProfValueType.TimeAllocSample =>
|
||||
$"{value.TimeAllocSample.Time * 1000:N2} ms, {value.TimeAllocSample.Alloc} B",
|
||||
ProfValueType.Int32 => value.Int32.ToString(),
|
||||
ProfValueType.Int64 => value.Int64.ToString(),
|
||||
_ => "???"
|
||||
FormatHelpers.FormatIntoMem(_sampleBuffer, $"{value.TimeAllocSample.Time * 1000:N2} ms, {value.TimeAllocSample.Alloc} B"),
|
||||
ProfValueType.Int32 => FormatHelpers.FormatIntoMem(_sampleBuffer, $"{value.Int32}"),
|
||||
ProfValueType.Int64 => FormatHelpers.FormatIntoMem(_sampleBuffer, $"{value.Int64}"),
|
||||
_ => "???".AsMemory()
|
||||
};
|
||||
|
||||
data.Handle.DrawString(data.Font, baseline, str, UIScale, Color.White);
|
||||
data.Handle.DrawString(data.Font, baseline, str.Span, UIScale, Color.White);
|
||||
}
|
||||
|
||||
private void DrawCmd(
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
private readonly List<int> _cachedTextWidths = new();
|
||||
private bool _textDimensionCacheValid;
|
||||
private string? _text;
|
||||
private ReadOnlyMemory<char> _textMemory;
|
||||
private bool _clipText;
|
||||
private AlignMode _align;
|
||||
|
||||
@@ -34,13 +35,44 @@ namespace Robust.Client.UserInterface.Controls
|
||||
/// <summary>
|
||||
/// The text to display.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Replaces <see cref="TextMemory"/> when set.
|
||||
/// </remarks>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown if <see cref="TextMemory"/> was set directly and there is no backing string instance to fetch.
|
||||
/// </exception>
|
||||
[ViewVariables]
|
||||
public string? Text
|
||||
{
|
||||
get => _text;
|
||||
get => _text ?? (_textMemory.Length > 0 ? throw new InvalidOperationException("Label uses TextMemory, cannot fetch string text.") : null);
|
||||
set
|
||||
{
|
||||
_text = value;
|
||||
_textMemory = value.AsMemory();
|
||||
_textDimensionCacheValid = false;
|
||||
InvalidateMeasure();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The text to display, set as a read-only memory.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Note that updating the backing memory while the control is using it can result in incorrect display due to caching of measure information and similar.
|
||||
/// If you modify the backing storage, re-assign the property to invalidate these.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Sets <see cref="Text"/> to throw an exception if read, as there is no backing string to retrieve.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public ReadOnlyMemory<char> TextMemory
|
||||
{
|
||||
get => _textMemory;
|
||||
set
|
||||
{
|
||||
_text = null;
|
||||
_textMemory = value;
|
||||
_textDimensionCacheValid = false;
|
||||
InvalidateMeasure();
|
||||
}
|
||||
@@ -124,7 +156,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
protected internal override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
if (_text == null)
|
||||
if (_textMemory.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -182,7 +214,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
var baseLine = CalcBaseline();
|
||||
|
||||
foreach (var rune in _text.EnumerateRunes())
|
||||
foreach (var rune in _textMemory.Span.EnumerateRunes())
|
||||
{
|
||||
if (rune == new Rune('\n'))
|
||||
{
|
||||
@@ -245,7 +277,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
_cachedTextWidths.Clear();
|
||||
_cachedTextWidths.Add(0);
|
||||
|
||||
if (_text == null)
|
||||
if (_textMemory.Length == 0)
|
||||
{
|
||||
_cachedTextHeight = 0;
|
||||
_textDimensionCacheValid = true;
|
||||
@@ -254,7 +286,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
var font = ActualFont;
|
||||
var height = font.GetHeight(UIScale);
|
||||
foreach (var rune in _text.EnumerateRunes())
|
||||
foreach (var rune in _textMemory.Span.EnumerateRunes())
|
||||
{
|
||||
if (rune == new Rune('\n'))
|
||||
{
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System.Text;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
@@ -12,6 +14,9 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
|
||||
private readonly Label _label;
|
||||
|
||||
private readonly StringBuilder _textBuilder = new();
|
||||
private readonly char[] _textBuffer = new char[256];
|
||||
|
||||
public DebugClydePanel()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
@@ -33,21 +38,23 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
return;
|
||||
}
|
||||
|
||||
_textBuilder.Clear();
|
||||
|
||||
var info = _clydeInternal.DebugInfo;
|
||||
var stats = _clydeInternal.DebugStats;
|
||||
|
||||
var overridingText = "";
|
||||
if (info.Overriding)
|
||||
{
|
||||
overridingText = $"\nVersion override: {info.OpenGLVersion}";
|
||||
}
|
||||
|
||||
_label.Text = $@"Renderer: {info.Renderer}
|
||||
_textBuilder.Append($@"Renderer: {info.Renderer}
|
||||
Vendor: {info.Vendor}
|
||||
Version: {info.VersionString}{overridingText}
|
||||
Draw Calls: Cly: {stats.LastClydeDrawCalls} GL: {stats.LastGLDrawCalls}
|
||||
Batches: {stats.LastBatches} Max size: {stats.LargestBatchSize}
|
||||
Lights: {stats.TotalLights}";
|
||||
Version: {info.VersionString}\n");
|
||||
|
||||
if (info.Overriding)
|
||||
_textBuilder.Append($"Version override: {info.OpenGLVersion}\n");
|
||||
|
||||
_textBuilder.Append($@"Draw Calls: Cly: {stats.LastClydeDrawCalls} GL: {stats.LastGLDrawCalls}
|
||||
Batches: {stats.LastBatches} Max size: ({stats.LargestBatchSize.vertices} vtx, {stats.LargestBatchSize.vertices} idx)
|
||||
Lights: {stats.TotalLights}");
|
||||
|
||||
_label.TextMemory = FormatHelpers.BuilderToMemory(_textBuilder, _textBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
@@ -20,8 +21,10 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
[Dependency] private readonly IClyde _displayManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
|
||||
private readonly StringBuilder _textBuilder = new();
|
||||
private readonly char[] _textBuffer = new char[1024];
|
||||
|
||||
private readonly Label _contents;
|
||||
private UIBox2i _uiBox;
|
||||
|
||||
public DebugCoordsPanel()
|
||||
{
|
||||
@@ -53,7 +56,7 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
return;
|
||||
}
|
||||
|
||||
var stringBuilder = new StringBuilder();
|
||||
_textBuilder.Clear();
|
||||
|
||||
var mouseScreenPos = _inputManager.MouseScreenPosition;
|
||||
var screenSize = _displayManager.ScreenSize;
|
||||
@@ -79,21 +82,20 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
|
||||
var controlHovered = UserInterfaceManager.CurrentlyHovered;
|
||||
|
||||
stringBuilder.AppendFormat(@"Positioning Debug:
|
||||
Screen Size: {0}
|
||||
_textBuilder.Append($@"Positioning Debug:
|
||||
Screen Size: {screenSize}
|
||||
Mouse Pos:
|
||||
Screen: {1}
|
||||
{2}
|
||||
{3}
|
||||
{4}
|
||||
GUI: {5}", screenSize, mouseScreenPos, mouseWorldMap, mouseGridPos,
|
||||
tile, controlHovered);
|
||||
Screen: {mouseScreenPos}
|
||||
{mouseWorldMap}
|
||||
{mouseGridPos}
|
||||
{tile}
|
||||
GUI: {controlHovered}");
|
||||
|
||||
stringBuilder.AppendLine("\nAttached Entity:");
|
||||
_textBuilder.AppendLine("\nAttached Entity:");
|
||||
var controlledEntity = _playerManager?.LocalPlayer?.ControlledEntity ?? EntityUid.Invalid;
|
||||
if (controlledEntity == EntityUid.Invalid)
|
||||
{
|
||||
stringBuilder.AppendLine("No attached entity.");
|
||||
_textBuilder.AppendLine("No attached entity.");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -106,42 +108,16 @@ Mouse Pos:
|
||||
|
||||
Angle gridRotation = _mapManager.TryGetGrid(entityTransform.GridID, out var grid) ? grid.WorldRotation : Angle.Zero;
|
||||
|
||||
stringBuilder.AppendFormat(@" Screen: {0}
|
||||
{1}
|
||||
{2}
|
||||
Rotation: {3:F2}°
|
||||
EntId: {4}
|
||||
GridID: {5}
|
||||
Grid Rotation: {6:F2}°", playerScreen, playerWorldOffset, playerCoordinates, playerRotation.Degrees, entityTransform.Owner,
|
||||
entityTransform.GridID, gridRotation.Degrees);
|
||||
_textBuilder.Append($@" Screen: {playerScreen}
|
||||
{playerWorldOffset}
|
||||
{playerCoordinates}
|
||||
Rotation: {playerRotation.Degrees:F2}°
|
||||
EntId: {entityTransform.Owner}
|
||||
GridID: {entityTransform.GridID}
|
||||
Grid Rotation: {gridRotation.Degrees:F2}°");
|
||||
}
|
||||
|
||||
if (controlHovered != null)
|
||||
{
|
||||
_uiBox = UIBox2i.FromDimensions(controlHovered.GlobalPixelPosition, controlHovered.PixelSize);
|
||||
}
|
||||
|
||||
_contents.Text = stringBuilder.ToString();
|
||||
// MinimumSizeChanged();
|
||||
}
|
||||
|
||||
protected internal override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
base.Draw(handle);
|
||||
|
||||
if (!VisibleInTree)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var (x, y) = GlobalPixelPosition;
|
||||
var renderBox = new UIBox2(
|
||||
_uiBox.Left - x,
|
||||
_uiBox.Top - y,
|
||||
_uiBox.Right - x,
|
||||
_uiBox.Bottom - y);
|
||||
|
||||
handle.DrawRect(renderBox, Color.Red, false);
|
||||
_contents.TextMemory = FormatHelpers.BuilderToMemory(_textBuilder, _textBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using System.Text;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
@@ -13,6 +15,10 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
|
||||
private readonly Label _label;
|
||||
|
||||
private readonly StringBuilder _textBuilder = new();
|
||||
private readonly char[] _textBuffer = new char[512];
|
||||
|
||||
|
||||
public DebugInputPanel()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
@@ -36,8 +42,15 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
return;
|
||||
}
|
||||
|
||||
var functionsText = string.Join("\n", _inputManager.DownKeyFunctions);
|
||||
_label.Text = $"Context: {_inputManager.Contexts.ActiveContext.Name}\n{functionsText}";
|
||||
_textBuilder.Clear();
|
||||
|
||||
_textBuilder.Append($"Input context: {_inputManager.Contexts.ActiveContext.Name}");
|
||||
foreach (var func in _inputManager.DownKeyFunctions)
|
||||
{
|
||||
_textBuilder.Append($"\n {func.FunctionName}");
|
||||
}
|
||||
|
||||
_label.TextMemory = FormatHelpers.BuilderToMemory(_textBuilder, _textBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
@@ -11,6 +11,7 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
private readonly Label _label;
|
||||
|
||||
private readonly char[] _textBuffer = new char[512];
|
||||
private readonly long[] _allocDeltas = new long[60];
|
||||
private long _lastAllocated;
|
||||
private int _allocDeltaIndex;
|
||||
@@ -40,10 +41,10 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
return;
|
||||
}
|
||||
|
||||
_label.Text = GetMemoryInfo();
|
||||
_label.TextMemory = GetMemoryInfo();
|
||||
}
|
||||
|
||||
private string GetMemoryInfo()
|
||||
private ReadOnlyMemory<char> GetMemoryInfo()
|
||||
{
|
||||
var gen0 = GC.CollectionCount(0);
|
||||
var gen1 = GC.CollectionCount(1);
|
||||
@@ -53,18 +54,15 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
LogAllocSize(allocated);
|
||||
var info = GC.GetGCMemoryInfo();
|
||||
|
||||
return $@"Total Allocated: {FormatBytes(allocated)}
|
||||
return FormatHelpers.FormatIntoMem(
|
||||
_textBuffer,
|
||||
$@"Total Allocated: {allocated / 1024:N0} KiB
|
||||
Total Collections: {gen0} {gen1} {gen2}
|
||||
Alloc Rate: {FormatBytes(CalculateAllocRate())} / frame
|
||||
Alloc Rate: {CalculateAllocRate() / 1024:N0} KiB / frame
|
||||
Last GC: {info.Index} Gen: {info.Generation} BGC: {info.Concurrent} C: {info.Compacted}
|
||||
Pause: {info.PauseDurations[0].TotalMilliseconds}ms
|
||||
Heap: {FormatBytes(info.HeapSizeBytes)}
|
||||
Fragmented: {FormatBytes(info.FragmentedBytes)}";
|
||||
}
|
||||
|
||||
private static string FormatBytes(long bytes)
|
||||
{
|
||||
return $"{bytes / 1024} KiB";
|
||||
Heap: {info.HeapSizeBytes / 1024:N0} KiB
|
||||
Fragmented: {info.FragmentedBytes / 1024:N0} KiB");
|
||||
}
|
||||
|
||||
private void LogAllocSize(long allocated)
|
||||
@@ -79,7 +77,18 @@ Last GC: {info.Index} Gen: {info.Generation} BGC: {info.Concurrent} C: {info.Com
|
||||
|
||||
private long CalculateAllocRate()
|
||||
{
|
||||
return (long) _allocDeltas.Where(x => x >= 0).Average();
|
||||
var sum = 0L;
|
||||
var count = 0;
|
||||
foreach (var val in _allocDeltas)
|
||||
{
|
||||
if (val >= 0)
|
||||
{
|
||||
sum += val;
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return count == 0 ? 0 : sum / count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
@@ -15,6 +16,8 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
private readonly IClientNetManager NetManager;
|
||||
private readonly IGameTiming GameTiming;
|
||||
|
||||
private readonly char[] _textBuffer = new char[256];
|
||||
|
||||
private TimeSpan LastUpdate;
|
||||
private Label contents;
|
||||
|
||||
@@ -84,11 +87,10 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
LastSentPackets = stats.SentPackets;
|
||||
LastReceivedPackets = stats.ReceivedPackets;
|
||||
|
||||
contents.Text = $@"UP: {sentBytes / ONE_KIBIBYTE:N} KiB/s, {sentPackets} pckt/s, {LastSentBytes / ONE_KIBIBYTE:N} KiB, {LastSentPackets} pckt
|
||||
contents.TextMemory = FormatHelpers.FormatIntoMem(_textBuffer,
|
||||
$@"UP: {sentBytes / ONE_KIBIBYTE:N} KiB/s, {sentPackets} pckt/s, {LastSentBytes / ONE_KIBIBYTE:N} KiB, {LastSentPackets} pckt
|
||||
DOWN: {receivedBytes / ONE_KIBIBYTE:N} KiB/s, {receivedPackets} pckt/s, {LastReceivedBytes / ONE_KIBIBYTE:N} KiB, {LastReceivedPackets} pckt
|
||||
PING: {NetManager.ServerChannel?.Ping ?? -1} ms";
|
||||
|
||||
// MinimumSizeChanged();
|
||||
PING: {NetManager.ServerChannel?.Ping ?? -1} ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using Robust.Client.GameStates;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
@@ -11,7 +13,8 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
private readonly IGameTiming _gameTiming;
|
||||
private readonly IClientGameStateManager _gameState;
|
||||
|
||||
private Label _contents;
|
||||
private readonly char[] _textBuffer = new char[256];
|
||||
private readonly Label _contents;
|
||||
|
||||
public DebugTimePanel(IGameTiming gameTiming, IClientGameStateManager gameState)
|
||||
{
|
||||
@@ -49,9 +52,10 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
// This means that CurTick reports the NEXT tick to be ran, NOT the last tick that was ran.
|
||||
// This is why there's a -1 on Pred:.
|
||||
|
||||
_contents.Text = $@"Paused: {_gameTiming.Paused}, CurTick: {_gameTiming.CurTick}/{_gameTiming.CurTick-1}, CurServerTick: {_gameState.CurServerTick}, Pred: {_gameTiming.CurTick.Value - _gameState.CurServerTick.Value-1}
|
||||
_contents.TextMemory = FormatHelpers.FormatIntoMem(_textBuffer,
|
||||
$@"Paused: {_gameTiming.Paused}, CurTick: {_gameTiming.CurTick}/{_gameTiming.CurTick - 1}, CurServerTick: {_gameState.CurServerTick}, Pred: {_gameTiming.CurTick.Value - _gameState.CurServerTick.Value - 1}
|
||||
CurTime: {_gameTiming.CurTime:hh\:mm\:ss\.ff}, RealTime: {_gameTiming.RealTime:hh\:mm\:ss\.ff}, CurFrame: {_gameTiming.CurFrame}
|
||||
ServerTime: {_gameTiming.ServerTime}, TickTimingAdjustment: {_gameTiming.TickTimingAdjustment}";
|
||||
ServerTime: {_gameTiming.ServerTime}, TickTimingAdjustment: {_gameTiming.TickTimingAdjustment}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
@@ -8,6 +9,8 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
private readonly IGameTiming _gameTiming;
|
||||
|
||||
private readonly char[] _textBuffer = new char[16];
|
||||
|
||||
public FpsCounter(IGameTiming gameTiming)
|
||||
{
|
||||
_gameTiming = gameTiming;
|
||||
@@ -25,7 +28,7 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
}
|
||||
|
||||
var fps = _gameTiming.FramesPerSecondAvg;
|
||||
Text = $"FPS: {fps:N0}";
|
||||
TextMemory = FormatHelpers.FormatIntoMem(_textBuffer, $"FPS: {fps:N0}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
{
|
||||
@@ -7,7 +8,7 @@ namespace Robust.Shared.Maths
|
||||
/// A representation of an angle, in radians.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public readonly struct Angle : IApproxEquatable<Angle>, IEquatable<Angle>
|
||||
public readonly struct Angle : IApproxEquatable<Angle>, IEquatable<Angle>, ISpanFormattable
|
||||
{
|
||||
public static Angle Zero { get; } = new();
|
||||
|
||||
@@ -291,5 +292,22 @@ namespace Robust.Shared.Maths
|
||||
{
|
||||
return $"{Theta} rad";
|
||||
}
|
||||
|
||||
public string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"{Theta} rad");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
{
|
||||
@@ -10,7 +11,7 @@ namespace Robust.Shared.Maths
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct Box2 : IEquatable<Box2>, IApproxEquatable<Box2>
|
||||
public struct Box2 : IEquatable<Box2>, IApproxEquatable<Box2>, ISpanFormattable
|
||||
{
|
||||
/// <summary>
|
||||
/// The X coordinate of the left edge of the box.
|
||||
@@ -310,11 +311,28 @@ namespace Robust.Shared.Maths
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
public readonly override string ToString()
|
||||
{
|
||||
return $"({Left}, {Bottom}, {Right}, {Top})";
|
||||
}
|
||||
|
||||
public readonly string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public readonly bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"({Left}, {Bottom}, {Right}, {Top})");
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float Area(in Box2 box)
|
||||
=> box.Width * box.Height;
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
{
|
||||
@@ -9,7 +10,7 @@ namespace Robust.Shared.Maths
|
||||
/// This type contains a <see cref="Box2"/> and a rotation <see cref="Angle"/> in world space.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct Box2Rotated : IEquatable<Box2Rotated>
|
||||
public struct Box2Rotated : IEquatable<Box2Rotated>, ISpanFormattable
|
||||
{
|
||||
public Box2 Box;
|
||||
public Angle Rotation;
|
||||
@@ -214,7 +215,24 @@ namespace Robust.Shared.Maths
|
||||
/// </summary>
|
||||
public override readonly string ToString()
|
||||
{
|
||||
return $"{Box.ToString()}, {Rotation.ToString()}";
|
||||
return $"{Box}, {Rotation}";
|
||||
}
|
||||
|
||||
public readonly string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public readonly bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"{Box}, {Rotation}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
{
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct Box2i : IEquatable<Box2i>
|
||||
public struct Box2i : IEquatable<Box2i>, ISpanFormattable
|
||||
{
|
||||
[FieldOffset(sizeof(int) * 0)] public int Left;
|
||||
[FieldOffset(sizeof(int) * 1)] public int Bottom;
|
||||
@@ -136,6 +137,23 @@ namespace Robust.Shared.Maths
|
||||
return $"({Left}, {Bottom}, {Right}, {Top})";
|
||||
}
|
||||
|
||||
public readonly string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public readonly bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"({Left}, {Bottom}, {Right}, {Top})");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies each side of the box by the scalar.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
{
|
||||
@@ -6,7 +7,7 @@ namespace Robust.Shared.Maths
|
||||
/// Represents a circle with a 2D position and a radius.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct Circle : IEquatable<Circle>
|
||||
public struct Circle : IEquatable<Circle>, ISpanFormattable
|
||||
{
|
||||
/// <summary>
|
||||
/// Position of the circle in 2D space.
|
||||
@@ -108,5 +109,22 @@ namespace Robust.Shared.Maths
|
||||
{
|
||||
return $"Circle ({Position.X}, {Position.Y}), {Radius} r";
|
||||
}
|
||||
|
||||
public readonly string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public readonly bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"Circle ({Position.X}, {Position.Y}), {Radius} r");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Xml.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Utility;
|
||||
using SysVector3 = System.Numerics.Vector3;
|
||||
using SysVector4 = System.Numerics.Vector4;
|
||||
|
||||
@@ -46,7 +47,7 @@ namespace Robust.Shared.Maths
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Color : IEquatable<Color>
|
||||
public struct Color : IEquatable<Color>, ISpanFormattable
|
||||
{
|
||||
/// <summary>
|
||||
/// The red component of this Color4 structure.
|
||||
@@ -239,6 +240,23 @@ namespace Robust.Shared.Maths
|
||||
return $"{{(R, G, B, A) = ({R}, {G}, {B}, {A})}}";
|
||||
}
|
||||
|
||||
public readonly string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public readonly bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"{{(R, G, B, A) = ({R}, {G}, {B}, {A})}}");
|
||||
}
|
||||
|
||||
public readonly Color WithRed(float newR)
|
||||
{
|
||||
return new(newR, G, B, A);
|
||||
|
||||
203
Robust.Shared.Maths/FormatHelpers.cs
Normal file
203
Robust.Shared.Maths/FormatHelpers.cs
Normal file
@@ -0,0 +1,203 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
|
||||
// Leaving this in this namespace because I only need this class here to work around maths being a separate assembly.
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Robust.Shared.Utility;
|
||||
|
||||
/// <summary>
|
||||
/// Helpers for dealing with string formatting and related things.
|
||||
/// </summary>
|
||||
public static class FormatHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Format a string interpolation into a given buffer. If the buffer is not large enough, the result is truncated.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Assuming everything you're formatting with implements <see cref="ISpanFormattable"/>, this should be zero-alloc.
|
||||
/// </remarks>
|
||||
/// <param name="buffer">The buffer to format into.</param>
|
||||
/// <param name="handler">String interpolation handler to implement buffer formatting logic.</param>
|
||||
/// <returns>The amount of chars written into the buffer.</returns>
|
||||
public static int FormatInto(
|
||||
Span<char> buffer,
|
||||
[InterpolatedStringHandlerArgument("buffer")] ref BufferInterpolatedStringHandler handler)
|
||||
{
|
||||
return handler.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to format a string interpolation into a given buffer.
|
||||
/// If the buffer is not large enough, the result is truncated.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This is intended to be used as an easy implementation of <see cref="ISpanFormattable"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Assuming everything you're formatting with implements <see cref="ISpanFormattable"/>,
|
||||
/// this should be zero-alloc on release.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="buffer">The buffer to format into.</param>
|
||||
/// <param name="charsWritten">The amount of chars written into the buffer.</param>
|
||||
/// <param name="handler">String interpolation handler to implement buffer formatting logic.</param>
|
||||
/// <returns>False if the formatting failed due to lack of space and was truncated.</returns>
|
||||
public static bool TryFormatInto(
|
||||
Span<char> buffer,
|
||||
out int charsWritten,
|
||||
[InterpolatedStringHandlerArgument("buffer")] ref BufferInterpolatedStringHandler handler)
|
||||
{
|
||||
charsWritten = handler.Length;
|
||||
return !handler.Truncated;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Format a string interpolation into a given memory buffer.
|
||||
/// If the buffer is not large enough, the result is truncated.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The memory buffer to format into.</param>
|
||||
/// <param name="handler">String interpolation handler to implement buffer formatting logic.</param>
|
||||
/// <returns>The region of memory filled by the formatting operation.</returns>
|
||||
public static Memory<char> FormatIntoMem(
|
||||
Memory<char> buffer,
|
||||
[InterpolatedStringHandlerArgument("buffer")] ref MemoryBufferInterpolatedStringHandler handler)
|
||||
{
|
||||
return buffer[..handler.Handler.Length];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the contents of a <see cref="StringBuilder"/> into a memory buffer, giving back the subregion used.
|
||||
/// If the buffer is not enough space, the result is truncated.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="StringBuilder"/> to copy from</param>
|
||||
/// <param name="memory">The memory buffer to copy into.</param>
|
||||
/// <returns>The memory region actually used by the copied data.</returns>
|
||||
public static Memory<char> BuilderToMemory(StringBuilder builder, Memory<char> memory)
|
||||
{
|
||||
var truncLength = Math.Min(builder.Length, memory.Length);
|
||||
builder.CopyTo(0, memory.Span, truncLength);
|
||||
return memory[..builder.Length];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interpolated string handler used by <see cref="FormatHelpers.FormatInto"/>.
|
||||
/// </summary>
|
||||
[InterpolatedStringHandler]
|
||||
public ref struct BufferInterpolatedStringHandler
|
||||
{
|
||||
private Span<char> _buffer;
|
||||
internal int Length;
|
||||
internal bool Truncated;
|
||||
|
||||
[SuppressMessage("ReSharper", "UnusedParameter.Local")]
|
||||
public BufferInterpolatedStringHandler(int literalLength, int formattedCount, Span<char> buffer)
|
||||
{
|
||||
_buffer = buffer;
|
||||
Length = 0;
|
||||
Truncated = false;
|
||||
}
|
||||
|
||||
public void AppendLiteral(string literal)
|
||||
{
|
||||
AppendString(literal);
|
||||
}
|
||||
|
||||
public void AppendFormatted(ReadOnlySpan<char> value)
|
||||
{
|
||||
AppendString(value);
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "MergeCastWithTypeCheck")]
|
||||
public void AppendFormatted<T>(T value)
|
||||
{
|
||||
if (value is ISpanFormattable)
|
||||
{
|
||||
// JIT is able to avoid boxing due to call structure.
|
||||
((ISpanFormattable)value).TryFormat(_buffer, out var written, default, null);
|
||||
Advance(written);
|
||||
return;
|
||||
}
|
||||
|
||||
var str = value?.ToString();
|
||||
if (str != null)
|
||||
AppendString(str);
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "MergeCastWithTypeCheck")]
|
||||
public void AppendFormatted<T>(T value, string format)
|
||||
{
|
||||
string? str;
|
||||
if (value is IFormattable)
|
||||
{
|
||||
if (value is ISpanFormattable)
|
||||
{
|
||||
// JIT is able to avoid boxing due to call structure.
|
||||
Truncated |= !((ISpanFormattable)value).TryFormat(_buffer, out var written, format, null);
|
||||
Advance(written);
|
||||
return;
|
||||
}
|
||||
|
||||
// JIT is able to avoid boxing due to call structure.
|
||||
str = ((IFormattable)value).ToString(format, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
str = value?.ToString();
|
||||
}
|
||||
|
||||
if (str != null)
|
||||
AppendString(str);
|
||||
}
|
||||
|
||||
private void AppendString(ReadOnlySpan<char> value)
|
||||
{
|
||||
var copyLength = value.Length;
|
||||
if (copyLength > _buffer.Length)
|
||||
{
|
||||
copyLength = _buffer.Length;
|
||||
Truncated = true;
|
||||
}
|
||||
|
||||
value[..copyLength].CopyTo(_buffer);
|
||||
Advance(copyLength);
|
||||
}
|
||||
|
||||
private void Advance(int amount)
|
||||
{
|
||||
_buffer = _buffer[amount..];
|
||||
Length += amount;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interpolated string handler used by <see cref="FormatHelpers.FormatIntoMem"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only exists as workaround for https://youtrack.jetbrains.com/issue/RIDER-78472.
|
||||
/// </remarks>
|
||||
[InterpolatedStringHandler]
|
||||
public ref struct MemoryBufferInterpolatedStringHandler
|
||||
{
|
||||
public BufferInterpolatedStringHandler Handler;
|
||||
|
||||
public MemoryBufferInterpolatedStringHandler(int literalLength, int formattedCount, Memory<char> buffer)
|
||||
{
|
||||
Handler = new BufferInterpolatedStringHandler(literalLength, formattedCount, buffer.Span);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void AppendLiteral(string literal) => Handler.AppendLiteral(literal);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void AppendFormatted(ReadOnlySpan<char> value) => Handler.AppendFormatted(value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void AppendFormatted<T>(T value) => Handler.AppendFormatted(value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void AppendFormatted<T>(T value, string format) => Handler.AppendFormatted(value, format);
|
||||
}
|
||||
@@ -29,12 +29,13 @@ using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
{
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Matrix3 : IEquatable<Matrix3>, IApproxEquatable<Matrix3>
|
||||
public struct Matrix3 : IEquatable<Matrix3>, IApproxEquatable<Matrix3>, ISpanFormattable
|
||||
{
|
||||
#region Fields & Access
|
||||
|
||||
@@ -1225,6 +1226,25 @@ namespace Robust.Shared.Maths
|
||||
+ $"|{R2C0}, {R2C1}, {R2C2}|\n";
|
||||
}
|
||||
|
||||
public readonly string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public readonly bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"|{R0C0}, {R0C1}, {R0C2}|\n"
|
||||
+ $"|{R1C0}, {R1C1}, {R1C2}|\n"
|
||||
+ $"|{R2C0}, {R2C1}, {R2C2}|\n");
|
||||
}
|
||||
|
||||
#endregion String
|
||||
}
|
||||
#pragma warning restore 3019
|
||||
|
||||
@@ -28,6 +28,7 @@ SOFTWARE.
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
{
|
||||
@@ -36,7 +37,7 @@ namespace Robust.Shared.Maths
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Matrix4 : IEquatable<Matrix4>
|
||||
public struct Matrix4 : IEquatable<Matrix4>, ISpanFormattable
|
||||
{
|
||||
#region Fields
|
||||
|
||||
@@ -1160,11 +1161,28 @@ namespace Robust.Shared.Maths
|
||||
/// Returns a System.String that represents the current Matrix44.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
public readonly override string ToString()
|
||||
{
|
||||
return $"{Row0}\n{Row1}\n{Row2}\n{Row3}";
|
||||
}
|
||||
|
||||
public readonly string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public readonly bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"{Row0}\n{Row1}\n{Row2}\n{Row3}");
|
||||
}
|
||||
|
||||
#endregion public override string ToString()
|
||||
|
||||
#region public override int GetHashCode()
|
||||
|
||||
@@ -29,6 +29,7 @@ using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Xml.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
{
|
||||
@@ -37,7 +38,7 @@ namespace Robust.Shared.Maths
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Quaternion : IEquatable<Quaternion>
|
||||
public struct Quaternion : IEquatable<Quaternion>, ISpanFormattable
|
||||
{
|
||||
#region Fields
|
||||
|
||||
@@ -903,9 +904,26 @@ namespace Robust.Shared.Maths
|
||||
/// Returns a System.String that represents the current Quaternion.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
public readonly override string ToString()
|
||||
{
|
||||
return $"V: {Xyz}, W: {W}";
|
||||
return $"V: {xyz}, W: {w}";
|
||||
}
|
||||
|
||||
public readonly string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public readonly bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"V: {xyz}, W: {w}");
|
||||
}
|
||||
|
||||
#endregion public override string ToString()
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
{
|
||||
[PublicAPI]
|
||||
public struct Thickness : IEquatable<Thickness>
|
||||
public struct Thickness : IEquatable<Thickness>, ISpanFormattable
|
||||
{
|
||||
public float Left;
|
||||
public float Top;
|
||||
@@ -108,11 +109,29 @@ namespace Robust.Shared.Maths
|
||||
return !left.Equals(in right);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
public readonly override string ToString()
|
||||
{
|
||||
return $"{Left},{Top},{Right},{Bottom}";
|
||||
}
|
||||
|
||||
|
||||
public readonly string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public readonly bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"{Left},{Top},{Right},{Bottom}");
|
||||
}
|
||||
|
||||
public readonly void Deconstruct(out float left, out float top, out float right, out float bottom)
|
||||
{
|
||||
left = Left;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
{
|
||||
@@ -10,7 +11,7 @@ namespace Robust.Shared.Maths
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct UIBox2 : IEquatable<UIBox2>
|
||||
public struct UIBox2 : IEquatable<UIBox2>, ISpanFormattable
|
||||
{
|
||||
/// <summary>
|
||||
/// The X coordinate of the left edge of the box.
|
||||
@@ -181,5 +182,22 @@ namespace Robust.Shared.Maths
|
||||
{
|
||||
return $"({Left}, {Top}, {Right}, {Bottom})";
|
||||
}
|
||||
|
||||
public readonly string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public readonly bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"({Left}, {Top}, {Right}, {Bottom})");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
{
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct UIBox2i : IEquatable<UIBox2i>
|
||||
public struct UIBox2i : IEquatable<UIBox2i>, ISpanFormattable
|
||||
{
|
||||
[FieldOffset(sizeof(int) * 0)] public int Left;
|
||||
[FieldOffset(sizeof(int) * 1)] public int Top;
|
||||
@@ -145,5 +146,22 @@ namespace Robust.Shared.Maths
|
||||
{
|
||||
return $"({Left}, {Top}, {Right}, {Bottom})";
|
||||
}
|
||||
|
||||
public readonly string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public readonly bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"({Left}, {Top}, {Right}, {Bottom})");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
{
|
||||
@@ -9,7 +10,7 @@ namespace Robust.Shared.Maths
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[Serializable]
|
||||
public struct Vector2 : IEquatable<Vector2>, IApproxEquatable<Vector2>
|
||||
public struct Vector2 : IEquatable<Vector2>, IApproxEquatable<Vector2>, ISpanFormattable
|
||||
{
|
||||
/// <summary>
|
||||
/// The X component of the vector.
|
||||
@@ -382,6 +383,23 @@ namespace Robust.Shared.Maths
|
||||
return $"({X}, {Y})";
|
||||
}
|
||||
|
||||
public readonly string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public readonly bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"({X}, {Y})");
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Vector2 a, Vector2 b)
|
||||
{
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.Json.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
{
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public struct Vector2i : IEquatable<Vector2i>
|
||||
public struct Vector2i : IEquatable<Vector2i>, ISpanFormattable
|
||||
{
|
||||
public static readonly Vector2i Zero = (0, 0);
|
||||
public static readonly Vector2i One = (1, 1);
|
||||
@@ -170,5 +171,22 @@ namespace Robust.Shared.Maths
|
||||
{
|
||||
return $"({X}, {Y})";
|
||||
}
|
||||
|
||||
public string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"({X}, {Y})");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Xml.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
{
|
||||
@@ -40,7 +41,7 @@ namespace Robust.Shared.Maths
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Vector3 : IEquatable<Vector3>
|
||||
public struct Vector3 : IEquatable<Vector3>, ISpanFormattable
|
||||
{
|
||||
#region Fields
|
||||
|
||||
@@ -1130,11 +1131,28 @@ namespace Robust.Shared.Maths
|
||||
/// Returns a System.String that represents the current Vector3.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
public readonly override string ToString()
|
||||
{
|
||||
return $"({X}, {Y}, {Z})";
|
||||
}
|
||||
|
||||
public readonly string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public readonly bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"({X}, {Y}, {Z})");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region public override int GetHashCode()
|
||||
|
||||
@@ -28,6 +28,7 @@ using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Xml.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
{
|
||||
@@ -37,7 +38,7 @@ namespace Robust.Shared.Maths
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Vector4 : IEquatable<Vector4>
|
||||
public struct Vector4 : IEquatable<Vector4>, ISpanFormattable
|
||||
{
|
||||
#region Fields
|
||||
|
||||
@@ -911,11 +912,28 @@ namespace Robust.Shared.Maths
|
||||
/// Returns a System.String that represents the current Vector4.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
public readonly override string ToString()
|
||||
{
|
||||
return $"({X}, {Y}, {Z}, {W})";
|
||||
}
|
||||
|
||||
public readonly string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public readonly bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"({X}, {Y}, {Z}, {W})");
|
||||
}
|
||||
|
||||
#endregion public override string ToString()
|
||||
|
||||
#region public override int GetHashCode()
|
||||
|
||||
@@ -4,6 +4,7 @@ using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Shared.GameObjects
|
||||
@@ -13,7 +14,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// This can be used by the EntityManager to access an entity
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public readonly struct EntityUid : IEquatable<EntityUid>, IComparable<EntityUid>
|
||||
public readonly struct EntityUid : IEquatable<EntityUid>, IComparable<EntityUid>, ISpanFormattable
|
||||
{
|
||||
/// <summary>
|
||||
/// If this bit is set on a UID, it's client sided.
|
||||
@@ -141,6 +142,28 @@ namespace Robust.Shared.GameObjects
|
||||
return _uid.ToString();
|
||||
}
|
||||
|
||||
public string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
if (IsClientSide())
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"c{_uid & ~ClientUid}");
|
||||
}
|
||||
|
||||
return _uid.TryFormat(destination, out charsWritten);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int CompareTo(EntityUid other)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Map
|
||||
{
|
||||
@@ -12,7 +13,7 @@ namespace Robust.Shared.Map
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
[Serializable, NetSerializable]
|
||||
public readonly struct EntityCoordinates : IEquatable<EntityCoordinates>
|
||||
public readonly struct EntityCoordinates : IEquatable<EntityCoordinates>, ISpanFormattable
|
||||
{
|
||||
public static readonly EntityCoordinates Invalid = new(EntityUid.Invalid, Vector2.Zero);
|
||||
|
||||
@@ -431,5 +432,19 @@ namespace Robust.Shared.Map
|
||||
{
|
||||
return $"EntId={EntityId}, X={Position.X:N2}, Y={Position.Y:N2}";
|
||||
}
|
||||
|
||||
public string ToString(string? format, IFormatProvider? formatProvider) => ToString();
|
||||
|
||||
public bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"EntId={EntityId}, X={Position.X:N2}, Y={Position.Y:N2}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Map
|
||||
{
|
||||
@@ -10,7 +11,7 @@ namespace Robust.Shared.Map
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
[Serializable, NetSerializable]
|
||||
public readonly struct MapCoordinates : IEquatable<MapCoordinates>
|
||||
public readonly struct MapCoordinates : IEquatable<MapCoordinates>, ISpanFormattable
|
||||
{
|
||||
public static readonly MapCoordinates Nullspace = new(Vector2.Zero, MapId.Nullspace);
|
||||
|
||||
@@ -60,6 +61,23 @@ namespace Robust.Shared.Map
|
||||
return $"Map={MapId}, X={Position.X:N2}, Y={Position.Y:N2}";
|
||||
}
|
||||
|
||||
public string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"Map={MapId}, X={Position.X:N2}, Y={Position.Y:N2}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that these coordinates are within a certain distance of another set.
|
||||
/// </summary>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Robust.Shared.Serialization;
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Map
|
||||
{
|
||||
@@ -10,7 +11,7 @@ namespace Robust.Shared.Map
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
[Serializable, NetSerializable]
|
||||
public readonly struct ScreenCoordinates : IEquatable<ScreenCoordinates>
|
||||
public readonly struct ScreenCoordinates : IEquatable<ScreenCoordinates>, ISpanFormattable
|
||||
{
|
||||
/// <summary>
|
||||
/// Position on the rendering screen.
|
||||
@@ -63,6 +64,23 @@ namespace Robust.Shared.Map
|
||||
return $"({Position.X}, {Position.Y}, W{Window.Value})";
|
||||
}
|
||||
|
||||
public string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"({Position.X}, {Position.Y}, W{Window.Value})");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Equals(ScreenCoordinates other)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Map;
|
||||
|
||||
@@ -7,7 +8,7 @@ namespace Robust.Shared.Map;
|
||||
/// This structure contains the data for an individual Tile in a <c>MapGrid</c>.
|
||||
/// </summary>
|
||||
[PublicAPI, Serializable]
|
||||
public readonly struct Tile : IEquatable<Tile>
|
||||
public readonly struct Tile : IEquatable<Tile>, ISpanFormattable
|
||||
{
|
||||
/// <summary>
|
||||
/// Internal type ID of this tile.
|
||||
@@ -96,6 +97,23 @@ public readonly struct Tile : IEquatable<Tile>
|
||||
return $"Tile {TypeId}, {Flags}, {Variant}";
|
||||
}
|
||||
|
||||
public string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"Tile {TypeId}, {Flags}, {Variant}");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Equals(Tile other)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Map
|
||||
{
|
||||
@@ -9,7 +10,7 @@ namespace Robust.Shared.Map
|
||||
/// All of the information needed to reference a tile in the game.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public readonly struct TileRef : IEquatable<TileRef>
|
||||
public readonly struct TileRef : IEquatable<TileRef>, ISpanFormattable
|
||||
{
|
||||
public static TileRef Zero => new(GridId.Invalid, EntityUid.Invalid, Vector2i.Zero, Tile.Empty);
|
||||
|
||||
@@ -75,6 +76,23 @@ namespace Robust.Shared.Map
|
||||
return $"TileRef: {X},{Y} ({Tile})";
|
||||
}
|
||||
|
||||
public string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public bool TryFormat(
|
||||
Span<char> destination,
|
||||
out int charsWritten,
|
||||
ReadOnlySpan<char> format,
|
||||
IFormatProvider? provider)
|
||||
{
|
||||
return FormatHelpers.TryFormatInto(
|
||||
destination,
|
||||
out charsWritten,
|
||||
$"TileRef: {X},{Y} ({Tile})");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Equals(TileRef other)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user