mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15eded3da8 | ||
|
|
b4165e8661 | ||
|
|
ad339b5bfd | ||
|
|
e1197af8ce | ||
|
|
102cadf3a6 | ||
|
|
e7723b61bc | ||
|
|
a9d17337a3 | ||
|
|
74622bac83 | ||
|
|
a3047b1687 | ||
|
|
3a55118143 | ||
|
|
3c5fbc648a | ||
|
|
f9c39bce0b | ||
|
|
0e8c803c0f | ||
|
|
6bb7b88c69 |
@@ -1,4 +1,4 @@
|
||||
<Project>
|
||||
|
||||
<!-- This file automatically reset by Tools/version.py -->
|
||||
<!-- This file automatically reset by Tools/version.py -->
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -42,6 +42,8 @@ public sealed partial class ClientEntityManager
|
||||
var pending = PendingNetEntityStates.GetOrNew(nEntity);
|
||||
pending.Add((typeof(T), callerEntity));
|
||||
|
||||
|
||||
|
||||
return entity.Item1;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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)));
|
||||
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
130
Robust.Shared/GameObjects/EntitySystemSubscriptionExt.cs
Normal file
130
Robust.Shared/GameObjects/EntitySystemSubscriptionExt.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user