This repository has been archived on 2025-04-22. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
com.unity.netcode.gameobjects/Runtime/Metrics/NetworkMetrics.cs
Unity Technologies 60e2dabef4 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)
2022-04-01 00:00:00 +00:00

540 lines
20 KiB
C#

#if MULTIPLAYER_TOOLS
using System;
using System.Collections.Generic;
using Unity.Multiplayer.Tools;
using Unity.Multiplayer.Tools.MetricTypes;
using Unity.Multiplayer.Tools.NetStats;
using Unity.Profiling;
using UnityEngine;
namespace Unity.Netcode
{
internal class NetworkMetrics : INetworkMetrics
{
const ulong k_MaxMetricsPerFrame = 1000L;
static Dictionary<uint, string> s_SceneEventTypeNames;
static ProfilerMarker s_FrameDispatch = new ProfilerMarker($"{nameof(NetworkMetrics)}.DispatchFrame");
static NetworkMetrics()
{
s_SceneEventTypeNames = new Dictionary<uint, string>();
foreach (SceneEventType type in Enum.GetValues(typeof(SceneEventType)))
{
s_SceneEventTypeNames[(uint)type] = type.ToString();
}
}
private static string GetSceneEventTypeName(uint typeCode)
{
if (!s_SceneEventTypeNames.TryGetValue(typeCode, out string name))
{
name = "Unknown";
}
return name;
}
private readonly Counter m_TransportBytesSent = new Counter(NetworkMetricTypes.TotalBytesSent.Id)
{
ShouldResetOnDispatch = true,
};
private readonly Counter m_TransportBytesReceived = new Counter(NetworkMetricTypes.TotalBytesReceived.Id)
{
ShouldResetOnDispatch = true,
};
private readonly EventMetric<NetworkMessageEvent> m_NetworkMessageSentEvent = new EventMetric<NetworkMessageEvent>(NetworkMetricTypes.NetworkMessageSent.Id);
private readonly EventMetric<NetworkMessageEvent> m_NetworkMessageReceivedEvent = new EventMetric<NetworkMessageEvent>(NetworkMetricTypes.NetworkMessageReceived.Id);
private readonly EventMetric<NamedMessageEvent> m_NamedMessageSentEvent = new EventMetric<NamedMessageEvent>(NetworkMetricTypes.NamedMessageSent.Id);
private readonly EventMetric<NamedMessageEvent> m_NamedMessageReceivedEvent = new EventMetric<NamedMessageEvent>(NetworkMetricTypes.NamedMessageReceived.Id);
private readonly EventMetric<UnnamedMessageEvent> m_UnnamedMessageSentEvent = new EventMetric<UnnamedMessageEvent>(NetworkMetricTypes.UnnamedMessageSent.Id);
private readonly EventMetric<UnnamedMessageEvent> m_UnnamedMessageReceivedEvent = new EventMetric<UnnamedMessageEvent>(NetworkMetricTypes.UnnamedMessageReceived.Id);
private readonly EventMetric<NetworkVariableEvent> m_NetworkVariableDeltaSentEvent = new EventMetric<NetworkVariableEvent>(NetworkMetricTypes.NetworkVariableDeltaSent.Id);
private readonly EventMetric<NetworkVariableEvent> m_NetworkVariableDeltaReceivedEvent = new EventMetric<NetworkVariableEvent>(NetworkMetricTypes.NetworkVariableDeltaReceived.Id);
private readonly EventMetric<OwnershipChangeEvent> m_OwnershipChangeSentEvent = new EventMetric<OwnershipChangeEvent>(NetworkMetricTypes.OwnershipChangeSent.Id);
private readonly EventMetric<OwnershipChangeEvent> m_OwnershipChangeReceivedEvent = new EventMetric<OwnershipChangeEvent>(NetworkMetricTypes.OwnershipChangeReceived.Id);
private readonly EventMetric<ObjectSpawnedEvent> m_ObjectSpawnSentEvent = new EventMetric<ObjectSpawnedEvent>(NetworkMetricTypes.ObjectSpawnedSent.Id);
private readonly EventMetric<ObjectSpawnedEvent> m_ObjectSpawnReceivedEvent = new EventMetric<ObjectSpawnedEvent>(NetworkMetricTypes.ObjectSpawnedReceived.Id);
private readonly EventMetric<ObjectDestroyedEvent> m_ObjectDestroySentEvent = new EventMetric<ObjectDestroyedEvent>(NetworkMetricTypes.ObjectDestroyedSent.Id);
private readonly EventMetric<ObjectDestroyedEvent> m_ObjectDestroyReceivedEvent = new EventMetric<ObjectDestroyedEvent>(NetworkMetricTypes.ObjectDestroyedReceived.Id);
private readonly EventMetric<RpcEvent> m_RpcSentEvent = new EventMetric<RpcEvent>(NetworkMetricTypes.RpcSent.Id);
private readonly EventMetric<RpcEvent> m_RpcReceivedEvent = new EventMetric<RpcEvent>(NetworkMetricTypes.RpcReceived.Id);
private readonly EventMetric<ServerLogEvent> m_ServerLogSentEvent = new EventMetric<ServerLogEvent>(NetworkMetricTypes.ServerLogSent.Id);
private readonly EventMetric<ServerLogEvent> m_ServerLogReceivedEvent = new EventMetric<ServerLogEvent>(NetworkMetricTypes.ServerLogReceived.Id);
private readonly EventMetric<SceneEventMetric> m_SceneEventSentEvent = new EventMetric<SceneEventMetric>(NetworkMetricTypes.SceneEventSent.Id);
private readonly EventMetric<SceneEventMetric> m_SceneEventReceivedEvent = new EventMetric<SceneEventMetric>(NetworkMetricTypes.SceneEventReceived.Id);
#if MULTIPLAYER_TOOLS_1_0_0_PRE_7
private readonly Counter m_PacketSentCounter = new Counter(NetworkMetricTypes.PacketsSent.Id)
{
ShouldResetOnDispatch = true,
};
private readonly Counter m_PacketReceivedCounter = new Counter(NetworkMetricTypes.PacketsReceived.Id)
{
ShouldResetOnDispatch = true,
};
private readonly Gauge m_RttToServerGauge = new Gauge(NetworkMetricTypes.RttToServer.Id)
{
ShouldResetOnDispatch = true,
};
private readonly Gauge m_NetworkObjectsGauge = new Gauge(NetworkMetricTypes.NetworkObjects.Id)
{
ShouldResetOnDispatch = true,
};
private readonly Gauge m_ConnectionsGauge = new Gauge(NetworkMetricTypes.ConnectedClients.Id)
{
ShouldResetOnDispatch = true,
};
private readonly Gauge m_PacketLossGauge = new Gauge(NetworkMetricTypes.PacketLoss.Id);
#endif
private ulong m_NumberOfMetricsThisFrame;
public NetworkMetrics()
{
Dispatcher = new MetricDispatcherBuilder()
.WithCounters(m_TransportBytesSent, m_TransportBytesReceived)
.WithMetricEvents(m_NetworkMessageSentEvent, m_NetworkMessageReceivedEvent)
.WithMetricEvents(m_NamedMessageSentEvent, m_NamedMessageReceivedEvent)
.WithMetricEvents(m_UnnamedMessageSentEvent, m_UnnamedMessageReceivedEvent)
.WithMetricEvents(m_NetworkVariableDeltaSentEvent, m_NetworkVariableDeltaReceivedEvent)
.WithMetricEvents(m_OwnershipChangeSentEvent, m_OwnershipChangeReceivedEvent)
.WithMetricEvents(m_ObjectSpawnSentEvent, m_ObjectSpawnReceivedEvent)
.WithMetricEvents(m_ObjectDestroySentEvent, m_ObjectDestroyReceivedEvent)
.WithMetricEvents(m_RpcSentEvent, m_RpcReceivedEvent)
.WithMetricEvents(m_ServerLogSentEvent, m_ServerLogReceivedEvent)
.WithMetricEvents(m_SceneEventSentEvent, m_SceneEventReceivedEvent)
#if MULTIPLAYER_TOOLS_1_0_0_PRE_7
.WithCounters(m_PacketSentCounter, m_PacketReceivedCounter)
.WithGauges(m_RttToServerGauge)
.WithGauges(m_NetworkObjectsGauge)
.WithGauges(m_ConnectionsGauge)
.WithGauges(m_PacketLossGauge)
#endif
.Build();
Dispatcher.RegisterObserver(NetcodeObserver.Observer);
}
internal IMetricDispatcher Dispatcher { get; }
private bool CanSendMetrics => m_NumberOfMetricsThisFrame < k_MaxMetricsPerFrame;
public void SetConnectionId(ulong connectionId)
{
Dispatcher.SetConnectionId(connectionId);
}
public void TrackTransportBytesSent(long bytesCount)
{
m_TransportBytesSent.Increment(bytesCount);
}
public void TrackTransportBytesReceived(long bytesCount)
{
m_TransportBytesReceived.Increment(bytesCount);
}
public void TrackNetworkMessageSent(ulong receivedClientId, string messageType, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_NetworkMessageSentEvent.Mark(new NetworkMessageEvent(new ConnectionInfo(receivedClientId), messageType, bytesCount));
IncrementMetricCount();
}
public void TrackNetworkMessageReceived(ulong senderClientId, string messageType, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_NetworkMessageReceivedEvent.Mark(new NetworkMessageEvent(new ConnectionInfo(senderClientId), messageType, bytesCount));
IncrementMetricCount();
}
public void TrackNamedMessageSent(ulong receiverClientId, string messageName, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_NamedMessageSentEvent.Mark(new NamedMessageEvent(new ConnectionInfo(receiverClientId), messageName, bytesCount));
IncrementMetricCount();
}
public void TrackNamedMessageSent(IReadOnlyCollection<ulong> receiverClientIds, string messageName, long bytesCount)
{
foreach (var receiver in receiverClientIds)
{
TrackNamedMessageSent(receiver, messageName, bytesCount);
}
}
public void TrackNamedMessageReceived(ulong senderClientId, string messageName, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_NamedMessageReceivedEvent.Mark(new NamedMessageEvent(new ConnectionInfo(senderClientId), messageName, bytesCount));
IncrementMetricCount();
}
public void TrackUnnamedMessageSent(ulong receiverClientId, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_UnnamedMessageSentEvent.Mark(new UnnamedMessageEvent(new ConnectionInfo(receiverClientId), bytesCount));
IncrementMetricCount();
}
public void TrackUnnamedMessageSent(IReadOnlyCollection<ulong> receiverClientIds, long bytesCount)
{
foreach (var receiverClientId in receiverClientIds)
{
TrackUnnamedMessageSent(receiverClientId, bytesCount);
}
}
public void TrackUnnamedMessageReceived(ulong senderClientId, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_UnnamedMessageReceivedEvent.Mark(new UnnamedMessageEvent(new ConnectionInfo(senderClientId), bytesCount));
IncrementMetricCount();
}
public void TrackNetworkVariableDeltaSent(
ulong receiverClientId,
NetworkObject networkObject,
string variableName,
string networkBehaviourName,
long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_NetworkVariableDeltaSentEvent.Mark(
new NetworkVariableEvent(
new ConnectionInfo(receiverClientId),
GetObjectIdentifier(networkObject),
variableName,
networkBehaviourName,
bytesCount));
IncrementMetricCount();
}
public void TrackNetworkVariableDeltaReceived(
ulong senderClientId,
NetworkObject networkObject,
string variableName,
string networkBehaviourName,
long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_NetworkVariableDeltaReceivedEvent.Mark(
new NetworkVariableEvent(
new ConnectionInfo(senderClientId),
GetObjectIdentifier(networkObject),
variableName,
networkBehaviourName,
bytesCount));
IncrementMetricCount();
}
public void TrackOwnershipChangeSent(ulong receiverClientId, NetworkObject networkObject, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_OwnershipChangeSentEvent.Mark(new OwnershipChangeEvent(new ConnectionInfo(receiverClientId), GetObjectIdentifier(networkObject), bytesCount));
IncrementMetricCount();
}
public void TrackOwnershipChangeReceived(ulong senderClientId, NetworkObject networkObject, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_OwnershipChangeReceivedEvent.Mark(new OwnershipChangeEvent(new ConnectionInfo(senderClientId),
GetObjectIdentifier(networkObject), bytesCount));
IncrementMetricCount();
}
public void TrackObjectSpawnSent(ulong receiverClientId, NetworkObject networkObject, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_ObjectSpawnSentEvent.Mark(new ObjectSpawnedEvent(new ConnectionInfo(receiverClientId), GetObjectIdentifier(networkObject), bytesCount));
IncrementMetricCount();
}
public void TrackObjectSpawnReceived(ulong senderClientId, NetworkObject networkObject, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_ObjectSpawnReceivedEvent.Mark(new ObjectSpawnedEvent(new ConnectionInfo(senderClientId), GetObjectIdentifier(networkObject), bytesCount));
IncrementMetricCount();
}
public void TrackObjectDestroySent(ulong receiverClientId, NetworkObject networkObject, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_ObjectDestroySentEvent.Mark(new ObjectDestroyedEvent(new ConnectionInfo(receiverClientId), GetObjectIdentifier(networkObject), bytesCount));
IncrementMetricCount();
}
public void TrackObjectDestroyReceived(ulong senderClientId, NetworkObject networkObject, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_ObjectDestroyReceivedEvent.Mark(new ObjectDestroyedEvent(new ConnectionInfo(senderClientId), GetObjectIdentifier(networkObject), bytesCount));
IncrementMetricCount();
}
public void TrackRpcSent(
ulong receiverClientId,
NetworkObject networkObject,
string rpcName,
string networkBehaviourName,
long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_RpcSentEvent.Mark(
new RpcEvent(
new ConnectionInfo(receiverClientId),
GetObjectIdentifier(networkObject),
rpcName,
networkBehaviourName,
bytesCount));
IncrementMetricCount();
}
public void TrackRpcSent(
ulong[] receiverClientIds,
NetworkObject networkObject,
string rpcName,
string networkBehaviourName,
long bytesCount)
{
foreach (var receiverClientId in receiverClientIds)
{
TrackRpcSent(receiverClientId, networkObject, rpcName, networkBehaviourName, bytesCount);
}
}
public void TrackRpcReceived(
ulong senderClientId,
NetworkObject networkObject,
string rpcName,
string networkBehaviourName,
long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_RpcReceivedEvent.Mark(
new RpcEvent(new ConnectionInfo(senderClientId),
GetObjectIdentifier(networkObject),
rpcName,
networkBehaviourName,
bytesCount));
IncrementMetricCount();
}
public void TrackServerLogSent(ulong receiverClientId, uint logType, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_ServerLogSentEvent.Mark(new ServerLogEvent(new ConnectionInfo(receiverClientId), (Multiplayer.Tools.MetricTypes.LogLevel)logType, bytesCount));
IncrementMetricCount();
}
public void TrackServerLogReceived(ulong senderClientId, uint logType, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_ServerLogReceivedEvent.Mark(new ServerLogEvent(new ConnectionInfo(senderClientId), (Multiplayer.Tools.MetricTypes.LogLevel)logType, bytesCount));
IncrementMetricCount();
}
public void TrackSceneEventSent(IReadOnlyList<ulong> receiverClientIds, uint sceneEventType, string sceneName, long bytesCount)
{
foreach (var receiverClientId in receiverClientIds)
{
TrackSceneEventSent(receiverClientId, sceneEventType, sceneName, bytesCount);
}
}
public void TrackSceneEventSent(ulong receiverClientId, uint sceneEventType, string sceneName, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_SceneEventSentEvent.Mark(new SceneEventMetric(new ConnectionInfo(receiverClientId), GetSceneEventTypeName(sceneEventType), sceneName, bytesCount));
IncrementMetricCount();
}
public void TrackSceneEventReceived(ulong senderClientId, uint sceneEventType, string sceneName, long bytesCount)
{
if (!CanSendMetrics)
{
return;
}
m_SceneEventReceivedEvent.Mark(new SceneEventMetric(new ConnectionInfo(senderClientId), GetSceneEventTypeName(sceneEventType), sceneName, bytesCount));
IncrementMetricCount();
}
public void TrackPacketSent(uint packetCount)
{
#if MULTIPLAYER_TOOLS_1_0_0_PRE_7
if (!CanSendMetrics)
{
return;
}
m_PacketSentCounter.Increment(packetCount);
IncrementMetricCount();
#endif
}
public void TrackPacketReceived(uint packetCount)
{
#if MULTIPLAYER_TOOLS_1_0_0_PRE_7
if (!CanSendMetrics)
{
return;
}
m_PacketReceivedCounter.Increment(packetCount);
IncrementMetricCount();
#endif
}
public void UpdateRttToServer(int rttMilliseconds)
{
#if MULTIPLAYER_TOOLS_1_0_0_PRE_7
if (!CanSendMetrics)
{
return;
}
var rttSeconds = rttMilliseconds * 1e-3;
m_RttToServerGauge.Set(rttSeconds);
#endif
}
public void UpdateNetworkObjectsCount(int count)
{
#if MULTIPLAYER_TOOLS_1_0_0_PRE_7
if (!CanSendMetrics)
{
return;
}
m_NetworkObjectsGauge.Set(count);
#endif
}
public void UpdateConnectionsCount(int count)
{
#if MULTIPLAYER_TOOLS_1_0_0_PRE_7
if (!CanSendMetrics)
{
return;
}
m_ConnectionsGauge.Set(count);
#endif
}
public void UpdatePacketLoss(float packetLoss)
{
#if MULTIPLAYER_TOOLS_1_0_0_PRE_7
if (!CanSendMetrics)
{
return;
}
m_PacketLossGauge.Set(packetLoss);
#endif
}
public void DispatchFrame()
{
s_FrameDispatch.Begin();
Dispatcher.Dispatch();
s_FrameDispatch.End();
m_NumberOfMetricsThisFrame = 0;
}
private void IncrementMetricCount()
{
m_NumberOfMetricsThisFrame++;
}
private static NetworkObjectIdentifier GetObjectIdentifier(NetworkObject networkObject)
{
return new NetworkObjectIdentifier(networkObject.GetNameForMetrics(), networkObject.NetworkObjectId);
}
}
internal class NetcodeObserver
{
public static IMetricObserver Observer { get; } = MetricObserverFactory.Construct();
}
}
#endif