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

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.7] - 2022-04-01

### Added

- Added editor only check prior to entering into play mode if the currently open and active scene is in the build list and if not displays a dialog box asking the user if they would like to automatically add it prior to entering into play mode. (#1828)
- Added `UnityTransport` implementation and `com.unity.transport` package dependency (#1823)
- Added `NetworkVariableWritePermission` to `NetworkVariableBase` and implemented `Owner` client writable netvars. (#1762)
- `UnityTransport` settings can now be set programmatically. (#1845)
- `FastBufferWriter` and Reader IsInitialized property. (#1859)

### Changed

- Updated `UnityTransport` dependency on `com.unity.transport` to 1.0.0 (#1849)

### Removed

- Removed `SnapshotSystem` (#1852)
- Removed `com.unity.modules.animation`, `com.unity.modules.physics` and `com.unity.modules.physics2d` dependencies from the package (#1812)
- Removed `com.unity.collections` dependency from the package (#1849)

### Fixed
- Fixed in-scene placed NetworkObjects not being found/ignored after a client disconnects and then reconnects. (#1850)
- Fixed issue where `UnityTransport` send queues were not flushed when calling `DisconnectLocalClient` or `DisconnectRemoteClient`. (#1847)
- Fixed NetworkBehaviour dependency verification check for an existing NetworkObject not searching from root parent transform relative GameObject. (#1841)
- Fixed issue where entries were not being removed from the NetworkSpawnManager.OwnershipToObjectsTable. (#1838)
- Fixed ClientRpcs would always send to all connected clients by default as opposed to only sending to the NetworkObject's Observers list by default. (#1836)
- Fixed clarity for NetworkSceneManager client side notification when it receives a scene hash value that does not exist in its local hash table. (#1828)
- Fixed client throws a key not found exception when it times out using UNet or UTP. (#1821)
- Fixed network variable updates are no longer limited to 32,768 bytes when NetworkConfig.EnsureNetworkVariableLengthSafety is enabled. The limits are now determined by what the transport can send in a message. (#1811)
- Fixed in-scene NetworkObjects get destroyed if a client fails to connect and shuts down the NetworkManager. (#1809)
- Fixed user never being notified in the editor that a NetworkBehaviour requires a NetworkObject to function properly. (#1808)
- Fixed PlayerObjects and dynamically spawned NetworkObjects not being added to the NetworkClient's OwnedObjects (#1801)
- Fixed issue where NetworkManager would continue starting even if the NetworkTransport selected failed. (#1780)
- Fixed issue when spawning new player if an already existing player exists it does not remove IsPlayer from the previous player (#1779)
- Fixed lack of notification that NetworkManager and NetworkObject cannot be added to the same GameObject with in-editor notifications (#1777)
- Fixed parenting warning printing for false positives (#1855)
This commit is contained in:
Unity Technologies
2022-04-01 00:00:00 +00:00
parent 5b4aaa8b59
commit 60e2dabef4
123 changed files with 5751 additions and 3419 deletions

View File

@@ -158,37 +158,57 @@ namespace Unity.Netcode
// We check to see if we need to shortcut for the case where we are the host/server and we can send a clientRPC
// to ourself. Sadly we have to figure that out from the list of clientIds :(
bool shouldSendToHost = false;
if (clientRpcParams.Send.TargetClientIds != null)
{
foreach (var clientId in clientRpcParams.Send.TargetClientIds)
foreach (var targetClientId in clientRpcParams.Send.TargetClientIds)
{
if (clientId == NetworkManager.ServerClientId)
if (targetClientId == NetworkManager.ServerClientId)
{
shouldSendToHost = true;
break;
}
// Check to make sure we are sending to only observers, if not log an error.
if (NetworkManager.LogLevel >= LogLevel.Error && !NetworkObject.Observers.Contains(targetClientId))
{
NetworkLog.LogError(GenerateObserverErrorMessage(clientRpcParams, targetClientId));
}
}
rpcWriteSize = NetworkManager.SendMessage(ref clientRpcMessage, networkDelivery, in clientRpcParams.Send.TargetClientIds);
}
else if (clientRpcParams.Send.TargetClientIdsNativeArray != null)
{
foreach (var clientId in clientRpcParams.Send.TargetClientIdsNativeArray)
foreach (var targetClientId in clientRpcParams.Send.TargetClientIdsNativeArray)
{
if (clientId == NetworkManager.ServerClientId)
if (targetClientId == NetworkManager.ServerClientId)
{
shouldSendToHost = true;
break;
}
// Check to make sure we are sending to only observers, if not log an error.
if (NetworkManager.LogLevel >= LogLevel.Error && !NetworkObject.Observers.Contains(targetClientId))
{
NetworkLog.LogError(GenerateObserverErrorMessage(clientRpcParams, targetClientId));
}
}
rpcWriteSize = NetworkManager.SendMessage(ref clientRpcMessage, networkDelivery, clientRpcParams.Send.TargetClientIdsNativeArray.Value);
}
else
{
shouldSendToHost = IsHost;
rpcWriteSize = NetworkManager.SendMessage(ref clientRpcMessage, networkDelivery, NetworkManager.ConnectedClientsIds);
var observerEnumerator = NetworkObject.Observers.GetEnumerator();
while (observerEnumerator.MoveNext())
{
// Skip over the host
if (IsHost && observerEnumerator.Current == NetworkManager.LocalClientId)
{
shouldSendToHost = true;
continue;
}
rpcWriteSize = NetworkManager.MessagingSystem.SendMessage(ref clientRpcMessage, networkDelivery, observerEnumerator.Current);
}
}
// If we are a server/host then we just no op and send to ourself
@@ -228,6 +248,12 @@ namespace Unity.Netcode
#endif
}
internal string GenerateObserverErrorMessage(ClientRpcParams clientRpcParams, ulong targetClientId)
{
var containerNameHoldingId = clientRpcParams.Send.TargetClientIds != null ? nameof(ClientRpcParams.Send.TargetClientIds) : nameof(ClientRpcParams.Send.TargetClientIdsNativeArray);
return $"Sending ClientRpc to non-observer! {containerNameHoldingId} contains clientId {targetClientId} that is not an observer!";
}
/// <summary>
/// Gets the NetworkManager that owns this NetworkBehaviour instance
/// See note around `NetworkObject` for how there is a chicken / egg problem when we are not initialized
@@ -235,42 +261,42 @@ namespace Unity.Netcode
public NetworkManager NetworkManager => NetworkObject.NetworkManager;
/// <summary>
/// Gets if the object is the the personal clients player object
/// If a NetworkObject is assigned, it will return whether or not this NetworkObject
/// is the local player object. If no NetworkObject is assigned it will always return false.
/// </summary>
public bool IsLocalPlayer => NetworkObject.IsLocalPlayer;
public bool IsLocalPlayer { get; private set; }
/// <summary>
/// Gets if the object is owned by the local player or if the object is the local player object
/// </summary>
public bool IsOwner => NetworkObject.IsOwner;
public bool IsOwner { get; internal set; }
/// <summary>
/// Gets if we are executing as server
/// </summary>
protected bool IsServer => IsRunning && NetworkManager.IsServer;
protected bool IsServer { get; private set; }
/// <summary>
/// Gets if we are executing as client
/// </summary>
protected bool IsClient => IsRunning && NetworkManager.IsClient;
protected bool IsClient { get; private set; }
/// <summary>
/// Gets if we are executing as Host, I.E Server and Client
/// </summary>
protected bool IsHost => IsRunning && NetworkManager.IsHost;
private bool IsRunning => NetworkManager && NetworkManager.IsListening;
protected bool IsHost { get; private set; }
/// <summary>
/// Gets Whether or not the object has a owner
/// </summary>
public bool IsOwnedByServer => NetworkObject.IsOwnedByServer;
public bool IsOwnedByServer { get; internal set; }
/// <summary>
/// Used to determine if it is safe to access NetworkObject and NetworkManager from within a NetworkBehaviour component
/// Primarily useful when checking NetworkObject/NetworkManager properties within FixedUpate
/// </summary>
public bool IsSpawned => HasNetworkObject ? NetworkObject.IsSpawned : false;
public bool IsSpawned { get; internal set; }
internal bool IsBehaviourEditable()
{
@@ -327,12 +353,12 @@ namespace Unity.Netcode
/// <summary>
/// Gets the NetworkId of the NetworkObject that owns this NetworkBehaviour
/// </summary>
public ulong NetworkObjectId => NetworkObject.NetworkObjectId;
public ulong NetworkObjectId { get; internal set; }
/// <summary>
/// Gets NetworkId for this NetworkBehaviour from the owner NetworkObject
/// </summary>
public ushort NetworkBehaviourId => NetworkObject.GetNetworkBehaviourOrderIndex(this);
public ushort NetworkBehaviourId { get; internal set; }
/// <summary>
/// Internally caches the Id of this behaviour in a NetworkObject. Makes look-up faster
@@ -352,7 +378,47 @@ namespace Unity.Netcode
/// <summary>
/// Gets the ClientId that owns the NetworkObject
/// </summary>
public ulong OwnerClientId => NetworkObject.OwnerClientId;
public ulong OwnerClientId { get; internal set; }
/// <summary>
/// Updates properties with network session related
/// dependencies such as a NetworkObject's spawned
/// state or NetworkManager's session state.
/// </summary>
internal void UpdateNetworkProperties()
{
// Set NetworkObject dependent properties
if (NetworkObject != null)
{
// Set identification related properties
NetworkObjectId = NetworkObject.NetworkObjectId;
IsLocalPlayer = NetworkObject.IsLocalPlayer;
// This is "OK" because GetNetworkBehaviourOrderIndex uses the order of
// NetworkObject.ChildNetworkBehaviours which is set once when first
// accessed.
NetworkBehaviourId = NetworkObject.GetNetworkBehaviourOrderIndex(this);
// Set ownership related properties
IsOwnedByServer = NetworkObject.IsOwnedByServer;
IsOwner = NetworkObject.IsOwner;
OwnerClientId = NetworkObject.OwnerClientId;
// Set NetworkManager dependent properties
if (NetworkManager != null)
{
IsHost = NetworkManager.IsListening && NetworkManager.IsHost;
IsClient = NetworkManager.IsListening && NetworkManager.IsClient;
IsServer = NetworkManager.IsListening && NetworkManager.IsServer;
}
}
else // Shouldn't happen, but if so then set the properties to their default value;
{
OwnerClientId = NetworkObjectId = default;
IsOwnedByServer = IsOwner = IsHost = IsClient = IsServer = default;
NetworkBehaviourId = default;
}
}
/// <summary>
/// Gets called when the <see cref="NetworkObject"/> gets spawned, message handlers are ready to be registered and the network is setup.
@@ -366,21 +432,41 @@ namespace Unity.Netcode
internal void InternalOnNetworkSpawn()
{
IsSpawned = true;
InitializeVariables();
UpdateNetworkProperties();
OnNetworkSpawn();
}
internal void InternalOnNetworkDespawn() { }
internal void InternalOnNetworkDespawn()
{
IsSpawned = false;
UpdateNetworkProperties();
OnNetworkDespawn();
}
/// <summary>
/// Gets called when the local client gains ownership of this object
/// </summary>
public virtual void OnGainedOwnership() { }
internal void InternalOnGainedOwnership()
{
UpdateNetworkProperties();
OnGainedOwnership();
}
/// <summary>
/// Gets called when we loose ownership of this object
/// </summary>
public virtual void OnLostOwnership() { }
internal void InternalOnLostOwnership()
{
UpdateNetworkProperties();
OnLostOwnership();
}
/// <summary>
/// Gets called when the parent NetworkObject of this NetworkBehaviour's NetworkObject has changed
/// </summary>
@@ -433,12 +519,10 @@ namespace Unity.Netcode
m_VarInit = true;
FieldInfo[] sortedFields = GetFieldInfoForType(GetType());
var sortedFields = GetFieldInfoForType(GetType());
for (int i = 0; i < sortedFields.Length; i++)
{
Type fieldType = sortedFields[i].FieldType;
var fieldType = sortedFields[i].FieldType;
if (fieldType.IsSubclassOf(typeof(NetworkVariableBase)))
{
var instance = (NetworkVariableBase)sortedFields[i].GetValue(this);
@@ -499,7 +583,7 @@ namespace Unity.Netcode
}
}
internal void VariableUpdate(ulong clientId)
internal void VariableUpdate(ulong targetClientId)
{
if (!m_VarInit)
{
@@ -507,67 +591,58 @@ namespace Unity.Netcode
}
PreNetworkVariableWrite();
NetworkVariableUpdate(clientId, NetworkBehaviourId);
NetworkVariableUpdate(targetClientId, NetworkBehaviourId);
}
internal readonly List<int> NetworkVariableIndexesToReset = new List<int>();
internal readonly HashSet<int> NetworkVariableIndexesToResetSet = new HashSet<int>();
private void NetworkVariableUpdate(ulong clientId, int behaviourIndex)
private void NetworkVariableUpdate(ulong targetClientId, int behaviourIndex)
{
if (!CouldHaveDirtyNetworkVariables())
{
return;
}
if (NetworkManager.NetworkConfig.UseSnapshotDelta)
for (int j = 0; j < m_DeliveryMappedNetworkVariableIndices.Count; j++)
{
var shouldSend = false;
for (int k = 0; k < NetworkVariableFields.Count; k++)
{
NetworkManager.SnapshotSystem.Store(NetworkObjectId, behaviourIndex, k, NetworkVariableFields[k]);
}
}
if (!NetworkManager.NetworkConfig.UseSnapshotDelta)
{
for (int j = 0; j < m_DeliveryMappedNetworkVariableIndices.Count; j++)
{
var shouldSend = false;
for (int k = 0; k < NetworkVariableFields.Count; k++)
var networkVariable = NetworkVariableFields[k];
if (networkVariable.IsDirty() && networkVariable.CanClientRead(targetClientId))
{
if (NetworkVariableFields[k].ShouldWrite(clientId, IsServer))
shouldSend = true;
break;
}
}
if (shouldSend)
{
var message = new NetworkVariableDeltaMessage
{
NetworkObjectId = NetworkObjectId,
NetworkBehaviourIndex = NetworkObject.GetNetworkBehaviourOrderIndex(this),
NetworkBehaviour = this,
TargetClientId = targetClientId,
DeliveryMappedNetworkVariableIndex = m_DeliveryMappedNetworkVariableIndices[j]
};
// TODO: Serialization is where the IsDirty flag gets changed.
// Messages don't get sent from the server to itself, so if we're host and sending to ourselves,
// we still have to actually serialize the message even though we're not sending it, otherwise
// the dirty flag doesn't change properly. These two pieces should be decoupled at some point
// so we don't have to do this serialization work if we're not going to use the result.
if (IsServer && targetClientId == NetworkManager.ServerClientId)
{
var tmpWriter = new FastBufferWriter(MessagingSystem.NON_FRAGMENTED_MESSAGE_MAX_SIZE, Allocator.Temp, MessagingSystem.FRAGMENTED_MESSAGE_MAX_SIZE);
using (tmpWriter)
{
shouldSend = true;
message.Serialize(tmpWriter);
}
}
if (shouldSend)
else
{
var message = new NetworkVariableDeltaMessage
{
NetworkObjectId = NetworkObjectId,
NetworkBehaviourIndex = NetworkObject.GetNetworkBehaviourOrderIndex(this),
NetworkBehaviour = this,
ClientId = clientId,
DeliveryMappedNetworkVariableIndex = m_DeliveryMappedNetworkVariableIndices[j]
};
// TODO: Serialization is where the IsDirty flag gets changed.
// Messages don't get sent from the server to itself, so if we're host and sending to ourselves,
// we still have to actually serialize the message even though we're not sending it, otherwise
// the dirty flag doesn't change properly. These two pieces should be decoupled at some point
// so we don't have to do this serialization work if we're not going to use the result.
if (IsServer && clientId == NetworkManager.ServerClientId)
{
var tmpWriter = new FastBufferWriter(MessagingSystem.NON_FRAGMENTED_MESSAGE_MAX_SIZE, Allocator.Temp, MessagingSystem.FRAGMENTED_MESSAGE_MAX_SIZE);
using (tmpWriter)
{
message.Serialize(tmpWriter);
}
}
else
{
NetworkManager.SendMessage(ref message, m_DeliveryTypesForNetworkVariableGroups[j], clientId);
}
NetworkManager.SendMessage(ref message, m_DeliveryTypesForNetworkVariableGroups[j], targetClientId);
}
}
}
@@ -595,7 +670,7 @@ namespace Unity.Netcode
}
}
internal void WriteNetworkVariableData(FastBufferWriter writer, ulong clientId)
internal void WriteNetworkVariableData(FastBufferWriter writer, ulong targetClientId)
{
if (NetworkVariableFields.Count == 0)
{
@@ -604,7 +679,7 @@ namespace Unity.Netcode
for (int j = 0; j < NetworkVariableFields.Count; j++)
{
bool canClientRead = NetworkVariableFields[j].CanClientRead(clientId);
bool canClientRead = NetworkVariableFields[j].CanClientRead(targetClientId);
if (canClientRead)
{