Skip to content

Commit a7b725b

Browse files
author
Unity Technologies
committed
## [1.6.2] - 2025-07-07 ### Added * `UnityEngine.Time.frameCount` is appended to netcode packet `timestamp` logs using format: `[Fr{0}]`. ### Changed * The client now sends - as part of its command data - some extra information regarding the command tick. In particular, it informs the server if the current command is for a full or partial update/tick. This ensure a more proper time-sync, and avoids mis-predictions. ### Fixed * Adding `GhostAuthoringComponent` will now work properly for a prefab that is opened (double clicked instead of just selected). * Issue preventing static-optimized, not pre-spawned ghosts from spawning on clients when their first serialization result was 'zero-change' against a baseline value of `default(T)`. They'd previously only be sent for the first time after changing. * **Project Breaking Change:** Regenerated the GUID for `Packages/com.unity.netcode/Tests/Editor/Physics/Unity.NetCode.Physics.Editor.Tests.asmdef` so that it would no longer clash with `Packages/com.havok.physics/Plugins/Android/Havok.Physics.Plugin.Android.asmdef`. Any assemblies attempting to reference **Unity.NetCode.Physics.Editor.Tests** by GUID `d8342c4acf8f78e439367cff1a5e802f` will need to be changed to `bec3f262d6e6466eb2c61661da550f47`. * An issue - due to improper time syncing in between the client and server - especially when using IPC, causing multiple side effects: * the client was typically only sending commands to the server for partial ticks, not full ticks, causing mis-predictions. * the client was slightly behind the server, thus receiving new snapshots slightly in advance, and skipping running the `PredictedSimulationSystemGroup` for one frame or more, causing jittery and noticeable artefacts. * **Potential Behaviour Breaking Change:** GhostInstance's GhostType is now set with the same valid value for both client and server prespawned instances. (Previously, this was always kept at an initial -1 value server side and never initialized). This way is now more consistent behaviour between client and server.
1 parent a6b64cf commit a7b725b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+582
-165
lines changed

.buginfo

Lines changed: 0 additions & 4 deletions
This file was deleted.

