feat: message versioning [MTT-3048] (#2290)
Adds support for SDKs at different versions with different message formats to be able to talk to each other - the side with the higher version being responsible for both converting up when receiving and converting down when sending.
This commit is contained in:
Родитель
f1870cd961
Коммит
e242f1b9aa
|
@ -9,7 +9,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
|
|||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Added support for different versions of the SDK to talk to each other in circumstances where changes permit it. Starting with this version and into future versions, patch versions should be compatible as long as the minor version is the same. (#2290)
|
||||
- Added `NetworkObject` auto-add helper and Multiplayer Tools install reminder settings to Project Settings. (#2285)
|
||||
- Added `public string DisconnectReason` getter to `NetworkManager` and `string Reason` to `ConnectionApprovalResponse`. Allows connection approval to communicate back a reason. Also added `public void DisconnectClient(ulong clientId, string reason)` allowing setting a disconnection reason, when explicitly disconnecting a client.
|
||||
|
||||
|
|
|
@ -102,15 +102,19 @@ namespace Unity.Netcode.Editor.CodeGen
|
|||
private PostProcessorAssemblyResolver m_AssemblyResolver;
|
||||
|
||||
private MethodReference m_MessagingSystem_ReceiveMessage_MethodRef;
|
||||
private MethodReference m_MessagingSystem_CreateMessageAndGetVersion_MethodRef;
|
||||
private TypeReference m_MessagingSystem_MessageWithHandler_TypeRef;
|
||||
private MethodReference m_MessagingSystem_MessageHandler_Constructor_TypeRef;
|
||||
private MethodReference m_MessagingSystem_VersionGetter_Constructor_TypeRef;
|
||||
private FieldReference m_ILPPMessageProvider___network_message_types_FieldRef;
|
||||
private FieldReference m_MessagingSystem_MessageWithHandler_MessageType_FieldRef;
|
||||
private FieldReference m_MessagingSystem_MessageWithHandler_Handler_FieldRef;
|
||||
private FieldReference m_MessagingSystem_MessageWithHandler_GetVersion_FieldRef;
|
||||
private MethodReference m_Type_GetTypeFromHandle_MethodRef;
|
||||
private MethodReference m_List_Add_MethodRef;
|
||||
|
||||
private const string k_ReceiveMessageName = nameof(MessagingSystem.ReceiveMessage);
|
||||
private const string k_CreateMessageAndGetVersionName = nameof(MessagingSystem.CreateMessageAndGetVersion);
|
||||
|
||||
private bool ImportReferences(ModuleDefinition moduleDefinition)
|
||||
{
|
||||
|
@ -126,6 +130,7 @@ namespace Unity.Netcode.Editor.CodeGen
|
|||
TypeDefinition listTypeDef = moduleDefinition.ImportReference(typeof(List<>)).Resolve();
|
||||
|
||||
TypeDefinition messageHandlerTypeDef = null;
|
||||
TypeDefinition versionGetterTypeDef = null;
|
||||
TypeDefinition messageWithHandlerTypeDef = null;
|
||||
TypeDefinition ilppMessageProviderTypeDef = null;
|
||||
TypeDefinition messagingSystemTypeDef = null;
|
||||
|
@ -137,6 +142,12 @@ namespace Unity.Netcode.Editor.CodeGen
|
|||
continue;
|
||||
}
|
||||
|
||||
if (versionGetterTypeDef == null && netcodeTypeDef.Name == nameof(MessagingSystem.VersionGetter))
|
||||
{
|
||||
versionGetterTypeDef = netcodeTypeDef;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (messageWithHandlerTypeDef == null && netcodeTypeDef.Name == nameof(MessagingSystem.MessageWithHandler))
|
||||
{
|
||||
messageWithHandlerTypeDef = netcodeTypeDef;
|
||||
|
@ -157,6 +168,7 @@ namespace Unity.Netcode.Editor.CodeGen
|
|||
}
|
||||
|
||||
m_MessagingSystem_MessageHandler_Constructor_TypeRef = moduleDefinition.ImportReference(messageHandlerTypeDef.GetConstructors().First());
|
||||
m_MessagingSystem_VersionGetter_Constructor_TypeRef = moduleDefinition.ImportReference(versionGetterTypeDef.GetConstructors().First());
|
||||
|
||||
m_MessagingSystem_MessageWithHandler_TypeRef = moduleDefinition.ImportReference(messageWithHandlerTypeDef);
|
||||
foreach (var fieldDef in messageWithHandlerTypeDef.Fields)
|
||||
|
@ -169,6 +181,9 @@ namespace Unity.Netcode.Editor.CodeGen
|
|||
case nameof(MessagingSystem.MessageWithHandler.Handler):
|
||||
m_MessagingSystem_MessageWithHandler_Handler_FieldRef = moduleDefinition.ImportReference(fieldDef);
|
||||
break;
|
||||
case nameof(MessagingSystem.MessageWithHandler.GetVersion):
|
||||
m_MessagingSystem_MessageWithHandler_GetVersion_FieldRef = moduleDefinition.ImportReference(fieldDef);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,6 +226,9 @@ namespace Unity.Netcode.Editor.CodeGen
|
|||
case k_ReceiveMessageName:
|
||||
m_MessagingSystem_ReceiveMessage_MethodRef = moduleDefinition.ImportReference(methodDef);
|
||||
break;
|
||||
case k_CreateMessageAndGetVersionName:
|
||||
m_MessagingSystem_CreateMessageAndGetVersion_MethodRef = moduleDefinition.ImportReference(methodDef);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,7 +254,7 @@ namespace Unity.Netcode.Editor.CodeGen
|
|||
return staticCtorMethodDef;
|
||||
}
|
||||
|
||||
private void CreateInstructionsToRegisterType(ILProcessor processor, List<Instruction> instructions, TypeReference type, MethodReference receiveMethod)
|
||||
private void CreateInstructionsToRegisterType(ILProcessor processor, List<Instruction> instructions, TypeReference type, MethodReference receiveMethod, MethodReference versionMethod)
|
||||
{
|
||||
// MessagingSystem.__network_message_types.Add(new MessagingSystem.MessageWithHandler{MessageType=typeof(type), Handler=type.Receive});
|
||||
processor.Body.Variables.Add(new VariableDefinition(m_MessagingSystem_MessageWithHandler_TypeRef));
|
||||
|
@ -252,7 +270,7 @@ namespace Unity.Netcode.Editor.CodeGen
|
|||
instructions.Add(processor.Create(OpCodes.Call, m_Type_GetTypeFromHandle_MethodRef));
|
||||
instructions.Add(processor.Create(OpCodes.Stfld, m_MessagingSystem_MessageWithHandler_MessageType_FieldRef));
|
||||
|
||||
// tmp.Handler = type.Receive
|
||||
// tmp.Handler = MessageHandler.ReceveMessage<type>
|
||||
instructions.Add(processor.Create(OpCodes.Ldloca, messageWithHandlerLocIdx));
|
||||
instructions.Add(processor.Create(OpCodes.Ldnull));
|
||||
|
||||
|
@ -260,6 +278,15 @@ namespace Unity.Netcode.Editor.CodeGen
|
|||
instructions.Add(processor.Create(OpCodes.Newobj, m_MessagingSystem_MessageHandler_Constructor_TypeRef));
|
||||
instructions.Add(processor.Create(OpCodes.Stfld, m_MessagingSystem_MessageWithHandler_Handler_FieldRef));
|
||||
|
||||
|
||||
// tmp.GetVersion = MessageHandler.CreateMessageAndGetVersion<type>
|
||||
instructions.Add(processor.Create(OpCodes.Ldloca, messageWithHandlerLocIdx));
|
||||
instructions.Add(processor.Create(OpCodes.Ldnull));
|
||||
|
||||
instructions.Add(processor.Create(OpCodes.Ldftn, versionMethod));
|
||||
instructions.Add(processor.Create(OpCodes.Newobj, m_MessagingSystem_VersionGetter_Constructor_TypeRef));
|
||||
instructions.Add(processor.Create(OpCodes.Stfld, m_MessagingSystem_MessageWithHandler_GetVersion_FieldRef));
|
||||
|
||||
// ILPPMessageProvider.__network_message_types.Add(tmp);
|
||||
instructions.Add(processor.Create(OpCodes.Ldloc, messageWithHandlerLocIdx));
|
||||
instructions.Add(processor.Create(OpCodes.Callvirt, m_List_Add_MethodRef));
|
||||
|
@ -285,7 +312,9 @@ namespace Unity.Netcode.Editor.CodeGen
|
|||
{
|
||||
var receiveMethod = new GenericInstanceMethod(m_MessagingSystem_ReceiveMessage_MethodRef);
|
||||
receiveMethod.GenericArguments.Add(type);
|
||||
CreateInstructionsToRegisterType(processor, instructions, type, receiveMethod);
|
||||
var versionMethod = new GenericInstanceMethod(m_MessagingSystem_CreateMessageAndGetVersion_MethodRef);
|
||||
versionMethod.GenericArguments.Add(type);
|
||||
CreateInstructionsToRegisterType(processor, instructions, type, receiveMethod, versionMethod);
|
||||
}
|
||||
|
||||
instructions.ForEach(instruction => processor.Body.Instructions.Insert(processor.Body.Instructions.Count - 1, instruction));
|
||||
|
|
|
@ -730,7 +730,7 @@ namespace Unity.Netcode
|
|||
var tmpWriter = new FastBufferWriter(MessagingSystem.NON_FRAGMENTED_MESSAGE_MAX_SIZE, Allocator.Temp, MessagingSystem.FRAGMENTED_MESSAGE_MAX_SIZE);
|
||||
using (tmpWriter)
|
||||
{
|
||||
message.Serialize(tmpWriter);
|
||||
message.Serialize(tmpWriter, message.Version);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -1440,7 +1440,7 @@ namespace Unity.Netcode
|
|||
}
|
||||
}
|
||||
|
||||
if (IsClient && IsConnectedClient)
|
||||
if (IsClient && IsListening)
|
||||
{
|
||||
// Client only, send disconnect to server
|
||||
NetworkConfig.NetworkTransport.DisconnectLocalClient();
|
||||
|
@ -1598,6 +1598,7 @@ namespace Unity.Netcode
|
|||
} while (IsListening && networkEvent != NetworkEvent.Nothing);
|
||||
|
||||
MessagingSystem.ProcessIncomingMessageQueue();
|
||||
MessagingSystem.CleanupDisconnectedClients();
|
||||
|
||||
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
s_TransportPoll.End();
|
||||
|
@ -1679,7 +1680,23 @@ namespace Unity.Netcode
|
|||
ShouldSendConnectionData = NetworkConfig.ConnectionApproval,
|
||||
ConnectionData = NetworkConfig.ConnectionData
|
||||
};
|
||||
|
||||
message.MessageVersions = new NativeArray<MessageVersionData>(MessagingSystem.MessageHandlers.Length, Allocator.Temp);
|
||||
for (int index = 0; index < MessagingSystem.MessageHandlers.Length; index++)
|
||||
{
|
||||
if (MessagingSystem.MessageTypes[index] != null)
|
||||
{
|
||||
var type = MessagingSystem.MessageTypes[index];
|
||||
message.MessageVersions[index] = new MessageVersionData
|
||||
{
|
||||
Hash = XXHash.Hash32(type.FullName),
|
||||
Version = MessagingSystem.GetLocalVersion(type)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
SendMessage(ref message, NetworkDelivery.ReliableSequenced, ServerClientId);
|
||||
message.MessageVersions.Dispose();
|
||||
}
|
||||
|
||||
private IEnumerator ApprovalTimeout(ulong clientId)
|
||||
|
@ -2230,22 +2247,23 @@ namespace Unity.Netcode
|
|||
}
|
||||
}
|
||||
|
||||
SendMessage(ref message, NetworkDelivery.ReliableFragmentedSequenced, ownerClientId);
|
||||
|
||||
message.MessageVersions = new NativeArray<MessageVersionData>(MessagingSystem.MessageHandlers.Length, Allocator.Temp);
|
||||
for (int index = 0; index < MessagingSystem.MessageHandlers.Length; index++)
|
||||
{
|
||||
if (MessagingSystem.MessageTypes[index] != null)
|
||||
{
|
||||
var orderingMessage = new OrderingMessage
|
||||
var type = MessagingSystem.MessageTypes[index];
|
||||
message.MessageVersions[index] = new MessageVersionData
|
||||
{
|
||||
Order = index,
|
||||
Hash = XXHash.Hash32(MessagingSystem.MessageTypes[index].FullName)
|
||||
Hash = XXHash.Hash32(type.FullName),
|
||||
Version = MessagingSystem.GetLocalVersion(type)
|
||||
};
|
||||
|
||||
SendMessage(ref orderingMessage, NetworkDelivery.ReliableFragmentedSequenced, ownerClientId);
|
||||
}
|
||||
}
|
||||
|
||||
SendMessage(ref message, NetworkDelivery.ReliableFragmentedSequenced, ownerClientId);
|
||||
message.MessageVersions.Dispose();
|
||||
|
||||
// If scene management is enabled, then let NetworkSceneManager handle the initial scene and NetworkObject synchronization
|
||||
if (!NetworkConfig.EnableSceneManagement)
|
||||
{
|
||||
|
|
|
@ -4,7 +4,9 @@ namespace Unity.Netcode
|
|||
{
|
||||
public string Reason;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public int Version => 0;
|
||||
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
string reasonSent = Reason;
|
||||
if (reasonSent == null)
|
||||
|
@ -12,9 +14,16 @@ namespace Unity.Netcode
|
|||
reasonSent = string.Empty;
|
||||
}
|
||||
|
||||
// Since we don't send a ConnectionApprovedMessage, the version for this message is encded with the message
|
||||
// itself. However, note that we HAVE received a ConnectionRequestMessage, so we DO have a valid targetVersion
|
||||
// on this side of things - we just have to make sure the receiving side knows what version we sent it,
|
||||
// since whoever has the higher version number is responsible for versioning and they may be the one
|
||||
// with the higher version number.
|
||||
BytePacker.WriteValueBitPacked(writer, Version);
|
||||
|
||||
if (writer.TryBeginWrite(FastBufferWriter.GetWriteSize(reasonSent)))
|
||||
{
|
||||
writer.WriteValueSafe(reasonSent);
|
||||
writer.WriteValue(reasonSent);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -24,8 +33,11 @@ namespace Unity.Netcode
|
|||
}
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
// Since we don't get a ConnectionApprovedMessage, the version for this message is encded with the message
|
||||
// itself. This will override what we got from MessagingSystem... which will always be 0 here.
|
||||
ByteUnpacker.ReadValueBitPacked(reader, out receivedMessageVersion);
|
||||
reader.ReadValueSafe(out Reason);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -40,8 +40,9 @@ namespace Unity.Netcode
|
|||
/// </summary>
|
||||
internal interface INetworkMessage
|
||||
{
|
||||
void Serialize(FastBufferWriter writer);
|
||||
bool Deserialize(FastBufferReader reader, ref NetworkContext context);
|
||||
void Serialize(FastBufferWriter writer, int targetVersion);
|
||||
bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion);
|
||||
void Handle(ref NetworkContext context);
|
||||
int Version { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,16 +2,18 @@ namespace Unity.Netcode
|
|||
{
|
||||
internal struct ChangeOwnershipMessage : INetworkMessage, INetworkSerializeByMemcpy
|
||||
{
|
||||
public int Version => 0;
|
||||
|
||||
public ulong NetworkObjectId;
|
||||
public ulong OwnerClientId;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
BytePacker.WriteValueBitPacked(writer, NetworkObjectId);
|
||||
BytePacker.WriteValueBitPacked(writer, OwnerClientId);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (!networkManager.IsClient)
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal struct ConnectionApprovedMessage : INetworkMessage
|
||||
{
|
||||
public int Version => 0;
|
||||
|
||||
public ulong OwnerClientId;
|
||||
public int NetworkTick;
|
||||
|
||||
|
@ -13,12 +15,24 @@ namespace Unity.Netcode
|
|||
|
||||
private FastBufferReader m_ReceivedSceneObjectData;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public NativeArray<MessageVersionData> MessageVersions;
|
||||
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
if (!writer.TryBeginWrite(sizeof(ulong) + sizeof(int) + sizeof(int)))
|
||||
// ============================================================
|
||||
// BEGIN FORBIDDEN SEGMENT
|
||||
// DO NOT CHANGE THIS HEADER. Everything added to this message
|
||||
// must go AFTER the message version header.
|
||||
// ============================================================
|
||||
BytePacker.WriteValueBitPacked(writer, MessageVersions.Length);
|
||||
foreach (var messageVersion in MessageVersions)
|
||||
{
|
||||
throw new OverflowException($"Not enough space in the write buffer to serialize {nameof(ConnectionApprovedMessage)}");
|
||||
messageVersion.Serialize(writer);
|
||||
}
|
||||
// ============================================================
|
||||
// END FORBIDDEN SEGMENT
|
||||
// ============================================================
|
||||
|
||||
BytePacker.WriteValueBitPacked(writer, OwnerClientId);
|
||||
BytePacker.WriteValueBitPacked(writer, NetworkTick);
|
||||
|
||||
|
@ -51,7 +65,7 @@ namespace Unity.Netcode
|
|||
}
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (!networkManager.IsClient)
|
||||
|
@ -59,6 +73,34 @@ namespace Unity.Netcode
|
|||
return false;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// BEGIN FORBIDDEN SEGMENT
|
||||
// DO NOT CHANGE THIS HEADER. Everything added to this message
|
||||
// must go AFTER the message version header.
|
||||
// ============================================================
|
||||
ByteUnpacker.ReadValueBitPacked(reader, out int length);
|
||||
var messageHashesInOrder = new NativeArray<uint>(length, Allocator.Temp);
|
||||
for (var i = 0; i < length; ++i)
|
||||
{
|
||||
var messageVersion = new MessageVersionData();
|
||||
messageVersion.Deserialize(reader);
|
||||
networkManager.MessagingSystem.SetVersion(context.SenderId, messageVersion.Hash, messageVersion.Version);
|
||||
messageHashesInOrder[i] = messageVersion.Hash;
|
||||
|
||||
// Update the received version since this message will always be passed version 0, due to the map not
|
||||
// being initialized until just now.
|
||||
var messageType = networkManager.MessagingSystem.GetMessageForHash(messageVersion.Hash);
|
||||
if (messageType == typeof(ConnectionApprovedMessage))
|
||||
{
|
||||
receivedMessageVersion = messageVersion.Version;
|
||||
}
|
||||
}
|
||||
networkManager.MessagingSystem.SetServerMessageOrder(messageHashesInOrder);
|
||||
messageHashesInOrder.Dispose();
|
||||
// ============================================================
|
||||
// END FORBIDDEN SEGMENT
|
||||
// ============================================================
|
||||
|
||||
ByteUnpacker.ReadValueBitPacked(reader, out OwnerClientId);
|
||||
ByteUnpacker.ReadValueBitPacked(reader, out NetworkTick);
|
||||
m_ReceivedSceneObjectData = reader;
|
||||
|
|
|
@ -1,15 +1,35 @@
|
|||
using Unity.Collections;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
internal struct ConnectionRequestMessage : INetworkMessage
|
||||
{
|
||||
public int Version => 0;
|
||||
|
||||
public ulong ConfigHash;
|
||||
|
||||
public byte[] ConnectionData;
|
||||
|
||||
public bool ShouldSendConnectionData;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public NativeArray<MessageVersionData> MessageVersions;
|
||||
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
// ============================================================
|
||||
// BEGIN FORBIDDEN SEGMENT
|
||||
// DO NOT CHANGE THIS HEADER. Everything added to this message
|
||||
// must go AFTER the message version header.
|
||||
// ============================================================
|
||||
BytePacker.WriteValueBitPacked(writer, MessageVersions.Length);
|
||||
foreach (var messageVersion in MessageVersions)
|
||||
{
|
||||
messageVersion.Serialize(writer);
|
||||
}
|
||||
// ============================================================
|
||||
// END FORBIDDEN SEGMENT
|
||||
// ============================================================
|
||||
|
||||
if (ShouldSendConnectionData)
|
||||
{
|
||||
writer.WriteValueSafe(ConfigHash);
|
||||
|
@ -21,7 +41,7 @@ namespace Unity.Netcode
|
|||
}
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (!networkManager.IsServer)
|
||||
|
@ -29,6 +49,30 @@ namespace Unity.Netcode
|
|||
return false;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// BEGIN FORBIDDEN SEGMENT
|
||||
// DO NOT CHANGE THIS HEADER. Everything added to this message
|
||||
// must go AFTER the message version header.
|
||||
// ============================================================
|
||||
ByteUnpacker.ReadValueBitPacked(reader, out int length);
|
||||
for (var i = 0; i < length; ++i)
|
||||
{
|
||||
var messageVersion = new MessageVersionData();
|
||||
messageVersion.Deserialize(reader);
|
||||
networkManager.MessagingSystem.SetVersion(context.SenderId, messageVersion.Hash, messageVersion.Version);
|
||||
|
||||
// Update the received version since this message will always be passed version 0, due to the map not
|
||||
// being initialized until just now.
|
||||
var messageType = networkManager.MessagingSystem.GetMessageForHash(messageVersion.Hash);
|
||||
if (messageType == typeof(ConnectionRequestMessage))
|
||||
{
|
||||
receivedMessageVersion = messageVersion.Version;
|
||||
}
|
||||
}
|
||||
// ============================================================
|
||||
// END FORBIDDEN SEGMENT
|
||||
// ============================================================
|
||||
|
||||
if (networkManager.NetworkConfig.ConnectionApproval)
|
||||
{
|
||||
if (!reader.TryBeginRead(FastBufferWriter.GetWriteSize(ConfigHash) + FastBufferWriter.GetWriteSize<int>()))
|
||||
|
|
|
@ -2,15 +2,17 @@ namespace Unity.Netcode
|
|||
{
|
||||
internal struct CreateObjectMessage : INetworkMessage
|
||||
{
|
||||
public int Version => 0;
|
||||
|
||||
public NetworkObject.SceneObject ObjectInfo;
|
||||
private FastBufferReader m_ReceivedNetworkVariableData;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
ObjectInfo.Serialize(writer);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (!networkManager.IsClient)
|
||||
|
|
|
@ -2,16 +2,18 @@ namespace Unity.Netcode
|
|||
{
|
||||
internal struct DestroyObjectMessage : INetworkMessage, INetworkSerializeByMemcpy
|
||||
{
|
||||
public int Version => 0;
|
||||
|
||||
public ulong NetworkObjectId;
|
||||
public bool DestroyGameObject;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
BytePacker.WriteValueBitPacked(writer, NetworkObjectId);
|
||||
writer.WriteValueSafe(DestroyGameObject);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (!networkManager.IsClient)
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
namespace Unity.Netcode
|
||||
{
|
||||
/// <summary>
|
||||
/// Conveys a version number on a remote node for the given message (identified by its hash)
|
||||
/// </summary>
|
||||
internal struct MessageVersionData
|
||||
{
|
||||
public uint Hash;
|
||||
public int Version;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
writer.WriteValueSafe(Hash);
|
||||
BytePacker.WriteValueBitPacked(writer, Version);
|
||||
}
|
||||
|
||||
public void Deserialize(FastBufferReader reader)
|
||||
{
|
||||
reader.ReadValueSafe(out Hash);
|
||||
ByteUnpacker.ReadValueBitPacked(reader, out Version);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 754d727b316b4263a2fa0d4c54fdad52
|
||||
timeCreated: 1666895514
|
|
@ -2,18 +2,20 @@ namespace Unity.Netcode
|
|||
{
|
||||
internal struct NamedMessage : INetworkMessage
|
||||
{
|
||||
public int Version => 0;
|
||||
|
||||
public ulong Hash;
|
||||
public FastBufferWriter SendData;
|
||||
|
||||
private FastBufferReader m_ReceiveData;
|
||||
|
||||
public unsafe void Serialize(FastBufferWriter writer)
|
||||
public unsafe void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
writer.WriteValueSafe(Hash);
|
||||
writer.WriteBytesSafe(SendData.GetUnsafePtr(), SendData.Length);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
reader.ReadValueSafe(out Hash);
|
||||
m_ReceiveData = reader;
|
||||
|
|
|
@ -12,6 +12,8 @@ namespace Unity.Netcode
|
|||
/// </summary>
|
||||
internal struct NetworkVariableDeltaMessage : INetworkMessage
|
||||
{
|
||||
public int Version => 0;
|
||||
|
||||
public ulong NetworkObjectId;
|
||||
public ushort NetworkBehaviourIndex;
|
||||
|
||||
|
@ -21,7 +23,7 @@ namespace Unity.Netcode
|
|||
|
||||
private FastBufferReader m_ReceivedNetworkVariableData;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
if (!writer.TryBeginWrite(FastBufferWriter.GetWriteSize(NetworkObjectId) + FastBufferWriter.GetWriteSize(NetworkBehaviourIndex)))
|
||||
{
|
||||
|
@ -110,7 +112,7 @@ namespace Unity.Netcode
|
|||
}
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
ByteUnpacker.ReadValueBitPacked(reader, out NetworkObjectId);
|
||||
ByteUnpacker.ReadValueBitPacked(reader, out NetworkBehaviourIndex);
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
/// <summary>
|
||||
/// Upon connecting, the host sends a series of OrderingMessage to the client so that it can make sure both sides
|
||||
/// have the same message types in the same positions in
|
||||
/// - MessagingSystem.m_MessageHandlers
|
||||
/// - MessagingSystem.m_ReverseTypeMap
|
||||
/// even if one side has extra messages (compilation, version, patch, or platform differences, etc...)
|
||||
///
|
||||
/// The ConnectionRequestedMessage, ConnectionApprovedMessage and OrderingMessage are prioritized at the beginning
|
||||
/// of the mapping, to guarantee they can be exchanged before the two sides share their ordering
|
||||
/// The sorting used in also stable so that even if MessageType names share hashes, it will work most of the time
|
||||
/// </summary>
|
||||
internal struct OrderingMessage : INetworkMessage
|
||||
{
|
||||
public int Order;
|
||||
public uint 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3ada9e8fd5bf94b1f9a6a21531c8a3ee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -4,6 +4,8 @@ namespace Unity.Netcode
|
|||
{
|
||||
internal struct ParentSyncMessage : INetworkMessage
|
||||
{
|
||||
public int Version => 0;
|
||||
|
||||
public ulong NetworkObjectId;
|
||||
|
||||
private byte m_BitField;
|
||||
|
@ -39,7 +41,7 @@ namespace Unity.Netcode
|
|||
public Quaternion Rotation;
|
||||
public Vector3 Scale;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
BytePacker.WriteValueBitPacked(writer, NetworkObjectId);
|
||||
writer.WriteValueSafe(m_BitField);
|
||||
|
@ -57,7 +59,7 @@ namespace Unity.Netcode
|
|||
writer.WriteValueSafe(Scale);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (!networkManager.IsClient)
|
||||
|
|
|
@ -85,17 +85,19 @@ namespace Unity.Netcode
|
|||
|
||||
internal struct ServerRpcMessage : INetworkMessage
|
||||
{
|
||||
public int Version => 0;
|
||||
|
||||
public RpcMetadata Metadata;
|
||||
|
||||
public FastBufferWriter WriteBuffer;
|
||||
public FastBufferReader ReadBuffer;
|
||||
|
||||
public unsafe void Serialize(FastBufferWriter writer)
|
||||
public unsafe void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
RpcMessageHelpers.Serialize(ref writer, ref Metadata, ref WriteBuffer);
|
||||
}
|
||||
|
||||
public unsafe bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public unsafe bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
return RpcMessageHelpers.Deserialize(ref reader, ref context, ref Metadata, ref ReadBuffer);
|
||||
}
|
||||
|
@ -118,17 +120,19 @@ namespace Unity.Netcode
|
|||
|
||||
internal struct ClientRpcMessage : INetworkMessage
|
||||
{
|
||||
public int Version => 0;
|
||||
|
||||
public RpcMetadata Metadata;
|
||||
|
||||
public FastBufferWriter WriteBuffer;
|
||||
public FastBufferReader ReadBuffer;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
RpcMessageHelpers.Serialize(ref writer, ref Metadata, ref WriteBuffer);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
return RpcMessageHelpers.Deserialize(ref reader, ref context, ref Metadata, ref ReadBuffer);
|
||||
}
|
||||
|
|
|
@ -4,16 +4,18 @@ namespace Unity.Netcode
|
|||
// like most of the other messages when we have some more time and can come back and refactor this.
|
||||
internal struct SceneEventMessage : INetworkMessage
|
||||
{
|
||||
public int Version => 0;
|
||||
|
||||
public SceneEventData EventData;
|
||||
|
||||
private FastBufferReader m_ReceivedData;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
EventData.Serialize(writer);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
m_ReceivedData = reader;
|
||||
return true;
|
||||
|
|
|
@ -2,6 +2,8 @@ namespace Unity.Netcode
|
|||
{
|
||||
internal struct ServerLogMessage : INetworkMessage
|
||||
{
|
||||
public int Version => 0;
|
||||
|
||||
public NetworkLog.LogType LogType;
|
||||
// It'd be lovely to be able to replace this with FixedString or NativeArray...
|
||||
// But it's not really practical. On the sending side, the user is likely to want
|
||||
|
@ -11,13 +13,13 @@ namespace Unity.Netcode
|
|||
public string Message;
|
||||
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
writer.WriteValueSafe(LogType);
|
||||
BytePacker.WriteValuePacked(writer, Message);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (networkManager.IsServer && networkManager.NetworkConfig.EnableNetworkLogs)
|
||||
|
|
|
@ -2,14 +2,16 @@ namespace Unity.Netcode
|
|||
{
|
||||
internal struct TimeSyncMessage : INetworkMessage, INetworkSerializeByMemcpy
|
||||
{
|
||||
public int Version => 0;
|
||||
|
||||
public int Tick;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
BytePacker.WriteValueBitPacked(writer, Tick);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
var networkManager = (NetworkManager)context.SystemOwner;
|
||||
if (!networkManager.IsClient)
|
||||
|
|
|
@ -2,15 +2,17 @@ namespace Unity.Netcode
|
|||
{
|
||||
internal struct UnnamedMessage : INetworkMessage
|
||||
{
|
||||
public int Version => 0;
|
||||
|
||||
public FastBufferWriter SendData;
|
||||
private FastBufferReader m_ReceivedData;
|
||||
|
||||
public unsafe void Serialize(FastBufferWriter writer)
|
||||
public unsafe void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
writer.WriteBytesSafe(SendData.GetUnsafePtr(), SendData.Length);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
m_ReceivedData = reader;
|
||||
return true;
|
||||
|
|
|
@ -46,6 +46,7 @@ namespace Unity.Netcode
|
|||
}
|
||||
|
||||
internal delegate void MessageHandler(FastBufferReader reader, ref NetworkContext context, MessagingSystem system);
|
||||
internal delegate int VersionGetter();
|
||||
|
||||
private NativeList<ReceiveQueueItem> m_IncomingMessageQueue = new NativeList<ReceiveQueueItem>(16, Allocator.Persistent);
|
||||
|
||||
|
@ -56,6 +57,11 @@ namespace Unity.Netcode
|
|||
private Dictionary<Type, uint> m_MessageTypes = new Dictionary<Type, uint>();
|
||||
private Dictionary<ulong, NativeList<SendQueueItem>> m_SendQueues = new Dictionary<ulong, NativeList<SendQueueItem>>();
|
||||
|
||||
// This is m_PerClientMessageVersion[clientId][messageType] = version
|
||||
private Dictionary<ulong, Dictionary<Type, int>> m_PerClientMessageVersions = new Dictionary<ulong, Dictionary<Type, int>>();
|
||||
private Dictionary<uint, Type> m_MessagesByHash = new Dictionary<uint, Type>();
|
||||
private Dictionary<Type, int> m_LocalVersions = new Dictionary<Type, int>();
|
||||
|
||||
private List<INetworkHooks> m_Hooks = new List<INetworkHooks>();
|
||||
|
||||
private uint m_HighMessageType;
|
||||
|
@ -80,6 +86,7 @@ namespace Unity.Netcode
|
|||
{
|
||||
public Type MessageType;
|
||||
public MessageHandler Handler;
|
||||
public VersionGetter GetVersion;
|
||||
}
|
||||
|
||||
internal List<MessageWithHandler> PrioritizeMessageOrder(List<MessageWithHandler> allowedTypes)
|
||||
|
@ -90,9 +97,8 @@ namespace Unity.Netcode
|
|||
// 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")
|
||||
if (t.MessageType.FullName == typeof(ConnectionRequestMessage).FullName ||
|
||||
t.MessageType.FullName == typeof(ConnectionApprovedMessage).FullName)
|
||||
{
|
||||
prioritizedTypes.Add(t);
|
||||
}
|
||||
|
@ -100,9 +106,8 @@ namespace Unity.Netcode
|
|||
|
||||
foreach (var t in allowedTypes)
|
||||
{
|
||||
if (t.MessageType.FullName != "Unity.Netcode.ConnectionRequestMessage" &&
|
||||
t.MessageType.FullName != "Unity.Netcode.ConnectionApprovedMessage" &&
|
||||
t.MessageType.FullName != "Unity.Netcode.OrderingMessage")
|
||||
if (t.MessageType.FullName != typeof(ConnectionRequestMessage).FullName &&
|
||||
t.MessageType.FullName != typeof(ConnectionApprovedMessage).FullName)
|
||||
{
|
||||
prioritizedTypes.Add(t);
|
||||
}
|
||||
|
@ -189,7 +194,14 @@ namespace Unity.Netcode
|
|||
|
||||
m_MessageHandlers[m_HighMessageType] = messageWithHandler.Handler;
|
||||
m_ReverseTypeMap[m_HighMessageType] = messageWithHandler.MessageType;
|
||||
m_MessagesByHash[XXHash.Hash32(messageWithHandler.MessageType.FullName)] = messageWithHandler.MessageType;
|
||||
m_MessageTypes[messageWithHandler.MessageType] = m_HighMessageType++;
|
||||
m_LocalVersions[messageWithHandler.MessageType] = messageWithHandler.GetVersion();
|
||||
}
|
||||
|
||||
public int GetLocalVersion(Type messageType)
|
||||
{
|
||||
return m_LocalVersions[messageType];
|
||||
}
|
||||
|
||||
internal void HandleIncomingData(ulong clientId, ArraySegment<byte> data, float receiveTime)
|
||||
|
@ -270,68 +282,53 @@ namespace Unity.Netcode
|
|||
return true;
|
||||
}
|
||||
|
||||
// Moves the handler for the type having hash `targetHash` to the `desiredOrder` position, in the handler list
|
||||
// This allows the server to tell the client which id it is using for which message and make sure the right
|
||||
// message is used when deserializing.
|
||||
internal void ReorderMessage(int desiredOrder, uint targetHash)
|
||||
internal Type GetMessageForHash(uint messageHash)
|
||||
{
|
||||
if (desiredOrder < 0)
|
||||
if (!m_MessagesByHash.ContainsKey(messageHash))
|
||||
{
|
||||
throw new ArgumentException("ReorderMessage desiredOrder must be positive");
|
||||
return null;
|
||||
}
|
||||
return m_MessagesByHash[messageHash];
|
||||
}
|
||||
|
||||
if (desiredOrder < m_ReverseTypeMap.Length &&
|
||||
XXHash.Hash32(m_ReverseTypeMap[desiredOrder].FullName) == targetHash)
|
||||
internal void SetVersion(ulong clientId, uint messageHash, int version)
|
||||
{
|
||||
if (!m_MessagesByHash.ContainsKey(messageHash))
|
||||
{
|
||||
// matching positions and hashes. All good.
|
||||
return;
|
||||
}
|
||||
var messageType = m_MessagesByHash[messageHash];
|
||||
|
||||
Debug.Log($"Unexpected hash for {desiredOrder}");
|
||||
|
||||
// Since the message at `desiredOrder` is not the expected one,
|
||||
// insert an empty placeholder and move the messages down
|
||||
var typesAsList = new List<Type>(m_ReverseTypeMap);
|
||||
|
||||
typesAsList.Insert(desiredOrder, null);
|
||||
var handlersAsList = new List<MessageHandler>(m_MessageHandlers);
|
||||
handlersAsList.Insert(desiredOrder, null);
|
||||
|
||||
// we added a dummy message, bump the end up
|
||||
m_HighMessageType++;
|
||||
|
||||
// Here, we rely on the server telling us about all messages, in order.
|
||||
// So, we know the handlers before desiredOrder are correct.
|
||||
// We start at desiredOrder to not shift them when we insert.
|
||||
int position = desiredOrder;
|
||||
bool found = false;
|
||||
while (position < typesAsList.Count)
|
||||
if (!m_PerClientMessageVersions.ContainsKey(clientId))
|
||||
{
|
||||
if (typesAsList[position] != null &&
|
||||
XXHash.Hash32(typesAsList[position].FullName) == targetHash)
|
||||
m_PerClientMessageVersions[clientId] = new Dictionary<Type, int>();
|
||||
}
|
||||
|
||||
m_PerClientMessageVersions[clientId][messageType] = version;
|
||||
}
|
||||
|
||||
internal void SetServerMessageOrder(NativeArray<uint> messagesInIdOrder)
|
||||
{
|
||||
var oldHandlers = m_MessageHandlers;
|
||||
var oldTypes = m_MessageTypes;
|
||||
m_ReverseTypeMap = new Type[messagesInIdOrder.Length];
|
||||
m_MessageHandlers = new MessageHandler[messagesInIdOrder.Length];
|
||||
m_MessageTypes = new Dictionary<Type, uint>();
|
||||
|
||||
for (var i = 0; i < messagesInIdOrder.Length; ++i)
|
||||
{
|
||||
if (!m_MessagesByHash.ContainsKey(messagesInIdOrder[i]))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
position++;
|
||||
var messageType = m_MessagesByHash[messagesInIdOrder[i]];
|
||||
var oldId = oldTypes[messageType];
|
||||
var handler = oldHandlers[oldId];
|
||||
var newId = (uint)i;
|
||||
m_MessageTypes[messageType] = newId;
|
||||
m_MessageHandlers[newId] = handler;
|
||||
m_ReverseTypeMap[newId] = messageType;
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
// Copy the handler and type to the right index
|
||||
|
||||
typesAsList[desiredOrder] = typesAsList[position];
|
||||
handlersAsList[desiredOrder] = handlersAsList[position];
|
||||
typesAsList.RemoveAt(position);
|
||||
handlersAsList.RemoveAt(position);
|
||||
|
||||
// we removed a copy after moving a message, reduce the high message index
|
||||
m_HighMessageType--;
|
||||
}
|
||||
|
||||
m_ReverseTypeMap = typesAsList.ToArray();
|
||||
m_MessageHandlers = handlersAsList.ToArray();
|
||||
}
|
||||
|
||||
public void HandleMessage(in MessageHeader header, FastBufferReader reader, ulong senderId, float timestamp, int serializedHeaderSize)
|
||||
|
@ -433,7 +430,7 @@ namespace Unity.Netcode
|
|||
m_SendQueues.Remove(clientId);
|
||||
}
|
||||
|
||||
private unsafe void CleanupDisconnectedClient(ulong clientId)
|
||||
private void CleanupDisconnectedClient(ulong clientId)
|
||||
{
|
||||
var queue = m_SendQueues[clientId];
|
||||
for (var i = 0; i < queue.Length; ++i)
|
||||
|
@ -444,10 +441,67 @@ namespace Unity.Netcode
|
|||
queue.Dispose();
|
||||
}
|
||||
|
||||
internal void CleanupDisconnectedClients()
|
||||
{
|
||||
var removeList = new NativeList<ulong>(Allocator.Temp);
|
||||
foreach (var clientId in m_PerClientMessageVersions.Keys)
|
||||
{
|
||||
if (!m_SendQueues.ContainsKey(clientId))
|
||||
{
|
||||
removeList.Add(clientId);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var clientId in removeList)
|
||||
{
|
||||
m_PerClientMessageVersions.Remove(clientId);
|
||||
}
|
||||
}
|
||||
|
||||
public static int CreateMessageAndGetVersion<T>() where T : INetworkMessage, new()
|
||||
{
|
||||
return new T().Version;
|
||||
}
|
||||
|
||||
internal int GetMessageVersion(Type type, ulong clientId, bool forReceive = false)
|
||||
{
|
||||
if (!m_PerClientMessageVersions.TryGetValue(clientId, out var versionMap))
|
||||
{
|
||||
if (forReceive)
|
||||
{
|
||||
Debug.LogWarning($"Trying to receive {type.Name} from client {clientId} which is not in a connected state.");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"Trying to send {type.Name} to client {clientId} which is not in a connected state.");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (!versionMap.TryGetValue(type, out var messageVersion))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return messageVersion;
|
||||
}
|
||||
|
||||
public static void ReceiveMessage<T>(FastBufferReader reader, ref NetworkContext context, MessagingSystem system) where T : INetworkMessage, new()
|
||||
{
|
||||
var message = new T();
|
||||
if (message.Deserialize(reader, ref context))
|
||||
var messageVersion = 0;
|
||||
// Special cases because these are the messages that carry the version info - thus the version info isn't
|
||||
// populated yet when we get these. The first part of these messages always has to be the version data
|
||||
// and can't change.
|
||||
if (typeof(T) != typeof(ConnectionRequestMessage) && typeof(T) != typeof(ConnectionApprovedMessage) && typeof(T) != typeof(DisconnectReasonMessage))
|
||||
{
|
||||
messageVersion = system.GetMessageVersion(typeof(T), context.SenderId, true);
|
||||
if (messageVersion < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (message.Deserialize(reader, ref context, messageVersion))
|
||||
{
|
||||
for (var hookIdx = 0; hookIdx < system.m_Hooks.Count; ++hookIdx)
|
||||
{
|
||||
|
@ -485,16 +539,47 @@ namespace Unity.Netcode
|
|||
return 0;
|
||||
}
|
||||
|
||||
var maxSize = delivery == NetworkDelivery.ReliableFragmentedSequenced ? FRAGMENTED_MESSAGE_MAX_SIZE : NON_FRAGMENTED_MESSAGE_MAX_SIZE;
|
||||
var largestSerializedSize = 0;
|
||||
var sentMessageVersions = new NativeHashSet<int>(clientIds.Count, Allocator.Temp);
|
||||
for (var i = 0; i < clientIds.Count; ++i)
|
||||
{
|
||||
var messageVersion = 0;
|
||||
// Special case because this is the message that carries the version info - thus the version info isn't
|
||||
// populated yet when we get this. The first part of this message always has to be the version data
|
||||
// and can't change.
|
||||
if (typeof(TMessageType) != typeof(ConnectionRequestMessage))
|
||||
{
|
||||
messageVersion = GetMessageVersion(typeof(TMessageType), clientIds[i]);
|
||||
if (messageVersion < 0)
|
||||
{
|
||||
// Client doesn't know this message exists, don't send it at all.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
using var tmpSerializer = new FastBufferWriter(NON_FRAGMENTED_MESSAGE_MAX_SIZE - FastBufferWriter.GetWriteSize<MessageHeader>(), Allocator.Temp, maxSize - FastBufferWriter.GetWriteSize<MessageHeader>());
|
||||
if (sentMessageVersions.Contains(messageVersion))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
message.Serialize(tmpSerializer);
|
||||
sentMessageVersions.Add(messageVersion);
|
||||
|
||||
return SendPreSerializedMessage(tmpSerializer, maxSize, ref message, delivery, clientIds);
|
||||
var maxSize = delivery == NetworkDelivery.ReliableFragmentedSequenced ? FRAGMENTED_MESSAGE_MAX_SIZE : NON_FRAGMENTED_MESSAGE_MAX_SIZE;
|
||||
|
||||
using var tmpSerializer = new FastBufferWriter(NON_FRAGMENTED_MESSAGE_MAX_SIZE - FastBufferWriter.GetWriteSize<MessageHeader>(), Allocator.Temp, maxSize - FastBufferWriter.GetWriteSize<MessageHeader>());
|
||||
|
||||
message.Serialize(tmpSerializer, messageVersion);
|
||||
|
||||
var size = SendPreSerializedMessage(tmpSerializer, maxSize, ref message, delivery, clientIds, messageVersion);
|
||||
largestSerializedSize = size > largestSerializedSize ? size : largestSerializedSize;
|
||||
}
|
||||
|
||||
sentMessageVersions.Dispose();
|
||||
|
||||
return largestSerializedSize;
|
||||
}
|
||||
|
||||
internal unsafe int SendPreSerializedMessage<TMessageType>(in FastBufferWriter tmpSerializer, int maxSize, ref TMessageType message, NetworkDelivery delivery, in IReadOnlyList<ulong> clientIds)
|
||||
internal unsafe int SendPreSerializedMessage<TMessageType>(in FastBufferWriter tmpSerializer, int maxSize, ref TMessageType message, NetworkDelivery delivery, in IReadOnlyList<ulong> clientIds, int messageVersionFilter)
|
||||
where TMessageType : INetworkMessage
|
||||
{
|
||||
using var headerSerializer = new FastBufferWriter(FastBufferWriter.GetWriteSize<MessageHeader>(), Allocator.Temp);
|
||||
|
@ -509,6 +594,25 @@ namespace Unity.Netcode
|
|||
|
||||
for (var i = 0; i < clientIds.Count; ++i)
|
||||
{
|
||||
var messageVersion = 0;
|
||||
// Special case because this is the message that carries the version info - thus the version info isn't
|
||||
// populated yet when we get this. The first part of this message always has to be the version data
|
||||
// and can't change.
|
||||
if (typeof(TMessageType) != typeof(ConnectionRequestMessage))
|
||||
{
|
||||
messageVersion = GetMessageVersion(typeof(TMessageType), clientIds[i]);
|
||||
if (messageVersion < 0)
|
||||
{
|
||||
// Client doesn't know this message exists, don't send it at all.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (messageVersion != messageVersionFilter)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var clientId = clientIds[i];
|
||||
|
||||
if (!CanSend(clientId, typeof(TMessageType), delivery))
|
||||
|
@ -559,8 +663,22 @@ namespace Unity.Netcode
|
|||
internal unsafe int SendPreSerializedMessage<TMessageType>(in FastBufferWriter tmpSerializer, int maxSize, ref TMessageType message, NetworkDelivery delivery, ulong clientId)
|
||||
where TMessageType : INetworkMessage
|
||||
{
|
||||
var messageVersion = 0;
|
||||
// Special case because this is the message that carries the version info - thus the version info isn't
|
||||
// populated yet when we get this. The first part of this message always has to be the version data
|
||||
// and can't change.
|
||||
if (typeof(TMessageType) != typeof(ConnectionRequestMessage))
|
||||
{
|
||||
messageVersion = GetMessageVersion(typeof(TMessageType), clientId);
|
||||
if (messageVersion < 0)
|
||||
{
|
||||
// Client doesn't know this message exists, don't send it at all.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ulong* clientIds = stackalloc ulong[] { clientId };
|
||||
return SendPreSerializedMessage(tmpSerializer, maxSize, ref message, delivery, new PointerListWrapper<ulong>(clientIds, 1));
|
||||
return SendPreSerializedMessage(tmpSerializer, maxSize, ref message, delivery, new PointerListWrapper<ulong>(clientIds, 1), messageVersion);
|
||||
}
|
||||
|
||||
private struct PointerListWrapper<T> : IReadOnlyList<T>
|
||||
|
|
|
@ -12,11 +12,11 @@ namespace Unity.Netcode.EditorTests
|
|||
var writer = new FastBufferWriter(20, Allocator.Temp, 20);
|
||||
var msg = new DisconnectReasonMessage();
|
||||
msg.Reason = string.Empty;
|
||||
msg.Serialize(writer);
|
||||
msg.Serialize(writer, msg.Version);
|
||||
|
||||
var fbr = new FastBufferReader(writer, Allocator.Temp);
|
||||
var recvMsg = new DisconnectReasonMessage();
|
||||
recvMsg.Deserialize(fbr, ref networkContext);
|
||||
recvMsg.Deserialize(fbr, ref networkContext, msg.Version);
|
||||
|
||||
Assert.IsEmpty(recvMsg.Reason);
|
||||
}
|
||||
|
@ -28,11 +28,11 @@ namespace Unity.Netcode.EditorTests
|
|||
var writer = new FastBufferWriter(20, Allocator.Temp, 20);
|
||||
var msg = new DisconnectReasonMessage();
|
||||
msg.Reason = "Foo";
|
||||
msg.Serialize(writer);
|
||||
msg.Serialize(writer, msg.Version);
|
||||
|
||||
var fbr = new FastBufferReader(writer, Allocator.Temp);
|
||||
var recvMsg = new DisconnectReasonMessage();
|
||||
recvMsg.Deserialize(fbr, ref networkContext);
|
||||
recvMsg.Deserialize(fbr, ref networkContext, msg.Version);
|
||||
|
||||
Assert.AreEqual("Foo", recvMsg.Reason);
|
||||
}
|
||||
|
@ -44,11 +44,11 @@ namespace Unity.Netcode.EditorTests
|
|||
var writer = new FastBufferWriter(20, Allocator.Temp, 20);
|
||||
var msg = new DisconnectReasonMessage();
|
||||
msg.Reason = "ThisStringIsWayLongerThanTwentyBytes";
|
||||
msg.Serialize(writer);
|
||||
msg.Serialize(writer, msg.Version);
|
||||
|
||||
var fbr = new FastBufferReader(writer, Allocator.Temp);
|
||||
var recvMsg = new DisconnectReasonMessage();
|
||||
recvMsg.Deserialize(fbr, ref networkContext);
|
||||
recvMsg.Deserialize(fbr, ref networkContext, msg.Version);
|
||||
|
||||
Assert.IsEmpty(recvMsg.Reason);
|
||||
}
|
||||
|
|
|
@ -18,12 +18,12 @@ namespace Unity.Netcode.EditorTests
|
|||
public static bool Handled;
|
||||
public static List<TestMessage> DeserializedValues = new List<TestMessage>();
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
writer.WriteValueSafe(this);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
Deserialized = true;
|
||||
reader.ReadValueSafe(out this);
|
||||
|
@ -35,6 +35,8 @@ namespace Unity.Netcode.EditorTests
|
|||
Handled = true;
|
||||
DeserializedValues.Add(this);
|
||||
}
|
||||
|
||||
public int Version => 0;
|
||||
}
|
||||
|
||||
private class TestMessageProvider : IMessageProvider
|
||||
|
@ -46,7 +48,8 @@ namespace Unity.Netcode.EditorTests
|
|||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(TestMessage),
|
||||
Handler = MessagingSystem.ReceiveMessage<TestMessage>
|
||||
Handler = MessagingSystem.ReceiveMessage<TestMessage>,
|
||||
GetVersion = MessagingSystem.CreateMessageAndGetVersion<TestMessage>
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -62,6 +65,7 @@ namespace Unity.Netcode.EditorTests
|
|||
TestMessage.DeserializedValues.Clear();
|
||||
|
||||
m_MessagingSystem = new MessagingSystem(new NopMessageSender(), this, new TestMessageProvider());
|
||||
m_MessagingSystem.SetVersion(0, XXHash.Hash32(typeof(TestMessage).FullName), 0);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
@ -11,12 +10,12 @@ namespace Unity.Netcode.EditorTests
|
|||
public int A;
|
||||
public int B;
|
||||
public int C;
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
writer.WriteValue(this);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -24,6 +23,8 @@ namespace Unity.Netcode.EditorTests
|
|||
public void Handle(ref NetworkContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public int Version => 0;
|
||||
}
|
||||
|
||||
private struct TestMessageTwo : INetworkMessage, INetworkSerializeByMemcpy
|
||||
|
@ -31,12 +32,12 @@ namespace Unity.Netcode.EditorTests
|
|||
public int A;
|
||||
public int B;
|
||||
public int C;
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
writer.WriteValue(this);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -44,6 +45,8 @@ namespace Unity.Netcode.EditorTests
|
|||
public void Handle(ref NetworkContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public int Version => 0;
|
||||
}
|
||||
private class TestMessageProviderOne : IMessageProvider
|
||||
{
|
||||
|
@ -54,12 +57,14 @@ namespace Unity.Netcode.EditorTests
|
|||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(TestMessageOne),
|
||||
Handler = MessagingSystem.ReceiveMessage<TestMessageOne>
|
||||
Handler = MessagingSystem.ReceiveMessage<TestMessageOne>,
|
||||
GetVersion = MessagingSystem.CreateMessageAndGetVersion<TestMessageOne>
|
||||
},
|
||||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(TestMessageTwo),
|
||||
Handler = MessagingSystem.ReceiveMessage<TestMessageTwo>
|
||||
Handler = MessagingSystem.ReceiveMessage<TestMessageTwo>,
|
||||
GetVersion = MessagingSystem.CreateMessageAndGetVersion<TestMessageTwo>
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -70,12 +75,12 @@ namespace Unity.Netcode.EditorTests
|
|||
public int A;
|
||||
public int B;
|
||||
public int C;
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
writer.WriteValue(this);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -83,6 +88,8 @@ namespace Unity.Netcode.EditorTests
|
|||
public void Handle(ref NetworkContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public int Version => 0;
|
||||
}
|
||||
private class TestMessageProviderTwo : IMessageProvider
|
||||
{
|
||||
|
@ -93,7 +100,8 @@ namespace Unity.Netcode.EditorTests
|
|||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(TestMessageThree),
|
||||
Handler = MessagingSystem.ReceiveMessage<TestMessageThree>
|
||||
Handler = MessagingSystem.ReceiveMessage<TestMessageThree>,
|
||||
GetVersion = MessagingSystem.CreateMessageAndGetVersion<TestMessageThree>
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -103,12 +111,12 @@ namespace Unity.Netcode.EditorTests
|
|||
public int A;
|
||||
public int B;
|
||||
public int C;
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
writer.WriteValue(this);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -116,6 +124,8 @@ namespace Unity.Netcode.EditorTests
|
|||
public void Handle(ref NetworkContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public int Version => 0;
|
||||
}
|
||||
private class TestMessageProviderThree : IMessageProvider
|
||||
{
|
||||
|
@ -126,7 +136,8 @@ namespace Unity.Netcode.EditorTests
|
|||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(TestMessageFour),
|
||||
Handler = MessagingSystem.ReceiveMessage<TestMessageFour>
|
||||
Handler = MessagingSystem.ReceiveMessage<TestMessageFour>,
|
||||
GetVersion = MessagingSystem.CreateMessageAndGetVersion<TestMessageFour>
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -183,11 +194,11 @@ namespace Unity.Netcode.EditorTests
|
|||
|
||||
internal class AAAEarlyLexicographicNetworkMessage : INetworkMessage
|
||||
{
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -195,6 +206,8 @@ namespace Unity.Netcode.EditorTests
|
|||
public void Handle(ref NetworkContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public int Version => 0;
|
||||
}
|
||||
|
||||
#pragma warning disable IDE1006
|
||||
|
@ -212,18 +225,19 @@ namespace Unity.Netcode.EditorTests
|
|||
var messageWithHandler = new MessagingSystem.MessageWithHandler();
|
||||
|
||||
messageWithHandler.MessageType = typeof(zzzLateLexicographicNetworkMessage);
|
||||
messageWithHandler.GetVersion = MessagingSystem.CreateMessageAndGetVersion<zzzLateLexicographicNetworkMessage>;
|
||||
listMessages.Add(messageWithHandler);
|
||||
|
||||
messageWithHandler.MessageType = typeof(ConnectionRequestMessage);
|
||||
messageWithHandler.GetVersion = MessagingSystem.CreateMessageAndGetVersion<ConnectionRequestMessage>;
|
||||
listMessages.Add(messageWithHandler);
|
||||
|
||||
messageWithHandler.MessageType = typeof(ConnectionApprovedMessage);
|
||||
listMessages.Add(messageWithHandler);
|
||||
|
||||
messageWithHandler.MessageType = typeof(OrderingMessage);
|
||||
messageWithHandler.GetVersion = MessagingSystem.CreateMessageAndGetVersion<ConnectionApprovedMessage>;
|
||||
listMessages.Add(messageWithHandler);
|
||||
|
||||
messageWithHandler.MessageType = typeof(AAAEarlyLexicographicNetworkMessage);
|
||||
messageWithHandler.GetVersion = MessagingSystem.CreateMessageAndGetVersion<AAAEarlyLexicographicNetworkMessage>;
|
||||
listMessages.Add(messageWithHandler);
|
||||
|
||||
return listMessages;
|
||||
|
@ -237,65 +251,16 @@ namespace Unity.Netcode.EditorTests
|
|||
var provider = new OrderingMessageProvider();
|
||||
using var messagingSystem = new MessagingSystem(sender, null, provider);
|
||||
|
||||
// the 3 priority messages should appear first, in lexicographic order
|
||||
// the 2 priority messages should appear first, in lexicographic order
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[0], typeof(ConnectionApprovedMessage));
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[1], typeof(ConnectionRequestMessage));
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[2], typeof(OrderingMessage));
|
||||
|
||||
// the other should follow after
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[3], typeof(AAAEarlyLexicographicNetworkMessage));
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[4], typeof(zzzLateLexicographicNetworkMessage));
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[2], typeof(AAAEarlyLexicographicNetworkMessage));
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[3], typeof(zzzLateLexicographicNetworkMessage));
|
||||
|
||||
// there should not be any extras
|
||||
Assert.AreEqual(messagingSystem.MessageHandlerCount, 5);
|
||||
|
||||
// reorder the zzz one to position 3
|
||||
messagingSystem.ReorderMessage(3, XXHash.Hash32(typeof(zzzLateLexicographicNetworkMessage).FullName));
|
||||
|
||||
// the 3 priority messages should still appear first, in lexicographic order
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[0], typeof(ConnectionApprovedMessage));
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[1], typeof(ConnectionRequestMessage));
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[2], typeof(OrderingMessage));
|
||||
|
||||
// the other should follow after, but reordered
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[3], typeof(zzzLateLexicographicNetworkMessage));
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[4], typeof(AAAEarlyLexicographicNetworkMessage));
|
||||
|
||||
// there should still not be any extras
|
||||
Assert.AreEqual(messagingSystem.MessageHandlerCount, 5);
|
||||
|
||||
// verify we get an exception when asking for an invalid position
|
||||
try
|
||||
{
|
||||
messagingSystem.ReorderMessage(-1, XXHash.Hash32(typeof(zzzLateLexicographicNetworkMessage).FullName));
|
||||
Assert.Fail();
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
}
|
||||
|
||||
// reorder the zzz one to position 3, again, to check nothing bad happens
|
||||
messagingSystem.ReorderMessage(3, XXHash.Hash32(typeof(zzzLateLexicographicNetworkMessage).FullName));
|
||||
|
||||
// the two non-priority should not have moved
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[3], typeof(zzzLateLexicographicNetworkMessage));
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[4], typeof(AAAEarlyLexicographicNetworkMessage));
|
||||
|
||||
// there should still not be any extras
|
||||
Assert.AreEqual(messagingSystem.MessageHandlerCount, 5);
|
||||
|
||||
// 4242 is a random hash that should not match anything
|
||||
messagingSystem.ReorderMessage(3, 4242);
|
||||
|
||||
// that should result in an extra entry
|
||||
Assert.AreEqual(messagingSystem.MessageHandlerCount, 6);
|
||||
|
||||
// with a null handler
|
||||
Assert.AreEqual(messagingSystem.MessageHandlers[3], null);
|
||||
|
||||
// and it should have bumped the previous messages down
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[4], typeof(zzzLateLexicographicNetworkMessage));
|
||||
Assert.AreEqual(messagingSystem.MessageTypes[5], typeof(AAAEarlyLexicographicNetworkMessage));
|
||||
Assert.AreEqual(messagingSystem.MessageHandlerCount, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,13 @@ namespace Unity.Netcode.EditorTests
|
|||
public int B;
|
||||
public int C;
|
||||
public static bool Serialized;
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
Serialized = true;
|
||||
writer.WriteValueSafe(this);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context)
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ namespace Unity.Netcode.EditorTests
|
|||
public void Handle(ref NetworkContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public int Version => 0;
|
||||
}
|
||||
|
||||
private class TestMessageSender : IMessageSender
|
||||
|
@ -66,7 +68,8 @@ namespace Unity.Netcode.EditorTests
|
|||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(TestMessage),
|
||||
Handler = MessagingSystem.ReceiveMessage<TestMessage>
|
||||
Handler = MessagingSystem.ReceiveMessage<TestMessage>,
|
||||
GetVersion = MessagingSystem.CreateMessageAndGetVersion<TestMessage>
|
||||
}
|
||||
};
|
||||
// Track messages sent
|
||||
|
@ -88,6 +91,7 @@ namespace Unity.Netcode.EditorTests
|
|||
m_TestMessageProvider = new TestMessageProvider();
|
||||
m_MessagingSystem = new MessagingSystem(m_MessageSender, this, m_TestMessageProvider);
|
||||
m_MessagingSystem.ClientConnected(0);
|
||||
m_MessagingSystem.SetVersion(0, XXHash.Hash32(typeof(TestMessage).FullName), 0);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
|
@ -256,7 +260,8 @@ namespace Unity.Netcode.EditorTests
|
|||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(TestMessage),
|
||||
Handler = null
|
||||
Handler = null,
|
||||
GetVersion = MessagingSystem.CreateMessageAndGetVersion<TestMessage>
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,503 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Internal;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class MessageVersioningTests
|
||||
{
|
||||
public static int SentVersion;
|
||||
public static int ReceivedVersion;
|
||||
|
||||
private const int k_DefaultB = 5;
|
||||
private const int k_DefaultC = 10;
|
||||
private const int k_DefaultD = 15;
|
||||
private const long k_DefaultE = 20;
|
||||
|
||||
private struct VersionedTestMessage_v0 : INetworkMessage, INetworkSerializeByMemcpy
|
||||
{
|
||||
public int A;
|
||||
public int B;
|
||||
public int C;
|
||||
public static bool Serialized;
|
||||
public static bool Deserialized;
|
||||
public static bool Handled;
|
||||
public static List<VersionedTestMessage_v0> DeserializedValues = new List<VersionedTestMessage_v0>();
|
||||
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
SentVersion = Version;
|
||||
Serialized = true;
|
||||
writer.WriteValueSafe(A);
|
||||
writer.WriteValueSafe(B);
|
||||
writer.WriteValueSafe(C);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
ReceivedVersion = Version;
|
||||
Deserialized = true;
|
||||
reader.ReadValueSafe(out A);
|
||||
reader.ReadValueSafe(out B);
|
||||
reader.ReadValueSafe(out C);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Handle(ref NetworkContext context)
|
||||
{
|
||||
Handled = true;
|
||||
DeserializedValues.Add(this);
|
||||
}
|
||||
|
||||
public int Version => 0;
|
||||
}
|
||||
|
||||
private struct VersionedTestMessage_v1 : INetworkMessage, INetworkSerializeByMemcpy
|
||||
{
|
||||
public int A;
|
||||
public int B;
|
||||
public int C;
|
||||
public int D;
|
||||
public static bool Serialized;
|
||||
public static bool Deserialized;
|
||||
public static bool Downgraded;
|
||||
public static bool Upgraded;
|
||||
public static bool Handled;
|
||||
public static List<VersionedTestMessage_v1> DeserializedValues = new List<VersionedTestMessage_v1>();
|
||||
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
if (targetVersion < Version)
|
||||
{
|
||||
Downgraded = true;
|
||||
var v0 = new VersionedTestMessage_v0 { A = A, B = B, C = C };
|
||||
v0.Serialize(writer, targetVersion);
|
||||
return;
|
||||
}
|
||||
SentVersion = Version;
|
||||
Serialized = true;
|
||||
writer.WriteValueSafe(C);
|
||||
writer.WriteValueSafe(D);
|
||||
writer.WriteValueSafe(A);
|
||||
writer.WriteValueSafe(B);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
if (receivedMessageVersion < Version)
|
||||
{
|
||||
var v0 = new VersionedTestMessage_v0();
|
||||
v0.Deserialize(reader, ref context, receivedMessageVersion);
|
||||
A = v0.A;
|
||||
B = v0.B;
|
||||
C = v0.C;
|
||||
D = k_DefaultD;
|
||||
Upgraded = true;
|
||||
return true;
|
||||
}
|
||||
ReceivedVersion = Version;
|
||||
Deserialized = true;
|
||||
reader.ReadValueSafe(out C);
|
||||
reader.ReadValueSafe(out D);
|
||||
reader.ReadValueSafe(out A);
|
||||
reader.ReadValueSafe(out B);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Handle(ref NetworkContext context)
|
||||
{
|
||||
Handled = true;
|
||||
DeserializedValues.Add(this);
|
||||
}
|
||||
|
||||
public int Version => 1;
|
||||
}
|
||||
|
||||
private struct VersionedTestMessage : INetworkMessage, INetworkSerializeByMemcpy
|
||||
{
|
||||
public int A;
|
||||
public float D;
|
||||
public long E;
|
||||
public static bool Serialized;
|
||||
public static bool Deserialized;
|
||||
public static bool Downgraded;
|
||||
public static bool Upgraded;
|
||||
public static bool Handled;
|
||||
public static List<VersionedTestMessage> DeserializedValues = new List<VersionedTestMessage>();
|
||||
|
||||
public void Serialize(FastBufferWriter writer, int targetVersion)
|
||||
{
|
||||
if (targetVersion < Version)
|
||||
{
|
||||
Downgraded = true;
|
||||
var v1 = new VersionedTestMessage_v1 { A = A, B = k_DefaultB, C = k_DefaultC, D = (int)D };
|
||||
v1.Serialize(writer, targetVersion);
|
||||
return;
|
||||
}
|
||||
SentVersion = Version;
|
||||
Serialized = true;
|
||||
writer.WriteValueSafe(D);
|
||||
writer.WriteValueSafe(A);
|
||||
writer.WriteValueSafe(E);
|
||||
}
|
||||
|
||||
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
|
||||
{
|
||||
if (receivedMessageVersion < Version)
|
||||
{
|
||||
var v1 = new VersionedTestMessage_v1();
|
||||
v1.Deserialize(reader, ref context, receivedMessageVersion);
|
||||
A = v1.A;
|
||||
D = (float)v1.D;
|
||||
E = k_DefaultE;
|
||||
Upgraded = true;
|
||||
return true;
|
||||
}
|
||||
ReceivedVersion = Version;
|
||||
Deserialized = true;
|
||||
reader.ReadValueSafe(out D);
|
||||
reader.ReadValueSafe(out A);
|
||||
reader.ReadValueSafe(out E);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Handle(ref NetworkContext context)
|
||||
{
|
||||
Handled = true;
|
||||
DeserializedValues.Add(this);
|
||||
}
|
||||
|
||||
public int Version => 2;
|
||||
}
|
||||
|
||||
private class TestMessageProvider_v0 : IMessageProvider
|
||||
{
|
||||
public List<MessagingSystem.MessageWithHandler> GetMessages()
|
||||
{
|
||||
return new List<MessagingSystem.MessageWithHandler>
|
||||
{
|
||||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(VersionedTestMessage_v0),
|
||||
Handler = MessagingSystem.ReceiveMessage<VersionedTestMessage_v0>,
|
||||
GetVersion = MessagingSystem.CreateMessageAndGetVersion<VersionedTestMessage_v0>
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class TestMessageProvider_v1 : IMessageProvider
|
||||
{
|
||||
public List<MessagingSystem.MessageWithHandler> GetMessages()
|
||||
{
|
||||
return new List<MessagingSystem.MessageWithHandler>
|
||||
{
|
||||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(VersionedTestMessage_v1),
|
||||
Handler = MessagingSystem.ReceiveMessage<VersionedTestMessage_v1>,
|
||||
GetVersion = MessagingSystem.CreateMessageAndGetVersion<VersionedTestMessage_v1>
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class TestMessageProvider_v2 : IMessageProvider
|
||||
{
|
||||
public List<MessagingSystem.MessageWithHandler> GetMessages()
|
||||
{
|
||||
return new List<MessagingSystem.MessageWithHandler>
|
||||
{
|
||||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(VersionedTestMessage),
|
||||
Handler = MessagingSystem.ReceiveMessage<VersionedTestMessage>,
|
||||
GetVersion = MessagingSystem.CreateMessageAndGetVersion<VersionedTestMessage>
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class TestMessageSender : IMessageSender
|
||||
{
|
||||
public List<byte[]> MessageQueue = new List<byte[]>();
|
||||
|
||||
public void Send(ulong clientId, NetworkDelivery delivery, FastBufferWriter batchData)
|
||||
{
|
||||
MessageQueue.Add(batchData.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private MessagingSystem m_MessagingSystem_v0;
|
||||
private MessagingSystem m_MessagingSystem_v1;
|
||||
private MessagingSystem m_MessagingSystem_v2;
|
||||
private TestMessageSender m_MessageSender;
|
||||
|
||||
private void CreateFakeClients(MessagingSystem system, uint hash)
|
||||
{
|
||||
// Create three fake clients for each messaging system
|
||||
// client 0 has version 0, client 1 has version 1, and client 2 has version 2
|
||||
system.ClientConnected(0);
|
||||
system.ClientConnected(1);
|
||||
system.ClientConnected(2);
|
||||
system.SetVersion(0, hash, 0);
|
||||
system.SetVersion(1, hash, 1);
|
||||
system.SetVersion(2, hash, 2);
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
VersionedTestMessage_v0.Serialized = false;
|
||||
VersionedTestMessage_v0.Deserialized = false;
|
||||
VersionedTestMessage_v0.Handled = false;
|
||||
VersionedTestMessage_v0.DeserializedValues.Clear();
|
||||
VersionedTestMessage_v1.Serialized = false;
|
||||
VersionedTestMessage_v1.Deserialized = false;
|
||||
VersionedTestMessage_v1.Downgraded = false;
|
||||
VersionedTestMessage_v1.Upgraded = false;
|
||||
VersionedTestMessage_v1.Handled = false;
|
||||
VersionedTestMessage_v1.DeserializedValues.Clear();
|
||||
VersionedTestMessage.Serialized = false;
|
||||
VersionedTestMessage.Deserialized = false;
|
||||
VersionedTestMessage.Downgraded = false;
|
||||
VersionedTestMessage.Upgraded = false;
|
||||
VersionedTestMessage.Handled = false;
|
||||
VersionedTestMessage.DeserializedValues.Clear();
|
||||
m_MessageSender = new TestMessageSender();
|
||||
|
||||
m_MessagingSystem_v0 = new MessagingSystem(m_MessageSender, this, new TestMessageProvider_v0());
|
||||
m_MessagingSystem_v1 = new MessagingSystem(m_MessageSender, this, new TestMessageProvider_v1());
|
||||
m_MessagingSystem_v2 = new MessagingSystem(m_MessageSender, this, new TestMessageProvider_v2());
|
||||
|
||||
CreateFakeClients(m_MessagingSystem_v0, XXHash.Hash32(typeof(VersionedTestMessage_v0).FullName));
|
||||
CreateFakeClients(m_MessagingSystem_v1, XXHash.Hash32(typeof(VersionedTestMessage_v1).FullName));
|
||||
CreateFakeClients(m_MessagingSystem_v2, XXHash.Hash32(typeof(VersionedTestMessage).FullName));
|
||||
|
||||
// Make sure that all three messages got the same IDs...
|
||||
Assert.AreEqual(
|
||||
m_MessagingSystem_v0.GetMessageType(typeof(VersionedTestMessage_v0)),
|
||||
m_MessagingSystem_v1.GetMessageType(typeof(VersionedTestMessage_v1)));
|
||||
Assert.AreEqual(
|
||||
m_MessagingSystem_v0.GetMessageType(typeof(VersionedTestMessage_v0)),
|
||||
m_MessagingSystem_v2.GetMessageType(typeof(VersionedTestMessage)));
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
m_MessagingSystem_v0.Dispose();
|
||||
m_MessagingSystem_v1.Dispose();
|
||||
m_MessagingSystem_v2.Dispose();
|
||||
}
|
||||
|
||||
private VersionedTestMessage_v0 GetMessage_v0()
|
||||
{
|
||||
var random = new Random();
|
||||
return new VersionedTestMessage_v0
|
||||
{
|
||||
A = random.Next(),
|
||||
B = random.Next(),
|
||||
C = random.Next(),
|
||||
};
|
||||
}
|
||||
|
||||
private VersionedTestMessage_v1 GetMessage_v1()
|
||||
{
|
||||
var random = new Random();
|
||||
return new VersionedTestMessage_v1
|
||||
{
|
||||
A = random.Next(),
|
||||
B = random.Next(),
|
||||
C = random.Next(),
|
||||
D = random.Next(),
|
||||
};
|
||||
}
|
||||
|
||||
private VersionedTestMessage GetMessage_v2()
|
||||
{
|
||||
var random = new Random();
|
||||
return new VersionedTestMessage
|
||||
{
|
||||
A = random.Next(),
|
||||
D = (float)(random.NextDouble() * 10000),
|
||||
E = ((long)random.Next() << 32) + random.Next()
|
||||
};
|
||||
}
|
||||
|
||||
public void CheckPostSendExpectations(int sourceLocalVersion, int remoteVersion)
|
||||
{
|
||||
Assert.AreEqual(Math.Min(sourceLocalVersion, remoteVersion) == 0, VersionedTestMessage_v0.Serialized);
|
||||
Assert.AreEqual(Math.Min(sourceLocalVersion, remoteVersion) == 1, VersionedTestMessage_v1.Serialized);
|
||||
Assert.AreEqual(Math.Min(sourceLocalVersion, remoteVersion) == 2, VersionedTestMessage.Serialized);
|
||||
Assert.AreEqual(sourceLocalVersion >= 1 && remoteVersion < 1, VersionedTestMessage_v1.Downgraded);
|
||||
Assert.AreEqual(sourceLocalVersion >= 2 && remoteVersion < 2, VersionedTestMessage.Downgraded);
|
||||
|
||||
Assert.AreEqual(1, m_MessageSender.MessageQueue.Count);
|
||||
Assert.AreEqual(Math.Min(sourceLocalVersion, remoteVersion), SentVersion);
|
||||
}
|
||||
|
||||
public void CheckPostReceiveExpectations(int sourceLocalVersion, int remoteVersion)
|
||||
{
|
||||
Assert.AreEqual(SentVersion == 0, VersionedTestMessage_v0.Deserialized);
|
||||
Assert.AreEqual(SentVersion == 1, VersionedTestMessage_v1.Deserialized);
|
||||
Assert.AreEqual(SentVersion == 2, VersionedTestMessage.Deserialized);
|
||||
Assert.AreEqual(remoteVersion >= 1 && sourceLocalVersion < 1, VersionedTestMessage_v1.Upgraded);
|
||||
Assert.AreEqual(remoteVersion >= 2 && sourceLocalVersion < 2, VersionedTestMessage.Upgraded);
|
||||
|
||||
Assert.AreEqual((remoteVersion == 0 ? 1 : 0), VersionedTestMessage_v0.DeserializedValues.Count);
|
||||
Assert.AreEqual((remoteVersion == 1 ? 1 : 0), VersionedTestMessage_v1.DeserializedValues.Count);
|
||||
Assert.AreEqual((remoteVersion == 2 ? 1 : 0), VersionedTestMessage.DeserializedValues.Count);
|
||||
|
||||
Assert.AreEqual(SentVersion, ReceivedVersion);
|
||||
}
|
||||
|
||||
private void SendMessageWithVersions<T>(T message, int fromVersion, int toVersion) where T : unmanaged, INetworkMessage
|
||||
{
|
||||
MessagingSystem sendSystem;
|
||||
switch (fromVersion)
|
||||
{
|
||||
case 0: sendSystem = m_MessagingSystem_v0; break;
|
||||
case 1: sendSystem = m_MessagingSystem_v1; break;
|
||||
default: sendSystem = m_MessagingSystem_v2; break;
|
||||
}
|
||||
sendSystem.SendMessage(ref message, NetworkDelivery.Reliable, (ulong)toVersion);
|
||||
sendSystem.ProcessSendQueues();
|
||||
CheckPostSendExpectations(fromVersion, toVersion);
|
||||
|
||||
MessagingSystem receiveSystem;
|
||||
switch (toVersion)
|
||||
{
|
||||
case 0: receiveSystem = m_MessagingSystem_v0; break;
|
||||
case 1: receiveSystem = m_MessagingSystem_v1; break;
|
||||
default: receiveSystem = m_MessagingSystem_v2; break;
|
||||
}
|
||||
receiveSystem.HandleIncomingData((ulong)fromVersion, new ArraySegment<byte>(m_MessageSender.MessageQueue[0]), 0.0f);
|
||||
receiveSystem.ProcessIncomingMessageQueue();
|
||||
CheckPostReceiveExpectations(fromVersion, toVersion);
|
||||
|
||||
m_MessageSender.MessageQueue.Clear();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSendingV0ToV0_DataIsReceivedCorrectly()
|
||||
{
|
||||
var message = GetMessage_v0();
|
||||
|
||||
SendMessageWithVersions(message, 0, 0);
|
||||
|
||||
var receivedMessage = VersionedTestMessage_v0.DeserializedValues[0];
|
||||
Assert.AreEqual(message.A, receivedMessage.A);
|
||||
Assert.AreEqual(message.B, receivedMessage.B);
|
||||
Assert.AreEqual(message.C, receivedMessage.C);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSendingV0ToV1_DataIsReceivedCorrectly()
|
||||
{
|
||||
var message = GetMessage_v0();
|
||||
|
||||
SendMessageWithVersions(message, 0, 1);
|
||||
|
||||
var receivedMessage = VersionedTestMessage_v1.DeserializedValues[0];
|
||||
Assert.AreEqual(message.A, receivedMessage.A);
|
||||
Assert.AreEqual(message.B, receivedMessage.B);
|
||||
Assert.AreEqual(message.C, receivedMessage.C);
|
||||
Assert.AreEqual(k_DefaultD, receivedMessage.D);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSendingV0ToV2_DataIsReceivedCorrectly()
|
||||
{
|
||||
var message = GetMessage_v0();
|
||||
|
||||
SendMessageWithVersions(message, 0, 2);
|
||||
|
||||
var receivedMessage = VersionedTestMessage.DeserializedValues[0];
|
||||
Assert.AreEqual(message.A, receivedMessage.A);
|
||||
Assert.AreEqual((float)k_DefaultD, receivedMessage.D);
|
||||
Assert.AreEqual(k_DefaultE, receivedMessage.E);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSendingV1ToV0_DataIsReceivedCorrectly()
|
||||
{
|
||||
var message = GetMessage_v1();
|
||||
|
||||
SendMessageWithVersions(message, 1, 0);
|
||||
|
||||
var receivedMessage = VersionedTestMessage_v0.DeserializedValues[0];
|
||||
Assert.AreEqual(message.A, receivedMessage.A);
|
||||
Assert.AreEqual(message.B, receivedMessage.B);
|
||||
Assert.AreEqual(message.C, receivedMessage.C);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSendingV1ToV1_DataIsReceivedCorrectly()
|
||||
{
|
||||
var message = GetMessage_v1();
|
||||
|
||||
SendMessageWithVersions(message, 1, 1);
|
||||
|
||||
var receivedMessage = VersionedTestMessage_v1.DeserializedValues[0];
|
||||
Assert.AreEqual(message.A, receivedMessage.A);
|
||||
Assert.AreEqual(message.B, receivedMessage.B);
|
||||
Assert.AreEqual(message.C, receivedMessage.C);
|
||||
Assert.AreEqual(message.D, receivedMessage.D);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSendingV1ToV2_DataIsReceivedCorrectly()
|
||||
{
|
||||
var message = GetMessage_v1();
|
||||
|
||||
SendMessageWithVersions(message, 1, 2);
|
||||
|
||||
var receivedMessage = VersionedTestMessage.DeserializedValues[0];
|
||||
Assert.AreEqual(message.A, receivedMessage.A);
|
||||
Assert.AreEqual((float)message.D, receivedMessage.D);
|
||||
Assert.AreEqual(k_DefaultE, receivedMessage.E);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSendingV2ToV0_DataIsReceivedCorrectly()
|
||||
{
|
||||
var message = GetMessage_v2();
|
||||
|
||||
SendMessageWithVersions(message, 2, 0);
|
||||
|
||||
var receivedMessage = VersionedTestMessage_v0.DeserializedValues[0];
|
||||
Assert.AreEqual(message.A, receivedMessage.A);
|
||||
Assert.AreEqual(k_DefaultB, receivedMessage.B);
|
||||
Assert.AreEqual(k_DefaultC, receivedMessage.C);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSendingV2ToV1_DataIsReceivedCorrectly()
|
||||
{
|
||||
var message = GetMessage_v2();
|
||||
|
||||
SendMessageWithVersions(message, 2, 1);
|
||||
|
||||
var receivedMessage = VersionedTestMessage_v1.DeserializedValues[0];
|
||||
Assert.AreEqual(message.A, receivedMessage.A);
|
||||
Assert.AreEqual(k_DefaultB, receivedMessage.B);
|
||||
Assert.AreEqual(k_DefaultC, receivedMessage.C);
|
||||
Assert.AreEqual((int)message.D, receivedMessage.D);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSendingV2ToV2_DataIsReceivedCorrectly()
|
||||
{
|
||||
var message = GetMessage_v2();
|
||||
|
||||
SendMessageWithVersions(message, 2, 2);
|
||||
|
||||
var receivedMessage = VersionedTestMessage.DeserializedValues[0];
|
||||
Assert.AreEqual(message.A, receivedMessage.A);
|
||||
Assert.AreEqual(message.D, receivedMessage.D);
|
||||
Assert.AreEqual(message.E, receivedMessage.E);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: eac9a654aacb4faf91128c9ab6024543
|
||||
timeCreated: 1667326658
|
|
@ -52,7 +52,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
|
|||
OwnerClientId = newOwner
|
||||
};
|
||||
using var writer = new FastBufferWriter(1024, Allocator.Temp);
|
||||
message.Serialize(writer);
|
||||
message.Serialize(writer, message.Version);
|
||||
return writer.Length;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Unity.Netcode.RuntimeTests.Metrics
|
|||
Message = logMessage
|
||||
};
|
||||
using var writer = new FastBufferWriter(1024, Allocator.Temp);
|
||||
message.Serialize(writer);
|
||||
message.Serialize(writer, message.Version);
|
||||
return writer.Length;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче