Skip to content

fix: rounding issue with tick calculation #1614

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
1 change: 1 addition & 0 deletions com.unity.netcode.gameobjects/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
- Fixed error when serializing ConnectionApprovalMessage with scene management disabled when one or more objects is hidden via the CheckObjectVisibility delegate (#1509)
- Fixed The NetworkConfig's checksum hash includes the NetworkTick so that clients with a different tickrate than the server are identified and not allowed to connect. (#1513)
- Fixed OwnedObjects not being properly modified when using ChangeOwnership. (#1572)
- Fixed network tick value sometimes being duplicated or skipped. (#1614)

### Changed

Expand Down
5 changes: 5 additions & 0 deletions com.unity.netcode.gameobjects/Runtime/Timing/NetworkTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ private void UpdateCache()
{
double d = m_TimeSec / m_TickInterval;
m_CachedTick = (int)d;
// This check is needed due to double division imprecision of large numbers
if ((d - m_CachedTick) >= 0.999999999999)
{
m_CachedTick++;
}
m_CachedTickOffset = ((d - Math.Truncate(d)) * m_TickInterval);

// This handles negative time, decreases tick by 1 and makes offset positive.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,39 @@ private void NetworkTimeAdvanceTestInternal(IEnumerable<float> steps, uint tickR
Assert.IsTrue(Approximately(startTime.Time, (startTime2 - dif).Time, maxAcceptableTotalOffset));
}

[Test]
public void NetworkTickAdvanceTest()
{
var shortSteps = Enumerable.Repeat(1 / 30f, 1000);
NetworkTickAdvanceTestInternal(shortSteps, 30, 0.0f, 0.0f);
}

private NetworkTickSystem m_TickSystem;
private NetworkTimeSystem m_TimeSystem;
private int m_PreviousTick;

private void NetworkTickAdvanceTestInternal(IEnumerable<float> steps, uint tickRate, float start, float start2 = 0f)
{
m_PreviousTick = 0;
m_TickSystem = new NetworkTickSystem(tickRate, start, start2);
m_TimeSystem = NetworkTimeSystem.ServerTimeSystem();

m_TickSystem.Tick += TickUpdate;
foreach (var step in steps)
{
m_TimeSystem.Advance(step);
m_TickSystem.UpdateTick(m_TimeSystem.LocalTime, m_TimeSystem.ServerTime);
}
}

private void TickUpdate()
{
// Make sure our tick is precisely 1 + m_PreviousTick
Assert.IsTrue(m_TickSystem.LocalTime.Tick == m_PreviousTick + 1);
// Assign the m_PreviousTick value for next tick check
m_PreviousTick = m_TickSystem.LocalTime.Tick;
}

private static bool Approximately(double a, double b, double epsilon = 0.000001d)
{
var dif = Math.Abs(a - b);
Expand Down