.signature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"timestamp":1748805628,"signature":"esi8seGvz4WL/MUCeUCPGG8QqQufu04yioXdYmxMvFiMjQ40jWjwr4icQ2LOYSEqRvhdy9kXIOySwehOKi/G6L/IlqD95dthLTkfHBsAUQNuikKYwhsp8yfCjZtcZQXYX/bKxDrjCtgkqeJNFbx6BUMH53JSrcURCIkFqpq6zurkrRuLPsoktaga+JFFLzuaypNPtDE0p7/S9PmNALLSltwteBhVPTuazK2TKqZ2kll8qD2b8EGtkk0hgszFSUMlSuZ6Lq8XK5ZZsV5Wvk7sKgC6b+QXUgWOqcBYoHlq7BGWClqkgmVgvY8kax/gPNXjyzPBvCG9IWTnkV4LYBPRmKgBU25lLjSZOzSdZu0x42xi0+aBVAh9gLE10k8IlfMAImIkVeDZ/zR2AhbZS+MpLhisxtReecqKZzXjbpWFwQdjyAZdLkN6Ao7XVfRrj+TefKUPlJvwJAeKzTRhtpLvZCm893Hll49NXtOJtj7sYQYckhGvE3GCiJx/l05LCYN9","publicKey":"LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQm9qQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FZOEFNSUlCaWdLQ0FZRUFzdUhXYUhsZ0I1cVF4ZEJjTlJKSAordHR4SmoxcVY1NTdvMlZaRE1XaXhYRVBkRTBEMVFkT1JIRXNSS1RscmplUXlERU83ZlNQS0ZwZ1A3MU5TTnJCCkFHM2NFSU45aHNQVDhOVmllZmdWem5QTkVMenFkVmdEbFhpb2VpUnV6OERKWFgvblpmU1JWKytwbk9ySTRibG4KS0twelJlNW14OTc1SjhxZ1FvRktKT0NNRlpHdkJMR2MxSzZZaEIzOHJFODZCZzgzbUovWjBEYkVmQjBxZm13cgo2ZDVFUXFsd0E5Y3JZT1YyV1VpWXprSnBLNmJZNzRZNmM1TmpBcEFKeGNiaTFOaDlRVEhUcU44N0ZtMDF0R1ZwCjVNd1pXSWZuYVRUemEvTGZLelR5U0pka0tldEZMVGdkYXpMYlpzUEE2aHBSK0FJRTJhc0tLTi84UUk1N3UzU2cKL2xyMnZKS1IvU2l5eEN1Q20vQWJkYnJMbXk0WjlSdm1jMGdpclA4T0lLQWxBRWZ2TzV5Z2hSKy8vd1RpTFlzUQp1SllDM0V2UE16ZGdKUzdGR2FscnFLZzlPTCsxVzROY05yNWdveVdSUUJ0cktKaWlTZEJVWmVxb0RvSUY5NHpCCndGbzJJT1JFdXFqcU51M3diMWZIM3p1dGdtalFra3IxVjJhd3hmcExLWlROQWdNQkFBRT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg"}
1+
{"timestamp":1751910872,"signature":"m+g4mUzsEAZQhRKaS+29tALYFf1GwmRdKiOveM8/lyimKgEbzDegDmWamRX3jgXNysIRG7ne3U6eaP7vbsFq4ujwq/4PzrooM09wujCkXhk0uegTsGN57Q1si4VtkYGPev24Me4frQQB4kHnXkYF6GpMs1C2/HD7ZBOLUGXXQx0/KtB8EuT31zoz0Kia9eknpQoS1aHnShfVJC0ZBxAUxW0qEhRtkG6bPErO9IndToPGMq93Tbbm6MRBIfCX5+Z75j6AqhadCoComeFf0ue0Wi3qyi5LhKkkWfBmiYxYXbqTWk3dqRYwlLWWLhDUTGuFxxZLXrQFwDsBBPYVzGuQ8ei5wljH5lvWKyYFiiGYhKjsOqTAyFVCFz6GxsTR4c+VKgmFQ1KojU9HVQf2HdPUNt0unLNCOTTZ/ib2PF0HVCVAL4T8LtybcB0OvrMPiaovvVna/FxnTiNYr4wvoAT002Eh00FQVlKs9b+Pe8mQvIVYmDndP0d0i35vNtI0DSrM","publicKey":"LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQm9qQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FZOEFNSUlCaWdLQ0FZRUFzdUhXYUhsZ0I1cVF4ZEJjTlJKSAordHR4SmoxcVY1NTdvMlZaRE1XaXhYRVBkRTBEMVFkT1JIRXNSS1RscmplUXlERU83ZlNQS0ZwZ1A3MU5TTnJCCkFHM2NFSU45aHNQVDhOVmllZmdWem5QTkVMenFkVmdEbFhpb2VpUnV6OERKWFgvblpmU1JWKytwbk9ySTRibG4KS0twelJlNW14OTc1SjhxZ1FvRktKT0NNRlpHdkJMR2MxSzZZaEIzOHJFODZCZzgzbUovWjBEYkVmQjBxZm13cgo2ZDVFUXFsd0E5Y3JZT1YyV1VpWXprSnBLNmJZNzRZNmM1TmpBcEFKeGNiaTFOaDlRVEhUcU44N0ZtMDF0R1ZwCjVNd1pXSWZuYVRUemEvTGZLelR5U0pka0tldEZMVGdkYXpMYlpzUEE2aHBSK0FJRTJhc0tLTi84UUk1N3UzU2cKL2xyMnZKS1IvU2l5eEN1Q20vQWJkYnJMbXk0WjlSdm1jMGdpclA4T0lLQWxBRWZ2TzV5Z2hSKy8vd1RpTFlzUQp1SllDM0V2UE16ZGdKUzdGR2FscnFLZzlPTCsxVzROY05yNWdveVdSUUJ0cktKaWlTZEJVWmVxb0RvSUY5NHpCCndGbzJJT1JFdXFqcU51M3diMWZIM3p1dGdtalFra3IxVjJhd3hmcExLWlROQWdNQkFBRT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg"}

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,26 @@
22
uid: changelog
33
---
44

