Compare commits

...

14 Commits

Author SHA1 Message Date
Pieter-Jan Briers
15eded3da8 Version: 210.0.2 2024-02-13 16:05:59 +01:00
Pieter-Jan Briers
b4165e8661 ALSO revert changes to TextureRect from #4841
Stretch modes are broken or something, SS14 lobby art looks wrong. Can't be arsed to debug it myself.
2024-02-13 16:05:46 +01:00
Pieter-Jan Briers
ad339b5bfd Version: 210.0.1 2024-02-13 15:30:20 +01:00
Pieter-Jan Briers
e1197af8ce Revert changes to TextureButton from #4841
Breaks SS14 stylesheets due to not responding to style properties anymore.

At least one of those seems to be unfixable (ModulateSelf usage) which makes me think we should just deprecate ModulateSelf instead. However I'm not fixing that here.
2024-02-13 15:29:46 +01:00
metalgearsloth
102cadf3a6 Version: 210.0.0 2024-02-13 18:26:01 +11:00
Hannah Giovanna Dawson
e7723b61bc Add UnicodeRange to sandbox (#4894)
* Add GetEncoding to sandbox (#4892)
Need this struct allowlisted to for nice unicode sanitization.

* Add UnicodeRanges too

* Changelog

---------

Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2024-02-11 17:22:11 +01:00
Moony
a9d17337a3 RT Patches for UI improvements (#4841)
* fix up buttons

* wah

* ough

* huhwuhuahsdhsfdj

* loud incorrect buzzer

* wawa

* Allow XmlnsDefinition

* wawa

* Release notes.

* Expose keybind loading.

* address reviews and other things

---------

Co-authored-by: moonheart08 <moonheart08@users.noreply.github.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2024-02-11 17:18:39 +01:00
Pieter-Jan Briers
74622bac83 Add DateTimeSerializer 2024-02-11 16:40:52 +01:00
Pieter-Jan Briers
a3047b1687 More warning fixes 2024-02-11 15:51:07 +01:00
Pieter-Jan Briers
3a55118143 Replace CVar OnValueChanged in systems with Subs.CVar 2024-02-11 13:29:27 +01:00
Pieter-Jan Briers
3c5fbc648a Add Subs.CVar helper for subscribing to CVar changes from entity systems 2024-02-11 13:29:27 +01:00
Pieter-Jan Briers
f9c39bce0b Use ValueList for EntitySystem subscriptions list.
That's a hundred something lists just gone and I don't have to ??=
2024-02-11 13:29:27 +01:00
Hannah Giovanna Dawson
0e8c803c0f Add GetEncoding to sandbox (#4892) 2024-02-10 17:59:13 +01:00
c4llv07e
6bb7b88c69 Save discord rich presense to the user config (#4884)
Signed-off-by: c4llv07e <kseandi@gmail.com>
2024-02-02 00:36:59 +01:00
46 changed files with 470 additions and 185 deletions

View File

@@ -1,4 +1,4 @@
<Project>
<!-- This file automatically reset by Tools/version.py -->
<!-- This file automatically reset by Tools/version.py -->

View File

@@ -54,6 +54,45 @@ END TEMPLATE-->
*None yet*
## 210.0.2
## 210.0.1
### Bugfixes
* Revert changes to `TextureButton` that broke style property handling.
## 210.0.0
### New features
* Controls can now hook before, after, and during rendering of their children.
* IRenderHandle is now a public API, with the caveat that it's properties and methods are unstable.
* ButtonGroup now exposes what buttons it contains, alongside which is currently pressed.
* OptionButton has additional styleclasses, and has a hook for modifying it's internal buttons.
* PanelContainer.GetStyleBox() is now protected rather than private.
* TextureButton now uses a TextureRect instead of custom drawing code.
* TextureRect has additional style properties exposed.
* A new property, TextureSizeTarget, was added, which allows specifying a size in virtual pixels that the control should attempt to draw at.
* Stretch mode is now a style property.
* Scale is now a style property.
* Avalonia.Metadata.XmlnsDefinitionAttribute is now permitted by the sandbox.
* Add MaxDimension property to Box2 to return the higher of the Width or Height.
* Add GetLocalPosition to convert ScreenCoordinates to coordinates relative to the control. Ignores window.
* Add GlobalRect and GlobalPixelRect for controls to get their UIBox2i in screen terms.
* Add dotted line drawing to DrawingHandleScreen.
* You can use `Subs.CVar()` from an entity systems to subscribe to CVar changes. This is more convenient than `IConfigurationManager.OnValueChanged` as it automatically unsubscribes on system shutdown.
* There is now a built-in type serializer for `DateTime`, so you can put `DateTime`s in your data fields.
* `System.Text.Unicode.UnicodeRange` and `UnicodeRanges` are now available in the sandbox.
### Bugfixes
* UI drawing now properly accounts for a control's draw routine potentially mangling the current matrix.
* UI roots now properly update when the global stylesheet is changed. They previously only did so if they had a dedicated stylesheet (which is the one case where they would be unaffected by a global sheet update.
## 209.0.1
### Bugfixes

View File

@@ -39,7 +39,7 @@ public sealed class AudioOverlay : Overlay
protected internal override void Draw(in OverlayDrawArgs args)
{
var localPlayer = _playerManager.LocalPlayer?.ControlledEntity;
var localPlayer = _playerManager.LocalEntity;
if (args.ViewportControl == null || localPlayer == null)
return;

View File

@@ -106,8 +106,8 @@ public sealed partial class AudioSystem : SharedAudioSystem
SubscribeNetworkEvent<PlayAudioEntityMessage>(OnEntityAudio);
SubscribeNetworkEvent<PlayAudioPositionalMessage>(OnEntityCoordinates);
CfgManager.OnValueChanged(CVars.AudioAttenuation, OnAudioAttenuation, true);
CfgManager.OnValueChanged(CVars.AudioRaycastLength, OnRaycastLengthChanged, true);
Subs.CVar(CfgManager, CVars.AudioAttenuation, OnAudioAttenuation, true);
Subs.CVar(CfgManager, CVars.AudioRaycastLength, OnRaycastLengthChanged, true);
}
private void OnAudioState(EntityUid uid, AudioComponent component, ref AfterAutoHandleStateEvent args)
@@ -133,13 +133,6 @@ public sealed partial class AudioSystem : SharedAudioSystem
_audio.SetMasterGain(value);
}
public override void Shutdown()
{
CfgManager.UnsubValueChanged(CVars.AudioAttenuation, OnAudioAttenuation);
CfgManager.UnsubValueChanged(CVars.AudioRaycastLength, OnRaycastLengthChanged);
base.Shutdown();
}
private void OnAudioPaused(EntityUid uid, AudioComponent component, ref EntityPausedEvent args)
{
component.Pause();

View File

@@ -229,7 +229,7 @@ namespace Robust.Client
// Don't invoke PlayerLeaveServer if PlayerJoinedServer & GameStartedSetup hasn't been called yet.
if (RunLevel > ClientRunLevel.Connecting)
PlayerLeaveServer?.Invoke(this, new PlayerEventArgs(_playMan.LocalPlayer?.Session));
PlayerLeaveServer?.Invoke(this, new PlayerEventArgs(_playMan.LocalSession));
LastDisconnectReason = args.Reason;
GameStoppedReset();

View File

@@ -188,7 +188,7 @@ namespace Robust.Client.Console
}
args.RemoveAt(0);
var shell = new ConsoleShell(this, session ?? _player.LocalPlayer?.Session, session == null);
var shell = new ConsoleShell(this, session ?? _player.LocalSession, session == null);
var cmdArgs = args.ToArray();
AnyCommandExecuted?.Invoke(shell, commandName, command, cmdArgs);
@@ -200,8 +200,7 @@ namespace Robust.Client.Console
// When not connected to a server, you can run all local commands.
// When connected to a server, you can only run commands according to the con group controller.
return _player.LocalPlayer == null
|| _player.LocalPlayer.Session.Status <= SessionStatus.Connecting
return _player.LocalSession is not { Status: > SessionStatus.Connecting }
|| _conGroup.CanCommand(cmdName);
}

View File

@@ -16,8 +16,7 @@ namespace Robust.Client.Console.Commands
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var controlled = _playerManager.LocalPlayer?.ControlledEntity ?? EntityUid.Invalid;
if (controlled == EntityUid.Invalid)
if (_playerManager.LocalEntity is not { } controlled)
{
shell.WriteLine("You don't have an attached entity.");
return;

View File

@@ -420,7 +420,7 @@ namespace Robust.Client.Debugging
if (mapPos.MapId != args.MapId)
return;
var player = _playerManager.LocalPlayer?.ControlledEntity;
var player = _playerManager.LocalEntity;
if (!_entityManager.TryGetComponent<TransformComponent>(player, out var playerXform) ||
playerXform.MapID != args.MapId)

View File

@@ -42,6 +42,8 @@ public sealed partial class ClientEntityManager
var pending = PendingNetEntityStates.GetOrNew(nEntity);
pending.Add((typeof(T), callerEntity));
return entity.Item1;
}

View File

@@ -221,7 +221,7 @@ namespace Robust.Client.GameObjects
public void DispatchReceivedNetworkMsg(EntityEventArgs msg)
{
var sessionType = typeof(EntitySessionMessage<>).MakeGenericType(msg.GetType());
var sessionMsg = Activator.CreateInstance(sessionType, new EntitySessionEventArgs(_playerManager.LocalPlayer!.Session), msg)!;
var sessionMsg = Activator.CreateInstance(sessionType, new EntitySessionEventArgs(_playerManager.LocalSession!), msg)!;
ReceivedSystemMessage?.Invoke(this, msg);
ReceivedSystemMessage?.Invoke(this, sessionMsg);
}

View File

@@ -105,12 +105,10 @@ namespace Robust.Client.GameObjects
/// <param name="inputCmd">Input command to handle as predicted.</param>
public void PredictInputCommand(IFullInputCmdMessage inputCmd)
{
DebugTools.AssertNotNull(_playerManager.LocalPlayer);
var keyFunc = _inputManager.NetworkBindMap.KeyFunctionName(inputCmd.InputFunctionId);
Predicted = true;
var session = _playerManager.LocalPlayer!.Session;
var session = _playerManager.LocalSession;
foreach (var handler in BindRegistry.GetHandlers(keyFunc))
{
if (handler.HandleCmdMessage(EntityManager, session, inputCmd))
@@ -145,27 +143,22 @@ namespace Robust.Client.GameObjects
private void GenerateInputCommand(IConsoleShell shell, string argstr, string[] args)
{
var localPlayer = _playerManager.LocalPlayer;
if(localPlayer is null)
return;
var pent = localPlayer.ControlledEntity;
if(pent is null)
if (_playerManager.LocalEntity is not { } pent)
return;
BoundKeyFunction keyFunction = new BoundKeyFunction(args[0]);
BoundKeyState state = args[1] == "u" ? BoundKeyState.Up: BoundKeyState.Down;
var pxform = Transform(pent.Value);
var pxform = Transform(pent);
var wPos = pxform.WorldPosition + new Vector2(float.Parse(args[2]), float.Parse(args[3]));
var coords = EntityCoordinates.FromMap(EntityManager, pent.Value, new MapCoordinates(wPos, pxform.MapID));
var coords = EntityCoordinates.FromMap(EntityManager, pent, new MapCoordinates(wPos, pxform.MapID));
var funcId = _inputManager.NetworkBindMap.KeyFunctionID(keyFunction);
var message = new FullInputCmdMessage(_timing.CurTick, _timing.TickFraction, funcId, state,
GetNetCoordinates(coords), new ScreenCoordinates(0, 0, default), NetEntity.Invalid);
HandleInputCommand(localPlayer.Session, keyFunction, message);
HandleInputCommand(_playerManager.LocalSession, keyFunction, message);
}
private void OnAttachedEntityChanged(LocalPlayerAttachedEvent message)
@@ -208,11 +201,8 @@ namespace Robust.Client.GameObjects
/// </summary>
public void SetEntityContextActive()
{
var controlled = _playerManager.LocalPlayer?.ControlledEntity ?? EntityUid.Invalid;
if (controlled == EntityUid.Invalid)
{
if (_playerManager.LocalEntity is not { } controlled)
return;
}
SetEntityContextActive(_inputManager, controlled);
}

View File

@@ -62,7 +62,7 @@ namespace Robust.Client.GameObjects
SubscribeLocalEvent<SpriteComponent, SpriteUpdateInertEvent>(QueueUpdateInert);
SubscribeLocalEvent<SpriteComponent, ComponentInit>(OnInit);
_cfg.OnValueChanged(CVars.RenderSpriteDirectionBias, OnBiasChanged, true);
Subs.CVar(_cfg, CVars.RenderSpriteDirectionBias, OnBiasChanged, true);
_sawmill = _logManager.GetSawmill("sprite");
}
@@ -72,12 +72,6 @@ namespace Robust.Client.GameObjects
QueueUpdateInert(uid, component);
}
public override void Shutdown()
{
base.Shutdown();
_cfg.UnsubValueChanged(CVars.RenderSpriteDirectionBias, OnBiasChanged);
}
private void OnBiasChanged(double value)
{
SpriteComponent.DirectionBias = value;

View File

@@ -29,10 +29,7 @@ namespace Robust.Client.GameObjects
var uiKey = ev.UiKey;
var message = ev.Message;
// This should probably not happen at this point, but better make extra sure!
if (_playerManager.LocalPlayer != null)
message.Session = _playerManager.LocalPlayer.Session;
message.Session = _playerManager.LocalSession!;
message.Entity = GetNetEntity(uid);
message.UiKey = uiKey;
@@ -75,8 +72,7 @@ namespace Robust.Client.GameObjects
boundInterface.Open();
uiComp.OpenInterfaces[uiKey] = boundInterface;
var playerSession = _playerManager.LocalPlayer?.Session;
if (playerSession != null)
if (_playerManager.LocalSession is { } playerSession)
{
uiComp.Interfaces[uiKey]._subscribedSessions.Add(playerSession);
RaiseLocalEvent(uid, new BoundUIOpenedEvent(uiKey, uid, playerSession), true);

View File

@@ -35,7 +35,7 @@ namespace Robust.Client.GameObjects
return;
}
var player = _playerManager.LocalPlayer?.ControlledEntity;
var player = _playerManager.LocalEntity;
if (player == null || !EntityManager.TryGetComponent(player.Value, out PhysicsComponent? body))
{

View File

@@ -232,9 +232,9 @@ namespace Robust.Client.GameStates
return default;
}
DebugTools.AssertNotNull(_players.LocalPlayer);
DebugTools.Assert(_players.LocalSession != null);
var evArgs = new EntitySessionEventArgs(_players.LocalPlayer!.Session);
var evArgs = new EntitySessionEventArgs(_players.LocalSession);
_pendingSystemMessages.Enqueue((_nextInputCmdSeq, _timing.CurTick, message,
new EntitySessionMessage<T>(evArgs, message)));

View File

@@ -313,7 +313,7 @@ namespace Robust.Client.GameStates
if (args.Length == 0)
{
entity = _playerManager.LocalPlayer?.ControlledEntity ?? EntityUid.Invalid;
entity = _playerManager.LocalEntity ?? EntityUid.Invalid;
}
else if (!NetEntity.TryParse(args[0], out var netEntity) || !_entManager.TryGetEntity(netEntity, out entity))
{

View File

@@ -6,7 +6,10 @@ using Robust.Shared.Maths;
namespace Robust.Client.Graphics
{
internal interface IRenderHandle
/// <remarks>
/// Unstable API. Likely to break hard during renderer rewrite if you rely on it.
/// </remarks>
public interface IRenderHandle
{
DrawingHandleScreen DrawingHandleScreen { get; }
DrawingHandleWorld DrawingHandleWorld { get; }

View File

@@ -126,7 +126,7 @@ namespace Robust.Client.Input
{
try
{
LoadKeyFile(path, true);
LoadKeyFile(path, false, true);
}
catch (Exception e)
{
@@ -136,7 +136,7 @@ namespace Robust.Client.Input
if (_resourceMan.ContentFileExists(path))
{
LoadKeyFile(path, false);
LoadKeyFile(path, true);
}
}
@@ -496,7 +496,13 @@ namespace Robust.Client.Input
return true;
}
private void LoadKeyFile(ResPath file, bool userData)
/// <summary>
/// Loads a keybind file, configuring keybinds.
/// </summary>
/// <param name="file">File to load from the content package</param>
/// <param name="defaultRegistration">Whether or not this is a "default" keybind set. If it is, then it won't override the current configuration, only the defaults.</param>
/// <param name="userData">Whether or not to load from the user data directory instead of the content package.</param>
public void LoadKeyFile(ResPath file, bool defaultRegistration, bool userData = false)
{
TextReader reader;
if (userData)
@@ -526,7 +532,7 @@ namespace Robust.Client.Input
continue;
}
if (!userData)
if (defaultRegistration)
{
_defaultRegistrations.Add(reg);
@@ -538,11 +544,11 @@ namespace Robust.Client.Input
}
}
RegisterBinding(reg, markModified: userData);
RegisterBinding(reg, markModified: defaultRegistration);
}
}
if (userData && mapping.TryGet("leaveEmpty", out var node))
if (!defaultRegistration && mapping.TryGet("leaveEmpty", out var node))
{
var leaveEmpty = _serialization.Read<BoundKeyFunction[]>(node, notNullableOverride: true);

View File

@@ -495,7 +495,7 @@ namespace Robust.Client.Placement
{
// Try to get current map.
var map = MapId.Nullspace;
if (EntityManager.TryGetComponent(PlayerManager.LocalPlayer?.ControlledEntity, out TransformComponent? xform))
if (EntityManager.TryGetComponent(PlayerManager.LocalEntity, out TransformComponent? xform))
{
map = xform.MapID;
}
@@ -512,7 +512,7 @@ namespace Robust.Client.Placement
private bool CurrentEraserMouseCoordinates(out EntityCoordinates coordinates)
{
var ent = PlayerManager.LocalPlayer?.ControlledEntity ?? EntityUid.Invalid;
var ent = PlayerManager.LocalEntity ?? EntityUid.Invalid;
if (ent == EntityUid.Invalid)
{
coordinates = new EntityCoordinates();
@@ -640,7 +640,7 @@ namespace Robust.Client.Placement
if (CurrentPermission is not {Range: > 0} ||
!CurrentMode.RangeRequired ||
PlayerManager.LocalPlayer?.ControlledEntity is not {Valid: true} controlled)
PlayerManager.LocalEntity is not {Valid: true} controlled)
return;
var worldPos = EntityManager.GetComponent<TransformComponent>(controlled).WorldPosition;

View File

@@ -216,7 +216,7 @@ namespace Robust.Client.Placement
{
if (!RangeRequired)
return true;
var controlled = pManager.PlayerManager.LocalPlayer?.ControlledEntity ?? EntityUid.Invalid;
var controlled = pManager.PlayerManager.LocalEntity ?? EntityUid.Invalid;
if (controlled == EntityUid.Invalid)
{
return false;

View File

@@ -10,14 +10,13 @@ namespace Robust.Client.Player
public override Filter FromEntities(Filter filter, params EntityUid[] entities)
{
if (_playerManager.LocalPlayer is not { } localPlayer
|| localPlayer.Session.AttachedEntity is not {Valid: true} attachedUid)
if (_playerManager.LocalEntity is not {Valid: true} attachedUid)
return filter;
foreach (var uid in entities)
{
if (uid == attachedUid)
filter.AddPlayer(localPlayer.Session);
filter.AddPlayer(_playerManager.LocalSession!);
}
return filter;

View File

@@ -36,12 +36,12 @@ internal sealed class ReplayRecordingManager : SharedReplayRecordingManager
private void OnRecordingStarted(MappingDataNode metadata, List<object> messages)
{
if (_player.LocalPlayer == null)
if (_player.LocalSession == null)
return;
// Add information about the user doing the recording. This is used to set the default replay observer position
// when playing back the replay.
var guid = _player.LocalPlayer.UserId.UserId.ToString();
var guid = _player.LocalUser.ToString();
metadata[ReplayConstants.MetaKeyRecordedBy] = new ValueDataNode(guid);
}

View File

@@ -545,6 +545,36 @@ namespace Robust.Client.UserInterface
Draw(renderHandle.DrawingHandleScreen);
}
protected internal virtual void PreRenderChildren(ref ControlRenderArguments args)
{
}
protected internal virtual void PostRenderChildren(ref ControlRenderArguments args)
{
}
protected internal virtual void RenderChildOverride(ref ControlRenderArguments args, int childIndex, Vector2i position)
{
RenderControl(ref args, childIndex, position);
}
public ref struct ControlRenderArguments
{
public IRenderHandle Handle;
public ref int Total;
public Vector2i Position;
public Color Modulate;
public UIBox2i? ScissorBox;
public ref Matrix3 CoordinateTransform;
}
protected void RenderControl(ref ControlRenderArguments args, int childIndex, Vector2i position)
{
UserInterfaceManagerInternal.RenderControl(args.Handle, ref args.Total, GetChild(childIndex), position, args.Modulate, args.ScissorBox, args.CoordinateTransform);
}
public void UpdateDraw()
{
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Client.Audio;
using Robust.Client.ResourceManagement;
using Robust.Shared.ContentPack;
@@ -37,8 +38,10 @@ namespace Robust.Client.UserInterface.Controls
get => _group;
set
{
if (value?.InternalButtons.Contains(this) ?? false)
return; // No work to do.
// Remove from old group.
_group?.Buttons.Remove(this);
_group?.InternalButtons.Remove(this);
_group = value;
@@ -47,11 +50,12 @@ namespace Robust.Client.UserInterface.Controls
return;
}
value.Buttons.Add(this);
value.InternalButtons.Add(this);
ToggleMode = true;
// Set us to pressed if we're the first button.
Pressed = value.Buttons.Count == 0;
// Set us to pressed if we're the first button. Doesn't go through the setter to avoid setting off our own error check.
_pressed = value.InternalButtons.Count == 1;
DrawModeChanged();
}
}
@@ -326,7 +330,7 @@ namespace Robust.Client.UserInterface.Controls
return;
}
foreach (var button in _group.Buttons)
foreach (var button in _group.InternalButtons)
{
if (button != this && button.Pressed)
{
@@ -440,6 +444,9 @@ namespace Robust.Client.UserInterface.Controls
/// </remarks>
public sealed class ButtonGroup
{
internal readonly List<BaseButton> Buttons = new();
internal readonly List<BaseButton> InternalButtons = new();
public IReadOnlyList<BaseButton> Buttons => InternalButtons;
public BaseButton? Pressed => InternalButtons.FirstOrDefault(x => x.Pressed);
}
}

View File

@@ -12,6 +12,7 @@ namespace Robust.Client.UserInterface.Controls
public class OptionButton : ContainerButton
{
public const string StyleClassOptionButton = "optionButton";
public const string StyleClassPopup = "optionButtonPopup";
public const string StyleClassOptionTriangle = "optionTriangle";
public readonly ScrollContainer OptionsScroll;
@@ -74,7 +75,8 @@ namespace Robust.Client.UserInterface.Controls
_popup = new Popup()
{
Children = { OptionsScroll }
Children = { new PanelContainer(), OptionsScroll },
StyleClasses = { StyleClassPopup }
};
_popup.OnPopupHide += OnPopupHide;
@@ -99,6 +101,11 @@ namespace Robust.Client.UserInterface.Controls
AddItem(label, id);
}
public virtual void ButtonOverride(Button button)
{
}
public void AddItem(string label, int? id = null)
{
if (id == null)
@@ -132,6 +139,8 @@ namespace Robust.Client.UserInterface.Controls
{
Select(0);
}
ButtonOverride(button);
}
private void TogglePopup(bool show)
@@ -139,6 +148,8 @@ namespace Robust.Client.UserInterface.Controls
if (show)
{
var globalPos = GlobalPosition;
globalPos.Y += Size.Y + 1; // Place it below us, with a safety margin.
globalPos.Y -= Margin.SumVertical;
OptionsScroll.Measure(Window?.Size ?? Vector2Helpers.Infinity);
var (minX, minY) = OptionsScroll.DesiredSize;
var box = UIBox2.FromDimensions(globalPos, new Vector2(Math.Max(minX, Width), minY));

View File

@@ -15,13 +15,13 @@ namespace Robust.Client.UserInterface.Controls
{
base.Draw(handle);
var style = _getStyleBox();
var style = GetStyleBox();
style?.Draw(handle, PixelSizeBox, UIScale);
}
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
var styleSize = _getStyleBox()?.MinimumSize ?? Vector2.Zero;
var styleSize = GetStyleBox()?.MinimumSize ?? Vector2.Zero;
var measureSize = Vector2.Max(availableSize - styleSize, Vector2.Zero);
var childSize = Vector2.Zero;
foreach (var child in Children)
@@ -36,7 +36,7 @@ namespace Robust.Client.UserInterface.Controls
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
var ourSize = UIBox2.FromDimensions(Vector2.Zero, finalSize);
var contentBox = _getStyleBox()?.GetContentBox(ourSize, 1) ?? ourSize;
var contentBox = GetStyleBox()?.GetContentBox(ourSize, 1) ?? ourSize;
foreach (var child in Children)
{
@@ -47,7 +47,7 @@ namespace Robust.Client.UserInterface.Controls
}
[System.Diagnostics.Contracts.Pure]
private StyleBox? _getStyleBox()
protected StyleBox? GetStyleBox()
{
if (PanelOverride != null)
{

View File

@@ -61,6 +61,9 @@ namespace Robust.Client.UserInterface
Vector2? CalcRelativeMousePositionFor(Control control, ScreenCoordinates mousePos);
Color GetMainClearColor();
void RenderControl(IRenderHandle renderHandle, ref int total, Control control, Vector2i position, Color modulate,
UIBox2i? scissorBox, Matrix3 coordinateTransform);
}
}

View File

@@ -132,9 +132,10 @@ internal sealed partial class UserInterfaceManager
try
{
var total = 0;
_render(renderHandle, ref total, root, Vector2i.Zero, Color.White, null);
var drawingHandle = renderHandle.DrawingHandleScreen;
drawingHandle.SetTransform(Vector2.Zero, Angle.Zero, Vector2.One);
drawingHandle.SetTransform(Matrix3.Identity);
RenderControl(renderHandle, ref total, root, Vector2i.Zero, Color.White, null, Matrix3.Identity);
drawingHandle.SetTransform(Matrix3.Identity);
OnPostDrawUIRoot?.Invoke(new PostDrawUIRootEventArgs(root, drawingHandle));
_prof.WriteValue("Controls rendered", ProfData.Int32(total));

View File

@@ -75,7 +75,7 @@ namespace Robust.Client.UserInterface
foreach (var root in _roots)
{
if (root.Stylesheet != null)
if (root.Stylesheet == null)
{
root.StylesheetUpdateRecursive();
}
@@ -329,8 +329,8 @@ namespace Robust.Client.UserInterface
}
}
private void _render(IRenderHandle renderHandle, ref int total, Control control, Vector2i position, Color modulate,
UIBox2i? scissorBox)
public void RenderControl(IRenderHandle renderHandle, ref int total, Control control, Vector2i position, Color modulate,
UIBox2i? scissorBox, Matrix3 coordinateTransform)
{
if (!control.Visible)
{
@@ -377,7 +377,10 @@ namespace Robust.Client.UserInterface
total += 1;
var handle = renderHandle.DrawingHandleScreen;
handle.SetTransform(position, Angle.Zero, Vector2.One);
var oldXform = handle.GetTransform();
var xform = oldXform;
xform.Multiply(Matrix3.CreateTransform(position, Angle.Zero, Vector2.One));
handle.SetTransform(xform);
modulate *= control.Modulate;
if (_rendering || control.AlwaysRender)
@@ -389,16 +392,32 @@ namespace Robust.Client.UserInterface
handle.Modulate = oldMod;
handle.UseShader(null);
}
handle.SetTransform(oldXform);
var args = new Control.ControlRenderArguments()
{
Handle = renderHandle,
Total = ref total,
Modulate = modulate,
ScissorBox = scissorRegion,
CoordinateTransform = ref coordinateTransform
};
control.PreRenderChildren(ref args);
foreach (var child in control.Children)
{
_render(renderHandle, ref total, child, position + child.PixelPosition, modulate, scissorRegion);
var pos = position + (Vector2i) coordinateTransform.Transform(child.PixelPosition);
control.RenderChildOverride(ref args, child.GetPositionInParent(), pos);
}
control.PostRenderChildren(ref args);
if (clip)
{
renderHandle.SetScissor(scissorBox);
}
handle.SetTransform(oldXform);
}
public Color GetMainClearColor() => RootControl.ActualBgColor;

View File

@@ -28,7 +28,7 @@ namespace Robust.Server.GameObjects
base.Initialize();
SubscribeLocalEvent<MapGridComponent, EmptyGridEvent>(HandleGridEmpty);
_cfg.OnValueChanged(CVars.GameDeleteEmptyGrids, SetGridDeletion, true);
Subs.CVar(_cfg, CVars.GameDeleteEmptyGrids, SetGridDeletion, true);
}
protected override void OnMapAdd(EntityUid uid, MapComponent component, ComponentAdd args)
@@ -64,13 +64,6 @@ namespace Robust.Server.GameObjects
return !(grid.GetAllTiles().Any());
}
public override void Shutdown()
{
base.Shutdown();
_cfg.UnsubValueChanged(CVars.GameDeleteEmptyGrids, SetGridDeletion);
}
private void HandleGridEmpty(EntityUid uid, MapGridComponent component, EmptyGridEvent args)
{
if (!_deleteEmptyGrids || TerminatingOrDeleted(uid) || HasComp<MapComponent>(uid))

View File

@@ -20,7 +20,8 @@ namespace Robust.Server.GameObjects
{
base.Initialize();
LoadMetricCVar();
_configurationManager.OnValueChanged(CVars.MetricsEnabled, _ => LoadMetricCVar());
Subs.CVar(_configurationManager, CVars.MetricsEnabled, _ => LoadMetricCVar());
}
private void LoadMetricCVar()

View File

@@ -126,11 +126,12 @@ internal sealed partial class PvsSystem : EntitySystem
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
_transform.OnGlobalMoveEvent += OnEntityMove;
_configManager.OnValueChanged(CVars.NetPVS, SetPvs, true);
_configManager.OnValueChanged(CVars.NetMaxUpdateRange, OnViewsizeChanged, true);
_configManager.OnValueChanged(CVars.NetLowLodRange, OnLodChanged, true);
_configManager.OnValueChanged(CVars.NetForceAckThreshold, OnForceAckChanged, true);
_configManager.OnValueChanged(CVars.NetPvsAsync, OnAsyncChanged, true);
Subs.CVar(_configManager, CVars.NetPVS, SetPvs, true);
Subs.CVar(_configManager, CVars.NetMaxUpdateRange, OnViewsizeChanged, true);
Subs.CVar(_configManager, CVars.NetLowLodRange, OnLodChanged, true);
Subs.CVar(_configManager, CVars.NetForceAckThreshold, OnForceAckChanged, true);
Subs.CVar(_configManager, CVars.NetPvsAsync, OnAsyncChanged, true);
Subs.CVar(_configManager, CVars.NetPvsCompressLevel, ResetParallelism, true);
_serverGameStateManager.ClientAck += OnClientAck;
_serverGameStateManager.ClientRequestFull += OnClientRequestFull;
@@ -138,7 +139,6 @@ internal sealed partial class PvsSystem : EntitySystem
InitializeDirty();
_parallelMgr.ParallelCountChanged += ResetParallelism;
_configManager.OnValueChanged(CVars.NetPvsCompressLevel, ResetParallelism, true);
}
public override void Shutdown()
@@ -148,10 +148,6 @@ internal sealed partial class PvsSystem : EntitySystem
_playerManager.PlayerStatusChanged -= OnPlayerStatusChanged;
_transform.OnGlobalMoveEvent -= OnEntityMove;
_configManager.UnsubValueChanged(CVars.NetPVS, SetPvs);
_configManager.UnsubValueChanged(CVars.NetMaxUpdateRange, OnViewsizeChanged);
_configManager.UnsubValueChanged(CVars.NetForceAckThreshold, OnForceAckChanged);
_configManager.UnsubValueChanged(CVars.NetPvsCompressLevel, ResetParallelism);
_parallelMgr.ParallelCountChanged -= ResetParallelism;
_serverGameStateManager.ClientAck -= OnClientAck;

View File

@@ -64,7 +64,7 @@ namespace Robust.Server.Physics
SubscribeNetworkEvent<RequestGridNodesMessage>(OnDebugRequest);
SubscribeNetworkEvent<StopGridNodesMessage>(OnDebugStopRequest);
_cfg.OnValueChanged(CVars.GridSplitting, SetSplitAllowed, true);
Subs.CVar(_cfg, CVars.GridSplitting, SetSplitAllowed, true);
}
private void SetSplitAllowed(bool value) => SplitAllowed = value;
@@ -73,7 +73,6 @@ namespace Robust.Server.Physics
{
base.Shutdown();
_subscribedSessions.Clear();
_cfg.UnsubValueChanged(CVars.GridSplitting, SetSplitAllowed);
}
/// <summary>

View File

@@ -50,17 +50,11 @@ public abstract partial class SharedAudioSystem : EntitySystem
base.Initialize();
InitializeEffect();
ZOffset = CfgManager.GetCVar(CVars.AudioZOffset);
CfgManager.OnValueChanged(CVars.AudioZOffset, SetZOffset);
Subs.CVar(CfgManager, CVars.AudioZOffset, SetZOffset);
SubscribeLocalEvent<AudioComponent, ComponentGetStateAttemptEvent>(OnAudioGetStateAttempt);
SubscribeLocalEvent<AudioComponent, EntityUnpausedEvent>(OnAudioUnpaused);
}
public override void Shutdown()
{
base.Shutdown();
CfgManager.UnsubValueChanged(CVars.AudioZOffset, SetZOffset);
}
protected void SetZOffset(float value)
{
ZOffset = value;

View File

@@ -1239,7 +1239,7 @@ namespace Robust.Shared
/// Enable Discord rich presence integration.
/// </summary>
public static readonly CVarDef<bool> DiscordEnabled =
CVarDef.Create("discord.enabled", true, CVar.CLIENTONLY);
CVarDef.Create("discord.enabled", true, CVar.CLIENTONLY | CVar.ARCHIVE);
public static readonly CVarDef<string> DiscordRichPresenceMainIconId =
CVarDef.Create("discord.rich_main_icon_id", "devstation", CVar.SERVER | CVar.REPLICATED);

View File

@@ -73,6 +73,9 @@ WhitelistedNamespaces:
# * The API is not *relevant* to content. e.g. System.Type.IsAnsiClass.
# * I am lazy these API lists are huge dude.
Types:
Avalonia.Metadata:
XmlnsDefinitionAttribute:
All: True
NetSerializer:
NetListAsArray`1:
Fields:
@@ -626,6 +629,7 @@ Types:
- "System.Text.Encoding get_UTF7()"
- "System.Text.Encoding get_UTF8()"
- "System.Text.Encoding get_UTF32()"
- "System.Text.Encoding GetEncoding(string)"
NormalizationForm: { } # Enum
Rune: { All: True }
StringBuilder:
@@ -716,6 +720,9 @@ Types:
ChunkEnumerator: { All: True }
AppendInterpolatedStringHandler: { All: True }
StringRuneEnumerator: { All: True }
System.Text.Unicode:
UnicodeRange: { All: True }
UnicodeRanges: { All: True }
System.Threading.Tasks:
Task: { All: True }
Task`1: { All: True }

View File

@@ -1,12 +1,12 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Robust.Shared.Collections;
namespace Robust.Shared.GameObjects
{
public abstract partial class EntitySystem
{
private List<SubBase>? _subscriptions;
private ValueList<SubBase> _subscriptions;
/// <summary>
/// A handle to allow subscription on this entity system's behalf.
@@ -84,7 +84,6 @@ namespace Robust.Shared.GameObjects
{
EntityManager.EventBus.SubscribeEvent(src, this, handler, GetType(), before, after);
_subscriptions ??= new();
_subscriptions.Add(new SubBroadcast<T>(src));
}
@@ -96,7 +95,6 @@ namespace Robust.Shared.GameObjects
{
EntityManager.EventBus.SubscribeEvent(src, this, handler, GetType(), before, after);
_subscriptions ??= new();
_subscriptions.Add(new SubBroadcast<T>(src));
}
@@ -108,7 +106,6 @@ namespace Robust.Shared.GameObjects
{
EntityManager.EventBus.SubscribeSessionEvent(src, this, handler, GetType(), before, after);
_subscriptions ??= new();
_subscriptions.Add(new SubBroadcast<EntitySessionMessage<T>>(src));
}
@@ -122,7 +119,6 @@ namespace Robust.Shared.GameObjects
{
EntityManager.EventBus.SubscribeLocalEvent(handler, GetType(), before, after);
_subscriptions ??= new();
_subscriptions.Add(new SubLocal<TComp, TEvent>());
}
@@ -134,7 +130,6 @@ namespace Robust.Shared.GameObjects
{
EntityManager.EventBus.SubscribeLocalEvent(handler, GetType(), before, after);
_subscriptions ??= new();
_subscriptions.Add(new SubLocal<TComp, TEvent>());
}
@@ -146,21 +141,17 @@ namespace Robust.Shared.GameObjects
{
EntityManager.EventBus.SubscribeLocalEvent(handler, GetType(), before, after);
_subscriptions ??= new();
_subscriptions.Add(new SubLocal<TComp, TEvent>());
}
private void ShutdownSubscriptions()
{
if (_subscriptions == null)
return;
foreach (var sub in _subscriptions)
{
sub.Unsubscribe(this, EntityManager.EventBus);
}
_subscriptions = null;
_subscriptions = default;
}
/// <summary>
@@ -232,6 +223,19 @@ namespace Robust.Shared.GameObjects
{
System.SubscribeLocalEvent(handler, before, after);
}
/// <summary>
/// Register an action to be ran when this entity system is shut down.
/// </summary>
/// <remarks>
/// This can be used by extension methods for <see cref="Subscriptions"/>
/// to unsubscribe from from external sources such as CVars.
/// </remarks>
/// <param name="action">An action to be ran when the entity system is shut down.</param>
public void RegisterUnsubscription(Action action)
{
System._subscriptions.Add(new SubAction(action));
}
}
private abstract class SubBase
@@ -261,5 +265,13 @@ namespace Robust.Shared.GameObjects
bus.UnsubscribeLocalEvent<TComp, TBase>();
}
}
private sealed class SubAction(Action action) : SubBase
{
public override void Unsubscribe(EntitySystem sys, IEventBus bus)
{
action();
}
}
}
}

View File

@@ -0,0 +1,130 @@
using System;
using Robust.Shared.Configuration;
namespace Robust.Shared.GameObjects;
/// <summary>
/// Extra subscription helpers for <see cref="EntitySystem"/> that are not part of the core entity system behavior.
/// </summary>
public static class EntitySystemSubscriptionExt
{
/// <summary>
/// Listen for an event for if the config value changes.
/// </summary>
/// <remarks>
/// This is an O(n) operation.
/// </remarks>
/// <param name="subs">
/// The entity system subscriptions.
/// Call this with <see cref="EntitySystem.Subscriptions"/>.
/// </param>
/// <param name="cfg">The configuration manager.</param>
/// <param name="name">The name of the CVar to listen for.</param>
/// <param name="onValueChanged">The delegate to run when the value was changed.</param>
/// <param name="invokeImmediately">
/// Whether to run the callback immediately inw this method. Can help reduce boilerplate
/// </param>
/// <typeparam name="T">The type of value contained in this CVar.</typeparam>
public static void CVar<T>(
this EntitySystem.Subscriptions subs,
IConfigurationManager cfg,
string name,
Action<T> onValueChanged,
bool invokeImmediately = false)
where T : notnull
{
cfg.OnValueChanged(name, onValueChanged, invokeImmediately);
subs.RegisterUnsubscription(() => cfg.UnsubValueChanged(name, onValueChanged));
}
/// <summary>
/// Listen for an event for if the config value changes.
/// </summary>
/// <remarks>
/// This is an O(n) operation.
/// </remarks>
/// <param name="subs">
/// The entity system subscriptions.
/// Call this with <see cref="EntitySystem.Subscriptions"/>.
/// </param>
/// <param name="cfg">The configuration manager.</param>
/// <param name="cVar">The CVar to listen for.</param>
/// <param name="onValueChanged">The delegate to run when the value was changed.</param>
/// <param name="invokeImmediately">
/// Whether to run the callback immediately in this method. Can help reduce boilerplate
/// </param>
/// <typeparam name="T">The type of value contained in this CVar.</typeparam>
public static void CVar<T>(
this EntitySystem.Subscriptions subs,
IConfigurationManager cfg,
CVarDef<T> cVar,
Action<T> onValueChanged,
bool invokeImmediately = false)
where T : notnull
{
cfg.OnValueChanged(cVar, onValueChanged, invokeImmediately);
subs.RegisterUnsubscription(() => cfg.UnsubValueChanged(cVar, onValueChanged));
}
/// <summary>
/// Listen for an event for if the config value changes.
/// </summary>
/// <remarks>
/// This is an O(n) operation.
/// </remarks>
/// <param name="subs">
/// The entity system subscriptions.
/// Call this with <see cref="EntitySystem.Subscriptions"/>.
/// </param>
/// <param name="cfg">The configuration manager.</param>
/// <param name="name">The name of the CVar to listen for.</param>
/// <param name="onValueChanged">The delegate to run when the value was changed.</param>
/// <param name="invokeImmediately">
/// Whether to run the callback immediately in this method. Can help reduce boilerplate
/// </param>
/// <typeparam name="T">The type of value contained in this CVar.</typeparam>
public static void CVar<T>(
this EntitySystem.Subscriptions subs,
IConfigurationManager cfg,
string name,
CVarChanged<T> onValueChanged,
bool invokeImmediately = false)
where T : notnull
{
cfg.OnValueChanged(name, onValueChanged, invokeImmediately);
subs.RegisterUnsubscription(() => cfg.UnsubValueChanged(name, onValueChanged));
}
/// <summary>
/// Listen for an event for if the config value changes.
/// </summary>
/// <remarks>
/// This is an O(n) operation.
/// </remarks>
/// <param name="subs">
/// The entity system subscriptions.
/// Call this with <see cref="EntitySystem.Subscriptions"/>.
/// </param>
/// <param name="cfg">The configuration manager.</param>
/// <param name="cVar">The CVar to listen for.</param>
/// <param name="onValueChanged">The delegate to run when the value was changed.</param>
/// <param name="invokeImmediately">
/// Whether to run the callback immediately in this method. Can help reduce boilerplate
/// </param>
/// <typeparam name="T">The type of value contained in this CVar.</typeparam>
public static void CVar<T>(
this EntitySystem.Subscriptions subs,
IConfigurationManager cfg,
CVarDef<T> cVar,
CVarChanged<T> onValueChanged,
bool invokeImmediately = false)
where T : notnull
{
cfg.OnValueChanged(cVar, onValueChanged, invokeImmediately);
subs.RegisterUnsubscription(() => cfg.UnsubValueChanged(cVar, onValueChanged));
}
}

View File

@@ -36,8 +36,8 @@ namespace Robust.Shared.GameObjects
base.Initialize();
UpdatesBefore.Add(typeof(SharedBroadphaseSystem));
_cfg.OnValueChanged(CVars.GenerateGridFixtures, SetEnabled, true);
_cfg.OnValueChanged(CVars.GridFixtureEnlargement, SetEnlargement, true);
Subs.CVar(_cfg, CVars.GenerateGridFixtures, SetEnabled, true);
Subs.CVar(_cfg, CVars.GridFixtureEnlargement, SetEnlargement, true);
SubscribeLocalEvent<GridInitializeEvent>(OnGridInit);
SubscribeLocalEvent<RegenerateGridBoundsEvent>(OnGridBoundsRegenerate);
@@ -58,14 +58,6 @@ namespace Robust.Shared.GameObjects
_map.RegenerateCollision(ev.EntityUid, grid, _map.GetMapChunks(ev.EntityUid, grid).Values.ToHashSet());
}
public override void Shutdown()
{
base.Shutdown();
_cfg.UnsubValueChanged(CVars.GenerateGridFixtures, SetEnabled);
_cfg.UnsubValueChanged(CVars.GridFixtureEnlargement, SetEnlargement);
}
private void SetEnabled(bool value) => _enabled = value;
private void SetEnlargement(float value) => _fixtureEnlargement = value;

View File

@@ -67,14 +67,7 @@ namespace Robust.Shared.Physics.Systems
UpdatesOutsidePrediction = true;
UpdatesAfter.Add(typeof(SharedTransformSystem));
_cfg.OnValueChanged(CVars.BroadphaseExpand, SetBroadphaseExpand, true);
}
public override void Shutdown()
{
base.Shutdown();
_cfg.UnsubValueChanged(CVars.BroadphaseExpand, SetBroadphaseExpand);
Subs.CVar(_cfg, CVars.BroadphaseExpand, SetBroadphaseExpand, true);
}
private void SetBroadphaseExpand(float value) => _broadphaseExpand = value;

View File

@@ -199,38 +199,20 @@ public abstract partial class SharedPhysicsSystem
private void InitializeIsland()
{
_configManager.OnValueChanged(CVars.NetTickrate, SetTickRate, true);
_configManager.OnValueChanged(CVars.WarmStarting, SetWarmStarting, true);
_configManager.OnValueChanged(CVars.MaxLinearCorrection, SetMaxLinearCorrection, true);
_configManager.OnValueChanged(CVars.MaxAngularCorrection, SetMaxAngularCorrection, true);
_configManager.OnValueChanged(CVars.VelocityIterations, SetVelocityIterations, true);
_configManager.OnValueChanged(CVars.PositionIterations, SetPositionIterations, true);
_configManager.OnValueChanged(CVars.MaxLinVelocity, SetMaxLinearVelocity, true);
_configManager.OnValueChanged(CVars.MaxAngVelocity, SetMaxAngularVelocity, true);
_configManager.OnValueChanged(CVars.SleepAllowed, SetSleepAllowed, true);
_configManager.OnValueChanged(CVars.AngularSleepTolerance, SetAngularToleranceSqr, true);
_configManager.OnValueChanged(CVars.LinearSleepTolerance, SetLinearToleranceSqr, true);
_configManager.OnValueChanged(CVars.TimeToSleep, SetTimeToSleep, true);
_configManager.OnValueChanged(CVars.VelocityThreshold, SetVelocityThreshold, true);
_configManager.OnValueChanged(CVars.Baumgarte, SetBaumgarte, true);
}
private void ShutdownIsland()
{
_configManager.UnsubValueChanged(CVars.NetTickrate, SetTickRate);
_configManager.UnsubValueChanged(CVars.WarmStarting, SetWarmStarting);
_configManager.UnsubValueChanged(CVars.MaxLinearCorrection, SetMaxLinearCorrection);
_configManager.UnsubValueChanged(CVars.MaxAngularCorrection, SetMaxAngularCorrection);
_configManager.UnsubValueChanged(CVars.VelocityIterations, SetVelocityIterations);
_configManager.UnsubValueChanged(CVars.PositionIterations, SetPositionIterations);
_configManager.UnsubValueChanged(CVars.MaxLinVelocity, SetMaxLinearVelocity);
_configManager.UnsubValueChanged(CVars.MaxAngVelocity, SetMaxAngularVelocity);
_configManager.UnsubValueChanged(CVars.SleepAllowed, SetSleepAllowed);
_configManager.UnsubValueChanged(CVars.AngularSleepTolerance, SetAngularToleranceSqr);
_configManager.UnsubValueChanged(CVars.LinearSleepTolerance, SetLinearToleranceSqr);
_configManager.UnsubValueChanged(CVars.TimeToSleep, SetTimeToSleep);
_configManager.UnsubValueChanged(CVars.VelocityThreshold, SetVelocityThreshold);
_configManager.UnsubValueChanged(CVars.Baumgarte, SetBaumgarte);
Subs.CVar(_configManager, CVars.NetTickrate, SetTickRate, true);
Subs.CVar(_configManager, CVars.WarmStarting, SetWarmStarting, true);
Subs.CVar(_configManager, CVars.MaxLinearCorrection, SetMaxLinearCorrection, true);
Subs.CVar(_configManager, CVars.MaxAngularCorrection, SetMaxAngularCorrection, true);
Subs.CVar(_configManager, CVars.VelocityIterations, SetVelocityIterations, true);
Subs.CVar(_configManager, CVars.PositionIterations, SetPositionIterations, true);
Subs.CVar(_configManager, CVars.MaxLinVelocity, SetMaxLinearVelocity, true);
Subs.CVar(_configManager, CVars.MaxAngVelocity, SetMaxAngularVelocity, true);
Subs.CVar(_configManager, CVars.SleepAllowed, SetSleepAllowed, true);
Subs.CVar(_configManager, CVars.AngularSleepTolerance, SetAngularToleranceSqr, true);
Subs.CVar(_configManager, CVars.LinearSleepTolerance, SetLinearToleranceSqr, true);
Subs.CVar(_configManager, CVars.TimeToSleep, SetTimeToSleep, true);
Subs.CVar(_configManager, CVars.VelocityThreshold, SetVelocityThreshold, true);
Subs.CVar(_configManager, CVars.Baumgarte, SetBaumgarte, true);
}
private void SetWarmStarting(bool value) => _warmStarting = value;

View File

@@ -92,9 +92,9 @@ namespace Robust.Shared.Physics.Systems
InitializeIsland();
InitializeContacts();
_configManager.OnValueChanged(CVars.AutoClearForces, OnAutoClearChange);
_configManager.OnValueChanged(CVars.NetTickrate, UpdateSubsteps, true);
_configManager.OnValueChanged(CVars.TargetMinimumTickrate, UpdateSubsteps, true);
Subs.CVar(_configManager, CVars.AutoClearForces, OnAutoClearChange);
Subs.CVar(_configManager, CVars.NetTickrate, UpdateSubsteps, true);
Subs.CVar(_configManager, CVars.TargetMinimumTickrate, UpdateSubsteps, true);
}
private void OnPhysicsShutdown(EntityUid uid, PhysicsComponent component, ComponentShutdown args)
@@ -250,8 +250,6 @@ namespace Robust.Shared.Physics.Systems
base.Shutdown();
ShutdownContacts();
ShutdownIsland();
_configManager.UnsubValueChanged(CVars.AutoClearForces, OnAutoClearChange);
}
private void UpdateMapAwakeState(EntityUid uid, PhysicsComponent body)

