diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 0b7a10e485..c3c0f6448f 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -18,6 +18,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Fixed +- Fixed an issue where `TimeSyncMessage` was sent using reliable delivery, which could cause delayed packets under packet loss to reset client clocks backwards and stall `NetworkTransform`s. (#4249) - Issue where every `NetworkObject` that started before a session logged a "Did not register because there is no session in progress!" warning when `NetworkManager.LogLevel` was `Developer`. Only `GhostObject` instances log it now. (#4245) - Fixed a NullReferenceException that would be thrown if a MonoBehaviour derived from NetworkManager defines it's own Awake or OnEnable. (#4244) - Issue where the unified bootstrap created a second world that ran a duplicate of every default system next to the default world. (#4243) diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/MessageDelivery.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/MessageDelivery.cs index cc54d9d102..a243ad8974 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/MessageDelivery.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/MessageDelivery.cs @@ -15,7 +15,7 @@ internal static class MessageDelivery /// - Skip the time sync messages since it has always used unreliable network delivery. /// private static readonly HashSet k_SkipMessageTypes = new HashSet(){ - NetworkMessageTypes.NamedMessage, NetworkMessageTypes.Unnamed}; + NetworkMessageTypes.NamedMessage, NetworkMessageTypes.Unnamed, NetworkMessageTypes.TimeSync}; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] private static void OnApplicationStart() @@ -49,6 +49,7 @@ private static void UpdateMessageTypes() } s_MessageToDelivery.Add(messageType, NetworkDelivery.ReliableFragmentedSequenced); } + s_MessageToDelivery.Add(NetworkMessageTypes.TimeSync, NetworkDelivery.UnreliableSequenced); s_MessageToMessageType = ILPPMessageProvider.GetMessageTypesMap(); // Fast path look-ups @@ -81,19 +82,25 @@ private static void UpdateMessageTypes() internal static NetworkDelivery GetDelivery(Type type) { // Return the default if not registered or null - if (type == null || k_SkipMessageTypes.Contains(s_MessageToMessageType[type])) + if (type == null || !s_MessageToMessageType.TryGetValue(type, out var messageType)) { return NetworkDelivery.ReliableFragmentedSequenced; } - return GetDelivery(s_MessageToMessageType[type]); + return GetDelivery(messageType); } internal static NetworkDelivery GetDelivery(NetworkMessageTypes messageType) { + if (s_MessageToDelivery.TryGetValue(messageType, out var delivery)) + { + return delivery; + } + if (k_SkipMessageTypes.Contains(messageType)) { throw new Exception($"{messageType} is not registered in the message type to network delivery map!"); } - return s_MessageToDelivery[messageType]; + + return NetworkDelivery.ReliableFragmentedSequenced; } } diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/TimeSyncMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/TimeSyncMessage.cs index bb820ece16..b1e53f0aef 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/TimeSyncMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/TimeSyncMessage.cs @@ -28,6 +28,11 @@ public void Handle(ref NetworkContext context) { var networkManager = (NetworkManager)context.SystemOwner; var time = new NetworkTime(networkManager.NetworkTickSystem.TickRate, Tick); + // Ignore stale time sync messages that arrive out of order + if (networkManager.NetworkTimeSystem.LastSyncedServerTimeSec > 0 && time.Time <= networkManager.NetworkTimeSystem.LastSyncedServerTimeSec) + { + return; + } networkManager.NetworkTimeSystem.SyncCount++; networkManager.NetworkTimeSystem.Sync(time.Time, networkManager.NetworkConfig.NetworkTransport.GetCurrentRtt(context.SenderId) / 1000d); } diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageRegistrationTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageRegistrationTests.cs index 025b3d54e4..677eaf23bf 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageRegistrationTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageRegistrationTests.cs @@ -191,5 +191,18 @@ public void WhenCreatingMessageSystem_BoundTypeMessageHandlersAreRegistered() Assert.AreEqual(handlerFour, systemThree.MessageHandlers[systemThree.GetMessageType(typeof(TestMessageFour))]); } } + + [Test] + public void WhenCheckingTimeSyncMessageDelivery_UsesUnreliableSequencedDelivery() + { + var delivery = MessageDelivery.GetDelivery(typeof(TimeSyncMessage)); + Assert.AreEqual(NetworkDelivery.UnreliableSequenced, delivery); + } + + [Test] + public void WhenCheckingTimeSyncMessageDeliveryType_UsesUnreliableSequencedDelivery() + { + Assert.AreEqual(NetworkDelivery.UnreliableSequenced, MessageDeliveryType.DefaultDelivery); + } } }