5+
## [1.6.2] - 2025-07-07
6+
7+
### Added
8+
9+
* `UnityEngine.Time.frameCount` is appended to netcode packet `timestamp` logs using format: `[Fr{0}]`.
10+
11+
### Changed
12+
13+
* The client now sends - as part of its command data - some extra information regarding the command tick. In particular, it informs the server if the current command is for a full or partial update/tick. This ensure a more proper time-sync, and avoids mis-predictions.
14+
15+
### Fixed
16+
17+
* Adding `GhostAuthoringComponent` will now work properly for a prefab that is opened (double clicked instead of just selected).
18+
* Issue preventing static-optimized, not pre-spawned ghosts from spawning on clients when their first serialization result was 'zero-change' against a baseline value of `default(T)`. They'd previously only be sent for the first time after changing.
19+
* **Project Breaking Change:** Regenerated the GUID for `Packages/com.unity.netcode/Tests/Editor/Physics/Unity.NetCode.Physics.Editor.Tests.asmdef` so that it would no longer clash with `Packages/com.havok.physics/Plugins/Android/Havok.Physics.Plugin.Android.asmdef`. Any assemblies attempting to reference **Unity.NetCode.Physics.Editor.Tests** by GUID `d8342c4acf8f78e439367cff1a5e802f` will need to be changed to `bec3f262d6e6466eb2c61661da550f47`.
20+
* An issue - due to improper time syncing in between the client and server - especially when using IPC, causing multiple side effects:
21+
* the client was typically only sending commands to the server for partial ticks, not full ticks, causing mis-predictions.
22+
* the client was slightly behind the server, thus receiving new snapshots slightly in advance, and skipping running the `PredictedSimulationSystemGroup` for one frame or more, causing jittery and noticeable artefacts.
23+
* **Potential Behaviour Breaking Change:** GhostInstance's GhostType is now set with the same valid value for both client and server prespawned instances. (Previously, this was always kept at an initial -1 value server side and never initialized). This way is now more consistent behaviour between client and server.
24+
525
## [1.6.1] - 2025-05-28
626

727
### Added

Documentation~/command-stream.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Use the command stream to handle inputs
22

3-
Each client send a continuous command stream to the server when [`NetworkStreamConnection`](https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.NetworkStreamConnection.html) is tagged as in-game. This stream includes all inputs and acknowledgements of the last received snapshot, and is typically one packet per `ServerTick`.
3+
Each client sends a continuous command stream to the server when [`NetworkStreamConnection`](https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.NetworkStreamConnection.html) is tagged as in-game. This stream includes all inputs and acknowledgements of the last received snapshot, and is typically one packet per `NetworkTime.ServerTick`.
44

5-
The connection is always kept alive, even if the client doesn't control any entities or generate any inputs that need to be transmitted to the server. The command packet is sent at a regular interval (every full simulated tick) to automatically acknowledge received snapshots, and to report other important information to the server.
5+
The connection is always kept alive, even if the client doesn't control any entities or generate any inputs that need to be transmitted to the server. The command packet is sent regularly on the timescale described in [Collecting and sending input from the client](#collecting-and-sending-input-from-the-client), automatically acknowledging received snapshots and reporting other important information to the server.
66

77
## Creating inputs (commands)
88

@@ -12,17 +12,19 @@ The serialization and registration code for the `ICommandData` is generated auto
1212

1313
The `ICommandData` buffer can be added to the entity controlled by the player either at baking time (using an authoring component) or at runtime. When adding the buffer at runtime, make sure that the dynamic buffer is present on both server and client.
1414

15-
### Handling input on the client
15+
### Collecting and sending input from the client
1616

17-
The client is responsible for polling the input source and adding `ICommand` to the buffer for the entities it controls. The queued commands are then sent automatically at regular intervals by `CommandSendPacketSystem`.
17+
The client is responsible for polling the input source and adding `ICommand` to the buffer for the entities it controls. The systems responsible for writing to the command buffers must all run inside the [`GhostInputSystemGroup`](https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostInputSystemGroup.html).
1818

