Skip to content

TimeSyncMessage is sent reliably, so a late one resets the client clock backwards and stalls its NetworkTransforms #4249

Open

Description

@zchristensen01

Description

TimeSyncMessage is sent reliably, although MessageDelivery says it's meant to stay unreliable. Under packet loss a time sync arrives late. The client takes its old host tick as current, its time offset passes HardResetThresholdSec (0.2 s by default), and NetworkTimeSystem hard-resets the client's clock backwards.

After that, NetworkTransformTickRegistration.TickUpdate skips while CurrentTick <= m_LastTick. Every NetworkTransform the client owns therefore sends nothing until its clock passes the last tick it sent. Teammates see that player freeze for up to about 0.5 s and then jump.

Details (line numbers from 2.13.3; the same code is in develop-3.x.x today):

  • MessageDelivery.cs: the summary of k_SkipMessageTypes says "Skip the time sync messages since it has always used unreliable network delivery". But the set holds only NamedMessage and Unnamed. So UpdateMessageTypes gives TimeSyncMessage ReliableFragmentedSequenced, and NetworkTimeSystem sends it with MessageDeliveryType<TimeSyncMessage>.DefaultDelivery.
  • NetworkTimeSystem: a sync whose send tick is old by the time it arrives produces a desired offset more than 0.2 s from the current one, so the clock is hard-reset to it, back in time.
  • NetworkTransform.cs:4765 (NetworkTransformTickRegistration.TickUpdate): if (CurrentTick <= m_LastTick) with the comment // TODO FIX: The local NetworkTickSystem can invoke with the same network tick as before. After a backward reset, this skips every tick until the clock catches up.

Reproduce Steps

  1. Host + 1 client (client-server), with the simulated poor connection on the host: about 75 ms delay, ±20 ms jitter and 2% packet loss.
  2. On the client, log NetworkManager.ServerTime.Tick every frame for a few minutes.
  3. Give the client an owner-authoritative NetworkTransform that moves continuously, and log on the host when its state updates arrive.

Actual Outcome

About twice a minute the client's ServerTime.Tick steps backwards (one example: 568 → 548). The client's NetworkTransform sends nothing until its tick passes 568 again, so the host sees it stand still for up to about 0.5 s and then jump.

Expected Outcome

A delayed time sync doesn't move a client's clock backwards, and its transforms keep sending. Possible fixes:

  • send TimeSyncMessage unreliably (add it to k_SkipMessageTypes, as the comment intends), so a lost one is replaced by the next a second later instead of arriving late;
  • or ignore a time sync older than the last one applied;
  • and/or let NetworkTransformTickRegistration recover from a backward tick (reset m_LastTick) instead of skipping until the clock catches up.

Screenshots

None. The numbers come from per-frame logs.

Environment

  • OS: Windows 11 Pro
  • Unity Version: 6000.3.27f1
  • Netcode Version: 2.13.3 (also present in develop-3.x.x and 3.2.0)
  • Netcode Commit: the v2.13.3 release
  • Netcode Topology: Client-Server (host)

Additional Context

  • Unity Transport 2.7.4.
  • Our workaround: each client raises NetworkTimeSystem.HardResetThresholdSec to 1 s when it starts. With that, the backward resets went from about two a minute to none in three minutes under the same conditions.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions