| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- using Content.Server.Movement.Components;
- using Robust.Server.Player;
- using Robust.Shared.Map;
- using Robust.Shared.Player;
- using Robust.Shared.Timing;
- namespace Content.Server.Movement.Systems;
- /// <summary>
- /// Stores a buffer of previous positions of the relevant entity.
- /// Can be used to check the entity's position at a recent point in time.
- /// </summary>
- public sealed class LagCompensationSystem : EntitySystem
- {
- [Dependency] private readonly IGameTiming _timing = default!;
- // I figured 500 ping is max, so 1.5 is 750.
- // Max ping I've had is 350ms from aus to spain.
- public static readonly TimeSpan BufferTime = TimeSpan.FromMilliseconds(750);
- public override void Initialize()
- {
- base.Initialize();
- Log.Level = LogLevel.Info;
- SubscribeLocalEvent<LagCompensationComponent, MoveEvent>(OnLagMove);
- }
- public override void Update(float frameTime)
- {
- base.Update(frameTime);
- var curTime = _timing.CurTime;
- var earliestTime = curTime - BufferTime;
- // Cull any old ones from active updates
- // Probably fine to include ignored.
- var query = AllEntityQuery<LagCompensationComponent>();
- while (query.MoveNext(out var comp))
- {
- while (comp.Positions.TryPeek(out var pos))
- {
- if (pos.Item1 < earliestTime)
- {
- comp.Positions.Dequeue();
- continue;
- }
- break;
- }
- }
- }
- private void OnLagMove(EntityUid uid, LagCompensationComponent component, ref MoveEvent args)
- {
- if (!args.NewPosition.EntityId.IsValid())
- return; // probably being sent to nullspace for deletion.
- component.Positions.Enqueue((_timing.CurTime, args.NewPosition, args.NewRotation));
- }
- public (EntityCoordinates Coordinates, Angle Angle) GetCoordinatesAngle(EntityUid uid, ICommonSession? pSession,
- TransformComponent? xform = null)
- {
- if (!Resolve(uid, ref xform))
- return (EntityCoordinates.Invalid, Angle.Zero);
- if (pSession == null || !TryComp<LagCompensationComponent>(uid, out var lag) || lag.Positions.Count == 0)
- return (xform.Coordinates, xform.LocalRotation);
- var angle = Angle.Zero;
- var coordinates = EntityCoordinates.Invalid;
- var ping = pSession.Channel.Ping;
- // Use 1.5 due to the trip buffer.
- var sentTime = _timing.CurTime - TimeSpan.FromMilliseconds(ping * 1.5);
- foreach (var pos in lag.Positions)
- {
- coordinates = pos.Item2;
- angle = pos.Item3;
- if (pos.Item1 >= sentTime)
- break;
- }
- if (coordinates == default)
- {
- Log.Debug($"No long comp coords found, using {xform.Coordinates}");
- coordinates = xform.Coordinates;
- angle = xform.LocalRotation;
- }
- else
- {
- Log.Debug($"Actual coords is {xform.Coordinates} and got {coordinates}");
- }
- return (coordinates, angle);
- }
- public Angle GetAngle(EntityUid uid, ICommonSession? session, TransformComponent? xform = null)
- {
- var (_, angle) = GetCoordinatesAngle(uid, session, xform);
- return angle;
- }
- public EntityCoordinates GetCoordinates(EntityUid uid, ICommonSession? session, TransformComponent? xform = null)
- {
- var (coordinates, _) = GetCoordinatesAngle(uid, session, xform);
- return coordinates;
- }
- }
|