diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 8cb9af6bd9..85ad8ff0f6 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -13,6 +13,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Fixed +- Fixed an exception being thrown when unregistering a custom message handler from within the registered callback. (#3417) ### Changed diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/CustomMessageManager.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/CustomMessageManager.cs index 815e38d35c..15e30205f8 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/CustomMessageManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/CustomMessageManager.cs @@ -180,14 +180,18 @@ internal void InvokeNamedMessage(ulong hash, ulong sender, FastBufferReader read // We dont know what size to use. Try every (more collision prone) if (m_NamedMessageHandlers32.TryGetValue(hash, out HandleNamedMessageDelegate messageHandler32)) { + // handler can remove itself, cache the name for metrics + var messageName = m_MessageHandlerNameLookup32[hash]; messageHandler32(sender, reader); - m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, m_MessageHandlerNameLookup32[hash], bytesCount); + m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, messageName, bytesCount); } if (m_NamedMessageHandlers64.TryGetValue(hash, out HandleNamedMessageDelegate messageHandler64)) { + // handler can remove itself, cache the name for metrics + var messageName = m_MessageHandlerNameLookup64[hash]; messageHandler64(sender, reader); - m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, m_MessageHandlerNameLookup64[hash], bytesCount); + m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, messageName, bytesCount); } } else @@ -198,15 +202,19 @@ internal void InvokeNamedMessage(ulong hash, ulong sender, FastBufferReader read case HashSize.VarIntFourBytes: if (m_NamedMessageHandlers32.TryGetValue(hash, out HandleNamedMessageDelegate messageHandler32)) { + // handler can remove itself, cache the name for metrics + var messageName = m_MessageHandlerNameLookup32[hash]; messageHandler32(sender, reader); - m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, m_MessageHandlerNameLookup32[hash], bytesCount); + m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, messageName, bytesCount); } break; case HashSize.VarIntEightBytes: if (m_NamedMessageHandlers64.TryGetValue(hash, out HandleNamedMessageDelegate messageHandler64)) { + // handler can remove itself, cache the name for metrics + var messageName = m_MessageHandlerNameLookup64[hash]; messageHandler64(sender, reader); - m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, m_MessageHandlerNameLookup64[hash], bytesCount); + m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, messageName, bytesCount); } break; } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Messaging/NamedMessageTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Messaging/NamedMessageTests.cs index 4c2d0d8cfd..28ab33223e 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Messaging/NamedMessageTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Messaging/NamedMessageTests.cs @@ -279,5 +279,38 @@ public unsafe void ErrorMessageIsPrintedWhenAttemptingToSendNamedMessageWithTooB Assert.IsTrue(message.Contains($"Given message size ({msgSize} bytes) is greater than the maximum"), $"Unexpected exception: {message}"); } } + + [Test] + public void NamedMessageHandlerIsUnregisteredWithoutException() + { + var messageName = Guid.NewGuid().ToString(); + const int numMessagesToSend = 3; + const int expectedMessageHandlerCallCount = 1; + + var messageHandlerCalled = 0; + m_ServerNetworkManager.CustomMessagingManager.RegisterNamedMessageHandler( + messageName, + (_, _) => + { + messageHandlerCalled++; + m_ServerNetworkManager.CustomMessagingManager.UnregisterNamedMessageHandler(messageName); + }); + + var messageContent = new ForceNetworkSerializeByMemcpy(Guid.NewGuid()); + var writer = new FastBufferWriter(1300, Allocator.Temp); + using (writer) + { + writer.WriteValueSafe(messageContent); + for (var i = 0; i < numMessagesToSend; i++) + { + m_ServerNetworkManager.CustomMessagingManager.SendNamedMessage( + messageName, + m_ServerNetworkManager.LocalClientId, + writer); + } + } + + Assert.AreEqual(expectedMessageHandlerCallCount, messageHandlerCalled); + } } }