| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
NetworkDeltaPosition carries the half float rounding loss of each update into the next one, which keeps the average transmitted position accurate while a value is moving. The loss alone is enough to change the encoded delta, so once the value stops moving that mechanism keeps changing what is sent even though the position has not moved. The encoded value alternates between neighbouring representable values and a stationary object is transmitted as one that oscillates. The rounding loss is now only carried forward while the value moves by at least one representable step. MaxDeltaBeforeAdjustment also determined the transmitted resolution, since a half float's step size grows with its magnitude. At 64 the coarsest step was 31.25mm, so objects away from their base position were reproduced in ~3cm increments. At 2 it is 0.977mm. Folding the delta into the base more often costs no bandwidth with reliable deltas because both sides apply the same rule to the same value, and the reconstructed position is unchanged by the fold. UseUnreliableDeltas forces a full precision base synchronization per fold, so those projects will send those more often. Measured on 10 settling physics objects with half float enabled: 28-42mm of oscillation before, none after, matching the same scene with half float disabled. Objects in motion improve as well, peak error dropping from 12.5mm to 0.587mm. Sender and receiver must agree on MaxDeltaBeforeAdjustment, so this is not compatible across builds. NetworkConstants.PROTOCOL_VERSION already participates in the connection config hash, so mismatched versions cannot connect. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two NetcodeIntegrationTest cases, one for an object moving in steps too small for the encoding to represent and one for an object at rest. Both move the authority forwards only and require non-authority instances to follow without ever moving backwards. Interpolation cannot overshoot, so movement opposite to the authority's has to have come from the encoding. That also avoids a tolerance that would need revisiting whenever the resolution changes. Two setup details are needed for these to detect anything. The object has to travel away from the base position established when it spawned, since resolution is fine near the base. It then has to step by an amount the encoding cannot represent before coming to rest, because a position a half float represents exactly leaves no rounding loss and so cannot exhibit the problem: resting on 30.0 produces no backwards movement at all while resting on 30.0007 produces 15.6mm. Verified in both directions. Without the fix all four cases fail on the intended assertion, reporting 7.9mm to 10.1mm of backwards movement. With the fix all four pass. These do not use the time travel harness because the behavior only appears over multiple real state update and interpolation cycles. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Updated changelog entries for NetworkTransform.UseHalfFloatPrecision to reflect changes in issue tracking numbers.
Codecov ReportAll modified and coverable lines are covered by tests ✅ @@ Coverage Diff @@
## develop-2.0.0 #4128 +/- ##
=================================================
+ Coverage 73.96% 74.10% +0.14%
=================================================
Files 172 172
Lines 28113 28127 +14
=================================================
+ Hits 20793 20844 +51
+ Misses 7320 7283 -37
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 2 files with indirect coverage changes
|
Sorry, something went wrong.
Adding better coverage and adjusting some of the test to better leverage from NetcodeIntegrationTest helper methods.
There was a problem hiding this comment.
The delta-encoding adjustment and its focused coverage are soundly structured, but changing the shared fold threshold alters the interpretation of existing half-float position payloads across builds.
Reviewed commit 46690ad
🤖 Helpful? 👍/👎
Sorry, something went wrong.
Moving the NetworkDeltaPositionTests into its own file.
Bumping the protocol version to assure legacy clients cannot connect to a session with the fixes. While the fixes aren't technically a "breaking change", any projects using the legacy lerp will end up with an offset from the expected final position. Since motion continually feeds the full position (half float or full precision) as deltas this would prevent from "long term drift". Either case, updating the protocol version only assures that clients of a previous version cannot connect to a session with the newer version.
There is one connected client, so the per instance dictionaries and the loops over m_NetworkManagers only ever held one entry. Resolve the non-authority instance once through GetNonAuthorityNetworkManager and name the two sampling frame counts that were inline literals.
…ed path ADeltaUnderTheThresholdIsLeftAsADelta asserted nothing the other tests do not: MovingFoldsThePreviousRoundingLossBackIn already requires the delta to stay under the threshold, and UnsynchronizedAxesAreLeftUntouched already requires the synchronized axis to hold the movement. QuantumDropsTheSignBecauseTheLatticeIsSymmetric ran its own value list to assert one thing, so it moves into the loop in QuantumIsTheSmallestChangeTheEncodingCanSee, which already walks the same kind of values. 300f joins that list so no input is lost. The masking it covers is a common path executed by every call, so the coverage score is unchanged either way.
….com/Unity-Technologies/com.unity.netcode.gameobjects into fix/half-float-delta-position-dither
The fixture is unit tests over NetworkDeltaPosition's encoding math with no session behind it, so it belongs in EditMode rather than paying PlayMode entry. QuantumIsGuardedAtTheTopOfTheRange becomes a [Test] over an array so every data set in the fixture is driven the same way, and the value list in QuantumIsTheSmallestChangeTheEncodingCanSee is hoisted out of the foreach to match the other three. The reference to NetworkTransformHalfFloatPrecisionTests drops its cref because that fixture is internal to Unity.Netcode.Runtime.Tests, which does not expose its internals to the editor test assembly.
The bound is unchanged: ticks 102 through 105 inclusive.
| Back | FazBrowse Home | New Git URL |
Purpose of this PR
NetworkTransform.UseHalfFloatPrecision made objects appear to jitter on non-authority instances while they were stationary or coming to rest, even though the authority was not moving them.
NetworkDeltaPosition encodes position as a half float delta from a base position, and carries the rounding loss of each update into the next one. That keeps the average transmitted position accurate while a value is moving. The problem is that the rounding loss alone is enough to change the encoded delta, so once the value stops moving that mechanism keeps changing what gets sent even though the position has not changed. The encoded value alternates between neighbouring representable values, and a stationary object is transmitted as one that oscillates.
The rounding loss is now only carried forward while the value moves by at least one representable step between updates. Below that the delta is sent as-is, which still follows slow movement but cannot introduce movement of its own. The threshold comes from the encoding rather than a configured value, so it engages where the resolution is coarse enough to matter and stays out of the way near the base position.
MaxDeltaBeforeAdjustment was a second, quieter half of the same problem: it determined the transmitted resolution, because a half float's step size grows with its magnitude. At 64 the coarsest step was 31.25mm, so objects away from their base position were reproduced in ~3cm increments. At 2 it is 0.977mm, which is finer than the default PositionThreshold of 1mm. The two settings were previously incoherent with each other.
Tradeoffs worth reviewer attention:
Jira ticket
Changelog
com.unity.netcode.gameobjects
Documentation
One gap was left out of scope: the relationship between UseHalfFloatPrecision and PositionThreshold is still undocumented. Setting a threshold finer than the encoding can represent is not meaningful. That is much less likely to matter at ~1mm resolution, but it is worth a follow-up doc note.
Testing & QA (How your changes can be verified during release Playtest)
Reproduced with the physics ball stress test in the NGO Examples project: 10 balls spawned, allowed to come to rest, with the client observed and recorded. The jitter appears on resting objects only once they are some distance from where they spawned, which is why it can look intermittent.
Measured on 10 settling objects with half float enabled throughout, showing per-update position change and direction reversals on the client:
After the change, half float precision is indistinguishable from float precision in this scene. The authority was confirmed stationary throughout, so the movement was being introduced between the authority and the client rather than reproduced from it. Objects in motion also improved, with peak error dropping from 12.5mm to 0.587mm.
Functional Testing
Manual testing :
Automated tests:
The new tests were verified in both directions. Without the fix all four cases fail on the intended assertion, reporting 7.9mm to 10.1mm of backwards movement. With the fix all four pass.
Does the change require QA team to:
These tests do not use the time travel harness, since the behaviour only appears over multiple real state update and interpolation cycles. Runtime is roughly 3.5s per case.
Up-port
#4129 is the up-port.
Required. NetworkDeltaPosition.cs is identical on develop-3.x.x, and the test folder and base classes are the same, so both commits should apply cleanly.
Backports
Not needed. NetworkDeltaPosition does not exist on develop (v1.x) and half float position synchronization is not present there.