docs.unity3d.com
Search Results for

    Show / Hide Table of Contents

    Struct ClientServerTickRate

    The ClientServerTickRate singleton is used to configure the client and server simulation time step, server packet send rate and other related settings. The singleton entity is automatically created for the clients in the NetworkStreamReceiveSystem first update if not present. On the server, by contrast, the entity is never automatically created and it is up to the user to create the singletong instance if they need to. This behaviour is asymmetric because the client need to have this singleton data synced with the server one. It is like this for compatibility reason and It may be changed in the future. In order to configure these settings you can either:

    • Create the entity in a custom Unity.NetCode.ClientServerBootstrap after the worlds has been created.
    • On a system, in either the OnCreate or OnUpdate.
    It is not mandatory to set all the fields to a proper value when creating the singleton. It is sufficient to change only the relevant setting, and call the ResolveDefaults() method to configure the fields that does not have a value set. The ClientServerTickRate settings are synced as part of the of the initial client connection handshake. (ClientServerTickRateRefreshRequest data). The ClientServerTickRate should also be used to customise other server only timing settings, such as
    • the maximum number of tick per frame
    • the maximum number of tick per frame
    • tick batching (<`MaxSimulationStepBatchSize`) and others.
    See the individual fields documentation for more information.
    Implements
    IComponentData
    IQueryTypeParameter
    Inherited Members
    ValueType.Equals(object)
    ValueType.GetHashCode()
    object.Equals(object, object)
    object.GetType()
    object.ReferenceEquals(object, object)
    Namespace: Unity.NetCode
    Assembly: Unity.NetCode.dll
    Syntax
    [Serializable]
    public struct ClientServerTickRate : IComponentData, IQueryTypeParameter
    Remarks
    • Once the client is connected, changes to the ClientServerTickRate are not replicated. If you change the settings are runtime, the same change must be done on both client and server.
    • The ClientServerTickRate should never be added to sub-scene with a baker. In case you want to setup the ClientServerTickRate based on some scene settings, we suggest to implement your own component and change the ClientServerTickRate inside a system in your game.
    Examples
    class MyCustomClientServerBootstrap : ClientServerBootstrap
    {
       override public void Initialize(string defaultWorld)
       {
           base.Initialise(defaultWorld);
           var customTickRate = new ClientServerTickRate();
           //run at 30hz
           customTickRate.simulationTickRate = 30;
           customTickRate.ResolveDefault();
           foreach(var world in World.All)
           {
               if(world.IsServer())
               {
                  //In this case we only create on the server, but we can do the same also for the client world
                  var tickRateEntity = world.EntityManager.CreateSingleton(new ClientServerTickRate
                  {
                      SimulationTickRate = 30;
                  });
               }
           }
       }
    }

    Fields

    HandshakeApprovalTimeoutMS

    The timeout for the connection handshake and approval procedure. Note: This is one counter for both states. In other words: The client must complete both Handshake and Approval before this timeout expires - it's not reset upon entering Approval.
    As soon as the client is accepted on the server, the timer will start. Timeout will occur if the server has not handshaked and approved the connection within the given duration. The default is 5000ms.

    Declaration
    [Tooltip("The timeout for the connection handshake and approval procedure. Both must succeed within the allotted time!\n\nDefaults to 0ms (which becomes 5s).")]
    [Range(0, 120000)]
    public uint HandshakeApprovalTimeoutMS
    Field Value
    Type Description
    uint
    Remarks

    The overall timeout sequence when a client is connecting is:
    1. The client goes through the transport-level connection timeout first (max connect attempt * connect timeout).
    2. Then, once the UTP connection succeeds, netcode begins the handshake process, where protocol version RPCs are automatically exchanged.
    3. If the client protocol is valid, the server will move the client to either the connected state, or to the approval state (if approval is enabled via RequireConnectionApproval).
    This timeout applies to both the Handshake and Approval elapsed durations. It's a single timer for both.

    MaxSimulationStepBatchSize

    If the server cannot keep up with the simulation frequency with running MaxSimulationStepsPerFrame ticks, it is possible to allow each tick to run with a longer delta time in order to keep the game time updating correctly. This means that instead of running two ticks with delta time N each, the system will run a single tick with delta time 2*N. It is a less expensive but more inaccurate way of dealing with server performance spikes, it also requires the game logic to be able to handle it.

    Declaration
    [Tooltip("Denotes how many individual ticks will be batched together (into a single tick) when recovering from a severe slowdown.\n\nDefault value is 0 (which becomes 4).\n\n<b>Warning: You lose accuracy when batching ticks, and gameplay code must account for it.</b>")]
    [Range(0, 16)]
    public int MaxSimulationStepBatchSize
    Field Value
    Type Description
    int

    MaxSimulationStepsPerFrame

    If the server cannot keep up with the passing of realtime (i.e. the server is ticking at too low a rate to match the SimulationTickRate), it will perform multiple ticks in a single frame (in an attempt to 'catch up'). This setting puts a limit on how many such updates it can perform in a single frame. Once this limit is reached, the simulation time will update slower than real time. The default value is 1.

    Declaration
    [Tooltip("Denotes how many fixed-step ticks can be performed on any given Unity frame, when 'catching up', when running too slowly.\n\nDefault value is 0 (which becomes 1).")]
    [Range(0, 16)]
    public int MaxSimulationStepsPerFrame
    Field Value
    Type Description
    int
    Remarks

    The network tick rate only applies to snapshots, the frequency commands and RPCs is not affected by this setting.

    NetworkTickRate

    The rate at which the server creates (and sends) a snapshots to each client. This can be lower than than the simulation frequency, which means the server only sends new snapshots to the clients every N frames. Defaults to the SimulationTickRate.

    Declaration
    [Tooltip("The rate at which the server creates (and sends) a snapshot to each client.\n\nIf zero (the default), this value will be set to the <b>SimulationTickRate</b>, but half (or one third) is often good enough.\n\nThe CPU work performed to build and send snapshots is often the most significant CPU cost in a multiplayer game. Thus, reducing this send-rate can lead to significant CPU savings, but at the expense of gameplay quality (especially when packets are lost to the network).")]
    [Min(0)]
    public int NetworkTickRate
    Field Value
    Type Description
    int
    Remarks

    The CPU work performed to build and send snapshots (via GhostSendSystem) is often the most significant CPU cost in a multiplayer game. Thus, reducing this send-rate can lead to significant CPU savings, but at the expense of gameplay quality (especially when packets are lost to the network). Note that the server can still send data on every simulation tick, but to different subsets of clients. This is to distribute CPU load over multiple simulation ticks (to avoid CPU spikes). For example, with a NetworkTickRate of 30 and a SimulationTickRate of 60, the server will send snapshots to half of the clients for one tick, and the other half, the next tick. So each client still end up with a packet every 2 simulation ticks, while the server is distributing the CPU load over each tick (via a 'round robin' strategy).

    PredictedFixedStepSimulationTickRatio

    Multiplier used to calculate the tick rate (i.e. frequency) for the PredictedFixedStepSimulationSystemGroup. The group rate must be an integer multiple of the SimulationTickRate. The default value is 1, meaning that the PredictedFixedStepSimulationSystemGroup run at the same frequency as the prediction loop. The calculated delta is 1.0/(SimulationTickRate*PredictedFixedStepSimulationTickRatio).

    Declaration
    [Tooltip("Multiplier used to calculate the tick rate (i.e. frequency) for the PredictedFixedStepSimulationSystemGroup.\n\nThe default (and recommendation) is 0 (which becomes 1 i.e. one fixed step per tick), where higher values allow physics to tick more frequently (i.e. at smaller intervals).")]
    [Range(0, 8)]
    public int PredictedFixedStepSimulationTickRatio
    Field Value
    Type Description
    int

    SimulationTickRate

    The fixed simulation frequency on the server and prediction loop. The client can render at a higher or lower rate than this. Default: 60Hz.

    Declaration
    [Tooltip("The fixed simulation frequency of the Netcode gameplay simulation. Higher values incur higher CPU costs on both the client and server, especially during client prediction.")]
    [Min(1)]
    public int SimulationTickRate
    Field Value
    Type Description
    int
    Remarks

    Note: Clients are not locked to this refresh rate (see Partial Ticks documentation). Higher values increase gameplay quality, but incur higher CPU and bandwidth costs. Higher values are particularly expensive on the client, as prediction cost increases.

    SnapshotAckMaskCapacity

    Netcode needs to store a history of snapshot acknowledgements ("acks") on the server - one per connection. This denotes the size of said history buffer, in bits, and is exposed only to allow further patching of an esoteric issue (see remarks). Default value is 4096 bits (0.5KB), which should prevent this issue in the common case. Previous hardcoded default was 256 bits.

    Declaration
    [Tooltip("Denotes how many entries the snapshot ack history BitArray stores. Default value: 4096 bits. Min: 1024 bits.\n\nSolves an emergent problem when replicating tens of thousands of relevant static ghosts to a single connection - a case we strongly advise against. See XML doc.")]
    public uint SnapshotAckMaskCapacity
    Field Value
    Type Description
    uint
    Remarks

    Due to GhostSendSystem priority queue mechanics, increasing this value may fix errors where:

    • Static ghosts never stop resending.
    • Static and dynamic ghosts do not correctly find their 'baselines' (i.e. previously send and acked values), when attempting delta-compression.

    Per connection, per chunk, netcode stores up to 32 previous snapshots (and thus baselines, and their acks) in a circular/ring buffer (GhostChunkSerializationState and SnapshotHistorySize). This ring-buffer appends an entry every time the chunk is successfully serialized into a snapshot writer.

    The problem is: When you have tens of thousands of relevant ghosts for a single connection (a case we strongly advise against), the priority queue will only "bubble up" a chunk to be resent after many tens of seconds. You can very loosely approximate the lower bound of this via (((numGhosts/avgNumGhostsPerChunk)*averageSizeOfChunkInBytes)/transportMTU)/NetworkTickRate E.g. 100k well optimized ghosts, sent at 30Hz (Simulation 60Hz), is (((100000/40)*1200)/1400)/30 = ~72s to replicate them all once. I.e. ~4285 simulation ticks will have occurred since the client was sent the previously sent snapshot.

    Thus, when we check the ack buffer ~72 seconds later, the ack has long since been bit-shifted off the end of the 256 tick history buffer. The simplest solution (implemented here) is to store an ack buffer that is considerably larger. It is now 4096 entries by default (i.e. ~1.1 minutes at 60Hz), and 1024 entries at a minimum (~17s at 60Hz), whereas the previous default was 256 (i.e. ~4.26s at 60Hz). This field configures said capacity.

    Because we are now able to find acks for snapshots sent over 4.26s ago, this fixed a regression in delta-compression performance (as, previously, the baseline was found, but treated as un-acked, thus unable to be used).

    We also previously failed to mark this chunk as having 'no changes' (via isZeroChange), as a ghost having 'no change' relies on its current value being compared to any of its acked baseline values. This means we previously could not early out via CanUseStaticOptimization (which looks for zero change). As a result, we frequently saw resending of previously acked static ghosts in these circumstances (at least until the server so happens to try to resend the same chunk within SnapshotAckMaskCapacity ticks of a previous ack).

    Similarly, if you implemented configuration options like MinSendImportance, we would delay processing of a chunk artificially. If this delay happened to exceed capacity, the chunk (and its ghosts) can never possibly ack. Thankfully, SnapshotAckMaskCapacity is now far higher than we'd ever recommend setting MinSendImportance.

    TargetFrameRateMode

    If the server is capable of updating more often than the simulation tick rate, it can either skip the simulation tick for some updates (BusyWait), or limit the updates using Application.TargetFrameRate (Sleep). Auto makes it use Sleep for dedicated server builds and BusyWait for client and server builds (as well as the editor).

    Declaration
    [Tooltip("Denotes how the server should sleep, when determining when it should next tick.\n\nDefaults to <b>Auto</b>, which will use <b>Sleep</b> for dedicated server builds, and <b>BusyWait</b> for client and server builds (as well as the editor).")]
    public ClientServerTickRate.FrameRateMode TargetFrameRateMode
    Field Value
    Type Description
    ClientServerTickRate.FrameRateMode

    Properties

    ClampPartialTicksThreshold

    On the client, Netcode attempts to align its own fixed step with the render refresh rate, with the goal of reducing Partial ticks, and increasing stability. This setting denotes the window (in %) to snap and align. Defaults to 5 (5%), which is applied each way: I.e. If you're within 5% of the last full tick, or if you're within 5% of the next full tick, we'll clamp. -1 is 'turn clamping off', 0 is 'use default'. Max value is 50 (i.e. 50% each way, leading to full clamping, as it's applied in both directions).

    Declaration
    [Tooltip("On the client, Netcode attempts to align its own fixed step with the render refresh rate, with the goal of reducing Partial ticks, and increasing stability.\n\nThis setting denotes the window (in %) to snap and align.\n\nDefaults to 5 (5%), which is applied each way.\nI.e. If you're within 5% of the last full tick, or if you're within 5% of the next full tick, we'll clamp. 50 (50%) to always clamp.")]
    public int ClampPartialTicksThreshold { readonly get; set; }
    Property Value
    Type Description
    int
    Remarks

    High values will lead to more aggressive alignment, which may be perceivable (as we'll need to shift time further).

    PredictedFixedStepSimulationTimeStep

    The fixed time used to run the physics simulation. Is always an integer multiple of the SimulationFixedTimeStep.
    The value is equal to 1f / (SimulationTickRate * PredictedFixedStepSimulationTickRatio).

    Declaration
    public float PredictedFixedStepSimulationTimeStep { get; }
    Property Value
    Type Description
    float

    SendSnapshotsForCatchUpTicks

    If the server has to run multiple simulation ticks in the same frame, the server can either send snapshots for all those ticks (true), or just the last one (false).

    Declaration
    public bool SendSnapshotsForCatchUpTicks { get; set; }
    Property Value
    Type Description
    bool

    SimulationFixedTimeStep

    1f / SimulationTickRate. Think of this as the netcode version of fixedDeltaTime.

    Declaration
    public float SimulationFixedTimeStep { get; }
    Property Value
    Type Description
    float

    Methods

    CalculateNetworkSendIntervalOfGhostInTicks(ushort)

    Returns the MaxSendRate as a SimulationTickRate interval UNTIL you can resend this chunk.

    Declaration
    public byte CalculateNetworkSendIntervalOfGhostInTicks(ushort MaxSendRate)
    Parameters
    Type Name Description
    ushort MaxSendRate

    From the GhostAuthoring.

    Returns
    Type Description
    byte

    The interval i.e. every nth SimulationTickRate tick.

    CalculateNetworkSendRateInterval()

    Helper: Returns 1 when NetworkTickRate is equal to (or close enough - via rounding - to) SimulationTickRate. Returns 2 when half, 3 when 1/3rd etc.

    Declaration
    public int CalculateNetworkSendRateInterval()
    Returns
    Type Description
    int

    The snapshot send interval.

    ResolveDefaults()

    Set all the properties that haven't been changed by the user (or that have invalid ranges) to a proper default value. In particular, this guarantees that both NetworkTickRate and SimulationTickRate are never 0.

    Declaration
    public void ResolveDefaults()

    Implements

    Unity.Entities.IComponentData
    Unity.Entities.IQueryTypeParameter

    Did you find this page useful? Please give it a rating:

    Thanks for rating this page!

    Report a problem on this page

    What kind of problem would you like to report?

    • This page needs code samples
    • Code samples do not work
    • Information is missing
    • Information is incorrect
    • Information is unclear or confusing
    • There is a spelling/grammar error on this page
    • Something else

    Thanks for letting us know! This page has been marked for review based on your feedback.

    If you have time, you can provide more information to help us fix the problem faster.

    Provide more information

    You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:

    You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:

    You've told us there is information missing from this page. Please tell us more about what's missing:

    You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:

    You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:

    You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:

    You've told us this page has a problem. Please tell us more about what's wrong:

    Thank you for helping to make the Unity documentation better!

    Your feedback has been submitted as a ticket for our documentation team to review.

    We are not able to reply to every ticket submitted.

    In This Article
    • Fields
      • HandshakeApprovalTimeoutMS
      • MaxSimulationStepBatchSize
      • MaxSimulationStepsPerFrame
      • NetworkTickRate
      • PredictedFixedStepSimulationTickRatio
      • SimulationTickRate
      • SnapshotAckMaskCapacity
      • TargetFrameRateMode
    • Properties
      • ClampPartialTicksThreshold
      • PredictedFixedStepSimulationTimeStep
      • SendSnapshotsForCatchUpTicks
      • SimulationFixedTimeStep
    • Methods
      • CalculateNetworkSendIntervalOfGhostInTicks(ushort)
      • CalculateNetworkSendRateInterval()
      • ResolveDefaults()
    • Implements
    Back to top
    Copyright © 2025 Unity Technologies — Trademarks and terms of use
    • Legal
    • Privacy Policy
    • Cookie Policy
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)