Files
RobustToolbox/Robust.Server/GameObjects/EntitySystems/UserInterfaceSystem.cs
T
Pieter-Jan Briers e334d6610e Fix race condition in the Bound UI system.
If you sent multiple state updates on the same frame these could easily arrive in different orders on the client, which is definitely not intended. This fixes that by sending them per frame.

As a result, this also means earlier updates on the same frame are discarded, saving bandwidth.
2020-05-26 16:20:47 +02:00

87 lines
2.8 KiB
C#

using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Robust.Server.GameObjects.Components.UserInterface;
using Robust.Server.Interfaces.Player;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.ViewVariables;
namespace Robust.Server.GameObjects.EntitySystems
{
[UsedImplicitly]
internal class UserInterfaceSystem : EntitySystem
{
private const float MaxWindowRange = 2;
private const float MaxWindowRangeSquared = MaxWindowRange * MaxWindowRange;
private readonly List<IPlayerSession> _sessionCache = new List<IPlayerSession>();
// List of all bound user interfaces that have at least one player looking at them.
[ViewVariables]
private readonly List<BoundUserInterface> _activeInterfaces = new List<BoundUserInterface>();
/// <inheritdoc />
public override void Initialize()
{
}
/// <inheritdoc />
public override void Update(float frameTime)
{
foreach (var userInterface in _activeInterfaces.ToList())
{
CheckRange(userInterface);
userInterface.DispatchPendingState();
}
}
/// <summary>
/// Verify that the subscribed clients are still in range of the interface.
/// </summary>
private void CheckRange(BoundUserInterface ui)
{
// We have to cache the set of sessions because Unsubscribe modifies the original.
_sessionCache.Clear();
_sessionCache.AddRange(ui.SubscribedSessions);
var transform = ui.Owner.Owner.Transform;
var uiPos = transform.WorldPosition;
var uiMap = transform.MapID;
foreach (var session in _sessionCache)
{
var attachedEntity = session.AttachedEntity;
// The component manages the set of sessions, so this invalid session should be removed soon.
if (attachedEntity == null || !attachedEntity.IsValid())
{
continue;
}
if (uiMap != attachedEntity.Transform.MapID)
{
ui.Close(session);
continue;
}
var distanceSquared = (uiPos - attachedEntity.Transform.WorldPosition).LengthSquared;
if (distanceSquared > MaxWindowRangeSquared)
{
ui.Close(session);
}
}
}
internal void DeactivateInterface(BoundUserInterface userInterface)
{
_activeInterfaces.Remove(userInterface);
}
internal void ActivateInterface(BoundUserInterface userInterface)
{
_activeInterfaces.Add(userInterface);
}
}
}