This repository was archived by the owner on Jul 23, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 225
chore: Managed Netvar documentation #818
Merged
ShadauxCat
merged 16 commits into
develop
from
chore/update_docs_with_managed_netvar_support
Dec 6, 2022
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
0ab5788
chore: Managed Netvar documentation
ShadauxCat 62d7492
small fix
ShadauxCat 21dac62
Reverted formatting changes performed without my consent by my markdo…
ShadauxCat 8e7fa29
Merge branch 'develop' into chore/update_docs_with_managed_netvar_sup…
chrispope 158ced7
Update docs/advanced-topics/serialization/inetworkserializable.md
ShadauxCat f89fe2f
some updates based on feedback - mostly fixing grammatical issues tha…
ShadauxCat 9e76113
Merge branch 'develop' into chore/update_docs_with_managed_netvar_sup…
chrispope 8397c13
Merge remote-tracking branch 'origin/chore/update_docs_with_managed_n…
ShadauxCat 7b5c3ba
PR feedback
ShadauxCat 4652056
Merge branch 'develop' into chore/update_docs_with_managed_netvar_sup…
34f8fbf
Merge branch 'develop' into chore/update_docs_with_managed_netvar_sup…
chrispope 18c9fb4
Merge branch 'develop' into chore/update_docs_with_managed_netvar_sup…
6b4adef
Merge branch 'develop' into chore/update_docs_with_managed_netvar_sup…
052f413
Merge branch 'develop' into chore/update_docs_with_managed_netvar_sup…
d0b1ce4
Merge branch 'develop' into chore/update_docs_with_managed_netvar_sup…
15aa0c2
Merge branch 'develop' into chore/update_docs_with_managed_netvar_sup…
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ id: custom-serialization | |
title: Custom Serialization | ||
--- | ||
|
||
When using `RPC`'s, `NetworkVariable`'s or any other Netcode for GameObjects (Netcode) related task that requires serialization. The Netcode uses a default serialization pipeline that looks like this: | ||
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: | ||
|
||
`` | ||
Custom Types => Built In Types => INetworkSerializable | ||
|
@@ -13,7 +13,9 @@ That is, when Netcode first gets hold of a type, it will check for any custom ty | |
|
||
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 contains only these basic types. | ||
|
||
With this flow, you can override **ALL** serialization for **ALL** types, even built in types, and with the API provided, it can even be done with types that you have not defined yourself, those who are behind a 3rd party wall, such as .NET types. | ||
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 have not 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. | ||
|
||
### For RPCs | ||
|
||
To register a custom type, or override an already handled type, you need to create extension methods for `FastBufferReader.ReadValueSafe()` and `FastBufferWriter.WriteValueSafe()`: | ||
|
||
|
@@ -22,15 +24,15 @@ To register a custom type, or override an already handled type, you need to crea | |
// The class name doesn't matter here. | ||
public static class SerializationExtensions | ||
{ | ||
public static void ReadValueSafe(this FastBufferReader reader, out Url value) | ||
public static void ReadValueSafe(this FastBufferReader reader, out Url url) | ||
{ | ||
reader.ReadValueSafe(out string val); | ||
value = new Url(val); | ||
url = new Url(val); | ||
} | ||
|
||
public static void WriteValueSafe(this FastBufferWriter writer, in Url value) | ||
public static void WriteValueSafe(this FastBufferWriter writer, in Url url) | ||
{ | ||
writer.WriteValueSafe(instance.Value); | ||
writer.WriteValueSafe(url.Value); | ||
} | ||
} | ||
``` | ||
|
@@ -39,19 +41,45 @@ The code generation for RPCs will automatically pick up and use these functions, | |
|
||
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`](/advanced-topics/serialization/inetworkserializable.md) types: | ||
|
||
```c# | ||
```csharp | ||
// The class name doesn't matter here. | ||
public static class SerializationExtensions | ||
{ | ||
public static void SerializeValue<TReaderWriter>(this BufferSerializer<TReaderWriter> serializer, ref Url value) where TReaderWriter: IReaderWriter | ||
public static void SerializeValue<TReaderWriter>(this BufferSerializer<TReaderWriter> serializer, ref Url url) where TReaderWriter: IReaderWriter | ||
{ | ||
if (serializer.IsReader) | ||
{ | ||
value = new Url(); | ||
url = new Url(); | ||
} | ||
serializer.SerializeValue(ref value.Value); | ||
serializer.SerializeValue(ref url.Value); | ||
} | ||
} | ||
``` | ||
|
||
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. | ||
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. | ||
|
||
### For NetworkVariable | ||
|
||
`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. | ||
|
||
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: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you provide a relative link to the "For RPCs" section reference? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do I provide a link to a heading in the same file? |
||
|
||
```csharp | ||
UserNetworkVariableSerialization<Url>.WriteValue = SerializationExtensions.WriteValueSafe; | ||
UserNetworkVariableSerialization<Url>.ReadValue = SerializationExtensions.ReadValueSafe; | ||
``` | ||
|
||
You can also use lambda expressions here: | ||
|
||
```csharp | ||
UserNetworkVariableSerialization<Url>.WriteValue = (FastBufferWriter writer, in Url url) => | ||
{ | ||
writer.WriteValueSafe(url.Value); | ||
}; | ||
|
||
UserNetworkVariableSerialization<Url>.ReadValue = (FastBufferReader reader, out Url url) | ||
{ | ||
reader.ReadValueSafe(out string val); | ||
url = new Url(val); | ||
}; | ||
``` |
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
--- | ||
id: fixedstrings | ||
title: Fixed Strings | ||
--- | ||
|
||
Netcode's serialization system natively supports Unity's Fixed String types (`FixedString32`, `FixedString64`, `FixedString128`, `FixedString512`, and `FixedString4096`). The serialization system intelligently understands these fixed string types and ensures that only the amount of the string in use is serialized, even for the larger types. This native support ensures Netcode uses no more bandwidth than is necessary. | ||
|
||
armstrongl marked this conversation as resolved.
Show resolved
Hide resolved
|
||
```csharp | ||
[ServerRpc] | ||
void SetPlayerNameServerRpc(FixedString32 playerName) { /* ... */ } | ||
|
||
void SetPlayerName(string name) | ||
{ | ||
SetPlayerNameServerRpc(new FixedString32(name)); | ||
} | ||
``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
docs/advanced-topics/serialization/inetworkserializebymemcpy.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
--- | ||
id: inetworkserializebymemcpy | ||
title: INetworkSerializeByMemcpy | ||
sidebar_label: INetworkSerializeByMemcpy | ||
--- | ||
|
||
The `INetworkSerializeByMemcpy` interface is used to mark an unmanaged struct type as being trivially serializable over the network by directly copying the whole struct, byte-for-byte, as it appears in memory, into and out of the buffer. This can offer some benefits for performance compared to serializing one field at a time, especially if the struct has many fields in it, but it may be less efficient from a bandwidth-usage perspective, as fields will often be padded for memory alignment and you won't be able to "pack" any of the fields to optimize for space usage. | ||
|
||
The interface itself has no methods in it - it's an empty interface that satisfies a constraint on methods that perform this type of serialization, primarily there to ensure that memcpy serialization isn't performed by accident on structs that don't support it. | ||
|
||
```csharp | ||
public struct MyStruct : INetworkSerializeByMemcpy | ||
{ | ||
public int A; | ||
public int B; | ||
public float C; | ||
public bool D; | ||
} | ||
``` | ||
|
||
If you have a type you wish to serialize that you know is compatible with this method of serialization, but don't have access to modify the struct to add this interface, you can wrap your values in `ForceNetworkSerializeByMemcpy` to enable it to be serialized this way. This works in both `RPC`s and `NetworkVariables`, as well as in other contexts such as `BufferSerializer<>`, `FastBufferReader`, and `FastBufferWriter`. | ||
chrispope marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```csharp | ||
public NetworkVariable<ForceNetworkSerializeByMemcpy<Guid>> GuidVar; | ||
``` | ||
|
||
f:::caution | ||
Take care with using `INetworkSerializeByMemcpy`, and especially `ForceNetworkSerializeByMemcpy`, because not all unmanaged structs are actually compatible with this type of serialization. Anything that includes pointer types (including Native Collections like `NativeArray<>`) will not function correctly when serialized this way, and will likely cause memory corruption or crashes on the receiving side. | ||
::: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.