19-
The systems responsible for writing to the command buffers must all run inside the [`GhostInputSystemGroup`](https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostInputSystemGroup.html).
19+
The `CommandSendPacketSystem` automatically sends the queued commands on completion of the client's first [partial tick](intro-to-pediction.md#partial-ticks) per full tick, along with commands from the previous `n` ticks (where `n` is defined by [`ClientTickRate.TargetCommandSlack`](https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.ClientTickRate.html#Unity_NetCode_ClientTickRate_TargetCommandSlack) plus [`ClientTickRate.NumAdditionalCommandsToSend`](https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.ClientTickRate.html#Unity_NetCode_ClientTickRate_NumAdditionalCommandsToSend)) as a buffer against packet loss.
20+
21+
For example: in tick 10.3, input is gathered and sent to the server as input for tick 10. In tick 10.7, the input has changed but is not sent to the server. In tick 11.2, the input for the full previous tick 10 is sent (refer to [ICommandData serialization and payload limit](#icommanddata-serialization-and-payload-limit)). The server updates the inputs for tick 10 to use in its simulation, if it hasn't already simulated tick 10.
2022

2123
### `ICommandData` serialization and payload limit
2224

23-
When using `ICommand`, Netcode for Entities automatically generates command serialization code in the [`CommandSendSystemGroup`](https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.CommandSendSystemGroup.html). Each individual command is serialized and queued in the [`OutgoingCommandDataStreamBuffer`](https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.OutgoingCommandDataStreamBuffer.html) (present on the network connection) by its own code-generated system. The `CommandSendPacketSystem` is then responsible for flushing the outgoing buffer at the `SimulationTickRate` interval.
25+
When using `ICommand`, Netcode for Entities automatically generates command serialization code in the [`CommandSendSystemGroup`](https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.CommandSendSystemGroup.html). Each individual command is serialized and queued in the [`OutgoingCommandDataStreamBuffer`](https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.OutgoingCommandDataStreamBuffer.html) (present on the network connection) by its own code-generated system. The `CommandSendPacketSystem` is then responsible for flushing the outgoing buffer on the timescale described in [Collecting and sending input from the client](#collecting-and-sending-input-from-the-client).
2426

25-
In addition to the most recent input, the previous three inputs are also included to provide redundancy in the case of packet loss. Each redundant command is delta compressed against the command for the current tick. The final serialized data looks something like the following:
27+
In addition to the most recent input, inputs from the previous `n` ticks are also included to provide redundancy in the case of packet loss (where `n` is defined by [`ClientTickRate.TargetCommandSlack`](https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.ClientTickRate.html#Unity_NetCode_ClientTickRate_TargetCommandSlack) plus [`ClientTickRate.NumAdditionalCommandsToSend`](https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.ClientTickRate.html#Unity_NetCode_ClientTickRate_NumAdditionalCommandsToSend), with a default value of 4). Each redundant command is delta compressed against the command for the current tick. The final serialized data looks something like the following:
2628

2729
```
2830
| Tick, Command | CommandDelta(Tick-1, Tick) | CommandDelta(Tick-2, Tick) | CommandDelta(Tick-3, Tick)|

Documentation~/ghostfield-synchronize.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,4 @@ Refer to [how to use and write templates](ghost-types-templates.md#defining-addi
149149
- [Ghost types templates](ghost-types-templates.md)
150150
- [Ghost variants](ghost-variants.md)
151151
- [Customizing replication with `GhostComponentAttribute`](ghostcomponentattribute.md)
152+
- [Preserializing ghosts](optimizations.md#preserialization)

Documentation~/network-connection.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Netcode for Entities uses the [Unity Transport package](https://docs.unity3d.com/Packages/com.unity.transport@latest) to manage connections and stores each connection as an entity. Each connection entity has a [NetworkStreamConnection](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NetworkStreamConnection.html) component with the `Transport` handle for the connection. When the connection is closed, either because the server disconnected the user or the client requested to disconnect, the entity is destroyed.
44

5-
To target which entity should receive the player commands, when not using the [`AutoCommandTarget` feature](command-stream#automatically handling-commands-autocommandtarget-) or for having more manual control, each connection has a [CommandTarget](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.CommandTarget.html) which must point to the entity where the received commands need to be stored. Your game is responsible for keeping this entity reference up to date.
5+
To target which entity should receive the player commands, when not using the [`AutoCommandTarget` feature](command-stream.md#automatically-handling-commands-autocommandtarget) or for having more manual control, each connection has a [CommandTarget](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.CommandTarget.html) which must point to the entity where the received commands need to be stored. Your game is responsible for keeping this entity reference up to date.
66

77
Your game can mark a connection as being in-game with the `NetworkStreamInGame` component. Your game must do this; it's never done automatically. Before the `NetworkStreamInGame` component is added to the connection, the client does not send commands, nor does the server send snapshots.
88

@@ -16,8 +16,8 @@ Each connection can have up to three incoming buffers, one for each type of stre
1616
- [IncomingCommandDataStreamBuffer](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.IncomingCommandDataStreamBuffer.html)
1717
- [IncomingSnapshotDataStreamBuffer](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.IncomingSnapshotDataStreamBuffer.html)
1818

19-
When a client receives a snapshot from the server, the message is queued into the buffer and processed later by the [GhostReceiveSystem](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.IncomingSnapshotDataStreamBuffer.html).
20-
Similarly, RPCs and commands follow the sample principle. The messages are gathered first by the [NetworkStreamReceiveSystem](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NetworkStreamReceiveSystem.html) and then consumed by the respective RPC and command receive system.
19+
When a client receives a snapshot from the server, the message is queued into the buffer and processed later by the [`GhostReceiveSystem`](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.IncomingSnapshotDataStreamBuffer.html).
20+
RPCs and commands follow the same principle. The messages are gathered first by the [`NetworkStreamReceiveSystem`](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NetworkStreamReceiveSystem.html) and then consumed by the respective RPC and command receive system.
2121

2222
> [!NOTE]
2323
> Server connection does not have an IncomingSnapshotDataStreamBuffer.

Documentation~/optimizations.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,17 @@ When a `GhostField` changes, we serialize the data and synchronize it over the n
9090
First, it serializes the data and compares it with the previous synchronized version of it. If the job did not change the `GhostField`, it discards the serialized result.
9191
For this reason, it is important to ensure that no jobs have write access to data if it will not change (to remove this hidden CPU cost).
9292

93+
## Preserialization
94+
95+
By default, all ghosts are serialized once per connection on the server. This is done on demand and each ghost is only serialized when it's actually sent to a client. This serialization process can be expensive in terms of CPU, especially when the server has many connections and many ghosts. To reduce this cost, you can use preserialization.
96+
97+
Preserialization is a feature that allows you to serialize ghost data once and reuse it for all connections on the server. You can enable preserialization in two ways:
98+
99+
1. Enabling [`UsePreserialization`](https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostAuthoringComponent.html#Unity_NetCode_GhostAuthoringComponent_UsePreSerialization) in the `GhostAuthoringComponent` inspector on your ghost prefab. This causes all ghosts of this type to use preserialization.
100+
2. Adding the [`PreSerializedGhost`](https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.PreSerializedGhost.html) component to the ghost entity in the server world. This causes only this specific ghost to use preserialization.
101+
102+
When preserialization is enabled the server only serializes the ghost once for all connections. However, preserialized ghosts are serialized regularly on every tick, even if the ghost isn't going to be sent to any client. As a result, preserialization is only recommended for ghosts that are frequently sent to multiple clients (otherwise the CPU cost might be higher than the default behavior of serializing ghosts on demand).
103+
93104
## Relevancy
94105

95106
"Ghost Relevancy" (a.k.a. "Ghost Filtering") is a server feature, allowing you to set conditions on whether or not a specific ghost entity is replicated to (i.e. spawned on) a specific client. You can use this to:

Documentation~/physics.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Physics Ghost Setup Checklist:
1919

2020
## Interpolated ghosts
2121

22-
For interpolated ghosts it's important that the physics simulation only runs on the server.On the client, the ghost's position and rotation are controlled by the snapshots from the server and the client shouldn't run the physics simulation for interpolated ghosts.
22+
For interpolated ghosts it's important that the physics simulation only runs on the server. On the client, the ghost's position and rotation are controlled by the snapshots from the server and the client shouldn't run the physics simulation for interpolated ghosts.
2323

2424
To make sure this is true, Netcode disables the `Simulate` component data tag on clients on appropriate ghost entities at the beginning on each frame. This makes the physics object `kinematic` and they won't be moved by the physics simulation.
2525

0 commit comments

Comments
 (0)