Fix some tabletop prediction jank (#12758)
This commit is contained in:
@@ -16,7 +16,6 @@ using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Timing;
|
||||
using static Robust.Shared.Input.Binding.PointerInputCmdHandler;
|
||||
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
|
||||
|
||||
namespace Content.Client.Tabletop
|
||||
{
|
||||
@@ -27,7 +26,6 @@ namespace Content.Client.Tabletop
|
||||
[Dependency] private readonly IUserInterfaceManager _uiManger = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
|
||||
// Time in seconds to wait until sending the location of a dragged entity to the server again
|
||||
private const float Delay = 1f / 10; // 10 Hz
|
||||
@@ -40,10 +38,11 @@ namespace Content.Client.Tabletop
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
UpdatesOutsidePrediction = true;
|
||||
|
||||
CommandBinds.Builder
|
||||
.Bind(EngineKeyFunctions.Use, new PointerInputCmdHandler(OnUse, false))
|
||||
.Bind(EngineKeyFunctions.Use, new PointerInputCmdHandler(OnUse, false, true))
|
||||
.Register<TabletopSystem>();
|
||||
|
||||
SubscribeNetworkEvent<TabletopPlayEvent>(OnTabletopPlay);
|
||||
@@ -57,12 +56,8 @@ namespace Content.Client.Tabletop
|
||||
StopDragging(false);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
// don't send network messages when doing prediction.
|
||||
if (!_gameTiming.IsFirstTimePredicted)
|
||||
return;
|
||||
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
@@ -110,7 +105,7 @@ namespace Content.Client.Tabletop
|
||||
// Only send new position to server when Delay is reached
|
||||
if (_timePassed >= Delay && _table != null)
|
||||
{
|
||||
RaiseNetworkEvent(new TabletopMoveEvent(_draggedEntity.Value, clampedCoords, _table.Value));
|
||||
RaisePredictiveEvent(new TabletopMoveEvent(_draggedEntity.Value, clampedCoords, _table.Value));
|
||||
_timePassed -= Delay;
|
||||
}
|
||||
}
|
||||
@@ -169,6 +164,9 @@ namespace Content.Client.Tabletop
|
||||
|
||||
private bool OnUse(in PointerInputCmdArgs args)
|
||||
{
|
||||
if (!_gameTiming.IsFirstTimePredicted)
|
||||
return false;
|
||||
|
||||
return args.State switch
|
||||
{
|
||||
BoundKeyState.Down => OnMouseDown(args),
|
||||
@@ -216,13 +214,7 @@ namespace Content.Client.Tabletop
|
||||
/// <param name="viewport">The viewport in which we are dragging.</param>
|
||||
private void StartDragging(EntityUid draggedEntity, ScalingViewport viewport)
|
||||
{
|
||||
RaiseNetworkEvent(new TabletopDraggingPlayerChangedEvent(draggedEntity, true));
|
||||
|
||||
if (EntityManager.TryGetComponent<AppearanceComponent>(draggedEntity, out var appearance))
|
||||
{
|
||||
_appearance.SetData(draggedEntity, TabletopItemVisuals.Scale, new Vector2(1.25f, 1.25f), appearance);
|
||||
_appearance.SetData(draggedEntity, TabletopItemVisuals.DrawDepth, (int) DrawDepth.Items + 1, appearance);
|
||||
}
|
||||
RaisePredictiveEvent(new TabletopDraggingPlayerChangedEvent(draggedEntity, true));
|
||||
|
||||
_draggedEntity = draggedEntity;
|
||||
_viewport = viewport;
|
||||
@@ -237,7 +229,8 @@ namespace Content.Client.Tabletop
|
||||
// Set the dragging player on the component to noone
|
||||
if (broadcast && _draggedEntity != null && EntityManager.HasComponent<TabletopDraggableComponent>(_draggedEntity.Value))
|
||||
{
|
||||
RaiseNetworkEvent(new TabletopDraggingPlayerChangedEvent(_draggedEntity.Value, false));
|
||||
RaisePredictiveEvent(new TabletopMoveEvent(_draggedEntity.Value, Transform(_draggedEntity.Value).MapPosition, _table!.Value));
|
||||
RaisePredictiveEvent(new TabletopDraggingPlayerChangedEvent(_draggedEntity.Value, false));
|
||||
}
|
||||
|
||||
_draggedEntity = null;
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
using Content.Server.Tabletop.Components;
|
||||
using Content.Shared.Tabletop;
|
||||
using Content.Shared.Tabletop.Components;
|
||||
using Content.Shared.Tabletop.Events;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Map;
|
||||
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
|
||||
|
||||
namespace Content.Server.Tabletop
|
||||
{
|
||||
public sealed partial class TabletopSystem
|
||||
{
|
||||
public void InitializeDraggable()
|
||||
{
|
||||
SubscribeNetworkEvent<TabletopMoveEvent>(OnTabletopMove);
|
||||
SubscribeNetworkEvent<TabletopDraggingPlayerChangedEvent>(OnDraggingPlayerChanged);
|
||||
SubscribeLocalEvent<TabletopDraggableComponent, ComponentGetState>(GetDraggableState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move an entity which is dragged by the user, but check if they are allowed to do so and to these coordinates
|
||||
/// </summary>
|
||||
private void OnTabletopMove(TabletopMoveEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (args.SenderSession as IPlayerSession is not { AttachedEntity: { } playerEntity } playerSession)
|
||||
return;
|
||||
|
||||
if (!EntityManager.TryGetComponent(msg.TableUid, out TabletopGameComponent? tabletop) || tabletop.Session is not {} session)
|
||||
return;
|
||||
|
||||
// Check if player is actually playing at this table
|
||||
if (!session.Players.ContainsKey(playerSession))
|
||||
return;
|
||||
|
||||
if (!CanSeeTable(playerEntity, msg.TableUid) || !CanDrag(playerEntity, msg.MovedEntityUid, out _))
|
||||
return;
|
||||
|
||||
// TODO: some permission system, disallow movement if you're not permitted to move the item
|
||||
|
||||
// Move the entity and dirty it (we use the map ID from the entity so noone can try to be funny and move the item to another map)
|
||||
var transform = EntityManager.GetComponent<TransformComponent>(msg.MovedEntityUid);
|
||||
var entityCoordinates = new EntityCoordinates(_mapManager.GetMapEntityId(transform.MapID), msg.Coordinates.Position);
|
||||
transform.Coordinates = entityCoordinates;
|
||||
}
|
||||
|
||||
private void OnDraggingPlayerChanged(TabletopDraggingPlayerChangedEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
var dragged = msg.DraggedEntityUid;
|
||||
|
||||
if (!EntityManager.TryGetComponent<TabletopDraggableComponent?>(dragged, out var draggableComponent)) return;
|
||||
|
||||
draggableComponent.DraggingPlayer = msg.IsDragging ? args.SenderSession.UserId : null;
|
||||
Dirty(draggableComponent);
|
||||
|
||||
if (!EntityManager.TryGetComponent<AppearanceComponent?>(dragged, out var appearance)) return;
|
||||
|
||||
if (draggableComponent.DraggingPlayer != null)
|
||||
{
|
||||
appearance.SetData(TabletopItemVisuals.Scale, new Vector2(1.25f, 1.25f));
|
||||
appearance.SetData(TabletopItemVisuals.DrawDepth, (int) DrawDepth.Items + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
appearance.SetData(TabletopItemVisuals.Scale, Vector2.One);
|
||||
appearance.SetData(TabletopItemVisuals.DrawDepth, (int) DrawDepth.Items);
|
||||
}
|
||||
}
|
||||
|
||||
private void GetDraggableState(EntityUid uid, TabletopDraggableComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new TabletopDraggableComponentState(component.DraggingPlayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ namespace Content.Server.Tabletop
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeNetworkEvent<TabletopStopPlayingEvent>(OnStopPlaying);
|
||||
SubscribeLocalEvent<TabletopGameComponent, ActivateInWorldEvent>(OnTabletopActivate);
|
||||
SubscribeLocalEvent<TabletopGameComponent, ComponentShutdown>(OnGameShutdown);
|
||||
@@ -27,7 +28,21 @@ namespace Content.Server.Tabletop
|
||||
SubscribeLocalEvent<TabletopGameComponent, GetVerbsEvent<ActivationVerb>>(AddPlayGameVerb);
|
||||
|
||||
InitializeMap();
|
||||
InitializeDraggable();
|
||||
}
|
||||
|
||||
protected override void OnTabletopMove(TabletopMoveEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (args.SenderSession is not IPlayerSession playerSession)
|
||||
return;
|
||||
|
||||
if (!TryComp(msg.TableUid, out TabletopGameComponent? tabletop) || tabletop.Session is not { } session)
|
||||
return;
|
||||
|
||||
// Check if player is actually playing at this table
|
||||
if (!session.Players.ContainsKey(playerSession))
|
||||
return;
|
||||
|
||||
base.OnTabletopMove(msg, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -2,7 +2,11 @@ using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Tabletop.Components;
|
||||
using Content.Shared.Tabletop.Events;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Serialization;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
@@ -10,8 +14,66 @@ namespace Content.Shared.Tabletop
|
||||
{
|
||||
public abstract class SharedTabletopSystem : EntitySystem
|
||||
{
|
||||
[Dependency] protected readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||
[Dependency] protected readonly ActionBlockerSystem ActionBlockerSystem = default!;
|
||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transforms = default!;
|
||||
[Dependency] private readonly IMapManager _mapMan = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<TabletopDraggableComponent, ComponentGetState>(GetDraggableState);
|
||||
SubscribeAllEvent<TabletopDraggingPlayerChangedEvent>(OnDraggingPlayerChanged);
|
||||
SubscribeAllEvent<TabletopMoveEvent>(OnTabletopMove);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move an entity which is dragged by the user, but check if they are allowed to do so and to these coordinates
|
||||
/// </summary>
|
||||
protected virtual void OnTabletopMove(TabletopMoveEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (args.SenderSession is not { AttachedEntity: { } playerEntity } playerSession)
|
||||
return;
|
||||
|
||||
if (!CanSeeTable(playerEntity, msg.TableUid) || !CanDrag(playerEntity, msg.MovedEntityUid, out _))
|
||||
return;
|
||||
|
||||
// Move the entity and dirty it (we use the map ID from the entity so noone can try to be funny and move the item to another map)
|
||||
var transform = EntityManager.GetComponent<TransformComponent>(msg.MovedEntityUid);
|
||||
_transforms.SetParent(transform, _mapMan.GetMapEntityId(transform.MapID));
|
||||
_transforms.SetLocalPositionNoLerp(transform, msg.Coordinates.Position);
|
||||
}
|
||||
|
||||
private void GetDraggableState(EntityUid uid, TabletopDraggableComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new TabletopDraggableComponentState(component.DraggingPlayer);
|
||||
}
|
||||
|
||||
private void OnDraggingPlayerChanged(TabletopDraggingPlayerChangedEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
var dragged = msg.DraggedEntityUid;
|
||||
|
||||
if (!TryComp(dragged, out TabletopDraggableComponent? draggableComponent))
|
||||
return;
|
||||
|
||||
draggableComponent.DraggingPlayer = msg.IsDragging ? args.SenderSession.UserId : null;
|
||||
Dirty(draggableComponent);
|
||||
|
||||
if (!TryComp(dragged, out AppearanceComponent? appearance))
|
||||
return;
|
||||
|
||||
if (draggableComponent.DraggingPlayer != null)
|
||||
{
|
||||
_appearance.SetData(dragged, TabletopItemVisuals.Scale, new Vector2(1.25f, 1.25f), appearance);
|
||||
_appearance.SetData(dragged, TabletopItemVisuals.DrawDepth, (int) DrawDepth.DrawDepth.Items + 1, appearance);
|
||||
}
|
||||
else
|
||||
{
|
||||
_appearance.SetData(dragged, TabletopItemVisuals.Scale, Vector2.One, appearance);
|
||||
_appearance.SetData(dragged, TabletopItemVisuals.DrawDepth, (int) DrawDepth.DrawDepth.Items, appearance);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class TabletopDraggableComponentState : ComponentState
|
||||
@@ -41,7 +103,7 @@ namespace Content.Shared.Tabletop
|
||||
return false;
|
||||
}
|
||||
|
||||
return _interactionSystem.InRangeUnobstructed(playerEntity, table.Value) && _actionBlockerSystem.CanInteract(playerEntity, table);
|
||||
return _interactionSystem.InRangeUnobstructed(playerEntity, table.Value) && ActionBlockerSystem.CanInteract(playerEntity, table);
|
||||
}
|
||||
|
||||
protected bool CanDrag(EntityUid playerEntity, EntityUid target, [NotNullWhen(true)] out TabletopDraggableComponent? draggable)
|
||||
|
||||
Reference in New Issue
Block a user