From e714dcc83c5e967c9db19132561a4e025e2d6572 Mon Sep 17 00:00:00 2001 From: eoineoineoin Date: Sun, 22 Sep 2024 13:41:27 +0100 Subject: [PATCH 1/7] Fix TabContainer click detection when UIScale was not == 1.0 (#5456) * Fix tabcontainer click detection when UIScale was not == 1.0 * Remove whitespace --------- Co-authored-by: Eoin Mcloughlin --- .../UserInterface/Controls/TabContainer.cs | 45 +++++-------------- 1 file changed, 12 insertions(+), 33 deletions(-) diff --git a/Robust.Client/UserInterface/Controls/TabContainer.cs b/Robust.Client/UserInterface/Controls/TabContainer.cs index 623ac18ac1a..5ffd9724ce1 100644 --- a/Robust.Client/UserInterface/Controls/TabContainer.cs +++ b/Robust.Client/UserInterface/Controls/TabContainer.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Numerics; using Robust.Client.Graphics; using Robust.Shared.Input; @@ -21,6 +22,8 @@ public class TabContainer : Container private int _currentTab; private bool _tabsVisible = true; + // The right-most coordinate of each tab header + private List _tabRight = new(); public int CurrentTab { @@ -157,11 +160,14 @@ protected internal override void Draw(DrawingHandleScreen handle) var headerOffset = 0f; + _tabRight.Clear(); + // Then, draw the tabs. for (var i = 0; i < ChildCount; i++) { if (!GetTabVisible(i)) { + _tabRight.Add(headerOffset); continue; } @@ -214,6 +220,8 @@ protected internal override void Draw(DrawingHandleScreen handle) } headerOffset += boxAdvance; + // Remember the right-most point of this tab, for testing clicked areas + _tabRight.Add(headerOffset); } } @@ -283,46 +291,17 @@ protected internal override void KeyBindDown(GUIBoundKeyEventArgs args) args.Handle(); var relX = args.RelativePixelPosition.X; - - var font = _getFont(); - var boxActive = _getTabBoxActive(); - var boxInactive = _getTabBoxInactive(); - - var headerOffset = 0f; - + float tabLeft = 0; for (var i = 0; i < ChildCount; i++) { - if (!GetTabVisible(i)) + if (relX > tabLeft && relX <= _tabRight[i]) { - continue; - } - - var title = GetActualTabTitle(i); - - var titleLength = 0; - // Get string length. - foreach (var rune in title.EnumerateRunes()) - { - if (!font.TryGetCharMetrics(rune, UIScale, out var metrics)) - { - continue; - } - - titleLength += metrics.Advance; - } - - var active = _currentTab == i; - var box = active ? boxActive : boxInactive; - var boxAdvance = titleLength + (box?.MinimumSize.X ?? 0); - - if (headerOffset < relX && headerOffset + boxAdvance > relX) - { - // Got em. CurrentTab = i; return; } - headerOffset += boxAdvance; + // Next tab starts here + tabLeft = _tabRight[i]; } } From 41ec2dc1314383c5b822b52bf1c0eb68e30dc603 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Tue, 24 Sep 2024 11:39:33 +1200 Subject: [PATCH 2/7] Try improve PVS exception tolerance a bit more (#5454) --- Robust.Server/GameStates/PvsChunk.cs | 10 ++++++---- Robust.Server/GameStates/PvsSystem.Chunks.cs | 1 + Robust.Server/GameStates/PvsSystem.cs | 3 ++- Robust.Shared/GameObjects/EntityManager.cs | 9 +++++++++ 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Robust.Server/GameStates/PvsChunk.cs b/Robust.Server/GameStates/PvsChunk.cs index 38ec670b45d..dc77564a1fb 100644 --- a/Robust.Server/GameStates/PvsChunk.cs +++ b/Robust.Server/GameStates/PvsChunk.cs @@ -141,9 +141,10 @@ public bool PopulateContents(EntityQuery meta, EntityQuery= EntityLifeStage.Terminating) { - DebugTools.Assert($"PVS chunk contains a deleted entity: {child}"); + DebugTools.Assert($"PVS chunk contains a delete or terminating entity: {child}"); MarkDirty(); return false; } @@ -188,9 +189,10 @@ public bool PopulateContents(EntityQuery meta, EntityQuery= EntityLifeStage.Terminating) { - DebugTools.Assert($"PVS chunk contains a deleted entity: {child}"); + DebugTools.Assert($"PVS chunk contains a delete or terminating entity: {child}"); MarkDirty(); return false; } diff --git a/Robust.Server/GameStates/PvsSystem.Chunks.cs b/Robust.Server/GameStates/PvsSystem.Chunks.cs index 40cafb0bb94..a7ac09043a4 100644 --- a/Robust.Server/GameStates/PvsSystem.Chunks.cs +++ b/Robust.Server/GameStates/PvsSystem.Chunks.cs @@ -232,6 +232,7 @@ internal void ProcessVisibleChunksSequential() [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AddEntityToChunk(EntityUid uid, MetaDataComponent meta, PvsChunkLocation location) { + DebugTools.Assert(meta.EntityLifeStage < EntityLifeStage.Terminating); ref var chunk = ref CollectionsMarshal.GetValueRefOrAddDefault(_chunks, location, out var existing); if (!existing) { diff --git a/Robust.Server/GameStates/PvsSystem.cs b/Robust.Server/GameStates/PvsSystem.cs index 7a53079a01e..bb63968cd1b 100644 --- a/Robust.Server/GameStates/PvsSystem.cs +++ b/Robust.Server/GameStates/PvsSystem.cs @@ -129,7 +129,6 @@ public override void Initialize() SubscribeLocalEvent(OnMapChanged); SubscribeLocalEvent(OnGridRemoved); - SubscribeLocalEvent(OnEntityTerminating); SubscribeLocalEvent(OnTransformStartup); _playerManager.PlayerStatusChanged += OnPlayerStatusChanged; @@ -137,6 +136,7 @@ public override void Initialize() EntityManager.EntityAdded += OnEntityAdded; EntityManager.EntityDeleted += OnEntityDeleted; EntityManager.AfterEntityFlush += AfterEntityFlush; + EntityManager.BeforeEntityTerminating += OnEntityTerminating; Subs.CVar(_configManager, CVars.NetPVS, SetPvs, true); Subs.CVar(_configManager, CVars.NetMaxUpdateRange, OnViewsizeChanged, true); @@ -162,6 +162,7 @@ public override void Shutdown() EntityManager.EntityAdded -= OnEntityAdded; EntityManager.EntityDeleted -= OnEntityDeleted; EntityManager.AfterEntityFlush -= AfterEntityFlush; + EntityManager.BeforeEntityTerminating -= OnEntityTerminating; _parallelMgr.ParallelCountChanged -= ResetParallelism; diff --git a/Robust.Shared/GameObjects/EntityManager.cs b/Robust.Shared/GameObjects/EntityManager.cs index bec9e9afbf0..6aa976d10b9 100644 --- a/Robust.Shared/GameObjects/EntityManager.cs +++ b/Robust.Shared/GameObjects/EntityManager.cs @@ -93,6 +93,14 @@ public abstract partial class EntityManager : IEntityManager public event Action>? EntityAdded; public event Action>? EntityInitialized; public event Action>? EntityDeleted; + + /// + /// Internal termination event handlers. This is mainly for exception tolerance, we want to ensure that PVS, + /// and other important engine systems can get updated before some content code throws an exception. + /// + internal event TerminatingEventHandler? BeforeEntityTerminating; + public delegate void TerminatingEventHandler(ref EntityTerminatingEvent ev); + public event Action? BeforeEntityFlush; public event Action? AfterEntityFlush; @@ -556,6 +564,7 @@ private void RecursiveFlagEntityTermination(EntityUid uid, try { var ev = new EntityTerminatingEvent((uid, metadata)); + BeforeEntityTerminating?.Invoke(ref ev); EventBus.RaiseLocalEvent(uid, ref ev, true); } catch (Exception e) From abb3f65fe42ca84e6717ea51600edad40d0802a2 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Tue, 24 Sep 2024 11:40:16 +1200 Subject: [PATCH 3/7] Make EnsureEntityDictionary use TryAdd (#5461) --- RELEASE-NOTES.md | 1 + Robust.Shared/GameObjects/EntityManager.Network.cs | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 2dcfd1f5b8a..a4a8cdca1e0 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -43,6 +43,7 @@ END TEMPLATE--> ### Bugfixes +* Auto-networked dictionaries now use `TryAdd()` to avoid duplicate key errors when a dictionary contains multiple unknown networked entities. * Fixed `ICommonSession.Ping` always returning zero instead of the ping. Note that this will still return zero for client-side code when trying to get the ping of other players. ### Other diff --git a/Robust.Shared/GameObjects/EntityManager.Network.cs b/Robust.Shared/GameObjects/EntityManager.Network.cs index df5cdcf5895..370d43269a0 100644 --- a/Robust.Shared/GameObjects/EntityManager.Network.cs +++ b/Robust.Shared/GameObjects/EntityManager.Network.cs @@ -391,7 +391,7 @@ public void EnsureEntityDictionary(Dictionary entities.EnsureCapacity(netEntities.Count); foreach (var pair in netEntities) { - entities.Add(EnsureEntity(pair.Key, callerEntity), pair.Value); + entities.TryAdd(EnsureEntity(pair.Key, callerEntity), pair.Value); } } @@ -402,7 +402,7 @@ public void EnsureEntityDictionaryNullableValue(Dictionary(pair.Key, callerEntity), pair.Value); + entities.TryAdd(EnsureEntity(pair.Key, callerEntity), pair.Value); } } @@ -413,7 +413,7 @@ public void EnsureEntityDictionary(Dictionary netE entities.EnsureCapacity(netEntities.Count); foreach (var pair in netEntities) { - entities.Add(pair.Key, EnsureEntity(pair.Value, callerEntity)); + entities.TryAdd(pair.Key, EnsureEntity(pair.Value, callerEntity)); } } @@ -424,7 +424,7 @@ public void EnsureEntityDictionary(Dictionary net entities.EnsureCapacity(netEntities.Count); foreach (var pair in netEntities) { - entities.Add(pair.Key, EnsureEntity(pair.Value, callerEntity)); + entities.TryAdd(pair.Key, EnsureEntity(pair.Value, callerEntity)); } } @@ -435,7 +435,7 @@ public void EnsureEntityDictionary(Dictionary netEn entities.EnsureCapacity(netEntities.Count); foreach (var pair in netEntities) { - entities.Add(EnsureEntity(pair.Key, callerEntity), EnsureEntity(pair.Value, callerEntity)); + entities.TryAdd(EnsureEntity(pair.Key, callerEntity), EnsureEntity(pair.Value, callerEntity)); } } @@ -446,7 +446,7 @@ public void EnsureEntityDictionary(Dictionary netE entities.EnsureCapacity(netEntities.Count); foreach (var pair in netEntities) { - entities.Add(EnsureEntity(pair.Key, callerEntity), EnsureEntity(pair.Value, callerEntity)); + entities.TryAdd(EnsureEntity(pair.Key, callerEntity), EnsureEntity(pair.Value, callerEntity)); } } From b84917e8e422a9cf77be64a96c4d31687e8d196b Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Tue, 24 Sep 2024 11:40:42 +1200 Subject: [PATCH 4/7] Obsolete some static localization methods (#5460) --- Robust.Shared/Localization/Loc.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Robust.Shared/Localization/Loc.cs b/Robust.Shared/Localization/Loc.cs index 2e19b6ac6cc..e12decae8ab 100644 --- a/Robust.Shared/Localization/Loc.cs +++ b/Robust.Shared/Localization/Loc.cs @@ -1,8 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; -using System.Globalization; using JetBrains.Annotations; -using Robust.Shared.ContentPack; using Robust.Shared.IoC; namespace Robust.Shared.Localization @@ -36,6 +34,7 @@ public static string GetString(string messageId) return LocalizationManager.GetString(messageId); } + [Obsolete("Use ILocalizationManager")] public static bool TryGetString(string messageId, [NotNullWhen(true)] out string? message) { return LocalizationManager.TryGetString(messageId, out message); @@ -49,6 +48,7 @@ public static string GetString(string messageId, params (string,object)[] args) return LocalizationManager.GetString(messageId, args); } + [Obsolete("Use ILocalizationManager")] public static bool TryGetString( string messageId, [NotNullWhen(true)] out string? value, From dbe297b1fc9bfd83996f648b6bab75291d8988d6 Mon Sep 17 00:00:00 2001 From: Stalen <33173619+stalengd@users.noreply.github.com> Date: Tue, 24 Sep 2024 02:43:00 +0300 Subject: [PATCH 5/7] Activate XAML hot reload on file rename (for VS support) (#5429) --- .../UserInterface/XAML/Proxy/XamlHotReloadManager.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Robust.Client/UserInterface/XAML/Proxy/XamlHotReloadManager.cs b/Robust.Client/UserInterface/XAML/Proxy/XamlHotReloadManager.cs index 39669abaa3a..d40fd02c13b 100644 --- a/Robust.Client/UserInterface/XAML/Proxy/XamlHotReloadManager.cs +++ b/Robust.Client/UserInterface/XAML/Proxy/XamlHotReloadManager.cs @@ -58,16 +58,16 @@ private FileSystemWatcher CreateWatcher(string location) var watcher = new FileSystemWatcher(location) { IncludeSubdirectories = true, - NotifyFilter = NotifyFilters.LastWrite, + NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName, }; - watcher.Changed += (_, args) => + void OnWatcherEvent(object sender, FileSystemEventArgs args) { switch (args.ChangeType) { - case WatcherChangeTypes.Renamed: case WatcherChangeTypes.Deleted: return; + case WatcherChangeTypes.Renamed: case WatcherChangeTypes.Created: case WatcherChangeTypes.Changed: case WatcherChangeTypes.All: @@ -98,7 +98,10 @@ private FileSystemWatcher CreateWatcher(string location) _xamlProxyManager.SetImplementation(resourceFileName, newText); }); - }; + } + + watcher.Changed += OnWatcherEvent; + watcher.Renamed += OnWatcherEvent; watcher.EnableRaisingEvents = true; return watcher; } From fb9b0ae89be0cfe8745b3206b894a6b3d0859907 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Sat, 28 Sep 2024 14:13:05 +1000 Subject: [PATCH 6/7] Remove IsTouching set on physics prediction (#5468) Just because an entity sleeps doesn't mean it's not touching necessarily. This causes client to mispredict against server and continuously fire collision events if we try to move into an entity. Easiest way to reproduced is to walk into a locked airlock and watch it flicker constantly. --- Robust.Client/Physics/PhysicsSystem.Predict.cs | 1 - Robust.Shared/Physics/Dynamics/Contacts/Contact.cs | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Robust.Client/Physics/PhysicsSystem.Predict.cs b/Robust.Client/Physics/PhysicsSystem.Predict.cs index af16a3fd023..c21ea92d38d 100644 --- a/Robust.Client/Physics/PhysicsSystem.Predict.cs +++ b/Robust.Client/Physics/PhysicsSystem.Predict.cs @@ -156,7 +156,6 @@ internal void UpdateIsTouching(List toUpdate) if (activeA == false && activeB == false) { - contact.IsTouching = false; continue; } diff --git a/Robust.Shared/Physics/Dynamics/Contacts/Contact.cs b/Robust.Shared/Physics/Dynamics/Contacts/Contact.cs index e588fc93952..fb27d6eae5a 100644 --- a/Robust.Shared/Physics/Dynamics/Contacts/Contact.cs +++ b/Robust.Shared/Physics/Dynamics/Contacts/Contact.cs @@ -35,6 +35,7 @@ using Robust.Shared.Physics.Collision.Shapes; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; +using Robust.Shared.ViewVariables; namespace Robust.Shared.Physics.Dynamics.Contacts { @@ -94,11 +95,13 @@ internal Contact(IManifoldManager manifoldManager) /// /// Determines whether the contact is touching. /// + [ViewVariables] public bool IsTouching { get; internal set; } /// Enable/disable this contact. This can be used inside the pre-solve /// contact listener. The contact is only disabled for the current /// time step (or sub-step in continuous collisions). + [ViewVariables] public bool Enabled { get; set; } /// From 74e7e61a98f12c2b729cce75337cb5f3bdfd13fa Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Sat, 28 Sep 2024 14:33:37 +1000 Subject: [PATCH 7/7] Revert "Make resetting contacts on the client only set is touching if it is true" (#5469) This reverts commit cdb94748c8cebad7633f056d01bdf6520888a93c. --- Robust.Shared/Physics/Dynamics/Contacts/Contact.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Robust.Shared/Physics/Dynamics/Contacts/Contact.cs b/Robust.Shared/Physics/Dynamics/Contacts/Contact.cs index fb27d6eae5a..177cc73da01 100644 --- a/Robust.Shared/Physics/Dynamics/Contacts/Contact.cs +++ b/Robust.Shared/Physics/Dynamics/Contacts/Contact.cs @@ -31,6 +31,8 @@ using System.Collections.Generic; using System.Numerics; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Maths; using Robust.Shared.Physics.Collision; using Robust.Shared.Physics.Collision.Shapes; using Robust.Shared.Physics.Components; @@ -259,9 +261,7 @@ internal void UpdateIsTouching(Transform bodyATransform, Transform bodyBTransfor { var manifold = Manifold; Evaluate(ref manifold, bodyATransform, bodyBTransform); - - if (IsTouching) - IsTouching = manifold.PointCount > 0; + IsTouching = manifold.PointCount > 0; } }