Compare commits

...

24 Commits

Author SHA1 Message Date
Pieter-Jan Briers
18c32a0258 Don't ServerSendToAll to channels without completed handshake. 2021-07-21 03:06:32 +02:00
Pieter-Jan Briers
72314a102d EventBus improvements
Can do ordered session event subscription.

Can subscribe to "All" in one call, to reduce shared boilerplate.
2021-07-21 00:56:42 +02:00
Pieter-Jan Briers
719ea26a31 IConfigurationManager.UnsubValueChanged. 2021-07-20 17:26:52 +02:00
metalgearsloth
5cb8fe1897 End IEndCollide (#1874) 2021-07-20 17:01:30 +02:00
metalgearsloth
f35a52fc24 Change KinematicControllerCollision to use WorldNormal instead (#1872)
Content cares about the WorldNormal and not the LocalNormal so this fixes pushing bugs.
2021-07-19 10:17:39 +02:00
metalgearsloth
6bdb0cef47 Fix IMapGrid WorldToLocal + LocalToWorld (#1871) 2021-07-19 10:17:15 +02:00
Pieter-Jan Briers
fe3c9fe28f Fix late nwVar warning on connect. 2021-07-19 10:16:24 +02:00
Pieter-Jan Briers
6085671f22 Fix memory leak with physics islands and contact solvers.
They were doing config OnValueChanged for every instance and, as such, never getting released.
2021-07-19 10:06:20 +02:00
Visne
a2398da324 Replace most VBox/HBoxContainers with BoxContainers (#1867) 2021-07-18 18:42:08 +02:00
Pieter-Jan Briers
b27304cc58 Add System.Index and System.Range to sandbox whitelist. 2021-07-17 23:51:57 +02:00
Swept
3bf851a6cf FPS Counter no longer shows a decimal 2021-07-17 16:46:09 +00:00
Pieter-Jan Briers
cef92efd0f NetManager now enforces that only specific messages can be sent before serializer handshake completes. 2021-07-17 14:37:40 +02:00
Pieter-Jan Briers
c5961a5ab1 Fix possible race condition in net var handling and improve logging. 2021-07-17 14:37:35 +02:00
Pieter-Jan Briers
8ddd92993d Don't do initial net var stuff on server. 2021-07-17 02:03:37 +02:00
Pieter-Jan Briers
da253a5f34 Log user ID correctly on connection approval 2021-07-17 02:02:59 +02:00
Pieter-Jan Briers
ca9400a1ff Don't log encryption secrets on auth handshake. 2021-07-17 01:24:39 +02:00
Pieter-Jan Briers
f232195ceb Fix audio log warning not using interpolated string correctly. 2021-07-17 01:17:23 +02:00
Pieter-Jan Briers
b54a803519 Add ToString to NetChannel.
Some things already try to log like this so let's just go with it.
2021-07-17 01:16:47 +02:00
Vera Aguilera Puerto
a0d3d2108f Use ResourcePath instead of Path.Join 2021-07-16 21:48:19 +02:00
Vera Aguilera Puerto
977e4a017b Fixes tile window hardcoding tile sprites. 2021-07-16 08:21:58 +02:00
Swept
2d8b159016 Updates the dumb shit stupid path for tile window 2021-07-16 05:38:19 +00:00
Visne
9caa0dde4b Remove unused IEntityManager parameter from EntityCoordinates.FromMap() (#1866) 2021-07-15 18:51:11 +02:00
Pieter-Jan Briers
7a5a8c5eb1 Remove unused Process.WaitForExitAsync helper.
.NET 5 has its own implementation so we use that now.
2021-07-15 10:07:52 +02:00
Swept
95ba58f0a4 Fixes SpriteComponent error reporting 2021-07-14 22:41:51 +00:00
61 changed files with 774 additions and 325 deletions

View File

@@ -27,6 +27,7 @@ using Robust.Shared.Reflection;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.Console.Commands
{
@@ -536,7 +537,10 @@ namespace Robust.Client.Console.Commands
var scroll = new ScrollContainer();
tabContainer.AddChild(scroll);
//scroll.SetAnchorAndMarginPreset(Control.LayoutPreset.Wide);
var vBox = new VBoxContainer();
var vBox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
};
scroll.AddChild(vBox);
var progressBar = new ProgressBar { MaxValue = 10, Value = 5 };
@@ -594,7 +598,10 @@ namespace Robust.Client.Console.Commands
}
var group = new ButtonGroup();
var vBoxRadioButtons = new VBoxContainer();
var vBoxRadioButtons = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
};
for (var i = 0; i < 10; i++)
{
vBoxRadioButtons.AddChild(new Button
@@ -610,8 +617,9 @@ namespace Robust.Client.Console.Commands
TabContainer.SetTabTitle(vBoxRadioButtons, "Radio buttons!!");
tabContainer.AddChild(new VBoxContainer
tabContainer.AddChild(new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
Name = "Slider",
Children =
{

View File

@@ -11,6 +11,7 @@ using Robust.Shared.IoC;
using Robust.Shared.Reflection;
using Robust.Shared.Scripting;
using Robust.Shared.Timing;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.Console
{
@@ -18,7 +19,7 @@ namespace Robust.Client.Console
{
private readonly IReflectionManager _reflectionManager;
private readonly VBoxContainer _watchesVBox;
private readonly BoxContainer _watchesVBox;
private readonly LineEdit _addWatchEdit;
private readonly Button _addWatchButton;
@@ -31,17 +32,20 @@ namespace Robust.Client.Console
Title = "Watch Window";
var mainVBox = new VBoxContainer
var mainVBox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
MinSize = (500, 300),
Children =
{
(_watchesVBox = new VBoxContainer
(_watchesVBox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
VerticalExpand = true
}),
new HBoxContainer
new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
(_addWatchEdit = new HistoryLineEdit
@@ -105,8 +109,9 @@ namespace Robust.Client.Console
Button delButton;
_runner = runner;
AddChild(new HBoxContainer
AddChild(new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
(_outputLabel = new Label
@@ -166,8 +171,9 @@ namespace Robust.Client.Console
public CompilationErrorControl(string message)
{
Button delButton;
AddChild(new HBoxContainer
AddChild(new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
new Label

View File

@@ -365,7 +365,7 @@ namespace Robust.Client.GameObjects
}
else
{
Logger.ErrorS(LogCategory, "Unable to load RSI '{0}'. Trace:\n{1}", rsiPath);
Logger.ErrorS(LogCategory, "Unable to load RSI '{0}'.", rsiPath);
}
}
}

View File

@@ -301,7 +301,7 @@ namespace Robust.Client.GameObjects
if (!source.SetPosition(coordinates.ToMapPos(EntityManager)))
{
source.Dispose();
Logger.Warning("Can't play positional audio \"{stream.Name}\", can't set position.");
Logger.Warning($"Can't play positional audio \"{stream.Name}\", can't set position.");
return null;
}

View File

@@ -8,6 +8,7 @@ using Robust.Client.Utility;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
@@ -62,7 +63,7 @@ namespace Robust.Client.Map
var row = i / dimensionX;
Image<Rgba32> image;
using (var stream = _resourceCache.ContentFileRead(Path.Join(def.Path, $"{def.SpriteName}.png")))
using (var stream = _resourceCache.ContentFileRead(new ResourcePath(def.Path) / $"{def.SpriteName}.png"))
{
image = Image.Load<Rgba32>(stream);
}

View File

@@ -504,8 +504,8 @@ namespace Robust.Client.Placement
coordinates = new EntityCoordinates();
return false;
}
coordinates = EntityCoordinates.FromMap(ent.EntityManager, MapManager,
eyeManager.ScreenToMap(_inputManager.MouseScreenPosition));
coordinates = EntityCoordinates.FromMap(MapManager,
eyeManager.ScreenToMap(_inputManager.MouseScreenPosition));
return true;
}
}

View File

@@ -250,7 +250,7 @@ namespace Robust.Client.Placement
var mapCoords = pManager.eyeManager.ScreenToMap(coords.Position);
if (!pManager.MapManager.TryFindGridAt(mapCoords, out var grid))
{
return EntityCoordinates.FromMap(pManager.EntityManager, pManager.MapManager, mapCoords);
return EntityCoordinates.FromMap(pManager.MapManager, mapCoords);
}
return EntityCoordinates.FromMap(pManager.EntityManager, grid.GridEntityId, mapCoords);

View File

@@ -18,8 +18,9 @@ namespace Robust.Client.UserInterface.Controls
{
ToggleMode = true;
var hBox = new HBoxContainer
var hBox = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
StyleClasses = { StyleClassCheckBox },
};
AddChild(hBox);

View File

@@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.UserInterface.Controls
{
@@ -13,9 +14,9 @@ namespace Robust.Client.UserInterface.Controls
{
private readonly List<Menu> _menus = new();
private readonly List<MenuBarTopButton> _buttons = new();
private readonly HBoxContainer _hBox;
private readonly BoxContainer _hBox;
private readonly Popup _popup;
private readonly VBoxContainer _popupVBox;
private readonly BoxContainer _popupVBox;
private bool _popupOpen;
public IList<Menu> Menus { get; }
@@ -26,13 +27,21 @@ namespace Robust.Client.UserInterface.Controls
{
Children =
{
(_popupVBox = new VBoxContainer {MinSize = (300, 0)})
(_popupVBox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
MinSize = (300, 0)
})
}
};
_popup.OnPopupHide += PopupHidden;
UserInterfaceManager.ModalRoot.AddChild(_popup);
Menus = new MenuCollection(this);
AddChild(_hBox = new HBoxContainer {SeparationOverride = 8});
AddChild(_hBox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
SeparationOverride = 8
});
}
private void AddMenu(Menu menu)

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Robust.Client.Graphics;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.UserInterface.Controls
{
@@ -20,7 +21,7 @@ namespace Robust.Client.UserInterface.Controls
// map from key to buttondata index
private Dictionary<TKey, int> _keyMap = new();
private readonly Popup _popup;
private readonly VBoxContainer _popupVBox;
private readonly BoxContainer _popupVBox;
private readonly Label _label;
public event Action<ItemPressedEventArgs>? OnItemSelected;
@@ -60,11 +61,17 @@ namespace Robust.Client.UserInterface.Controls
AddStyleClass(StyleClassButton);
OnPressed += OnPressedInternal;
var hBox = new HBoxContainer();
var hBox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal
};
AddChild(hBox);
_popup = new Popup();
_popupVBox = new VBoxContainer();
_popupVBox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
};
_popup.AddChild(_popupVBox);
_popup.OnPopupHide += OnPopupHide;

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using Robust.Client.Graphics;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.UserInterface.Controls
{
@@ -13,7 +14,7 @@ namespace Robust.Client.UserInterface.Controls
private readonly List<ButtonData> _buttonData = new();
private readonly Dictionary<int, int> _idMap = new();
private readonly Popup _popup;
private readonly VBoxContainer _popupVBox;
private readonly BoxContainer _popupVBox;
private readonly Label _label;
private readonly TextureRect _triangle;
@@ -49,11 +50,17 @@ namespace Robust.Client.UserInterface.Controls
Prefix = "";
OnPressed += OnPressedInternal;
var hBox = new HBoxContainer();
var hBox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal
};
AddChild(hBox);
_popup = new Popup();
_popupVBox = new VBoxContainer();
_popupVBox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
};
_popup.AddChild(_popupVBox);
_popup.OnPopupHide += OnPopupHide;

View File

@@ -2,6 +2,7 @@ using System;
using System.Linq;
using System.Collections.Generic;
using static Robust.Client.UserInterface.Controls.BaseButton;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.UserInterface.Controls
{
@@ -34,11 +35,17 @@ namespace Robust.Client.UserInterface.Controls
switch (layout)
{
case RadioOptionsLayout.Vertical:
_container = new VBoxContainer();
_container = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
};
break;
case RadioOptionsLayout.Horizontal:
default:
_container = new HBoxContainer();
_container = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal
};
break;
}

View File

@@ -1,6 +1,6 @@
<Control xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics">
<VBoxContainer>
<BoxContainer Orientation="Vertical">
<OutputPanel Name="Output" VerticalExpand="True">
<OutputPanel.StyleBoxOverride>
<gfx:StyleBoxFlat BackgroundColor="#25252add"
@@ -9,5 +9,5 @@
</OutputPanel.StyleBoxOverride>
</OutputPanel>
<HistoryLineEdit Name="CommandBar" PlaceHolder="{Loc 'console-line-edit-placeholder'}" />
</VBoxContainer>
</BoxContainer>
</Control>

View File

@@ -12,6 +12,7 @@ using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.UserInterface.CustomControls
{
@@ -21,7 +22,7 @@ namespace Robust.Client.UserInterface.CustomControls
private readonly IPrototypeManager prototypeManager;
private readonly IResourceCache resourceCache;
private VBoxContainer MainVBox;
private BoxContainer MainVBox;
private PrototypeListContainer PrototypeList;
private LineEdit SearchBar;
private OptionButton OverrideMenu;
@@ -71,13 +72,15 @@ namespace Robust.Client.UserInterface.CustomControls
SetSize = (250, 300);
MinSize = (250, 200);
Contents.AddChild(MainVBox = new VBoxContainer
Contents.AddChild(MainVBox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
Name = "AAAAAA",
Children =
{
new HBoxContainer
new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
(SearchBar = new LineEdit
@@ -102,8 +105,9 @@ namespace Robust.Client.UserInterface.CustomControls
(PrototypeList = new PrototypeListContainer())
}
},
new HBoxContainer
new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
(EraseButton = new Button
@@ -472,8 +476,9 @@ namespace Robust.Client.UserInterface.CustomControls
ToggleMode = true,
});
AddChild(new HBoxContainer
AddChild(new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
(EntityTextureRects = new LayeredTextureRect

View File

@@ -25,7 +25,7 @@ namespace Robust.Client.UserInterface.CustomControls
}
var fps = _gameTiming.FramesPerSecondAvg;
Text = $"FPS: {fps:N1}";
Text = $"FPS: {fps:N0}";
}
}
}

View File

@@ -1,13 +1,13 @@
<SS14Window xmlns="https://spacestation14.io" MinWidth="100" MinHeight="50">
<PanelContainer StyleClasses="windowPanel" />
<VBoxContainer SeparationOverride="0">
<BoxContainer Orientation="Vertical" SeparationOverride="0">
<PanelContainer Name="WindowHeader" StyleClasses="windowHeader">
<HBoxContainer>
<BoxContainer Orientation="Horizontal">
<Label Margin="5 0 0 0" HorizontalExpand="true" Name="TitleLabel" StyleIdentifier="foo" ClipText="True"
Text="{Loc 'ss14window-placeholder-title'}" VAlign="Center" StyleClasses="windowTitle" />
<TextureButton Name="CloseButton" StyleClasses="windowCloseButton" VerticalAlignment="Center" />
</HBoxContainer>
</BoxContainer>
</PanelContainer>
<Control Name="ContentsContainer" Margin="10" RectClipContent="True" VerticalExpand="true" />
</VBoxContainer>
</BoxContainer>
</SS14Window>

View File

@@ -1,6 +1,7 @@
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.UserInterface.CustomControls
{
@@ -12,8 +13,9 @@ namespace Robust.Client.UserInterface.CustomControls
protected ScriptConsole()
{
Contents.AddChild(new VBoxContainer
Contents.AddChild(new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
Children =
{
new PanelContainer
@@ -29,8 +31,9 @@ namespace Robust.Client.UserInterface.CustomControls
},
VerticalExpand = true,
},
new HBoxContainer
new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
(InputBar = new HistoryLineEdit

View File

@@ -2,12 +2,15 @@
using Robust.Shared.Enums;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Robust.Client.Graphics;
using Robust.Client.Placement;
using Robust.Client.ResourceManagement;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.Controls.BoxContainer;
using Robust.Shared.Utility;
namespace Robust.Client.UserInterface.CustomControls
{
@@ -32,9 +35,15 @@ namespace Robust.Client.UserInterface.CustomControls
_placementManager = placementManager;
_resourceCache = resourceCache;
var vBox = new VBoxContainer();
var vBox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
};
Contents.AddChild(vBox);
var hBox = new HBoxContainer();
var hBox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal
};
vBox.AddChild(hBox);
SearchBar = new LineEdit {PlaceHolder = "Search", HorizontalExpand = true};
SearchBar.OnTextChanged += OnSearchBarTextChanged;
@@ -105,7 +114,7 @@ namespace Robust.Client.UserInterface.CustomControls
Texture? texture = null;
if (!string.IsNullOrEmpty(entry.SpriteName))
{
texture = _resourceCache.GetResource<TextureResource>($"/Textures/Constructible/Tiles/{entry.SpriteName}.png");
texture = _resourceCache.GetResource<TextureResource>(new ResourcePath(entry.Path) / $"{entry.SpriteName}.png");
}
TileList.AddItem(entry.DisplayName, texture);
}

View File

@@ -2,6 +2,7 @@ using System.Globalization;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.ViewVariables.Editors
{
@@ -9,8 +10,9 @@ namespace Robust.Client.ViewVariables.Editors
{
protected override Control MakeUI(object? value)
{
var hBox = new HBoxContainer
var hBox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
MinSize = new Vector2(200, 0)
};
var angle = (Angle) value!;

View File

@@ -5,6 +5,7 @@ using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.ViewVariables.Editors
{
@@ -13,8 +14,9 @@ namespace Robust.Client.ViewVariables.Editors
protected override Control MakeUI(object? value)
{
var coords = (EntityCoordinates) value!;
var hBoxContainer = new HBoxContainer
var hBoxContainer = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
MinSize = new Vector2(240, 0),
};

View File

@@ -2,6 +2,7 @@
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.ViewVariables.Editors
{
@@ -9,8 +10,9 @@ namespace Robust.Client.ViewVariables.Editors
{
protected override Control MakeUI(object? value)
{
var hBox = new HBoxContainer
var hBox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
MinSize = new Vector2(200, 0)
};

View File

@@ -5,6 +5,7 @@ using Robust.Client.UserInterface.Controls;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.ViewVariables;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.ViewVariables.Editors
{
@@ -20,7 +21,11 @@ namespace Robust.Client.ViewVariables.Editors
{
_localValue = value;
var hbox = new HBoxContainer() { HorizontalExpand = true };
var hbox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
HorizontalExpand = true
};
_lineEdit = new LineEdit()
{

View File

@@ -3,6 +3,7 @@ using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.IoC;
using Robust.Shared.ViewVariables;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.ViewVariables.Editors
{
@@ -20,7 +21,10 @@ namespace Robust.Client.ViewVariables.Editors
protected override Control MakeUI(object? value)
{
var hBox = new HBoxContainer();
var hBox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal
};
dynamic d = value!;

View File

@@ -3,6 +3,7 @@ using System.Globalization;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.ViewVariables.Editors
{
@@ -17,8 +18,9 @@ namespace Robust.Client.ViewVariables.Editors
protected override Control MakeUI(object? value)
{
var hBoxContainer = new HBoxContainer
var hBoxContainer = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
MinSize = new Vector2(200, 0),
};

View File

@@ -2,6 +2,7 @@ using System.Globalization;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.ViewVariables.Editors
{
@@ -16,8 +17,9 @@ namespace Robust.Client.ViewVariables.Editors
protected override Control MakeUI(object? value)
{
var hBoxContainer = new HBoxContainer
var hBoxContainer = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
MinSize = new Vector2(240, 0),
};

View File

@@ -17,6 +17,7 @@ using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using static Robust.Client.UserInterface.Control;
using static Robust.Client.UserInterface.Controls.BoxContainer;
using static Robust.Client.UserInterface.Controls.LineEdit;
namespace Robust.Client.ViewVariables.Instances
@@ -48,10 +49,10 @@ namespace Robust.Client.ViewVariables.Instances
private ViewVariablesBlobMembers? _membersBlob;
private VBoxContainer _clientComponents = default!;
private BoxContainer _clientComponents = default!;
private VBoxContainer _serverVariables = default!;
private VBoxContainer _serverComponents = default!;
private BoxContainer _serverVariables = default!;
private BoxContainer _serverComponents = default!;
private Button _clientComponentsAddButton = default!;
private Button _serverComponentsAddButton = default!;
@@ -73,7 +74,10 @@ namespace Robust.Client.ViewVariables.Instances
var scrollContainer = new ScrollContainer();
//scrollContainer.SetAnchorPreset(Control.LayoutPreset.Wide, true);
window.Contents.AddChild(scrollContainer);
var vBoxContainer = new VBoxContainer();
var vBoxContainer = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
};
scrollContainer.AddChild(vBoxContainer);
// Handle top bar displaying type and ToString().
@@ -84,7 +88,11 @@ namespace Robust.Client.ViewVariables.Instances
{
//var smallFont = new VectorFont(_resourceCache.GetResource<FontResource>("/Fonts/CALIBRI.TTF"), 10);
// Custom ToString() implementation.
var headBox = new VBoxContainer {SeparationOverride = 0};
var headBox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
SeparationOverride = 0
};
headBox.AddChild(new Label {Text = stringified, ClipText = true});
headBox.AddChild(new Label
{
@@ -102,7 +110,10 @@ namespace Robust.Client.ViewVariables.Instances
if (_entity.TryGetComponent(out ISpriteComponent? sprite))
{
var hBox = new HBoxContainer();
var hBox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal
};
top.HorizontalExpand = true;
hBox.AddChild(top);
hBox.AddChild(new SpriteView {Sprite = sprite});
@@ -118,7 +129,11 @@ namespace Robust.Client.ViewVariables.Instances
_tabs.OnTabChanged += _tabsOnTabChanged;
vBoxContainer.AddChild(_tabs);
var clientVBox = new VBoxContainer {SeparationOverride = 0};
var clientVBox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
SeparationOverride = 0
};
_tabs.AddChild(clientVBox);
_tabs.SetTabTitle(TabClientVars, Loc.GetString("view-variable-instance-entity-client-variables-tab-title"));
@@ -136,7 +151,11 @@ namespace Robust.Client.ViewVariables.Instances
}
}
_clientComponents = new VBoxContainer {SeparationOverride = 0};
_clientComponents = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
SeparationOverride = 0
};
_tabs.AddChild(_clientComponents);
_tabs.SetTabTitle(TabClientComponents, Loc.GetString("view-variable-instance-entity-client-components-tab-title"));
@@ -144,11 +163,19 @@ namespace Robust.Client.ViewVariables.Instances
if (!_entity.Uid.IsClientSide())
{
_serverVariables = new VBoxContainer {SeparationOverride = 0};
_serverVariables = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
SeparationOverride = 0
};
_tabs.AddChild(_serverVariables);
_tabs.SetTabTitle(TabServerVars, Loc.GetString("view-variable-instance-entity-server-variables-tab-title"));
_serverComponents = new VBoxContainer {SeparationOverride = 0};
_serverComponents = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
SeparationOverride = 0
};
_tabs.AddChild(_serverComponents);
_tabs.SetTabTitle(TabServerComponents, Loc.GetString("view-variable-instance-entity-server-components-tab-title"));

View File

@@ -8,6 +8,7 @@ using Robust.Shared.Input;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using Robust.Shared.Utility;
using static Robust.Client.UserInterface.Controls.BoxContainer;
using Timer = Robust.Shared.Timing.Timer;
namespace Robust.Client.ViewVariables.Instances
@@ -64,8 +65,9 @@ namespace Robust.Client.ViewVariables.Instances
var scrollContainer = new ScrollContainer();
//scrollContainer.SetAnchorPreset(Control.LayoutPreset.Wide, true);
window.Contents.AddChild(scrollContainer);
var vBoxContainer = new VBoxContainer
var vBoxContainer = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
HorizontalExpand = true,
VerticalExpand = true,
};
@@ -73,7 +75,10 @@ namespace Robust.Client.ViewVariables.Instances
// Handle top bar.
{
var headBox = new HBoxContainer();
var headBox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal
};
var name = MakeTopBar(top, bottom);
name.HorizontalExpand = true;
headBox.AddChild(name);

View File

@@ -10,6 +10,7 @@ using Robust.Client.ViewVariables.Editors;
using Robust.Client.ViewVariables.Instances;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.ViewVariables.Traits
{
@@ -25,8 +26,8 @@ namespace Robust.Client.ViewVariables.Traits
private Button _leftButton = default!;
private Button _rightButton = default!;
private LineEdit _pageLabel = default!;
private HBoxContainer _controlsHBox = default!;
private VBoxContainer _elementsVBox = default!;
private BoxContainer _controlsHBox = default!;
private BoxContainer _elementsVBox = default!;
private int HighestKnownPage => Math.Max(0, ((_cache.Count + ElementsPerPage - 1) / ElementsPerPage) - 1);
@@ -47,9 +48,13 @@ namespace Robust.Client.ViewVariables.Traits
_enumerator = enumerable.GetEnumerator();
}
var outerVBox = new VBoxContainer();
_controlsHBox = new HBoxContainer
var outerVBox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
};
_controlsHBox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
HorizontalAlignment = Control.HAlignment.Center
};
@@ -70,7 +75,10 @@ namespace Robust.Client.ViewVariables.Traits
outerVBox.AddChild(_controlsHBox);
_elementsVBox = new VBoxContainer();
_elementsVBox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
};
outerVBox.AddChild(_elementsVBox);
instance.AddTab("IEnumerable", outerVBox);

View File

@@ -5,6 +5,7 @@ using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.ViewVariables.Traits
{
@@ -13,12 +14,16 @@ namespace Robust.Client.ViewVariables.Traits
private readonly IViewVariablesManagerInternal _vvm;
private readonly IRobustSerializer _robustSerializer;
private VBoxContainer _memberList = default!;
private BoxContainer _memberList = default!;
public override void Initialize(ViewVariablesInstanceObject instance)
{
base.Initialize(instance);
_memberList = new VBoxContainer {SeparationOverride = 0};
_memberList = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
SeparationOverride = 0
};
instance.AddTab("Members", _memberList);
}

View File

@@ -1,8 +1,8 @@
<cc:SS14Window xmlns:cc="clr-namespace:Robust.Client.UserInterface.CustomControls"
xmlns:c="clr-namespace:Robust.Client.UserInterface.Controls">
<c:VBoxContainer VerticalExpand="True">
<c:BoxContainer Orientation="Vertical" VerticalExpand="True">
<c:LineEdit Name="SearchLineEdit" PlaceHolder="Search..." HorizontalExpand="True" />
<c:ItemList Name="EntryItemList" VerticalExpand="True" HorizontalExpand="True" SelectMode="Single" />
<c:Button Name="AddButton" Text="Select" TextAlign="Center" HorizontalExpand="True"/>
</c:VBoxContainer>
</c:BoxContainer>
</cc:SS14Window>

View File

@@ -9,6 +9,7 @@ using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.ViewVariables
{
@@ -126,7 +127,11 @@ namespace Robust.Client.ViewVariables
// 10);
// Custom ToString() implementation.
var headBox = new VBoxContainer {SeparationOverride = 0};
var headBox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
SeparationOverride = 0
};
headBox.AddChild(new Label {Text = top, ClipText = true});
headBox.AddChild(new Label
{

View File

@@ -8,14 +8,15 @@ using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.Client.ViewVariables
{
internal class ViewVariablesPropertyControl : PanelContainer
{
public VBoxContainer VBox { get; }
public HBoxContainer TopContainer { get; }
public HBoxContainer BottomContainer { get; }
public BoxContainer VBox { get; }
public BoxContainer TopContainer { get; }
public BoxContainer BottomContainer { get; }
public Label NameLabel { get; }
private readonly Label _bottomLabel;
@@ -34,14 +35,23 @@ namespace Robust.Client.ViewVariables
ToolTip = "Click to expand";
MinHeight = 25;
VBox = new VBoxContainer {SeparationOverride = 0};
VBox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
SeparationOverride = 0
};
AddChild(VBox);
TopContainer = new HBoxContainer {VerticalExpand = true};
TopContainer = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
VerticalExpand = true
};
VBox.AddChild(TopContainer);
BottomContainer = new HBoxContainer
BottomContainer = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Visible = false
};
VBox.AddChild(BottomContainer);

View File

@@ -83,7 +83,7 @@ namespace Robust.Shared.Configuration
{
// overwrite the value with the saved one
cfgVar.Value = tomlValue;
cfgVar.ValueChanged?.Invoke(cfgVar.Value);
InvokeValueChanged(cfgVar, cfgVar.Value);
}
else
{
@@ -189,16 +189,13 @@ namespace Robust.Shared.Configuration
public void RegisterCVar<T>(string name, T defaultValue, CVar flags = CVar.NONE, Action<T>? onValueChanged = null)
where T : notnull
{
Action<object>? valueChangedDelegate = null;
if (onValueChanged != null)
{
valueChangedDelegate = v => onValueChanged((T) v);
}
RegisterCVar(name, typeof(T), defaultValue, flags);
RegisterCVar(name, typeof(T), defaultValue, flags, valueChangedDelegate);
if (onValueChanged != null)
OnValueChanged(name, onValueChanged);
}
private void RegisterCVar(string name, Type type, object defaultValue, CVar flags, Action<object>? onValueChanged)
private void RegisterCVar(string name, Type type, object defaultValue, CVar flags)
{
DebugTools.Assert(!type.IsEnum || type.GetEnumUnderlyingType() == typeof(int),
$"{name}: Enum cvars must have int as underlying type.");
@@ -219,7 +216,6 @@ namespace Robust.Shared.Configuration
cVar.DefaultValue = defaultValue;
cVar.Flags = flags;
cVar.Registered = true;
cVar.ValueChanged = onValueChanged;
if (cVar.OverrideValue != null)
{
@@ -233,7 +229,6 @@ namespace Robust.Shared.Configuration
{
Registered = true,
Value = defaultValue,
ValueChanged = onValueChanged
});
}
@@ -247,7 +242,11 @@ namespace Robust.Shared.Configuration
where T : notnull
{
var reg = _configVars[name];
reg.ValueChanged += o => onValueChanged((T) o);
var exDel = (Action<T>?) reg.ValueChanged;
exDel += onValueChanged;
reg.ValueChanged = exDel;
reg.ValueChangedInvoker ??= (del, v) => ((Action<T>) del)((T) v);
if (invokeImmediately)
{
@@ -255,6 +254,19 @@ namespace Robust.Shared.Configuration
}
}
public void UnsubValueChanged<T>(CVarDef<T> cVar, Action<T> onValueChanged) where T : notnull
{
UnsubValueChanged(cVar.Name, onValueChanged);
}
public void UnsubValueChanged<T>(string name, Action<T> onValueChanged) where T : notnull
{
var reg = _configVars[name];
var exDel = (Action<T>?) reg.ValueChanged;
exDel -= onValueChanged;
reg.ValueChanged = exDel;
}
public void LoadCVarsFromAssembly(Assembly assembly)
{
foreach (var defField in assembly
@@ -282,7 +294,7 @@ namespace Robust.Shared.Configuration
throw new InvalidOperationException($"CVarDef '{defField.Name}' on '{defField.DeclaringType?.FullName}' is null.");
}
RegisterCVar(def.Name, type, def.DefaultValue, def.Flags, null);
RegisterCVar(def.Name, type, def.DefaultValue, def.Flags);
}
}
@@ -316,7 +328,7 @@ namespace Robust.Shared.Configuration
cVar.OverrideValueParsed = null;
cVar.Value = value;
cVar.ValueChanged?.Invoke(value);
InvokeValueChanged(cVar, value);
}
}
else
@@ -362,7 +374,7 @@ namespace Robust.Shared.Configuration
{
cfgVar.OverrideValue = value;
cfgVar.OverrideValueParsed = ParseOverrideValue(value, cfgVar.DefaultValue?.GetType());
cfgVar.ValueChanged?.Invoke(cfgVar.OverrideValueParsed);
InvokeValueChanged(cfgVar, cfgVar.OverrideValueParsed);
}
else
{
@@ -422,6 +434,11 @@ namespace Robust.Shared.Configuration
}
}
private static void InvokeValueChanged(ConfigVar var, object value)
{
var.ValueChangedInvoker?.Invoke(var.ValueChanged!, value);
}
/// <summary>
/// Holds the data for a single configuration variable.
/// </summary>
@@ -476,7 +493,9 @@ namespace Robust.Shared.Configuration
/// <summary>
/// Invoked when the value of this CVar is changed.
/// </summary>
public Action<object>? ValueChanged { get; set; }
public Delegate? ValueChanged { get; set; }
public Action<Delegate, object>? ValueChangedInvoker { get; set; }
// We don't know what the type of the var is until it's registered.
// So we can't actually parse them until then.

View File

@@ -63,10 +63,48 @@ namespace Robust.Shared.Configuration
/// <param name="name">The name of the CVar</param>
Type GetCVarType(string name);
/// <summary>
/// Listen for an event for if the config value changes.
/// </summary>
/// <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>
/// <seealso cref="UnsubValueChanged{T}(Robust.Shared.Configuration.CVarDef{T},System.Action{T})"/>
void OnValueChanged<T>(CVarDef<T> cVar, Action<T> onValueChanged, bool invokeImmediately = false)
where T : notnull;
/// <summary>
/// Listen for an event for if the config value changes.
/// </summary>
/// <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>
/// <seealso cref="UnsubValueChanged{T}(string,System.Action{T})"/>
void OnValueChanged<T>(string name, Action<T> onValueChanged, bool invokeImmediately = false)
where T : notnull;
/// <summary>
/// Unsubscribe an event previously registered with <see cref="OnValueChanged{T}(Robust.Shared.Configuration.CVarDef{T},System.Action{T},bool)"/>.
/// </summary>
/// <param name="cVar">The CVar to unsubscribe from.</param>
/// <param name="onValueChanged">The delegate to unsubscribe.</param>
/// <typeparam name="T">The type of value contained in this CVar.</typeparam>
void UnsubValueChanged<T>(CVarDef<T> cVar, Action<T> onValueChanged)
where T : notnull;
/// <summary>
/// Unsubscribe an event previously registered with <see cref="OnValueChanged{T}(string,System.Action{T},bool)"/>.
/// </summary>
/// <param name="name">The name of the CVar to unsubscribe from.</param>
/// <param name="onValueChanged">The delegate to unsubscribe.</param>
/// <typeparam name="T">The type of value contained in this CVar.</typeparam>
void UnsubValueChanged<T>(string name, Action<T> onValueChanged)
where T : notnull;
}
}

View File

@@ -97,7 +97,7 @@ namespace Robust.Shared.Configuration
private void HandleNetVarMessage(MsgConVars message)
{
if(!_receivedInitialNwVars)
if (_netManager.IsClient && !_receivedInitialNwVars)
{
_receivedInitialNwVars = true;
@@ -125,7 +125,7 @@ namespace Robust.Shared.Configuration
ApplyNetVarChange(msg.MsgChannel, msg.NetworkedVars);
if(msg.Tick < _timing.LastRealTick)
if(msg.Tick != default && msg.Tick < _timing.LastRealTick)
Logger.WarningS("cfg", $"{msg.MsgChannel}: Received late nwVar message ({msg.Tick} < {_timing.LastRealTick} ).");
_netVarsMessages.RemoveSwap(i);
@@ -148,45 +148,50 @@ namespace Robust.Shared.Configuration
private void ApplyNetVarChange(INetChannel msgChannel, List<(string name, object value)> networkedVars)
{
Logger.DebugS("cfg", "Handling replicated cvars...");
Logger.DebugS("cfg", $"{msgChannel} Handling replicated cvars...");
foreach (var (name, value) in networkedVars)
if (_netManager.IsClient)
{
if (_netManager.IsClient) // Server sent us a CVar update.
// Server sent us a CVar update.
foreach (var (name, value) in networkedVars)
{
// Actually set the CVar
base.SetCVar(name, value);
Logger.DebugS("cfg", $"name={name}, val={value}");
}
else // Client sent us a CVar update
return;
}
// Client sent us a CVar update
if (!_replicatedCVars.TryGetValue(msgChannel, out var clientCVars))
{
Logger.WarningS("cfg", $"{msgChannel} tried to replicate CVars but is not in _replicatedCVars.");
return;
}
foreach (var (name, value) in networkedVars)
{
if (!_configVars.TryGetValue(name, out var cVar))
{
if (!_configVars.TryGetValue(name, out var cVar))
{
Logger.WarningS("cfg", $"{msgChannel} tried to replicate an unknown CVar '{name}.'");
continue;
}
Logger.WarningS("cfg", $"{msgChannel} tried to replicate an unknown CVar '{name}.'");
continue;
}
if (!cVar.Registered)
{
Logger.WarningS("cfg", $"{msgChannel} tried to replicate an unregistered CVar '{name}.'");
continue;
}
if (!cVar.Registered)
{
Logger.WarningS("cfg", $"{msgChannel} tried to replicate an unregistered CVar '{name}.'");
continue;
}
if((cVar.Flags & CVar.REPLICATED) != 0)
{
var clientCVars = _replicatedCVars[msgChannel];
if (clientCVars.ContainsKey(name))
clientCVars[name] = value;
else
clientCVars.Add(name, value);
Logger.DebugS("cfg", $"name={name}, val={value}");
}
else
{
Logger.WarningS("cfg", $"{msgChannel} tried to replicate an un-replicated CVar '{name}.'");
}
if((cVar.Flags & CVar.REPLICATED) != 0)
{
clientCVars[name] = value;
Logger.DebugS("cfg", $"name={name}, val={value}");
}
else
{
Logger.WarningS("cfg", $"{msgChannel} tried to replicate an un-replicated CVar '{name}.'");
}
}
}
@@ -290,7 +295,7 @@ namespace Robust.Shared.Configuration
Logger.InfoS("cfg", "Sending client info...");
var msg = _netManager.CreateNetMessage<MsgConVars>();
msg.Tick = _timing.CurTick;
msg.Tick = default;
msg.NetworkedVars = GetReplicatedVars();
_netManager.ClientSendMessage(msg);
}

View File

@@ -871,6 +871,7 @@ Types:
IEquatable`1: { }
IFormatProvider: { All: True }
IFormattable: { All: True }
Index: { All: True }
IndexOutOfRangeException: { All: True }
Int16: { All: True }
Int32: { All: True }
@@ -912,6 +913,7 @@ Types:
ParamArrayAttribute: { All: True }
Predicate`1: { All: True } # Delegate
Random: { All: True }
Range: { All: True }
ReadOnlyMemory`1:
Methods:
- "!0[] ToArray()"

View File

@@ -18,18 +18,6 @@ namespace Robust.Shared.GameObjects
void CollideWith(Fixture ourFixture, Fixture otherFixture, in Manifold manifold);
}
/// <summary>
/// Called once when a collision ends.
/// </summary>
public interface IEndCollide
{
/// <summary>
/// Run behaviour after all other collision behaviors have run.
/// </summary>
[Obsolete("Use EndCollideEvent instead")]
void CollideWith(Fixture ourFixture, Fixture otherFixture, in Manifold manifold);
}
[Serializable, NetSerializable]
public enum BodyStatus: byte
{

View File

@@ -11,46 +11,74 @@ namespace Robust.Shared.GameObjects
protected void SubscribeNetworkEvent<T>(
EntityEventHandler<T> handler,
Type[]? before=null, Type[]? after=null)
Type[]? before = null, Type[]? after = null)
where T : notnull
{
EntityManager.EventBus.SubscribeEvent(EventSource.Network, this, handler, GetType(), before, after);
_subscriptions ??= new();
_subscriptions.Add(new SubBroadcast<T>(EventSource.Network));
}
protected void SubscribeNetworkEvent<T>(
EntitySessionEventHandler<T> handler,
Type[]? before=null, Type[]? after=null)
where T : notnull
{
EntityManager.EventBus.SubscribeSessionEvent(EventSource.Network, this, handler);
_subscriptions ??= new();
_subscriptions.Add(new SubBroadcast<EntitySessionMessage<T>>(EventSource.Network));
SubEvent(EventSource.Network, handler, before, after);
}
protected void SubscribeLocalEvent<T>(
EntityEventHandler<T> handler,
Type[]? before=null, Type[]? after=null)
Type[]? before = null, Type[]? after = null)
where T : notnull
{
EntityManager.EventBus.SubscribeEvent(EventSource.Local, this, handler, GetType(), before, after);
SubEvent(EventSource.Local, handler, before, after);
}
_subscriptions ??= new();
_subscriptions.Add(new SubBroadcast<T>(EventSource.Local));
protected void SubscribeAllEvent<T>(
EntityEventHandler<T> handler,
Type[]? before = null, Type[]? after = null)
where T : notnull
{
SubEvent(EventSource.All, handler, before, after);
}
protected void SubscribeNetworkEvent<T>(
EntitySessionEventHandler<T> handler,
Type[]? before = null, Type[]? after = null)
where T : notnull
{
SubSessionEvent(EventSource.Network, handler, before, after);
}
protected void SubscribeLocalEvent<T>(
EntitySessionEventHandler<T> handler,
Type[]? before=null, Type[]? after=null)
Type[]? before = null, Type[]? after = null)
where T : notnull
{
EntityManager.EventBus.SubscribeSessionEvent(EventSource.Local, this, handler);
SubSessionEvent(EventSource.Local, handler, before, after);
}
protected void SubscribeAllEvent<T>(
EntitySessionEventHandler<T> handler,
Type[]? before = null, Type[]? after = null)
where T : notnull
{
SubSessionEvent(EventSource.All, handler, before, after);
}
private void SubEvent<T>(
EventSource src,
EntityEventHandler<T> handler,
Type[]? before, Type[]? after)
where T : notnull
{
EntityManager.EventBus.SubscribeEvent(src, this, handler, GetType(), before, after);
_subscriptions ??= new();
_subscriptions.Add(new SubBroadcast<EntitySessionMessage<T>>(EventSource.Local));
_subscriptions.Add(new SubBroadcast<T>(src));
}
private void SubSessionEvent<T>(
EventSource src,
EntitySessionEventHandler<T> handler,
Type[]? before, Type[]? after)
where T : notnull
{
EntityManager.EventBus.SubscribeSessionEvent(src, this, handler, GetType(), before, after);
_subscriptions ??= new();
_subscriptions.Add(new SubBroadcast<EntitySessionMessage<T>>(src));
}
[Obsolete("Unsubscribing of entity system events is now automatic")]
@@ -69,7 +97,7 @@ namespace Robust.Shared.GameObjects
protected void SubscribeLocalEvent<TComp, TEvent>(
ComponentEventHandler<TComp, TEvent> handler,
Type[]? before=null, Type[]? after=null)
Type[]? before = null, Type[]? after = null)
where TComp : IComponent
where TEvent : EntityEventArgs
{

View File

@@ -1,14 +1,37 @@
using System;
namespace Robust.Shared.GameObjects
{
public static class EventBusExt
{
public static void SubscribeSessionEvent<T>(this IEventBus eventBus, EventSource source,
IEntityEventSubscriber subscriber, EntitySessionEventHandler<T> handler)
public static void SubscribeSessionEvent<T>(
this IEventBus eventBus,
EventSource source,
IEntityEventSubscriber subscriber,
EntitySessionEventHandler<T> handler)
{
var wrapper = new HandlerWrapper<T>(handler);
eventBus.SubscribeEvent<EntitySessionMessage<T>>(source, subscriber, wrapper.Invoke);
}
public static void SubscribeSessionEvent<T>(
this IEventBus eventBus,
EventSource source,
IEntityEventSubscriber subscriber,
EntitySessionEventHandler<T> handler,
Type orderType,
Type[]? before=null,
Type[]? after=null)
{
var wrapper = new HandlerWrapper<T>(handler);
eventBus.SubscribeEvent<EntitySessionMessage<T>>(
source,
subscriber,
wrapper.Invoke,
orderType,
before, after);
}
private sealed class HandlerWrapper<T>
{
public HandlerWrapper(EntitySessionEventHandler<T> handler)

View File

@@ -83,7 +83,7 @@ namespace Robust.Shared.GameObjects
internal IReadOnlyList<VirtualController> Controllers => _controllers;
private List<VirtualController> _controllers = new();
public Action<Fixture, Fixture, float, Manifold>? KinematicControllerCollision;
public Action<Fixture, Fixture, float, Vector2>? KinematicControllerCollision;
public bool MetricsEnabled;
private readonly Stopwatch _stopwatch = new();
@@ -146,7 +146,7 @@ namespace Robust.Shared.GameObjects
body.LinearVelocity += linearVelocityDiff;
body.AngularVelocity += angularVelocityDiff;
}
private void HandleGridInit(GridInitializeEvent ev)
{
if (!EntityManager.TryGetEntity(ev.EntityUid, out var gridEntity)) return;

View File

@@ -365,10 +365,10 @@ namespace Robust.Shared.Map
/// <summary>
/// Creates a set of EntityCoordinates given some MapCoordinates.
/// </summary>
/// <param name="entityManager"></param>
/// <param name="mapManager"></param>
/// <param name="coordinates"></param>
/// <returns></returns>
[Obsolete("Use FromMap(IMapManager mapManager, MapCoordinates coordinates) instead.")]
public static EntityCoordinates FromMap(IEntityManager entityManager, IMapManager mapManager, MapCoordinates coordinates)
{
var mapId = coordinates.MapId;
@@ -377,6 +377,19 @@ namespace Robust.Shared.Map
return new EntityCoordinates(mapEntity.Uid, coordinates.Position);
}
/// <summary>
/// Creates a set of EntityCoordinates given some MapCoordinates.
/// </summary>
/// <param name="mapManager"></param>
/// <param name="coordinates"></param>
public static EntityCoordinates FromMap(IMapManager mapManager, MapCoordinates coordinates)
{
var mapId = coordinates.MapId;
var mapEntity = mapManager.GetMapEntity(mapId);
return new EntityCoordinates(mapEntity.Uid, coordinates.Position);
}
/// <summary>
/// Converts this set of coordinates to Vector2i.
/// </summary>

View File

@@ -47,6 +47,10 @@ namespace Robust.Shared.Map
/// </summary>
Vector2 WorldPosition { get; set; }
Matrix3 WorldMatrix { get; }
Matrix3 InvWorldMatrix { get; }
#region TileAccess
/// <summary>

View File

@@ -112,6 +112,34 @@ namespace Robust.Shared.Map
}
}
/// <inheritdoc />
[ViewVariables]
public Matrix3 WorldMatrix
{
get
{
//TODO: Make grids real parents of entities.
if(GridEntityId.IsValid())
return _mapManager.EntityManager.GetEntity(GridEntityId).Transform.WorldMatrix;
return Matrix3.Identity;
}
}
/// <inheritdoc />
[ViewVariables]
public Matrix3 InvWorldMatrix
{
get
{
//TODO: Make grids real parents of entities.
if(GridEntityId.IsValid())
return _mapManager.EntityManager.GetEntity(GridEntityId).Transform.InvWorldMatrix;
return Matrix3.Identity;
}
}
/// <summary>
/// Expands the AABB for this grid when a new tile is added. If the tile is already inside the existing AABB,
/// nothing happens. If it is outside, the AABB is expanded to fit the new tile.
@@ -489,7 +517,7 @@ namespace Robust.Shared.Map
/// <inheritdoc />
public Vector2 WorldToLocal(Vector2 posWorld)
{
return posWorld - WorldPosition;
return InvWorldMatrix.Transform(posWorld);
}
/// <inheritdoc />
@@ -509,7 +537,7 @@ namespace Robust.Shared.Map
/// <inheritdoc />
public Vector2 LocalToWorld(Vector2 posLocal)
{
return posLocal + WorldPosition;
return WorldMatrix.Transform(posLocal);
}
public Vector2i WorldToTile(Vector2 posWorld)

View File

@@ -56,6 +56,11 @@ namespace Robust.Shared.Network
NetUserData UserData { get; }
/// <summary>
/// Has the serializer handshake completed and <see cref="INetManager.Connected"/> been ran?
/// </summary>
bool IsHandshakeComplete { get; }
/// <summary>
/// Creates a new NetMessage to be filled up and sent.
/// </summary>

View File

@@ -20,7 +20,7 @@ namespace Robust.Shared.Network.Messages
[UsedImplicitly]
internal class MsgMapStrClientHandshake : NetMessage
{
public override MsgGroups MsgGroup => MsgGroups.Core;
public override MsgGroups MsgGroup => MsgGroups.String;
/// <value>
/// <c>true</c> if the client needs a new copy of the mapping,

View File

@@ -216,7 +216,7 @@ namespace Robust.Shared.Network
private static byte[] MakeAuthHash(byte[] sharedSecret, byte[] pkBytes)
{
Logger.DebugS("auth", "shared: {0}, pk: {1}", Convert.ToBase64String(sharedSecret), Convert.ToBase64String(pkBytes));
// Logger.DebugS("auth", "shared: {0}, pk: {1}", Convert.ToBase64String(sharedSecret), Convert.ToBase64String(pkBytes));
var incHash = IncrementalHash.CreateHash(HashAlgorithmName.SHA256);
incHash.AppendData(sharedSecret);

View File

@@ -46,6 +46,8 @@ namespace Robust.Shared.Network
[ViewVariables] public NetUserId UserId => UserData.UserId;
[ViewVariables] public NetUserData UserData { get; }
public bool IsHandshakeComplete { get; set; }
// Only used on server, contains the encryption to use for this channel.
public NetEncryption? Encryption { get; set; }
@@ -88,6 +90,11 @@ namespace Robust.Shared.Network
if (_connection.Status == NetConnectionStatus.Connected)
_connection.Disconnect(reason);
}
public override string ToString()
{
return $"{RemoteEndPoint}/{UserId}";
}
}
}
}

View File

@@ -234,7 +234,7 @@ namespace Robust.Shared.Network
Logger.InfoS("net",
"Approved {ConnectionEndpoint} with username {Username} user ID {userId} into the server",
connection.RemoteEndPoint, userData.UserName, userData.UserName);
connection.RemoteEndPoint, userData.UserName, userData.UserId);
// Handshake complete!
HandleInitialHandshakeComplete(peer, connection, userData, encryption, type);

View File

@@ -118,7 +118,7 @@ namespace Robust.Shared.Network
/// <summary>
/// Holds lookup table for NetMessage.Id -> NetMessage.Type
/// </summary>
private readonly Dictionary<string, Type> _messages = new();
private readonly Dictionary<string, (Type type, bool isHandshake)> _messages = new();
/// <summary>
/// The StringTable for transforming packet Ids to Packet name.
@@ -204,7 +204,9 @@ namespace Robust.Shared.Network
public IReadOnlyDictionary<Type, ProcessMessage> CallbackAudit => _callbacks;
/// <inheritdoc />
public INetChannel? ServerChannel
public INetChannel? ServerChannel => ServerChannelImpl;
private NetChannel? ServerChannelImpl
{
get
{
@@ -261,7 +263,7 @@ namespace Robust.Shared.Network
_serializer.ClientHandshakeComplete += () =>
{
Logger.InfoS("net", "Client completed serializer handshake.");
OnConnected(ServerChannel!);
OnConnected(ServerChannelImpl!);
};
_initialized = true;
@@ -792,6 +794,7 @@ namespace Robust.Shared.Network
var id = msg.ReadByte();
ref var entry = ref _netMsgFunctions[id];
if (entry.CreateFunction == null)
{
Logger.WarningS("net",
@@ -801,6 +804,15 @@ namespace Robust.Shared.Network
return true;
}
if (!channel.IsHandshakeComplete && !entry.IsHandshake)
{
Logger.WarningS("net",
$"{msg.SenderConnection.RemoteEndPoint}: Got non-handshake message {entry.Type.Name} before handshake completion.");
channel.Disconnect("Got unacceptable net message before handshake completion");
return true;
}
var type = entry.Type;
var instance = entry.CreateFunction(channel);
@@ -837,6 +849,7 @@ namespace Robust.Shared.Network
// Callback must be available or else construction delegate will not be registered.
var callback = _callbacks[type];
// Logger.DebugS("net", $"RECV: {instance.GetType().Name}");
try
{
callback?.Invoke(instance);
@@ -857,11 +870,13 @@ namespace Robust.Shared.Network
return;
}
if (!_messages.TryGetValue(name, out var packetType))
if (!_messages.TryGetValue(name, out var msgDat))
{
return;
}
var (packetType, isHandshake) = msgDat;
if (!_callbacks.ContainsKey(packetType))
{
return;
@@ -897,6 +912,7 @@ namespace Robust.Shared.Network
ref var entry = ref _netMsgFunctions[id];
entry.CreateFunction = @delegate;
entry.Type = packetType;
entry.IsHandshake = isHandshake;
}
#region NetMessages
@@ -909,7 +925,7 @@ namespace Robust.Shared.Network
var name = new T().MsgName;
var id = _strings.AddString(name);
_messages.Add(name, typeof(T));
_messages.Add(name, (typeof(T), (accept & NetMessageAccept.Handshake) != 0));
var thisSide = IsServer ? NetMessageAccept.Server : NetMessageAccept.Client;
@@ -986,6 +1002,9 @@ namespace Robust.Shared.Network
foreach (var channel in _channels.Values)
{
if (!channel.IsHandshakeComplete)
continue;
ServerSendMessage(message, channel);
}
}
@@ -1006,6 +1025,12 @@ namespace Robust.Shared.Network
var method = message.DeliveryMethod;
peer.SendMessage(packet, channel.Connection, method);
LogSend(message, method, packet);
}
private static void LogSend(NetMessage message, NetDeliveryMethod method, NetOutgoingMessage packet)
{
// Logger.DebugS("net", $"SEND: {message.GetType().Name} {method} {packet.LengthBytes}");
}
/// <inheritdoc />
@@ -1042,6 +1067,7 @@ namespace Robust.Shared.Network
}
peer.Peer.SendMessage(packet, peer.ConnectionsWithChannels[0], method);
LogSend(message, method, packet);
}
#endregion NetMessages
@@ -1068,8 +1094,10 @@ namespace Robust.Shared.Network
ConnectFailed?.Invoke(this, args);
}
private void OnConnected(INetChannel channel)
private void OnConnected(NetChannel channel)
{
channel.IsHandshakeComplete = true;
Connected?.Invoke(this, new NetChannelArgs(channel));
}
@@ -1151,6 +1179,7 @@ namespace Robust.Shared.Network
private struct NetMsgEntry
{
public Func<INetChannel, NetMessage>? CreateFunction;
public bool IsHandshake;
public Type Type;
}
}

View File

@@ -13,16 +13,26 @@ namespace Robust.Shared.Network
/// <summary>
/// Message can only be received on the server and it is an error to send it to a client.
/// </summary>
Server = 1,
Server = 1 << 0,
/// <summary>
/// Message can only be received on the client and it is an error to send it to a server.
/// </summary>
Client = 2,
Client = 1 << 1,
/// <summary>
/// Message can be received on both client and server.
/// </summary>
Both = Client | Server
Both = Client | Server,
/// <summary>
/// Message is used during connection handshake and may be sent before the initial handshake is completed.
/// </summary>
/// <remarks>
/// There is a window of time between the initial authentication handshake and serialization handshake,
/// where the connection *does* have an INetChannel.
/// During this handshake messages are still blocked however unless this flag is sent on the message type.
/// </remarks>
Handshake = 1 << 2,
}
}

View File

@@ -61,7 +61,7 @@ namespace Robust.Shared.Network
_callback = callback;
_updateCallback = updateCallback;
_network.RegisterNetMessage<MsgStringTableEntries>(ReceiveEntries, NetMessageAccept.Client);
_network.RegisterNetMessage<MsgStringTableEntries>(ReceiveEntries, NetMessageAccept.Client | NetMessageAccept.Handshake);
Reset();
}

View File

@@ -34,6 +34,7 @@ using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics.Broadphase;
using Robust.Shared.Physics.Collision;
using Robust.Shared.Physics.Dynamics.Contacts;
@@ -63,7 +64,7 @@ namespace Robust.Shared.Physics.Dynamics
/// <summary>
/// Invoked whenever a KinematicController body collides. The first body is always guaranteed to be a KinematicController
/// </summary>
internal event Action<Fixture, Fixture, float, Manifold>? KinematicControllerCollision;
internal event Action<Fixture, Fixture, float, Vector2>? KinematicControllerCollision;
// TODO: Need to migrate the interfaces to comp bus when possible
// TODO: Also need to clean the station up to not have 160 contacts on roundstart
@@ -412,20 +413,6 @@ namespace Robust.Shared.Physics.Dynamics
_entityManager.EventBus.RaiseLocalEvent(bodyA.Owner.Uid, new EndCollideEvent(fixtureA, fixtureB, manifold));
_entityManager.EventBus.RaiseLocalEvent(bodyB.Owner.Uid, new EndCollideEvent(fixtureB, fixtureA, manifold));
#pragma warning disable 618
foreach (var comp in bodyA.Owner.GetAllComponents<IEndCollide>().ToArray())
{
if (bodyB.Deleted) break;
comp.CollideWith(fixtureA, fixtureB, manifold);
}
foreach (var comp in bodyB.Owner.GetAllComponents<IEndCollide>().ToArray())
{
if (bodyA.Deleted) break;
comp.CollideWith(fixtureB, fixtureA, manifold);
}
#pragma warning restore 618
}
_startCollisions.Clear();
@@ -434,26 +421,29 @@ namespace Robust.Shared.Physics.Dynamics
public void PreSolve(float frameTime)
{
Span<Vector2> points = stackalloc Vector2[2];
// We'll do pre and post-solve around all islands rather than each specific island as it seems cleaner with race conditions.
for (var contact = ContactList.Next; contact != ContactList; contact = contact?.Next)
{
if (contact == null || !contact.IsTouching || !contact.Enabled)
if (contact is not {IsTouching: true, Enabled: true})
{
continue;
}
var bodyA = contact.FixtureA!.Body;
var bodyB = contact.FixtureB!.Body;
contact.GetWorldManifold(out var worldNormal, points);
// Didn't use an EntitySystemMessage as this is called FOR EVERY COLLISION AND IS REALLY EXPENSIVE
// so we just use the Action. Also we'll sort out BodyA / BodyB for anyone listening first.
if (bodyA.BodyType == BodyType.KinematicController)
{
KinematicControllerCollision?.Invoke(contact.FixtureA!, contact.FixtureB!, frameTime, contact.Manifold);
KinematicControllerCollision?.Invoke(contact.FixtureA!, contact.FixtureB!, frameTime, -worldNormal);
}
else if (bodyB.BodyType == BodyType.KinematicController)
{
KinematicControllerCollision?.Invoke(contact.FixtureB!, contact.FixtureA!, frameTime, contact.Manifold);
KinematicControllerCollision?.Invoke(contact.FixtureB!, contact.FixtureA!, frameTime, worldNormal);
}
}
}
@@ -472,20 +462,18 @@ namespace Robust.Shared.Physics.Dynamics
{
public Fixture OurFixture { get; }
public Fixture OtherFixture { get; }
public Manifold Manifold { get; }
public CollideEvent(Fixture ourFixture, Fixture otherFixture, Manifold manifold)
public CollideEvent(Fixture ourFixture, Fixture otherFixture)
{
OurFixture = ourFixture;
OtherFixture = otherFixture;
Manifold = manifold;
}
}
public sealed class StartCollideEvent : CollideEvent
{
public StartCollideEvent(Fixture ourFixture, Fixture otherFixture, Manifold manifold)
: base(ourFixture, otherFixture, manifold)
: base(ourFixture, otherFixture)
{
}
}
@@ -493,7 +481,7 @@ namespace Robust.Shared.Physics.Dynamics
public sealed class EndCollideEvent : CollideEvent
{
public EndCollideEvent(Fixture ourFixture, Fixture otherFixture, Manifold manifold)
: base(ourFixture, otherFixture, manifold)
: base(ourFixture, otherFixture)
{
}
}

View File

@@ -21,9 +21,6 @@
*/
using System;
using System.IO;
using Robust.Shared.Configuration;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Physics.Collision;
using Robust.Shared.Utility;
@@ -32,8 +29,6 @@ namespace Robust.Shared.Physics.Dynamics.Contacts
{
internal sealed class ContactSolver
{
[Dependency] private readonly IConfigurationManager _configManager = default!;
private bool _warmStarting;
private float _velocityThreshold;
private float _baumgarte;
@@ -52,24 +47,13 @@ namespace Robust.Shared.Physics.Dynamics.Contacts
private ContactVelocityConstraint[] _velocityConstraints = Array.Empty<ContactVelocityConstraint>();
private ContactPositionConstraint[] _positionConstraints = Array.Empty<ContactPositionConstraint>();
public void Initialize()
public void LoadConfig(in IslandCfg cfg)
{
IoCManager.InjectDependencies(this);
_warmStarting = _configManager.GetCVar(CVars.WarmStarting);
_configManager.OnValueChanged(CVars.WarmStarting, value => _warmStarting = value);
_velocityThreshold = _configManager.GetCVar(CVars.VelocityThreshold);
_configManager.OnValueChanged(CVars.VelocityThreshold, value => _velocityThreshold = value);
_baumgarte = _configManager.GetCVar(CVars.Baumgarte);
_configManager.OnValueChanged(CVars.Baumgarte, value => _baumgarte = value);
_linearSlop = _configManager.GetCVar(CVars.LinearSlop);
_configManager.OnValueChanged(CVars.LinearSlop, value => _linearSlop = value);
_maxLinearCorrection = _configManager.GetCVar(CVars.MaxLinearCorrection);
_configManager.OnValueChanged(CVars.MaxLinearCorrection, value => _maxLinearCorrection = value);
_warmStarting = cfg.WarmStarting;
_velocityThreshold = cfg.VelocityThreshold;
_baumgarte = cfg.Baumgarte;
_linearSlop = cfg.LinearSlop;
_maxLinearCorrection = cfg.MaxLinearCorrection;
}
public void Reset(SolverData data, int contactCount, Contact[] contacts)

View File

@@ -22,15 +22,12 @@
using System;
using System.Collections.Generic;
using Robust.Shared.Configuration;
using Robust.Shared.Containers;
using System.Diagnostics;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics.Dynamics.Contacts;
using Robust.Shared.Physics.Dynamics.Joints;
using Robust.Shared.Utility;
namespace Robust.Shared.Physics.Dynamics
{
@@ -140,13 +137,13 @@ stored in a single array since multiple arrays lead to multiple misses.
*/
public sealed class PhysicsIsland
{
[Dependency] private readonly IConfigurationManager _configManager = default!;
// if you add new deps to this, the IoCManager inject dependencies is behind #if too.
#if DEBUG
[Dependency] private readonly IEntityManager _entityManager = default!;
private List<IPhysBody> _debugBodies = new(8);
#endif
private ContactSolver _contactSolver = default!;
private readonly ContactSolver _contactSolver = new();
internal int ID { get; set; } = -1;
@@ -211,53 +208,25 @@ stored in a single array since multiple arrays lead to multiple misses.
/// </summary>
public int JointCount { get; private set; }
public void Initialize()
[Conditional("DEBUG")]
internal void Initialize()
{
IoCManager.InjectDependencies(this);
_contactSolver = new ContactSolver();
_contactSolver.Initialize();
}
// Values
_angTolSqr = MathF.Pow(_configManager.GetCVar(CVars.AngularSleepTolerance), 2);
_configManager.OnValueChanged(CVars.AngularSleepTolerance, value => _angTolSqr = MathF.Pow(value, 2));
internal void LoadConfig(in IslandCfg cfg)
{
_angTolSqr = cfg.AngTolSqr;
_linTolSqr = cfg.LinTolSqr;
_warmStarting = cfg.WarmStarting;
_velocityIterations = cfg.VelocityIterations;
_maxLinearVelocity = cfg.MaxLinearVelocity;
_maxAngularVelocity = cfg.MaxAngularVelocity;
_positionIterations = cfg.PositionIterations;
_sleepAllowed = cfg.SleepAllowed;
_timeToSleep = cfg.TimeToSleep;
_linTolSqr = MathF.Pow(_configManager.GetCVar(CVars.LinearSleepTolerance), 2);
_configManager.OnValueChanged(CVars.LinearSleepTolerance, value => _linTolSqr = MathF.Pow(value, 2));
_warmStarting = _configManager.GetCVar(CVars.WarmStarting);
_configManager.OnValueChanged(CVars.WarmStarting, value => _warmStarting = value);
_velocityIterations = _configManager.GetCVar(CVars.VelocityIterations);
_configManager.OnValueChanged(CVars.VelocityIterations, value => _velocityIterations = value);
_configManager.OnValueChanged(CVars.MaxLinVelocity, value => SetMaxLinearVelocity(value, null));
_configManager.OnValueChanged(CVars.NetTickrate, value => SetMaxLinearVelocity(null, value));
void SetMaxLinearVelocity(float? maxLinVelocity = null, int? tickrate = null)
{
maxLinVelocity ??= _configManager.GetCVar(CVars.MaxLinVelocity);
tickrate ??= _configManager.GetCVar(CVars.NetTickrate);
_maxLinearVelocity = (float)(maxLinVelocity / tickrate);
}
SetMaxLinearVelocity();
_configManager.OnValueChanged(CVars.MaxAngVelocity, value => SetMaxAngularVelocity(value, null));
_configManager.OnValueChanged(CVars.NetTickrate, value => SetMaxAngularVelocity(null, value));
void SetMaxAngularVelocity(float? maxAngVelocity = null, int? tickrate = null)
{
maxAngVelocity ??= _configManager.GetCVar(CVars.MaxAngVelocity);
tickrate ??= _configManager.GetCVar(CVars.NetTickrate);
_maxAngularVelocity = (float)((MathF.PI * 2 * maxAngVelocity) / tickrate);
}
SetMaxAngularVelocity();
_positionIterations = _configManager.GetCVar(CVars.PositionIterations);
_configManager.OnValueChanged(CVars.PositionIterations, value => _positionIterations = value);
_sleepAllowed = _configManager.GetCVar(CVars.SleepAllowed);
_configManager.OnValueChanged(CVars.SleepAllowed, value => _sleepAllowed = value);
_timeToSleep = _configManager.GetCVar(CVars.TimeToSleep);
_configManager.OnValueChanged(CVars.TimeToSleep, value => _timeToSleep = value);
_contactSolver.LoadConfig(cfg);
}
public void Append(List<IPhysBody> bodies, List<Contact> contacts, List<Joint> joints)
@@ -631,4 +600,24 @@ stored in a single array since multiple arrays lead to multiple misses.
public Vector2[] Positions { get; set; } = default!;
public float[] Angles { get; set; } = default!;
}
/// <summary>
/// Contains all configuration parameters that need to be passed to physics islands.
/// </summary>
internal struct IslandCfg
{
public float AngTolSqr;
public float LinTolSqr;
public bool SleepAllowed;
public bool WarmStarting;
public int VelocityIterations;
public float MaxLinearVelocity;
public float MaxAngularVelocity;
public int PositionIterations;
public float TimeToSleep;
public float VelocityThreshold;
public float Baumgarte;
public float LinearSlop;
public float MaxLinearCorrection;
}
}

View File

@@ -10,7 +10,11 @@ subject to the following restrictions:
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using System.Collections.Generic;
using Robust.Shared.Configuration;
using Robust.Shared.IoC;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Utility;
@@ -31,6 +35,8 @@ namespace Robust.Shared.Physics
/// </summary>
internal sealed class IslandManager : IIslandManager
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
private static readonly IslandBodyCapacitySort CapacitySort = new();
private static readonly IslandBodyCountSort CountSort = new();
@@ -67,13 +73,83 @@ namespace Robust.Shared.Physics
}
}
private int _tickRate;
private float _maxLinearVelocityRaw;
private float _maxAngularVelocityRaw;
private IslandCfg _islandCfg;
public void Initialize()
{
InitConfig();
_loneIsland.Initialize();
// Set an initial size so we don't spam a bunch of array resizes at the start
_loneIsland.Resize(64, 32, 8);
}
private void InitConfig()
{
// Config stuff.
CfgVar(CVars.AngularSleepTolerance, value => _islandCfg.AngTolSqr = value * value);
CfgVar(CVars.LinearSleepTolerance, value => _islandCfg.LinTolSqr = value * value);
CfgVar(CVars.WarmStarting, value => _islandCfg.WarmStarting = value);
CfgVar(CVars.VelocityIterations, value => _islandCfg.VelocityIterations = value);
CfgVar(CVars.PositionIterations, value => _islandCfg.PositionIterations = value);
CfgVar(CVars.SleepAllowed, value => _islandCfg.SleepAllowed = value);
CfgVar(CVars.TimeToSleep, value => _islandCfg.TimeToSleep = value);
CfgVar(CVars.VelocityThreshold, value => _islandCfg.VelocityThreshold = value);
CfgVar(CVars.Baumgarte, value => _islandCfg.Baumgarte = value);
CfgVar(CVars.LinearSlop, value => _islandCfg.LinearSlop = value);
CfgVar(CVars.MaxLinearCorrection, value => _islandCfg.MaxLinearCorrection = value);
CfgVar(CVars.MaxLinVelocity, value =>
{
_maxLinearVelocityRaw = value;
UpdateMaxLinearVelocity();
});
CfgVar(CVars.MaxAngVelocity, value =>
{
_maxAngularVelocityRaw = value;
UpdateMaxAngularVelocity();
});
CfgVar(CVars.NetTickrate, value =>
{
_tickRate = value;
UpdateMaxLinearVelocity();
UpdateMaxAngularVelocity();
});
void UpdateMaxLinearVelocity()
{
_islandCfg.MaxLinearVelocity = _maxLinearVelocityRaw / _tickRate;
}
void UpdateMaxAngularVelocity()
{
_islandCfg.MaxAngularVelocity = (MathF.PI * 2 * _maxAngularVelocityRaw) / _tickRate;
}
void CfgVar<T>(CVarDef<T> cVar, Action<T> callback) where T : notnull
{
_cfg.OnValueChanged(cVar, value =>
{
callback(value);
UpdateIslandCfg();
}, true);
}
}
private void UpdateIslandCfg()
{
// OOP bad
_loneIsland.LoadConfig(_islandCfg);
foreach (var island in _allocatedIslands)
{
island.LoadConfig(_islandCfg);
}
}
public void InitializePools()
{
_loneIsland.Clear();
@@ -159,6 +235,7 @@ namespace Robust.Shared.Physics
{
island = new PhysicsIsland();
island.Initialize();
island.LoadConfig(_islandCfg);
_allocatedIslands.Add(island);
}

View File

@@ -214,9 +214,9 @@ namespace Robust.Shared.Serialization
/// <seealso cref="OnClientCompleteHandshake"/>
private void NetworkInitialize()
{
_net.RegisterNetMessage<MsgMapStrServerHandshake>(HandleServerHandshake, NetMessageAccept.Client);
_net.RegisterNetMessage<MsgMapStrClientHandshake>(HandleClientHandshake, NetMessageAccept.Server);
_net.RegisterNetMessage<MsgMapStrStrings>(HandleStringsMessage, NetMessageAccept.Client);
_net.RegisterNetMessage<MsgMapStrServerHandshake>(HandleServerHandshake, NetMessageAccept.Client | NetMessageAccept.Handshake);
_net.RegisterNetMessage<MsgMapStrClientHandshake>(HandleClientHandshake, NetMessageAccept.Server | NetMessageAccept.Handshake);
_net.RegisterNetMessage<MsgMapStrStrings>(HandleStringsMessage, NetMessageAccept.Client | NetMessageAccept.Handshake);
_net.Disconnect += NetOnDisconnect;
}

View File

@@ -1,41 +0,0 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace Robust.Shared.Utility
{
public static class ProcessExt
{
public static async Task WaitForExitAsync(this Process process, CancellationToken cancellationToken = default)
{
var tcs = new TaskCompletionSource<bool>();
void ProcessExited(object? sender, EventArgs e)
{
tcs.TrySetResult(true);
}
process.EnableRaisingEvents = true;
process.Exited += ProcessExited;
try
{
if (process.HasExited)
{
return;
}
using (cancellationToken.Register(() => tcs.TrySetCanceled()))
{
await tcs.Task;
}
}
finally
{
process.Exited -= ProcessExited;
}
}
}
}

View File

@@ -2,6 +2,7 @@ using NUnit.Framework;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Robust.UnitTesting.Client.UserInterface.Controls
{
@@ -15,7 +16,11 @@ namespace Robust.UnitTesting.Client.UserInterface.Controls
public void TestLayoutBasic()
{
var root = new LayoutContainer();
var boxContainer = new VBoxContainer {MinSize = (50, 60)};
var boxContainer = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
MinSize = (50, 60)
};
var control1 = new Control {MinSize = (20, 20)};
var control2 = new Control {MinSize = (30, 30)};
@@ -37,7 +42,11 @@ namespace Robust.UnitTesting.Client.UserInterface.Controls
public void TestLayoutExpand()
{
var root = new LayoutContainer();
var boxContainer = new VBoxContainer {MinSize = (50, 60)};
var boxContainer = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
MinSize = (50, 60)
};
var control1 = new Control
{
VerticalExpand = true
@@ -61,7 +70,10 @@ namespace Robust.UnitTesting.Client.UserInterface.Controls
[Test]
public void TestCalcMinSize()
{
var boxContainer = new VBoxContainer();
var boxContainer = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
};
var control1 = new Control
{
MinSize = (50, 30)
@@ -80,7 +92,11 @@ namespace Robust.UnitTesting.Client.UserInterface.Controls
public void TestTwoExpand()
{
var root = new LayoutContainer();
var boxContainer = new VBoxContainer {MinSize = (30, 80)};
var boxContainer = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
MinSize = (30, 80)
};
var control1 = new Control
{
VerticalExpand = true,

View File

@@ -387,6 +387,8 @@ namespace Robust.UnitTesting
public bool IsConnected { get; set; }
public NetUserData UserData { get; }
// integration tests don't simulate serializer handshake so this is always true.
public bool IsHandshakeComplete => true;
// TODO: Should this port value make sense?
public IPEndPoint RemoteEndPoint { get; } = new(IPAddress.Loopback, 1212);

View File

@@ -0,0 +1,39 @@
using NUnit.Framework;
using Robust.Shared.Configuration;
namespace Robust.UnitTesting.Shared.Configuration
{
[TestFixture]
[Parallelizable(ParallelScope.All)]
[TestOf(typeof(ConfigurationManager))]
public sealed class ConfigurationManagerTest
{
[Test]
public void TestSubscribeUnsubscribe()
{
var mgr = new ConfigurationManager();
mgr.RegisterCVar("foo.bar", 5);
var lastValue = 0;
var timesRan = 0;
void ValueChanged(int value)
{
timesRan += 1;
lastValue = value;
}
mgr.OnValueChanged<int>("foo.bar", ValueChanged);
mgr.SetCVar("foo.bar", 2);
Assert.That(timesRan, Is.EqualTo(1), "OnValueChanged did not run!");
Assert.That(lastValue, Is.EqualTo(2), "OnValueChanged value was wrong!");
mgr.UnsubValueChanged<int>("foo.bar", ValueChanged);
Assert.That(timesRan, Is.EqualTo(1), "UnsubValueChanged did not unsubscribe!");
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
using System.Threading.Tasks;
using NUnit.Framework;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Maths;
namespace Robust.UnitTesting.Shared.Map
{
[TestFixture]
public class GridRotation_Tests : RobustIntegrationTest
{
// Because integration tests are ten billion percent easier we'll just do all the rotation tests here.
// These are mainly looking out for situations where the grid is rotated 90 / 180 degrees and we
// need to rotate points about the grid's origin which is a /very/ common source of bugs.
[Test]
public async Task Test()
{
var server = StartServer();
await server.WaitIdleAsync();
var entMan = server.ResolveDependency<IEntityManager>();
var mapMan = server.ResolveDependency<IMapManager>();
await server.WaitAssertion(() =>
{
var mapId = mapMan.CreateMap();
var grid = mapMan.CreateGrid(mapId);
var gridEnt = entMan.GetEntity(grid.GridEntityId);
var coordinates = new EntityCoordinates(gridEnt.Uid, new Vector2(10, 0));
// if no rotation and 0,0 position should just be the same coordinate.
Assert.That(gridEnt.Transform.WorldRotation, Is.EqualTo(Angle.Zero));
Assert.That(grid.WorldToLocal(coordinates.Position), Is.EqualTo(coordinates.Position));
// Rotate 180 degrees should show -10, 0 for the position in map-terms and 10, 0 for the position in entity terms (i.e. no change).
gridEnt.Transform.WorldRotation += new Angle(MathF.PI);
Assert.That(gridEnt.Transform.WorldRotation, Is.EqualTo(new Angle(MathF.PI)));
// Check the map coordinate rotates correctly
Assert.That(grid.WorldToLocal(new Vector2(10, 0)).EqualsApprox(new Vector2(-10, 0)));
Assert.That(grid.LocalToWorld(coordinates.Position).EqualsApprox(new Vector2(-10, 0)));
// Now we'll do the same for 180 degrees.
gridEnt.Transform.WorldRotation += MathF.PI / 2f;
// If grid facing down then worldpos of 10, 0 gets rotated 90 degrees CCW and hence should be 0, 10
Assert.That(grid.WorldToLocal(new Vector2(10, 0)).EqualsApprox(new Vector2(0, 10)));
// If grid facing down then local 10,0 pos should just return 0, -10 given it's aligned with the rotation.
Assert.That(grid.LocalToWorld(coordinates.Position).EqualsApprox(new Vector2(0, -10)));
});
}
}
}