From 25d32f8a704040d2fe04b47aeae503d9c8b396e4 Mon Sep 17 00:00:00 2001
From: Unity Technologies <@unity>
Date: Wed, 16 Oct 2024 00:00:00 +0000
Subject: [PATCH] com.unity.netcode@1.3.6 ## [1.3.6] - 2024-10-16
### Changed
* Improved XML document for `NetworkStreamDriver.ConnectionEventsForTick`.
* Updated entities packages dependencies
### Fixed
* an issue with netcode source generated files, causing multiple Burst.CompileAsync invocation, ending up in stalling the editor and the player for long time, and / or causing crashes.
* Issue where `OverrideAutomaticNetcodeBootstrap` instances in scenes would be ignored in the Editor if 'Fast Enter Play-Mode Options' is disabled (i.e. when domain reloads triggered after clicking to enter play-mode).
* Longstanding API documentation errors across Netcode for Entities API documentation.
---
CHANGELOG.md | 12 +-
Documentation~/playmode-tool.md | 104 ++++++-----
Editor/Authoring/GhostComponentAnalytics.cs | 165 +++++++++++++-----
Editor/Templates/GhostComponentSerializer.cs | 3 +-
Runtime/Analytics/NetCodeAnalyticsState.cs | 12 --
Runtime/Authoring/DefaultVariantSystemBase.cs | 2 +-
.../Authoring/DefaultVariantSystemGroup.cs | 2 +-
Runtime/Authoring/GhostComponentVariation.cs | 2 +-
Runtime/Authoring/GhostFieldAttribute.cs | 2 +-
Runtime/Authoring/GhostModifiers.cs | 4 +-
Runtime/Authoring/Hybrid/BakerExtension.cs | 4 +-
.../Hybrid/GhostAuthoringComponent.cs | 4 +
Runtime/Authoring/TypeRegistryEntry.cs | 10 +-
.../ClientServerBootstrap.cs | 66 ++++---
.../ClientServerWorld/ClientServerTickRate.cs | 54 +++---
.../OverrideAutomaticNetcodeBootstrap.cs | 16 +-
Runtime/Command/CommandSendSystem.cs | 4 +-
Runtime/Command/CommandTarget.cs | 11 +-
.../Connection/DefaultDriverConstructor.cs | 67 ++++---
Runtime/Connection/NetCodeConnectionEvent.cs | 10 +-
Runtime/Connection/NetworkDriverStore.cs | 40 +++--
Runtime/Connection/NetworkProtocolVersion.cs | 9 +-
Runtime/Connection/NetworkSnapshotAck.cs | 4 +-
.../NetworkStreamConnectionComponent.cs | 8 +-
Runtime/Connection/NetworkStreamDriver.cs | 57 +++++-
.../Connection/NetworkStreamReceiveSystem.cs | 4 +-
.../SnapshotPacketLossStatistics.cs | 12 ++
.../Physics/Hybrid/NetCodePhysicsConfig.cs | 6 +-
.../Physics/Hybrid/NetCodePhysicsInspector.cs | 4 +
Runtime/Physics/PhysicsVelocityVariant.cs | 6 +-
.../GhostSimulationSystemGroup.cs | 4 +-
.../PredictionTicking/NetworkTimeSystem.cs | 4 +-
.../NetcodeServerRateManager.cs | 2 +-
Runtime/Rpc/IRpcCommand.cs | 20 ++-
Runtime/Rpc/RpcCommandRequest.cs | 8 +-
Runtime/Rpc/RpcQueue.cs | 9 +-
Runtime/Rpc/RpcSystem.cs | 14 +-
.../CustomSerializerHelpers.cs | 164 ++++++++---------
.../SerializationHelpers/IGhostSerializer.cs | 14 +-
Runtime/Snapshot/GhostCollectionComponent.cs | 23 ++-
Runtime/Snapshot/GhostCollectionSystem.cs | 5 +-
Runtime/Snapshot/GhostComponent.cs | 12 +-
Runtime/Snapshot/GhostComponentSerializer.cs | 94 +++++++++-
...omponentSerializerCollectionSystemGroup.cs | 3 +-
Runtime/Snapshot/GhostDespawnSystem.cs | 2 +
Runtime/Snapshot/GhostImportance.cs | 6 +
Runtime/Snapshot/GhostOwner.cs | 4 +-
.../GhostPredictionSmoothingSystem.cs | 7 +-
.../GhostPredictionSwitchingQueues.cs | 6 +-
Runtime/Snapshot/GhostPrefabCreation.cs | 25 +--
Runtime/Snapshot/GhostReceiveSystem.cs | 4 +
Runtime/Snapshot/GhostSendSystem.cs | 8 +-
.../GhostSpawnClassificationSystem.cs | 2 +
Runtime/Snapshot/GhostSpawnSystem.cs | 8 +-
Runtime/Snapshot/GhostUpdateSystem.cs | 2 +-
.../ClientPopulatePrespawnedGhostsSystem.cs | 7 +-
Runtime/Snapshot/SnapshotData.cs | 8 +-
.../SnapshotDataBufferComponentLookup.cs | 19 +-
.../SwitchPredictionSmoothingSystem.cs | 4 +-
.../NetCodeSourceGenerator.dll | Bin 272896 -> 272896 bytes
.../NetCodeSourceGenerator.pdb | Bin 36844 -> 36844 bytes
Runtime/Variants/GhostTransformVariants.cs | 6 +-
Tests/Editor/AnalyticsTests.cs | 149 ++++++++++++++++
ValidationExceptions.json | 30 ++--
package.json | 10 +-
65 files changed, 909 insertions(+), 478 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bf9889f..e9f9c5a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,8 +2,18 @@
uid: changelog
---
-# Changelog
+## [1.3.6] - 2024-10-16
+### Changed
+
+* Improved XML document for `NetworkStreamDriver.ConnectionEventsForTick`.
+* Updated entities packages dependencies
+
+### Fixed
+
+* an issue with netcode source generated files, causing multiple Burst.CompileAsync invocation, ending up in stalling the editor and the player for long time, and / or causing crashes.
+* Issue where `OverrideAutomaticNetcodeBootstrap` instances in scenes would be ignored in the Editor if 'Fast Enter Play-Mode Options' is disabled (i.e. when domain reloads triggered after clicking to enter play-mode).
+* Longstanding API documentation errors across Netcode for Entities API documentation.
## [1.3.2] - 2024-09-06
diff --git a/Documentation~/playmode-tool.md b/Documentation~/playmode-tool.md
index 84abe30..7b813a1 100644
--- a/Documentation~/playmode-tool.md
+++ b/Documentation~/playmode-tool.md
@@ -1,62 +1,84 @@
-# PlayMode Tool window
+# Playmode Tool window
-The __PlayMode Tools__ window in the Unity Editor provide a set of utility to:
-- select what type of mode (client, server, client/server) you would like the game start.
-- enable and configure the [network simulator](network-connection.md#network-simulator).
-- configure the number of [thin-clients](client-server-worlds.md#thin-clients) to use.
-- changing the current logging level and enabling packet dumps.
-- connect/disconnect clients when in play-mode
-- showing bounding box gizmos.
+Use the __Playmode Tools__ window (menu: **Window** > **Multiplayer** > **Playmode Tools**) to do the following:
+- Select the behaviour of the Netcode for Entities bootstrapping flow (assuming it's enabled) when you enter Play Mode. This controls whether the `ClientServerBootstrap` creates a client world, a server world, or both client and server worlds, and whether they connect automatically.
+- Enable and configure the [network simulator](network-connection.md#network-simulator).
+- Configure the number of [thin-clients](client-server-worlds.md#thin-clients) to use.
+- Change the current logging level, and control whether or not Unity creates packet dumps.
+- View, control, and debug Netcode for Entities client and server worlds and their transport data (only available after entering Play Mode).
+- Display bounding box gizmos for all ghosts.
-You can access __PlayMode Tools__, go to menu: __Multiplayer > PlayMode Tools__.
+## Properties
-| **Property** | **Description** |
-|-------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| __PlayMode Type__ | Choose to make Play Mode either __Client__ only, __Server__ only, or __Client & Server__. |
-| __Num Thin Clients__ | Set the number of thin clients. Thin clients cannot be presented, and never spawn any entities it receives from the server. However, they can generate fake input to send to the server to simulate a realistic load. |
-| __Simulate_Dedicated_Server__ | When enabled, in the editor the sub-scene for the server world are baked using the server settings. |
+| **Property** | **Description** |
+|-------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| __PlayMode Type__ | Determines the behaviour of the Netcode for Entities bootstrapping flow (assuming it's enabled) when entering Play Mode. __Client__ spawns only the client world, __Server__ spawns only the server world, and __Client & Server__ spawns one of each. |
+| __Simulate Dedicated Server__ | Denotes the build environment that Netcode for Entities emulates when it bakes the ServerWorld version of the sub scenes. For example, a client-hosted game server might have some additional assemblies which are unavailable on a Dedicated Game Server (DGS) build, so with this toggle unchecked, types in those assemblies would show up on the entities within the ServerWorld. This option is only visible when Client Hosted Builds are enabled in the Project Settings, because it defaults to emulating a DGS if your client can't support hosting a game server. |
+| __Num Thin Clients__ | Set the number of thin clients spawned and automatically maintained in-Editor by the package. You can use these clients to test multiplayer PvP interactions. Thin clients can't present and don't spawn any ghosts they receive from the server. However, they can generate fake input, and simulate a realistic load on the server. | |
-When you enter Play Mode, from this window you can also connect and disconnect clients.
-When you change a client that Unity is presenting, it stops calling the update on the `ClientPresentationSystemGroup` for the Worlds which it should no longer present. As such, your code needs to be able to handle this situation, or your presentation code won’t run and all rendering objects you’ve created still exist.
+> [!NOTE]
+> Be aware that this window, when open, adheres strictly to the target _Num Thin Clients_ value at runtime. If you've spawned any thin clients yourself that take the total number of thin clients over _Num Thin Clients_, then those thin clients will be destroyed. This is a known issue.
+
+### Emulate client network conditions
+
+Use the network emulator to replicate specific network conditions while your game is running in the Unity Editor.
+When you enable network emulation, you can set the packet delay and packet loss in the following ways:
+ - Manually set the packet delay and drop values.
+ - Select a `preset`. For example, '4G' or 'Broadband'.
-## NetworkSimulator
-The Network Simulator can be used to simulate some network condition while running your game in the editor.
-Once the simulator is enabled, you can set the packet delay, drop either manually (by setting your own value) or by selecting some provided `presets` (i.e 4G, Broadband, etc.).
+Frequently test your gameplay with the emulator enabled to get a more accurate picture of how real-world network latency impacts gameplay quality. Gameplay test also demonstrate the performance implications of the rollback and re-simulate logic involved in client prediction. For example, a higher ping requires the client to perform more prediction ticks which uses higher CPU resources on the client's side.
-You can also specify your own settings, by setting custom values in the `RTT Delay`, `RTT Jitter` `PacketDrop` fields (or `Packet Delay`, `Packet Jitter` for `Packet View`).
+To manually specify network conditions, enter custom values in the following fields:
+- **RTT Delay**
+- **RTT Jitter**
+- **Packet Drop**
+If you use **Packet View**, enter custom values in the following fields:
+- **Packet Delay**
+- **Packet Jitter**
+- **Packet Drop**
+
+Unity runs the network emulation via a Unity Transport Pipeline Stage. This stage is only added to the client driver and so Unity applies these settings to incoming and outgoing packets. To view the combined impact on the ping, open the dropdown and select __Ping View__.
| **Property** | **Description** |
|----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| __RTT Delay (ms)__ | Use this property to emulate round trip time. The property delay the incoming and outgoing packet (in ms) such that the sum of the delays equals the specified value. |
+| __RTT Delay (ms)__ | Use this property to emulate round trip time. This property delays the incoming and outgoing packet (in ms) such that the sum of the delays equals the specified value. |
| __RTT Jitter (ms)__ | Use this property to add (or subtract) a random value to the delay, which makes the delay a value between the delay you have set plus or minus the jitter value. For example, if you set __RTTDelay__ to 45 and __RTTJitter__ to 5, you will get a random value between 40 and 50. |
-| __Packet Drop (%)__ | Use this property to simulate bad connections where not all packets arrive. Specify a value (as a percentage) and Netcode discards that percentage of packets from the total it receives. For example, set the value to 5 and Netcode discards 5% of all incoming and outgoing packets. |
-| __Packet Fuzz (%)__ | Use this property to simulate security-related MitM attacks, where malicious clients will attempt to bring down your server (or other clients) by intentionally serializing bad data. |
-| __Auto Connect Address (Client only)__ | Specify which server a client should connect to. This field only appears if you set __PlayMode Type__ to __Client__. The user code needs to read this value and connect because the connection flows are in user code. |
+| __Packet Drop (%)__ | Use this property to simulate bad connections where not all packets arrive. Specify a value (as a percentage) and Netcode for Entities discards that percentage of packets from the total it receives. For example, set the value to 5 and Netcode for Entities discards 5% of all incoming and outgoing packets. |
+| __Packet Fuzz (%)__ | Use this property to simulate security-related person-in-the-middle (PITM) attacks, where malicious clients attempt to bring down your server (or other clients) by intentionally serializing bad data. |
+| __Auto Connect Address (Client only)__ | Specify which server address a client connects to. This field only appears if you set __PlayMode Type__ to __Client__. If you're not using auto connect functionality, your user code needs to read this value (via `ClientServerBootstrap.IsEditorInputtedAddressValidForConnect`), and manually connect to the outputted `NetworkEndpoint`. |
| __Auto Connect Port (Client only)__ | Override and/or specify which port to use for both listening (server) and connecting (client) |
-
-> [!NOTE]
-> These simulator settings are applied on a per-packet basis (i.e. each way).
> [!NOTE]
-> Enabling network simulation will force the Unity Transport's network interface to be a full UDP socket. Otherwise, when a both Client and Server worlds are present in the same process an IPC (Inter-Process Communication) connection is used instead.
-> See [DefaultDriverConstructor](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.IPCAndSocketDriverConstructor.html)
+> When you enable network emulation, Unity forces the Unity Transport's network interface to be a full UDP socket. Otherwise, Unity uses an IPC (Inter-Process Communication) connection when both client and server worlds exist in the same process.
+> Refer to [DefaultDriverConstructor](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.IPCAndSocketDriverConstructor.html)
> [!NOTE]
-> The `AutoConnectAddress` and `AutoConnectPort` will be used when automatically connecting the client to a server (in client only mode) and overrides the values set in the [ClientServerBootstrap](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.ClientServerBootstrap.html). However, when the bootstrap sets `AutoConnectPort` to 0 these fields will be unused unless the Connect button in the Playmode Tools is pressed.
+> Unity uses `AutoConnectAddress` and `AutoConnectPort` when it automatically connects the client to a server in client-only mode, and overrides the values set in the [ClientServerBootstrap](https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.ClientServerBootstrap.html). However, Unity ignores these fields when the bootstrap sets `AutoConnectPort` to 0. You can use the __Connect__ button in the Playmode Tools window to force the connection to the target `AutoConnectAddress` and `AutoConnectPort`.
-We strongly recommend that you frequently test your gameplay with the simulator enabled, as it more closely resembles real-world conditions.
+### Visualize bounding boxes on GameObjects
+Entities that use Entities Graphics automatically draw bounding boxes. To draw bounding boxes around objects that don't use entities graphics, add the `GhostDebugMeshBounds` component to the GameObject's supporting entity. You can call `Initialize` for convenience to set it up.
+Refer to `GhostPresentationGameObjectEntityOwner` for an example.
-### Initialize simulator from the command line
-Network simulation can be enabled (**in development builds only! DotsRuntime is also not supported!**) via the command line argument `--loadNetworkSimulatorJsonFile [optionalJsonFilePath]`.
-Alternatively, `--createNetworkSimulatorJsonFile [optionalJsonFilePath]` can be passed if you want the file to be auto-generated (in the case that it's not found).
-It expects a json file containing `SimulatorUtility.Parameters`.
+
-Passing in either parameter will **always** enable a simulator profile, as we fallback to using the `DefaultSimulatorProfile` if the file is not found (or generated).
+## Initialize the network emulator from the command line
+Use the command line arguments `--loadNetworkSimulatorJsonFile [optionalJsonFilePath]` to load an existing JSON (.json) `SimulatorUtility.Parameters` preset. If the file isn't found, unity throws an error.
+Alternatively; use `--createNetworkSimulatorJsonFile [optionalJsonFilePath]` to generate a default JSON file automatically. The default file name (if unspecified) is `NetworkSimulatorProfile.json`.
-### Bounding boxes on GameObjects
-To draw bounding boxes around objects not using entities graphics, you need to add the `GhostDebugMeshBounds` component to its supporting entity. You can call `Initialize` for convenience to set it up.
-See GhostPresentationGameObjectEntityOwner for an example.
-Entities using Entities Graphics will automatically draw bounding boxes.
+Passing in either parameter always enables a simulator profile, even in the error case. If the file isn't found or generated, it uses the `NetworkSimulatorSettings.DefaultSimulatorParameters`.
-
+> [!NOTE]
+> You can only enable Network emulation in development builds.
+
+## Use the Playmode Tool window with Multiplayer Play Mode
+
+To use the Playmode Tool window in Multiplayer Play Mode to test a [virtual player](https://docs-multiplayer.unity3d.com/mppm/current/virtual-players/) in a project that uses netcode for Entities, perform the following actions:
+1. [Install the Multiplayer Play Mode package](https://docs-multiplayer.unity3d.com/mppm/current/install/).
+2. Open the Multiplayer Play Mode window (**Window** > **Multiplayer Play Mode**).
+3. [Activate a virtual player](https://docs-multiplayer.unity3d.com/mppm/current/virtual-players/virtual-players-enable/).
+4. IN a virtual player's Play Mode window, navigate to **Layout** and select **Playmode Tool**.
+5. Set the **Play Mode Type** to make this clone act as a __Client__, a __Server__, or both a __Client & Server__.
+
+>[!NOTE]
+> If the [Dedicated Server package](https://docs.unity3d.com/Packages/com.unity.dedicated-server@1.0/manual/index.html) exists in your project, the [Multiplayer Role](https://docs.unity3d.com/Packages/com.unity.dedicated-server@1.0/manual/multiplayer-roles.html) you select overrides the PlayMode Type.
diff --git a/Editor/Authoring/GhostComponentAnalytics.cs b/Editor/Authoring/GhostComponentAnalytics.cs
index 06ef964..e7ad470 100644
--- a/Editor/Authoring/GhostComponentAnalytics.cs
+++ b/Editor/Authoring/GhostComponentAnalytics.cs
@@ -5,6 +5,7 @@
using Unity.NetCode.Analytics;
using Unity.Networking.Transport;
using UnityEditor;
+using UnityEditor.PackageManager;
using UnityEngine.Analytics;
namespace Unity.NetCode.Editor
@@ -40,14 +41,12 @@ static GhostScaleAnalyticsData ComputeScaleData()
{
var data = new GhostScaleAnalyticsData
{
- PlayerCount = NetCodeAnalyticsState.GetPlayerCount(),
Settings = new PlaymodeSettings
{
ThinClientCount = MultiplayerPlayModePreferences.RequestedNumThinClients,
SimulatorEnabled = MultiplayerPlayModePreferences.SimulatorEnabled,
Delay = MultiplayerPlayModePreferences.PacketDelayMs,
DropPercentage = MultiplayerPlayModePreferences.PacketDropPercentage,
- FuzzPercentage = MultiplayerPlayModePreferences.PacketFuzzPercentage,
Jitter = MultiplayerPlayModePreferences.PacketJitterMs,
PlayModeType = MultiplayerPlayModePreferences.RequestedPlayType.ToString(),
SimulatorPreset = MultiplayerPlayModePreferences.CurrentNetworkSimulatorPreset
@@ -62,39 +61,6 @@ static GhostScaleAnalyticsData ComputeScaleData()
var numServerWorlds = 0;
foreach (var world in World.All)
{
- void CollectMainClientData()
- {
- TryGetSingleton(world, out data.ClientTickRate);
- data.MainClientData.NumOfSpawnedGhost = CountSpawnedGhosts(world.EntityManager);
- TryGetSingleton(world, out data.ClientServerTickRate);
-
- var spawnedGhostCount = CountSpawnedGhosts(world.EntityManager);
- TryGetSingleton(world, out var ghostRelevancy);
- using var predictedGhostQuery = world.EntityManager.CreateEntityQuery(ComponentType.ReadOnly());
- var predictionCount = predictedGhostQuery.CalculateEntityCountWithoutFiltering();
- TryGetSingleton(world, out var predictionSwitchingAnalyticsData);
- data.MainClientData = new MainClientData
- {
- RelevancyMode = ghostRelevancy.GhostRelevancyMode,
- NumOfSpawnedGhost = spawnedGhostCount,
- NumOfPredictedGhosts = predictionCount,
- NumSwitchToInterpolated = predictionSwitchingAnalyticsData.NumTimesSwitchedToInterpolated,
- NumSwitchToPredicted = predictionSwitchingAnalyticsData.NumTimesSwitchedToPredicted,
- };
- }
-
- void CollectServerData()
- {
- data.ServerSpawnedGhostCount = CountSpawnedGhosts(world.EntityManager);
-
- data.GhostTypes = CollectGhostTypes(world.EntityManager);
- data.GhostTypeCount = data.GhostTypes.Length;
-
- data.SnapshotTargetSize = TryGetSingleton(world, out var snapshotTargetSize)
- ? snapshotTargetSize.Value
- : NetworkParameterConstants.MaxMessageSize;
- }
-
var sent = NetCodeAnalyticsState.GetUpdateLength(world);
if (sent > 0)
{
@@ -118,6 +84,47 @@ void CollectServerData()
}
numMainClientWorlds++;
}
+
+ continue;
+
+ void CollectServerData()
+ {
+ data.ServerSpawnedGhostCount = CountSpawnedGhosts(world.EntityManager);
+
+ data.GhostTypes = CollectGhostTypes(world.EntityManager);
+ data.GhostTypeCount = data.GhostTypes.Length;
+
+ data.SnapshotTargetSize = TryGetSingleton(world, out var snapshotTargetSize)
+ ? snapshotTargetSize.Value
+ : NetworkParameterConstants.MaxMessageSize;
+ }
+
+ void CollectMainClientData()
+ {
+ if (TryGetSingleton(world, out ClientTickRate clientTickRate))
+ {
+ data.ClientTickRate = new WrappedClientTickRate(clientTickRate);
+ }
+ data.MainClientData.NumOfSpawnedGhost = CountSpawnedGhosts(world.EntityManager);
+ if (TryGetSingleton(world, out ClientServerTickRate clientServerTickRate))
+ {
+ data.ClientServerTickRate = new WrappedClientServerTickRate(clientServerTickRate);
+ }
+
+ var spawnedGhostCount = CountSpawnedGhosts(world.EntityManager);
+ TryGetSingleton(world, out var ghostRelevancy);
+ using var predictedGhostQuery = world.EntityManager.CreateEntityQuery(ComponentType.ReadOnly());
+ var predictionCount = predictedGhostQuery.CalculateEntityCountWithoutFiltering();
+ TryGetSingleton(world, out var predictionSwitchingAnalyticsData);
+ data.MainClientData = new MainClientData
+ {
+ RelevancyMode = (int)ghostRelevancy.GhostRelevancyMode,
+ NumOfSpawnedGhost = spawnedGhostCount,
+ NumOfPredictedGhosts = predictionCount,
+ NumSwitchToInterpolated = (int)predictionSwitchingAnalyticsData.NumTimesSwitchedToInterpolated,
+ NumSwitchToPredicted = (int)predictionSwitchingAnalyticsData.NumTimesSwitchedToPredicted,
+ };
+ }
}
if (amount == 0)
@@ -126,7 +133,7 @@ void CollectServerData()
}
else
{
- data.AverageGhostInSnapshot = serializedSent / amount;
+ data.AverageGhostInSnapshot = (int)(serializedSent / amount);
}
data.NumMainClientWorlds = numMainClientWorlds;
data.NumServerWorlds = numServerWorlds;
@@ -211,6 +218,74 @@ public override string ToString()
}
}
+ ///
+ /// This struct is used to wrap the struct to be serializable.
+ /// We ensure here that the data matches the expected format for the analytics.
+ /// If you change this struct, you must also update the analytics event in schemata.
+ ///
+ [Serializable]
+ internal struct WrappedClientServerTickRate
+ {
+ public int MaxSimulationStepBatchSize;
+ public int MaxSimulationStepsPerFrame;
+ public int NetworkTickRate;
+ public int SimulationTickRate;
+ public int TargetFrameRateMode;
+
+ public WrappedClientServerTickRate(ClientServerTickRate clientServerTickRate)
+ {
+ this.MaxSimulationStepBatchSize = clientServerTickRate.MaxSimulationStepBatchSize;
+ this.MaxSimulationStepsPerFrame = clientServerTickRate.MaxSimulationStepsPerFrame;
+ this.NetworkTickRate = clientServerTickRate.NetworkTickRate;
+ this.SimulationTickRate = clientServerTickRate.SimulationTickRate;
+ this.TargetFrameRateMode = (int)clientServerTickRate.TargetFrameRateMode;
+ }
+ }
+
+ ///
+ /// This struct is used to wrap the struct to be serializable.
+ /// We ensure here that the data matches the expected format for the analytics.
+ /// If you change this struct, you must also update the analytics event in schemata.
+ ///
+ [Serializable]
+ internal struct WrappedClientTickRate
+ {
+ public int CommandAgeCorrectionFraction;
+ public int InterpolationDelayCorrectionFraction;
+ public int InterpolationDelayJitterScale;
+ public int InterpolationDelayMaxDeltaTicksFraction;
+ public int InterpolationTimeMS;
+ public int InterpolationTimeNetTicks;
+ public int InterpolationTimeScaleMax;
+ public int InterpolationTimeScaleMin;
+ public int MaxExtrapolationTimeSimTicks;
+ public int MaxPredictAheadTimeMS;
+ public int MaxPredictionStepBatchSizeFirstTimeTick;
+ public int MaxPredictionStepBatchSizeRepeatedTick;
+ public int PredictionTimeScaleMax;
+ public int PredictionTimeScaleMin;
+ public int TargetCommandSlack;
+
+ public WrappedClientTickRate(ClientTickRate clientTickRate)
+ {
+ this.CommandAgeCorrectionFraction = (int)clientTickRate.CommandAgeCorrectionFraction;
+ this.InterpolationDelayCorrectionFraction = (int)clientTickRate.InterpolationDelayCorrectionFraction;
+ this.InterpolationDelayJitterScale = (int)clientTickRate.InterpolationDelayJitterScale;
+ this.InterpolationDelayMaxDeltaTicksFraction = (int)clientTickRate.InterpolationDelayMaxDeltaTicksFraction;
+ this.InterpolationTimeMS = (int)clientTickRate.InterpolationTimeMS;
+ this.InterpolationTimeNetTicks = (int)clientTickRate.InterpolationTimeNetTicks;
+ this.InterpolationTimeScaleMax = (int)clientTickRate.InterpolationTimeScaleMax;
+ this.InterpolationTimeScaleMin = (int)clientTickRate.InterpolationTimeScaleMin;
+ this.MaxExtrapolationTimeSimTicks = (int)clientTickRate.MaxExtrapolationTimeSimTicks;
+ this.MaxPredictAheadTimeMS = (int)clientTickRate.MaxPredictAheadTimeMS;
+ this.MaxPredictionStepBatchSizeFirstTimeTick = clientTickRate.MaxPredictionStepBatchSizeFirstTimeTick;
+ this.MaxPredictionStepBatchSizeRepeatedTick = clientTickRate.MaxPredictionStepBatchSizeRepeatedTick;
+ this.PredictionTimeScaleMax = (int)clientTickRate.PredictionTimeScaleMax;
+ this.PredictionTimeScaleMin = (int)clientTickRate.PredictionTimeScaleMin;
+ this.TargetCommandSlack = (int)clientTickRate.TargetCommandSlack;
+ }
+ }
+
[Serializable]
#if UNITY_2023_2_OR_NEWER
struct GhostScaleAnalyticsData : IAnalytic.IData
@@ -219,13 +294,12 @@ struct GhostScaleAnalyticsData
#endif
{
public PlaymodeSettings Settings;
- public int PlayerCount;
public int ServerSpawnedGhostCount;
public int GhostTypeCount;
- public uint AverageGhostInSnapshot;
+ public int AverageGhostInSnapshot;
public GhostTypeData[] GhostTypes;
- public ClientServerTickRate ClientServerTickRate;
- public ClientTickRate ClientTickRate;
+ public WrappedClientServerTickRate ClientServerTickRate;
+ public WrappedClientTickRate ClientTickRate;
public MainClientData MainClientData;
public int SnapshotTargetSize;
public int NumMainClientWorlds;
@@ -235,7 +309,6 @@ public override string ToString()
{
var builder = new StringBuilder();
builder.Append($"{nameof(Settings)}: {Settings}, " +
- $"{nameof(PlayerCount)}: {PlayerCount}, " +
$"{nameof(ServerSpawnedGhostCount)}: {ServerSpawnedGhostCount}, " +
$"{nameof(GhostTypeCount)}: {GhostTypeCount}, " +
$"{nameof(AverageGhostInSnapshot)}: {AverageGhostInSnapshot}, " +
@@ -259,10 +332,10 @@ public override string ToString()
[Serializable]
struct MainClientData
{
- public GhostRelevancyMode RelevancyMode;
+ public int RelevancyMode;
public int NumOfPredictedGhosts;
- public long NumSwitchToPredicted;
- public long NumSwitchToInterpolated;
+ public int NumSwitchToPredicted;
+ public int NumSwitchToInterpolated;
public int NumOfSpawnedGhost;
public override string ToString()
@@ -282,7 +355,6 @@ struct PlaymodeSettings
public bool SimulatorEnabled;
public int Delay;
public int DropPercentage;
- public int FuzzPercentage;
public int Jitter;
public string PlayModeType;
public string SimulatorPreset;
@@ -293,7 +365,6 @@ public override string ToString()
$"{nameof(SimulatorEnabled)}: {SimulatorEnabled}, " +
$"{nameof(Delay)}: {Delay}, " +
$"{nameof(DropPercentage)}: {DropPercentage}, " +
- $"{nameof(FuzzPercentage)}: {FuzzPercentage}, " +
$"{nameof(Jitter)}: {Jitter}, " +
$"{nameof(PlayModeType)}: {PlayModeType}, " +
$"{nameof(SimulatorPreset)}: {SimulatorPreset}, ";
@@ -306,7 +377,7 @@ static class GhostComponentAnalytics
public const int k_MaxItems = 1000;
public const string k_VendorKey = "unity.netcode";
public const string k_Scale = "NetcodeGhostComponentScale";
- public const int k_ScaleVersion = 2;
+ public const int k_ScaleVersion = 3;
public const int k_ConfigurationVersion = 1;
public const string k_Configuration = "NetcodeGhostComponentConfiguration";
diff --git a/Editor/Templates/GhostComponentSerializer.cs b/Editor/Templates/GhostComponentSerializer.cs
index 33c3dad..b2dd4a9 100644
--- a/Editor/Templates/GhostComponentSerializer.cs
+++ b/Editor/Templates/GhostComponentSerializer.cs
@@ -337,7 +337,7 @@ static internal GhostComponentSerializer.State GetState(ref SystemState state)
var innerMarker = new Unity.Profiling.ProfilerMarker("__GHOST_NAME__");
innerMarker.Begin();
#endif
- SetupFunctionPointers(ref s_State, ref state);
+ s_StateInitialized = SetupFunctionPointers(ref s_State, ref state);
//TODO: DOTS-7926 we should understand why we have in some cases a StackOverflowException.
//UNCOMMENT THIS LINE TO DEBUG IF A BIG COMPONENT MAY BE CAUSING A STACK OVERFLOW
// const int maxSizeToAvoidStackOverflow = 4_500;
@@ -356,6 +356,7 @@ static internal GhostComponentSerializer.State GetState(ref SystemState state)
}
return s_State;
}
+
private static bool s_StateInitialized;
private static GhostComponentSerializer.State s_State;
diff --git a/Runtime/Analytics/NetCodeAnalyticsState.cs b/Runtime/Analytics/NetCodeAnalyticsState.cs
index 91ed0d8..ca1ca3d 100644
--- a/Runtime/Analytics/NetCodeAnalyticsState.cs
+++ b/Runtime/Analytics/NetCodeAnalyticsState.cs
@@ -1,24 +1,12 @@
#if UNITY_EDITOR
using System.Linq;
using Unity.Entities;
-using UnityEditor;
using UnityEngine.Assertions;
namespace Unity.NetCode.Analytics
{
internal static class NetCodeAnalyticsState
{
- const string NetCodePlayerCount = "netcode_player_count";
- public static void SetPlayerCount(int playerCount)
- {
- SessionState.SetInt(NetCodePlayerCount, playerCount);
- }
-
- public static int GetPlayerCount()
- {
- return SessionState.GetInt(NetCodePlayerCount, 0);
- }
-
public static uint GetUpdateLength(World world)
{
if (!world.EntityManager.CanBeginExclusiveEntityTransaction())
diff --git a/Runtime/Authoring/DefaultVariantSystemBase.cs b/Runtime/Authoring/DefaultVariantSystemBase.cs
index 62b2513..fb0745c 100644
--- a/Runtime/Authoring/DefaultVariantSystemBase.cs
+++ b/Runtime/Authoring/DefaultVariantSystemBase.cs
@@ -164,7 +164,7 @@ protected sealed override void OnUpdate()
}
///
- /// Implement this method by adding to the mapping your
+ /// Implement this method by adding to the mapping your
/// default type->variant .
///
///
diff --git a/Runtime/Authoring/DefaultVariantSystemGroup.cs b/Runtime/Authoring/DefaultVariantSystemGroup.cs
index 3a70834..7297ac7 100644
--- a/Runtime/Authoring/DefaultVariantSystemGroup.cs
+++ b/Runtime/Authoring/DefaultVariantSystemGroup.cs
@@ -7,10 +7,10 @@ namespace Unity.NetCode
/// The system group OnCreate method finalizes the default mapping inside its own `OnCreate` method, by collecting from all the registered
/// systems the set of variant to use.
/// The order in which variants are set in the map is governed by the creation order (see , ).
+ ///
///
/// The group is present in both baking and client/server worlds.
///
- ///
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation | WorldSystemFilterFlags.ClientSimulation |
WorldSystemFilterFlags.ThinClientSimulation | WorldSystemFilterFlags.BakingSystem)]
public partial class DefaultVariantSystemGroup : ComponentSystemGroup
diff --git a/Runtime/Authoring/GhostComponentVariation.cs b/Runtime/Authoring/GhostComponentVariation.cs
index dd395cf..3f67226 100644
--- a/Runtime/Authoring/GhostComponentVariation.cs
+++ b/Runtime/Authoring/GhostComponentVariation.cs
@@ -7,11 +7,11 @@ namespace Unity.NetCode
/// present in variant declaration.
/// The component variant can be assigned at authoring time using the GhostAuthoringComponent editor.
/// Note: This is incompatible with any type implementing .
+ ///
///
/// When declaring a variant, all fields that should be serialized must be declared. Any missing field or new field
/// not present in the original struct will not be serialized.
///
- ///
[AttributeUsage(AttributeTargets.Struct)]
public class GhostComponentVariationAttribute : Attribute
{
diff --git a/Runtime/Authoring/GhostFieldAttribute.cs b/Runtime/Authoring/GhostFieldAttribute.cs
index 611fbaa..35767b5 100644
--- a/Runtime/Authoring/GhostFieldAttribute.cs
+++ b/Runtime/Authoring/GhostFieldAttribute.cs
@@ -39,9 +39,9 @@ public class GhostFieldAttribute : Attribute
public bool Composite { get; set; } = false;
///
- ///
/// Default is .
///
+ ///
public SmoothingAction Smoothing { get; set; } = SmoothingAction.Clamp;
/// Allows you to specify a custom serializer for this GhostField using the API.
diff --git a/Runtime/Authoring/GhostModifiers.cs b/Runtime/Authoring/GhostModifiers.cs
index dd89190..8577a72 100644
--- a/Runtime/Authoring/GhostModifiers.cs
+++ b/Runtime/Authoring/GhostModifiers.cs
@@ -8,7 +8,7 @@ namespace Unity.NetCode
{
///
/// Assign to every , and denotes which Ghost prefab version this component is allowed to exist on.
- /// Use this to disable rendering components on the Server version of the Ghost.
+ /// Use this to disable rendering components on the Server version of the Ghost.
/// If you cannot change the ComponentType, use the `GhostAuthoringInspectionComponent` to manually override on a specific Ghost prefab.
///
[Flags]
@@ -71,7 +71,7 @@ public enum GhostSendType
/// Meta-data of a component, denoting whether or not the server should replicate the
/// input commands back down to clients.
/// Configure via .
- /// Docs for ICommandData:
+ /// See the documentation for ICommandData:
///
[Flags]
public enum SendToOwnerType
diff --git a/Runtime/Authoring/Hybrid/BakerExtension.cs b/Runtime/Authoring/Hybrid/BakerExtension.cs
index e08f6ba..8643677 100644
--- a/Runtime/Authoring/Hybrid/BakerExtension.cs
+++ b/Runtime/Authoring/Hybrid/BakerExtension.cs
@@ -22,8 +22,8 @@ public static class BakerExtensions
/// an instance of the baker
/// state is we are converting a prefab or not
///
- /// In the editor, if a is present in the build configuration used for conversion,
- /// the target specified by the build component is used.
+ /// In the editor, if a is present in the build configuration used for conversion,
+ /// the target specified by the build component is used.
///
/// Otherwise, the conversion target will be determined by the destination world for runtime conversion, and fallback to always be
/// is nothing apply or for prefabs.
diff --git a/Runtime/Authoring/Hybrid/GhostAuthoringComponent.cs b/Runtime/Authoring/Hybrid/GhostAuthoringComponent.cs
index 7de035e..cc8e3b4 100644
--- a/Runtime/Authoring/Hybrid/GhostAuthoringComponent.cs
+++ b/Runtime/Authoring/Hybrid/GhostAuthoringComponent.cs
@@ -103,9 +103,11 @@ void OnValidate()
[Tooltip("CPU optimization that forces this ghost to be quantized and copied to the snapshot format once for all connections (instead of once per connection). This can save CPU time in the `GhostSendSystem` assuming all of the following:\n\n - The ghost contains many serialized components, serialized components on child entities, or serialized buffers.\n\n - The ghost is almost always sent to at least one connection.\n\nExample use-cases: Players, important gameplay items like footballs and crowns, global entities like map settings and dynamic weather conditions.")]
public bool UsePreSerialization;
///
+ ///
/// Only for client, force predicted spawn ghost of this type to rollback and re-predict their state from the tick client spawned them until
/// the authoritative server spawn has been received and classified. In order to save some CPU, the ghost state is rollback only in case a
/// new snapshot has been received, and it contains new predicted ghost data for this or other ghosts.
+ ///
///
/// By default this options is set to false, meaning that predicted spawned ghost by the client never rollback their original state and re-predict
/// until the authoritative data is received. This behaviour is usually fine in many situation and it is cheaper in term of CPU.
@@ -114,8 +116,10 @@ void OnValidate()
[Tooltip("Only for client, force predicted spawn ghost of this type to rollback and re-predict their state from their spawn tick until the authoritative server spawn has been received and classified. In order to save some CPU, the ghost state is rollback only in case a new snapshot has been received, and it contains new predicted ghost data for this or other ghosts.\nBy default this options is set to false, meaning that predicted spawned ghost by the client never rollback their original state and re-predict until the authoritative data is received. This behaviour is usually fine in many situation and it is cheaper in term of CPU.")]
public bool RollbackPredictedSpawnedGhostState;
///
+ ///
/// Client CPU optimization, force predicted ghost of this type to replay and re-predict their state from the last received snapshot tick in case of a structural change
/// or in general when an entry for the entity cannot be found in the prediction backup (see ).
+ ///
///
/// By default this options is set to true, to preserve the original 1.0 behavior. Once the optimization is turned on, removing or adding replicated components from the predicted ghost on the client may cause issue on the restored value. Please check the documentation, in particular the Prediction edge case and known issue.
///
diff --git a/Runtime/Authoring/TypeRegistryEntry.cs b/Runtime/Authoring/TypeRegistryEntry.cs
index a2c80f6..14c859a 100644
--- a/Runtime/Authoring/TypeRegistryEntry.cs
+++ b/Runtime/Authoring/TypeRegistryEntry.cs
@@ -1,13 +1,13 @@
namespace Unity.NetCode.Generators
{
///
- /// Used to configure the serialization/deserialization code-generation for a specific type (primitive or struct) and
+ /// Used to configure the serialization/deserialization code-generation for a specific type (primitive or struct) and
/// combination of quantized, smooting and sub-type flags.
/// The tuple [, , , ] is mapped to
/// a template file that contains the code to use to serialize/deserialize this specific type.
/// It is possible so to register for each individual type multiple serialization rules, that can be selected using the
/// .
- /// For example, the default float type (subtype 0) has 4 different serialization rules:
+ /// For example, the default float type (subtype 0) has 4 different serialization rules:
/// (float, unquantized, Clamp, 0)
/// (float, unquantized, InterpolateAndExtrapolate, 0)
/// (float, quantized, Clamp, 0)
@@ -41,12 +41,12 @@ public class TypeRegistryEntry
///
public SmoothingAction Smoothing;
///
- /// floating point number can be serialized in two ways:
+ /// floating point number can be serialized in two ways:
/// - as a full 32bit raw value
/// - as a fixed-point number, with a given precision (see )
- /// The use of quantization requires special handling by the code-generation and in particular the code in the template file
+ /// The use of quantization requires special handling by the code-generation and in particular the code in the template file
/// must uses certain rules.
- /// You should set this flag to true if the type-template combination should be used for quantized types.
+ /// You should set this flag to true if the type-template combination should be used for quantized types.
///
public bool Quantized;
///
diff --git a/Runtime/ClientServerWorld/ClientServerBootstrap.cs b/Runtime/ClientServerWorld/ClientServerBootstrap.cs
index fb875c9..de72542 100644
--- a/Runtime/ClientServerWorld/ClientServerBootstrap.cs
+++ b/Runtime/ClientServerWorld/ClientServerBootstrap.cs
@@ -86,12 +86,10 @@ public ClientServerBootstrap()
///
/// Utility method for creating a local world without any netcode systems.
- /// Name of the world instantiated.
- /// World with default systems added, set to run as the main local world.
- /// See .
///
/// The name to use for the default world.
- /// A new world instance.
+ /// World with default systems added, set to run as the main local world.
+ /// See .
public static World CreateLocalWorld(string defaultWorldName)
{
// The default world must be created before generating the system list in order to have a valid TypeManager instance.
@@ -112,7 +110,7 @@ public static World CreateLocalWorld(string defaultWorldName)
/// In the Editor, it also creates thin client worlds, if is not 0.
///
/// The name to use for the default world. Unused, can be null or empty.
- ///
+ ///
public virtual bool Initialize(string defaultWorldName)
{
// If the user added an OverrideDefaultNetcodeBootstrap MonoBehaviour to their active scene,
@@ -132,29 +130,31 @@ public virtual bool Initialize(string defaultWorldName)
/// The first override in the active scene.
public static OverrideAutomaticNetcodeBootstrap DiscoverAutomaticNetcodeBootstrap(bool logNonErrors = false)
{
+ // Note that GetActiveScene will return invalid when domain reloads are ENABLED.
var activeScene = SceneManager.GetActiveScene();
- // We must includeInactive here, otherwise we'll get zero results.
- var sceneConfigurations = UnityEngine.Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.InstanceID);
- if (sceneConfigurations.Length <= 0) return null;
+ // We must use `FindObjectsInactive.Include` here, otherwise we'll get zero results.
+ var sceneConfigurations = UnityEngine.Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None);
+ if (sceneConfigurations.Length <= 0)
+ {
+ if(logNonErrors)
+ UnityEngine.Debug.Log($"[DiscoverAutomaticNetcodeBootstrap] Did not find any instances of `OverrideAutomaticNetcodeBootstrap`.");
+ return null;
+ }
+ Array.Sort(sceneConfigurations); // Attempt to make the results somewhat deterministic and reliable via sorting by `name`, then `InstanceId`.
OverrideAutomaticNetcodeBootstrap selectedConfig = null;
for (int i = 0; i < sceneConfigurations.Length; i++)
{
var config = sceneConfigurations[i];
- // Root-level only:
- if (config.transform.root != config.transform)
- {
- Debug.LogError($"[DiscoverAutomaticNetcodeBootstrap] Ignoring OverrideAutomaticNetcodeBootstrap on GameObject '{config.name}' with value `{config.ForceAutomaticBootstrapInScene}` (in scene '{config.gameObject.scene.path}') as it's not at the root of the Hierarchy!", config);
- continue;
- }
-
// A scene comparison here DOES NOT WORK in builds, as - in a build - the GameObject has not yet been attached to its scene.
- // Thus, Active Scene Validation is only performed in editor.
- // Note: Double click on a scene to set it as the Active scene.
- var isConfigInActiveScene = !UnityEngine.Application.isEditor || config.gameObject.scene == activeScene;
+ // Update 08/24: Also true when domain reloads are enabled!
+ // Thus, Active Scene Validation is only performed when available (Editor && UnityEditor.EditorSettings.enterPlayModeOptions == None).
+ // Note: Double-click on a scene to set it as the Active scene.
+ var activeSceneIsValid = activeScene.IsValid() || SceneManager.loadedSceneCount == 1;
+ var isConfigInActiveScene = !activeSceneIsValid || !config.gameObject.scene.IsValid() || config.gameObject.scene == activeScene;
if (selectedConfig != null)
{
- var msg = $"[DiscoverAutomaticNetcodeBootstrap] Cannot select OverrideAutomaticNetcodeBootstrap on GameObject '{config.name}' with value `{config.ForceAutomaticBootstrapInScene}` (in scene '{config.gameObject.scene.path}') as we've already selected another ('{selectedConfig.name}' with value `{selectedConfig.ForceAutomaticBootstrapInScene}` in scene '{selectedConfig.gameObject.scene.path}')!";
- if (isConfigInActiveScene)
+ var msg = $"[DiscoverAutomaticNetcodeBootstrap] Cannot select `OverrideAutomaticNetcodeBootstrap` on GameObject '{config.name}' with value `{config.ForceAutomaticBootstrapInScene}` (in scene '{LogScene(config.gameObject.scene, activeScene)}') as we've already selected another ('{selectedConfig.name}' with value `{selectedConfig.ForceAutomaticBootstrapInScene}` in scene '{LogScene(selectedConfig.gameObject.scene, activeScene)}')!";
+ if (config.gameObject.scene == selectedConfig.gameObject.scene || isConfigInActiveScene)
{
msg += " It's erroneous to have multiple in the same scene!";
UnityEngine.Debug.LogError(msg, config);
@@ -173,14 +173,22 @@ public static OverrideAutomaticNetcodeBootstrap DiscoverAutomaticNetcodeBootstra
if (isConfigInActiveScene)
{
selectedConfig = config;
- if(logNonErrors)
- UnityEngine.Debug.Log($"[DiscoverAutomaticNetcodeBootstrap] Using discovered OverrideAutomaticNetcodeBootstrap on GameObject '{selectedConfig.name}' with value `{selectedConfig.ForceAutomaticBootstrapInScene}` (in Active scene '{selectedConfig.gameObject.scene.path}')!");
+ if (logNonErrors)
+ UnityEngine.Debug.Log($"[DiscoverAutomaticNetcodeBootstrap] Using discovered `OverrideAutomaticNetcodeBootstrap` on GameObject '{selectedConfig.name}' with value `{selectedConfig.ForceAutomaticBootstrapInScene}` (in scene '{LogScene(selectedConfig.gameObject.scene, activeScene)}') as it's in the active scene ({LogScene(activeScene, activeScene)})!");
continue;
}
- if(logNonErrors)
- UnityEngine.Debug.Log($"[DiscoverAutomaticNetcodeBootstrap] Ignoring OverrideAutomaticNetcodeBootstrap on GameObject '{config.name}' with value `{config.ForceAutomaticBootstrapInScene}` (in scene '{config.gameObject.scene.path}') as this scene is not the Active scene!");
+
+ if (logNonErrors)
+ UnityEngine.Debug.Log($"[DiscoverAutomaticNetcodeBootstrap] Ignoring `OverrideAutomaticNetcodeBootstrap` on GameObject '{config.name}' with value `{config.ForceAutomaticBootstrapInScene}` (in scene '{LogScene(config.gameObject.scene, activeScene)}') as this scene is not the Active scene!");
}
return selectedConfig;
+
+ static string LogScene(Scene scene, Scene active)
+ {
+ var isValid = scene.IsValid();
+ var extraWhenValid = isValid ? $",name:'{scene.name}',path:'{scene.path}'" : null;
+ return $"Scene[buildIdx:{scene.buildIndex},handle:{scene.handle},valid:{isValid},loaded:{scene.isLoaded},isSubScene:{scene.isSubScene},isActive:{(active == scene)},rootCount:{scene.rootCount}{extraWhenValid}]";
+ }
}
///
@@ -391,7 +399,7 @@ public static World CreateServerWorld(string name)
///
public static NetworkEndpoint DefaultListenAddress = NetworkEndpoint.AnyIpv4;
///
- /// Denotes if the server should start listening for incoming connection automatically after the world has been created.
+ /// Denotes if the server should start listening for incoming connection automatically after the world has been created.
///
/// If the is set, the server should start listening for connection using the
/// and .
@@ -406,8 +414,8 @@ public static World CreateServerWorld(string name)
public enum PlayType
{
///
- /// The application can run as client, server, or both. By default, both client and server worlds are created
- /// and the application can host and play as client at the same time.
+ /// The application can run as client, server, or both. By default, both client and server worlds are created
+ /// and the application can host and play as client at the same time.
///
/// This is the default modality when playing in the Editor, unless changed by using the PlayMode tool.
///
@@ -466,13 +474,13 @@ internal struct ServerClientCount
internal static readonly SharedStatic WorldCounts = SharedStatic.GetOrCreate();
///
/// Check if a world with a is present.
- /// If at least one world with flags has been created.
///
+ /// If at least one world with flags has been created.
public static bool HasServerWorld => WorldCounts.Data.serverWorlds > 0;
///
/// Check if a world with a is present.
- /// If at least one world with flags has been created.
///
+ /// If at least one world with flags has been created.
public static bool HasClientWorlds => WorldCounts.Data.clientWorlds > 0;
static class ClientServerTracker
diff --git a/Runtime/ClientServerWorld/ClientServerTickRate.cs b/Runtime/ClientServerWorld/ClientServerTickRate.cs
index 2b83d87..d090da1 100644
--- a/Runtime/ClientServerWorld/ClientServerTickRate.cs
+++ b/Runtime/ClientServerWorld/ClientServerTickRate.cs
@@ -13,21 +13,29 @@ namespace Unity.NetCode
/// server packet send rate and other related settings.
/// The singleton entity is automatically created for the clients in the
/// first update if not present.
- /// On the server, by countrary, the entity is never automatically created and it is up to the user to create the singletong instance if
+ /// On the server, by contrast, the entity is never automatically created and it is up to the user to create the singletong instance if
/// they need to.
- ///
/// This behaviour is asymmetric because the client need to have this singleton data synced with the server one. It is like
/// this for compatibility reason and It may be changed in the future.
- ///
/// In order to configure these settings you can either:
- ///
- /// - - Create the entity in a custom after the worlds has been created.
- /// - - On a system, in either the OnCreate or OnUpdate.
+ ///
+ /// - Create the entity in a custom after the worlds has been created.
+ /// - On a system, in either the OnCreate or OnUpdate.
///
/// It is not mandatory to set all the fields to a proper value when creating the singleton. It is sufficient to change only the relevant setting, and call the method to
/// configure the fields that does not have a value set.
- /// ```
+ /// The settings are synced as part of the of the initial client connection handshake.
+ /// ( data).
+ /// The ClientServerTickRate should also be used to customise other server only timing settings, such as
+ ///
+ /// - the maximum number of tick per frame
+ /// - the maximum number of tick per frame
+ /// - tick batching (<`MaxSimulationStepBatchSize`) and others.
+ ///
+ /// See the individual fields documentation for more information.
+ ///
///
+ ///
/// class MyCustomClientServerBootstrap : ClientServerBootstrap
/// {
/// override public void Initialize(string defaultWorld)
@@ -50,26 +58,16 @@ namespace Unity.NetCode
/// }
/// }
/// }
+ ///
///
- /// ```
- /// The settings are synced as part of the of the initial client connection handshake.
- /// ( data).
- /// The ClientServerTickRate should also be used to customise other server only timing settings, such as
- ///
- /// - the maximum number of tick per frame
- /// - the maximum number of tick per frame
- /// - tick batching ( and others.
- ///
- /// See the individual fields documentation for more information.
- ///
///
- ///
+ ///
/// -
/// Once the client is connected, changes to the are not replicated. If you change the settings are runtime, the same change must
/// be done on both client and server.
///
/// -
- /// The ClientServerTickRate should never be added to sub-scene with a baker. In case you want to setup the ClientServerTickRate
+ /// The ClientServerTickRate should never be added to sub-scene with a baker. In case you want to setup the ClientServerTickRate
/// based on some scene settings, we suggest to implement your own component and change the ClientServerTickRate inside a system in
/// your game.
///
@@ -451,8 +449,8 @@ public struct ClientTickRate : IComponentData
[Range(0.01f, 0.5f)]
public float InterpolationDelayMaxDeltaTicksFraction;
///
- /// The percentage of the error in the interpolation delay that can be corrected in one frame. Used to control InterpolationTickTimeScale.
- /// Must be in range (0, 1).
+ /// The percentage of the error in the interpolation delay that can be corrected in one frame. Used to control InterpolationTickTimeScale.
+ /// Must be in range (0, 1).
///
/// ________ Max
/// /
@@ -460,8 +458,8 @@ public struct ClientTickRate : IComponentData
/// Min _____/____________
/// InterpolationDelayDelta
///
- /// DefaultValue: 10% of the delta in between the current and next desired interpolation tick.
- /// Good ranges: [0.075 - 0.2]
+ /// DefaultValue: 10% of the delta in between the current and next desired interpolation tick.
+ /// Good ranges: [0.075 - 0.2]
///
[Tooltip("The percentage of the error in the interpolation delay that can be corrected in one frame. Used to control InterpolationTickTimeScale.\n\nRecommended range is [0.075 - 0.2].")]
[Range(0f, 1f)]
@@ -479,9 +477,9 @@ public struct ClientTickRate : IComponentData
[Min(1f)]
public float InterpolationTimeScaleMax;
///
- /// The percentage of the error in the predicted server tick that can be corrected each frame. Used to control the client deltaTime scaling, used to
+ /// The percentage of the error in the predicted server tick that can be corrected each frame. Used to control the client deltaTime scaling, used to
/// slow-down/speed-up the server tick estimate.
- /// Must be in (0, 1) range.
+ /// Must be in (0, 1) range.
///
///
/// ________ Max
@@ -490,7 +488,7 @@ public struct ClientTickRate : IComponentData
/// Min ______/__________
/// CommandAge
///
- /// DefaultValue: 10% of the error.
+ /// DefaultValue: 10% of the error.
/// The two major causes affecting the command age are:
/// - Network condition (Latency and Jitter)
/// - Server performance (running below the target frame rate)
@@ -498,7 +496,7 @@ public struct ClientTickRate : IComponentData
/// Small time scale values allow for smooth adjustments of the prediction tick but slower reaction to changes in both network and server frame rate.
/// By using larger values, is faster to recovery to desync situation (caused by bad network and condition or/and slow server performance) but the
/// predicted ticks delta are larger.
- /// Good ranges: [0.075 - 0.2]
+ /// Good ranges: [0.075 - 0.2]
///
[Tooltip("The percentage of the error in the predicted server tick that can be corrected each frame. Used to control the client deltaTime scaling, used to slow-down/speed-up the server tick estimate.\n\nDefaults to 10% of the error. Recommended range is [0.075 - 0.2].\n\n - Small time scale values allow for smooth adjustments of the prediction tick, but slower reaction to changes in both network and server frame rate.\n - Larger values causes recovery to be faster in desync situations, but the predicted ticks delta are larger.")]
[Range(0f, 1f)]
diff --git a/Runtime/ClientServerWorld/OverrideAutomaticNetcodeBootstrap.cs b/Runtime/ClientServerWorld/OverrideAutomaticNetcodeBootstrap.cs
index 2640dcf..f88c83c 100644
--- a/Runtime/ClientServerWorld/OverrideAutomaticNetcodeBootstrap.cs
+++ b/Runtime/ClientServerWorld/OverrideAutomaticNetcodeBootstrap.cs
@@ -14,7 +14,7 @@ namespace Unity.NetCode
/// Also note: This will not work if you use your own bootstrapper, unless you call
/// early, and return false if false.
///
- public sealed class OverrideAutomaticNetcodeBootstrap : MonoBehaviour
+ public sealed class OverrideAutomaticNetcodeBootstrap : MonoBehaviour, IComparable
{
///
[Tooltip("Note: This will only replace the bootstrap for this one scene, and only if this scene is the Active scene when entering playmode, or the first scene in the build.")]
@@ -25,5 +25,19 @@ private void OnValidate()
if(transform.root != transform)
Debug.LogError($"OverrideAutomaticNetcodeBootstrap can only be added to the root GameObject! '{this}' is invalid, and should be moved or deleted!", this);
}
+
+ ///
+ /// Tries to ensure deterministic-ish sort ordering, for reliable bootstrapping behaviour.
+ ///
+ ///
+ ///
+ int IComparable.CompareTo(OverrideAutomaticNetcodeBootstrap other)
+ {
+ if (ReferenceEquals(this, other)) return 0;
+ if (ReferenceEquals(null, other)) return 1;
+ var nameSort = string.Compare(name, other.name, StringComparison.Ordinal);
+ if (nameSort != 0) return nameSort;
+ return GetInstanceID().CompareTo(other.GetInstanceID());
+ }
}
}
diff --git a/Runtime/Command/CommandSendSystem.cs b/Runtime/Command/CommandSendSystem.cs
index 2ab3ed0..564c80c 100644
--- a/Runtime/Command/CommandSendSystem.cs
+++ b/Runtime/Command/CommandSendSystem.cs
@@ -579,9 +579,9 @@ private static uint GetDataAtTickAndCmp(NetworkTick targetTick, ref TCommandData
}
///
- /// Lookup all the ghost entities for which commands need to be serialized for the current
+ /// Lookup all the ghost entities for which commands need to be serialized for the current
/// tick and enqueue them into the .
- /// Are considered as potential ghost targets:
+ /// Are considered as potential ghost targets:
/// - the entity referenced by the
/// - All ghosts owned by the player (see ) that present
/// an enabled components.
diff --git a/Runtime/Command/CommandTarget.cs b/Runtime/Command/CommandTarget.cs
index ee7b36e..c418d18 100644
--- a/Runtime/Command/CommandTarget.cs
+++ b/Runtime/Command/CommandTarget.cs
@@ -11,14 +11,15 @@ public struct CommandTargetComponent : IComponentData
{}
///
- /// Component added to all , stores a reference to the entity
+ /// Component added to all , stores a reference to the entity
/// where commands should be read from (client) or written to (server).
/// It is mandatory to set a valid reference to the in order to receive client
- /// commands if:
- /// - you are not using the .
- /// - you want to support thin-clients (because does not work in that case)
+ /// commands if:
+ ///
+ /// - You are not using the .
+ /// - You want to support thin-clients (because does not work in that case)
/// The use of and CommandTarget is complementary. I.e. They can both be used
- /// at the same time.
+ /// at the same time.
///
///
/// The target entity must have at least one `ICommandData` component on it.
diff --git a/Runtime/Connection/DefaultDriverConstructor.cs b/Runtime/Connection/DefaultDriverConstructor.cs
index 54a4450..9c6755b 100644
--- a/Runtime/Connection/DefaultDriverConstructor.cs
+++ b/Runtime/Connection/DefaultDriverConstructor.cs
@@ -56,9 +56,6 @@ public static NetworkSettings GetNetworkSettings()
public static NetworkSettings GetNetworkServerSettings(int playerCount = 0)
{
var settings = new NetworkSettings();
-#if UNITY_EDITOR
- NetCodeAnalyticsState.SetPlayerCount(playerCount);
-#endif
settings.WithReliableStageParameters(windowSize: DefaultWindowSize)
.WithFragmentationStageParameters(payloadCapacity: DefaultPayloadCapacity);
#if UNITY_EDITOR || NETCODE_DEBUG
@@ -75,7 +72,7 @@ public static NetworkSettings GetNetworkServerSettings(int playerCount = 0)
///
/// Helper method for creating NetworkDriver suitable for client.
- /// The driver will use the the specified INetworkInterface and is configured
+ /// The driver will use the the specified and is configured
/// using the internal defaults. See: .
///
/// the type ot use
@@ -126,7 +123,7 @@ private static int QueueSizeFromPlayerCount(int playerCount)
#if !UNITY_WEBGL || UNITY_EDITOR
///
- /// Helper method for creating server NetworkDriver given the specified INetworkInterface
+ /// Helper method for creating server NetworkDriver given the specified .
/// The driver is configured with the internal defaults. See: .
///
/// the type ot use
@@ -139,10 +136,10 @@ public static NetworkDriverStore.NetworkDriverInstance CreateServerNetworkDriver
}
///
- /// Helper method for creating server NetworkDriver given the specified INetworkInterface
- /// The driver is configured using the NetworkSettings.
+ /// Helper method for creating server NetworkDriver given the specified
+ /// The driver is configured using the
///
- /// the type ot use
+ /// The type to use
///
/// A list of the parameters that describe the network configuration.
/// A new
@@ -200,9 +197,9 @@ public static bool ClientUseSocketDriver(NetDebug netDebug)
///
/// Register a NetworkDriver instance in the that uses either:
///
- /// a single NetworkDriver if the both client and server worlds are present in the same process.
- /// a single driver if you are targeting a standalone platform.
- /// a single if you are targeting WebGL.
+ /// - a single NetworkDriver if both the client and server worlds are present in the same process.
+ /// - a single driver if you are targeting a standalone platform.
+ /// - a single if you are targeting WebGL.
///
/// These are configured using internal defaults. See: .
///
@@ -217,11 +214,11 @@ public static void RegisterClientDriver(World world, ref NetworkDriverStore driv
///
/// Register a NetworkDriver instance in the that uses either:
///
- /// a single NetworkDriver if the both client and server worlds are present in the same process.
- /// a single driver if you are targeting a standalone platform.
- /// a single if you are targeting WebGL.
+ /// - a single NetworkDriver if both the client and server worlds are present in the same process.
+ /// - a single driver if you are targeting a standalone platform.
+ /// - a single if you are targeting WebGL.
///
- /// These are configured using the NetworkSettings passed in.
+ /// These are configured using the passed in.
///
/// Used for determining whether we are running in a client or server world.
/// Store for NetworkDriver.
@@ -246,7 +243,7 @@ public static void RegisterClientDriver(World world, ref NetworkDriverStore driv
#if !UNITY_WEBGL || UNITY_EDITOR
///
/// Register a NetworkDriver instance in .
- /// This are configured using the NetworkSettings passed in.
+ /// This are configured using the passed in.
///
/// Used for determining whether we are running in a client or server world.
/// Store for NetworkDriver.
@@ -263,7 +260,7 @@ public static void RegisterClientUdpDriver(World world, ref NetworkDriverStore d
#endif
///
/// Register a NetworkDriver instance in .
- /// This are configured using the NetworkSettings passed in. The constructed driver
+ /// This are configured using the passed in. The constructed driver
/// does not use a reliable pipeline stage (websocket are already reliable) and the
/// instance is a .
///
@@ -303,7 +300,7 @@ public static void RegisterClientWebSocketDriver(World world, ref NetworkDriverS
}
///
/// Register an NetworkDriver instance in .
- /// This are configured using the NetworkSettings passed in.
+ /// This are configured using the passed in.
///
/// Used for determining whether we are running in a client or server world.
/// Store for NetworkDriver.
@@ -322,9 +319,9 @@ public static void RegisterClientIpcDriver(World world, ref NetworkDriverStore d
///
/// Register multiple NetworkDriver instances to the that uses different :
///
- /// One driver that uses if the is Client/Server.
- /// One driver that uses if the current build target is a standalone platorm (no WebGL) or dedicated server.
- /// One driver that uses if the current build target is WebGL.
+ /// - One driver that uses if the `ClientServerBootstrap.RequestedPlayType` is Client/Server.
+ /// - One driver that uses if the current build target is a standalone platorm (no WebGL) or dedicated server.
+ /// - One driver that uses if the current build target is WebGL.
///
/// These are configured using internal defaults. See: .
///
@@ -340,11 +337,11 @@ public static void RegisterServerDriver(World world, ref NetworkDriverStore driv
///
/// Register a multiple NetworkDriver instances to hte :
///
- /// One driver that uses if the is Client/Server.
- /// One driver that uses if the current build target is a standalone platorm (no WebGL) or dedicated server.
- /// One driver that uses if the current build target is WebGL.
+ /// - One driver that uses if the `ClientServerBootstrap.RequestedPlayType` is Client/Server.
+ /// - One driver that uses if the current build target is a standalone platorm (no WebGL) or dedicated server.
+ /// - One driver that uses if the current build target is WebGL.
///
- /// These drivers are configured using the NetworkSettings passed in.
+ /// These drivers are configured using the NetworkSettings passed in.
///
/// Used for determining whether we are running in a client or server world.
/// Store for NetworkDriver.
@@ -363,7 +360,7 @@ public static void RegisterServerDriver(World world, ref NetworkDriverStore driv
///
/// Register a NetworkDriver instance in .
- /// This are configured using the NetworkSettings passed in.
+ /// This are configured using the passed in.
///
/// If the requested is
/// this will do nothing as no local clients will ever make use of the IPC mechanism.
@@ -388,7 +385,7 @@ public static void RegisterServerIpcDriver(World world, ref NetworkDriverStore d
///
/// Register a NetworkDriver instance in .
- /// This are configured using the NetworkSettings passed in.
+ /// These are configured using the passed in.
///
/// Used for determining whether we are running in a client or server world.
/// Store for NetworkDriver.
@@ -405,7 +402,7 @@ public static void RegisterServerUdpDriver(World world, ref NetworkDriverStore d
///
/// Register a NetworkDriver instance in .
- /// This are configured using the NetworkSettings passed in. The constructed driver
+ /// This are configured using the passed in. The constructed driver
/// does not use a reliable pipeline stage (websocket are already reliable) and the
/// instance is a .
///
@@ -496,9 +493,9 @@ public static void RegisterClientDriver(World world, ref NetworkDriverStore driv
///
/// Register a multiple NetworkDriver instances to hte :
///
- /// One driver that uses if the is Client/Server.
- /// For all targets apart WebGL, one driver instance using a . For WebGL and in the Editor, one driver instance using the
- /// .
+ /// - One driver that uses if the is Client/Server.
+ /// - For all targets apart WebGL, one driver instance using a . For WebGL and in the Editor, one driver instance using the
+ /// .
///
/// These are configured using the default settings. See .
///
@@ -541,9 +538,9 @@ public static void RegisterClientDriver(World world, ref NetworkDriverStore driv
///
/// Register multiple NetworkDriver instances to the that uses different :
///
- /// One driver that uses if the is Client/Server.
- /// One driver that uses if the current build target is a standalone platorm (no WebGL) or dedicated server.
- /// One driver that uses if the current build target is WebGL.
+ /// - One driver that uses if the is Client/Server.
+ /// - One driver that uses if the current build target is a standalone platorm (no WebGL) or dedicated server.
+ /// - One driver that uses if the current build target is WebGL.
///
/// These are configured using internal defaults. See: .
///
@@ -573,8 +570,8 @@ public static void RegisterServerDriver(World world, ref NetworkDriverStore driv
/// - a single NetworkDriver if the both client and server worlds are present in the same process.
/// - a single driver in all other cases.
/// In the Editor and Development build, if the network simulator is enabled, force on the client to use the network driver.
+ /// To let the client use the IPC network interface when in client and server mode, you must create the server world first (in other words; call `NetworkStreamDriver.Listen` on it before attempting to connect to it).
///
- /// To let the client use the IPC network interface In ClientServer mode it is mandatory to always create the server world first.
public struct IPCAndSocketDriverConstructor : INetworkStreamDriverConstructor
{
///
diff --git a/Runtime/Connection/NetCodeConnectionEvent.cs b/Runtime/Connection/NetCodeConnectionEvent.cs
index e799ab0..f3b7805 100644
--- a/Runtime/Connection/NetCodeConnectionEvent.cs
+++ b/Runtime/Connection/NetCodeConnectionEvent.cs
@@ -5,15 +5,9 @@
namespace Unity.NetCode
{
///
- /// Contains a single, discrete client connect / disconnect event.
- /// Raised any time any connection changes .
- /// These events are cleared automatically, by the netcode package.
- /// Do not consume them yourself.
+ /// Contains a single, discrete 'NetworkConnection' connect / disconnect event.
+ /// For more details, refer to .
///
- ///
- /// These events are raised on client worlds, too, but only when said client connects to - or disconnects from -
- /// the server. I.e. You will NOT receive events for other players.
- ///
public struct NetCodeConnectionEvent
{
///
diff --git a/Runtime/Connection/NetworkDriverStore.cs b/Runtime/Connection/NetworkDriverStore.cs
index 5b56eb9..da39780 100644
--- a/Runtime/Connection/NetworkDriverStore.cs
+++ b/Runtime/Connection/NetworkDriverStore.cs
@@ -311,9 +311,10 @@ internal readonly unsafe ref NetworkDriverData GetDriverDataRO(int driverId)
///
/// Returns the instance, by ref.
///
- ///
+ ///
/// The instance, by ref.
- ///
+ ///
+ ///
internal unsafe ref NetworkDriverData GetDriverDataRW(int driverId)
{
fixed (NetworkDriverStore* store = &this)
@@ -339,57 +340,64 @@ internal unsafe ref NetworkDriverData GetDriverDataRW(int driverId)
/// that update internal driver data (that aren't suited to be copied around) may not work as expected.
///
///
- ///
+ ///
+ ///
[Obsolete("Prefer GetDriverInstanceRW or GetDriverInstanceRO to avoid copying.", false)]
public readonly ref NetworkDriverInstance GetDriverInstance(int driverId) => ref GetDriverDataRO(driverId).instance;
///
/// Return the with the given .
///
- ///
+ ///
///
- ///
+ ///
+ ///
[Obsolete("Prefer GetDriverRW or GetDriverRO to avoid copying.", false)]
public readonly NetworkDriver GetNetworkDriver(int driverId) => GetDriverDataRO(driverId).instance.driver;
///
/// Return a reference to the instance with the given .
///
- ///
+ ///
///
- ///
+ ///
+ ///
public ref NetworkDriverStore.NetworkDriverInstance GetDriverInstanceRW(int driverId) => ref GetDriverDataRW(driverId).instance;
///
/// Return a reference to the instance with the given .
///
- ///
+ ///
///
- ///
+ ///
+ ///
public ref readonly NetworkDriverStore.NetworkDriverInstance GetDriverInstanceRO(int driverId) => ref GetDriverDataRO(driverId).instance;
///
/// Retrieve a ReadWrite reference to the for the given .
///
- ///
+ ///
///
- ///
+ ///
+ ///
public ref NetworkDriver GetDriverRW(int driverId) => ref GetDriverInstanceRW(driverId).driver;
///
/// Retrieve a Read-Only reference to the for the given .
///
- ///
+ ///
///
- ///
+ ///
+ ///
public ref readonly NetworkDriver GetDriverRO(int driverId) => ref GetDriverInstanceRO(driverId).driver;
///
/// Return the transport type used by the registered driver.
///
- ///
+ ///
///
- ///
+ ///
+ ///
public TransportType GetDriverType(int driverId) => GetDriverDataRO(driverId).transportType;
///
@@ -402,9 +410,9 @@ internal unsafe ref NetworkDriverData GetDriverDataRW(int driverId)
///
/// Signature for all functions that can be used to visit the registered drivers in the store using the method.
+ ///
/// a reference to a
/// the id of the driver
- ///
public delegate void DriverVisitor(ref NetworkDriverInstance driver, int driverId);
///
diff --git a/Runtime/Connection/NetworkProtocolVersion.cs b/Runtime/Connection/NetworkProtocolVersion.cs
index d6f97cd..c45a397 100644
--- a/Runtime/Connection/NetworkProtocolVersion.cs
+++ b/Runtime/Connection/NetworkProtocolVersion.cs
@@ -9,20 +9,21 @@
namespace Unity.NetCode
{
///
- /// The NetworkProtocolVersion is a singleton entity that is automatically created by the
+ /// The NetworkProtocolVersion is a singleton entity that is automatically created by the
/// (once the GhostCollection is ready), and is used to verify client and
- /// server compatibility.
+ /// server compatibility.
///
- /// The protocol version is composed by different part:
+ /// The protocol version is composed by different part:
/// - The NetCode package version.
/// - A user defined game version, that identify the version of your game
/// - A unique hash of all the and that is used to verify both client and server
/// recognize the same rpc and command and that can serialize/deserialize them in the same way
/// - A unique hash of all the replicated and that is used to verify
/// both client and server can serialize/deserialize all the replicated component present in the ghosts
- ///
+ ///
/// When a client tries to connect to the server, as part of the initial handshake, they exchange their protocol version
/// to validate they are both using same version. If the version mismatch, the connection is forcibly closed.
+ ///
///
public struct NetworkProtocolVersion : IComponentData
{
diff --git a/Runtime/Connection/NetworkSnapshotAck.cs b/Runtime/Connection/NetworkSnapshotAck.cs
index 301535d..db0757e 100644
--- a/Runtime/Connection/NetworkSnapshotAck.cs
+++ b/Runtime/Connection/NetworkSnapshotAck.cs
@@ -112,7 +112,7 @@ public bool IsReceivedByRemote(NetworkTick tick)
}
///
- /// The last snapshot (tick) received from the remote peer.
+ /// The last snapshot (tick) received from the remote peer.
/// For the client, it represents the last received snapshot received from the server.
/// For the server, it is the last acknowledge packet that has been received by client.
///
@@ -122,7 +122,7 @@ public bool IsReceivedByRemote(NetworkTick tick)
private ulong ReceivedSnapshotByRemoteMask2;
private ulong ReceivedSnapshotByRemoteMask3;
///
- /// The field has a different meaning on the client vs on the server:
+ /// The field has a different meaning on the client vs on the server:
/// Client: it is the last received ghost snapshot from the server.
/// Server: record the last command tick that has been received. Used to discard either out of order or late commands.
///
diff --git a/Runtime/Connection/NetworkStreamConnectionComponent.cs b/Runtime/Connection/NetworkStreamConnectionComponent.cs
index cb568ca..8fa4e25 100644
--- a/Runtime/Connection/NetworkStreamConnectionComponent.cs
+++ b/Runtime/Connection/NetworkStreamConnectionComponent.cs
@@ -10,17 +10,17 @@
namespace Unity.NetCode
{
///
- /// A connection is represented by an entity having a NetworkStreamConnection.
+ /// A connection is represented by an entity having a NetworkStreamConnection.
/// The component hold a reference to the underlying transport and the
/// that created it.
- /// All connections share a common set of components:
+ /// All connections share a common set of components:
/// -
/// -
/// -
/// -
/// -
/// -
- /// Client connections also have a to handle server ghost snapshots.
+ /// Client connections also have a to handle server ghost snapshots.
///
/// Never destroy this entity yourself. You'll receive an error if you attempt to do so.
public struct NetworkStreamConnection : ICleanupComponentData
@@ -217,7 +217,7 @@ public enum State
public NetworkStreamDisconnectReason DisconnectReason;
///
- /// Check if two connection state are equals. They are if:
+ /// Check if two connection state are equals. They are if:
/// - The is the same.
/// - The is the same.
/// - The is the same.
diff --git a/Runtime/Connection/NetworkStreamDriver.cs b/Runtime/Connection/NetworkStreamDriver.cs
index cfd5e36..9158ba6 100644
--- a/Runtime/Connection/NetworkStreamDriver.cs
+++ b/Runtime/Connection/NetworkStreamDriver.cs
@@ -42,7 +42,7 @@ internal NetworkStreamDriver(void* driverStore, NativeReference numIds, Nat
///
///
/// has specific usage patterns (see for loop use-cases below). Use with care!
- /// Copying such a large struct is expensive, prefer ref var driverStore = ref networkStreamDriver.RefRW.DriverStore;
syntax.
+ /// Copying such a large struct is expensive, prefer ref var driverStore = ref networkStreamDriver.RefRW.DriverStore; syntax.
///
public ref NetworkDriverStore DriverStore => ref UnsafeUtility.AsRef(m_DriverPointer).DriverStore;
@@ -56,9 +56,9 @@ internal NetworkStreamDriver(void* driverStore, NativeReference numIds, Nat
/// Convenience. Records the DriverStore used in the latest call to or .
///
///
- /// Note that the actual Endpoint used by each may be different,
- /// due to .
- /// See and .
+ /// Note that the actual Endpoint used by each may be different,
+ /// due to .
+ /// See and .
///
public NetworkEndpoint LastEndPoint { get; internal set; }
@@ -93,13 +93,52 @@ public bool RequireConnectionApproval
internal byte RequireConnectionApprovalInternal;
///
- /// Stores all 's raised by Netcode for this tick.
- /// Allows user-code to subscribe to connection and disconnection events.
- /// Self-cleaning list, thus no consume API.
+ ///
+ /// Stores all s raised by Netcode for this
+ /// tick,
+ /// which allows user code to subscribe to connection and disconnection events (including
+ /// and , if
+ /// applicable).
+ /// Refer to the Network connection page
+ /// (https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/manual/network-connection.html)
+ /// for more details.
+ ///
+ ///
+ /// It's a self-cleaning list and therefore has no consume API (in other words, there's no need to explicitly
+ /// remove entries from this collection, which is why it's read-only). This also means that events are only
+ /// valid for a single tick, and therefore must be polled inside this group.
+ ///
+ ///
+ /// This collection is cleared and repopulated in the , which
+ /// is also the ECB playback that creates and destroys 'NetworkConnection'
+ /// entities.
+ /// Therefore, if you query this collection after the `NetworkGroupCommandBufferSystem` system (via the
+ /// ),
+ /// you'll get the current tick's event data, but if you poll before it, your event data will always be one tick
+ /// out of date.
+ ///
+ ///
+ /// [BurstCompile]
+ /// void ISystem.OnUpdate(ref SystemState state)
+ /// {
+ /// foreach (var evt in SystemAPI.GetSingleton<NetworkStreamDriver>().ConnectionEventsForTick)
+ /// {
+ /// UnityEngine.Debug.Log($"[{state.WorldUnmanaged.Name}] {evt.ToFixedString()}!");
+ /// }
+ /// }
///
///
- /// Because events are only valid for a single tick, any code that reads from (i.e. consumes) these events must
- /// update in the .
+ ///
+ /// This collection can be safely passed into jobs, as long as the singleton
+ /// is fetched as read/write.
+ ///
+ ///
+ /// These events are raised on client worlds as well, but only for your own client world.
+ /// I.e. Each client does not receive events regarding other clients. Refer to the PlayerList NetcodeSamples sample
+ /// (https://github.com/Unity-Technologies/EntityComponentSystemSamples/tree/master/NetcodeSamples/Assets/Samples/PlayerList)
+ /// for an example implementation of RPC logic that actually communicates player join and leave events (with
+ /// display names and s).
+ ///
///
public NativeArray.ReadOnly ConnectionEventsForTick { get; internal set; }
diff --git a/Runtime/Connection/NetworkStreamReceiveSystem.cs b/Runtime/Connection/NetworkStreamReceiveSystem.cs
index 3136016..338465c 100644
--- a/Runtime/Connection/NetworkStreamReceiveSystem.cs
+++ b/Runtime/Connection/NetworkStreamReceiveSystem.cs
@@ -229,10 +229,10 @@ public void OnUpdate(ref SystemState systemState)
}
///
- /// The NetworkStreamReceiveSystem is one of the most important system of the NetCode package and its fundamental job
+ /// The NetworkStreamReceiveSystem is one of the most important system of the NetCode package and its fundamental job
/// is to manage all the life-cycles (creation, update, destruction), and receiving all the
/// message types.
- /// It is responsible also responsible for:
+ /// It is responsible also responsible for:
/// - creating the singleton (see also and ).
/// - handling the driver migration (see and ).
/// - listening and accepting incoming connections (server).
diff --git a/Runtime/Connection/SnapshotPacketLossStatistics.cs b/Runtime/Connection/SnapshotPacketLossStatistics.cs
index 35fc8d6..2a33795 100644
--- a/Runtime/Connection/SnapshotPacketLossStatistics.cs
+++ b/Runtime/Connection/SnapshotPacketLossStatistics.cs
@@ -35,6 +35,12 @@ public struct SnapshotPacketLossStatistics
/// Count of packets lost in some form.
public ulong CombinedPacketLossCount => NumPacketsDroppedNeverArrived + NumPacketsCulledOutOfOrder + NumPacketsCulledAsArrivedOnSameFrame;
+ ///
+ /// Adds two SnapshotPacketLossStatistics
+ ///
+ /// First SnapshotPacketLossStatistics
+ /// Second SnapshotPacketLossStatistics
+ /// The resulting sum of the two SnapshotPacketLossStatistics.
public static SnapshotPacketLossStatistics operator +(SnapshotPacketLossStatistics a, SnapshotPacketLossStatistics b)
{
a.NumPacketsReceived += b.NumPacketsReceived;
@@ -44,6 +50,12 @@ public struct SnapshotPacketLossStatistics
return a;
}
+ ///
+ /// Subtracts two SnapshotPacketLossStatistics
+ ///
+ /// First SnapshotPacketLossStatistics
+ /// Second SnapshotPacketLossStatistics
+ /// The resulting difference of the two SnapshotPacketLossStatistics.
public static SnapshotPacketLossStatistics operator -(SnapshotPacketLossStatistics a, SnapshotPacketLossStatistics b)
{
// Guard subtraction as it can get negative when we're polling 3s intervals.
diff --git a/Runtime/Physics/Hybrid/NetCodePhysicsConfig.cs b/Runtime/Physics/Hybrid/NetCodePhysicsConfig.cs
index dc4aa0b..ee65e93 100644
--- a/Runtime/Physics/Hybrid/NetCodePhysicsConfig.cs
+++ b/Runtime/Physics/Hybrid/NetCodePhysicsConfig.cs
@@ -34,16 +34,16 @@ public sealed class NetCodePhysicsConfig : MonoBehaviour
///
/// When using predicted physics all dynamic physics objects in the main physics world on the client
- /// mus be ghosts. Setting this will move any non-ghost in the default physics world to another world.
+ /// must be ghosts. Setting this will move any non-ghost in the default physics world to another world.
///
[Tooltip("The physics world index to use for all dynamic physics objects which are not ghosts.")]
public uint ClientNonGhostWorldIndex = 0;
- /// >
+ ///
[Tooltip("Denotes whether or not Netcode will deep copy dynamic colliders into the Lag Compensation CollisionWorld ring buffer used for Lag Compensation.\n\nRecommendation & Default: True.\n\nEnable this if you get exceptions when querying since-destroyed entities.")]
public bool DeepCopyDynamicColliders = true;
- /// >
+ ///
[Tooltip("Denotes whether or not Netcode will deep copy static colliders into the Lag Compensation CollisionWorld ring buffer used for Lag Compensation.\n\nEnable if you need perfectly accurate lag compensation query results with static colliders, which is typically only necessary if they occasionally change.\n\nRecommendation & Default: False.\n\nInstead: Run two queries - one against static geometry - then another against the dynamic entities in the historic buffer.")]
public bool DeepCopyStaticColliders;
}
diff --git a/Runtime/Physics/Hybrid/NetCodePhysicsInspector.cs b/Runtime/Physics/Hybrid/NetCodePhysicsInspector.cs
index 0f0f045..6562b00 100644
--- a/Runtime/Physics/Hybrid/NetCodePhysicsInspector.cs
+++ b/Runtime/Physics/Hybrid/NetCodePhysicsInspector.cs
@@ -10,6 +10,7 @@ public sealed class NetCodePhysicsInspector : UnityEditor.Editor
private SerializedProperty EnableLagCompensation;
private SerializedProperty ServerHistorySize;
private SerializedProperty ClientHistorySize;
+ private SerializedProperty ClientNonGhostWorldIndex;
private SerializedProperty DeepCopyDynamicColliders;
private SerializedProperty DeepCopyStaticColliders;
private static readonly GUIContent s_LagCompensationTitle = new GUIContent("Lag Compensation", "Configure how the Lag Compensation ring buffers function.");
@@ -19,6 +20,7 @@ private void OnEnable()
EnableLagCompensation = serializedObject.FindProperty(nameof(NetCodePhysicsConfig.EnableLagCompensation));
ServerHistorySize = serializedObject.FindProperty(nameof(NetCodePhysicsConfig.ServerHistorySize));
ClientHistorySize = serializedObject.FindProperty(nameof(NetCodePhysicsConfig.ClientHistorySize));
+ ClientNonGhostWorldIndex = serializedObject.FindProperty(nameof(NetCodePhysicsConfig.ClientNonGhostWorldIndex));
DeepCopyDynamicColliders = serializedObject.FindProperty(nameof(NetCodePhysicsConfig.DeepCopyDynamicColliders));
DeepCopyStaticColliders = serializedObject.FindProperty(nameof(NetCodePhysicsConfig.DeepCopyStaticColliders));
}
@@ -40,6 +42,8 @@ public override void OnInspectorGUI()
EditorGUI.indentLevel -= 1;
}
+ EditorGUILayout.PropertyField(ClientNonGhostWorldIndex);
+
if (serializedObject.hasModifiedProperties)
serializedObject.ApplyModifiedProperties();
}
diff --git a/Runtime/Physics/PhysicsVelocityVariant.cs b/Runtime/Physics/PhysicsVelocityVariant.cs
index 664f3bb..4c83b57 100644
--- a/Runtime/Physics/PhysicsVelocityVariant.cs
+++ b/Runtime/Physics/PhysicsVelocityVariant.cs
@@ -37,13 +37,13 @@ public struct PhysicsGraphicalSmoothingDefaultVariant
///
/// Optionally register the default variant to use for the and the
/// .
+ ///
///
- /// It will never override the default assignment for the `PhysicsVelocity` nor the `PhysicsGraphicalSmoothing` components
- /// if they are already present in the map.
+ /// It will never override the default assignment for the `PhysicsVelocity` nor the `PhysicsGraphicalSmoothing` components
+ /// if they are already present in the map.
/// Any system deriving from will take precendence, even if they are created
/// after this system.
///
- ///
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation | WorldSystemFilterFlags.ClientSimulation |
WorldSystemFilterFlags.ThinClientSimulation | WorldSystemFilterFlags.BakingSystem)]
[CreateAfter(typeof(GhostComponentSerializerCollectionSystemGroup))]
diff --git a/Runtime/PredictionTicking/GhostSimulationSystemGroup.cs b/Runtime/PredictionTicking/GhostSimulationSystemGroup.cs
index 0e988f9..20e11d1 100644
--- a/Runtime/PredictionTicking/GhostSimulationSystemGroup.cs
+++ b/Runtime/PredictionTicking/GhostSimulationSystemGroup.cs
@@ -4,9 +4,9 @@
namespace Unity.NetCode
{
///
- /// Present for both client and server worlds (and Local, for singleplayer input support).
+ /// Present for both client and server worlds (and Local, for singleplayer input support).
/// This is the core group, and contains the majority of the netcode systems.
- /// Its responsibilities are varied, and can be roughly sub-divided in the following categories:
+ /// Its responsibilities are varied, and can be roughly sub-divided in the following categories:
/// -input gathering:
/// -command handling:
/// -ghost prediction/simulation:
diff --git a/Runtime/PredictionTicking/NetworkTimeSystem.cs b/Runtime/PredictionTicking/NetworkTimeSystem.cs
index 4326fd3..f4adb04 100644
--- a/Runtime/PredictionTicking/NetworkTimeSystem.cs
+++ b/Runtime/PredictionTicking/NetworkTimeSystem.cs
@@ -265,10 +265,10 @@ public static void ResetFixedTime()
/// Return a low precision real-time stamp that represents the number of milliseconds since the process started.
/// In Development build and Editor, the maximum reported delta in between two calls of the TimestampMS is capped
/// to 100 milliseconds.
+ ///
///
/// The TimestampMS is mostly used for sake of time synchronization (for calculting the RTT).
///
- ///
public static uint TimestampMS
{
get
@@ -293,10 +293,10 @@ public static uint TimestampMS
/// Return a low precision real-time stamp that represents the number of milliseconds since the process started.
/// In Development build and Editor, the maximum reported delta in between two calls of the TimestampMS is capped
/// to 100 milliseconds.
+ ///
///
/// The TimestampMS is mostly used for sake of time synchronization (for calculting the RTT).
///
- ///
public static uint TimestampMS =>
(uint)TimerHelpers.GetCurrentTimestampMS();
#endif
diff --git a/Runtime/PredictionTicking/UpdateRateManagement/NetcodeServerRateManager.cs b/Runtime/PredictionTicking/UpdateRateManagement/NetcodeServerRateManager.cs
index 61d7c75..8d0611d 100644
--- a/Runtime/PredictionTicking/UpdateRateManagement/NetcodeServerRateManager.cs
+++ b/Runtime/PredictionTicking/UpdateRateManagement/NetcodeServerRateManager.cs
@@ -108,6 +108,7 @@ public float Timestep
/// less busy one frame out of two. This can be used to do extra operations.
/// This method can be accessible through the server's rate manager.
///
+ ///
///
/// [WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
/// [UpdateInGroup(typeof(InitializationSystemGroup))]
@@ -121,7 +122,6 @@ public float Timestep
/// }
/// }
///
- ///
/// Whether the server's simulation system group will update this frame or not
public bool WillUpdate()
{
diff --git a/Runtime/Rpc/IRpcCommand.cs b/Runtime/Rpc/IRpcCommand.cs
index 6bf8022..6edb2bc 100644
--- a/Runtime/Rpc/IRpcCommand.cs
+++ b/Runtime/Rpc/IRpcCommand.cs
@@ -5,7 +5,7 @@
namespace Unity.NetCode
{
///
- /// An interface that should be used to declare a struct.
+ /// An interface that should be used to declare a struct.
///
/// RPCs are "one-shot" messages that can be sent and received by both the client and server, and can be used for different
/// purposes. E.g. Implementing a lobby, loading level logic, requesting to spawn a player etc.
@@ -31,25 +31,25 @@ namespace Unity.NetCode
/// Usage: To send an RPC declared using the interface, you should create a new entity with your rpc message component,
/// as well as a (which will notify the NetCode system that it exists, and send it).
/// It is best to do this with an archetype to avoid runtime structural changes:
- ///
+ ///
///
/// m_RpcArchetype = EntityManager.CreateArchetype(..);
///
/// var ent = EntityManager.CreateEntity(m_RpcArchetype);
/// EntityManager.SetComponentData(new MyRpc { SomeData = 5 });
///
- ///
///
/// RPCs declared using the will have serialization and other boilerplate code for handling
/// the request automatically generated.
/// For example:
+ ///
///
/// public struct MyRpc : IRpcCommand
/// {
/// public int SomeData;
/// }
///
- /// will generate the following systems and structs:
+ /// will generate the following systems and structs:
/// - A struct implementing the for your rpc type.
/// - A system responsible for consuming the requests, and queuing
/// the messages into the stream (for the outgoing connection), invoked via
@@ -124,11 +124,12 @@ public struct RpcDeserializerState
}
///
- /// Interface that must be implemented by a burst-compatible struct to serialize/deserialize the
- /// specified rpc type.
+ /// Interface that must be implemented by a burst-compatible struct to serialize/deserialize the
+ /// specified type.
/// A common pattern is to make the struct declaring the rpc to also implement the serialize/deserialize interface.
/// For example:
- ///
+ ///
+ ///
/// struct MyRpc : IComponentData, IRpcCommandSerializer{MyRpc}
/// {
/// public void Serialize(ref DataStreamWriter writer, in RpcSerializerState state, in MyRpc data)
@@ -138,11 +139,12 @@ public struct RpcDeserializerState
/// PortableFunctionPointer{RpcExecutor.ExecuteDelegate} CompileExecute()
/// { ... }
/// }
- ///
- ///
+ ///
+ ///
/// When declaring an rpc using the interface, it is not necessary to implement the
/// `IRpcCommandSerializer` interface yourself; the code-generation will automatically create a struct implementing the interface
/// and all necessary boilerplate code.
+ ///
///
///
public interface IRpcCommandSerializer where T: struct, IComponentData
diff --git a/Runtime/Rpc/RpcCommandRequest.cs b/Runtime/Rpc/RpcCommandRequest.cs
index 15b661a..3e700ac 100644
--- a/Runtime/Rpc/RpcCommandRequest.cs
+++ b/Runtime/Rpc/RpcCommandRequest.cs
@@ -109,8 +109,8 @@ public struct RpcCommandRequest
where TActionSerializer : unmanaged, IRpcCommandSerializer
{
///
- /// A struct that can be embedded into your system job, and should be used to delegate the rpc handling.
- /// Example of use:
+ /// A struct that can be embedded into your system job, and should be used to delegate the rpc handling.
+ /// Example of use:
///
/// [BurstCompile]
/// struct SendRpc : IJobChunk
@@ -122,8 +122,8 @@ public struct RpcCommandRequest
/// }
/// }
///
- /// Always use the method to construct
- /// a valid instance.
+ /// Always use the method to construct
+ /// a valid instance.
///
public struct SendRpcData
{
diff --git a/Runtime/Rpc/RpcQueue.cs b/Runtime/Rpc/RpcQueue.cs
index 4cd2959..46aa026 100644
--- a/Runtime/Rpc/RpcQueue.cs
+++ b/Runtime/Rpc/RpcQueue.cs
@@ -18,18 +18,13 @@ namespace Unity.NetCode
/// , pair from the
/// by calling the method.
///
- ///
- /// The typename of the struct implementing the interface
- /// for the
- /// The typename of a struct implementing the interface
- ///
///
///
/// If you intend to cache the retrieved queue (e.g. inside an OnCreate function in your system),
/// you must ensure that your system is created after the by using the .
///
- /// the struct type that implements the IRpcCommandSerializer interface.
- /// the rpc type
+ /// The typename of the struct implementing the interface for the .
+ /// The typename of a struct implementing the interface.
public struct RpcQueue
where TActionRequest : struct, IComponentData
where TActionSerializer : struct, IRpcCommandSerializer
diff --git a/Runtime/Rpc/RpcSystem.cs b/Runtime/Rpc/RpcSystem.cs
index d941f19..c0a8932 100644
--- a/Runtime/Rpc/RpcSystem.cs
+++ b/Runtime/Rpc/RpcSystem.cs
@@ -82,8 +82,9 @@ public RpcDeserializerState DeserializerState
}
///
- /// The reference to static burst-compatible method that is invoked when an rpc has been received.
+ /// The reference to static burst-compatible method that is invoked when an rpc has been received.
/// For example:
+ ///
///
/// [BurstCompile(DisableDirectCall = true)]
/// [AOT.MonoPInvokeCallback(typeof(RpcExecutor.ExecuteDelegate))]
@@ -91,18 +92,20 @@ public RpcDeserializerState DeserializerState
///
///
///
- /// The DisableDirectCall = true
was necessary to workaround an issue with burst and function delegate.
+ /// The DisableDirectCall = true was necessary to workaround an issue with burst and function delegate.
/// If you are implementing your custom rpc serializer, please remember to disable the direct call.
///
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ExecuteDelegate(ref Parameters parameters);
///
- /// Helper method that can be used to implement the execute method for the
+ /// Helper method that can be used to implement the execute method for the
/// interface.
/// By calling the ExecuteCreateRequestComponent, a new entity (with a and
/// a component) is created.
/// It is the users responsibility to write a system that consumes the created rpcs entities. For example:
+ ///
///
/// public struct MyRpcConsumeSystem : ISystem
/// {
@@ -554,17 +557,18 @@ public void OnUpdate(ref SystemState state)
}
///
- /// A system responsible for handling all the created by the
+ /// A system responsible for handling all the created by the
/// while receiving rpcs.
+ ///
///
/// The connection that generated the will be disconnected, by adding
/// a component, and a verbose error message containing the following
/// is reported to the application:
+ ///
/// - The local protocol.
/// - The remote protocol.
/// - The list of all registered rpc.
/// - The list of all registered serializer.
- ///
///
[UpdateInGroup(typeof(GhostSimulationSystemGroup))]
[BurstCompile]
diff --git a/Runtime/SerializationHelpers/CustomSerializerHelpers.cs b/Runtime/SerializationHelpers/CustomSerializerHelpers.cs
index c6506a2..210036c 100644
--- a/Runtime/SerializationHelpers/CustomSerializerHelpers.cs
+++ b/Runtime/SerializationHelpers/CustomSerializerHelpers.cs
@@ -21,14 +21,14 @@ public static unsafe class CustomGhostSerializerHelpers
/// index to
/// .
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
+ /// the chunk
+ /// the serialization context
+ /// the component typehandles
+ /// the buffer
+ /// the snapshot buffer data store
+ /// the offset in bytes where the component data should be stored
+ /// the current serializer to use
+ /// the unmanaged component type
public static void CopyComponentToSnapshot(
this T serializer,
ArchetypeChunk chunk,
@@ -52,15 +52,15 @@ public static void CopyComponentToSnapshot(
///
/// Copy a single component data for a child component to the snapshot buffer.
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
+ /// the serializer to use
+ /// the chunk to copy
+ /// the index in the chunk
+ /// the serialization context
+ /// the component type handles
+ /// the collection
+ /// the snapshot buffer
+ /// the start offset from the beginning of the snapshot buffer
+ /// the component type
public static void CopyChildComponentToSnapshot(
this T serializer,
ArchetypeChunk chunk,
@@ -81,15 +81,15 @@ public static void CopyChildComponentToSnapshot(
/// starting from index to
/// .
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
+ /// the serializer to use
+ /// the chunk to copy
+ /// the serialization context
+ /// the component type handles
+ /// the collection
+ /// the snapshot buffer
+ /// the start offset from the beginning of the snapshot buffer
+ /// the offset in the dynamic snapshot data buffer where the buffer data is stored
+ /// the buffer type
public static void CopyBufferToSnapshot(
this T serializer,
ArchetypeChunk chunk, ref GhostPrefabCustomSerializer.Context context,
@@ -114,16 +114,16 @@ public static void CopyBufferToSnapshot(
///
/// Copy a single buffer on a child entity for a given to the snapshot buffer.
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
+ /// the serializer to use
+ /// the chunk to copy
+ /// the index in the chunk
+ /// the serialization context
+ /// the component type handles
+ /// the collection
+ /// the snapshot buffer
+ /// the start offset from the beginning of the snapshot buffer
+ /// the offset in the dynamic snapshot data buffer where the buffer data is stored
+ /// the buffer type
public static void CopyChildBufferToSnapshot(
this T serializer,
ArchetypeChunk chunk, int indexInChunk,
@@ -172,13 +172,13 @@ private static void CopyBufferDataToSnapshot(GhostPrefabCustomSerializer.Cont
/// Copy all the enable bits state for the given to
/// the snapshot buffer.
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
+ /// the chunk
+ /// the start entity index
+ /// the end entity index (not inclusive)
+ /// the stride in bytes (the size) of the snapshot data for the given archretype
+ /// the component type handle to extrac
+ /// the snapshot enable bit mask array
+ /// the offset in bits in the array
public static void CopyEnableBits(ArchetypeChunk chunk, int startIndex, int endIndex,
int snapshotStride, ref DynamicComponentTypeHandle componentTypeHandle, byte* enableMasks,
ref int maskOffset)
@@ -210,17 +210,17 @@ static public class GhostCustomSerializerExtensions
///
/// Serialize the given component into the data stream by using a single baseline.
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
+ /// the serializer instance
+ /// the snapshot buffer
+ /// the baseline to diff against. Can be a zere baseline
+ /// the change mask bits buffer
+ /// the bitmask start offset
+ /// the data start offset
+ /// the data writer
+ /// the compression model
+ /// instruct if the component should be sent or not
+ /// the seralizer type
+ /// the number of bits written in the stream
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static public int SerializeComponentSingleBaseline(
this TSerializer serializer,
@@ -263,20 +263,20 @@ static public int SerializeComponentSingleBaseline(
/// The will calculate new predicted baseline that
/// will be used for delta compression.
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
+ /// the serializer instance
+ /// the snapshot buffer
+ /// the first baseline to diff against.
+ /// the second baseline to diff against.
+ /// the third baseline to diff against.
+ /// the change mask bits buffer
+ /// the bitmask start offset
+ /// the data start offset
+ /// the delta predictor instance
+ /// the data writer
+ /// the compression model
+ /// denote if the component should be replicated or not.
+ /// the seralizer type
+ /// the number of bits written in the stream
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static public int SerializeComponentThreeBaseline(
this TSerializer serializer,
@@ -319,20 +319,20 @@ static public int SerializeComponentThreeBaseline(
/// Serialize a single buffer to the datastream using the default buffer serialisation
/// strategy.
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
+ /// the serializer instance
+ /// the snapshot buffer
+ /// the baseline to diff against. Can be a zere baseline
+ /// the dynamic snapshot data buffer
+ /// the dynamic snapshot data buffer baseline
+ /// the change mask bits buffer
+ /// the bitmask start offset
+ /// the data start offset
+ /// the writtern data size in bytes in the dynamic snapshot buffer
+ /// the data writer
+ /// the compression model
+ /// denote if the buffer should be sent or not
+ /// the seralizer type
+ /// the number of bits written in the stream
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static public int SerializeBuffer(
this TSerializer serializer,
diff --git a/Runtime/SerializationHelpers/IGhostSerializer.cs b/Runtime/SerializationHelpers/IGhostSerializer.cs
index 25b4e03..a1f6ba9 100644
--- a/Runtime/SerializationHelpers/IGhostSerializer.cs
+++ b/Runtime/SerializationHelpers/IGhostSerializer.cs
@@ -61,7 +61,7 @@ public void CopyFromSnapshot(in GhostDeserializerState serializerState, [NoAlias
void CalculateChangeMask([NoAlias][ReadOnly]IntPtr snapshot, [NoAlias][ReadOnly]IntPtr baseline, [NoAlias]IntPtr changeMaskData, int startOffset);
///
- /// Serialise the snapshot data to the and calculate the current changemask.
+ /// Serialise the snapshot data to the and calculate the current changemask.
///
///
///
@@ -74,7 +74,7 @@ void SerializeCombined([ReadOnly][NoAlias] IntPtr snapshot, [ReadOnly][NoAlias]
ref DataStreamWriter writer, in StreamCompressionModel compressionModel);
///
- /// Serialise the snapshot dato to the and calculate the current changemask.
+ /// Serialise the snapshot dato to the and calculate the current changemask.
///
///
///
@@ -94,7 +94,7 @@ void SerializeWithPredictedBaseline([ReadOnly] [NoAlias] IntPtr snapshot,
ref DataStreamWriter writer, in StreamCompressionModel compressionModel);
///
- /// Serialise the snapshot dato to the based on the calculated changemask.
+ /// Serialise the snapshot dato to the based on the calculated changemask.
/// Expecte the changemask bits be all already set.
///
///
@@ -117,7 +117,7 @@ void Serialize([ReadOnly][NoAlias] IntPtr snapshot, [ReadOnly][NoAlias] IntPtr b
void PredictDelta([NoAlias] IntPtr snapshotData, [NoAlias] IntPtr baseline1Data, [NoAlias] IntPtr baseline2Data, ref GhostDeltaPredictor predictor);
///
- /// Read the data from the stream into the snapshot data.
+ /// Read the data from the stream into the snapshot data.
///
///
///
@@ -201,7 +201,7 @@ void CopyToSnapshotGenerated(in GhostSerializerState serializerState, ref TSnaps
in TComponent component);
///
- /// Serialise the snapshot dato to the based on the calculated changemask.
+ /// Serialise the snapshot dato to the based on the calculated changemask.
///
///
///
@@ -214,7 +214,7 @@ void SerializeGenerated(in TSnapshot snapshot, in TSnapshot baseline,
in StreamCompressionModel compressionModel);
///
- /// Serialise the snapshot dato to the based on the calculated changemask.
+ /// Serialise the snapshot dato to the based on the calculated changemask.
///
///
///
@@ -227,7 +227,7 @@ void SerializeCombinedGenerated(in TSnapshot snapshot, in TSnapshot baseline,
ref DataStreamWriter writer, in StreamCompressionModel compressionModel);
///
- /// Read the data from the stream into the snapshot data.
+ /// Read the data from the stream into the snapshot data.
///
///
///
diff --git a/Runtime/Snapshot/GhostCollectionComponent.cs b/Runtime/Snapshot/GhostCollectionComponent.cs
index da97266..b59d45e 100644
--- a/Runtime/Snapshot/GhostCollectionComponent.cs
+++ b/Runtime/Snapshot/GhostCollectionComponent.cs
@@ -113,8 +113,10 @@ internal struct GhostPrefabTracking : ICleanupComponentData
public struct GhostCollection : IComponentData
{
///
+ ///
/// The number of prefabs that have been loaded into the collection.
/// Use to determine which ghosts types the server can stream to the clients.
+ ///
///
/// The server reports (to the client) the list of loaded prefabs (with their see guid)
/// as part of the snapshot protocol.
@@ -124,12 +126,12 @@ public struct GhostCollection : IComponentData
/// Clients report (to the server) the number of loaded prefabs, as part of the command protocol.
/// When the client receives a ghost snapshot, the ghost prefab list is processed, and the collection
/// is updated with any new ghost types not already present in the collection.
+ ///
///
/// The client does not need to have loaded ALL prefab types in the to initialize the world. I.e. They can
/// be loaded/added dynamically into the world (i.e when streaming a sub-scene), and the state
/// should be used in that case (to inform the that the specified prefabs are currently being loaded into the world).
///
- ///
///
public int NumLoadedPrefabs;
#if UNITY_EDITOR || NETCODE_DEBUG
@@ -141,11 +143,11 @@ public struct GhostCollection : IComponentData
///
/// The index in the list where the prefab with the given .
/// It is populated by the when new prefabs hash are received from the server and it used to track what prefabs need to be mapped/loaded.
+ ///
///
/// Should be used only by the client. For server the map is always empty. It also contains a special key for the default(GhostType) that indicate if the list has been changed since the
/// last time has been processed.
///
- ///
public NativeHashMap PendingGhostPrefabAssignment;
///
/// The index in the list for given .
@@ -246,9 +248,10 @@ public struct GhostCollectionPrefabSerializer : IBufferElementData
///
public int ChangeMaskBits;
///
- /// Only set if the is present on the entity prefab,
+ /// Only set if the is present on the entity prefab,
/// is the offset in bytes, from the beginning of the snapshot data, in which the network id of the of client
/// owning the entity can be retrieved.
+ ///
///
/// var ghostOwner = *(uint*)(snapshotDataPtr + PredictionOwnerOffset)
///
@@ -282,7 +285,6 @@ public struct GhostCollectionPrefabSerializer : IBufferElementData
///
/// Client CPU optimization. Force predicted ghost to always try to continue from the last prediction in case of structural changes. True by default (because may introduce some issue when replicated component are removed).
///
- ///
public byte RollbackPredictionOnStructuralChanges;
///
/// Reflect the importance value set in the . Is used as the base value for the
@@ -527,11 +529,20 @@ public struct Context
///
/// Delegate to specify a custom order for the serialised components.
///
+ ///
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CollectComponentDelegate(IntPtr componentTypes, IntPtr componentCount);
///
/// Delegate for the custom chunk serializer.
///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ChunkSerializerDelegate(
ref ArchetypeChunk chunk,
@@ -544,6 +555,10 @@ public delegate void ChunkSerializerDelegate(
///
/// Delegate for the custom chunk pre-serialization function.
///
+ ///
+ ///
+ ///
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ChunkPreserializeDelegate(
in ArchetypeChunk chunk,
diff --git a/Runtime/Snapshot/GhostCollectionSystem.cs b/Runtime/Snapshot/GhostCollectionSystem.cs
index 3fb5c89..d037690 100644
--- a/Runtime/Snapshot/GhostCollectionSystem.cs
+++ b/Runtime/Snapshot/GhostCollectionSystem.cs
@@ -27,14 +27,15 @@ struct CodeGhostPrefab : IBufferElementData
}
///
+ ///
/// System responsible to construct and manage the singleton data.
+ ///
///
- /// The system processes all the ghost prefabs present in the world by:
+ /// The system processes all the ghost prefabs present in the world by:
/// - stripping and removing components from the entity prefab based on
/// - populating the
/// - preparing and constructing all the necessary data structure (, and
/// ) for serializing ghosts
- ///
///
[BurstCompile]
[UpdateInGroup(typeof(GhostSimulationSystemGroup))]
diff --git a/Runtime/Snapshot/GhostComponent.cs b/Runtime/Snapshot/GhostComponent.cs
index e022632..b80f56a 100644
--- a/Runtime/Snapshot/GhostComponent.cs
+++ b/Runtime/Snapshot/GhostComponent.cs
@@ -274,11 +274,10 @@ public struct PredictedGhost : IComponentData
/// The server tick from which the entity should start predicting.
/// When a new ghost snapshot is received, the entity is synced to the server state,
/// and the PredictionStartTick is set to the snapshot server tick.
- /// Otherwise, the PredictionStartTick should correspond to:
+ /// Otherwise, the PredictionStartTick should correspond to:
/// - The last simulated full tick by the client (see )
/// if a prediction backup (see ) exists
/// - The last received snapshot tick if a continuation backup is not found.
- ///
///
public NetworkTick PredictionStartTick;
@@ -294,20 +293,23 @@ public bool ShouldPredict(NetworkTick tick)
}
///
+ ///
/// Optional component, used to request predictive spawn of a ghosts by the client.
- /// The component is automatically added to the authored ghost prefabs when:
- ///
+ /// The component is automatically added to the authored ghost prefabs when:
+ ///
/// - The baking target is or .
/// - When using the hybrid authoring workflow, if the
/// is or .
/// - When using the , if the
/// is set to or .
- ///
+ ///
+ ///
/// The predicted spawn request is consumed by , which will remove the component from the
/// instantiated entity after an initial setup.
/// The package provides a default handling for predictive spawning ().
/// In case you need a custom or more accurate way to match the predicted spawned entities with the authoritive server spawned ones,
/// you can implement a custom spawn classification system. See for further details.
+ ///
///
public struct PredictedGhostSpawnRequest : IComponentData
{
diff --git a/Runtime/Snapshot/GhostComponentSerializer.cs b/Runtime/Snapshot/GhostComponentSerializer.cs
index 7abdffe..04d86f4 100644
--- a/Runtime/Snapshot/GhostComponentSerializer.cs
+++ b/Runtime/Snapshot/GhostComponentSerializer.cs
@@ -31,17 +31,17 @@ public unsafe struct GhostComponentSerializer
/// the buffer data inside the buffer. This shadow component entry has the
/// following format:
///
- /// uint Length: the length of the buffer
- /// uint Offset: the position in bytes from the beginning of the dynamic data buffer (for that specific history slot)
+ /// - uint Length: the length of the buffer
+ /// - uint Offset: the position in bytes from the beginning of the dynamic data buffer (for that specific history slot)
///
///
public const int DynamicBufferComponentSnapshotSize = sizeof(uint) + sizeof(uint);
///
/// The number of change mask bits used the shadow buffer data. The change mask for the buffer is like this:
///
- /// 00 : nothing change
- /// 01 : len is the same, content has changed.
- /// 10 : len is changed, we consider the content has changed too. (may change in the future).
+ /// - 00 : nothing change
+ /// - 01 : len is the same, content has changed.
+ /// - 10 : len is changed, we consider the content has changed too. (may change in the future).
///
///
public const int DynamicBufferComponentMaskBits = 2;
@@ -73,23 +73,67 @@ public enum SendMask
///
/// Delegate method to use to post-serialize the component when the ghost use pre-serialization optimization.
///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void PostSerializeDelegate(IntPtr snapshotData, int snapshotOffset, int snapshotStride, int maskOffsetInBits, int count, IntPtr baselines, ref DataStreamWriter writer, ref StreamCompressionModel compressionModel, IntPtr entityStartBit);
///
/// Delegate method to use to post-serialize buffers when the ghost use pre-serialization optimization.
///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void PostSerializeBufferDelegate(IntPtr snapshotData, int snapshotOffset, int snapshotStride, int maskOffsetInBits, int changeMaskBits, int count, IntPtr baselines, ref DataStreamWriter writer, ref StreamCompressionModel compressionModel, IntPtr entityStartBit, IntPtr snapshotDynamicDataPtr, IntPtr dynamicSizePerEntity, int dynamicSnapshotMaxOffset);
///
/// Delegate method used to serialize the component data for the root entity into the outgoing data stream.
/// Works in batches.
///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void SerializeDelegate(IntPtr stateData, IntPtr snapshotData, int snapshotOffset, int snapshotStride, int maskOffsetInBits, IntPtr componentData, int count, IntPtr baselines, ref DataStreamWriter writer, ref StreamCompressionModel compressionModel, IntPtr entityStartBit);
///
/// Delegate method used to serialize the component data present in the child entity into the outgoing data stream.
/// Works on a single entity at time.
///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
[Obsolete("The SerializeChildDelegate delegate has been deprecated and will be removed. Please use only use the SerializeDelegate instead", false)]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void SerializeChildDelegate(IntPtr stateData, IntPtr snapshotData, int snapshotOffset, int snapshotStride, int maskOffsetInBits, IntPtr componentData, int count, IntPtr baselines, ref DataStreamWriter writer, ref StreamCompressionModel compressionModel, IntPtr entityStartBit);
@@ -97,11 +141,35 @@ public enum SendMask
/// Delegate method used to serialize the buffer content for the whole chunk.
/// Works in batches.
///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void SerializeBufferDelegate(IntPtr stateData, IntPtr snapshotData, int snapshotOffset, int snapshotStride, int maskOffsetInBits, int changeMaskBits, IntPtr componentData, IntPtr componentDataLen, int count, IntPtr baselines, ref DataStreamWriter writer, ref StreamCompressionModel compressionModel, IntPtr entityStartBit, IntPtr snapshotDynamicDataPtr, ref int snapshotDynamicDataOffset, IntPtr dynamicSizePerEntity, int dynamicSnapshotMaxOffset);
///
/// Delegate method used to transfer the component data to/from the snapshot buffer.
///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CopyToFromSnapshotDelegate(IntPtr stateData, IntPtr snapshotData, int snapshotOffset, int snapshotStride, IntPtr componentData, int componentStride, int count);
///
@@ -109,22 +177,38 @@ public enum SendMask
/// buffer. Because the history buffer perform a memory copy of the whole component data, it is necessary to call this method to
/// ensure only the replicated portion of the component is actually restored.
///
+ ///
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void RestoreFromBackupDelegate(IntPtr componentData, IntPtr backupData);
///
/// Calculate the prediction delta for components and buffer. Used for delta-compression.
///
+ ///
+ ///
+ ///
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void PredictDeltaDelegate(IntPtr snapshotData, IntPtr baseline1Data, IntPtr baseline2Data, ref GhostDeltaPredictor predictor);
///
/// Deserialize the component and buffer data from the received snapshot and store it inside the .
///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DeserializeDelegate(IntPtr snapshotData, IntPtr baselineData, ref DataStreamReader reader, ref StreamCompressionModel compressionModel, IntPtr changeMaskData, int startOffset);
///
/// Delegate used by the , collect and report the prediction error
/// for all the replicated fields.
///
+ ///
+ ///
+ ///
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ReportPredictionErrorsDelegate(IntPtr componentData, IntPtr backupData, IntPtr errorsList, int errorsCount);
diff --git a/Runtime/Snapshot/GhostComponentSerializerCollectionSystemGroup.cs b/Runtime/Snapshot/GhostComponentSerializerCollectionSystemGroup.cs
index b7dd8c5..9cb1535 100644
--- a/Runtime/Snapshot/GhostComponentSerializerCollectionSystemGroup.cs
+++ b/Runtime/Snapshot/GhostComponentSerializerCollectionSystemGroup.cs
@@ -79,8 +79,9 @@ public enum DefaultType : byte
///
/// Types like `Translation` don't have a default serializer as the type itself doesn't define any GhostFields, but they do have serialized variants.
public byte IsDefaultSerializer;
- ///
+ ///
/// True if this is an editor test variant. Forces this variant to be considered a "default" which makes writing tests easier.
+ ///
public byte IsTestVariant;
/// True if the flag is true on this variant (if it has one), or this type (if not).
public byte SendForChildEntities;
diff --git a/Runtime/Snapshot/GhostDespawnSystem.cs b/Runtime/Snapshot/GhostDespawnSystem.cs
index 0cf1e18..c83eabc 100644
--- a/Runtime/Snapshot/GhostDespawnSystem.cs
+++ b/Runtime/Snapshot/GhostDespawnSystem.cs
@@ -6,8 +6,10 @@
namespace Unity.NetCode
{
///
+ ///
/// Present only in client worlds. Responsible for destroying spawned ghosts when a despawn
/// request/command is received from the server.
+ ///
/// Clients are not responsible for destroying ghost entities (and thus should never). The server is
/// responsible for notifying the client about which ghosts should be destroyed (as part of the snapshot protocol).
///
diff --git a/Runtime/Snapshot/GhostImportance.cs b/Runtime/Snapshot/GhostImportance.cs
index 2b6a9b8..8cc76de 100644
--- a/Runtime/Snapshot/GhostImportance.cs
+++ b/Runtime/Snapshot/GhostImportance.cs
@@ -61,6 +61,7 @@ public struct GhostImportance : IComponentData
/// Optional configuration data. Ex. Each tile's configuration. Handle IntPtr.Zero!
/// Per chunk information. Ex. each entity's tile index.
/// Priority computed by after computing tick when last updated and irrelevance.
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int ScaleImportanceDelegate(IntPtr connectionData, IntPtr importanceData, IntPtr chunkTile, int basePriority);
@@ -79,18 +80,23 @@ public struct GhostImportance : IComponentData
/// Per connection data. Ex. position in the world that should be prioritized.
/// Optional configuration data. Ex. Each tile's configuration. Handle IntPtr.Zero!
/// to retrieve the per-chunk tile information. Ex. each chunk's tile index.
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void BatchScaleImportanceDelegate(IntPtr connectionData, IntPtr importanceData, IntPtr sharedComponentTypeHandlePtr,
ref UnsafeList chunkData);
///
+ ///
/// This function pointer will be invoked with collected data as described in .
+ ///
/// It is mandatory to set either this or function pointer.
/// It is also valid to set both, in which case the BatchScaleImportanceFunction is preferred.
///
///
public PortableFunctionPointer ScaleImportanceFunction;
///
+ ///
/// This function pointer will be invoked with collected data as described in .
+ ///
/// It is mandatory to set either this or function pointer.
/// It is also valid to set both, in which case the BatchScaleImportanceFunction is preferred.
///
diff --git a/Runtime/Snapshot/GhostOwner.cs b/Runtime/Snapshot/GhostOwner.cs
index 7da7c95..d8c40ee 100644
--- a/Runtime/Snapshot/GhostOwner.cs
+++ b/Runtime/Snapshot/GhostOwner.cs
@@ -12,12 +12,15 @@ public struct GhostOwnerComponent : IComponentData
{}
///
+ ///
/// The GhostOwnerComponent is an optional component that can be added to a ghost to create a bond/relationship in
/// between an entity and a specific client (for example, the client who spawned that entity, a bullet, the player entity).
/// It is usually added to predicted ghost (see ) but can also be present on the interpolated
/// ones.
+ ///
///
/// It is mandatory to add a in the following cases:
+ ///
/// - When a ghost is configured to be owner-predicted , because it is necessary to distinguish in between who
/// is predicting (the owner) and who is interpolating the ghost.
///
@@ -25,7 +28,6 @@ public struct GhostOwnerComponent : IComponentData
/// based on ownership the .
///
/// - If you want to use the feature.
- ///
///
[DontSupportPrefabOverrides]
[GhostComponent(SendDataForChildEntity = true)]
diff --git a/Runtime/Snapshot/GhostPredictionSmoothingSystem.cs b/Runtime/Snapshot/GhostPredictionSmoothingSystem.cs
index f353d1f..2b5aa10 100644
--- a/Runtime/Snapshot/GhostPredictionSmoothingSystem.cs
+++ b/Runtime/Snapshot/GhostPredictionSmoothingSystem.cs
@@ -13,9 +13,9 @@ namespace Unity.NetCode
{
///
- /// Singleton used to register a for a certain component type.
+ /// Singleton used to register a for a certain component type.
/// The is used to change the component value over time correct misprediction. Two different types of
- /// smoothing action can be registered:
+ /// smoothing action can be registered:
/// - A smoothing action without argument. See
/// - A smoothing action that take a component data as argument. See
///
@@ -31,6 +31,9 @@ internal GhostPredictionSmoothing(NativeParallelHashMap
/// All the smoothing action must have this signature. The smoothing actions must also be burst compatible.
///
+ ///
+ ///
+ ///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void SmoothingActionDelegate(IntPtr currentData, IntPtr previousData, IntPtr userData);
diff --git a/Runtime/Snapshot/GhostPredictionSwitchingQueues.cs b/Runtime/Snapshot/GhostPredictionSwitchingQueues.cs
index ca13975..c3a6989 100644
--- a/Runtime/Snapshot/GhostPredictionSwitchingQueues.cs
+++ b/Runtime/Snapshot/GhostPredictionSwitchingQueues.cs
@@ -70,9 +70,9 @@ internal struct OwnerSwithchingEntry
///
/// Singleton component, used to track when an ghost with mode set to has changed
/// owner and require changing how it is simulated on the client. In particular:
- ///
- /// If the owner is the same as client the ghost will become predicted
- /// If the owner is not the same as client the ghost will become interpolated
+ ///
+ /// - If the owner is the same as client the ghost will become predicted
+ /// - If the owner is not the same as client the ghost will become interpolated
///
///
internal struct GhostOwnerPredictedSwitchingQueue : IComponentData
diff --git a/Runtime/Snapshot/GhostPrefabCreation.cs b/Runtime/Snapshot/GhostPrefabCreation.cs
index eae8a08..be1b10d 100644
--- a/Runtime/Snapshot/GhostPrefabCreation.cs
+++ b/Runtime/Snapshot/GhostPrefabCreation.cs
@@ -31,10 +31,12 @@ public enum NetcodeConversionTarget
namespace Unity.NetCode
{
///
- /// Stores the `Supported Ghost Mode` by a ghost at authoring time.
- /// - Interpolated:
- /// - Predicted:
- /// - All:
+ /// Stores the `Supported Ghost Mode` by a ghost at authoring time.
+ ///
+ /// - Interpolated:
+ /// - Predicted:
+ /// - All:
+ ///
///
public enum GhostModeMask
{
@@ -67,13 +69,15 @@ public enum GhostModeMask
///
/// The Current Ghost Mode of a Ghost, on any given client. Denotes replication and prediction rules.
- ///
///
+ ///
public enum GhostMode
{
- ///
+ ///
+ ///
Interpolated,
- ///
+ ///
+ ///
Predicted,
///
/// The ghost will be by the Ghost Owner (set via )
@@ -84,9 +88,9 @@ public enum GhostMode
///
/// Specify if the ghost replication should be optimized for frequent (dynamic) or for infrequent (static) data changes.
- ///
- ///
///
+ ///
+ ///
public enum GhostOptimizationMode
{
///
@@ -149,19 +153,16 @@ public struct Config
///
/// Enable predicted spawned ghost to rollback their initial spawn state and re-predict until the authoritative spawn has been received from the server.
///
- ///
public bool PredictedSpawnedGhostRollbackToSpawnTick;
///
/// Client CPU optimization. Force predicted ghost to always try to continue from the last prediction in case of structural changes. True by default (because may introduce some issue when replicated component are removed).
///
- ///
public bool RollbackPredictionOnStructuralChanges;
///
/// Optional, custom deterministic function that retrieve all no-backing and serializable component types for this ghost. By serializable,
/// we means components that either have ghost fields (fields with a attribute)
/// or a .
///
- ///
public PortableFunctionPointer CollectComponentFunc;
}
///
diff --git a/Runtime/Snapshot/GhostReceiveSystem.cs b/Runtime/Snapshot/GhostReceiveSystem.cs
index 62243d1..967e48e 100644
--- a/Runtime/Snapshot/GhostReceiveSystem.cs
+++ b/Runtime/Snapshot/GhostReceiveSystem.cs
@@ -104,11 +104,15 @@ public struct GhostDeserializerState
}
///
+ ///
/// System present only in clients worlds, receive and decode the ghost snapshosts sent by the server.
+ ///
///
/// When a new snapshost is received, the system will start decoding the packet protocol by extracting:
+ ///
/// -the list of ghost that need to despawned
/// -for each serialized ghost, it delta-compressed or uncompressed state
+ ///
/// The system will schedule spawning and despawning ghosts requests, by using
/// the , and respectively.
///
diff --git a/Runtime/Snapshot/GhostSendSystem.cs b/Runtime/Snapshot/GhostSendSystem.cs
index 82b411b..66a87f4 100644
--- a/Runtime/Snapshot/GhostSendSystem.cs
+++ b/Runtime/Snapshot/GhostSendSystem.cs
@@ -323,8 +323,10 @@ internal void Initialize()
}
///
+ ///
/// System present only for servers worlds, and responsible to replicate ghost entities to the clients.
/// The is one of the most complex system of the whole package and heavily rely on multi-thread jobs to dispatch ghosts to all connection as much as possible in parallel.
+ ///
///
/// Ghosts entities are replicated by sending a 'snapshot' of their state to the clients, at frequency.
/// Snaphosts are streamed to the client when their connection is tagged with a component (we usually refere a connection with that tag as "in-game"),
@@ -332,18 +334,22 @@ internal void Initialize()
/// By default, up to 3 baseline are used to delta-compress the data, by using a predictive compression scheme (see ). It is possible
/// to reduce the number of baseline used (and CPU cycles) using the settings.
///
+ ///
/// The GhostSendSystem is designed to send to each connection one single packet per network update. By default, the system will try to
/// replicate to the clients all the existing ghost present in the world. When all ghosts cannot be serialized into the same packet,
/// the enties are prioritized by their importance.
+ ///
///
/// The base ghost importance can be set at authoring time on the prefab ();
/// At runtime the ghost importance is scaled based on:
+ ///
/// - age (the last time the entities has been sent)
/// - scaled by distance, (see ,
/// - scaled by custom scaling (see
- ///
+ ///
/// Ghost entities are replicated on "per-chunk" basis; all ghosts for the same chunk, are replicated
/// together. The importance, as well as the importance scaling, apply to whole chunk.
+ ///
///
/// The send system can also be configured to send multiple ghost packets per frame and to to use snaphost larger than the MaxMessageSize.
/// In that case, the snapshot packet is sent using another unreliable channel, setup with a .
diff --git a/Runtime/Snapshot/GhostSpawnClassificationSystem.cs b/Runtime/Snapshot/GhostSpawnClassificationSystem.cs
index 7ca092a..c4a1a39 100644
--- a/Runtime/Snapshot/GhostSpawnClassificationSystem.cs
+++ b/Runtime/Snapshot/GhostSpawnClassificationSystem.cs
@@ -127,8 +127,10 @@ public bool HasClassifiedPredictedSpawn
}
///
+ ///
/// Contains all the system that classify spawned ghost. Runs after the system.
/// Your custom classification system should be updated into this group.
+ ///
///
/// [UpdateInGroup(typeof(GhostSpawnClassificationSystemGroup))]
/// public partial struct MyCustomClassificationSystemGroup
diff --git a/Runtime/Snapshot/GhostSpawnSystem.cs b/Runtime/Snapshot/GhostSpawnSystem.cs
index 6f8e0ac..993386d 100644
--- a/Runtime/Snapshot/GhostSpawnSystem.cs
+++ b/Runtime/Snapshot/GhostSpawnSystem.cs
@@ -7,7 +7,9 @@
namespace Unity.NetCode
{
///
+ ///
/// System responsible for spawning all the ghost entities for the client world.
+ ///
///
/// When a ghost snapshot is received from the server, the add a spawning request to the .
/// After the spawning requests has been classified (see ),
@@ -15,6 +17,7 @@ namespace Unity.NetCode
///
///
/// Based on the spawning (), the requests are handled quite differently.
+ ///
/// When the mode is set to , the ghost creation is delayed
/// until the match (or is greater) the actual spawning tick on the server.
/// A temporary entity, holding the spawning information, the received snapshot data from the server, and tagged with the
@@ -24,15 +27,12 @@ namespace Unity.NetCode
///
/// When the mode is set to , a new ghost instance in spawned immediately if the
/// current simulated is greater or equals the spawning tick reported by the server.
- ///
/// This condition is usually the norm, since the client timeline (the current simulated tick) should be ahead of the server.
- ///
+ ///
///
/// Otherwise, the ghost creation is delayed until the the is greater or equals the required spawning tick.
/// Like to interpolated ghost, a temporary placeholder entity is created to hold spawning information and for holding new received snapshots.
///
- ///
- ///
///
[BurstCompile]
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ThinClientSimulation)]
diff --git a/Runtime/Snapshot/GhostUpdateSystem.cs b/Runtime/Snapshot/GhostUpdateSystem.cs
index 9805706..e61b7c5 100644
--- a/Runtime/Snapshot/GhostUpdateSystem.cs
+++ b/Runtime/Snapshot/GhostUpdateSystem.cs
@@ -20,7 +20,7 @@ struct GhostPredictionGroupTickState : IComponentData
}
///
- /// System present only in client worlds, and responsible for:
+ /// System present only in client worlds, and responsible for:
/// - updating the state of interpolated ghosts, by copying and intepolating data from the received snapshosts.
/// - restore the predicted ghost state from the before running the next prediction loop (until new snapshot aren't received).
/// - updating the properties for all predicted ghost, by reflecting the latest received snapshot (see )
diff --git a/Runtime/Snapshot/Prespawn/ClientPopulatePrespawnedGhostsSystem.cs b/Runtime/Snapshot/Prespawn/ClientPopulatePrespawnedGhostsSystem.cs
index 28346f8..3d0482f 100644
--- a/Runtime/Snapshot/Prespawn/ClientPopulatePrespawnedGhostsSystem.cs
+++ b/Runtime/Snapshot/Prespawn/ClientPopulatePrespawnedGhostsSystem.cs
@@ -17,18 +17,17 @@ namespace Unity.NetCode
///
///
///
- /// Clients expect to receive the following as part ot the protocol:
+ /// Clients expect to receive the following as part ot the protocol:
/// - The subscene hash and baseline hash for validation.
/// - The ghost id range for each subscene.
- ///
/// ### The Full Prespawn Subscene Sync Protocol
///
/// The Client will eventually receive the subscene data and will store it into the `PrespawnSceneLoaded` collection.
/// The Client (in parallel, before or after) will serialize the prespawn baseline when a new scene is loaded.
- /// The Client should validate that:
+ /// The Client should validate that:
/// - The prespawn scenes are present on the server.
/// - That the prespawn ghost count, subscene hash and baseline hash match the one on the server.
- /// The Client will assign the ghost ids to the prespawns.
+ /// The Client will assign the ghost ids to the prespawns.
/// The Client must notify the server what scene sections has been loaded and initialized.
///
///
diff --git a/Runtime/Snapshot/SnapshotData.cs b/Runtime/Snapshot/SnapshotData.cs
index 52766c2..8f255a2 100644
--- a/Runtime/Snapshot/SnapshotData.cs
+++ b/Runtime/Snapshot/SnapshotData.cs
@@ -45,11 +45,9 @@ public struct DataAtTick
///
/// The required values of the property in order for a component to be sent.
/// The mask depends on the presence and value of the component:
- ///
- /// if the is not present on the entity
- /// if the value of the is equals to the of the client.
- /// if the value of the is different than the of the client.
- ///
+ /// if the is not present on the entity
+ /// if the value of the is equals to the of the client.
+ /// if the value of the is different than the of the client.
///
public SendToOwnerType RequiredOwnerSendMask;
///
diff --git a/Runtime/Snapshot/SnapshotDataBufferComponentLookup.cs b/Runtime/Snapshot/SnapshotDataBufferComponentLookup.cs
index dfcabca..97fc4d4 100644
--- a/Runtime/Snapshot/SnapshotDataBufferComponentLookup.cs
+++ b/Runtime/Snapshot/SnapshotDataBufferComponentLookup.cs
@@ -10,10 +10,10 @@ namespace Unity.NetCode.LowLevel
/// Helper struct that can be used to inspect the presence of components from a buffer
/// and retrieve their data.
/// The lookup can be passed ot jobs
+ ///
///
- /// The helper allow to only read component data. Buffers are not supported.
+ /// The helper only allows you to read component data. Buffers are not supported.
///
- ///
public struct SnapshotDataBufferComponentLookup
{
[ReadOnly]DynamicBuffer m_ghostPrefabType;
@@ -116,13 +116,10 @@ public bool HasBuffer(int ghostTypeIndex) where T: unmanaged, IBufferElementD
}
///
- /// Try to retrieve the data for a component type from the the snapshot history buffer.
+ /// Try to retrieve the data for a component type from the the snapshot history buffer.
///
///
- /// Buffers aren't supported.
- ///
- /// Only component present on the root entity can be retrieved. Trying to get data for component in a child entity is not supported.
- ///
+ /// Buffers aren't supported. Only components present on the root entity can be retrieved. Trying to get data for components in a child entity is not supported.
///
/// The index in the collection.
/// The entity snapshot history buffer.
@@ -149,13 +146,10 @@ public bool TryGetComponentDataFromSnapshotHistory(int ghostTypeIndex, in Dyn
}
///
- /// Try to retrieve the data for a component type from the spawning buffer.
+ /// Try to retrieve the data for a component type from the spawning buffer.
///
///
- /// Buffers aren't supported.
- ///
- /// Only component present on the root entity can be retrieved. Trying to get data for component in a child entity is not supported.
- ///
+ /// Buffers aren't supported. Only components present on the root entity can be retrieved. Trying to get data for components in a child entity is not supported.
///
///
///
@@ -328,4 +322,3 @@ public struct SerializerIndexAndOffset
internal NativeHashMap ComponentDataOffsets;
}
}
-
diff --git a/Runtime/Snapshot/SwitchPredictionSmoothingSystem.cs b/Runtime/Snapshot/SwitchPredictionSmoothingSystem.cs
index f010b04..3e43d85 100644
--- a/Runtime/Snapshot/SwitchPredictionSmoothingSystem.cs
+++ b/Runtime/Snapshot/SwitchPredictionSmoothingSystem.cs
@@ -38,8 +38,8 @@ public struct SwitchPredictionSmoothing : IComponentData
}
///
- /// System that manage the prediction transition for all ghost that present a
- /// components.
+ /// System that manage the prediction transition for all ghost that present a
+ /// components.
///
/// The system applying a visual smoohting to the ghost, by modifying the entity matrix.
/// When the transition is completed, the system removes the component.
diff --git a/Runtime/SourceGenerators/NetCodeSourceGenerator.dll b/Runtime/SourceGenerators/NetCodeSourceGenerator.dll
index 973c21b39defeae149cd9672326eaf8e410f14fb..ad70ec50dbd7b1824410c05475af7bb574226e7f 100644
GIT binary patch
delta 781
zcmXxiTWHfz7y#h^oW@Oxn;k_RtVl0HGgqWd+I7|GI#G1YxmE^Fye(}qR}l4~f(X)j
zffW^OEpmMDL1kWw!jOp(CNd|uB5e4u7ZFhg^9pV{l;VZ?r)N9iPrmb?|D5C`Nl#kR
zla_2o5T^@sxr;XPC|B4`;(0>cOZ+VYbg>6c!IR%Z+~i6AG)WPbC)8!CT~CdH`k@H@
z^*t4400aQ;uLTeXxXld!Blo!5(W1_M9&36=xj%aVN>kjs(8aIZBUoSh$8E>_s|r$H
z{}Se}FXx^`_tlo2g0ooE-M|NqiU3Ok+;0qT;?ASf+qup4c!Manj`{F@?hxk1L)|!4$FqH1`updk)hYU7vep<=d)0uVYW`qM@=A&lSDQkTtZ1?<1^t15
zCi_*r?E@Kh(MXc5{z%63aWnO_viYsFva0P!BAHMQCr)areIv_8Xq|4|L4TOo-z(J2
z{)A1{x-CM*bppVsWtdl$3D;#WtD=C=dSKFub+ytsf1
zEVf&Q?K#Iv!t|t5I79U6HNpW?rw?Kvg9eRwRiPIn01BQp@Iw%D5_mBbJmQ#bf)Ms(
g>}hzG(Lt;W;9>Orpt51N&_N%2^%_x_Avtg5e>Z`)=Kufz
delta 726
zcmXxhTWHfz7y#h^q-PbnF*9&=_+?!!eqj`(@64s;^n7@Po>PyUf(6h_TPq4oJmw6M$=bfan{#A^R
zuVr3AXFD3!;Q|&Vx>(|*0I;%+`JL^Z%m(^+irLkPAILFV7#9vPD;VdGF~2~6KFj>v
z{)rNEFK%FVl6lGA@Z;@lVq!z-1M@UC#D6n;uxP)NYwSQpA8BL$h4sZb{YUN+}#lZ>AUTlFgG^9h<*C`2St$*WpSl?xG7)}*{BX_~BrN7RTEEy$`O$HLaY
zM^f=~J*Ul$pU5-orHc#oS*^Rc7HaN-fvK*e-
zLwt&O&_y%jrS7Icftr=O;~W@nIT%fulU{nado@~FUX9{f>yx$i
zs=Il!c{sXm`V=nk|GHupeRKoStqC7JPmBcVuv!Cj*s)s!5ej%mKtd^y2Ng7k;V3tv
s_FKbT9Dle|6JzCr=My>PNT|
z{Y=6DCil>4-SHxL&$|zeWcVf78-ZB-0{{T6liyFmFc8Pz_g7qa(ik?_Kvawgl0baW
z7$Ev!e7LQ*tx4CK{*dgyw*w&%qTylfQ}248@7?tpMcr0c5Jhm0&Z=%fk~CUk4~?x^
ztCAbY6eC!pfxREne;N?1QX=#>cbBIn%7ToygKgq+E(j{DAwy>fxXhH+lvzlr#BZ)N
zpk%P-LU;=ZWi0S~2eTz@g*`~qUOC)k8=a=xa!&$hxGZ2<8%x#r=oBs}7rqRxk+hHr
QuNVfw4*?nhv%EhrPzx>61^@s6
delta 422
zcmV;X0a^a+p91Wk0+4(ZRSUL9(MQ8es|HD43|clwmGat}v5>Dlf3!`&2*A77oolJ_
z7%TbVb#sEly$_aMXW)Lc8P(+a1%X)n0{{T6lTmBJFc8Pz`za2eHim6&apD{UCn$T^
z7%JPt*u%BCw1G4kNjmAbU#e3S+3=ysQ|@xV|J~&hMg2}!5Jhm0wbT8A6d82H9$H(w
z)}^qJYeuj^3kN@Be+?iwt!3zM?k~?uR0UaY2iL}NAqgsMAjjGg2$gGND0h%iiQhsS
zK*eAqr1Tb$+By(?4|65$ggwa6K{?!J8=a@yaZiHU3RS?Wv5uB&3-0q7hPl{_(ZF52S2kwT&oDY+DOvpx<@*$=yp*UeI9S?FG
zCbvAraXK1Ytomv+t8>>~Q`f>t>JImBU)wQW9Dk>F-k(>GwU7+njd0XT&kYt8DF?aq
QieV7^009~Sv%EhrP}HBxegFUf
diff --git a/Runtime/Variants/GhostTransformVariants.cs b/Runtime/Variants/GhostTransformVariants.cs
index b2be6cf..8d5c232 100644
--- a/Runtime/Variants/GhostTransformVariants.cs
+++ b/Runtime/Variants/GhostTransformVariants.cs
@@ -139,13 +139,13 @@ public struct RotationScaleVariant
/// -
/// -
/// -
+ ///
///
- /// It will never override the default assignment for the transform components if they are already present in the
- /// map.
+ /// It will never override the default assignment for the transform components if they are already present in the
+ /// map.
/// Any system deriving from will take precedence, even if they are created
/// after this system.
///
- ///
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation | WorldSystemFilterFlags.ClientSimulation |
WorldSystemFilterFlags.ThinClientSimulation | WorldSystemFilterFlags.BakingSystem)]
[CreateAfter(typeof(GhostComponentSerializerCollectionSystemGroup))]
diff --git a/Tests/Editor/AnalyticsTests.cs b/Tests/Editor/AnalyticsTests.cs
index 3e511e5..67d680a 100644
--- a/Tests/Editor/AnalyticsTests.cs
+++ b/Tests/Editor/AnalyticsTests.cs
@@ -1,5 +1,6 @@
using NUnit.Framework;
using Unity.NetCode.Analytics;
+using Unity.NetCode.Editor;
namespace Unity.NetCode.Tests
{
@@ -76,5 +77,153 @@ public void MultipleValueCanBeRetrieved()
Assert.That(y.id, Is.EqualTo(res[1].id));
}
}
+
+ class FieldVerification
+ {
+ ///
+ /// This test will fail because you have changed the layout of the analytics data in the schema.
+ /// https://schemata.prd.cds.internal.unity3d.com/onboarding
+ ///
+ [Test]
+ public void VerifyGhostConfigurationAnalyticsData()
+ {
+ var ghostConfigurationAnalyticsDataFields = typeof(GhostConfigurationAnalyticsData).GetFields();
+ Assert.That(ghostConfigurationAnalyticsDataFields.Length, Is.EqualTo(7));
+ Assert.That(ghostConfigurationAnalyticsDataFields[0].Name, Is.EqualTo("id"));
+ Assert.That(ghostConfigurationAnalyticsDataFields[0].FieldType, Is.EqualTo(typeof(string)));
+ Assert.That(ghostConfigurationAnalyticsDataFields[1].Name, Is.EqualTo("ghostMode"));
+ Assert.That(ghostConfigurationAnalyticsDataFields[1].FieldType, Is.EqualTo(typeof(string)));
+ Assert.That(ghostConfigurationAnalyticsDataFields[2].Name, Is.EqualTo("optimizationMode"));
+ Assert.That(ghostConfigurationAnalyticsDataFields[2].FieldType, Is.EqualTo(typeof(string)));
+ Assert.That(ghostConfigurationAnalyticsDataFields[3].Name, Is.EqualTo("prespawnedCount"));
+ Assert.That(ghostConfigurationAnalyticsDataFields[3].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(ghostConfigurationAnalyticsDataFields[4].Name, Is.EqualTo("autoCommandTarget"));
+ Assert.That(ghostConfigurationAnalyticsDataFields[4].FieldType, Is.EqualTo(typeof(bool)));
+ Assert.That(ghostConfigurationAnalyticsDataFields[5].Name, Is.EqualTo("variance"));
+ Assert.That(ghostConfigurationAnalyticsDataFields[5].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(ghostConfigurationAnalyticsDataFields[6].Name, Is.EqualTo("importance"));
+ Assert.That(ghostConfigurationAnalyticsDataFields[6].FieldType, Is.EqualTo(typeof(int)));
+ }
+
+ ///
+ /// This test will fail because you have changed the layout of the analytics data in the schema.
+ /// https://schemata.prd.cds.internal.unity3d.com/onboarding
+ ///
+ [Test]
+ public void VerifyGhostScaleAnalyticsData()
+ {
+ var ghostConfigurationAnalyticsDataFields = typeof(GhostScaleAnalyticsData).GetFields();
+ Assert.That(ghostConfigurationAnalyticsDataFields.Length, Is.EqualTo(11));
+ Assert.That(ghostConfigurationAnalyticsDataFields[0].Name, Is.EqualTo("Settings"));
+ Assert.IsTrue(ghostConfigurationAnalyticsDataFields[0].FieldType.IsValueType);
+ Assert.That(ghostConfigurationAnalyticsDataFields[1].Name, Is.EqualTo("ServerSpawnedGhostCount"));
+ Assert.That(ghostConfigurationAnalyticsDataFields[1].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(ghostConfigurationAnalyticsDataFields[2].Name, Is.EqualTo("GhostTypeCount"));
+ Assert.That(ghostConfigurationAnalyticsDataFields[2].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(ghostConfigurationAnalyticsDataFields[3].Name, Is.EqualTo("AverageGhostInSnapshot"));
+ Assert.That(ghostConfigurationAnalyticsDataFields[3].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(ghostConfigurationAnalyticsDataFields[4].Name, Is.EqualTo("GhostTypes"));
+ Assert.IsTrue(ghostConfigurationAnalyticsDataFields[4].FieldType.IsArray);
+ Assert.That(ghostConfigurationAnalyticsDataFields[5].Name, Is.EqualTo("ClientServerTickRate"));
+ Assert.IsTrue(ghostConfigurationAnalyticsDataFields[5].FieldType.IsValueType);
+ Assert.That(ghostConfigurationAnalyticsDataFields[6].Name, Is.EqualTo("ClientTickRate"));
+ Assert.IsTrue(ghostConfigurationAnalyticsDataFields[6].FieldType.IsValueType);
+ Assert.That(ghostConfigurationAnalyticsDataFields[7].Name, Is.EqualTo("MainClientData"));
+ Assert.IsTrue(ghostConfigurationAnalyticsDataFields[7].FieldType.IsValueType);
+ Assert.That(ghostConfigurationAnalyticsDataFields[8].Name, Is.EqualTo("SnapshotTargetSize"));
+ Assert.That(ghostConfigurationAnalyticsDataFields[8].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(ghostConfigurationAnalyticsDataFields[9].Name, Is.EqualTo("NumMainClientWorlds"));
+ Assert.That(ghostConfigurationAnalyticsDataFields[9].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(ghostConfigurationAnalyticsDataFields[10].Name, Is.EqualTo("NumServerWorlds"));
+ Assert.That(ghostConfigurationAnalyticsDataFields[10].FieldType, Is.EqualTo(typeof(int)));
+
+ var playmodeSettingsFields = ghostConfigurationAnalyticsDataFields[0].FieldType.GetFields();
+ Assert.That(playmodeSettingsFields.Length, Is.EqualTo(7));
+ Assert.That(playmodeSettingsFields[0].Name, Is.EqualTo("ThinClientCount"));
+ Assert.That(playmodeSettingsFields[0].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(playmodeSettingsFields[1].Name, Is.EqualTo("SimulatorEnabled"));
+ Assert.That(playmodeSettingsFields[1].FieldType, Is.EqualTo(typeof(bool)));
+ Assert.That(playmodeSettingsFields[2].Name, Is.EqualTo("Delay"));
+ Assert.That(playmodeSettingsFields[2].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(playmodeSettingsFields[3].Name, Is.EqualTo("DropPercentage"));
+ Assert.That(playmodeSettingsFields[3].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(playmodeSettingsFields[4].Name, Is.EqualTo("Jitter"));
+ Assert.That(playmodeSettingsFields[4].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(playmodeSettingsFields[5].Name, Is.EqualTo("PlayModeType"));
+ Assert.That(playmodeSettingsFields[5].FieldType, Is.EqualTo(typeof(string)));
+ Assert.That(playmodeSettingsFields[6].Name, Is.EqualTo("SimulatorPreset"));
+ Assert.That(playmodeSettingsFields[6].FieldType, Is.EqualTo(typeof(string)));
+
+ var ghostTypeDataFields = ghostConfigurationAnalyticsDataFields[4].FieldType.GetElementType().GetFields();
+ Assert.That(ghostTypeDataFields.Length, Is.EqualTo(4));
+ Assert.That(ghostTypeDataFields[0].Name, Is.EqualTo("GhostId"));
+ Assert.That(ghostTypeDataFields[0].FieldType, Is.EqualTo(typeof(string)));
+ Assert.That(ghostTypeDataFields[1].Name, Is.EqualTo("ChildrenCount"));
+ Assert.That(ghostTypeDataFields[1].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(ghostTypeDataFields[2].Name, Is.EqualTo("ComponentCount"));
+ Assert.That(ghostTypeDataFields[2].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(ghostTypeDataFields[3].Name, Is.EqualTo("ComponentsWithSerializedDataCount"));
+ Assert.That(ghostTypeDataFields[3].FieldType, Is.EqualTo(typeof(int)));
+
+ var clientServerTickRateFields = ghostConfigurationAnalyticsDataFields[5].FieldType.GetFields();
+ Assert.That(clientServerTickRateFields.Length, Is.EqualTo(5));
+ Assert.That(clientServerTickRateFields[0].Name, Is.EqualTo("MaxSimulationStepBatchSize"));
+ Assert.That(clientServerTickRateFields[0].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientServerTickRateFields[1].Name, Is.EqualTo("MaxSimulationStepsPerFrame"));
+ Assert.That(clientServerTickRateFields[1].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientServerTickRateFields[2].Name, Is.EqualTo("NetworkTickRate"));
+ Assert.That(clientServerTickRateFields[2].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientServerTickRateFields[3].Name, Is.EqualTo("SimulationTickRate"));
+ Assert.That(clientServerTickRateFields[3].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientServerTickRateFields[4].Name, Is.EqualTo("TargetFrameRateMode"));
+ Assert.That(clientServerTickRateFields[4].FieldType, Is.EqualTo(typeof(int)));
+
+ var clientTickRateFields = ghostConfigurationAnalyticsDataFields[6].FieldType.GetFields();
+ Assert.That(clientTickRateFields.Length, Is.EqualTo(15));
+ Assert.That(clientTickRateFields[0].Name, Is.EqualTo("CommandAgeCorrectionFraction"));
+ Assert.That(clientTickRateFields[0].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientTickRateFields[1].Name, Is.EqualTo("InterpolationDelayCorrectionFraction"));
+ Assert.That(clientTickRateFields[1].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientTickRateFields[2].Name, Is.EqualTo("InterpolationDelayJitterScale"));
+ Assert.That(clientTickRateFields[2].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientTickRateFields[3].Name, Is.EqualTo("InterpolationDelayMaxDeltaTicksFraction"));
+ Assert.That(clientTickRateFields[3].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientTickRateFields[4].Name, Is.EqualTo("InterpolationTimeMS"));
+ Assert.That(clientTickRateFields[4].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientTickRateFields[5].Name, Is.EqualTo("InterpolationTimeNetTicks"));
+ Assert.That(clientTickRateFields[5].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientTickRateFields[6].Name, Is.EqualTo("InterpolationTimeScaleMax"));
+ Assert.That(clientTickRateFields[6].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientTickRateFields[7].Name, Is.EqualTo("InterpolationTimeScaleMin"));
+ Assert.That(clientTickRateFields[7].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientTickRateFields[8].Name, Is.EqualTo("MaxExtrapolationTimeSimTicks"));
+ Assert.That(clientTickRateFields[8].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientTickRateFields[9].Name, Is.EqualTo("MaxPredictAheadTimeMS"));
+ Assert.That(clientTickRateFields[9].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientTickRateFields[10].Name, Is.EqualTo("MaxPredictionStepBatchSizeFirstTimeTick"));
+ Assert.That(clientTickRateFields[10].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientTickRateFields[11].Name, Is.EqualTo("MaxPredictionStepBatchSizeRepeatedTick"));
+ Assert.That(clientTickRateFields[11].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientTickRateFields[12].Name, Is.EqualTo("PredictionTimeScaleMax"));
+ Assert.That(clientTickRateFields[12].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientTickRateFields[13].Name, Is.EqualTo("PredictionTimeScaleMin"));
+ Assert.That(clientTickRateFields[13].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(clientTickRateFields[14].Name, Is.EqualTo("TargetCommandSlack"));
+ Assert.That(clientTickRateFields[14].FieldType, Is.EqualTo(typeof(int)));
+
+ var mainClientDataFields = ghostConfigurationAnalyticsDataFields[7].FieldType.GetFields();
+ Assert.That(mainClientDataFields.Length, Is.EqualTo(5));
+ Assert.That(mainClientDataFields[0].Name, Is.EqualTo("RelevancyMode"));
+ Assert.That(mainClientDataFields[0].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(mainClientDataFields[1].Name, Is.EqualTo("NumOfPredictedGhosts"));
+ Assert.That(mainClientDataFields[1].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(mainClientDataFields[2].Name, Is.EqualTo("NumSwitchToPredicted"));
+ Assert.That(mainClientDataFields[2].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(mainClientDataFields[3].Name, Is.EqualTo("NumSwitchToInterpolated"));
+ Assert.That(mainClientDataFields[3].FieldType, Is.EqualTo(typeof(int)));
+ Assert.That(mainClientDataFields[4].Name, Is.EqualTo("NumOfSpawnedGhost"));
+ Assert.That(mainClientDataFields[4].FieldType, Is.EqualTo(typeof(int)));
+ }
+ }
}
}
diff --git a/ValidationExceptions.json b/ValidationExceptions.json
index 49ce021..fcd78b3 100644
--- a/ValidationExceptions.json
+++ b/ValidationExceptions.json
@@ -1,25 +1,15 @@
{
"ErrorExceptions": [
- {
- "ValidationTest": "API Validation",
- "ExceptionMessage": "For Experimental or Preview Packages, breaking changes require a new minor version.",
- "PackageVersion": "1.3.2"
- },
- {
- "ValidationTest": "API Validation",
- "ExceptionMessage": "Breaking changes require a new major version.",
- "PackageVersion": "1.3.2"
- },
- {
- "ValidationTest": "API Validation",
- "ExceptionMessage": "Additions require a new minor or major version.",
- "PackageVersion": "1.3.2"
- },
- {
- "ValidationTest": "API Validation",
- "ExceptionMessage": "New assembly \"Unity.NetCode.TestsUtils\" may only be added in a new minor or major version.",
- "PackageVersion": "1.3.2"
- }
+ {
+ "ValidationTest": "API Validation",
+ "ExceptionMessage": "Additions require a new minor or major version.",
+ "PackageVersion": "1.3.6"
+ },
+ {
+ "ValidationTest": "API Validation",
+ "ExceptionMessage": "New assembly \"Unity.NetCode.TestsUtils\" may only be added in a new minor or major version.",
+ "PackageVersion": "1.3.6"
+ }
],
"WarningExceptions": []
}
diff --git a/package.json b/package.json
index abc9dbe..ef3dfcc 100644
--- a/package.json
+++ b/package.json
@@ -1,25 +1,25 @@
{
"name": "com.unity.netcode",
"displayName": "Netcode for Entities",
- "version": "1.3.2",
+ "version": "1.3.6",
"unity": "2022.3",
"unityRelease": "11f1",
"description": "Unity's Data Oriented Technology Stack (DOTS) multiplayer netcode layer - a high level netcode system built on entities. This package provides a foundation for creating networked multiplayer applications within DOTS.",
"dependencies": {
"com.unity.transport": "2.2.1",
- "com.unity.entities": "1.3.2",
+ "com.unity.entities": "1.3.5",
"com.unity.modules.animation": "1.0.0"
},
"_upm": {
- "changelog": "### Changed\n * Updated entities packages dependencies\n\n### Added\n\n* Significantly reduced bandwidth consumption of command packets (i.e. input packets), by a) converting the first command payload in each packet to use delta-compression against zero, b) by making the number of commands sent (per-packet) tied to the `TargetCommandSlack`, c) by delta-compressing the NetworkTicks using the assumed previous tick (which is a correct assumption in the common case), and d) by using a single `changeBit` if the previous command is exactly the same.\n* `ClientTickRate.NumAdditionalCommandsToSend` is a new field allowing you to configure how many additional commands to send to the server in each command (i.e. input) packet.\n* Support for dumping input commands into the `NetDebugPacket` dump, helping users visualize and diagnose bandwidth consumption. Implement the optional, burst-compatible method `ToFixedString` on your input components to see field data in your packet dumps, too.\n* A `NetworkSnapshotAck.CommandArrivalStatistics` struct, documenting (on the server, for each client) how many commands arrive, and how many commands arrive too late. These statistics can be used to inform and tweak `TargetCommandSlack` and `NumAdditionalCommandsToSend`.\n* Significantly expanded our automated test coverage for Lag Compensation. We now detect off-by-one-tick errors between the client and server's lag compensation resolutions.\n* `LagCompensationConfig.DeepCopyDynamicColliders` (defaulting to true) and `LagCompensationConfig.DeepCopyStaticColliders` (defaulting to false) configuration values, enabling you to control whether or not colliders are deep copied during world cloning, preventing runtime exceptions when querying historic worlds during Lag Compensation. Also see the specialized `PhysicsWorldHistorySingleton.DeepCopyRigidBodyCollidersWhitelist` collection.\n\n### Changed\n\n* `PhysicsWorldHistory` now clones collision worlds *after* the `BuildPhysicsWorld` step for the given `ServerTick`. This fixes an issue where the `CollisionWorld` returned by `GetCollisionWorldFromTick` is off-by-one on the server. It is now easier to reason about, as the data stored for `ServerTick` T now actually corresponds to the `BuildPhysicsWorld` operation that occurred on tick T (rather than T-1, which was the previous behaviour). We strongly recommend having automated testing for lag compensation accuracy, as this may introduce a regression, and is therefore a minor breaking change.\n* `PhysicsWorldHistory` now deep copies dynamic colliders by default (see fix entry). Performance impact should be negligible.\n\n### Fixed\n\n* Corrected `seealso` usage in XML package documentation.\n* Documentation improvements and clarifications on the following pages: command stream, ghost snapshots, spawning ghosts, logging, network connection, networked cube, prediction, and RPCs.\n* Lag Compensation issue in the case where an Entity - hit by a query against a historic lag compensation `CollisionWorld` fetched via `GetCollisionWorldFromTick` - has since been deleted. The colliders of dynamic ghosts are now deep cloned by default, preventing the blob asset assertions which would have otherwise been encountered here. You can also opt-into copying static colliders via the `LagCompensationConfig` or `NetCodePhysicsConfig` authoring (although the recommendation is to instead query twice; once against static geometry exclusively, using the latest collision world, then again using the hit position of the static query, against lag compensated dynamic entities).\n* Issue where non-power-of-2 History Buffer sizes would return incorrect entries when `ServerTick` wraps around.\n* an issue with iOS and WebGL AOT, causing the player throwing exceptions while trying to initialize the Netcode generated ghost serializer function pointers. The issue is present when using Burst 1.8 and Unity 6.0+\n* an issue with GhostGroup serialization, incorrectly accessing the wrong ghost prefab type in the GhostCollectionPrefab array.\n* an issue with buffer serialization when using GhostGroup, causing memory stomping at runtime (and exception thrown in the editor), due to the fact the required size for storing the buffer in the snapshot was calculated incorrectly. The root cause was the incorrect index used to access the GhostCollectionPrefab collection."
+ "changelog": "### Changed\n\n* Improved XML document for `NetworkStreamDriver.ConnectionEventsForTick`.\n* Updated entities packages dependencies\n\n### Fixed\n\n* an issue with netcode source generated files, causing multiple Burst.CompileAsync invocation, ending up in stalling the editor and the player for long time, and / or causing crashes.\n* Issue where `OverrideAutomaticNetcodeBootstrap` instances in scenes would be ignored in the Editor if 'Fast Enter Play-Mode Options' is disabled (i.e. when domain reloads triggered after clicking to enter play-mode).\n* Longstanding API documentation errors across Netcode for Entities API documentation."
},
"upmCi": {
- "footprint": "e5b1dca67670175eeaa61f4876150e1f0d88af18"
+ "footprint": "dd892a7e8ce8bd7bb9afdeceaee9a4d43457c0f7"
},
"documentationUrl": "https://docs.unity3d.com/Packages/com.unity.netcode@1.3/manual/index.html",
"repository": {
"url": "https://github.cds.internal.unity3d.com/unity/dots.git",
"type": "git",
- "revision": "921920e681054c59b440cc1e2aef10f781dc4124"
+ "revision": "29c020e0888603e080b55e22043f284ba3bff81d"
}
}