Skip to content

feat: Configurable Intervals - #4114

Open
MrGadget1024 wants to merge 8 commits into
masterfrom
ConfigurableIntervals
Open

feat: Configurable Intervals#4114
MrGadget1024 wants to merge 8 commits into
masterfrom
ConfigurableIntervals

Conversation

@MrGadget1024

Copy link
Copy Markdown
Collaborator
image

@MrGadget1024
MrGadget1024 requested a review from miwarnec June 20, 2026 07:45
@MrGadget1024 MrGadget1024 added enhancement New feature or request Awaiting Review labels Jun 20, 2026
@codecov

codecov Bot commented Jun 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.08108% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 42.20%. Comparing base (effb412) to head (549bc85).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
Assets/Mirror/Core/NetworkManager.cs 57.14% 6 Missing ⚠️
Assets/Mirror/Core/NetworkServer.cs 92.85% 1 Missing ⚠️

❌ Your patch check has failed because the patch coverage (81.08%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4114      +/-   ##
==========================================
+ Coverage   42.18%   42.20%   +0.01%     
==========================================
  Files         157      157              
  Lines       15132    15148      +16     
==========================================
+ Hits         6384     6393       +9     
- Misses       8748     8755       +7     
Flag Coverage Δ
unittests 42.20% <81.08%> (+0.01%) ⬆️
unity-6000.5.6f1 ?
unity-6000.5.7f1 42.20% <81.08%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
Assets/Mirror/Core/NetworkClient.cs 93.81% <100.00%> (+0.01%) ⬆️
Assets/Mirror/Core/NetworkConnectionToClient.cs 100.00% <100.00%> (ø)
Assets/Mirror/Core/NetworkTime.cs 88.46% <100.00%> (ø)
Assets/Mirror/Core/NetworkServer.cs 68.56% <92.85%> (+0.09%) ⬆️
Assets/Mirror/Core/NetworkManager.cs 42.17% <57.14%> (+0.30%) ⬆️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@miwarnec

Copy link
Copy Markdown
Collaborator

need more time on this, gonna test in a production game soon to make sure it doesnt break anything

@miwarnec

Copy link
Copy Markdown
Collaborator

@copilot solve merge conflicts

Copilot AI commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

@copilot solve merge conflicts

Merge conflicts resolved. Both NetworkClient.cs and NetworkServer.cs had conflicts around TimeSnapshotMessage sends — master added a scaledTime field while our branch added the tickInterval gating. The resolution keeps both: the interval check from this PR and the { scaledTime = NetworkTime.localScaledTime } from master.

@miwarnec

miwarnec commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

@copilot review the changes. any timing related changes have a high chance of brekaing networktime, snapshotinterpolation, and any variant of networktransform.* - check all, give a risk assessment

Copilot AI commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

@copilot review the changes. any timing related changes have a high chance of brekaing networktime, snapshotinterpolation, and any variant of networktransform.* - check all, give a risk assessment

Here is the full risk assessment across the timing-sensitive areas:


Changes Summary

The PR introduces three independently-configurable rates on NetworkManager:

  • Send RateNetworkServer.sendRate / NetworkClient.sendRate (snapshot/world-state sends)
  • Tick RateNetworkServer.tickRate (TimeSnapshotMessage gating)
  • Ping RateNetworkTime.PingInterval (RTT/prediction ping)

sendRate was previously an alias for tickRate; now they are distinct fields with separate AccurateInterval trackers (lastSendTime vs lastTickTime).


Risk: NetworkTime ⚠️ MEDIUM

What changed: NetworkTime.PingInterval is now set from pingRate in ApplyConfiguration() (default 10 Hz instead of the old value). The UpdateClient() ping path and UpdatePing() (server side) both got a PingInterval > 0 guard before firing.

Risk: If pingRate = 0, pings are permanently disabled. RTT estimate (rtt), offset, and prediction (predictedTime) all stop updating. SnapshotInterpolation's driftEma/deliveryTimeEma are sized with NetworkServer.sendRate at connection construction — if sendRate changes after connection, those EMAs are sized wrong (pre-existing issue, not introduced here).

Zero-rate edge case: PingInterval = 0 is accepted silently; users could set pingRate = 0 and never get RTT measurements, breaking lag compensation and prediction without any warning.


Risk: SnapshotInterpolation ⚠️ MEDIUM

What changed: TimeSnapshotMessage is now gated on tickIntervalElapsed (separate from sendIntervalElapsed). BroadcastToConnection() (component data) is still gated by sendIntervalElapsed. The two intervals are both set to sendRate by OnValidate() (if (tickRate > 0) tickRate = sendRate), so in practice they stay in sync as long as NetworkManager is present.

Risk 1 — tick ≠ send desync: The tickIntervalElapsed path uses lastTickTime, while BroadcastToConnection uses lastSendTime. Even though both rates are forced equal by OnValidate, they start from different lastXTime = 0 baselines and can drift by up to one frame. TimeSnapshotMessage could arrive one frame ahead of or behind the associated component data. This is subtle but could cause occasional snapshot interpolation glitches (one snapshot without a paired time update).

Risk 2 — OnValidate coupling: if (tickRate > 0) tickRate = sendRate means the tickRate field in the Inspector is not independently configurable — setting it to anything other than 0 silently resets it to sendRate. The UI label "Tick Rate" implies independent control, but it behaves as a binary enable/disable toggle. This is confusing but not a correctness bug.

Risk 3 — NetworkClient.tickRate not set by ApplyConfiguration: NetworkClient.tickRate is declared and used to gate TimeSnapshotMessage sends from client to server, but ApplyConfiguration() only sets NetworkServer.tickRate. NetworkClient.tickRate always stays at its default 30. If sendRate is changed (e.g., to 60), the client's time snapshots still send at 30 Hz, mismatching the server's expectation.


Risk: NetworkTransform (Reliable / Unreliable / Hybrid) 🟢 LOW

All three variants read NetworkServer.sendInterval (derived from sendRate) for their send-interval gating, timeStampAdjustment, offset, buffer-reset checks, and snapshot correction. Since sendRate is applied consistently to both client and server via ApplyConfiguration(), these components are unaffected. The old sendRate => tickRate alias is replaced by a direct sendRate field but the value path is identical.


Risk: PredictedRigidbody 🟢 LOW

Uses NetworkServer.sendInterval for state-send gating — same as NetworkTransform, no change in behavior.


Summary

Area Risk Root Cause
NetworkTime / RTT ⚠️ Medium pingRate=0 silently disables all RTT with no warning
SnapshotInterpolation ⚠️ Medium lastTickTime vs lastSendTime can drift; NetworkClient.tickRate never set from ApplyConfiguration
NetworkTransform.* 🟢 Low Reads sendRate/sendInterval only, unaffected
PredictedRigidbody 🟢 Low Same as above

The two items I'd fix before merging:

  1. NetworkClient.tickRate should be set in ApplyConfiguration() (same as NetworkServer.tickRate), otherwise client→server time snapshots always send at 30 Hz regardless of the configured send rate.
  2. Add a validator warning (or just clamp pingRate >= 1) so pingRate = 0 can't silently break RTT/prediction.

@miwarnec miwarnec added wait_for_dogfooding Risky diff, pending dogfooding in production game. and removed enhancement New feature or request Awaiting Review labels Aug 4, 2026
@miwarnec

miwarnec commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

@MrGadget1024 significant risk, might be good idea but need to wait longer for me to test this in a production game

@MrGadget1024

MrGadget1024 commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

@miwarnec

Risk: If pingRate = 0, pings are permanently disabled

PingRate has a Range[0.01f, 10f] on it. We only allow, and check for, zero for unit tests to work. User would have to work at forcing it to zero intentionally.

Risk 2 — OnValidate coupling: if (tickRate > 0) tickRate = sendRate means the tickRate field in the Inspector is not independently configurable — setting it to anything other than 0 silently resets it to sendRate.

By design, because only games with NetworkTransform / Predicted components need TimeSnapshotMessage. Being able to disable that for games that don't use those is a bandwidth / CPU saving feature. Otherwise TickRate and SendRate have to match for them to work properly. This will be documented after the PR is merged.

Risk 3 — NetworkClient.tickRate not set by ApplyConfiguration

Now it is.

Risk 1 — tick ≠ send desync: The tickIntervalElapsed path uses lastTickTime, while BroadcastToConnection uses lastSendTime.

Ask copilot to suggest a fix...my budget is spent for the month.

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

Labels

wait_for_dogfooding Risky diff, pending dogfooding in production game.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants