-
Notifications
You must be signed in to change notification settings - Fork 461
feat: host tells client which IDs it uses for INetworkMessages #2103
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
Changes from 6 commits
e5ecbe4
89648b6
1dcd9c1
0be53b1
d5a359d
4496a31
c7c5f3d
e2c91ed
418cc88
fc0cd45
e8a3905
98c8035
51f0240
53992a7
a161f89
f1493eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| using System; | ||
|
|
||
| namespace Unity.Netcode | ||
| { | ||
| /// <summary> | ||
| /// This particular struct is a little weird because it doesn't actually contain the data | ||
| /// it's serializing. Instead, it contains references to the data it needs to do the | ||
| /// serialization. This is due to the generally amorphous nature of network variable | ||
| /// deltas, since they're all driven by custom virtual method overloads. | ||
| /// </summary> | ||
| internal struct OrderingMessage : INetworkMessage | ||
|
jeffreyrainy marked this conversation as resolved.
|
||
| { | ||
| public int Order; | ||
| public int Hash; | ||
|
|
||
| public void Serialize(FastBufferWriter writer) | ||
| { | ||
| if (!writer.TryBeginWrite(FastBufferWriter.GetWriteSize(Order) + FastBufferWriter.GetWriteSize(Hash))) | ||
| { | ||
| throw new OverflowException($"Not enough space in the buffer to write {nameof(OrderingMessage)}"); | ||
| } | ||
|
|
||
| writer.WriteValue(Order); | ||
| writer.WriteValue(Hash); | ||
| } | ||
|
|
||
| public bool Deserialize(FastBufferReader reader, ref NetworkContext context) | ||
| { | ||
| if (!reader.TryBeginRead(FastBufferWriter.GetWriteSize(Order) + FastBufferWriter.GetWriteSize(Hash))) | ||
| { | ||
| throw new OverflowException($"Not enough data in the buffer to read {nameof(OrderingMessage)}"); | ||
| } | ||
|
|
||
| reader.ReadValue(out Order); | ||
| reader.ReadValue(out Hash); | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| public void Handle(ref NetworkContext context) | ||
| { | ||
| ((NetworkManager)context.SystemOwner).MessagingSystem.ReorderMessage(Order, Hash); | ||
| } | ||
| } | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| using System; | ||
| using System.Collections; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Runtime.CompilerServices; | ||
| using Unity.Collections; | ||
| using Unity.Collections.LowLevel.Unsafe; | ||
|
|
@@ -59,6 +60,8 @@ public SendQueueItem(NetworkDelivery delivery, int writerSize, Allocator writerA | |
|
|
||
| internal Type[] MessageTypes => m_ReverseTypeMap; | ||
| internal MessageHandler[] MessageHandlers => m_MessageHandlers; | ||
|
JesseOlmer marked this conversation as resolved.
|
||
| internal Type[] ReverseTypeMap => m_ReverseTypeMap; | ||
|
jeffreyrainy marked this conversation as resolved.
Outdated
|
||
|
|
||
| internal uint MessageHandlerCount => m_HighMessageType; | ||
|
|
||
| internal uint GetMessageType(Type t) | ||
|
|
@@ -75,6 +78,35 @@ internal struct MessageWithHandler | |
| public MessageHandler Handler; | ||
| } | ||
|
|
||
| private List<MessageWithHandler> PrioritizeMessageOrder(List<MessageWithHandler> allowedTypes) | ||
| { | ||
| var prioritizedTypes = new List<MessageWithHandler>(); | ||
|
|
||
| // first pass puts the priority message in the first indices | ||
| // Those are the messages that must be delivered in order to allow re-ordering the others later | ||
| foreach (var t in allowedTypes) | ||
| { | ||
| if (t.MessageType.FullName == "Unity.Netcode.ConnectionRequestMessage" || | ||
| t.MessageType.FullName == "Unity.Netcode.ConnectionApprovedMessage" || | ||
| t.MessageType.FullName == "Unity.Netcode.OrderingMessage") | ||
| { | ||
| prioritizedTypes.Add(t); | ||
| } | ||
| } | ||
|
|
||
| foreach (var t in allowedTypes) | ||
| { | ||
| if (t.MessageType.FullName != "Unity.Netcode.ConnectionRequestMessage" && | ||
| t.MessageType.FullName != "Unity.Netcode.ConnectionApprovedMessage" && | ||
| t.MessageType.FullName != "Unity.Netcode.OrderingMessage") | ||
| { | ||
| prioritizedTypes.Add(t); | ||
| } | ||
| } | ||
|
|
||
| return prioritizedTypes; | ||
| } | ||
|
|
||
| public MessagingSystem(IMessageSender messageSender, object owner, IMessageProvider provider = null) | ||
| { | ||
| try | ||
|
|
@@ -89,6 +121,7 @@ public MessagingSystem(IMessageSender messageSender, object owner, IMessageProvi | |
| var allowedTypes = provider.GetMessages(); | ||
|
|
||
| allowedTypes.Sort((a, b) => string.CompareOrdinal(a.MessageType.FullName, b.MessageType.FullName)); | ||
| allowedTypes = PrioritizeMessageOrder(allowedTypes); | ||
| foreach (var type in allowedTypes) | ||
| { | ||
| RegisterMessageType(type); | ||
|
|
@@ -226,6 +259,66 @@ private bool CanReceive(ulong clientId, Type messageType, FastBufferReader messa | |
| return true; | ||
| } | ||
|
|
||
| internal void ReorderMessage(int desiredOrder, int targetHash) | ||
| { | ||
| if (desiredOrder < 0) | ||
| { | ||
| // invalid message re-ordering request. Ignore. | ||
| return; | ||
|
jeffreyrainy marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| if (desiredOrder < m_ReverseTypeMap.Length && | ||
| m_ReverseTypeMap[desiredOrder].FullName.GetHashCode() == targetHash) | ||
|
jeffreyrainy marked this conversation as resolved.
Outdated
|
||
| { | ||
| // matching positions and hashes. All good. | ||
| return; | ||
| } | ||
|
|
||
| // Since the message at `desiredOrder` is not the expected one, | ||
| // insert an empty placeholder and move the messages down | ||
| var typesAsList = m_ReverseTypeMap.ToList(); | ||
| typesAsList.Insert(desiredOrder, null); | ||
| m_ReverseTypeMap = typesAsList.ToArray(); | ||
| var handlersAsList = m_MessageHandlers.ToList(); | ||
| handlersAsList.Insert(desiredOrder, null); | ||
| m_MessageHandlers = handlersAsList.ToArray(); | ||
|
jeffreyrainy marked this conversation as resolved.
Outdated
|
||
|
|
||
| // we added a dummy message, bump the end up | ||
| m_HighMessageType++; | ||
|
|
||
| int position = desiredOrder; | ||
|
jeffreyrainy marked this conversation as resolved.
|
||
| bool found = false; | ||
| while (position < m_ReverseTypeMap.Length) | ||
| { | ||
| if (m_ReverseTypeMap[position] != null && | ||
| m_ReverseTypeMap[position].FullName.GetHashCode() == targetHash) | ||
| { | ||
| found = true; | ||
| break; | ||
| } | ||
|
|
||
| position++; | ||
| } | ||
|
|
||
| if (found) | ||
|
jeffreyrainy marked this conversation as resolved.
|
||
| { | ||
| // Copy the handler and type to the right index | ||
| m_ReverseTypeMap[desiredOrder] = m_ReverseTypeMap[position]; | ||
| m_MessageHandlers[desiredOrder] = m_MessageHandlers[position]; | ||
|
|
||
| // Shift back the remaining messages | ||
| typesAsList = m_ReverseTypeMap.ToList(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are you doing array->list->array conversions again? Shouldn't you either always have them be lists as in a comment I made above, or else convert array->list, do ALL operations in this method on the lists, then just do 1 conversion back to array?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, it was either:
I picked 3, mainly so intent was clear. If you insist, I can do 1. or 2. But I really feel, although the code looks to do repeating operations, it will be easier to maintain.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can do #3 with 2 fewer Array allocations and 2 fewer List allocations per message. I'll add some suggested changes.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check out Bonus is it gets rid of Linq usages (which you can do even if you don't take the rest of the change) |
||
| typesAsList.RemoveAt(position); | ||
| m_ReverseTypeMap = typesAsList.ToArray(); | ||
| handlersAsList = m_MessageHandlers.ToList(); | ||
| handlersAsList.RemoveAt(position); | ||
| m_MessageHandlers = handlersAsList.ToArray(); | ||
|
|
||
| // we removed a copy after moving a message, reduce the high message index | ||
| m_HighMessageType--; | ||
| } | ||
| } | ||
|
|
||
| public void HandleMessage(in MessageHeader header, FastBufferReader reader, ulong senderId, float timestamp, int serializedHeaderSize) | ||
| { | ||
| if (header.MessageType >= m_HighMessageType) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.