Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .yamato/_triggers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ pr_code_changes_checks:
# Note that our daily tests will anyway run both test configurations in "minimal supported" and "trunk" configurations
- .yamato/desktop-standalone-tests.yml#desktop_standalone_test_testproject_ubuntu_il2cpp_{{ pinnedTrunk }}
- .yamato/cmb-service-standalone-tests.yml#cmb_service_standalone_test_testproject_ubuntu_il2cpp_{{ pinnedTrunk }}
# Run code coverage test
- .yamato/code-coverage.yml#code_coverage_ubuntu_{{ validation_editors.default }}
# Run code coverage test (PRs use the pinned "safe" trunk)
- .yamato/code-coverage.yml#code_coverage_project_test_testproject_ubuntu_{{ pinnedTrunk }}
triggers:
expression: |-
(pull_request.comment eq "ngo" OR
Expand Down Expand Up @@ -161,8 +161,8 @@ develop_nightly:
- .yamato/project-updated-dependencies-test.yml#updated-dependencies_testproject_NGO_win_{{ validation_editors.default }}
# 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
- .yamato/vetting-test.yml#vetting_test
# Run code coverage test
- .yamato/code-coverage.yml#code_coverage_ubuntu_{{ validation_editors.default }}
# Run code coverage test (nightly uses actual trunk)
- .yamato/code-coverage.yml#code_coverage_project_test_testproject_ubuntu_trunk


# Run all tests on weekly bases
Expand Down
29 changes: 17 additions & 12 deletions .yamato/code-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,37 @@
---

# DESCRIPTION--------------------------------------------------------------------------
# This job is responsible for executing package tests with code coverage analysis enabled.
# This job runs the in-repo testproject tests with code coverage analysis enabled.
# The project tests also exercise the NGO package tests, so a separate package-test coverage job is not needed.
# Coverage analysis provides insights into:
# Test coverage metrics for NGO assemblies
# Line and branch coverage statistics
# Generated HTML reports for coverage visualization
# Additional metrics for coverage analysis

# CONFIGURATION STRUCTURE--------------------------------------------------------------
# Jobs are generated using nested loops through:
# 1. For default platform only (Ubuntu) since coverage would not vary between platforms (no need for checks on more platforms)
# 2. For default editor version (trunk) since coverage would not vary between editors (no need for checks on more editors)
# Jobs are generated for:
# 1. Default platform only (Ubuntu) since coverage would not vary between platforms (no need for checks on more platforms)
# 2. Two editors: actual "trunk" (used by nightly) and the "pinnedTrunk" safe version (used by PRs).
# Occasionally trunk breaks our tests, so PRs run against a pinned "safe" trunk while nightly runs actual trunk.

#TECHNICAL CONSIDERATIONS---------------------------------------------------------------
# In theory this job also runs package tests, but we don't want to use it as default since is heavier (because of added coverage analysis) and coverage is not changing that often
# Requires Unity Editor installation
# Burst compilation is disabled to ensure accurate coverage measurement
# In order to properly use -coverage-results-path parameter we need to start it with $PWD (which means the absolute path). Otherwise coverage results will not be visible

# QUALITY CONSIDERATIONS--------------------------------------------------------------------
# To see where this job is included (in trigger job definitions) look into _triggers.yml file

# To see where this job is included (in trigger job definitions) look into _triggers.yml file. Currently:
# [Code Coverage] Project Test runs on PR changes (pr_code_changes_checks, pinnedTrunk) and nightly (develop_nightly, trunk)

{% assign coverage_editors = "trunk," | append: pinnedTrunk | split: "," -%}

{% for platform in test_platforms.default -%}
{% for editor in validation_editors.default -%}
code_coverage_{{ platform.name }}_{{ editor }}:
name: Code Coverage - NGO [{{ platform.name }}, {{ editor }}]
{% for project in projects.default -%}
{% for editor in coverage_editors -%}
{% if editor == "trunk" -%}{% assign editor_label = "trunk" -%}{% else -%}{% assign editor_label = "pinnedTrunk" -%}{% endif -%}
code_coverage_project_test_{{ project.name }}_{{ platform.name }}_{{ editor }}:
name: '[Code Coverage] Project Test - NGO {{ project.name }} [{{ platform.name }}, {{ editor }}]'
agent:
type: {{ platform.type }}
image: {{ platform.image }}
Expand All @@ -38,13 +42,14 @@ code_coverage_{{ platform.name }}_{{ editor }}:
{% endif %}
commands:
- unity-downloader-cli --fast --wait -u {{ editor }} -c Editor {% if platform.name == "mac" %} --arch arm64 {% endif %} # For macOS we use ARM64 models
- upm-pvp create-test-project test-project --packages "upm-ci~/packages/*.tgz" --unity .Editor
- 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
- UnifiedTestRunner --testproject={{ project.path }} --suite=editor --suite=playmode --editor-location=.Editor --enable-code-coverage --coverage-upload-options="reportsDir:$PWD/test-results/CoverageResults;name:NGOv2_project_{{ project.name }}_{{ platform.name }}_{{ editor_label }};flags:NGOv2_project_{{ project.name }}_{{ platform.name }}_{{ editor_label }};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
artifacts:
logs:
paths:
- "test-results/**/*"
dependencies:
- .yamato/_run-all.yml#run_quick_checks # initial checks to perform fast validation of common errors
- .yamato/package-pack.yml#package_pack_-_ngo_{{ platform.name }}
{% endfor -%}
{% endfor -%}
{% endfor -%}
6 changes: 5 additions & 1 deletion Tools/CI/service.cmb/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Testing against the CMB Service

The CMB Service is a tool that is external to our repository. The tool is inside the `runtime` folder in the [mps-common-multiplayer-backend](https://github.com/Unity-Technologies/mps-common-multiplayer-backend) repository.
The CMB Service is a tool that is external to our repository. The tool is inside the `runtime` folder of the [CMB service](https://github.com/Unity-Technologies/unity-player-services/tree/main/services/common-multiplayer-backend) in the Unity Player Services monorepo.

Due to this, there is some more setup needed when running tests against the CMB Service.

Expand Down Expand Up @@ -56,3 +56,7 @@ The following environment variables allow for further configuration of the setup
`CMB_SERVICE_PORT` defines the port where the tests will try to connect to the service (defaults to `7789`).

`NGO_HOST` defines the http address where the tests will try to connect to the service (defaults to `127.0.0.1`).

## Running on CI (Yamato)

The CMB tests can also be run from Yamato. The jobs are defined in [`.yamato/cmb-service-standalone-tests.yml`](../../../.yamato/cmb-service-standalone-tests.yml) and appear in Yamato as `CMB Service Test - NGO <project> - [<platform>, <editor>, <backend>]`. The job can be triggered manually from any branch meaning it can be easier to run the CMB tests from Yamato rather than set them up locally. The test uses [`run_cmb_service.sh`](./run_cmb_service.sh) to setup and run the CMB service.
11 changes: 7 additions & 4 deletions Tools/CI/service.cmb/run_cmb_service.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# Example usage:
# ./<path-to-script>/run_cmb_service.sh -e 7788 -s 7799

# This script is currently used in the desktop-standalone-tests yamato job.
# This script is currently used in the cmb-service-standalone-tests yamato job (found at ../../../.yamato/cmb-service-standalone-tests.yml).

# TECHNICAL CONSIDERATIONS---------------------------------------------------------------
# This is a bash script and so needs to be run on a Unix based system.
Expand Down Expand Up @@ -136,11 +136,14 @@ else
logMessage "Protocol Buffer Compiler Installed & ENV variables verified!\n PROTOC path is: $PROTOC"
fi

# clone the cmb service repo
git clone https://github.com/Unity-Technologies/mps-common-multiplayer-backend.git
# Sparse-checkout only the CMB service directory from the unity-player-services monorepo.
# --filter=blob:none + --depth 1 avoids downloading file contents and history for the rest of the monorepo.
git clone --depth 1 --filter=blob:none --sparse https://github.com/Unity-Technologies/unity-player-services.git
cd ./unity-player-services
git sparse-checkout set services/common-multiplayer-backend/runtime

# navigate to the cmb service directory
cd ./mps-common-multiplayer-backend/runtime
cd ./services/common-multiplayer-backend/runtime

# Install rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
Expand Down
6 changes: 6 additions & 0 deletions com.unity.netcode.gameobjects/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Additional documentation and release notes are available at [Multiplayer Documen
- `Unity.Netcode.Editor.PackageChecker` → `Unity.Netcode.GameObjects.Editor.PackageChecker`
- `Unity.Netcode.Editor.Tests` → `Unity.Netcode.GameObjects.Editor.Tests`



### Deprecated


Expand All @@ -27,6 +29,10 @@ Additional documentation and release notes are available at [Multiplayer Documen

### Fixed

- Issue with not being able to spawn initially disabled in-scene placed objects. (#4093)
- Issue with pre-instantiated network prefab instances being marked as in-scene placed. Now pre-instantiated network prefabs are dynamically spawned. (#4093)
- Issue where a user could spawn runtime created `NetworkObject` that has a GlobalObjectIdHash of zero. These are not valid instances and will no longer be allowed to spawn. (#4093)


### Security

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,4 @@ Reading and writing a value provides the minimal amount of `NetworkVariable` fun
Here is a full implementation of a custom type with the methods needed for `UserNetworkVariableSerialization`

[!code-cs[](../../Tests/Runtime/DocumentationCodeSamples/NetworkVariable/NetworkVariableSerialization.cs#HealthExample)]
[!code-cs[](../../Tests/Runtime/DocumentationCodeSamples/NetworkVariable/CustomSerializationDocsTests.cs#HealthExample)]
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ This allows the four bytes of the embedded struct to be rapidly serialized as a

`FastBufferWriter` and `FastBufferReader` are replacements for the old `NetworkWriter` and `NetworkReader`. For those familiar with the old classes, there are some key differences:

- `FastBufferWriter` uses `WriteValue()` as the name of the method for all types *except* [`INetworkSerializable`](serialization/inetworkserializable) types, which are serialized through `WriteNetworkSerializable()`
- `FastBufferWriter` uses `WriteValue()` as the name of the method for all types *except* [`INetworkSerializable`](serialization/inetworkserializable.md) types, which are serialized through `WriteNetworkSerializable()`
- `FastBufferReader` similarly uses `ReadValue()` for all types except INetworkSerializable (which is read through `ReadNetworkSerializable`), with the output changed from a return value to an `out` parameter to allow for method overload resolution to pick the correct value.
- `FastBufferWriter` and `FastBufferReader` outsource packed writes and reads to `BytePacker` and `ByteUnpacker`, respectively.
- `FastBufferWriter` and `FastBufferReader` are **structs**, not **classes**. This means they can be constructed and destructed without GC allocations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ void AbcdServerRpc(int somenumber) { /* ... */ }
void XyzwServerRpc(int somenumber, ServerRpcParams serverRpcParams = default) { /* ... */ }
```

[ServerRpcParams Documentation](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.ServerRpcParams.html)
[ServerRpcParams Documentation](xref:Unity.Netcode.ServerRpcParams)

## ClientRpc Params

Expand All @@ -94,7 +94,7 @@ void AbcdClientRpc(int framekey) { /* ... */ }
void XyzwClientRpc(int framekey, ClientRpcParams clientRpcParams = default) { /* ... */ }
```

[ClientRpcParams Documentation](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.ClientRpcParams.html)
[ClientRpcParams Documentation](xref:Unity.Netcode.ClientRpcParams)

> [!NOTE]
> `ClientRpcSendParams`'s `TargetClientIds` property is a `ulong[]` which means everytime you try to specify a subset of target clients or even a single client target, you will have to allocate a `new ulong[]`. This pattern can quickly lead into lots of heap allocations and pressure GC which would cause GC spikes at runtime. We suggest developers cache their `ulong[]` variables or use an array pool to cycle `ulong[]` instances so that it would cause less heap allocations.
Original file line number Diff line number Diff line change
Expand Up @@ -328,4 +328,4 @@ void Update()
## Additional resources

* [RPC parameters](rpc-params.md)
* [Customizing serialization](../custom-serialization.md#remote-procedure-call-rpc)
* [Customizing serialization](../custom-serialization.md#remote-procedure-call-rpcs)
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

The network prefab handler system provides advanced control over how network prefabs are instantiated and destroyed during runtime. You can use it to override the default Netcode for GameObjects [object spawning](../basics/object-spawning.md) behavior by implementing custom prefab handlers.

The network prefab handler system is accessible from the [NetworkManager](../components/networkmanager.md) as `NetworkManager.PrefabHandler`.
The network prefab handler system is accessible from the [NetworkManager](../components/core/networkmanager.md) as `NetworkManager.PrefabHandler`.

## When to use a prefab handler

Expand All @@ -13,14 +13,14 @@ For an overview of the default object spawning behavior, refer to the [object sp
- **Custom initialization**: Setting up objects with game client specific data or configurations.
- **Conditional spawning**: Initializing different prefab variants based on runtime conditions.

The prefab handler system addresses these needs through an interface-based architecture. The system relies on two key methods: `Instantiate` and `Destroy`. `Instantiate` is called on non-authority clients when an [authority](../terms-concepts/authority.md) spawns a new [NetworkObject](../basics/networkobject.md) that has a registered network prefab handler. `Destroy` is called on all game clients whenever a registered [NetworkObject](../basics/networkobject.md) is destroyed.
The prefab handler system addresses these needs through an interface-based architecture. The system relies on two key methods: `Instantiate` and `Destroy`. `Instantiate` is called on non-authority clients when an [authority](../terms-concepts/authority.md) spawns a new [NetworkObject](../components/core/networkobject.md) that has a registered network prefab handler. `Destroy` is called on all game clients whenever a registered [NetworkObject](../components/core/networkobject.md) is destroyed.

## Create a prefab handler

Prefab handlers are classes that implement one of the Netcode for GameObjects prefab handler descriptions. There are currently two such descriptions:

- [**INetworkPrefabInstanceHandler**](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.INetworkPrefabInstanceHandler.html): This is the simplest interface for custom prefab handlers.
- [**NetworkPrefabInstanceHandlerWithData**](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkPrefabInstanceHandlerWithData.html): This specialized handler receives custom data from the authority during spawning, enabling dynamic prefab customization.
- [**INetworkPrefabInstanceHandler**](xref:Unity.Netcode.INetworkPrefabInstanceHandler): This is the simplest interface for custom prefab handlers.
- [**NetworkPrefabInstanceHandlerWithData**](xref:Unity.Netcode.NetworkPrefabInstanceHandlerWithData): This specialized handler receives custom data from the authority during spawning, enabling dynamic prefab customization.

When using a prefab handler, Netcode for GameObjects uses the `Instantiate` and `Destroy` methods instead of default spawn handlers for the NetworkObject during spawning and despawning. The authority instance uses the traditional spawning approach where it will, via user script, instantiate and spawn a network prefab (even for those registered with a prefab handler). However, all non-authority clients will automatically use the instantiate method defined by the `INetworkPrefabInstanceHandler` implementation if the network prefab spawned has a registered `INetworkPrefabInstanceHandler` implementation with the `NetworkPrefabHandler` (`NetworkManager.PrefabHandler`).

Expand Down Expand Up @@ -55,7 +55,7 @@ public abstract class NetworkPrefabInstanceHandlerWithData<T> : INetworkPrefabIn

## Register a prefab handler

Once you've [created a prefab handler](#create-a-prefab-handler), whether by implementing or deriving, you need to register any new instance of that handler with the network prefab handler system using `NetworkManager.PrefabHandler.AddHandler`. Prefab handlers are registered against a NetworkObject's [GlobalObjectIdHash](../basics/networkobject.md#using-networkobjects).
Once you've [created a prefab handler](#create-a-prefab-handler), whether by implementing or deriving, you need to register any new instance of that handler with the network prefab handler system using `NetworkManager.PrefabHandler.AddHandler`. Prefab handlers are registered against a NetworkObject's [GlobalObjectIdHash](../components/core/networkobject.md#using-networkobjects).

```csharp
public class GameManager : NetworkBehaviour
Expand All @@ -70,7 +70,7 @@ public class GameManager : NetworkBehaviour
}
```

To un-register a prefab handler, you can [invoke the `NetworkManager.PrefabHandler.RemoveHandler` method](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkPrefabHandler.html#Unity_Netcode_NetworkPrefabHandler_RemoveHandler_System_UInt32_). There are several override versions of this method.
To un-register a prefab handler, you can [invoke the `NetworkManager.PrefabHandler.RemoveHandler` method](xref:Unity.Netcode.NetworkPrefabHandler.RemoveHandler*). There are several override versions of this method.

## Object spawning with prefab handlers

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ The following diagrams provide insight into the Network Update Loop process and

<div class="imgwhite">

![Injecting NetworkUpdateLoop Systems Into PlayerLoop](../images/injecting-networkupdatesloop.svg)
![Injecting NetworkUpdateLoop Systems Into PlayerLoop](../../images/injecting-networkupdatesloop.svg)

</div>

## NetworkUpdateLoop Running INetworkUpdateSystem Updates

<div class="imgwhite">

![NetworkUpdateLoop Running INetworkUpdateSystem Updates](../images/runninginetworkupdatesystemupdates.svg)
![NetworkUpdateLoop Running INetworkUpdateSystem Updates](../../images/runninginetworkupdatesystemupdates.svg)

</div>
Loading