com.unity.netcode.gameobjects@1.0.0-pre.6

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com).

## [1.0.0-pre.6] - 2022-03-02

### Added
- NetworkAnimator now properly synchrhonizes all animation layers as well as runtime-adjusted weighting between them (#1765)
- Added first set of tests for NetworkAnimator - parameter syncing, trigger set / reset, override network animator (#1735)

### Changed

### Fixed
- Fixed an issue where sometimes the first client to connect to the server could see messages from the server as coming from itself. (#1683)
- Fixed an issue where clients seemed to be able to send messages to ClientId 1, but these messages would actually still go to the server (id 0) instead of that client. (#1683)
- Improved clarity of error messaging when a client attempts to send a message to a destination other than the server, which isn't allowed. (#1683)
- Disallowed async keyword in RPCs (#1681)
- Fixed an issue where Alpha release versions of Unity (version 2022.2.0a5 and later) will not compile due to the UNet Transport no longer existing (#1678)
- Fixed messages larger than 64k being written with incorrectly truncated message size in header (#1686) (credit: @kaen)
- Fixed overloading RPC methods causing collisions and failing on IL2CPP targets. (#1694)
- Fixed spawn flow to propagate `IsSceneObject` down to children NetworkObjects, decouple implicit relationship between object spawning & `IsSceneObject` flag (#1685)
- Fixed error when serializing ConnectionApprovalMessage with scene management disabled when one or more objects is hidden via the CheckObjectVisibility delegate (#1720)
- Fixed CheckObjectVisibility delegate not being properly invoked for connecting clients when Scene Management is enabled. (#1680)
- Fixed NetworkList to properly call INetworkSerializable's NetworkSerialize() method (#1682)
- Fixed NetworkVariables containing more than 1300 bytes of data (such as large NetworkLists) no longer cause an OverflowException (the limit on data size is now whatever limit the chosen transport imposes on fragmented NetworkDelivery mechanisms) (#1725)
- Fixed ServerRpcParams and ClientRpcParams must be the last parameter of an RPC in order to function properly. Added a compile-time check to ensure this is the case and trigger an error if they're placed elsewhere (#1721)
- Fixed FastBufferReader being created with a length of 1 if provided an input of length 0 (#1724)
- Fixed The NetworkConfig's checksum hash includes the NetworkTick so that clients with a different tickrate than the server are identified and not allowed to connect (#1728)
- Fixed OwnedObjects not being properly modified when using ChangeOwnership (#1731)
- Improved performance in NetworkAnimator (#1735)
- Removed the "always sync" network animator (aka "autosend") parameters (#1746)
This commit is contained in:
Unity Technologies
2022-03-02 00:00:00 +00:00
parent 4818405514
commit 5b4aaa8b59
205 changed files with 6971 additions and 2722 deletions

View File

@@ -0,0 +1,70 @@
using System;
namespace Unity.Netcode.TestHelpers.Runtime
{
internal class MessageHooks : INetworkHooks
{
public bool IsWaiting;
public delegate bool MessageReceiptCheck(object receivedMessage);
public MessageReceiptCheck ReceiptCheck;
public static bool CheckForMessageOfType<T>(object receivedMessage) where T : INetworkMessage
{
return receivedMessage is T;
}
public void OnBeforeSendMessage<T>(ulong clientId, ref T message, NetworkDelivery delivery) where T : INetworkMessage
{
}
public void OnAfterSendMessage<T>(ulong clientId, ref T message, NetworkDelivery delivery, int messageSizeBytes) where T : INetworkMessage
{
}
public void OnBeforeReceiveMessage(ulong senderId, Type messageType, int messageSizeBytes)
{
}
public void OnAfterReceiveMessage(ulong senderId, Type messageType, int messageSizeBytes)
{
}
public void OnBeforeSendBatch(ulong clientId, int messageCount, int batchSizeInBytes, NetworkDelivery delivery)
{
}
public void OnAfterSendBatch(ulong clientId, int messageCount, int batchSizeInBytes, NetworkDelivery delivery)
{
}
public void OnBeforeReceiveBatch(ulong senderId, int messageCount, int batchSizeInBytes)
{
}
public void OnAfterReceiveBatch(ulong senderId, int messageCount, int batchSizeInBytes)
{
}
public bool OnVerifyCanSend(ulong destinationId, Type messageType, NetworkDelivery delivery)
{
return true;
}
public bool OnVerifyCanReceive(ulong senderId, Type messageType)
{
return true;
}
public void OnBeforeHandleMessage<T>(ref T message, ref NetworkContext context) where T : INetworkMessage
{
}
public void OnAfterHandleMessage<T>(ref T message, ref NetworkContext context) where T : INetworkMessage
{
if (IsWaiting && (ReceiptCheck == null || ReceiptCheck.Invoke(message)))
{
IsWaiting = false;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e860701e80ca3be4d8cb89d340faebd1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,95 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
namespace Unity.Netcode.TestHelpers.Runtime
{
public class MessageHooksConditional : ConditionalPredicateBase
{
private List<MessageHookEntry> m_MessageHookEntries;
public bool AllMessagesReceived { get; internal set; }
public int NumberOfMessagesReceived
{
get
{
return m_MessageHookEntries.Where((c) => !c.MessageHooks.IsWaiting).Count();
}
}
public string GetHooksStillWaiting()
{
var retMessageTypes = string.Empty;
var waitingMessages = m_MessageHookEntries.Where((c) => c.MessageHooks.IsWaiting);
foreach (var waitingMessage in waitingMessages)
{
retMessageTypes += $":{waitingMessage.MessageType}:";
}
return retMessageTypes;
}
protected override bool OnHasConditionBeenReached()
{
AllMessagesReceived = NumberOfMessagesReceived == m_MessageHookEntries.Count;
if (AllMessagesReceived)
{
return AllMessagesReceived;
}
return AllMessagesReceived;
}
protected override void OnFinished()
{
base.OnFinished();
}
public void Reset()
{
foreach (var entry in m_MessageHookEntries)
{
entry.Initialize();
}
}
public MessageHooksConditional(List<MessageHookEntry> messageHookEntries)
{
m_MessageHookEntries = messageHookEntries;
}
}
public class MessageHookEntry
{
internal MessageHooks MessageHooks;
protected NetworkManager m_NetworkManager;
private MessageHooks.MessageReceiptCheck m_MessageReceiptCheck;
internal string MessageType;
public void Initialize()
{
Assert.IsNotNull(m_MessageReceiptCheck, $"{nameof(m_MessageReceiptCheck)} is null, did you forget to initialize?");
MessageHooks = new MessageHooks();
MessageHooks.ReceiptCheck = m_MessageReceiptCheck;
Assert.IsNotNull(m_NetworkManager.MessagingSystem, $"{nameof(NetworkManager.MessagingSystem)} is null! Did you forget to start first?");
m_NetworkManager.MessagingSystem.Hook(MessageHooks);
}
internal void AssignMessageType<T>() where T : INetworkMessage
{
MessageType = typeof(T).Name;
m_MessageReceiptCheck = MessageHooks.CheckForMessageOfType<T>;
Initialize();
}
public MessageHookEntry(NetworkManager networkManager)
{
m_NetworkManager = networkManager;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2a97b3c56f3b2ba42a0669716e81674f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,267 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.Netcode.TestHelpers.Runtime
{
/// <summary>
/// SIPTransport (SIngleProcessTransport)
/// is a NetworkTransport designed to be used with multiple network instances in a single process
/// it's designed for the netcode in a way where no networking stack has to be available
/// it's designed for testing purposes and it's not designed with speed in mind
/// </summary>
public class SIPTransport : TestingNetworkTransport
{
private struct Event
{
public NetworkEvent Type;
public ulong ConnectionId;
public ArraySegment<byte> Data;
}
private class Peer
{
public ulong ConnectionId;
public SIPTransport Transport;
public Queue<Event> IncomingBuffer = new Queue<Event>();
}
private readonly Dictionary<ulong, Peer> m_Peers = new Dictionary<ulong, Peer>();
private ulong m_ClientsCounter = 1;
private static Peer s_Server;
private Peer m_LocalConnection;
public override ulong ServerClientId => 0;
public ulong LocalClientId;
public override void DisconnectLocalClient()
{
if (m_LocalConnection != null)
{
// Inject local disconnect
m_LocalConnection.IncomingBuffer.Enqueue(new Event
{
Type = NetworkEvent.Disconnect,
ConnectionId = m_LocalConnection.ConnectionId,
Data = new ArraySegment<byte>()
});
if (s_Server != null && m_LocalConnection != null)
{
// Remove the connection
s_Server.Transport.m_Peers.Remove(m_LocalConnection.ConnectionId);
}
if (m_LocalConnection.ConnectionId == ServerClientId)
{
StopServer();
}
// Remove the local connection
m_LocalConnection = null;
}
}
// Called by server
public override void DisconnectRemoteClient(ulong clientId)
{
if (m_Peers.ContainsKey(clientId))
{
// Inject disconnect into remote
m_Peers[clientId].IncomingBuffer.Enqueue(new Event
{
Type = NetworkEvent.Disconnect,
ConnectionId = clientId,
Data = new ArraySegment<byte>()
});
// Inject local disconnect
m_LocalConnection.IncomingBuffer.Enqueue(new Event
{
Type = NetworkEvent.Disconnect,
ConnectionId = clientId,
Data = new ArraySegment<byte>()
});
// Remove the local connection on remote
m_Peers[clientId].Transport.m_LocalConnection = null;
// Remove connection on server
m_Peers.Remove(clientId);
}
}
public override ulong GetCurrentRtt(ulong clientId)
{
// Always returns 50ms
return 50;
}
public override void Initialize(NetworkManager networkManager = null)
{
}
private void StopServer()
{
s_Server = null;
m_Peers.Remove(ServerClientId);
m_LocalConnection = null;
}
public override void Shutdown()
{
// Inject disconnects to all the remotes
foreach (KeyValuePair<ulong, Peer> onePeer in m_Peers)
{
onePeer.Value.IncomingBuffer.Enqueue(new Event
{
Type = NetworkEvent.Disconnect,
ConnectionId = LocalClientId,
Data = new ArraySegment<byte>()
});
}
if (m_LocalConnection != null && m_LocalConnection.ConnectionId == ServerClientId)
{
StopServer();
}
// TODO: Cleanup
}
public override bool StartClient()
{
if (s_Server == null)
{
// No server
Debug.LogError("No server");
return false;
}
if (m_LocalConnection != null)
{
// Already connected
Debug.LogError("Already connected");
return false;
}
// Generate an Id for the server that represents this client
ulong serverConnectionId = ++s_Server.Transport.m_ClientsCounter;
LocalClientId = serverConnectionId;
// Create local connection
m_LocalConnection = new Peer()
{
ConnectionId = serverConnectionId,
Transport = this,
IncomingBuffer = new Queue<Event>()
};
// Add the server as a local connection
m_Peers.Add(ServerClientId, s_Server);
// Add local connection as a connection on the server
s_Server.Transport.m_Peers.Add(serverConnectionId, m_LocalConnection);
// Sends a connect message to the server
s_Server.Transport.m_LocalConnection.IncomingBuffer.Enqueue(new Event()
{
Type = NetworkEvent.Connect,
ConnectionId = serverConnectionId,
Data = new ArraySegment<byte>()
});
// Send a local connect message
m_LocalConnection.IncomingBuffer.Enqueue(new Event
{
Type = NetworkEvent.Connect,
ConnectionId = ServerClientId,
Data = new ArraySegment<byte>()
});
return true;
}
public override bool StartServer()
{
if (s_Server != null)
{
// Can only have one server
Debug.LogError("Server already started");
return false;
}
if (m_LocalConnection != null)
{
// Already connected
Debug.LogError("Already connected");
return false;
}
// Create local connection
m_LocalConnection = new Peer()
{
ConnectionId = ServerClientId,
Transport = this,
IncomingBuffer = new Queue<Event>()
};
// Set the local connection as the server
s_Server = m_LocalConnection;
m_Peers.Add(ServerClientId, s_Server);
return true;
}
public override void Send(ulong clientId, ArraySegment<byte> payload, NetworkDelivery networkDelivery)
{
if (m_LocalConnection != null)
{
// Create copy since netcode wants the byte array back straight after the method call.
// Hard on GC.
byte[] copy = new byte[payload.Count];
Buffer.BlockCopy(payload.Array, payload.Offset, copy, 0, payload.Count);
if (m_Peers.ContainsKey(clientId))
{
m_Peers[clientId].IncomingBuffer.Enqueue(new Event
{
Type = NetworkEvent.Data,
ConnectionId = m_LocalConnection.ConnectionId,
Data = new ArraySegment<byte>(copy)
});
}
}
}
public override NetworkEvent PollEvent(out ulong clientId, out ArraySegment<byte> payload, out float receiveTime)
{
if (m_LocalConnection != null)
{
if (m_LocalConnection.IncomingBuffer.Count == 0)
{
clientId = 0;
payload = new ArraySegment<byte>();
receiveTime = 0;
return NetworkEvent.Nothing;
}
var peerEvent = m_LocalConnection.IncomingBuffer.Dequeue();
clientId = peerEvent.ConnectionId;
payload = peerEvent.Data;
receiveTime = 0;
return peerEvent.Type;
}
clientId = 0;
payload = new ArraySegment<byte>();
receiveTime = 0;
return NetworkEvent.Nothing;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1fd1b14eba874a189f13f12d343c331c
timeCreated: 1620145176