View File

@@ -0,0 +1,65 @@
using System;
using System.Globalization;
using JetBrains.Annotations;
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
namespace Robust.Shared.Serialization.TypeSerializers.Implementations;
/// <summary>
/// Implements serialization for <see cref="DateTime"/>.
/// </summary>
/// <remarks>
/// Serialization is implemented with <see cref="DateTimeStyles.RoundtripKind"/> and the "o" format specifier.
/// </remarks>
[TypeSerializer]
public sealed class DateTimeSerializer : ITypeSerializer<DateTime, ValueDataNode>, ITypeCopyCreator<DateTime>
{
public ValidationNode Validate(
ISerializationManager serializationManager,
ValueDataNode node,
IDependencyCollection dependencies,
ISerializationContext? context = null)
{
return DateTime.TryParse(node.Value, null, DateTimeStyles.RoundtripKind, out _)
? new ValidatedValueNode(node)
: new ErrorNode(node, "Failed parsing DateTime");
}
public DateTime Read(
ISerializationManager serializationManager,
ValueDataNode node,
IDependencyCollection dependencies,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<DateTime>? instanceProvider = null)
{
return DateTime.Parse(node.Value, null, DateTimeStyles.RoundtripKind);
}
public DataNode Write(
ISerializationManager serializationManager,
DateTime value,
IDependencyCollection dependencies,
bool alwaysWrite = false,
ISerializationContext? context = null)
{
return new ValueDataNode(value.ToString("o"));
}
[MustUseReturnValue]
public DateTime CreateCopy(
ISerializationManager serializationManager,
DateTime source,
IDependencyCollection dependencies,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
return source;
}
}

