Skip to content

Commit 7ddf4e9

Browse files
Merge branch 'develop-2.0.0' into doc/singleplayer-transport-addition
2 parents 9ec8f89 + 3e579ed commit 7ddf4e9

49 files changed

Lines changed: 1450 additions & 905 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.yamato/_triggers.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ develop_nightly:
157157
- .yamato/project-updated-dependencies-test.yml#updated-dependencies_testproject_NGO_win_6000.0
158158
# Run API validation to early-detect all new APIs that would force us to release new minor version of the package. Note that for this to work the package version in package.json must correspond to "actual package state" which means that it should be higher than last released version
159159
- .yamato/vetting-test.yml#vetting_test
160+
# Run code coverage test
161+
- .yamato/code-coverage.yml#code_coverage_ubuntu_{{ validation_editors.default }}
160162

161163

162164
# Run all tests on weekly bases
@@ -187,5 +189,3 @@ develop_weekly_trunk:
187189
- .yamato/_run-all.yml#run_all_webgl_builds
188190
# Run Runtime tests against CMB service
189191
- .yamato/_run-all.yml#run_all_project_tests_cmb_service
190-
# Run code coverage test
191-
- .yamato/code-coverage.yml#code_coverage_ubuntu_{{ validation_editors.default }}

.yamato/code-coverage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ code_coverage_{{ platform.name }}_{{ editor }}:
3939
commands:
4040
- unity-downloader-cli --fast --wait -u {{ editor }} -c Editor {% if platform.name == "mac" %} --arch arm64 {% endif %} # For macOS we use ARM64 models
4141
- upm-pvp create-test-project test-project --packages "upm-ci~/packages/*.tgz" --unity .Editor
42-
- UnifiedTestRunner --suite=editor --suite=playmode --editor-location=.Editor --testproject=test-project --enable-code-coverage coverage-upload-options="reportsDir:$PWD/test-results/CoverageResults;name:NGOv2_{{ platform.name }}_{{ editor }};flags:NGOv2_{{ platform.name }}_{{ editor }};verbose" --coverage-results-path=$PWD/test-results/CoverageResults --coverage-options="generateHtmlReport;generateAdditionalMetrics;assemblyFilters:+Unity.Netcode.Editor,+Unity.Netcode.Runtime" --extra-editor-arg=--burst-disable-compilation --timeout={{ test_timeout }} --rerun-strategy=Test --retry={{ num_test_retries }} --clean-library-on-rerun --artifacts-path=test-results
42+
- UnifiedTestRunner --suite=editor --suite=playmode --editor-location=.Editor --testproject=test-project --enable-code-coverage --coverage-upload-options="reportsDir:$PWD/test-results/CoverageResults;name:NGOv2_{{ platform.name }}_{{ editor }};flags:NGOv2_{{ platform.name }}_{{ editor }};verbose" --coverage-results-path=$PWD/test-results/CoverageResults --coverage-options="generateHtmlReport;generateAdditionalMetrics;assemblyFilters:+Unity.Netcode.Editor,+Unity.Netcode.Runtime" --extra-editor-arg=--burst-disable-compilation --timeout={{ test_timeout }} --rerun-strategy=Test --retry={{ num_test_retries }} --clean-library-on-rerun --artifacts-path=test-results
4343
artifacts:
4444
logs:
4545
paths:

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ Additional documentation and release notes are available at [Multiplayer Documen
2121

2222

2323
### Fixed
24+
25+
- Issue where a NullReferenceException was thrown when a non-authority failed to spawn a NetworkObject. (#4067)
26+
- Issue where the active scene was not being serialized as the 1st scene which could result in various errors including a soft synchronization error if, on the client-side, other synchronized scenes had already been loaded prior to the active scene, which is always loaded as `LoadSceneMode.SingleMode` when client synchronization is set to `LoadSceneMode.SingleMode`, resulting in the previously loaded scene(s) to be unloaded. (#4065)
27+
- Issue when FastBufferReader is attempting to read a string and all or a portion of the character count has already been read by user script, it could read a character length that results in a negative byte length which could result in an editor crash. (#4052)
2428
- Issue where NetworkRigidbodyBase was not applying rotation correctly when using Rigidbody2D. (#4012)
2529
- Issue where NetworkRigidbodyBase was always checking the 3D rigid body's interpolation mode when determining if it is kinematic and needs to put the rigid body to sleep and then switch to interpolation. (#4012)
2630

com.unity.netcode.gameobjects/Documentation~/TableOfContents.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,17 @@
7171
* [Network update loop reference](advanced-topics/network-update-loop-system/network-update-loop-reference.md)
7272
* [Network time and ticks](advanced-topics/networktime-ticks.md)
7373
* [Serialization](serialization.md)
74+
* [Serialization overview](advanced-topics/serialization/serialization-overview.md)
7475
* [C# primitives](advanced-topics/serialization/cprimitives.md)
7576
* [Unity primitives](advanced-topics/serialization/unity-primitives.md)
7677
* [Enum types](advanced-topics/serialization/enum-types.md)
7778
* [Arrays](advanced-topics/serialization/serialization-arrays.md)
78-
* [INetworkSerializable](advanced-topics/serialization/inetworkserializable.md)
79-
* [INetworkSerializeByMemcpy](advanced-topics/serialization/inetworkserializebymemcpy.md)
80-
* [Custom serialization](advanced-topics/custom-serialization.md)
81-
* [NetworkObject serialization](advanced-topics/serialization/networkobject-serialization.md)
79+
* [Customize serializable types with INetworkSerializable](advanced-topics/serialization/inetworkserializable.md)
80+
* [Serialize unmanaged structs with INetworkSerializeByMemcpy](advanced-topics/serialization/inetworkserializebymemcpy.md)
81+
* [NetworkObject and NetworkBehaviour serialization](advanced-topics/serialization/networkobject-serialization.md)
8282
* [FastBufferWriter and FastBufferReader](advanced-topics/fastbufferwriter-fastbufferreader.md)
83+
* [BufferSerializer](advanced-topics/bufferserializer.md)
84+
* [Custom serialization](advanced-topics/custom-serialization.md)
8385
* [Scene management](scene-management.md)
8486
* [Scene management overview](basics/scenemanagement/scene-management-overview.md)
8587
* [Integrated management](integrated-management.md)

com.unity.netcode.gameobjects/Documentation~/advanced-topics/bufferserializer.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# BufferSerializer
22

3+
> [!NOTE]
4+
> Read the [Serialization overview](./serialization/serialization-overview.md) page to understand the basics of serialization before learning how to use `BufferSerializer`.
5+
36
`BufferSerializer<TReaderWriter>` is the bi-directional serializer primarily used for serializing within [`INetworkSerializable`](serialization/inetworkserializable.md) types. It wraps [`FastBufferWriter` and `FastBufferReader`](fastbufferwriter-fastbufferreader.md) to provide high performance serialization, but has a couple of differences to make it more user-friendly:
47

58
- Rather than writing separate methods for serializing and deserializing, `BufferSerializer<TReaderWriter>` allows writing a single method that can handle both operations, which reduces the possibility of a mismatch between the two
@@ -15,3 +18,7 @@ However, when those downsides are unreasonable, `BufferSerializer<TReaderWriter>
1518

1619
- For performance, you can use `PreCheck(int amount)` followed by `SerializeValuePreChecked()` to perform bounds checking for multiple fields at once.
1720
- For both performance and bandwidth usage, you can obtain the wrapped underlying reader/writer via `serializer.GetFastBufferReader()` when `serializer.IsReader` is `true`, and `serializer.GetFastBufferWriter()` when `serializer.IsWriter` is `true`. These provide micro-performance improvements by removing a level of indirection, and also give you a type you can use with `BytePacker` and `ByteUnpacker`.
21+
22+
## Serializing custom types
23+
24+
`BufferSerializer<TReaderWriter>` can be extended via extension methods to handle serializing custom types. Refer to [customizing `BufferSerializer`](./custom-serialization.md#bufferserializer) for instructions on how to do this.
Lines changed: 46 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,71 @@
11
# Custom serialization
22

3-
Netcode uses a default serialization pipeline when using `RPC`s, `NetworkVariable`s, or any other Netcode-related tasks that require serialization. The serialization pipeline looks like this:
3+
> [!NOTE]
4+
> Read the [Serialization overview](./serialization/serialization-overview.md) page to understand the basics of serialization before learning how to customize serialization.
45
5-
``
6-
Custom Types => Built In Types => INetworkSerializable
7-
``
6+
Netcode for GameObjects provide support for serializing any unsupported types, and with the API provided, it can even be done with types that you haven't defined yourself, those who are behind a 3rd party wall, such as .NET types. However, the way custom serialization is implemented for RPCs and NetworkVariables is slightly different.
87

9-
That is, when Netcode first gets hold of a type, it will check for any custom types that the user have registered for serialization, after that it will check if it's a built in type, such as a Vector3, float etc. These are handled by default. If not, it will check if the type inherits `INetworkSerializable`, if it does, it will call it's write methods.
8+
Netcode for GameObjects supports custom serialization of unsupported types, including those you haven't defined yourself, such as third-party .NET types. You can also use custom serialization to override how an existing supported type is serialized.
109

11-
By default, any type that satisfies the `unmanaged` generic constraint can be automatically serialized as RPC parameters. This includes all basic types (bool, byte, int, float, enum, etc) as well as any structs that has only these basic types.
10+
Custom serialization is implemented slightly differently for RPCs and NetworkVariables. The examples on this page provide different ways to serialization a custom health struct.
1211

13-
With this flow, you can provide support for serializing any unsupported types, and with the API provided, it can even be done with types that you haven't defined yourself, those who are behind a 3rd party wall, such as .NET types. However, the way custom serialization is implemented for RPCs and NetworkVariables is slightly different.
12+
[!code-cs[](../../Tests/Editor/DocumentationCodeSamples/Serialization/SerializationCustomization.cs#HealthStruct)]
1413

15-
### Serialize a type in a Remote Procedure Call (RPC)
14+
## FastBufferReader and FastBufferWriter
1615

17-
> [!NOTE]
18-
> From versioln 1.7.0 Remote Procedure Calls (RPCs) can also use the Network Variable flow, but NetworkVariables can't use the RPC flow. The RPC flow is more efficient when RPCs serialize the type. Unity selects the RPC flow if you implement both the RPC and Network variable flows. When a type is used by both NetworkVariables and RPCs you can use the NetworkVariable flow to lower maintenance requirements.
16+
[`FastBufferReader` and `FastBufferWriter`](./fastbufferwriter-fastbufferreader.md) are the main serialization tools in Netcode for GameObjects. To register serialization for a custom type, or override an already handled type, you need to create extension methods for `FastBufferReader.ReadValueSafe()` and `FastBufferWriter.WriteValueSafe()`. `FastBufferReader` and `FastBufferWriter` can read and write primitive types, and you can extend this functionality to serialize your custom type.
1917

20-
To register a custom type, or override an already handled type, you need to create extension methods for `FastBufferReader.ReadValueSafe()` and `FastBufferWriter.WriteValueSafe()`:
18+
[!code-cs[](../../Tests/Editor/DocumentationCodeSamples/Serialization/SerializationCustomization.cs#FastBuffer)]
2119

22-
```csharp
23-
// Tells the Netcode how to serialize and deserialize Url in the future.
24-
// The class name doesn't matter here.
25-
public static class SerializationExtensions
26-
{
27-
public static void ReadValueSafe(this FastBufferReader reader, out Url url)
28-
{
29-
reader.ReadValueSafe(out string val);
30-
url = new Url(val);
31-
}
32-
33-
public static void WriteValueSafe(this FastBufferWriter writer, in Url url)
34-
{
35-
writer.WriteValueSafe(url.Value);
36-
}
37-
}
38-
```
20+
You may also need to add extensions for `FastBufferReader.ReadValue()`, `FastBufferWriter.WriteValue()` if you want to serialize without [bounds checking](./fastbufferwriter-fastbufferreader.md#bounds-checking)
3921

40-
The code generation for RPCs will automatically pick up and use these functions, and they'll become available via `FastBufferWriter` and `FastBufferReader` directly.
22+
## BufferSerializer
4123

42-
You can also optionally use the same method to add support for `BufferSerializer<TReaderWriter>.SerializeValue()`, if you wish, which will make this type readily available within [`INetworkSerializable`](serialization/inetworkserializable.md) types:
24+
You can also add custom serialization support to the bi-directional [`BufferSerializer`](./bufferserializer.md). This makes your custom type readily available within [`INetworkSerializable`](serialization/inetworkserializable.md) types and in the [`NetworkBehaviour.OnSynchronize()` method](../components/core/networkbehaviour-synchronize.md#prespawn-synchronization-with-onsynchronize):
4325

44-
```csharp
45-
// The class name doesn't matter here.
46-
public static class SerializationExtensions
47-
{
48-
public static void SerializeValue<TReaderWriter>(this BufferSerializer<TReaderWriter> serializer, ref Url url) where TReaderWriter: IReaderWriter
49-
{
50-
if (serializer.IsReader)
51-
{
52-
url = new Url();
53-
}
54-
serializer.SerializeValue(ref url.Value);
55-
}
56-
}
57-
```
26+
[!code-cs[](../../Tests/Editor/DocumentationCodeSamples/Serialization/SerializationCustomization.cs#BufferSerializer)]
5827

59-
Additionally, you can also add extensions for `FastBufferReader.ReadValue()`, `FastBufferWriter.WriteValue()`, and `BufferSerializer<TReaderWriter>.SerializeValuePreChecked()` to provide more optimal implementations for manual serialization using `FastBufferReader.TryBeginRead()`, `FastBufferWriter.TryBeginWrite()`, and `BufferSerializer<TReaderWriter>.PreCheck()`, respectively. However, none of these will be used for serializing RPCs - only `ReadValueSafe` and `WriteValueSafe` are used.
28+
## Remote procedure call (RPCs)
6029

61-
### For NetworkVariable
30+
> [!NOTE]
31+
> RPCs can use the Network Variable flow, but NetworkVariables can't use the RPC flow. The RPC flow is more efficient when only RPCs need to serialize the type. When a type is used by both NetworkVariables and RPCs, you can implement just the NetworkVariable flow to lower maintenance requirements. Unity will select the RPC flow for RPCs if you have implemented both flows.
6232
63-
`NetworkVariable` goes through a slightly different pipeline than `RPC`s and relies on a different process for determining how to serialize its types. As a result, making a custom type available to the `RPC` pipeline doesn't automatically make it available to the `NetworkVariable` pipeline, and vice-versa. The same method can be used for both, but currently, `NetworkVariable` requires an additional runtime step to make it aware of the methods.
33+
To serialize a custom type, or override an already handled type, you need to create extension methods for `FastBufferReader.ReadValueSafe()` and `FastBufferWriter.WriteValueSafe()` as [outlined above](#fastbufferreader-and-fastbufferwriter).
6434

65-
To add custom serialization support in `NetworkVariable`, follow the steps from the "For RPCs" section to write extension methods for `FastBufferReader` and `FastBufferWriter`; then, somewhere in your application startup (before any `NetworkVariable`s using the affected types will be serialized) add the following:
35+
The code generation for RPCs will automatically pick up and use these functions, as they'll become available via `FastBufferWriter` and `FastBufferReader` directly.
6636

67-
```csharp
68-
UserNetworkVariableSerialization<Url>.WriteValue = SerializationExtensions.WriteValueSafe;
69-
UserNetworkVariableSerialization<Url>.ReadValue = SerializationExtensions.ReadValueSafe;
70-
```
37+
## NetworkVariable
38+
39+
Implementing [`INetworkSerializable`](./serialization/inetworkserializable.md) is the cleanest and most straightforward way to customize the serialization of a type within a [`NetworkVariable`](../basics/networkvariable.md). `UserNetworkVariableSerialization` provides runtime configuration to further override serialization of a type.
7140

72-
You can also use lambda expressions here:
41+
First you will need to create extension methods for `FastBufferReader.ReadValueSafe()` and `FastBufferWriter.WriteValueSafe()` as [outlined above](#fastbufferreader-and-fastbufferwriter).
42+
43+
Secondly, somewhere in your application startup (before any `NetworkVariable`s using the affected types will be serialized), add the following:
7344

7445
```csharp
75-
UserNetworkVariableSerialization<Url>.WriteValue = (FastBufferWriter writer, in Url url) =>
76-
{
77-
writer.WriteValueSafe(url.Value);
78-
};
79-
80-
UserNetworkVariableSerialization<Url>.ReadValue = (FastBufferReader reader, out Url url)
81-
{
82-
reader.ReadValueSafe(out string val);
83-
url = new Url(val);
84-
};
46+
UserNetworkVariableSerialization<Health>.WriteValue = SerializationExtensions.WriteValueSafe;
47+
UserNetworkVariableSerialization<Health>.ReadValue = SerializationExtensions.ReadValueSafe;
48+
UserNetworkVariableSerialization<Health>.DuplicateValue = (in Health value, ref Health duplicatedValue) => duplicatedValue = value;
8549
```
8650

87-
When you create an extension method in `NetworkVariable<T>` you need to implement the following values:
51+
`DuplicateValue` should return a complete deep copy of the value that `NetworkVariable<T>` compares to a previous value, which is used to check whether the value has changed. `DuplicateValue` avoids re-serializing it over the network every frame when it hasn't changed.
52+
53+
> [!NOTE]
54+
> `WriteValue`, `ReadValue` and `DuplicateValue` all need to be defined to customize your serialization.
55+
56+
> [!NOTE]
57+
> `WriteValue` and `ReadValue` will not be used if a type implements `INetworkSerializable` or [`INetworkSerializeByMemcpy`](./serialization/inetworkserializebymemcpy.md).
58+
59+
### Serializing delta updates
60+
61+
Reading and writing a value provides the minimal amount of `NetworkVariable` functionality. This will synchronize your whole type whenever any value within the type value changes. To support sending delta updates rather than a full update whenever your type has changed, implement the following functions:
62+
63+
- `WriteDelta`
64+
- `ReadDelta`
65+
66+
> [!NOTE]
67+
> Both `WriteDelta` and `ReadDelta` need to be defined for either to be used.
8868
89-
- `WriteValue`
90-
- `ReadValue`
91-
- `DuplicateValue`
69+
Here is a full implementation of a custom type with the methods needed for `UserNetworkVariableSerialization`
9270

93-
`DuplicateValue` returns a complete deep copy of the value that `NetworkVariable<T>` compares to a previous value to check whether or not that values has changed. This avoids reserializing it over the network every frame when it hasn't changed.
71+
[!code-cs[](../../Tests/Runtime/DocumentationCodeSamples/NetworkVariable/NetworkVariableSerialization.cs#HealthExample)]

com.unity.netcode.gameobjects/Documentation~/advanced-topics/fastbufferwriter-fastbufferreader.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# FastBufferWriter and FastBufferReader
22

3+
> [!NOTE]
4+
> Read the [Serialization overview](./serialization/serialization-overview.md) page to understand the basics of serialization before learning about `FastBufferWriter` and `FastBufferReader`.
5+
36
The serialization and deserialization is done via `FastBufferWriter` and `FastBufferReader`. These have methods for serializing individual types and methods for serializing packed numbers, but in particular provide a high-performance method called `WriteValue()/ReadValue()` (for Writers and Readers, respectively) that can extremely quickly write an entire unmanaged struct to a buffer.
47

58
There's a trade-off of CPU usage vs bandwidth in using this: Writing individual fields is slower (especially when it includes operations on unaligned memory), but allows the buffer to be filled more efficiently, both because it avoids padding for alignment in structs, and because it allows you to use `BytePacker.WriteValuePacked()`/`ByteUnpacker.ReadValuePacked()` and `BytePacker.WriteValueBitPacked()`/`ByteUnpacker.ReadValueBitPacked()`. The difference between these two is that the BitPacked variants pack more efficiently, but they reduce the valid range of values. See the section below for details on packing.
@@ -156,3 +159,7 @@ Packing values is done using the utility classes `BytePacker` and `ByteUnpacker`
156159
| uint | 30 bits (0 to 1,073,741,824) |
157160
| long | 60 bits + sign bit (-1,152,921,504,606,846,976 to 1,152,921,504,606,846,975) |
158161
| ulong | 61 bits (0 to 2,305,843,009,213,693,952) |
162+
163+
## Serializing custom types
164+
165+
`FastBufferReader` and `FastBufferWriter` can be extended via extension methods to handle serializing custom types. Refer to [customizing `FastBufferReader` and `FastBufferWriter`](./custom-serialization.md#fastbufferreader-and-fastbufferwriter) for instructions on how to do this.

0 commit comments

Comments
 (0)