View File

@@ -759,8 +759,9 @@ namespace Robust.UnitTesting
public sealed class ClientIntegrationInstance : IntegrationInstance
{
[Obsolete("Use Session instead")]
public LocalPlayer? Player => ((IPlayerManager) PlayerMan).LocalPlayer;
public ICommonSession? Session => Player?.Session;
public ICommonSession? Session => ((IPlayerManager) PlayerMan).LocalSession;
public NetUserId? User => Session?.UserId;
public EntityUid? AttachedEntity => Session?.AttachedEntity;

View File

@@ -73,8 +73,8 @@ public sealed class DisconnectTest : RobustIntegrationTest
session = sPlayerMan.Sessions.Single();
Assert.That(session.Status, Is.EqualTo(SessionStatus.Connected));
Assert.That(session.UserId, Is.EqualTo(cPlayerMan!.LocalPlayer?.UserId));
Assert.That(cPlayerMan.LocalPlayer, Is.Not.Null);
Assert.That(session.UserId, Is.EqualTo(cPlayerMan.LocalUser));
Assert.That(cPlayerMan.LocalSession, Is.Not.Null);
}
void AssertDisconnected()

View File

@@ -0,0 +1,31 @@
using System;
using System.Globalization;
using NUnit.Framework;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Serialization.TypeSerializers.Implementations;
namespace Robust.UnitTesting.Shared.Serialization.TypeSerializers;
[TestFixture]
[TestOf(typeof(DateTimeSerializer))]
internal sealed class DateTimeSerializerTest : SerializationTest
{
[Test]
public void WriteTest()
{
var dateTime = DateTime.UtcNow;
var result = Serialization.WriteValueAs<ValueDataNode>(dateTime);
var parsed = DateTime.Parse(result.Value, null, DateTimeStyles.RoundtripKind);
Assert.That(parsed, Is.EqualTo(dateTime));
}
[Test]
public void ReadTest()
{
var result = Serialization.Read<DateTime>(new ValueDataNode("2020-07-10 15:00:00.000"));
Assert.That(result, Is.EqualTo(new DateTime(2020, 07, 10, 15, 0, 0)));
}
}