diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index d54be2e86e..ad9486f7b4 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -10,4 +10,4 @@ AssemblyInfo.cs @NoelStephensUnity @EmandM @Unity-Technologies/netcode-qa
.github/ @NoelStephensUnity @EmandM @Unity-Technologies/netcode-qa
.yamato/ @NoelStephensUnity @EmandM @Unity-Technologies/netcode-qa
com.unity.netcode.gameobjects/Documentation*/ @jabbacakes
-com.unity.netcode.gameobjects/Runtime/Transports/UTP/ @Unity-Technologies/multiplayer-workflows
+com.unity.netcode.gameobjects/Runtime/Transports/UTP/ @simon-lemay-unity
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 1af44ed7da..5872f6cbbd 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -56,6 +56,12 @@ _Does the change require QA team to:_
If any boxes above are checked the QA team will be automatically added as a PR reviewer.
+## Up-port
+[//]: # (
+This section is REQUIRED and should link to the PR that targets develop-3.0.0 branch. Assuming that the PR lands agains default develop-2.0.0 branch
+If this is not needed, for example feature specific to NGOv2.X, then just mention this fact.
+)
+
## Backports
[//]: # (
This section is REQUIRED and should link to the PR that targets other NGO version which is either develop or develop-2.0.0 branch
diff --git a/.github/renovate.json5 b/.github/renovate.json5
index 1143236874..679cec5d47 100644
--- a/.github/renovate.json5
+++ b/.github/renovate.json5
@@ -1,5 +1,5 @@
{
- "baseBranches": ["develop", "develop-2.0.0"],
+ "baseBranches": ["develop-2.0.0"],
"dependencyDashboard": true,
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
@@ -27,10 +27,12 @@
"unity-upm-package"
],
"enabled": "true",
- "schedule": [
- "every weekend"
- ],
+ "schedule": ["every weekend"],
"rollbackPrs": false,
+ },
+ {
+ "groupName": "CI deps updates",
+ "matchPackagePatterns": ["^RecipeEngine", "actions/checkout", "package-ci/ubuntu-22.04"]
}
],
}
diff --git a/.github/workflows/autoupdate.yaml b/.github/workflows/autoupdate.yaml
index 764b52b373..298c87bc37 100644
--- a/.github/workflows/autoupdate.yaml
+++ b/.github/workflows/autoupdate.yaml
@@ -4,6 +4,7 @@ on:
branches:
- develop
- develop-2.0.0
+ - develop-3.x.x
jobs:
autoupdate:
name: auto-update
diff --git a/.github/workflows/conventional-pr.yml b/.github/workflows/conventional-pr.yml
index 30274254e2..e5176d4912 100644
--- a/.github/workflows/conventional-pr.yml
+++ b/.github/workflows/conventional-pr.yml
@@ -6,6 +6,7 @@ on:
branches:
- develop
- develop-2.0.0
+ - develop-3.x.x
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
diff --git a/.github/workflows/pr-description-validation.yml b/.github/workflows/pr-description-validation.yml
index 9d2b4ccc75..b117ff21ef 100644
--- a/.github/workflows/pr-description-validation.yml
+++ b/.github/workflows/pr-description-validation.yml
@@ -14,6 +14,7 @@ on:
branches:
- develop
- develop-2.0.0
+ - develop-3.x.x
- release/*
jobs:
@@ -21,7 +22,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@v6
+ uses: actions/checkout@v7
- name: Check PR description
uses: actions/github-script@v9
@@ -30,17 +31,17 @@ jobs:
const pr = context.payload.pull_request;
const body = pr.body || '';
- // List of users to skip description validation
+ // List of user patterns to skip description validation
// This should be automations where we don't care that much about the description format
- const skipUsersPrefixes = [
- 'unity-renovate',
- 'svc-'
+ const skipUserPatterns = [
+ /^unity-renovate/,
+ /svc/
];
-
- // If PR author is in the skip list, exit early
+
+ // If PR author matches the skip list, exit early
const author = pr.user.login;
console.log(`PR author: ${author}`);
- if (skipUsersPrefixes.some(prefix => author.startsWith(prefix))) {
+ if (skipUserPatterns.some(pattern => pattern.test(author))) {
console.log(`Skipping PR description check for user: ${author}`);
return;
}
@@ -51,6 +52,10 @@ jobs:
header: '## Backports',
description: 'PR description must include a "## Backports" section. Please add this section and provide information about this PR backport to develop or develop-2.0.0 branch respectively or explain why backport is not needed.'
},
+ {
+ header: '## Up-port',
+ description: 'PR description must include a "## Up-port" section. Please add this section and provide information about this PR up-port to develop-3.0.0 branch or explain why up-port is not needed.'
+ },
{
header: '## Testing & QA',
description: 'PR description must include a "## Testing & QA" section. Please add this section and provide information about the testing performed for this PR. It can range from adding unit tests to full samples and is needed from QA side to analyze PRs while Playtesting for the release.'
diff --git a/.github/workflows/pr-supervisor.yaml b/.github/workflows/pr-supervisor.yaml
index ba8da21e93..b1660c2522 100644
--- a/.github/workflows/pr-supervisor.yaml
+++ b/.github/workflows/pr-supervisor.yaml
@@ -2,8 +2,8 @@
# We are using https://cli.github.com/manual/gh_pr_checks
# The aim is to ensure that conditionally triggered Yamato jobs are completed successfully before allowing merges
-# This job will be required in branch protection rules for develop, develop-2.0.0, and release/* branches. It's only goal will be to ensure that Yamato jobs are completed successfully before allowing Pr to merge.
-# Note that conditional jobs will have 30s to show which is always the cas since they are showing up as soon as in distribution stage.
+# This job will be required in branch protection rules for develop and release/* branches. It's only goal will be to ensure that Yamato jobs are completed successfully before allowing Pr to merge.
+# Note that conditional jobs will have 30s to show which is always the case since they are showing up as soon as in distribution stage.
name: Yamato PR Supervisor
@@ -13,8 +13,9 @@ on:
branches:
- develop
- develop-2.0.0
+ - develop-3.x.x
- release/*
-
+
concurrency:
group: pr-${{ github.event.pull_request.number }}
cancel-in-progress: true
@@ -23,13 +24,20 @@ jobs:
yamato-supervisor:
runs-on: ubuntu-latest
timeout-minutes: 720
+ permissions:
+ actions: read
+ checks: read
+ statuses: read
+ pull-requests: read
+ contents: read
steps:
- name: Checkout repository
- uses: actions/checkout@v6
-
+ uses: actions/checkout@v4
+
+
- name: Wait and Verify Yamato Job Status
env:
- GH_TOKEN: ${{ secrets.GH_TOKEN }}
+ GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
set -e
@@ -42,18 +50,25 @@ jobs:
for ((i=1;i<=MAX_ATTEMPTS;i++)); do
echo "Polling PR checks (attempt $i/$MAX_ATTEMPTS)..."
- # We want to watch for pending checks beside this check
- checks=$(gh pr checks $PR_NUMBER --json name,state --jq '[ .[] | select(.name != "yamato-supervisor") ]')
-
+ # gh pr checks exits non-zero while checks are pending (8) or failing (1); we evaluate state ourselves, so don't let that abort the loop.
+ checks=$(gh pr checks $PR_NUMBER --json name,state --jq '[ .[] | select(.name != "yamato-supervisor") ]') || true
+
+ if [[ -z "$checks" ]]; then
+ echo "No non-supervisor checks reported yet; waiting..."
+ sleep $INTERVAL
+ continue
+ fi
+
pending=$(echo "$checks" | jq '[.[] | select(.state == "PENDING")] | length')
skipping=$(echo "$checks" | jq '[.[] | select(.state == "SKIPPED")] | length')
passed=$(echo "$checks" | jq '[.[] | select(.state == "SUCCESS")] | length')
failed=$(echo "$checks" | jq '[.[] | select(.state == "FAILURE")] | length')
- echo "Pending checks: $pending, Skipping checks: $skipping", Passed checks: $passed, Failed checks: $failed
+ echo "Pending checks: $pending; Skipping checks: $skipping, Passed checks: $passed, Failed checks: $failed"
if [[ "$failed" -gt 0 ]]; then
echo "A check has failed! Failing fast."
+ echo "If you rerun the job and everything is green then just rerun this job as well."
exit 1
fi
diff --git a/.gitignore b/.gitignore
index 1d3ee28bec..b38b538937 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,5 @@ utr.bat
Tools/CI/bin
Tools/CI/obj
+# Do not include the packages-lock file
+packages-lock.json
diff --git a/.pr_agent.toml b/.pr_agent.toml
index 49734d8c44..71d8783c0c 100644
--- a/.pr_agent.toml
+++ b/.pr_agent.toml
@@ -1,2 +1,9 @@
+# This is the configuration for the u-pr bot
+# https://github.cds.internal.unity3d.com/unity/u-pr
+# For configuration of this file:
+# https://developer.portal.internal.unity.com/catalog/default/component/u-pr/docs/configuration/automatic_runs/
+
[github_app]
-pr_commands = []
+handle_pr_actions = ['opened', 'ready_for_review'] # PR events that auto-run pr_commands
+pr_commands = ["/harness-review"] # what runs on those events
+reviewer_commands = ["/harness-review"] # what runs when @u-pr is added as reviewer
diff --git a/.yamato/_run-all.yml b/.yamato/_run-all.yml
index 24daf40665..fad7923322 100644
--- a/.yamato/_run-all.yml
+++ b/.yamato/_run-all.yml
@@ -16,7 +16,7 @@ run_quick_checks:
name: Run Quick Initial Checks
dependencies:
# Ensure the code is running to our current standards
- - .yamato/project-standards.yml#standards_ubuntu_testproject_{{ validation_editors.default }}
+ - .yamato/project-standards.yml#standards_ubuntu_testproject_{{ validation_editors.standards }}
# This is needed for most of the jobs to execute tests + it runs xray PVP checks (all fast checks)
- .yamato/package-pack.yml#package_pack_-_ngo_win
@@ -27,33 +27,25 @@ run_all_package_tests:
dependencies:
{% for platform in test_platforms.desktop -%}
{% for editor in validation_editors.all -%}
- - .yamato/package-tests.yml#package_test_-_ngo_{{ editor }}_{{ platform.name }}
+ - .yamato/package-tests.yml#package_test_-_ngo_{{ platform.name }}_{{ editor }}
{% endfor -%}
{% endfor -%}
-# Runs all package tests on trunk editor
-run_all_package_tests_trunk:
- name: Run All Package Tests [Trunk only]
+# Runs all package tests on latest supported editor
+run_all_package_tests_{{ validation_editors.latest }}:
+ name: Run All Package Tests [{{ validation_editors.latest }} only]
dependencies:
{% for platform in test_platforms.desktop -%}
- - .yamato/package-tests.yml#package_test_-_ngo_trunk_{{ platform.name }}
+ - .yamato/package-tests.yml#package_test_-_ngo_{{ platform.name }}_{{ validation_editors.latest }}
{% endfor -%}
-# Runs all package tests on pinned trunk editor (This is used for PR testing as we want to avoid blocking failures)
-run_all_package_tests_pinnedTrunk:
- name: Run All Package Tests [Pinned Trunk only]
+# Runs all package tests on minimal supported editor
+run_all_package_tests_{{ validation_editors.minimal }}:
+ name: Run All Package Tests [{{ validation_editors.minimal }}]
dependencies:
{% for platform in test_platforms.desktop -%}
- - .yamato/package-tests.yml#package_test_-_ngo_{{ pinnedTrunk }}_{{ platform.name }}
-{% endfor -%}
-
-# Runs all package tests on mimimum supported editor (6000.0 in case of NGOv2.X)
-run_all_package_tests_6000:
- name: Run All Package Tests [6000.0]
- dependencies:
-{% for platform in test_platforms.desktop -%}
- - .yamato/package-tests.yml#package_test_-_ngo_6000.0_{{ platform.name }}
+ - .yamato/package-tests.yml#package_test_-_ngo_{{ platform.name }}_{{ validation_editors.minimal }}
{% endfor -%}
@@ -72,38 +64,26 @@ run_all_project_tests:
{% endfor -%}
-# Runs all projects tests on trunk editor
-run_all_project_tests_trunk:
- name: Run All Project Tests [Trunk only]
- dependencies:
-{% for project in projects.all -%}
-{% if project.has_tests == "true" -%}
-{% for platform in test_platforms.desktop -%}
- - .yamato/project-tests.yml#test_{{ project.name }}_{{ platform.name }}_trunk
-{% endfor -%}
-{% endif -%}
-{% endfor -%}
-
-# Runs all projects tests on pinned trunk editor (This is used for PR testing as we want to avoid blocking failures)
-run_all_project_tests_pinnedTrunk:
- name: Run All Project Tests [Pinned Trunk only]
+# Runs all projects tests on latest supported editor
+run_all_project_tests_{{ validation_editors.latest }}:
+ name: Run All Project Tests [{{ validation_editors.latest }} only]
dependencies:
{% for project in projects.all -%}
{% if project.has_tests == "true" -%}
{% for platform in test_platforms.desktop -%}
- - .yamato/project-tests.yml#test_{{ project.name }}_{{ platform.name }}_{{ pinnedTrunk }}
+ - .yamato/project-tests.yml#test_{{ project.name }}_{{ platform.name }}_{{ validation_editors.latest }}
{% endfor -%}
{% endif -%}
{% endfor -%}
-# Runs all projects tests on mimimum supported editor (6000.0 in case of NGOv2.X)
-run_all_project_tests_6000:
- name: Run All Project Tests [6000.0]
+# Runs all projects tests on minimal supported editor
+run_all_project_tests_{{ validation_editors.minimal }}:
+ name: Run All Project Tests [{{ validation_editors.minimal }}]
dependencies:
{% for project in projects.all -%}
{% if project.has_tests == "true" -%}
{% for platform in test_platforms.desktop -%}
- - .yamato/project-tests.yml#test_{{ project.name }}_{{ platform.name }}_6000.0
+ - .yamato/project-tests.yml#test_{{ project.name }}_{{ platform.name }}_{{ validation_editors.minimal }}
{% endfor -%}
{% endif -%}
{% endfor -%}
@@ -115,7 +95,7 @@ run_all_projects_standards:
dependencies:
{% for platform in test_platforms.default -%}
{% for project in projects.all -%}
-{% for editor in validation_editors.default -%}
+{% for editor in validation_editors.standards -%}
- .yamato/project-standards.yml#standards_{{ platform.name }}_{{ project.name }}_{{ editor }}
{% endfor -%}
{% endfor -%}
@@ -135,34 +115,24 @@ run_all_webgl_builds:
{% endfor -%}
-# Runs all WebGL builds on trunk editor
-run_all_webgl_builds_trunk:
- name: Run All WebGl Build [Trunk only]
+# Runs all WebGL builds on latest supported editor
+run_all_webgl_builds_{{ validation_editors.latest }}:
+ name: Run All WebGl Build [{{ validation_editors.latest }} only]
dependencies:
{% for project in projects.default -%}
{% for platform in test_platforms.desktop -%}
- - .yamato/webgl-build.yml#webgl_build_{{ project.name }}_{{ platform.name }}_trunk
+ - .yamato/webgl-build.yml#webgl_build_{{ project.name }}_{{ platform.name }}_{{ validation_editors.latest }}
{% endfor -%}
{% endfor -%}
-# Runs all WebGL builds on pinned trunk editor (This is used for PR testing as we want to avoid blocking failures)
-run_all_webgl_builds_pinnedTrunk:
- name: Run All WebGl Build [Pinned Trunk only]
+# Runs all WebGL builds on minimal supported editor
+run_all_webgl_builds_{{ validation_editors.minimal }}:
+ name: Run All WebGl Build [{{ validation_editors.minimal }}]
dependencies:
{% for project in projects.default -%}
{% for platform in test_platforms.desktop -%}
- - .yamato/webgl-build.yml#webgl_build_{{ project.name }}_{{ platform.name }}_{{ pinnedTrunk }}
-{% endfor -%}
-{% endfor -%}
-
-# Runs all WebGL builds on 6000.0 editor
-run_all_webgl_builds_6000:
- name: Run All WebGl Build [6000.0]
- dependencies:
-{% for project in projects.default -%}
-{% for platform in test_platforms.desktop -%}
- - .yamato/webgl-build.yml#webgl_build_{{ project.name }}_{{ platform.name }}_6000.0
+ - .yamato/webgl-build.yml#webgl_build_{{ project.name }}_{{ platform.name }}_{{ validation_editors.minimal }}
{% endfor -%}
{% endfor -%}
@@ -182,38 +152,26 @@ run_all_project_tests_desktop_standalone:
{% endfor -%}
-# Runs all Desktop tests on trunk editor
-run_all_project_tests_desktop_standalone_trunk:
- name: Run All Standalone Tests - Desktop [Trunk only]
+# Runs all Desktop tests on latest supported editor
+run_all_project_tests_desktop_standalone_{{ validation_editors.latest }}:
+ name: Run All Standalone Tests - Desktop [{{ validation_editors.latest }} only]
dependencies:
{% for project in projects.default -%}
{% for platform in test_platforms.desktop -%}
{% for backend in scripting_backends -%}
- - .yamato/desktop-standalone-tests.yml#desktop_standalone_test_{{ project.name }}_{{ platform.name }}_{{ backend }}_trunk
+ - .yamato/desktop-standalone-tests.yml#desktop_standalone_test_{{ project.name }}_{{ platform.name }}_{{ backend }}_{{ validation_editors.latest }}
{% endfor -%}
{% endfor -%}
{% endfor -%}
-# Runs all Desktop tests on pinned trunk editor (This is used for PR testing as we want to avoid blocking failures)
-run_all_project_tests_desktop_standalone_pinnedTrunk:
- name: Run All Standalone Tests - Desktop [Pinned Trunk only]
+# Runs all Desktop tests on minimal supported editor
+run_all_project_tests_desktop_standalone_{{ validation_editors.minimal }}:
+ name: Run All Standalone Tests - Desktop [{{ validation_editors.minimal }}]
dependencies:
{% for project in projects.default -%}
{% for platform in test_platforms.desktop -%}
{% for backend in scripting_backends -%}
- - .yamato/desktop-standalone-tests.yml#desktop_standalone_test_{{ project.name }}_{{ platform.name }}_{{ backend }}_{{ pinnedTrunk }}
-{% endfor -%}
-{% endfor -%}
-{% endfor -%}
-
-# Runs all Desktop tests on mimimum supported editor (6000.0 in case of NGOv2.X)
-run_all_project_tests_desktop_standalone_6000:
- name: Run All Standalone Tests - Desktop [6000.0]
- dependencies:
-{% for project in projects.default -%}
-{% for platform in test_platforms.desktop -%}
-{% for backend in scripting_backends -%}
- - .yamato/desktop-standalone-tests.yml#desktop_standalone_test_{{ project.name }}_{{ platform.name }}_{{ backend }}_6000.0
+ - .yamato/desktop-standalone-tests.yml#desktop_standalone_test_{{ project.name }}_{{ platform.name }}_{{ backend }}_{{ validation_editors.minimal }}
{% endfor -%}
{% endfor -%}
{% endfor -%}
@@ -231,33 +189,24 @@ run_all_project_tests_mobile_standalone:
{% endfor -%}
-# Runs all Mobile tests on trunk editor
-run_all_project_tests_mobile_standalone_trunk:
- name: Run All Standalone Tests - Mobile [Trunk only]
+# Runs all Mobile tests on latest supported editor
+run_all_project_tests_mobile_standalone_{{ validation_editors.latest }}:
+ name: Run All Standalone Tests - Mobile [{{ validation_editors.latest }} only]
dependencies:
{% for project in projects.default -%}
{% for platform in test_platforms.mobile_test -%}
- - .yamato/mobile-standalone-test.yml#mobile_standalone_test_{{ project.name }}_{{ platform.name }}_trunk
+ - .yamato/mobile-standalone-test.yml#mobile_standalone_test_{{ project.name }}_{{ platform.name }}_{{ validation_editors.latest }}
{% endfor -%}
{% endfor -%}
-# Runs all Mobile tests on pinned trunk editor (This is used for PR testing as we want to avoid blocking failures)
-run_all_project_tests_mobile_standalone_pinnedTrunk:
- name: Run All Standalone Tests - Mobile [Pinned Trunk only]
- dependencies:
-{% for project in projects.default -%}
-{% for platform in test_platforms.mobile_test -%}
- - .yamato/mobile-standalone-test.yml#mobile_standalone_test_{{ project.name }}_{{ platform.name }}_{{ pinnedTrunk }}
-{% endfor -%}
-{% endfor -%}
-# Runs all Mobile tests on mimimum supported editor (6000.0 in case of NGOv2.X)
-run_all_project_tests_mobile_standalone_6000:
- name: Run All Standalone Tests - Mobile [6000.0]
+# Runs all Mobile tests on minimal supported editor
+run_all_project_tests_mobile_standalone_{{ validation_editors.minimal }}:
+ name: Run All Standalone Tests - Mobile [{{ validation_editors.minimal }}]
dependencies:
{% for project in projects.default -%}
{% for platform in test_platforms.mobile_test -%}
- - .yamato/mobile-standalone-test.yml#mobile_standalone_test_{{ project.name }}_{{ platform.name }}_6000.0
+ - .yamato/mobile-standalone-test.yml#mobile_standalone_test_{{ project.name }}_{{ platform.name }}_{{ validation_editors.minimal }}
{% endfor -%}
{% endfor -%}
@@ -275,33 +224,23 @@ run_all_project_tests_console_standalone:
{% endfor -%}
-# Runs all Console tests on trunk editor
-run_all_project_tests_console_standalone_trunk:
- name: Run All Standalone Tests - Console [Trunk only]
- dependencies:
-{% for project in projects.default -%}
-{% for platform in test_platforms.console_test -%}
- - .yamato/console-standalone-test.yml#console_standalone_test_{{ project.name }}_{{ platform.name }}_trunk
-{% endfor -%}
-{% endfor -%}
-
-# Runs all Console tests on pinned trunk editor (This is used for PR testing as we want to avoid blocking failures)
-run_all_project_tests_console_standalone_pinnedTrunk:
- name: Run All Standalone Tests - Console [Pinned Trunk only]
+# Runs all Console tests on latest supported editor
+run_all_project_tests_console_standalone_{{ validation_editors.latest }}:
+ name: Run All Standalone Tests - Console [{{ validation_editors.latest }} only]
dependencies:
{% for project in projects.default -%}
{% for platform in test_platforms.console_test -%}
- - .yamato/console-standalone-test.yml#console_standalone_test_{{ project.name }}_{{ platform.name }}_{{ pinnedTrunk }}
+ - .yamato/console-standalone-test.yml#console_standalone_test_{{ project.name }}_{{ platform.name }}_{{ validation_editors.latest }}
{% endfor -%}
{% endfor -%}
-# Runs all Console tests on mimimum supported editor (6000.0 in case of NGOv2.X)
-run_all_project_tests_console_standalone_6000:
- name: Run All Standalone Tests - Console [6000.0]
+# Runs all Console tests on minimal supported editor
+run_all_project_tests_console_standalone_{{ validation_editors.minimal }}:
+ name: Run All Standalone Tests - Console [{{ validation_editors.minimal }}]
dependencies:
{% for project in projects.default -%}
{% for platform in test_platforms.console_test -%}
- - .yamato/console-standalone-test.yml#console_standalone_test_{{ project.name }}_{{ platform.name }}_6000.0
+ - .yamato/console-standalone-test.yml#console_standalone_test_{{ project.name }}_{{ platform.name }}_{{ validation_editors.minimal }}
{% endfor -%}
{% endfor -%}
@@ -320,38 +259,26 @@ run_all_project_tests_cmb_service:
{% endfor -%}
{% endfor -%}
-# Runs all CMB service tests on trunk editor
-run_all_project_tests_cmb_service_trunk:
- name: Run All CMB Service Tests [Trunk only]
- dependencies:
-{% for project in projects.default -%}
-{% for platform in test_platforms.default -%}
-{% for backend in scripting_backends -%}
- - .yamato/cmb-service-standalone-tests.yml#cmb_service_standalone_test_{{ project.name }}_{{ platform.name }}_{{ backend }}_trunk
-{% endfor -%}
-{% endfor -%}
-{% endfor -%}
-
-# Runs all CMB service tests on pinned trunk editor (This is used for PR testing as we want to avoid blocking failures)
-run_all_project_tests_cmb_service_pinnedTrunk:
- name: Run All CMB Service Tests [Pinned Trunk only]
+# Runs all CMB service tests on latest supported editor
+run_all_project_tests_cmb_service_{{ validation_editors.latest }}:
+ name: Run All CMB Service Tests [{{ validation_editors.latest }} only]
dependencies:
{% for project in projects.default -%}
{% for platform in test_platforms.default -%}
{% for backend in scripting_backends -%}
- - .yamato/cmb-service-standalone-tests.yml#cmb_service_standalone_test_{{ project.name }}_{{ platform.name }}_{{ backend }}_{{ pinnedTrunk }}
+ - .yamato/cmb-service-standalone-tests.yml#cmb_service_standalone_test_{{ project.name }}_{{ platform.name }}_{{ backend }}_{{ validation_editors.latest }}
{% endfor -%}
{% endfor -%}
{% endfor -%}
-# Runs all CMB service tests on mimimum supported editor (6000.0 in case of NGOv2.X)
-run_all_project_tests_cmb_service_6000:
- name: Run All CMB Service Tests [6000.0]
+# Runs all CMB service tests on minimal supported editor
+run_all_project_tests_cmb_service_{{ validation_editors.minimal }}:
+ name: Run All CMB Service Tests [{{ validation_editors.minimal }}]
dependencies:
{% for project in projects.default -%}
{% for platform in test_platforms.default -%}
{% for backend in scripting_backends -%}
- - .yamato/cmb-service-standalone-tests.yml#cmb_service_standalone_test_{{ project.name }}_{{ platform.name }}_{{ backend }}_6000.0
+ - .yamato/cmb-service-standalone-tests.yml#cmb_service_standalone_test_{{ project.name }}_{{ platform.name }}_{{ backend }}_{{ validation_editors.minimal }}
{% endfor -%}
{% endfor -%}
{% endfor -%}
diff --git a/.yamato/_triggers.yml b/.yamato/_triggers.yml
index 8cdf8445ce..380d07b997 100644
--- a/.yamato/_triggers.yml
+++ b/.yamato/_triggers.yml
@@ -17,7 +17,7 @@
# 1) Minimal PR checks that run on all PRs (even if only docs are changed)
# 2) More extensive pr_code_changes_checks that run if code is changed. This test validates Standards, Package tests, Project tests and Desktop standalone tests to ensure that main platforms are covered
# By default pr_minimal_required_checks it's triggered if
- # 1) PR targets develop, develop-2.0.0 or release branches
+ # 1) PR targets develop, develop-2.0., develop-3.x.x or release branches
# 2) PR is not a draft
# Then pr_code_changes_checks it's triggered if the same conditions apply plus:
# 1) PR changes code in com.unity.netcode.gameobjects package (Editor, Runtime or Tests folders) or in testproject folder or package.json file
@@ -51,13 +51,14 @@
pr_minimal_required_checks:
name: Minimal PR checks
dependencies:
- - .yamato/project-standards.yml#standards_ubuntu_testproject_{{ validation_editors.default }}
+ - .yamato/project-standards.yml#standards_ubuntu_testproject_{{ validation_editors.standards }}
- .yamato/package-pack.yml#package_pack_-_ngo_win
triggers:
expression: |-
(pull_request.comment eq "ngo" OR
(pull_request.target eq "develop" OR
pull_request.target eq "develop-2.0.0" OR
+ pull_request.target eq "develop-3.x.x" OR
pull_request.target match "release/*")) AND
NOT pull_request.draft
cancel_old_ci: true
@@ -75,25 +76,28 @@ pr_code_changes_checks:
# 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 package EditMode and Playmode package tests on trunk and an older supported editor (6000.0)
- - .yamato/package-tests.yml#package_test_-_ngo_{{ pinnedTrunk }}_mac
- - .yamato/package-tests.yml#package_test_-_ngo_6000.0_win
+ # Run package EditMode and Playmode package tests
+ - .yamato/package-tests.yml#package_test_-_ngo_mac_{{ validation_editors.default }}
+ - .yamato/package-tests.yml#package_test_-_ngo_win_{{ validation_editors.minimal }}
- # Run testproject EditMode and Playmode project tests on trunk and an older supported editor (6000.0)
- - .yamato/project-tests.yml#test_testproject_win_{{ pinnedTrunk }}
- - .yamato/project-tests.yml#test_testproject_mac_6000.0
+ # Run testproject EditMode and Playmode project tests
+ - .yamato/project-tests.yml#test_testproject_win_{{ validation_editors.default }}
+ - .yamato/project-tests.yml#test_testproject_mac_{{ validation_editors.minimal }}
# Run standalone test. We run it only on Ubuntu since it's the fastest machine, and it was noted that for example distribution on macOS is taking 40m since we switched to Apple Silicon
# Coverage on other standalone machines is present in Nightly job so it's enough to not run all of them for PRs
# desktop_standalone_test and cmb_service_standalone_test are both reusing desktop_standalone_build dependency so we run those in the same configuration on PRs to reduce waiting time.
# 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 }}
+ - .yamato/desktop-standalone-tests.yml#desktop_standalone_test_testproject_ubuntu_il2cpp_{{ validation_editors.default }}
+ - .yamato/cmb-service-standalone-tests.yml#cmb_service_standalone_test_testproject_ubuntu_il2cpp_{{ validation_editors.default }}
+ # Run code coverage test
+ - .yamato/code-coverage.yml#code_coverage_project_test_testproject_ubuntu_{{ validation_editors.default }}
triggers:
expression: |-
(pull_request.comment eq "ngo" OR
(pull_request.target eq "develop" OR
pull_request.target eq "develop-2.0.0" OR
+ pull_request.target eq "develop-3.x.x" OR
pull_request.target match "release/*")) AND
NOT pull_request.draft AND
pull_request.changes.any match [
@@ -116,11 +120,10 @@ pr_code_changes_checks:
-# Run all tests on trunk on nightly basis.
+# Run all tests on minimal and latest editors on nightly basis (rest of editors runs weekly)
# Same subset as pull_request_trigger with addition of mobile/desktop/console tests and webgl builds
-# Those tests are all running on trunk editor (since it's daily and running all of them would add a lot of overhead)
develop_nightly:
- name: "\U0001F319 [Nightly] Run All Tests [Trunk and 6000]"
+ name: "\U0001F319 [Nightly] Run All Tests [Latest Editor and Minimal Editor]"
triggers:
recurring:
- branch: develop-2.0.0
@@ -128,41 +131,43 @@ develop_nightly:
rerun: always
dependencies:
# Run project standards to verify package/default project
- - .yamato/project-standards.yml#standards_ubuntu_testproject_{{ validation_editors.default }}
+ - .yamato/project-standards.yml#standards_ubuntu_testproject_{{ validation_editors.standards }}
# Run APV jobs to make sure the change won't break any dependants
- .yamato/wrench/preview-a-p-v.yml#all_preview_apv_jobs
- # Run package EditMode and Playmode tests on desktop platforms on trunk and 6000.0
- - .yamato/_run-all.yml#run_all_package_tests_trunk
- - .yamato/_run-all.yml#run_all_package_tests_6000
- # Run project EditMode and PLaymode tests on desktop platforms on trunk and 6000.0
- - .yamato/_run-all.yml#run_all_project_tests_trunk
- - .yamato/_run-all.yml#run_all_project_tests_6000
- # Run Runtime tests on desktop players on trunk and 6000.0 editors
- - .yamato/_run-all.yml#run_all_project_tests_desktop_standalone_trunk
- - .yamato/_run-all.yml#run_all_project_tests_desktop_standalone_6000
- # Run Runtime tests on mobile players on trunk and 6000.0 editors
- - .yamato/_run-all.yml#run_all_project_tests_mobile_standalone_trunk
- - .yamato/_run-all.yml#run_all_project_tests_mobile_standalone_6000
- # Run Runtime tests on console players on trunk and 6000.0 editors
- - .yamato/_run-all.yml#run_all_project_tests_console_standalone_trunk
- - .yamato/_run-all.yml#run_all_project_tests_console_standalone_6000
- # Build player for webgl platform on trunk and 6000.0 editors
- - .yamato/_run-all.yml#run_all_webgl_builds_trunk
- - .yamato/_run-all.yml#run_all_webgl_builds_6000
- # Run Runtime tests against cmb service on trunk and 6000.0 editors
- - .yamato/_run-all.yml#run_all_project_tests_cmb_service_trunk
- - .yamato/_run-all.yml#run_all_project_tests_cmb_service_6000
- # Build player for webgl platform on trunk and 6000.0 editors
- - .yamato/project-updated-dependencies-test.yml#updated-dependencies_testproject_NGO_ubuntu_trunk
- - .yamato/project-updated-dependencies-test.yml#updated-dependencies_testproject_NGO_win_6000.0
+ # Run package EditMode and Playmode tests on desktop platforms
+ - .yamato/_run-all.yml#run_all_package_tests_{{ validation_editors.latest }}
+ - .yamato/_run-all.yml#run_all_package_tests_{{ validation_editors.minimal }}
+ # Run project EditMode and PLaymode tests on desktop platforms
+ - .yamato/_run-all.yml#run_all_project_tests_{{ validation_editors.latest }}
+ - .yamato/_run-all.yml#run_all_project_tests_{{ validation_editors.minimal }}
+ # Run Runtime tests on desktop players
+ - .yamato/_run-all.yml#run_all_project_tests_desktop_standalone_{{ validation_editors.latest }}
+ - .yamato/_run-all.yml#run_all_project_tests_desktop_standalone_{{ validation_editors.minimal }}
+ # Run Runtime tests on mobile players
+ - .yamato/_run-all.yml#run_all_project_tests_mobile_standalone_{{ validation_editors.latest }}
+ - .yamato/_run-all.yml#run_all_project_tests_mobile_standalone_{{ validation_editors.minimal }}
+ # Run Runtime tests on console players
+ - .yamato/_run-all.yml#run_all_project_tests_console_standalone_{{ validation_editors.latest }}
+ - .yamato/_run-all.yml#run_all_project_tests_console_standalone_{{ validation_editors.minimal }}
+ # Build player for webgl platform
+ - .yamato/_run-all.yml#run_all_webgl_builds_{{ validation_editors.latest }}
+ - .yamato/_run-all.yml#run_all_webgl_builds_{{ validation_editors.minimal }}
+ # Run Runtime tests against cmb service
+ - .yamato/_run-all.yml#run_all_project_tests_cmb_service_{{ validation_editors.latest }}
+ - .yamato/_run-all.yml#run_all_project_tests_cmb_service_{{ validation_editors.minimal }}
+ # Build player for webgl platform on trunk
+ - .yamato/project-updated-dependencies-test.yml#updated-dependencies_testproject_NGO_ubuntu_{{ validation_editors.latest }}
+ - .yamato/project-updated-dependencies-test.yml#updated-dependencies_testproject_NGO_win_{{ validation_editors.minimal }}
# 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_project_test_testproject_ubuntu_{{ validation_editors.default }}
# Run all tests on weekly bases
# Same subset as develop_nightly but runs per all supported editors as well as executes code coverage test and runs project standards per project
# It's not running wrench jobs since those will run either way in nightly test run
-# This in contrast to nightly checks will run tests on all editors (not only trunk). Running those on weekly basis and trunk tests nightly should be a good balance between making sure that tests are passing and overhead of running lots of tests
+# This in contrast to nightly checks will run tests on all editors. Running those on weekly basis and trunk tests nightly should be a good balance between making sure that tests are passing and overhead of running lots of tests
develop_weekly_trunk:
name: "\U0001F319 [Weekly] Run All Tests"
triggers:
@@ -187,5 +192,3 @@ develop_weekly_trunk:
- .yamato/_run-all.yml#run_all_webgl_builds
# Run Runtime tests against CMB service
- .yamato/_run-all.yml#run_all_project_tests_cmb_service
- # Run code coverage test
- - .yamato/code-coverage.yml#code_coverage_ubuntu_{{ validation_editors.default }}
diff --git a/.yamato/build-automation/standalone-projects.yml b/.yamato/build-automation/standalone-projects.yml
new file mode 100644
index 0000000000..2d06d4f69b
--- /dev/null
+++ b/.yamato/build-automation/standalone-projects.yml
@@ -0,0 +1,113 @@
+#######################################################
+### ###
+### Auto-generated by Recipe Engine, DO NOT EDIT. ###
+### ###
+#######################################################
+# Source: RecipeEngine.Modules.BuildAutomation.Recipes.ProjectBuildersRecipe
+# Generated by RecipeEngine.Modules.BuildAutomation
+build_asteroids_project:
+ name: Asteroids
+ agent:
+ image: package-ci/win10:v4
+ type: Unity::VM
+ flavor: b1.xlarge
+ commands:
+ - command: pip install --upgrade unity-downloader-cli
+ - command: python Tools/CI/scripts/BuildAutomation/extend_source_sparse_checkout.py --source-dir %YAMATO_SOURCE_DIR% --local-tested-packages-path .
+ - command: python Tools/CI/scripts/BuildAutomation/validate_params.py --build-machine-os windows --check-sample-branch https://github.cds.internal.unity3d.com/unity/Asteroids-CMB-NGO-Sample.git --check-unity-version --check-local-tested-packages %YAMATO_SOURCE_DIR%/. --min-supported-editor 6000.3
+ - command: git clone --single-branch --branch %SAMPLE_BRANCH% https://github.cds.internal.unity3d.com/unity/Asteroids-CMB-NGO-Sample.git C:/ClonedProject
+ - command: python Tools/CI/scripts/BuildAutomation/manifest_update.py --manifest-path C:/ClonedProject/./Packages/manifest.json --local-tested-packages-path %YAMATO_SOURCE_DIR%/.
+ - command: python Tools/CI/scripts/BuildAutomation/print_build_summary.py --project-name Asteroids --build-machine-os windows --sample-repo-url https://github.cds.internal.unity3d.com/unity/Asteroids-CMB-NGO-Sample.git --project-path C:/ClonedProject/.
+ - command: unity-downloader-cli --unity-version %UNITY_VERSION% --path C:/TestingEditor --wait --fast -c editor -c il2cpp -c android -c macos
+ - command: python Tools/CI/scripts/BuildAutomation/setup_build_scripts.py --project-path C:/ClonedProject/.
+ - command: python Tools/CI/scripts/BuildAutomation/get_build_method.py --project-path C:/ClonedProject/. --unity-path C:/TestingEditor/Unity.exe
+ - command: python -c "import os, shutil; dst = './PlayerArtifacts/Asteroids'; src = r'C:/ClonedProject/./build'; os.makedirs(dst, exist_ok=True); shutil.copytree(src, dst, dirs_exist_ok=True)"
+ artifacts:
+ logs:
+ paths:
+ - artifacts/**/*
+ players:
+ paths:
+ - PlayerArtifacts/**/*
+ variables:
+ LOCAL_TESTED_PACKAGES_NAMES: com.unity.netcode.gameobjects
+ PLATFORM_(WIN64_MAC_ANDROID): win64
+ SAMPLE_BRANCH: main
+ SCRIPTING_BACKEND_(IL2CPP_MONO_CORECLR): il2cpp
+ UNITY_VERSION: 6000.3
+ source:
+ files:
+ sparse_checkout_rules: Tools/CI/scripts/BuildAutomation/project-sparse-checkouts/Asteroids.patterns
+ checkout_mode: sparse
+build_bossroom_project:
+ name: BossRoom
+ agent:
+ image: package-ci/win10:v4
+ type: Unity::VM
+ flavor: b1.xlarge
+ commands:
+ - command: pip install --upgrade unity-downloader-cli
+ - command: python Tools/CI/scripts/BuildAutomation/extend_source_sparse_checkout.py --source-dir %YAMATO_SOURCE_DIR% --local-tested-packages-path .
+ - command: python Tools/CI/scripts/BuildAutomation/validate_params.py --build-machine-os windows --check-sample-branch https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop.git --check-unity-version --check-local-tested-packages %YAMATO_SOURCE_DIR%/. --min-supported-editor 6000.3
+ - command: git clone --single-branch --branch %SAMPLE_BRANCH% https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop.git C:/ClonedProject
+ - command: python Tools/CI/scripts/BuildAutomation/manifest_update.py --manifest-path C:/ClonedProject/./Packages/manifest.json --local-tested-packages-path %YAMATO_SOURCE_DIR%/.
+ - command: python Tools/CI/scripts/BuildAutomation/print_build_summary.py --project-name BossRoom --build-machine-os windows --sample-repo-url https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop.git --project-path C:/ClonedProject/.
+ - command: unity-downloader-cli --unity-version %UNITY_VERSION% --path C:/TestingEditor --wait --fast -c editor -c il2cpp -c android -c macos
+ - command: python Tools/CI/scripts/BuildAutomation/setup_build_scripts.py --project-path C:/ClonedProject/.
+ - command: python Tools/CI/scripts/BuildAutomation/get_build_method.py --project-path C:/ClonedProject/. --unity-path C:/TestingEditor/Unity.exe
+ - command: python -c "import os, shutil; dst = './PlayerArtifacts/BossRoom'; src = r'C:/ClonedProject/./build'; os.makedirs(dst, exist_ok=True); shutil.copytree(src, dst, dirs_exist_ok=True)"
+ artifacts:
+ logs:
+ paths:
+ - artifacts/**/*
+ players:
+ paths:
+ - PlayerArtifacts/**/*
+ variables:
+ LOCAL_TESTED_PACKAGES_NAMES: com.unity.netcode.gameobjects
+ PLATFORM_(WIN64_MAC_ANDROID): win64
+ SAMPLE_BRANCH: ngo-playtest-update
+ SCRIPTING_BACKEND_(IL2CPP_MONO_CORECLR): il2cpp
+ UNITY_VERSION: 6000.3
+ source:
+ files:
+ sparse_checkout_rules: Tools/CI/scripts/BuildAutomation/project-sparse-checkouts/BossRoom.patterns
+ checkout_mode: sparse
+build_socialhub_project:
+ name: SocialHub
+ agent:
+ image: package-ci/win10:v4
+ type: Unity::VM
+ flavor: b1.xlarge
+ commands:
+ - command: pip install --upgrade unity-downloader-cli
+ - command: python Tools/CI/scripts/BuildAutomation/extend_source_sparse_checkout.py --source-dir %YAMATO_SOURCE_DIR% --local-tested-packages-path .
+ - command: python Tools/CI/scripts/BuildAutomation/validate_params.py --build-machine-os windows --check-sample-branch https://github.com/Unity-Technologies/com.unity.multiplayer.samples.bitesize.git --check-unity-version --check-local-tested-packages %YAMATO_SOURCE_DIR%/. --min-supported-editor 6000.0
+ - command: git clone --filter=blob:none --no-checkout --single-branch --branch %SAMPLE_BRANCH% https://github.com/Unity-Technologies/com.unity.multiplayer.samples.bitesize.git C:/ClonedProject
+ - command: git -C C:/ClonedProject sparse-checkout set Basic/DistributedAuthoritySocialHub
+ - command: git -C C:/ClonedProject checkout %SAMPLE_BRANCH%
+ - command: python Tools/CI/scripts/BuildAutomation/resolve_sparse_file_references.py --cloned-root C:/ClonedProject --project-path Basic/DistributedAuthoritySocialHub --branch %SAMPLE_BRANCH%
+ - command: python Tools/CI/scripts/BuildAutomation/manifest_update.py --manifest-path C:/ClonedProject/Basic/DistributedAuthoritySocialHub/Packages/manifest.json --local-tested-packages-path %YAMATO_SOURCE_DIR%/.
+ - command: python Tools/CI/scripts/BuildAutomation/print_build_summary.py --project-name DistributedAuthoritySocialHub --build-machine-os windows --sample-repo-url https://github.com/Unity-Technologies/com.unity.multiplayer.samples.bitesize.git --project-path C:/ClonedProject/Basic/DistributedAuthoritySocialHub
+ - command: unity-downloader-cli --unity-version %UNITY_VERSION% --path C:/TestingEditor --wait --fast -c editor -c il2cpp -c android -c macos
+ - command: python Tools/CI/scripts/BuildAutomation/setup_build_scripts.py --project-path C:/ClonedProject/Basic/DistributedAuthoritySocialHub
+ - command: python Tools/CI/scripts/BuildAutomation/get_build_method.py --project-path C:/ClonedProject/Basic/DistributedAuthoritySocialHub --unity-path C:/TestingEditor/Unity.exe
+ - command: python -c "import os, shutil; dst = './PlayerArtifacts/SocialHub'; src = r'C:/ClonedProject/Basic/DistributedAuthoritySocialHub/build'; os.makedirs(dst, exist_ok=True); shutil.copytree(src, dst, dirs_exist_ok=True)"
+ artifacts:
+ logs:
+ paths:
+ - artifacts/**/*
+ players:
+ paths:
+ - PlayerArtifacts/**/*
+ variables:
+ LOCAL_TESTED_PACKAGES_NAMES: com.unity.netcode.gameobjects
+ PLATFORM_(WIN64_MAC_ANDROID): win64
+ SAMPLE_BRANCH: main
+ SCRIPTING_BACKEND_(IL2CPP_MONO_CORECLR): il2cpp
+ UNITY_VERSION: 6000.0
+ source:
+ files:
+ sparse_checkout_rules: Tools/CI/scripts/BuildAutomation/project-sparse-checkouts/SocialHub.patterns
+ checkout_mode: sparse
+
diff --git a/.yamato/code-coverage.yml b/.yamato/code-coverage.yml
index caeeff72ec..3b2062b399 100644
--- a/.yamato/code-coverage.yml
+++ b/.yamato/code-coverage.yml
@@ -2,7 +2,8 @@
---
# 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
@@ -10,25 +11,23 @@
# 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. Default (most used) editor which is 6000.3
#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) and nightly (develop_nightly)
{% 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 -%}
+code_coverage_project_test_{{ project.name }}_{{ platform.name }}_{{ validation_editors.default }}:
+ name: '[Code Coverage] Project Test - NGO {{ project.name }} [{{ platform.name }}, {{ validation_editors.default }}]'
agent:
type: {{ platform.type }}
image: {{ platform.image }}
@@ -37,14 +36,14 @@ code_coverage_{{ platform.name }}_{{ editor }}:
model: {{ platform.model }} # This is set only in platforms where we want non-default model to use (more information in project.metafile)
{% 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
+ - unity-downloader-cli --fast --wait -u {{ validation_editors.default }} -c Editor {% if platform.name == "mac" %} --arch arm64 {% endif %} # For macOS we use ARM64 models
+ - 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 }};flags:NGOv2_project_{{ project.name }}_{{ platform.name }};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 -%}
diff --git a/.yamato/console-standalone-test.yml b/.yamato/console-standalone-test.yml
index dba4a796a1..9574e07e1b 100644
--- a/.yamato/console-standalone-test.yml
+++ b/.yamato/console-standalone-test.yml
@@ -31,7 +31,6 @@
# Each console requires specific SDK paths and tools
# QUALITY THOUGHTS--------------------------------------------------------------------
- # TODO: consider adding all projects that have tests
# To see where this job is included (in trigger job definitions) look into _triggers.yml file
@@ -51,16 +50,16 @@ console_standalone_build_{{ project.name }}_{{ platform.name }}_{{ editor }}:
{% endif %}
commands:
- unity-downloader-cli --fast --wait -u {{ editor }} -c Editor -c il2cpp -c {{ platform.name }}
- - UnifiedTestRunner --testproject={{ project.path }} --architecture={% if platform.name == "switch" %}arm64{% else %}x64{% endif %} --scripting-backend=il2cpp --suite=playmode --platform={{ platform.standalone }} --editor-location=.Editor --artifacts-path=artifacts --player-save-path=build/players --testfilter="Unity.Netcode.RuntimeTests.*" --extra-editor-arg=-batchmode --extra-editor-arg=-nographics --reruncount=1 --clean-library-on-rerun --build-only --timeout={{ test_timeout}}
+ - UnifiedTestRunner --testproject={{ project.path }} --architecture={% if platform.name == "switch" %}arm64{% else %}x64{% endif %} --scripting-backend=il2cpp --suite=playmode --platform={{ platform.standalone }} --editor-location=.Editor --artifacts-path=artifacts --player-save-path=build/players --testfilter="Unity.Netcode.RuntimeTests.*" --extra-editor-arg=-batchmode --extra-editor-arg=-nographics{% if platform.name == "switch" %} --extra-editor-arg=-overrideTextureCompression --extra-editor-arg=ForceUncompressed{% endif %} --reruncount=1 --clean-library-on-rerun --build-only --timeout={{ test_timeout}}
variables:
# PS4 related
SCE_ORBIS_SDK_DIR: 'C:\Users\bokken\SCE\ps4_sdk_12_00'
-# PS5 related --> THIS WAS DISABLED IN PROJECT.METAFILE. SEE MTT-12118
- SCE_PROSPERO_SDK_DIR: 'C:\Program Files (x86)\SCE\Prospero SDKs\9.000'
- SHADER_COMPILER_PATH: '${SCE_PROSPERO_SDK_DIR}\target\bins'
+# PS5 related --> win10-ps5:v4 ships SDK 13.000 but defaults SCE_PROSPERO_SDK_DIR to an unsupported version, so set it explicitly.
+ SCE_PROSPERO_SDK_DIR: 'C:\Program Files (x86)\SCE\Prospero SDKs\13.000'
+ SHADER_COMPILER_PATH: '${SCE_PROSPERO_SDK_DIR}\host_tools\bin'
SCE_ROOT_DIR: 'C:\Program Files (x86)\SCE'
-# Switch related
- NINTENDO_SDK_ROOT: 'C:\Nintendo\nx_sdk-18_3_0\NintendoSDK'
+# Switch related --> Switch is DISABLED in project.metafile (MTT-15636): 6000.x/trunk editors mandate NintendoSDK 22.2.x, which is not installed on win10-switch:v4 (only nintendosdk-en-21_4_0 is). This target path is correct for when PETS ships 22.2.x and Switch is re-enabled.
+ NINTENDO_SDK_ROOT: 'C:\Nintendo\nintendosdk-en-22_2_0\NintendoSDK'
UNITY_NINTENDOSDK_CLI_TOOLS: '${NINTENDO_SDK_ROOT}\Tools\CommandLineTools'
artifacts:
players:
@@ -94,12 +93,12 @@ console_standalone_test_{{ project.name }}_{{ platform.name }}_{{ editor }}:
variables:
# PS4 related
SCE_ORBIS_SDK_DIR: 'C:\Users\bokken\SCE\ps4_sdk_12_00'
-# PS5 related --> THIS WAS DISABLED IN PROJECT.METAFILE. SEE MTT-12118
- SCE_PROSPERO_SDK_DIR: 'C:\Program Files (x86)\SCE\Prospero SDKs\9.000'
- SHADER_COMPILER_PATH: '${SCE_PROSPERO_SDK_DIR}\target\bins'
+# PS5 related --> win10-ps5:v4 ships SDK 13.000 but defaults SCE_PROSPERO_SDK_DIR to an unsupported version, so set it explicitly.
+ SCE_PROSPERO_SDK_DIR: 'C:\Program Files (x86)\SCE\Prospero SDKs\13.000'
+ SHADER_COMPILER_PATH: '${SCE_PROSPERO_SDK_DIR}\host_tools\bin'
SCE_ROOT_DIR: 'C:\Program Files (x86)\SCE'
-# Switch related
- NINTENDO_SDK_ROOT: 'C:\Nintendo\nx_sdk-18_3_0\NintendoSDK'
+# Switch related --> Switch is DISABLED in project.metafile (MTT-15636): 6000.x/trunk editors mandate NintendoSDK 22.2.x, which is not installed on win10-switch:v4 (only nintendosdk-en-21_4_0 is). This target path is correct for when PETS ships 22.2.x and Switch is re-enabled.
+ NINTENDO_SDK_ROOT: 'C:\Nintendo\nintendosdk-en-22_2_0\NintendoSDK'
UNITY_NINTENDOSDK_CLI_TOOLS: '${NINTENDO_SDK_ROOT}\Tools\CommandLineTools'
artifacts:
logs:
diff --git a/.yamato/generated-scripts/infrastructure-instability-detection-mac.sh b/.yamato/generated-scripts/infrastructure-instability-detection-mac.sh
index aef156dad9..1f7b566191 100644
--- a/.yamato/generated-scripts/infrastructure-instability-detection-mac.sh
+++ b/.yamato/generated-scripts/infrastructure-instability-detection-mac.sh
@@ -2,6 +2,13 @@
# This is an auto-generated script. Do not edit manually!
set -x
+crashReportDir="${TMPDIR%/}/BugReporterCrashReportJson"
+if [ -d "$crashReportDir" ]; then
+ for f in "$crashReportDir"/CrashReport_*.json; do
+ [ -e "$f" ] || continue
+ curl -X POST --connect-timeout 5 --max-time 10 -H "Content-Type: application/json" -T "$f" "https://internal-crash-collector.prd.cds.internal.unity3d.com/api/crash" || echo "Failed to upload $f. Ignoring..."
+ done
+fi
set -e
if [ -f "infrastructure_instability_detection_standalone.zip" ]; then
echo "removed existing archive infrastructure_instability_detection_standalone.zip"
diff --git a/.yamato/generated-scripts/infrastructure-instability-detection-win.cmd b/.yamato/generated-scripts/infrastructure-instability-detection-win.cmd
index 40d3bc8b3d..2397b45ae0 100644
--- a/.yamato/generated-scripts/infrastructure-instability-detection-win.cmd
+++ b/.yamato/generated-scripts/infrastructure-instability-detection-win.cmd
@@ -1,7 +1,7 @@
@echo on
rem This is an auto-generated script. Do not edit manually!
-if exist "%TEMP%\BugReporterCrashReportJson" for /f "delims=" %%i in ('dir /b /a-d "%TEMP%\BugReporterCrashReportJson\*.json"') do curl -X POST -H "Content-Type: application/json" -T "%TEMP%\BugReporterCrashReportJson\%%i" "https://internal-crash-collector.prd.cds.internal.unity3d.com/api/crash" || echo Failed to upload %%i. Ignoring...
+if exist "%TEMP%\BugReporterCrashReportJson" for /f "delims=" %%i in ('dir /b /a-d "%TEMP%\BugReporterCrashReportJson\CrashReport_*.json"') do curl -X POST --connect-timeout 5 --max-time 10 -H "Content-Type: application/json" -T "%TEMP%\BugReporterCrashReportJson\%%i" "https://internal-crash-collector.prd.cds.internal.unity3d.com/api/crash" || echo Failed to upload %%i. Ignoring...
curl -fs "https://artifactory-slo.bf.unity3d.com/artifactory/automation-and-tooling/infrastructure-instability-detection/standalone/1.2.2/windows.zip" --output "infrastructure_instability_detection_standalone.zip" --retry 5
IF EXIST "infrastructure_instability_detection" rmdir /s /q infrastructure_instability_detection
powershell.exe -nologo -noprofile -command "& { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::ExtractToDirectory('infrastructure_instability_detection_standalone.zip', '.'); }" && DEL "infrastructure_instability_detection_standalone.zip"
diff --git a/.yamato/package-pack.yml b/.yamato/package-pack.yml
index 94c940b74b..7554274fe8 100644
--- a/.yamato/package-pack.yml
+++ b/.yamato/package-pack.yml
@@ -40,7 +40,7 @@ package_pack_-_ngo_{{ platform.name }}:
{% endif %}
timeout: 0.25
variables:
- XRAY_PROFILE: "gold ./pvpExceptions.json"
+ XRAY_PROFILE: "gold ./pvpExceptions.json rme"
commands:
- upm-pvp pack "com.unity.netcode.gameobjects" --output upm-ci~/packages
- upm-pvp xray --packages "upm-ci~/packages/com.unity.netcode.gameobjects*.tgz" --results pvp-results
diff --git a/.yamato/package-tests.yml b/.yamato/package-tests.yml
index e9df795f10..5d6364c526 100644
--- a/.yamato/package-tests.yml
+++ b/.yamato/package-tests.yml
@@ -26,7 +26,7 @@
{% for platform in test_platforms.desktop -%}
{% for editor in validation_editors.all -%}
-package_test_-_ngo_{{ editor }}_{{ platform.name }}:
+package_test_-_ngo_{{ platform.name }}_{{ editor }}:
name : Package Test - NGO [{{ platform.name }}, {{ editor }}]
agent:
type: {{ platform.type }}
@@ -36,7 +36,7 @@ package_test_-_ngo_{{ editor }}_{{ platform.name }}:
model: {{ platform.model }} # This is set only in platforms where we want non-default model to use (more information in project.metafile)
{% endif %}
variables:
- XRAY_PROFILE: "gold ./pvpExceptions.json"
+ XRAY_PROFILE: "gold ./pvpExceptions.json rme"
UNITY_EXT_LOGGING: 1
commands:
- unity-downloader-cli --fast --wait -u {{ editor }} -c Editor {% if platform.name == "mac" %} --arch arm64 {% endif %} # For macOS we use ARM64 models.
diff --git a/.yamato/project-builders/builder.metafile b/.yamato/project-builders/builder.metafile
deleted file mode 100644
index b261d28dea..0000000000
--- a/.yamato/project-builders/builder.metafile
+++ /dev/null
@@ -1,22 +0,0 @@
-# https://internaldocs.unity.com/yamato_continuous_integration/usage/templating/
-
-NetcodeProjects:
- # Note that we are using internal Unity repo. This means that we may test with newest changes that are not yet released to our users (there are also public versions)
- # The parameters specify repo location, default branch to use (since you can modify it via job variable), path to manifest.json file so we can replace package entry and path to the project root folder since it differs between projects
- # Note that for BossRoom 'main' branch supports NGOv1.X and 'develop' branch supports NGOv2.X
- # TODO: For BossRoom correct branch to develop when PR-3736 is merged in their repo
- BossRoom:
- GithubRepo: "https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop.git"
- defaultBranch: ngo-playtest-update
- manifestPath: Packages/manifest.json
- projectPath: '.'
- Asteroids:
- GithubRepo: "https://github.cds.internal.unity3d.com/unity/Asteroids-CMB-NGO-Sample.git"
- defaultBranch: main
- manifestPath: Packages/manifest.json
- projectPath: '.'
- SocialHub:
- GithubRepo: "https://github.com/Unity-Technologies/com.unity.multiplayer.samples.bitesize.git"
- defaultBranch: main
- manifestPath: Basic/DistributedAuthoritySocialHub/Packages/manifest.json
- projectPath: 'Basic/DistributedAuthoritySocialHub'
diff --git a/.yamato/project-builders/project-builders.yml b/.yamato/project-builders/project-builders.yml
deleted file mode 100644
index 327598d9ea..0000000000
--- a/.yamato/project-builders/project-builders.yml
+++ /dev/null
@@ -1,97 +0,0 @@
-{% metadata_file .yamato/project-builders/builder.metafile %}
----
-# The above line corresponds to https://internaldocs.unity.com/yamato_continuous_integration/usage/templating/
-
-# Yamato paths disclaimer:
-# Note that artifacts can get only local paths and since cloned project is in different location, you need to be careful with paths
-# All artifact paths are defined relative to the Yamato source directory (YAMATO_SOURCE_DIR) and are case-sensitive.
-# !!! important “Artifact directory locations” All artifact globs are defined relative to the source directory (YAMATO_SOURCE_DIR). Yamato can’t capture artifacts from outside this directory, so if you need files from elsewhere, you should copy them into your source directory as part of job commands.
-
-# Those jobs were created in order to (in most cases) speed up playtesting and development time.
-# The aim is to collect all possible projects that use Netcode for Entities and create a job that will build the project with the given version of N4E package.
-# The package is taken directly from the branch from which the job was triggered. So image triggering the job from release/2.0.0 and release/2.1.0 branch to compare differences
-# Example use case would be to trigger the build job on Sunday so by Monday morning all builds are ready for playtesting. This limits the time a dev/QA has to spend building projects for different configurations (win, mac, Android, scripting backends, burst etc) or simply time necessary for building huge projects (Megacity).
-
-# This job takes parameters as scriptable backend configuration, burst compilation, unity editor version and platform.
-# Since Yamato variables can't be restricted to only specific values, the job will validate the parameters passed to it and fail quickly if those are incorrect. In order to see what options are available, please look at the variable name.
-
-# Note that for now all of those builds are being made on Windows machine (so for example combination of macOS + il2cpp is expected to fail)
-# TODO: for now all builds are being made on Windows machine, but it would be nice to have a Mac build as well.
-# TODO: add iOS support
-{% for netcodeProject in NetcodeProjects -%}
-build_{{ netcodeProject[0] }}_project:
- name: {{ netcodeProject[0] }}
- agent:
- type: Unity::VM
- image: package-ci/win10:v4
- flavor: b1.xlarge
- variables:
- UNITY_VERSION: trunk
- SCRIPTING_BACKEND_IL2CPP_MONO: il2cpp
- BURST_ON_OFF: on
- PLATFORM_WIN64_MAC_ANDROID: win64
- SAMPLE_BRANCH: {{ netcodeProject[1].defaultBranch }}
- commands:
- # Validate inputs passed via Yamato variables
- - python Tools/scripts/BuildAutomation/validate_params.py
- - echo Building {{ netcodeProject[0] }} project from branch %SAMPLE_BRANCH% with Unity version of %UNITY_VERSION%, Scripting backend %SCRIPTING_BACKEND_IL2CPP_MONO%, Burst %BURST_ON_OFF% for platform %PLATFORM_WIN64_MAC_ANDROID%
-
- # Clone the external project repository into a specific directory. Notice that branch is also specified.
- - git clone --single-branch --branch %SAMPLE_BRANCH% {{ netcodeProject[1].GithubRepo }} C:/ClonedProject
-
- # Modify the external project's manifest to use the local N4E package from current branch on which this Yamato job is running. (requires python that should be preinstalled in the image)
- - python Tools/scripts/BuildAutomation/manifest_update.py --manifest-path C:/ClonedProject/{{ netcodeProject[1].manifestPath }} --local-package-path %YAMATO_SOURCE_DIR%/com.unity.netcode.gameobjects
-
- # Run python script to update ProjectSettings.asset in order to connect the project to Unity Services/set proper values.
- # Notice that if a project has this already set up then in theory we don't need to run this script.
- - python Tools/scripts/BuildAutomation/connect_services.py --project-settings-path C:/ClonedProject/{{ netcodeProject[1].projectPath }}/ProjectSettings/ProjectSettings.asset
-
- # Enable or disable Burst compilation. This step is specific to Netcode package (or any package that uses Burst)
- - IF "%BURST_ON_OFF%"=="on" (python Tools/scripts/BuildAutomation/disable-enable-burst.py --enable-burst --project-path C:/ClonedProject/{{ netcodeProject[1].projectPath }})
- ELSE (python Tools/scripts/BuildAutomation/disable-enable-burst.py --disable-burst --project-path C:/ClonedProject/{{ netcodeProject[1].projectPath }})
-
- # Download the Unity Editor version specified in the UNITY_VERSION variable. Il2cpp component is downloaded only if the SCRIPTING_BACKEND_IL2CPP_MONO is set to "il2cpp".
- # TODO: we could download components only if needed
- - unity-downloader-cli --fast --wait -u %UNITY_VERSION% -p C:/TestingEditor -c Editor -c il2cpp -c Android -c macOS
-
- # Add BuilderScript.cs to the project so we can modify and build the project using Unity Editor.
- # This is a bit tricky step, notice that we also need to include proper assembly definition in order for those scripts to compile properly.
- # TODO: the asmdef file can be simplified
- - python Tools/scripts/BuildAutomation/FileCopy.py "C:/ClonedProject/{{ netcodeProject[1].projectPath }}"
-
- # Build the project using Unity Editor. This will call the given static BuilderScripts method.
- # Ideally, it would be nice to parametrize the BuilderScripts (for example to pass scripting backend as parameter) but -executeMethod only calls static methods without parameters so for now we will have multiple configurations
- # Notice that for Android platform even if mono is selected, il2cpp will be used since mono is not supported for Android builds.
- - IF /I "%PLATFORM_WIN64_MAC_ANDROID%"=="win64" (
- IF /I "%SCRIPTING_BACKEND_IL2CPP_MONO%"=="il2cpp" (
- C:/TestingEditor/Unity.exe -projectPath C:/ClonedProject/{{ netcodeProject[1].projectPath }} -buildTarget win64 -executeMethod BuilderScripts.BuildWinIl2cpp -batchmode -logFile ./artifacts/UnityLog.txt -automated -crash-report-folder ./artifacts/CrashArtifacts -quit
- ) ELSE (
- C:/TestingEditor/Unity.exe -projectPath C:/ClonedProject/{{ netcodeProject[1].projectPath }} -buildTarget win64 -executeMethod BuilderScripts.BuildWinMono -batchmode -logFile ./artifacts/UnityLog.txt -automated -crash-report-folder ./artifacts/CrashArtifacts -quit
- )
- )
- ELSE IF /I "%PLATFORM_WIN64_MAC_ANDROID%"=="mac" (
- IF /I "%SCRIPTING_BACKEND_IL2CPP_MONO%"=="il2cpp" (
- C:/TestingEditor/Unity.exe -projectPath C:/ClonedProject/{{ netcodeProject[1].projectPath }} -buildTarget osx -executeMethod BuilderScripts.BuildMacIl2cpp -batchmode -logFile ./artifacts/UnityLog.txt -automated -crash-report-folder ./artifacts/CrashArtifacts -quit
- ) ELSE (
- C:/TestingEditor/Unity.exe -projectPath C:/ClonedProject/{{ netcodeProject[1].projectPath }} -buildTarget osx -executeMethod BuilderScripts.BuildMacMono -batchmode -logFile ./artifacts/UnityLog.txt -automated -crash-report-folder ./artifacts/CrashArtifacts -quit
- )
- )
- ELSE IF /I "%PLATFORM_WIN64_MAC_ANDROID%"=="android" (
- C:/TestingEditor/Unity.exe -projectPath C:/ClonedProject/{{ netcodeProject[1].projectPath }} -buildTarget android -executeMethod BuilderScripts.BuildAndroidIl2cpp -batchmode -logFile ./artifacts/UnityLog.txt -automated -crash-report-folder ./artifacts/CrashArtifacts -quit
- )
-
- # Because of this we need to ensure that all files are copied to the source directory.
- # TODO: this can be omitted if I can somehow build the project in the source directory (YAMATO_SOURCE_DIR) instead of C:/CompetitiveAction
- - python -c "import os; os.makedirs('./build', exist_ok=True)" # --> Create the build directory if it doesn't exist
- - python -c "import shutil; shutil.copytree('C:/ClonedProject/{{ netcodeProject[1].projectPath }}/build', './build', dirs_exist_ok=True)" # --> Copy the build directory to the source directory (YAMATO_SOURCE_DIR). Remember to copy entire directory and not only exe file
-
- artifacts:
- logs:
- paths:
- - '*.log'
- - '*.xml'
- - artifacts/**/*
- players:
- paths:
- - build/**/*
-{% endfor -%}
\ No newline at end of file
diff --git a/.yamato/project-standards.yml b/.yamato/project-standards.yml
index 24380a152e..2ebae81b5e 100644
--- a/.yamato/project-standards.yml
+++ b/.yamato/project-standards.yml
@@ -30,7 +30,7 @@
{% for project in projects.all -%}
{% for platform in test_platforms.default -%}
-{% for editor in validation_editors.default -%}
+{% for editor in validation_editors.standards -%}
standards_{{ platform.name }}_{{ project.name }}_{{ editor }}:
name: Standards Check - NGO {{ project.name }} [{{ platform.name }}, {{ editor }}]
agent:
@@ -48,8 +48,7 @@ standards_{{ platform.name }}_{{ project.name }}_{{ editor }}:
- unity-downloader-cli --fast --wait -u {{ editor }} -c editor {% if platform.name == "mac" %} --arch arm64 {% endif %} # For macOS we use ARM64 models. Downloads basic editor
- .Editor/Unity -batchmode -nographics -logFile - -executeMethod Packages.Rider.Editor.RiderScriptEditor.SyncSolution -projectPath {{ project.path }} -quit # This command is used to invoke Unity in a "headless" mode. It's used to sync the project
- dotnet run --project=dotnet-tools/netcode.standards -- --project={{ project.path }} --fix # Auto-fix formatting issues
- - git checkout -- {{ project.path }}/Packages/manifest.json {{ project.path }}/Packages/packages-lock.json {{ project.path }}/ProjectSettings/ProjectVersion.txt 2>/dev/null || true # Restore files that Unity may have modified (we only want to check code formatting)
- - 'git diff --exit-code || (echo "ERROR: Code formatting issues found. Run dotnet run --project=dotnet-tools/netcode.standards -- --project={{ project.path }} --fix locally and commit the changes." && exit 1)' # Fail if formatter made any changes
+ - 'git diff --exit-code || (echo "ERROR: Code formatting issues found. Run dotnet run --project=dotnet-tools/netcode.standards -- --project={{ project.path }} --fix locally and commit the changes. Note that dotnet version that was used in this check depends on the image that was used so local results may differ (see the first command of this job to know which dotnet version was used)" && exit 1)' # Fail if formatter made any changes
{% endfor -%}
{% endfor -%}
{% endfor -%}
\ No newline at end of file
diff --git a/.yamato/project.metafile b/.yamato/project.metafile
index 871ff18710..c1e846d489 100644
--- a/.yamato/project.metafile
+++ b/.yamato/project.metafile
@@ -24,7 +24,7 @@
small_agent_platform:
- name: ubuntu
type: Unity::VM
- image: package-ci/ubuntu-22.04:v4.83.0
+ image: package-ci/ubuntu-22.04:v4.87.0
flavor: b1.small
@@ -39,15 +39,15 @@ test_platforms:
default:
- name: ubuntu
type: Unity::VM
- image: package-ci/ubuntu-22.04:v4.83.0
+ image: package-ci/ubuntu-22.04:v4.87.0
flavor: b1.large
standalone: StandaloneLinux64
desktop:
- name: ubuntu
type: Unity::VM
- image: package-ci/ubuntu-22.04:v4.83.0
+ image: package-ci/ubuntu-22.04:v4.87.0
flavor: b1.large
- smaller_flavor: b1.medium
+ smaller_flavor: b1.large
larger_flavor: b1.xlarge
standalone: StandaloneLinux64
- name: win
@@ -111,18 +111,20 @@ test_platforms:
flavor: b1.large
larger_flavor: b1.xlarge
standalone: PS4
- # - name: ps5 --> SEE MTT-12118
- # type: Unity::VM
- # image: package-ci/win10-ps5:v4
- # flavor: b1.large
- # larger_flavor: b1.xlarge
- # standalone: PS5
- - name: switch
+ # ps5: win10-ps5:v4 defaults SCE_PROSPERO_SDK_DIR to an unsupported SDK, so it is overridden to 13.000 in console-standalone-test.yml.
+ - name: ps5
type: Unity::VM
- image: package-ci/win10-switch:v4
+ image: package-ci/win10-ps5:v4
flavor: b1.large
larger_flavor: b1.xlarge
- standalone: Switch
+ standalone: PS5
+ # switch --> DISABLED. SEE MTT-15636 (split from MTT-12118). 6000.x/trunk editors mandate NintendoSDK 22.2.x, but package-ci/win10-switch:v4 currently ships only nintendosdk-en-21_4_0. That fixes texture packaging but the native IL2CPP link then fails (undefined symbol std::__1::__hash_memory, from the 22_02 SwitchPlayer.a). Re-enable once PETS publishes a win10-switch image with nintendosdk-en-22_2_x.
+ # - name: switch
+ # type: Unity::VM
+ # image: package-ci/win10-switch:v4
+ # flavor: b1.large
+ # larger_flavor: b1.xlarge
+ # standalone: Switch
- name: GameCoreXboxOne
type: Unity::VM
image: package-ci/win10-xbox:v4
@@ -142,19 +144,20 @@ test_platforms:
flavor: b1.large
larger_flavor: b1.xlarge
standalone: PS4
- #- name: ps5 --> SEE MTT-12118
- # type: Unity::console::ps5
- # image: package-ci/win10-ps5:v4
- # flavor: b1.large
- # larger_flavor: b1.xlarge
- # standalone: PS5
- - name: switch
- type: Unity::console::switch
- image: package-ci/win10-switch:v4
+ - name: ps5
+ type: Unity::console::ps5
+ image: package-ci/win10-ps5:v4
flavor: b1.large
larger_flavor: b1.xlarge
- standalone: Switch
- base: win
+ standalone: PS5
+ # switch --> DISABLED. SEE MTT-15636 (needs NintendoSDK 22.2.x on the image; see console_build note).
+ # - name: switch
+ # type: Unity::console::switch
+ # image: package-ci/win10-switch:v4
+ # flavor: b1.large
+ # larger_flavor: b1.xlarge
+ # standalone: Switch
+ # base: win
- name: GameCoreXboxOne
type: Unity::console::xbox
image: package-ci/win10-xbox:v4
@@ -171,20 +174,21 @@ test_platforms:
# EDITOR CONFIGURATIONS-------------------------------------------------------------------------------
# Editors to be used for testing. NGOv2.X official support started from 6000.0 editor
# TODO: When a new editor will be released it should be added to this list
+# standards editor is used for standards check so we won't get random manifest changes due to newer editor being used
validation_editors:
default:
- 6000.3
+ minimal:
+ - 6000.0
+ latest:
+ - 6000.6
all:
- 6000.0
- 6000.3
- - 6000.4
- - 6000.5
- - trunk
- - a4ce83e807ca9aff8394d1cc07341168dc49df03
- minimal:
- - 6000.0
-pinnedTrunk: a4ce83e807ca9aff8394d1cc07341168dc49df03
+ - 6000.6
+ standards:
+ - 6000.0.72f1
# Scripting backends used by Standalone RunTimeTests---------------------------------------------------
diff --git a/.yamato/wrench/api-validation-jobs.yml b/.yamato/wrench/api-validation-jobs.yml
index d99abd06f0..b92db75f1f 100644
--- a/.yamato/wrench/api-validation-jobs.yml
+++ b/.yamato/wrench/api-validation-jobs.yml
@@ -18,7 +18,7 @@ api_validation_-_netcode_gameobjects_-_6000_0_-_win10:
type: Unity::VM
flavor: b1.large
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "%WRENCH_LOCALAPV_URL%" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
@@ -60,8 +60,9 @@ api_validation_-_netcode_gameobjects_-_6000_0_-_win10:
UNITY_LICENSING_SERVER_DELETE_NUL: 0
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
diff --git a/.yamato/wrench/package-pack-jobs.yml b/.yamato/wrench/package-pack-jobs.yml
index 3994a564c2..768dd701e6 100644
--- a/.yamato/wrench/package-pack-jobs.yml
+++ b/.yamato/wrench/package-pack-jobs.yml
@@ -27,7 +27,8 @@ package_pack_-_netcode_gameobjects:
- upm-ci~/packages/**/*
variables:
UPMCI_ACK_LARGE_PACKAGE: 1
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
diff --git a/.yamato/wrench/preview-a-p-v.yml b/.yamato/wrench/preview-a-p-v.yml
index 55736dc6b8..3e6e67e31f 100644
--- a/.yamato/wrench/preview-a-p-v.yml
+++ b/.yamato/wrench/preview-a-p-v.yml
@@ -16,18 +16,12 @@ all_preview_apv_jobs:
- path: .yamato/wrench/preview-a-p-v.yml#preview_apv_-_6000_3_-_macos13
- path: .yamato/wrench/preview-a-p-v.yml#preview_apv_-_6000_3_-_ubuntu2204
- path: .yamato/wrench/preview-a-p-v.yml#preview_apv_-_6000_3_-_win10
- - path: .yamato/wrench/preview-a-p-v.yml#preview_apv_-_6000_4_-_macos13
- - path: .yamato/wrench/preview-a-p-v.yml#preview_apv_-_6000_4_-_ubuntu2204
- - path: .yamato/wrench/preview-a-p-v.yml#preview_apv_-_6000_4_-_win10
- - path: .yamato/wrench/preview-a-p-v.yml#preview_apv_-_6000_5_-_macos13
- - path: .yamato/wrench/preview-a-p-v.yml#preview_apv_-_6000_5_-_ubuntu2204
- - path: .yamato/wrench/preview-a-p-v.yml#preview_apv_-_6000_5_-_win10
- - path: .yamato/wrench/preview-a-p-v.yml#preview_apv_-_6000_6_-_macos13
+ - path: .yamato/wrench/preview-a-p-v.yml#preview_apv_-_6000_6_-_macos13arm
- path: .yamato/wrench/preview-a-p-v.yml#preview_apv_-_6000_6_-_ubuntu2204
- path: .yamato/wrench/preview-a-p-v.yml#preview_apv_-_6000_6_-_win10
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
# Functional tests for dependents found in the latest 6000.0 manifest (MacOS).
preview_apv_-_6000_0_-_macos13:
@@ -37,7 +31,7 @@ preview_apv_-_6000_0_-_macos13:
type: Unity::VM::osx
flavor: b1.xlarge
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "$WRENCH_LOCALAPV_URL" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
@@ -47,7 +41,7 @@ preview_apv_-_6000_0_-_macos13:
- command: unity-downloader-cli -u 6000.0/staging -c editor --path .Editor --fast
timeout: 10
retries: 3
- - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.0 --testsuite=editor,playmode --artifacts-path=PreviewApvArtifacts~
+ - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.0 --artifacts-path=PreviewApvArtifacts~
- command: echo 'Skipping Editor Manifest Validator as it is only supported on Windows'
after:
- command: bash .yamato/generated-scripts/infrastructure-instability-detection-mac.sh
@@ -82,10 +76,11 @@ preview_apv_-_6000_0_-_macos13:
UNITY_LICENSING_SERVER_DELETE_NUL: 0
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
# Functional tests for dependents found in the latest 6000.0 manifest (Ubuntu).
preview_apv_-_6000_0_-_ubuntu2204:
@@ -95,7 +90,7 @@ preview_apv_-_6000_0_-_ubuntu2204:
type: Unity::VM
flavor: b1.large
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "$WRENCH_LOCALAPV_URL" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
@@ -105,7 +100,7 @@ preview_apv_-_6000_0_-_ubuntu2204:
- command: unity-downloader-cli -u 6000.0/staging -c editor --path .Editor --fast
timeout: 10
retries: 3
- - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.0 --testsuite=editor,playmode --artifacts-path=PreviewApvArtifacts~
+ - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.0 --artifacts-path=PreviewApvArtifacts~
- command: echo 'Skipping Editor Manifest Validator as it is only supported on Windows'
after:
- command: bash .yamato/generated-scripts/infrastructure-instability-detection-linux.sh
@@ -140,10 +135,11 @@ preview_apv_-_6000_0_-_ubuntu2204:
UNITY_LICENSING_SERVER_DELETE_NUL: 0
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
# Functional tests for dependents found in the latest 6000.0 manifest (Windows).
preview_apv_-_6000_0_-_win10:
@@ -154,7 +150,7 @@ preview_apv_-_6000_0_-_win10:
flavor: b1.large
commands:
- command: gsudo reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem" /v LongPathsEnabled /t REG_DWORD /d 1 /f
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "%WRENCH_LOCALAPV_URL%" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
@@ -164,7 +160,7 @@ preview_apv_-_6000_0_-_win10:
- command: unity-downloader-cli -u 6000.0/staging -c editor --path .Editor --fast
timeout: 10
retries: 3
- - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.0 --testsuite=editor,playmode --artifacts-path=PreviewApvArtifacts~
+ - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.0 --artifacts-path=PreviewApvArtifacts~
- command: python PythonScripts/editor_manifest_validator.py --version=6000.0 --wrench-config=.yamato/wrench/wrench_config.json
after:
- command: .yamato\generated-scripts\infrastructure-instability-detection-win.cmd
@@ -199,10 +195,11 @@ preview_apv_-_6000_0_-_win10:
UNITY_LICENSING_SERVER_DELETE_NUL: 0
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
# Functional tests for dependents found in the latest 6000.3 manifest (MacOS).
preview_apv_-_6000_3_-_macos13:
@@ -212,7 +209,7 @@ preview_apv_-_6000_3_-_macos13:
type: Unity::VM::osx
flavor: b1.xlarge
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "$WRENCH_LOCALAPV_URL" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
@@ -222,7 +219,7 @@ preview_apv_-_6000_3_-_macos13:
- command: unity-downloader-cli -u 6000.3/staging -c editor --path .Editor --fast
timeout: 10
retries: 3
- - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.3 --testsuite=editor,playmode --artifacts-path=PreviewApvArtifacts~
+ - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.3 --artifacts-path=PreviewApvArtifacts~
- command: echo 'Skipping Editor Manifest Validator as it is only supported on Windows'
after:
- command: bash .yamato/generated-scripts/infrastructure-instability-detection-mac.sh
@@ -257,10 +254,11 @@ preview_apv_-_6000_3_-_macos13:
UNITY_LICENSING_SERVER_DELETE_NUL: 0
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
# Functional tests for dependents found in the latest 6000.3 manifest (Ubuntu).
preview_apv_-_6000_3_-_ubuntu2204:
@@ -270,7 +268,7 @@ preview_apv_-_6000_3_-_ubuntu2204:
type: Unity::VM
flavor: b1.large
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "$WRENCH_LOCALAPV_URL" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
@@ -280,7 +278,7 @@ preview_apv_-_6000_3_-_ubuntu2204:
- command: unity-downloader-cli -u 6000.3/staging -c editor --path .Editor --fast
timeout: 10
retries: 3
- - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.3 --testsuite=editor,playmode --artifacts-path=PreviewApvArtifacts~
+ - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.3 --artifacts-path=PreviewApvArtifacts~
- command: echo 'Skipping Editor Manifest Validator as it is only supported on Windows'
after:
- command: bash .yamato/generated-scripts/infrastructure-instability-detection-linux.sh
@@ -315,10 +313,11 @@ preview_apv_-_6000_3_-_ubuntu2204:
UNITY_LICENSING_SERVER_DELETE_NUL: 0
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
# Functional tests for dependents found in the latest 6000.3 manifest (Windows).
preview_apv_-_6000_3_-_win10:
@@ -329,7 +328,7 @@ preview_apv_-_6000_3_-_win10:
flavor: b1.large
commands:
- command: gsudo reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem" /v LongPathsEnabled /t REG_DWORD /d 1 /f
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "%WRENCH_LOCALAPV_URL%" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
@@ -339,7 +338,7 @@ preview_apv_-_6000_3_-_win10:
- command: unity-downloader-cli -u 6000.3/staging -c editor --path .Editor --fast
timeout: 10
retries: 3
- - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.3 --testsuite=editor,playmode --artifacts-path=PreviewApvArtifacts~
+ - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.3 --artifacts-path=PreviewApvArtifacts~
- command: python PythonScripts/editor_manifest_validator.py --version=6000.3 --wrench-config=.yamato/wrench/wrench_config.json
after:
- command: .yamato\generated-scripts\infrastructure-instability-detection-win.cmd
@@ -374,380 +373,32 @@ preview_apv_-_6000_3_-_win10:
UNITY_LICENSING_SERVER_DELETE_NUL: 0
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
-
-# Functional tests for dependents found in the latest 6000.4 manifest (MacOS).
-preview_apv_-_6000_4_-_macos13:
- name: Preview APV - 6000.4 - macos13
- agent:
- image: package-ci/macos-13:v4
- type: Unity::VM::osx
- flavor: b1.xlarge
- commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
- - command: 7z x -aoa wrench-localapv.zip
- - command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- - command: python PythonScripts/print_machine_info.py
- - command: npm install upm-ci-utils@stable -g --registry https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-npm
- timeout: 20
- retries: 10
- - command: unity-downloader-cli -u 6000.4/staging -c editor --path .Editor --fast
- timeout: 10
- retries: 3
- - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.4 --testsuite=editor,playmode --artifacts-path=PreviewApvArtifacts~
- - command: echo 'Skipping Editor Manifest Validator as it is only supported on Windows'
- after:
- - command: bash .yamato/generated-scripts/infrastructure-instability-detection-mac.sh
- artifacts:
- Crash Dumps:
- paths:
- - CrashDumps/**
- logs:
- paths:
- - '*.log'
- - '*.xml'
- - upm-ci~/test-results/**/*
- - upm-ci~/temp/*/Logs/**
- - upm-ci~/temp/*/Library/*.log
- - upm-ci~/temp/*/*.log
- - upm-ci~/temp/Builds/*.log
- packages:
- paths:
- - upm-ci~/packages/**/*
- PreviewAPVResults:
- paths:
- - PreviewApvArtifacts~/**
- - APVTest/**/manifest.json
- pvp-results:
- paths:
- - upm-ci~/pvp/**/*
- browsable: onDemand
- dependencies:
- - path: .yamato/wrench/package-pack-jobs.yml#package_pack_-_netcode_gameobjects
- variables:
- UNITY_LICENSING_SERVER_BASE_URL: http://unity-ci-licenses.hq.unity3d.com:8080/
- UNITY_LICENSING_SERVER_DELETE_NUL: 0
- UNITY_LICENSING_SERVER_DELETE_ULF: 0
- UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
- metadata:
- Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
-
-# Functional tests for dependents found in the latest 6000.4 manifest (Ubuntu).
-preview_apv_-_6000_4_-_ubuntu2204:
- name: Preview APV - 6000.4 - ubuntu2204
- agent:
- image: package-ci/ubuntu-22.04:v4
- type: Unity::VM
- flavor: b1.large
- commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
- - command: 7z x -aoa wrench-localapv.zip
- - command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- - command: python PythonScripts/print_machine_info.py
- - command: npm install upm-ci-utils@stable -g --registry https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-npm
- timeout: 20
- retries: 10
- - command: unity-downloader-cli -u 6000.4/staging -c editor --path .Editor --fast
- timeout: 10
- retries: 3
- - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.4 --testsuite=editor,playmode --artifacts-path=PreviewApvArtifacts~
- - command: echo 'Skipping Editor Manifest Validator as it is only supported on Windows'
- after:
- - command: bash .yamato/generated-scripts/infrastructure-instability-detection-linux.sh
- artifacts:
- Crash Dumps:
- paths:
- - CrashDumps/**
- logs:
- paths:
- - '*.log'
- - '*.xml'
- - upm-ci~/test-results/**/*
- - upm-ci~/temp/*/Logs/**
- - upm-ci~/temp/*/Library/*.log
- - upm-ci~/temp/*/*.log
- - upm-ci~/temp/Builds/*.log
- packages:
- paths:
- - upm-ci~/packages/**/*
- PreviewAPVResults:
- paths:
- - PreviewApvArtifacts~/**
- - APVTest/**/manifest.json
- pvp-results:
- paths:
- - upm-ci~/pvp/**/*
- browsable: onDemand
- dependencies:
- - path: .yamato/wrench/package-pack-jobs.yml#package_pack_-_netcode_gameobjects
- variables:
- UNITY_LICENSING_SERVER_BASE_URL: http://unity-ci-licenses.hq.unity3d.com:8080/
- UNITY_LICENSING_SERVER_DELETE_NUL: 0
- UNITY_LICENSING_SERVER_DELETE_ULF: 0
- UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
- metadata:
- Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
-
-# Functional tests for dependents found in the latest 6000.4 manifest (Windows).
-preview_apv_-_6000_4_-_win10:
- name: Preview APV - 6000.4 - win10
- agent:
- image: package-ci/win10:v4
- type: Unity::VM
- flavor: b1.large
- commands:
- - command: gsudo reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem" /v LongPathsEnabled /t REG_DWORD /d 1 /f
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
- - command: 7z x -aoa wrench-localapv.zip
- - command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- - command: python PythonScripts/print_machine_info.py
- - command: npm install upm-ci-utils@stable -g --registry https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-npm
- timeout: 20
- retries: 10
- - command: unity-downloader-cli -u 6000.4/staging -c editor --path .Editor --fast
- timeout: 10
- retries: 3
- - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.4 --testsuite=editor,playmode --artifacts-path=PreviewApvArtifacts~
- - command: python PythonScripts/editor_manifest_validator.py --version=6000.4 --wrench-config=.yamato/wrench/wrench_config.json
- after:
- - command: .yamato\generated-scripts\infrastructure-instability-detection-win.cmd
- artifacts:
- Crash Dumps:
- paths:
- - CrashDumps/**
- logs:
- paths:
- - '*.log'
- - '*.xml'
- - upm-ci~/test-results/**/*
- - upm-ci~/temp/*/Logs/**
- - upm-ci~/temp/*/Library/*.log
- - upm-ci~/temp/*/*.log
- - upm-ci~/temp/Builds/*.log
- packages:
- paths:
- - upm-ci~/packages/**/*
- PreviewAPVResults:
- paths:
- - PreviewApvArtifacts~/**
- - APVTest/**/manifest.json
- pvp-results:
- paths:
- - upm-ci~/pvp/**/*
- browsable: onDemand
- dependencies:
- - path: .yamato/wrench/package-pack-jobs.yml#package_pack_-_netcode_gameobjects
- variables:
- UNITY_LICENSING_SERVER_BASE_URL: http://unity-ci-licenses.hq.unity3d.com:8080/
- UNITY_LICENSING_SERVER_DELETE_NUL: 0
- UNITY_LICENSING_SERVER_DELETE_ULF: 0
- UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
- metadata:
- Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
-
-# Functional tests for dependents found in the latest 6000.5 manifest (MacOS).
-preview_apv_-_6000_5_-_macos13:
- name: Preview APV - 6000.5 - macos13
- agent:
- image: package-ci/macos-13:v4
- type: Unity::VM::osx
- flavor: b1.xlarge
- commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
- - command: 7z x -aoa wrench-localapv.zip
- - command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- - command: python PythonScripts/print_machine_info.py
- - command: npm install upm-ci-utils@stable -g --registry https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-npm
- timeout: 20
- retries: 10
- - command: unity-downloader-cli -u 6000.5/staging -c editor --path .Editor --fast
- timeout: 10
- retries: 3
- - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.5 --testsuite=editor,playmode --artifacts-path=PreviewApvArtifacts~
- - command: echo 'Skipping Editor Manifest Validator as it is only supported on Windows'
- after:
- - command: bash .yamato/generated-scripts/infrastructure-instability-detection-mac.sh
- artifacts:
- Crash Dumps:
- paths:
- - CrashDumps/**
- logs:
- paths:
- - '*.log'
- - '*.xml'
- - upm-ci~/test-results/**/*
- - upm-ci~/temp/*/Logs/**
- - upm-ci~/temp/*/Library/*.log
- - upm-ci~/temp/*/*.log
- - upm-ci~/temp/Builds/*.log
- packages:
- paths:
- - upm-ci~/packages/**/*
- PreviewAPVResults:
- paths:
- - PreviewApvArtifacts~/**
- - APVTest/**/manifest.json
- pvp-results:
- paths:
- - upm-ci~/pvp/**/*
- browsable: onDemand
- dependencies:
- - path: .yamato/wrench/package-pack-jobs.yml#package_pack_-_netcode_gameobjects
- variables:
- UNITY_LICENSING_SERVER_BASE_URL: http://unity-ci-licenses.hq.unity3d.com:8080/
- UNITY_LICENSING_SERVER_DELETE_NUL: 0
- UNITY_LICENSING_SERVER_DELETE_ULF: 0
- UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
- metadata:
- Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
-
-# Functional tests for dependents found in the latest 6000.5 manifest (Ubuntu).
-preview_apv_-_6000_5_-_ubuntu2204:
- name: Preview APV - 6000.5 - ubuntu2204
- agent:
- image: package-ci/ubuntu-22.04:v4
- type: Unity::VM
- flavor: b1.large
- commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
- - command: 7z x -aoa wrench-localapv.zip
- - command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- - command: python PythonScripts/print_machine_info.py
- - command: npm install upm-ci-utils@stable -g --registry https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-npm
- timeout: 20
- retries: 10
- - command: unity-downloader-cli -u 6000.5/staging -c editor --path .Editor --fast
- timeout: 10
- retries: 3
- - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.5 --testsuite=editor,playmode --artifacts-path=PreviewApvArtifacts~
- - command: echo 'Skipping Editor Manifest Validator as it is only supported on Windows'
- after:
- - command: bash .yamato/generated-scripts/infrastructure-instability-detection-linux.sh
- artifacts:
- Crash Dumps:
- paths:
- - CrashDumps/**
- logs:
- paths:
- - '*.log'
- - '*.xml'
- - upm-ci~/test-results/**/*
- - upm-ci~/temp/*/Logs/**
- - upm-ci~/temp/*/Library/*.log
- - upm-ci~/temp/*/*.log
- - upm-ci~/temp/Builds/*.log
- packages:
- paths:
- - upm-ci~/packages/**/*
- PreviewAPVResults:
- paths:
- - PreviewApvArtifacts~/**
- - APVTest/**/manifest.json
- pvp-results:
- paths:
- - upm-ci~/pvp/**/*
- browsable: onDemand
- dependencies:
- - path: .yamato/wrench/package-pack-jobs.yml#package_pack_-_netcode_gameobjects
- variables:
- UNITY_LICENSING_SERVER_BASE_URL: http://unity-ci-licenses.hq.unity3d.com:8080/
- UNITY_LICENSING_SERVER_DELETE_NUL: 0
- UNITY_LICENSING_SERVER_DELETE_ULF: 0
- UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
- metadata:
- Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
-
-# Functional tests for dependents found in the latest 6000.5 manifest (Windows).
-preview_apv_-_6000_5_-_win10:
- name: Preview APV - 6000.5 - win10
- agent:
- image: package-ci/win10:v4
- type: Unity::VM
- flavor: b1.large
- commands:
- - command: gsudo reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem" /v LongPathsEnabled /t REG_DWORD /d 1 /f
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
- - command: 7z x -aoa wrench-localapv.zip
- - command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- - command: python PythonScripts/print_machine_info.py
- - command: npm install upm-ci-utils@stable -g --registry https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-npm
- timeout: 20
- retries: 10
- - command: unity-downloader-cli -u 6000.5/staging -c editor --path .Editor --fast
- timeout: 10
- retries: 3
- - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.5 --testsuite=editor,playmode --artifacts-path=PreviewApvArtifacts~
- - command: python PythonScripts/editor_manifest_validator.py --version=6000.5 --wrench-config=.yamato/wrench/wrench_config.json
- after:
- - command: .yamato\generated-scripts\infrastructure-instability-detection-win.cmd
- artifacts:
- Crash Dumps:
- paths:
- - CrashDumps/**
- logs:
- paths:
- - '*.log'
- - '*.xml'
- - upm-ci~/test-results/**/*
- - upm-ci~/temp/*/Logs/**
- - upm-ci~/temp/*/Library/*.log
- - upm-ci~/temp/*/*.log
- - upm-ci~/temp/Builds/*.log
- packages:
- paths:
- - upm-ci~/packages/**/*
- PreviewAPVResults:
- paths:
- - PreviewApvArtifacts~/**
- - APVTest/**/manifest.json
- pvp-results:
- paths:
- - upm-ci~/pvp/**/*
- browsable: onDemand
- dependencies:
- - path: .yamato/wrench/package-pack-jobs.yml#package_pack_-_netcode_gameobjects
- variables:
- UNITY_LICENSING_SERVER_BASE_URL: http://unity-ci-licenses.hq.unity3d.com:8080/
- UNITY_LICENSING_SERVER_DELETE_NUL: 0
- UNITY_LICENSING_SERVER_DELETE_ULF: 0
- UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
- metadata:
- Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
# Functional tests for dependents found in the latest 6000.6 manifest (MacOS).
-preview_apv_-_6000_6_-_macos13:
- name: Preview APV - 6000.6 - macos13
+preview_apv_-_6000_6_-_macos13arm:
+ name: Preview APV - 6000.6 - macos13arm
agent:
- image: package-ci/macos-13:v4
+ image: package-ci/macos-13-arm64:v4
type: Unity::VM::osx
- flavor: b1.xlarge
+ flavor: m1.mac
+ model: M1
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "$WRENCH_LOCALAPV_URL" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
- command: npm install upm-ci-utils@stable -g --registry https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-npm
timeout: 20
retries: 10
- - command: unity-downloader-cli -u trunk -c editor --path .Editor --fast
+ - command: unity-downloader-cli -u 6000.6/staging -c editor --path .Editor --fast --arch arm64
timeout: 10
retries: 3
- - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.6 --testsuite=editor,playmode --artifacts-path=PreviewApvArtifacts~
+ - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.6 --artifacts-path=PreviewApvArtifacts~
- command: echo 'Skipping Editor Manifest Validator as it is only supported on Windows'
after:
- command: bash .yamato/generated-scripts/infrastructure-instability-detection-mac.sh
@@ -782,10 +433,11 @@ preview_apv_-_6000_6_-_macos13:
UNITY_LICENSING_SERVER_DELETE_NUL: 0
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
# Functional tests for dependents found in the latest 6000.6 manifest (Ubuntu).
preview_apv_-_6000_6_-_ubuntu2204:
@@ -795,17 +447,17 @@ preview_apv_-_6000_6_-_ubuntu2204:
type: Unity::VM
flavor: b1.large
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "$WRENCH_LOCALAPV_URL" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
- command: npm install upm-ci-utils@stable -g --registry https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-npm
timeout: 20
retries: 10
- - command: unity-downloader-cli -u trunk -c editor --path .Editor --fast
+ - command: unity-downloader-cli -u 6000.6/staging -c editor --path .Editor --fast
timeout: 10
retries: 3
- - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.6 --testsuite=editor,playmode --artifacts-path=PreviewApvArtifacts~
+ - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.6 --artifacts-path=PreviewApvArtifacts~
- command: echo 'Skipping Editor Manifest Validator as it is only supported on Windows'
after:
- command: bash .yamato/generated-scripts/infrastructure-instability-detection-linux.sh
@@ -840,10 +492,11 @@ preview_apv_-_6000_6_-_ubuntu2204:
UNITY_LICENSING_SERVER_DELETE_NUL: 0
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
# Functional tests for dependents found in the latest 6000.6 manifest (Windows).
preview_apv_-_6000_6_-_win10:
@@ -854,17 +507,17 @@ preview_apv_-_6000_6_-_win10:
flavor: b1.large
commands:
- command: gsudo reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem" /v LongPathsEnabled /t REG_DWORD /d 1 /f
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "%WRENCH_LOCALAPV_URL%" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
- command: npm install upm-ci-utils@stable -g --registry https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-npm
timeout: 20
retries: 10
- - command: unity-downloader-cli -u trunk -c editor --path .Editor --fast
+ - command: unity-downloader-cli -u 6000.6/staging -c editor --path .Editor --fast
timeout: 10
retries: 3
- - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.6 --testsuite=editor,playmode --artifacts-path=PreviewApvArtifacts~
+ - command: python PythonScripts/preview_apv.py --wrench-config=.yamato/wrench/wrench_config.json --editor-version=6000.6 --artifacts-path=PreviewApvArtifacts~
- command: python PythonScripts/editor_manifest_validator.py --version=6000.6 --wrench-config=.yamato/wrench/wrench_config.json
after:
- command: .yamato\generated-scripts\infrastructure-instability-detection-win.cmd
@@ -899,8 +552,9 @@ preview_apv_-_6000_6_-_win10:
UNITY_LICENSING_SERVER_DELETE_NUL: 0
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
diff --git a/.yamato/wrench/promotion-jobs.yml b/.yamato/wrench/promotion-jobs.yml
index e4beeec200..ed5c138ff1 100644
--- a/.yamato/wrench/promotion-jobs.yml
+++ b/.yamato/wrench/promotion-jobs.yml
@@ -14,7 +14,7 @@ publish_dry_run_netcode_gameobjects:
type: Unity::VM
flavor: b1.large
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "$WRENCH_LOCALAPV_URL" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
@@ -91,75 +91,15 @@ publish_dry_run_netcode_gameobjects:
UTR:
location: results/UTR/validate-netcode.gameobjects-6000.3-win10
unzip: true
- - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_4_-_macos13
+ - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_6_-_macos13arm
specific_options:
packages:
ignore_artifact: true
pvp-results:
- location: results/pvp/validate-netcode.gameobjects-6000.4-macos13
+ location: results/pvp/validate-netcode.gameobjects-6000.6-macos13arm
unzip: true
UTR:
- location: results/UTR/validate-netcode.gameobjects-6000.4-macos13
- unzip: true
- - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_4_-_ubuntu2204
- specific_options:
- packages:
- ignore_artifact: true
- pvp-results:
- location: results/pvp/validate-netcode.gameobjects-6000.4-ubuntu2204
- unzip: true
- UTR:
- location: results/UTR/validate-netcode.gameobjects-6000.4-ubuntu2204
- unzip: true
- - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_4_-_win10
- specific_options:
- packages:
- ignore_artifact: true
- pvp-results:
- location: results/pvp/validate-netcode.gameobjects-6000.4-win10
- unzip: true
- UTR:
- location: results/UTR/validate-netcode.gameobjects-6000.4-win10
- unzip: true
- - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_5_-_macos13
- specific_options:
- packages:
- ignore_artifact: true
- pvp-results:
- location: results/pvp/validate-netcode.gameobjects-6000.5-macos13
- unzip: true
- UTR:
- location: results/UTR/validate-netcode.gameobjects-6000.5-macos13
- unzip: true
- - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_5_-_ubuntu2204
- specific_options:
- packages:
- ignore_artifact: true
- pvp-results:
- location: results/pvp/validate-netcode.gameobjects-6000.5-ubuntu2204
- unzip: true
- UTR:
- location: results/UTR/validate-netcode.gameobjects-6000.5-ubuntu2204
- unzip: true
- - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_5_-_win10
- specific_options:
- packages:
- ignore_artifact: true
- pvp-results:
- location: results/pvp/validate-netcode.gameobjects-6000.5-win10
- unzip: true
- UTR:
- location: results/UTR/validate-netcode.gameobjects-6000.5-win10
- unzip: true
- - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_6_-_macos13
- specific_options:
- packages:
- ignore_artifact: true
- pvp-results:
- location: results/pvp/validate-netcode.gameobjects-6000.6-macos13
- unzip: true
- UTR:
- location: results/UTR/validate-netcode.gameobjects-6000.6-macos13
+ location: results/UTR/validate-netcode.gameobjects-6000.6-macos13arm
unzip: true
- path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_6_-_ubuntu2204
specific_options:
@@ -183,10 +123,11 @@ publish_dry_run_netcode_gameobjects:
unzip: true
variables:
UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
# Publish for netcode.gameobjects to https://artifactory-slo.bf.unity3d.com/artifactory/api/npm/upm-npm
publish_netcode_gameobjects:
@@ -196,7 +137,7 @@ publish_netcode_gameobjects:
type: Unity::VM
flavor: b1.large
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "$WRENCH_LOCALAPV_URL" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
@@ -273,75 +214,15 @@ publish_netcode_gameobjects:
UTR:
location: results/UTR/validate-netcode.gameobjects-6000.3-win10
unzip: true
- - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_4_-_macos13
- specific_options:
- packages:
- ignore_artifact: true
- pvp-results:
- location: results/pvp/validate-netcode.gameobjects-6000.4-macos13
- unzip: true
- UTR:
- location: results/UTR/validate-netcode.gameobjects-6000.4-macos13
- unzip: true
- - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_4_-_ubuntu2204
- specific_options:
- packages:
- ignore_artifact: true
- pvp-results:
- location: results/pvp/validate-netcode.gameobjects-6000.4-ubuntu2204
- unzip: true
- UTR:
- location: results/UTR/validate-netcode.gameobjects-6000.4-ubuntu2204
- unzip: true
- - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_4_-_win10
- specific_options:
- packages:
- ignore_artifact: true
- pvp-results:
- location: results/pvp/validate-netcode.gameobjects-6000.4-win10
- unzip: true
- UTR:
- location: results/UTR/validate-netcode.gameobjects-6000.4-win10
- unzip: true
- - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_5_-_macos13
- specific_options:
- packages:
- ignore_artifact: true
- pvp-results:
- location: results/pvp/validate-netcode.gameobjects-6000.5-macos13
- unzip: true
- UTR:
- location: results/UTR/validate-netcode.gameobjects-6000.5-macos13
- unzip: true
- - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_5_-_ubuntu2204
- specific_options:
- packages:
- ignore_artifact: true
- pvp-results:
- location: results/pvp/validate-netcode.gameobjects-6000.5-ubuntu2204
- unzip: true
- UTR:
- location: results/UTR/validate-netcode.gameobjects-6000.5-ubuntu2204
- unzip: true
- - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_5_-_win10
- specific_options:
- packages:
- ignore_artifact: true
- pvp-results:
- location: results/pvp/validate-netcode.gameobjects-6000.5-win10
- unzip: true
- UTR:
- location: results/UTR/validate-netcode.gameobjects-6000.5-win10
- unzip: true
- - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_6_-_macos13
+ - path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_6_-_macos13arm
specific_options:
packages:
ignore_artifact: true
pvp-results:
- location: results/pvp/validate-netcode.gameobjects-6000.6-macos13
+ location: results/pvp/validate-netcode.gameobjects-6000.6-macos13arm
unzip: true
UTR:
- location: results/UTR/validate-netcode.gameobjects-6000.6-macos13
+ location: results/UTR/validate-netcode.gameobjects-6000.6-macos13arm
unzip: true
- path: .yamato/wrench/validation-jobs.yml#validate_-_netcode_gameobjects_-_6000_6_-_ubuntu2204
specific_options:
@@ -365,8 +246,10 @@ publish_netcode_gameobjects:
unzip: true
variables:
UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
+ allow_on: branch match "^release/.*"
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
diff --git a/.yamato/wrench/recipe-regeneration.yml b/.yamato/wrench/recipe-regeneration.yml
index 1550408dd2..1529d50b33 100644
--- a/.yamato/wrench/recipe-regeneration.yml
+++ b/.yamato/wrench/recipe-regeneration.yml
@@ -31,5 +31,5 @@ test_-_wrench_jobs_up_to_date:
cancel_old_ci: true
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
diff --git a/.yamato/wrench/validation-jobs.yml b/.yamato/wrench/validation-jobs.yml
index f247f7d6a4..ff46e2c4ac 100644
--- a/.yamato/wrench/validation-jobs.yml
+++ b/.yamato/wrench/validation-jobs.yml
@@ -14,7 +14,7 @@ validate_-_netcode_gameobjects_-_6000_0_-_macos13:
type: Unity::VM::osx
flavor: b1.xlarge
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "$WRENCH_LOCALAPV_URL" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
@@ -28,13 +28,19 @@ validate_-_netcode_gameobjects_-_6000_0_-_macos13:
- command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp
timeout: 40
retries: 0
+ - command: python PythonScripts/ignore_clean_console_failures.py
+ timeout: 5
+ retries: 0
- command: upm-pvp require "pkgprom-promote -PVP-29-2 rme" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 5
retries: 0
- command: upm-pvp require "rme PVP-160-1 supported" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 10
retries: 0
- - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts --suite=Editor --suite=Playmode "--ff={ops.upmpvpevidence.enable=true}" '
+ - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/editor --suite=editor "--ff={ops.upmpvpevidence.enable=true}" '
+ timeout: 40
+ retries: 1
+ - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/playmode --suite=playmode "--ff={ops.upmpvpevidence.enable=true}" '
timeout: 40
retries: 1
after:
@@ -69,10 +75,11 @@ validate_-_netcode_gameobjects_-_6000_0_-_macos13:
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
labels:
- Packages:netcode.gameobjects
@@ -84,7 +91,7 @@ validate_-_netcode_gameobjects_-_6000_0_-_ubuntu2204:
type: Unity::VM
flavor: b1.large
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "$WRENCH_LOCALAPV_URL" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
@@ -98,13 +105,19 @@ validate_-_netcode_gameobjects_-_6000_0_-_ubuntu2204:
- command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp
timeout: 40
retries: 0
+ - command: python PythonScripts/ignore_clean_console_failures.py
+ timeout: 5
+ retries: 0
- command: upm-pvp require "pkgprom-promote -PVP-29-2 rme" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 5
retries: 0
- command: upm-pvp require "rme PVP-160-1 supported" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 10
retries: 0
- - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts --suite=Editor --suite=Playmode "--ff={ops.upmpvpevidence.enable=true}" '
+ - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/editor --suite=editor "--ff={ops.upmpvpevidence.enable=true}" '
+ timeout: 40
+ retries: 1
+ - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/playmode --suite=playmode "--ff={ops.upmpvpevidence.enable=true}" '
timeout: 40
retries: 1
after:
@@ -139,10 +152,11 @@ validate_-_netcode_gameobjects_-_6000_0_-_ubuntu2204:
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
labels:
- Packages:netcode.gameobjects
@@ -154,7 +168,7 @@ validate_-_netcode_gameobjects_-_6000_0_-_win10:
type: Unity::VM
flavor: b1.large
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "%WRENCH_LOCALAPV_URL%" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
@@ -168,13 +182,19 @@ validate_-_netcode_gameobjects_-_6000_0_-_win10:
- command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp
timeout: 40
retries: 0
+ - command: python PythonScripts/ignore_clean_console_failures.py
+ timeout: 5
+ retries: 0
- command: upm-pvp require "pkgprom-promote -PVP-29-2 rme" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 5
retries: 0
- command: upm-pvp require "rme PVP-160-1 supported" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 10
retries: 0
- - command: 'UnifiedTestRunner.exe --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts --suite=Editor --suite=Playmode "--ff={ops.upmpvpevidence.enable=true}" '
+ - command: 'UnifiedTestRunner.exe --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/editor --suite=editor "--ff={ops.upmpvpevidence.enable=true}" '
+ timeout: 40
+ retries: 1
+ - command: 'UnifiedTestRunner.exe --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/playmode --suite=playmode "--ff={ops.upmpvpevidence.enable=true}" '
timeout: 40
retries: 1
after:
@@ -209,10 +229,11 @@ validate_-_netcode_gameobjects_-_6000_0_-_win10:
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
labels:
- Packages:netcode.gameobjects
@@ -224,7 +245,7 @@ validate_-_netcode_gameobjects_-_6000_3_-_macos13:
type: Unity::VM::osx
flavor: b1.xlarge
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "$WRENCH_LOCALAPV_URL" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
@@ -238,13 +259,19 @@ validate_-_netcode_gameobjects_-_6000_3_-_macos13:
- command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp
timeout: 40
retries: 0
+ - command: python PythonScripts/ignore_clean_console_failures.py
+ timeout: 5
+ retries: 0
- command: upm-pvp require "pkgprom-promote -PVP-29-2 rme" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 5
retries: 0
- command: upm-pvp require "rme PVP-160-1 supported" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 10
retries: 0
- - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts --suite=Editor --suite=Playmode "--ff={ops.upmpvpevidence.enable=true}" '
+ - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/editor --suite=editor "--ff={ops.upmpvpevidence.enable=true}" '
+ timeout: 40
+ retries: 1
+ - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/playmode --suite=playmode "--ff={ops.upmpvpevidence.enable=true}" '
timeout: 40
retries: 1
after:
@@ -279,10 +306,11 @@ validate_-_netcode_gameobjects_-_6000_3_-_macos13:
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
labels:
- Packages:netcode.gameobjects
@@ -294,7 +322,7 @@ validate_-_netcode_gameobjects_-_6000_3_-_ubuntu2204:
type: Unity::VM
flavor: b1.large
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "$WRENCH_LOCALAPV_URL" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
@@ -308,13 +336,19 @@ validate_-_netcode_gameobjects_-_6000_3_-_ubuntu2204:
- command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp
timeout: 40
retries: 0
+ - command: python PythonScripts/ignore_clean_console_failures.py
+ timeout: 5
+ retries: 0
- command: upm-pvp require "pkgprom-promote -PVP-29-2 rme" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 5
retries: 0
- command: upm-pvp require "rme PVP-160-1 supported" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 10
retries: 0
- - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts --suite=Editor --suite=Playmode "--ff={ops.upmpvpevidence.enable=true}" '
+ - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/editor --suite=editor "--ff={ops.upmpvpevidence.enable=true}" '
+ timeout: 40
+ retries: 1
+ - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/playmode --suite=playmode "--ff={ops.upmpvpevidence.enable=true}" '
timeout: 40
retries: 1
after:
@@ -349,10 +383,11 @@ validate_-_netcode_gameobjects_-_6000_3_-_ubuntu2204:
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
labels:
- Packages:netcode.gameobjects
@@ -364,7 +399,7 @@ validate_-_netcode_gameobjects_-_6000_3_-_win10:
type: Unity::VM
flavor: b1.large
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "%WRENCH_LOCALAPV_URL%" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
@@ -378,223 +413,19 @@ validate_-_netcode_gameobjects_-_6000_3_-_win10:
- command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp
timeout: 40
retries: 0
- - command: upm-pvp require "pkgprom-promote -PVP-29-2 rme" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
+ - command: python PythonScripts/ignore_clean_console_failures.py
timeout: 5
retries: 0
- - command: upm-pvp require "rme PVP-160-1 supported" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
- timeout: 10
- retries: 0
- - command: 'UnifiedTestRunner.exe --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts --suite=Editor --suite=Playmode "--ff={ops.upmpvpevidence.enable=true}" '
- timeout: 40
- retries: 1
- after:
- - command: .yamato\generated-scripts\infrastructure-instability-detection-win.cmd
- artifacts:
- Crash Dumps:
- paths:
- - CrashDumps/**
- packages:
- paths:
- - upm-ci~/packages/**/*
- pvp-results:
- paths:
- - upm-ci~/pvp/**/*
- browsable: onDemand
- UTR:
- paths:
- - '*.log'
- - '*.xml'
- - artifacts/**/*
- - testproject/Logs/**
- - testproject/Library/*.log
- - testproject/*.log
- - testproject/Builds/*.log
- - build/test-results/**
- browsable: onDemand
- dependencies:
- - path: .yamato/wrench/package-pack-jobs.yml#package_pack_-_netcode_gameobjects
- variables:
- UNITY_LICENSING_SERVER_BASE_URL: http://unity-ci-licenses.hq.unity3d.com:8080/
- UNITY_LICENSING_SERVER_DELETE_NUL: 0
- UNITY_LICENSING_SERVER_DELETE_ULF: 0
- UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
- metadata:
- Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
- labels:
- - Packages:netcode.gameobjects
-
-# PVP Editor and Playmode tests for Validate - netcode.gameobjects - 6000.4 - macos13 (6000.4 - MacOS).
-validate_-_netcode_gameobjects_-_6000_4_-_macos13:
- name: Validate - netcode.gameobjects - 6000.4 - macos13
- agent:
- image: package-ci/macos-13:v4
- type: Unity::VM::osx
- flavor: b1.xlarge
- commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
- - command: 7z x -aoa wrench-localapv.zip
- - command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- - command: python PythonScripts/print_machine_info.py
- - command: unity-downloader-cli -u 6000.4/staging -c editor --path .Editor --fast
- timeout: 20
- retries: 3
- - command: upm-pvp create-test-project testproject --packages "upm-ci~/packages/*.tgz" --filter "com.unity.netcode.gameobjects com.unity.netcode.gameobjects.tests" --unity .Editor
- timeout: 10
- retries: 1
- - command: echo No internal packages to add.
- - command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp
- timeout: 40
- retries: 0
- command: upm-pvp require "pkgprom-promote -PVP-29-2 rme" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 5
retries: 0
- command: upm-pvp require "rme PVP-160-1 supported" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 10
retries: 0
- - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts --suite=Editor --suite=Playmode "--ff={ops.upmpvpevidence.enable=true}" '
+ - command: 'UnifiedTestRunner.exe --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/editor --suite=editor "--ff={ops.upmpvpevidence.enable=true}" '
timeout: 40
retries: 1
- after:
- - command: bash .yamato/generated-scripts/infrastructure-instability-detection-mac.sh
- artifacts:
- Crash Dumps:
- paths:
- - CrashDumps/**
- packages:
- paths:
- - upm-ci~/packages/**/*
- pvp-results:
- paths:
- - upm-ci~/pvp/**/*
- browsable: onDemand
- UTR:
- paths:
- - '*.log'
- - '*.xml'
- - artifacts/**/*
- - testproject/Logs/**
- - testproject/Library/*.log
- - testproject/*.log
- - testproject/Builds/*.log
- - build/test-results/**
- browsable: onDemand
- dependencies:
- - path: .yamato/wrench/package-pack-jobs.yml#package_pack_-_netcode_gameobjects
- variables:
- UNITY_LICENSING_SERVER_BASE_URL: http://unity-ci-licenses.hq.unity3d.com:8080/
- UNITY_LICENSING_SERVER_DELETE_NUL: 0
- UNITY_LICENSING_SERVER_DELETE_ULF: 0
- UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
- metadata:
- Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
- labels:
- - Packages:netcode.gameobjects
-
-# PVP Editor and Playmode tests for Validate - netcode.gameobjects - 6000.4 - ubuntu2204 (6000.4 - Ubuntu).
-validate_-_netcode_gameobjects_-_6000_4_-_ubuntu2204:
- name: Validate - netcode.gameobjects - 6000.4 - ubuntu2204
- agent:
- image: package-ci/ubuntu-22.04:v4
- type: Unity::VM
- flavor: b1.large
- commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
- - command: 7z x -aoa wrench-localapv.zip
- - command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- - command: python PythonScripts/print_machine_info.py
- - command: unity-downloader-cli -u 6000.4/staging -c editor --path .Editor --fast
- timeout: 20
- retries: 3
- - command: upm-pvp create-test-project testproject --packages "upm-ci~/packages/*.tgz" --filter "com.unity.netcode.gameobjects com.unity.netcode.gameobjects.tests" --unity .Editor
- timeout: 10
- retries: 1
- - command: echo No internal packages to add.
- - command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp
- timeout: 40
- retries: 0
- - command: upm-pvp require "pkgprom-promote -PVP-29-2 rme" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
- timeout: 5
- retries: 0
- - command: upm-pvp require "rme PVP-160-1 supported" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
- timeout: 10
- retries: 0
- - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts --suite=Editor --suite=Playmode "--ff={ops.upmpvpevidence.enable=true}" '
- timeout: 40
- retries: 1
- after:
- - command: bash .yamato/generated-scripts/infrastructure-instability-detection-linux.sh
- artifacts:
- Crash Dumps:
- paths:
- - CrashDumps/**
- packages:
- paths:
- - upm-ci~/packages/**/*
- pvp-results:
- paths:
- - upm-ci~/pvp/**/*
- browsable: onDemand
- UTR:
- paths:
- - '*.log'
- - '*.xml'
- - artifacts/**/*
- - testproject/Logs/**
- - testproject/Library/*.log
- - testproject/*.log
- - testproject/Builds/*.log
- - build/test-results/**
- browsable: onDemand
- dependencies:
- - path: .yamato/wrench/package-pack-jobs.yml#package_pack_-_netcode_gameobjects
- variables:
- UNITY_LICENSING_SERVER_BASE_URL: http://unity-ci-licenses.hq.unity3d.com:8080/
- UNITY_LICENSING_SERVER_DELETE_NUL: 0
- UNITY_LICENSING_SERVER_DELETE_ULF: 0
- UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
- metadata:
- Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
- labels:
- - Packages:netcode.gameobjects
-
-# PVP Editor and Playmode tests for Validate - netcode.gameobjects - 6000.4 - win10 (6000.4 - Windows).
-validate_-_netcode_gameobjects_-_6000_4_-_win10:
- name: Validate - netcode.gameobjects - 6000.4 - win10
- agent:
- image: package-ci/win10:v4
- type: Unity::VM
- flavor: b1.large
- commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
- - command: 7z x -aoa wrench-localapv.zip
- - command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- - command: python PythonScripts/print_machine_info.py
- - command: unity-downloader-cli -u 6000.4/staging -c editor --path .Editor --fast
- timeout: 20
- retries: 3
- - command: upm-pvp create-test-project testproject --packages "upm-ci~/packages/*.tgz" --filter "com.unity.netcode.gameobjects com.unity.netcode.gameobjects.tests" --unity .Editor
- timeout: 10
- retries: 1
- - command: echo No internal packages to add.
- - command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp
- timeout: 40
- retries: 0
- - command: upm-pvp require "pkgprom-promote -PVP-29-2 rme" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
- timeout: 5
- retries: 0
- - command: upm-pvp require "rme PVP-160-1 supported" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
- timeout: 10
- retries: 0
- - command: 'UnifiedTestRunner.exe --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts --suite=Editor --suite=Playmode "--ff={ops.upmpvpevidence.enable=true}" '
+ - command: 'UnifiedTestRunner.exe --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/playmode --suite=playmode "--ff={ops.upmpvpevidence.enable=true}" '
timeout: 40
retries: 1
after:
@@ -629,26 +460,28 @@ validate_-_netcode_gameobjects_-_6000_4_-_win10:
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
labels:
- Packages:netcode.gameobjects
-# PVP Editor and Playmode tests for Validate - netcode.gameobjects - 6000.5 - macos13 (6000.5 - MacOS).
-validate_-_netcode_gameobjects_-_6000_5_-_macos13:
- name: Validate - netcode.gameobjects - 6000.5 - macos13
+# PVP Editor and Playmode tests for Validate - netcode.gameobjects - 6000.6 - macos13arm (6000.6 - MacOS).
+validate_-_netcode_gameobjects_-_6000_6_-_macos13arm:
+ name: Validate - netcode.gameobjects - 6000.6 - macos13arm
agent:
- image: package-ci/macos-13:v4
+ image: package-ci/macos-13-arm64:v4
type: Unity::VM::osx
- flavor: b1.xlarge
+ flavor: m1.mac
+ model: M1
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "$WRENCH_LOCALAPV_URL" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
- - command: unity-downloader-cli -u 6000.5/staging -c editor --path .Editor --fast
+ - command: unity-downloader-cli -u 6000.6/staging -c editor --path .Editor --fast --arch arm64
timeout: 20
retries: 3
- command: upm-pvp create-test-project testproject --packages "upm-ci~/packages/*.tgz" --filter "com.unity.netcode.gameobjects com.unity.netcode.gameobjects.tests" --unity .Editor
@@ -658,223 +491,19 @@ validate_-_netcode_gameobjects_-_6000_5_-_macos13:
- command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp
timeout: 40
retries: 0
- - command: upm-pvp require "pkgprom-promote -PVP-29-2 rme" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
+ - command: python PythonScripts/ignore_clean_console_failures.py
timeout: 5
retries: 0
- - command: upm-pvp require "rme PVP-160-1 supported" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
- timeout: 10
- retries: 0
- - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts --suite=Editor --suite=Playmode "--ff={ops.upmpvpevidence.enable=true}" '
- timeout: 40
- retries: 1
- after:
- - command: bash .yamato/generated-scripts/infrastructure-instability-detection-mac.sh
- artifacts:
- Crash Dumps:
- paths:
- - CrashDumps/**
- packages:
- paths:
- - upm-ci~/packages/**/*
- pvp-results:
- paths:
- - upm-ci~/pvp/**/*
- browsable: onDemand
- UTR:
- paths:
- - '*.log'
- - '*.xml'
- - artifacts/**/*
- - testproject/Logs/**
- - testproject/Library/*.log
- - testproject/*.log
- - testproject/Builds/*.log
- - build/test-results/**
- browsable: onDemand
- dependencies:
- - path: .yamato/wrench/package-pack-jobs.yml#package_pack_-_netcode_gameobjects
- variables:
- UNITY_LICENSING_SERVER_BASE_URL: http://unity-ci-licenses.hq.unity3d.com:8080/
- UNITY_LICENSING_SERVER_DELETE_NUL: 0
- UNITY_LICENSING_SERVER_DELETE_ULF: 0
- UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
- metadata:
- Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
- labels:
- - Packages:netcode.gameobjects
-
-# PVP Editor and Playmode tests for Validate - netcode.gameobjects - 6000.5 - ubuntu2204 (6000.5 - Ubuntu).
-validate_-_netcode_gameobjects_-_6000_5_-_ubuntu2204:
- name: Validate - netcode.gameobjects - 6000.5 - ubuntu2204
- agent:
- image: package-ci/ubuntu-22.04:v4
- type: Unity::VM
- flavor: b1.large
- commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
- - command: 7z x -aoa wrench-localapv.zip
- - command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- - command: python PythonScripts/print_machine_info.py
- - command: unity-downloader-cli -u 6000.5/staging -c editor --path .Editor --fast
- timeout: 20
- retries: 3
- - command: upm-pvp create-test-project testproject --packages "upm-ci~/packages/*.tgz" --filter "com.unity.netcode.gameobjects com.unity.netcode.gameobjects.tests" --unity .Editor
- timeout: 10
- retries: 1
- - command: echo No internal packages to add.
- - command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp
- timeout: 40
- retries: 0
- command: upm-pvp require "pkgprom-promote -PVP-29-2 rme" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 5
retries: 0
- command: upm-pvp require "rme PVP-160-1 supported" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 10
retries: 0
- - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts --suite=Editor --suite=Playmode "--ff={ops.upmpvpevidence.enable=true}" '
+ - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/editor --suite=editor "--ff={ops.upmpvpevidence.enable=true}" '
timeout: 40
retries: 1
- after:
- - command: bash .yamato/generated-scripts/infrastructure-instability-detection-linux.sh
- artifacts:
- Crash Dumps:
- paths:
- - CrashDumps/**
- packages:
- paths:
- - upm-ci~/packages/**/*
- pvp-results:
- paths:
- - upm-ci~/pvp/**/*
- browsable: onDemand
- UTR:
- paths:
- - '*.log'
- - '*.xml'
- - artifacts/**/*
- - testproject/Logs/**
- - testproject/Library/*.log
- - testproject/*.log
- - testproject/Builds/*.log
- - build/test-results/**
- browsable: onDemand
- dependencies:
- - path: .yamato/wrench/package-pack-jobs.yml#package_pack_-_netcode_gameobjects
- variables:
- UNITY_LICENSING_SERVER_BASE_URL: http://unity-ci-licenses.hq.unity3d.com:8080/
- UNITY_LICENSING_SERVER_DELETE_NUL: 0
- UNITY_LICENSING_SERVER_DELETE_ULF: 0
- UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
- metadata:
- Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
- labels:
- - Packages:netcode.gameobjects
-
-# PVP Editor and Playmode tests for Validate - netcode.gameobjects - 6000.5 - win10 (6000.5 - Windows).
-validate_-_netcode_gameobjects_-_6000_5_-_win10:
- name: Validate - netcode.gameobjects - 6000.5 - win10
- agent:
- image: package-ci/win10:v4
- type: Unity::VM
- flavor: b1.large
- commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
- - command: 7z x -aoa wrench-localapv.zip
- - command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- - command: python PythonScripts/print_machine_info.py
- - command: unity-downloader-cli -u 6000.5/staging -c editor --path .Editor --fast
- timeout: 20
- retries: 3
- - command: upm-pvp create-test-project testproject --packages "upm-ci~/packages/*.tgz" --filter "com.unity.netcode.gameobjects com.unity.netcode.gameobjects.tests" --unity .Editor
- timeout: 10
- retries: 1
- - command: echo No internal packages to add.
- - command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp
- timeout: 40
- retries: 0
- - command: upm-pvp require "pkgprom-promote -PVP-29-2 rme" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
- timeout: 5
- retries: 0
- - command: upm-pvp require "rme PVP-160-1 supported" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
- timeout: 10
- retries: 0
- - command: 'UnifiedTestRunner.exe --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts --suite=Editor --suite=Playmode "--ff={ops.upmpvpevidence.enable=true}" '
- timeout: 40
- retries: 1
- after:
- - command: .yamato\generated-scripts\infrastructure-instability-detection-win.cmd
- artifacts:
- Crash Dumps:
- paths:
- - CrashDumps/**
- packages:
- paths:
- - upm-ci~/packages/**/*
- pvp-results:
- paths:
- - upm-ci~/pvp/**/*
- browsable: onDemand
- UTR:
- paths:
- - '*.log'
- - '*.xml'
- - artifacts/**/*
- - testproject/Logs/**
- - testproject/Library/*.log
- - testproject/*.log
- - testproject/Builds/*.log
- - build/test-results/**
- browsable: onDemand
- dependencies:
- - path: .yamato/wrench/package-pack-jobs.yml#package_pack_-_netcode_gameobjects
- variables:
- UNITY_LICENSING_SERVER_BASE_URL: http://unity-ci-licenses.hq.unity3d.com:8080/
- UNITY_LICENSING_SERVER_DELETE_NUL: 0
- UNITY_LICENSING_SERVER_DELETE_ULF: 0
- UNITY_LICENSING_SERVER_TOOLSET: pro
- UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
- metadata:
- Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
- labels:
- - Packages:netcode.gameobjects
-
-# PVP Editor and Playmode tests for Validate - netcode.gameobjects - 6000.6 - macos13 (6000.6 - MacOS).
-validate_-_netcode_gameobjects_-_6000_6_-_macos13:
- name: Validate - netcode.gameobjects - 6000.6 - macos13
- agent:
- image: package-ci/macos-13:v4
- type: Unity::VM::osx
- flavor: b1.xlarge
- commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
- - command: 7z x -aoa wrench-localapv.zip
- - command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- - command: python PythonScripts/print_machine_info.py
- - command: unity-downloader-cli -u trunk -c editor --path .Editor --fast
- timeout: 20
- retries: 3
- - command: upm-pvp create-test-project testproject --packages "upm-ci~/packages/*.tgz" --filter "com.unity.netcode.gameobjects com.unity.netcode.gameobjects.tests" --unity .Editor
- timeout: 10
- retries: 1
- - command: echo No internal packages to add.
- - command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp
- timeout: 40
- retries: 0
- - command: upm-pvp require "pkgprom-promote -PVP-29-2 rme" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
- timeout: 5
- retries: 0
- - command: upm-pvp require "rme PVP-160-1 supported" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
- timeout: 10
- retries: 0
- - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts --suite=Editor --suite=Playmode "--ff={ops.upmpvpevidence.enable=true}" '
+ - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/playmode --suite=playmode "--ff={ops.upmpvpevidence.enable=true}" '
timeout: 40
retries: 1
after:
@@ -909,10 +538,11 @@ validate_-_netcode_gameobjects_-_6000_6_-_macos13:
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
labels:
- Packages:netcode.gameobjects
@@ -924,11 +554,11 @@ validate_-_netcode_gameobjects_-_6000_6_-_ubuntu2204:
type: Unity::VM
flavor: b1.large
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "$WRENCH_LOCALAPV_URL" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
- - command: unity-downloader-cli -u trunk -c editor --path .Editor --fast
+ - command: unity-downloader-cli -u 6000.6/staging -c editor --path .Editor --fast
timeout: 20
retries: 3
- command: upm-pvp create-test-project testproject --packages "upm-ci~/packages/*.tgz" --filter "com.unity.netcode.gameobjects com.unity.netcode.gameobjects.tests" --unity .Editor
@@ -938,13 +568,19 @@ validate_-_netcode_gameobjects_-_6000_6_-_ubuntu2204:
- command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp
timeout: 40
retries: 0
+ - command: python PythonScripts/ignore_clean_console_failures.py
+ timeout: 5
+ retries: 0
- command: upm-pvp require "pkgprom-promote -PVP-29-2 rme" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 5
retries: 0
- command: upm-pvp require "rme PVP-160-1 supported" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 10
retries: 0
- - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts --suite=Editor --suite=Playmode "--ff={ops.upmpvpevidence.enable=true}" '
+ - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/editor --suite=editor "--ff={ops.upmpvpevidence.enable=true}" '
+ timeout: 40
+ retries: 1
+ - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/playmode --suite=playmode "--ff={ops.upmpvpevidence.enable=true}" '
timeout: 40
retries: 1
after:
@@ -979,10 +615,11 @@ validate_-_netcode_gameobjects_-_6000_6_-_ubuntu2204:
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
labels:
- Packages:netcode.gameobjects
@@ -994,11 +631,11 @@ validate_-_netcode_gameobjects_-_6000_6_-_win10:
type: Unity::VM
flavor: b1.large
commands:
- - command: curl https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-3_51b4e6affb4c10b90f92db9551b9dc80c5520794983600cff4fa925111db116d.zip -o wrench-localapv.zip
+ - command: curl "%WRENCH_LOCALAPV_URL%" -o wrench-localapv.zip
- command: 7z x -aoa wrench-localapv.zip
- command: pip install semver requests --index-url https://artifactory-slo.bf.unity3d.com/artifactory/api/pypi/pypi/simple
- command: python PythonScripts/print_machine_info.py
- - command: unity-downloader-cli -u trunk -c editor --path .Editor --fast
+ - command: unity-downloader-cli -u 6000.6/staging -c editor --path .Editor --fast
timeout: 20
retries: 3
- command: upm-pvp create-test-project testproject --packages "upm-ci~/packages/*.tgz" --filter "com.unity.netcode.gameobjects com.unity.netcode.gameobjects.tests" --unity .Editor
@@ -1008,13 +645,19 @@ validate_-_netcode_gameobjects_-_6000_6_-_win10:
- command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp
timeout: 40
retries: 0
+ - command: python PythonScripts/ignore_clean_console_failures.py
+ timeout: 5
+ retries: 0
- command: upm-pvp require "pkgprom-promote -PVP-29-2 rme" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 5
retries: 0
- command: upm-pvp require "rme PVP-160-1 supported" --results upm-ci~/pvp --exemptions upm-ci~/pvp/failures.json
timeout: 10
retries: 0
- - command: 'UnifiedTestRunner.exe --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts --suite=Editor --suite=Playmode "--ff={ops.upmpvpevidence.enable=true}" '
+ - command: 'UnifiedTestRunner.exe --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/editor --suite=editor "--ff={ops.upmpvpevidence.enable=true}" '
+ timeout: 40
+ retries: 1
+ - command: 'UnifiedTestRunner.exe --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/playmode --suite=playmode "--ff={ops.upmpvpevidence.enable=true}" '
timeout: 40
retries: 1
after:
@@ -1049,10 +692,11 @@ validate_-_netcode_gameobjects_-_6000_6_-_win10:
UNITY_LICENSING_SERVER_DELETE_ULF: 0
UNITY_LICENSING_SERVER_TOOLSET: pro
UPMPVP_ACK_UPMPVP_DOES_NO_API_VALIDATION: 1
- UPMPVP_CONTEXT_WRENCH: 2.7.0.0
+ UPMPVP_CONTEXT_WRENCH: 3.12.1.0
+ WRENCH_LOCALAPV_URL: https://artifactory.prd.it.unity3d.com/artifactory/stevedore-unity-internal/wrench-localapv/1-3-20_6ace78b5de8cf4671628832afa80f64bddc76883d89b9781fa19478b4bb33732.zip
metadata:
Job Maintainers: '#rm-packageworks'
- Wrench: 2.7.0.0
+ Wrench: 3.12.1.0
labels:
- Packages:netcode.gameobjects
diff --git a/.yamato/wrench/wrench_config.json b/.yamato/wrench/wrench_config.json
index 2d7eb092b2..b48ed0d37c 100644
--- a/.yamato/wrench/wrench_config.json
+++ b/.yamato/wrench/wrench_config.json
@@ -18,7 +18,7 @@
},
"InternalOnly": false,
"NeverPublish": false,
- "MaxEditorVersion": "",
+ "MaxEditorVersion": "6000.6",
"coverageEnabled": false,
"coverageCommands": [
"generateAdditionalMetrics;generateHtmlReport;assemblyFilters:ASSEMBLY_NAME;"
@@ -39,7 +39,7 @@
},
"publishing_job": ".yamato/wrench/promotion-jobs.yml#publish_netcode_gameobjects",
"branch_pattern": "ReleaseSlash",
- "wrench_version": "2.7.0.0",
+ "wrench_version": "3.12.1.0",
"pvp_exemption_path": ".yamato/wrench/pvp-exemptions.json",
"cs_project_path": "Tools/CI/NGO.Cookbook.csproj"
}
\ No newline at end of file
diff --git a/Examples/CharacterControllerMovingBodies/Packages/manifest.json b/Examples/CharacterControllerMovingBodies/Packages/manifest.json
index 0a8e3c4a4b..750ad11d6c 100644
--- a/Examples/CharacterControllerMovingBodies/Packages/manifest.json
+++ b/Examples/CharacterControllerMovingBodies/Packages/manifest.json
@@ -2,23 +2,23 @@
"dependencies": {
"com.unity.2d.sprite": "1.0.0",
"com.unity.2d.tilemap": "1.0.0",
- "com.unity.ads": "4.4.2",
- "com.unity.ai.navigation": "2.0.9",
+ "com.unity.ads": "4.16.4",
+ "com.unity.ai.navigation": "2.0.12",
"com.unity.analytics": "3.8.1",
- "com.unity.collab-proxy": "2.10.0",
+ "com.unity.collab-proxy": "2.12.4",
"com.unity.feature.development": "1.0.2",
- "com.unity.ide.rider": "3.0.38",
- "com.unity.ide.visualstudio": "2.0.25",
+ "com.unity.ide.rider": "3.0.39",
+ "com.unity.ide.visualstudio": "2.0.27",
"com.unity.multiplayer.center": "1.0.0",
"com.unity.netcode.gameobjects": "https://github.com/Unity-Technologies/com.unity.netcode.gameobjects.git?path=com.unity.netcode.gameobjects#develop-2.0.0",
- "com.unity.purchasing": "4.12.2",
+ "com.unity.purchasing": "4.14.2",
"com.unity.services.multiplayer": "1.2.0",
"com.unity.test-framework": "1.6.0",
- "com.unity.timeline": "1.8.9",
+ "com.unity.timeline": "1.8.10",
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.10",
- "com.unity.transport": "2.6.0",
+ "com.unity.transport": "2.7.2",
"com.unity.ugui": "2.0.0",
- "com.unity.visualscripting": "1.9.7",
+ "com.unity.visualscripting": "1.9.11",
"com.unity.xr.legacyinputhelpers": "2.1.12",
"com.unity.modules.accessibility": "1.0.0",
"com.unity.modules.ai": "1.0.0",
diff --git a/Examples/CharacterControllerMovingBodies/Packages/packages-lock.json b/Examples/CharacterControllerMovingBodies/Packages/packages-lock.json
deleted file mode 100644
index c19504fc77..0000000000
--- a/Examples/CharacterControllerMovingBodies/Packages/packages-lock.json
+++ /dev/null
@@ -1,643 +0,0 @@
-{
- "dependencies": {
- "com.unity.2d.sprite": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.2d.tilemap": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.tilemap": "1.0.0",
- "com.unity.modules.uielements": "1.0.0"
- }
- },
- "com.unity.ads": {
- "version": "4.4.2",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.ai.navigation": {
- "version": "2.0.9",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.modules.ai": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.analytics": {
- "version": "3.8.1",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0",
- "com.unity.services.analytics": "1.0.4"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.burst": {
- "version": "1.8.25",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.mathematics": "1.2.1",
- "com.unity.modules.jsonserialize": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.collab-proxy": {
- "version": "2.10.0",
- "depth": 0,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.collections": {
- "version": "2.6.2",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.burst": "1.8.23",
- "com.unity.mathematics": "1.3.2",
- "com.unity.test-framework": "1.4.6",
- "com.unity.nuget.mono-cecil": "1.11.5",
- "com.unity.test-framework.performance": "3.0.3"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.editorcoroutines": {
- "version": "1.0.1",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.ext.nunit": {
- "version": "2.0.5",
- "depth": 1,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.feature.development": {
- "version": "1.0.2",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.ide.visualstudio": "2.0.25",
- "com.unity.ide.rider": "3.0.38",
- "com.unity.editorcoroutines": "1.0.1",
- "com.unity.performance.profile-analyzer": "1.2.4",
- "com.unity.test-framework": "1.6.0",
- "com.unity.testtools.codecoverage": "1.2.7"
- }
- },
- "com.unity.ide.rider": {
- "version": "3.0.38",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.ext.nunit": "1.0.6"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.ide.visualstudio": {
- "version": "2.0.25",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.test-framework": "1.1.31"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.mathematics": {
- "version": "1.3.2",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.multiplayer.center": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.uielements": "1.0.0"
- }
- },
- "com.unity.netcode.gameobjects": {
- "version": "https://github.com/Unity-Technologies/com.unity.netcode.gameobjects.git?path=com.unity.netcode.gameobjects#develop-2.0.0",
- "depth": 0,
- "source": "git",
- "dependencies": {
- "com.unity.nuget.mono-cecil": "1.11.4",
- "com.unity.transport": "2.6.0"
- },
- "hash": "37bdf528127a9ae3e104d76b9a13343bffd653cb"
- },
- "com.unity.nuget.mono-cecil": {
- "version": "1.11.5",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.nuget.newtonsoft-json": {
- "version": "3.2.1",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.performance.profile-analyzer": {
- "version": "1.2.4",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.purchasing": {
- "version": "4.12.2",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0",
- "com.unity.services.core": "1.12.5",
- "com.unity.modules.androidjni": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0",
- "com.unity.modules.unitywebrequest": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.analytics": {
- "version": "6.1.0",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0",
- "com.unity.services.core": "1.12.4",
- "com.unity.modules.jsonserialize": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.authentication": {
- "version": "3.5.1",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0",
- "com.unity.services.core": "1.15.1",
- "com.unity.nuget.newtonsoft-json": "3.2.1",
- "com.unity.modules.unitywebrequest": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.core": {
- "version": "1.15.1",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.modules.androidjni": "1.0.0",
- "com.unity.nuget.newtonsoft-json": "3.2.1",
- "com.unity.modules.unitywebrequest": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.deployment": {
- "version": "1.6.2",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.services.core": "1.15.1",
- "com.unity.services.deployment.api": "1.1.2"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.deployment.api": {
- "version": "1.1.2",
- "depth": 2,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.services.multiplayer": {
- "version": "1.2.0",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.transport": "2.5.0",
- "com.unity.collections": "2.2.1",
- "com.unity.services.qos": "1.3.0",
- "com.unity.services.core": "1.15.1",
- "com.unity.services.wire": "1.4.0",
- "com.unity.services.deployment": "1.6.2",
- "com.unity.nuget.newtonsoft-json": "3.2.1",
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.services.authentication": "3.5.1"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.qos": {
- "version": "1.3.0",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.collections": "1.2.4",
- "com.unity.services.core": "1.12.4",
- "com.unity.nuget.newtonsoft-json": "3.0.2",
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.services.authentication": "2.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.wire": {
- "version": "1.4.0",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.services.core": "1.12.5",
- "com.unity.nuget.newtonsoft-json": "3.2.1",
- "com.unity.services.authentication": "2.7.4"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.settings-manager": {
- "version": "2.1.0",
- "depth": 2,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.sysroot": {
- "version": "2.0.10",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.sysroot.linux-x86_64": {
- "version": "2.0.9",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.sysroot": "2.0.10"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.test-framework": {
- "version": "1.6.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.ext.nunit": "2.0.3",
- "com.unity.modules.imgui": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0"
- }
- },
- "com.unity.test-framework.performance": {
- "version": "3.2.0",
- "depth": 2,
- "source": "registry",
- "dependencies": {
- "com.unity.test-framework": "1.1.33",
- "com.unity.modules.jsonserialize": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.testtools.codecoverage": {
- "version": "1.2.7",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.test-framework": "1.0.16",
- "com.unity.settings-manager": "1.0.1"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.timeline": {
- "version": "1.8.9",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.modules.audio": "1.0.0",
- "com.unity.modules.director": "1.0.0",
- "com.unity.modules.animation": "1.0.0",
- "com.unity.modules.particlesystem": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.toolchain.win-x86_64-linux-x86_64": {
- "version": "2.0.10",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.sysroot": "2.0.10",
- "com.unity.sysroot.linux-x86_64": "2.0.9"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.transport": {
- "version": "2.6.0",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.burst": "1.8.24",
- "com.unity.collections": "2.2.1",
- "com.unity.mathematics": "1.3.2"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.ugui": {
- "version": "2.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.ui": "1.0.0",
- "com.unity.modules.imgui": "1.0.0"
- }
- },
- "com.unity.visualscripting": {
- "version": "1.9.7",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.xr.legacyinputhelpers": {
- "version": "2.1.12",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.modules.vr": "1.0.0",
- "com.unity.modules.xr": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.modules.accessibility": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.ai": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.androidjni": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.animation": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.assetbundle": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.audio": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.cloth": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.physics": "1.0.0"
- }
- },
- "com.unity.modules.director": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.audio": "1.0.0",
- "com.unity.modules.animation": "1.0.0"
- }
- },
- "com.unity.modules.hierarchycore": {
- "version": "1.0.0",
- "depth": 1,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.imageconversion": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.imgui": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.jsonserialize": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.particlesystem": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.physics": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.physics2d": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.screencapture": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.imageconversion": "1.0.0"
- }
- },
- "com.unity.modules.subsystems": {
- "version": "1.0.0",
- "depth": 1,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.jsonserialize": "1.0.0"
- }
- },
- "com.unity.modules.terrain": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.terrainphysics": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.physics": "1.0.0",
- "com.unity.modules.terrain": "1.0.0"
- }
- },
- "com.unity.modules.tilemap": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.physics2d": "1.0.0"
- }
- },
- "com.unity.modules.ui": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.uielements": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.ui": "1.0.0",
- "com.unity.modules.imgui": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0",
- "com.unity.modules.hierarchycore": "1.0.0"
- }
- },
- "com.unity.modules.umbra": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.unityanalytics": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0"
- }
- },
- "com.unity.modules.unitywebrequest": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.unitywebrequestassetbundle": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.assetbundle": "1.0.0",
- "com.unity.modules.unitywebrequest": "1.0.0"
- }
- },
- "com.unity.modules.unitywebrequestaudio": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.modules.audio": "1.0.0"
- }
- },
- "com.unity.modules.unitywebrequesttexture": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.modules.imageconversion": "1.0.0"
- }
- },
- "com.unity.modules.unitywebrequestwww": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.modules.unitywebrequestassetbundle": "1.0.0",
- "com.unity.modules.unitywebrequestaudio": "1.0.0",
- "com.unity.modules.audio": "1.0.0",
- "com.unity.modules.assetbundle": "1.0.0",
- "com.unity.modules.imageconversion": "1.0.0"
- }
- },
- "com.unity.modules.vehicles": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.physics": "1.0.0"
- }
- },
- "com.unity.modules.video": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.audio": "1.0.0",
- "com.unity.modules.ui": "1.0.0",
- "com.unity.modules.unitywebrequest": "1.0.0"
- }
- },
- "com.unity.modules.vr": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.jsonserialize": "1.0.0",
- "com.unity.modules.physics": "1.0.0",
- "com.unity.modules.xr": "1.0.0"
- }
- },
- "com.unity.modules.wind": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.xr": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.physics": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0",
- "com.unity.modules.subsystems": "1.0.0"
- }
- }
- }
-}
diff --git a/Examples/CharacterControllerMovingBodies/ProjectSettings/ProjectVersion.txt b/Examples/CharacterControllerMovingBodies/ProjectSettings/ProjectVersion.txt
index 47df254537..ba577c5bf5 100644
--- a/Examples/CharacterControllerMovingBodies/ProjectSettings/ProjectVersion.txt
+++ b/Examples/CharacterControllerMovingBodies/ProjectSettings/ProjectVersion.txt
@@ -1,2 +1,2 @@
-m_EditorVersion: 6000.0.61f1
-m_EditorVersionWithRevision: 6000.0.61f1 (74a0adb02c31)
+m_EditorVersion: 6000.0.72f1
+m_EditorVersionWithRevision: 6000.0.72f1 (b731fd3ae857)
diff --git a/Examples/OverridingScenesAndPrefabs/Packages/manifest.json b/Examples/OverridingScenesAndPrefabs/Packages/manifest.json
index 0a8e3c4a4b..750ad11d6c 100644
--- a/Examples/OverridingScenesAndPrefabs/Packages/manifest.json
+++ b/Examples/OverridingScenesAndPrefabs/Packages/manifest.json
@@ -2,23 +2,23 @@
"dependencies": {
"com.unity.2d.sprite": "1.0.0",
"com.unity.2d.tilemap": "1.0.0",
- "com.unity.ads": "4.4.2",
- "com.unity.ai.navigation": "2.0.9",
+ "com.unity.ads": "4.16.4",
+ "com.unity.ai.navigation": "2.0.12",
"com.unity.analytics": "3.8.1",
- "com.unity.collab-proxy": "2.10.0",
+ "com.unity.collab-proxy": "2.12.4",
"com.unity.feature.development": "1.0.2",
- "com.unity.ide.rider": "3.0.38",
- "com.unity.ide.visualstudio": "2.0.25",
+ "com.unity.ide.rider": "3.0.39",
+ "com.unity.ide.visualstudio": "2.0.27",
"com.unity.multiplayer.center": "1.0.0",
"com.unity.netcode.gameobjects": "https://github.com/Unity-Technologies/com.unity.netcode.gameobjects.git?path=com.unity.netcode.gameobjects#develop-2.0.0",
- "com.unity.purchasing": "4.12.2",
+ "com.unity.purchasing": "4.14.2",
"com.unity.services.multiplayer": "1.2.0",
"com.unity.test-framework": "1.6.0",
- "com.unity.timeline": "1.8.9",
+ "com.unity.timeline": "1.8.10",
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.10",
- "com.unity.transport": "2.6.0",
+ "com.unity.transport": "2.7.2",
"com.unity.ugui": "2.0.0",
- "com.unity.visualscripting": "1.9.7",
+ "com.unity.visualscripting": "1.9.11",
"com.unity.xr.legacyinputhelpers": "2.1.12",
"com.unity.modules.accessibility": "1.0.0",
"com.unity.modules.ai": "1.0.0",
diff --git a/Examples/OverridingScenesAndPrefabs/Packages/packages-lock.json b/Examples/OverridingScenesAndPrefabs/Packages/packages-lock.json
deleted file mode 100644
index c19504fc77..0000000000
--- a/Examples/OverridingScenesAndPrefabs/Packages/packages-lock.json
+++ /dev/null
@@ -1,643 +0,0 @@
-{
- "dependencies": {
- "com.unity.2d.sprite": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.2d.tilemap": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.tilemap": "1.0.0",
- "com.unity.modules.uielements": "1.0.0"
- }
- },
- "com.unity.ads": {
- "version": "4.4.2",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.ai.navigation": {
- "version": "2.0.9",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.modules.ai": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.analytics": {
- "version": "3.8.1",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0",
- "com.unity.services.analytics": "1.0.4"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.burst": {
- "version": "1.8.25",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.mathematics": "1.2.1",
- "com.unity.modules.jsonserialize": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.collab-proxy": {
- "version": "2.10.0",
- "depth": 0,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.collections": {
- "version": "2.6.2",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.burst": "1.8.23",
- "com.unity.mathematics": "1.3.2",
- "com.unity.test-framework": "1.4.6",
- "com.unity.nuget.mono-cecil": "1.11.5",
- "com.unity.test-framework.performance": "3.0.3"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.editorcoroutines": {
- "version": "1.0.1",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.ext.nunit": {
- "version": "2.0.5",
- "depth": 1,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.feature.development": {
- "version": "1.0.2",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.ide.visualstudio": "2.0.25",
- "com.unity.ide.rider": "3.0.38",
- "com.unity.editorcoroutines": "1.0.1",
- "com.unity.performance.profile-analyzer": "1.2.4",
- "com.unity.test-framework": "1.6.0",
- "com.unity.testtools.codecoverage": "1.2.7"
- }
- },
- "com.unity.ide.rider": {
- "version": "3.0.38",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.ext.nunit": "1.0.6"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.ide.visualstudio": {
- "version": "2.0.25",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.test-framework": "1.1.31"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.mathematics": {
- "version": "1.3.2",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.multiplayer.center": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.uielements": "1.0.0"
- }
- },
- "com.unity.netcode.gameobjects": {
- "version": "https://github.com/Unity-Technologies/com.unity.netcode.gameobjects.git?path=com.unity.netcode.gameobjects#develop-2.0.0",
- "depth": 0,
- "source": "git",
- "dependencies": {
- "com.unity.nuget.mono-cecil": "1.11.4",
- "com.unity.transport": "2.6.0"
- },
- "hash": "37bdf528127a9ae3e104d76b9a13343bffd653cb"
- },
- "com.unity.nuget.mono-cecil": {
- "version": "1.11.5",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.nuget.newtonsoft-json": {
- "version": "3.2.1",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.performance.profile-analyzer": {
- "version": "1.2.4",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.purchasing": {
- "version": "4.12.2",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0",
- "com.unity.services.core": "1.12.5",
- "com.unity.modules.androidjni": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0",
- "com.unity.modules.unitywebrequest": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.analytics": {
- "version": "6.1.0",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0",
- "com.unity.services.core": "1.12.4",
- "com.unity.modules.jsonserialize": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.authentication": {
- "version": "3.5.1",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0",
- "com.unity.services.core": "1.15.1",
- "com.unity.nuget.newtonsoft-json": "3.2.1",
- "com.unity.modules.unitywebrequest": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.core": {
- "version": "1.15.1",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.modules.androidjni": "1.0.0",
- "com.unity.nuget.newtonsoft-json": "3.2.1",
- "com.unity.modules.unitywebrequest": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.deployment": {
- "version": "1.6.2",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.services.core": "1.15.1",
- "com.unity.services.deployment.api": "1.1.2"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.deployment.api": {
- "version": "1.1.2",
- "depth": 2,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.services.multiplayer": {
- "version": "1.2.0",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.transport": "2.5.0",
- "com.unity.collections": "2.2.1",
- "com.unity.services.qos": "1.3.0",
- "com.unity.services.core": "1.15.1",
- "com.unity.services.wire": "1.4.0",
- "com.unity.services.deployment": "1.6.2",
- "com.unity.nuget.newtonsoft-json": "3.2.1",
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.services.authentication": "3.5.1"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.qos": {
- "version": "1.3.0",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.collections": "1.2.4",
- "com.unity.services.core": "1.12.4",
- "com.unity.nuget.newtonsoft-json": "3.0.2",
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.services.authentication": "2.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.wire": {
- "version": "1.4.0",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.services.core": "1.12.5",
- "com.unity.nuget.newtonsoft-json": "3.2.1",
- "com.unity.services.authentication": "2.7.4"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.settings-manager": {
- "version": "2.1.0",
- "depth": 2,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.sysroot": {
- "version": "2.0.10",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.sysroot.linux-x86_64": {
- "version": "2.0.9",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.sysroot": "2.0.10"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.test-framework": {
- "version": "1.6.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.ext.nunit": "2.0.3",
- "com.unity.modules.imgui": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0"
- }
- },
- "com.unity.test-framework.performance": {
- "version": "3.2.0",
- "depth": 2,
- "source": "registry",
- "dependencies": {
- "com.unity.test-framework": "1.1.33",
- "com.unity.modules.jsonserialize": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.testtools.codecoverage": {
- "version": "1.2.7",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.test-framework": "1.0.16",
- "com.unity.settings-manager": "1.0.1"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.timeline": {
- "version": "1.8.9",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.modules.audio": "1.0.0",
- "com.unity.modules.director": "1.0.0",
- "com.unity.modules.animation": "1.0.0",
- "com.unity.modules.particlesystem": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.toolchain.win-x86_64-linux-x86_64": {
- "version": "2.0.10",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.sysroot": "2.0.10",
- "com.unity.sysroot.linux-x86_64": "2.0.9"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.transport": {
- "version": "2.6.0",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.burst": "1.8.24",
- "com.unity.collections": "2.2.1",
- "com.unity.mathematics": "1.3.2"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.ugui": {
- "version": "2.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.ui": "1.0.0",
- "com.unity.modules.imgui": "1.0.0"
- }
- },
- "com.unity.visualscripting": {
- "version": "1.9.7",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.xr.legacyinputhelpers": {
- "version": "2.1.12",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.modules.vr": "1.0.0",
- "com.unity.modules.xr": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.modules.accessibility": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.ai": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.androidjni": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.animation": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.assetbundle": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.audio": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.cloth": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.physics": "1.0.0"
- }
- },
- "com.unity.modules.director": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.audio": "1.0.0",
- "com.unity.modules.animation": "1.0.0"
- }
- },
- "com.unity.modules.hierarchycore": {
- "version": "1.0.0",
- "depth": 1,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.imageconversion": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.imgui": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.jsonserialize": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.particlesystem": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.physics": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.physics2d": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.screencapture": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.imageconversion": "1.0.0"
- }
- },
- "com.unity.modules.subsystems": {
- "version": "1.0.0",
- "depth": 1,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.jsonserialize": "1.0.0"
- }
- },
- "com.unity.modules.terrain": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.terrainphysics": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.physics": "1.0.0",
- "com.unity.modules.terrain": "1.0.0"
- }
- },
- "com.unity.modules.tilemap": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.physics2d": "1.0.0"
- }
- },
- "com.unity.modules.ui": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.uielements": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.ui": "1.0.0",
- "com.unity.modules.imgui": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0",
- "com.unity.modules.hierarchycore": "1.0.0"
- }
- },
- "com.unity.modules.umbra": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.unityanalytics": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0"
- }
- },
- "com.unity.modules.unitywebrequest": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.unitywebrequestassetbundle": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.assetbundle": "1.0.0",
- "com.unity.modules.unitywebrequest": "1.0.0"
- }
- },
- "com.unity.modules.unitywebrequestaudio": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.modules.audio": "1.0.0"
- }
- },
- "com.unity.modules.unitywebrequesttexture": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.modules.imageconversion": "1.0.0"
- }
- },
- "com.unity.modules.unitywebrequestwww": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.modules.unitywebrequestassetbundle": "1.0.0",
- "com.unity.modules.unitywebrequestaudio": "1.0.0",
- "com.unity.modules.audio": "1.0.0",
- "com.unity.modules.assetbundle": "1.0.0",
- "com.unity.modules.imageconversion": "1.0.0"
- }
- },
- "com.unity.modules.vehicles": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.physics": "1.0.0"
- }
- },
- "com.unity.modules.video": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.audio": "1.0.0",
- "com.unity.modules.ui": "1.0.0",
- "com.unity.modules.unitywebrequest": "1.0.0"
- }
- },
- "com.unity.modules.vr": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.jsonserialize": "1.0.0",
- "com.unity.modules.physics": "1.0.0",
- "com.unity.modules.xr": "1.0.0"
- }
- },
- "com.unity.modules.wind": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.xr": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.physics": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0",
- "com.unity.modules.subsystems": "1.0.0"
- }
- }
- }
-}
diff --git a/Examples/OverridingScenesAndPrefabs/ProjectSettings/ProjectVersion.txt b/Examples/OverridingScenesAndPrefabs/ProjectSettings/ProjectVersion.txt
index 47df254537..ba577c5bf5 100644
--- a/Examples/OverridingScenesAndPrefabs/ProjectSettings/ProjectVersion.txt
+++ b/Examples/OverridingScenesAndPrefabs/ProjectSettings/ProjectVersion.txt
@@ -1,2 +1,2 @@
-m_EditorVersion: 6000.0.61f1
-m_EditorVersionWithRevision: 6000.0.61f1 (74a0adb02c31)
+m_EditorVersion: 6000.0.72f1
+m_EditorVersionWithRevision: 6000.0.72f1 (b731fd3ae857)
diff --git a/Examples/PingTool/Packages/manifest.json b/Examples/PingTool/Packages/manifest.json
index 0c5e1bb258..b1e4adc52f 100644
--- a/Examples/PingTool/Packages/manifest.json
+++ b/Examples/PingTool/Packages/manifest.json
@@ -2,25 +2,25 @@
"dependencies": {
"com.unity.2d.sprite": "1.0.0",
"com.unity.2d.tilemap": "1.0.0",
- "com.unity.ads": "4.4.2",
- "com.unity.ai.navigation": "2.0.9",
+ "com.unity.ads": "4.16.4",
+ "com.unity.ai.navigation": "2.0.12",
"com.unity.analytics": "3.8.1",
- "com.unity.collab-proxy": "2.10.0",
+ "com.unity.collab-proxy": "2.12.4",
"com.unity.feature.development": "1.0.2",
- "com.unity.ide.rider": "3.0.38",
- "com.unity.ide.visualstudio": "2.0.25",
+ "com.unity.ide.rider": "3.0.39",
+ "com.unity.ide.visualstudio": "2.0.27",
"com.unity.multiplayer.center": "1.0.0",
- "com.unity.multiplayer.playmode": "1.6.1",
- "com.unity.multiplayer.tools": "2.2.6",
+ "com.unity.multiplayer.playmode": "1.6.3",
+ "com.unity.multiplayer.tools": "2.2.8",
"com.unity.netcode.gameobjects": "https://github.com/Unity-Technologies/com.unity.netcode.gameobjects.git?path=com.unity.netcode.gameobjects#develop-2.0.0",
- "com.unity.purchasing": "4.12.2",
+ "com.unity.purchasing": "4.14.2",
"com.unity.services.multiplayer": "1.2.0",
"com.unity.test-framework": "1.6.0",
- "com.unity.timeline": "1.8.9",
+ "com.unity.timeline": "1.8.10",
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.10",
- "com.unity.transport": "2.6.0",
+ "com.unity.transport": "2.7.2",
"com.unity.ugui": "2.0.0",
- "com.unity.visualscripting": "1.9.7",
+ "com.unity.visualscripting": "1.9.11",
"com.unity.xr.legacyinputhelpers": "2.1.12",
"com.unity.modules.accessibility": "1.0.0",
"com.unity.modules.ai": "1.0.0",
diff --git a/Examples/PingTool/Packages/packages-lock.json b/Examples/PingTool/Packages/packages-lock.json
deleted file mode 100644
index f76bd76778..0000000000
--- a/Examples/PingTool/Packages/packages-lock.json
+++ /dev/null
@@ -1,674 +0,0 @@
-{
- "dependencies": {
- "com.unity.2d.sprite": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.2d.tilemap": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.tilemap": "1.0.0",
- "com.unity.modules.uielements": "1.0.0"
- }
- },
- "com.unity.ads": {
- "version": "4.4.2",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.ai.navigation": {
- "version": "2.0.9",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.modules.ai": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.analytics": {
- "version": "3.8.1",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0",
- "com.unity.services.analytics": "1.0.4"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.burst": {
- "version": "1.8.25",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.mathematics": "1.2.1",
- "com.unity.modules.jsonserialize": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.collab-proxy": {
- "version": "2.10.0",
- "depth": 0,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.collections": {
- "version": "2.6.2",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.burst": "1.8.23",
- "com.unity.mathematics": "1.3.2",
- "com.unity.test-framework": "1.4.6",
- "com.unity.nuget.mono-cecil": "1.11.5",
- "com.unity.test-framework.performance": "3.0.3"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.editorcoroutines": {
- "version": "1.0.1",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.ext.nunit": {
- "version": "2.0.5",
- "depth": 1,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.feature.development": {
- "version": "1.0.2",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.ide.visualstudio": "2.0.25",
- "com.unity.ide.rider": "3.0.38",
- "com.unity.editorcoroutines": "1.0.1",
- "com.unity.performance.profile-analyzer": "1.2.4",
- "com.unity.test-framework": "1.6.0",
- "com.unity.testtools.codecoverage": "1.2.7"
- }
- },
- "com.unity.ide.rider": {
- "version": "3.0.38",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.ext.nunit": "1.0.6"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.ide.visualstudio": {
- "version": "2.0.25",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.test-framework": "1.1.31"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.mathematics": {
- "version": "1.3.2",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.multiplayer.center": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.uielements": "1.0.0"
- }
- },
- "com.unity.multiplayer.playmode": {
- "version": "1.6.1",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.nuget.newtonsoft-json": "2.0.2"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.multiplayer.tools": {
- "version": "2.2.6",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.burst": "1.8.18",
- "com.unity.collections": "2.5.1",
- "com.unity.mathematics": "1.3.2",
- "com.unity.profiling.core": "1.0.2",
- "com.unity.nuget.mono-cecil": "1.11.4",
- "com.unity.modules.uielements": "1.0.0",
- "com.unity.nuget.newtonsoft-json": "3.2.1"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.netcode.gameobjects": {
- "version": "https://github.com/Unity-Technologies/com.unity.netcode.gameobjects.git?path=com.unity.netcode.gameobjects#develop-2.0.0",
- "depth": 0,
- "source": "git",
- "dependencies": {
- "com.unity.nuget.mono-cecil": "1.11.4",
- "com.unity.transport": "2.6.0"
- },
- "hash": "37bdf528127a9ae3e104d76b9a13343bffd653cb"
- },
- "com.unity.nuget.mono-cecil": {
- "version": "1.11.5",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.nuget.newtonsoft-json": {
- "version": "3.2.1",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.performance.profile-analyzer": {
- "version": "1.2.4",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.profiling.core": {
- "version": "1.0.2",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.purchasing": {
- "version": "4.12.2",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0",
- "com.unity.services.core": "1.12.5",
- "com.unity.modules.androidjni": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0",
- "com.unity.modules.unitywebrequest": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.analytics": {
- "version": "6.1.0",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0",
- "com.unity.services.core": "1.12.4",
- "com.unity.modules.jsonserialize": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.authentication": {
- "version": "3.5.1",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0",
- "com.unity.services.core": "1.15.1",
- "com.unity.nuget.newtonsoft-json": "3.2.1",
- "com.unity.modules.unitywebrequest": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.core": {
- "version": "1.15.1",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.modules.androidjni": "1.0.0",
- "com.unity.nuget.newtonsoft-json": "3.2.1",
- "com.unity.modules.unitywebrequest": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.deployment": {
- "version": "1.6.2",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.services.core": "1.15.1",
- "com.unity.services.deployment.api": "1.1.2"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.deployment.api": {
- "version": "1.1.2",
- "depth": 2,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.services.multiplayer": {
- "version": "1.2.0",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.transport": "2.5.0",
- "com.unity.collections": "2.2.1",
- "com.unity.services.qos": "1.3.0",
- "com.unity.services.core": "1.15.1",
- "com.unity.services.wire": "1.4.0",
- "com.unity.services.deployment": "1.6.2",
- "com.unity.nuget.newtonsoft-json": "3.2.1",
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.services.authentication": "3.5.1"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.qos": {
- "version": "1.3.0",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.collections": "1.2.4",
- "com.unity.services.core": "1.12.4",
- "com.unity.nuget.newtonsoft-json": "3.0.2",
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.services.authentication": "2.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.services.wire": {
- "version": "1.4.0",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.services.core": "1.12.5",
- "com.unity.nuget.newtonsoft-json": "3.2.1",
- "com.unity.services.authentication": "2.7.4"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.settings-manager": {
- "version": "2.1.0",
- "depth": 2,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.sysroot": {
- "version": "2.0.10",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
- "com.unity.sysroot.linux-x86_64": {
- "version": "2.0.9",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.sysroot": "2.0.10"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.test-framework": {
- "version": "1.6.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.ext.nunit": "2.0.3",
- "com.unity.modules.imgui": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0"
- }
- },
- "com.unity.test-framework.performance": {
- "version": "3.2.0",
- "depth": 2,
- "source": "registry",
- "dependencies": {
- "com.unity.test-framework": "1.1.33",
- "com.unity.modules.jsonserialize": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.testtools.codecoverage": {
- "version": "1.2.7",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.test-framework": "1.0.16",
- "com.unity.settings-manager": "1.0.1"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.timeline": {
- "version": "1.8.9",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.modules.audio": "1.0.0",
- "com.unity.modules.director": "1.0.0",
- "com.unity.modules.animation": "1.0.0",
- "com.unity.modules.particlesystem": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.toolchain.win-x86_64-linux-x86_64": {
- "version": "2.0.10",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.sysroot": "2.0.10",
- "com.unity.sysroot.linux-x86_64": "2.0.9"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.transport": {
- "version": "2.6.0",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.burst": "1.8.24",
- "com.unity.collections": "2.2.1",
- "com.unity.mathematics": "1.3.2"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.ugui": {
- "version": "2.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.ui": "1.0.0",
- "com.unity.modules.imgui": "1.0.0"
- }
- },
- "com.unity.visualscripting": {
- "version": "1.9.7",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.ugui": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.xr.legacyinputhelpers": {
- "version": "2.1.12",
- "depth": 0,
- "source": "registry",
- "dependencies": {
- "com.unity.modules.vr": "1.0.0",
- "com.unity.modules.xr": "1.0.0"
- },
- "url": "https://packages.unity.com"
- },
- "com.unity.modules.accessibility": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.ai": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.androidjni": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.animation": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.assetbundle": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.audio": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.cloth": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.physics": "1.0.0"
- }
- },
- "com.unity.modules.director": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.audio": "1.0.0",
- "com.unity.modules.animation": "1.0.0"
- }
- },
- "com.unity.modules.hierarchycore": {
- "version": "1.0.0",
- "depth": 1,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.imageconversion": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.imgui": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.jsonserialize": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.particlesystem": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.physics": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.physics2d": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.screencapture": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.imageconversion": "1.0.0"
- }
- },
- "com.unity.modules.subsystems": {
- "version": "1.0.0",
- "depth": 1,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.jsonserialize": "1.0.0"
- }
- },
- "com.unity.modules.terrain": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.terrainphysics": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.physics": "1.0.0",
- "com.unity.modules.terrain": "1.0.0"
- }
- },
- "com.unity.modules.tilemap": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.physics2d": "1.0.0"
- }
- },
- "com.unity.modules.ui": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.uielements": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.ui": "1.0.0",
- "com.unity.modules.imgui": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0",
- "com.unity.modules.hierarchycore": "1.0.0"
- }
- },
- "com.unity.modules.umbra": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.unityanalytics": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0"
- }
- },
- "com.unity.modules.unitywebrequest": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.unitywebrequestassetbundle": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.assetbundle": "1.0.0",
- "com.unity.modules.unitywebrequest": "1.0.0"
- }
- },
- "com.unity.modules.unitywebrequestaudio": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.modules.audio": "1.0.0"
- }
- },
- "com.unity.modules.unitywebrequesttexture": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.modules.imageconversion": "1.0.0"
- }
- },
- "com.unity.modules.unitywebrequestwww": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.unitywebrequest": "1.0.0",
- "com.unity.modules.unitywebrequestassetbundle": "1.0.0",
- "com.unity.modules.unitywebrequestaudio": "1.0.0",
- "com.unity.modules.audio": "1.0.0",
- "com.unity.modules.assetbundle": "1.0.0",
- "com.unity.modules.imageconversion": "1.0.0"
- }
- },
- "com.unity.modules.vehicles": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.physics": "1.0.0"
- }
- },
- "com.unity.modules.video": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.audio": "1.0.0",
- "com.unity.modules.ui": "1.0.0",
- "com.unity.modules.unitywebrequest": "1.0.0"
- }
- },
- "com.unity.modules.vr": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.jsonserialize": "1.0.0",
- "com.unity.modules.physics": "1.0.0",
- "com.unity.modules.xr": "1.0.0"
- }
- },
- "com.unity.modules.wind": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {}
- },
- "com.unity.modules.xr": {
- "version": "1.0.0",
- "depth": 0,
- "source": "builtin",
- "dependencies": {
- "com.unity.modules.physics": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0",
- "com.unity.modules.subsystems": "1.0.0"
- }
- }
- }
-}
diff --git a/Examples/PingTool/ProjectSettings/ProjectVersion.txt b/Examples/PingTool/ProjectSettings/ProjectVersion.txt
index 47df254537..ba577c5bf5 100644
--- a/Examples/PingTool/ProjectSettings/ProjectVersion.txt
+++ b/Examples/PingTool/ProjectSettings/ProjectVersion.txt
@@ -1,2 +1,2 @@
-m_EditorVersion: 6000.0.61f1
-m_EditorVersionWithRevision: 6000.0.61f1 (74a0adb02c31)
+m_EditorVersion: 6000.0.72f1
+m_EditorVersionWithRevision: 6000.0.72f1 (b731fd3ae857)
diff --git a/Examples/PingTool/ProjectSettings/VirtualProjectsConfig.json b/Examples/PingTool/ProjectSettings/VirtualProjectsConfig.json
index 4ea16eb5a7..602c3b1ec3 100644
--- a/Examples/PingTool/ProjectSettings/VirtualProjectsConfig.json
+++ b/Examples/PingTool/ProjectSettings/VirtualProjectsConfig.json
@@ -1,4 +1,4 @@
{
"PlayerTags": [],
- "version": "1.6.1"
+ "version": "1.6.3"
}
\ No newline at end of file
diff --git a/Tools/CI/NGO.Cookbook.csproj b/Tools/CI/NGO.Cookbook.csproj
index aa420f1382..9296598611 100644
--- a/Tools/CI/NGO.Cookbook.csproj
+++ b/Tools/CI/NGO.Cookbook.csproj
@@ -8,11 +8,16 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/Tools/CI/Program.cs b/Tools/CI/Program.cs
index 176215bdff..913e04d496 100644
--- a/Tools/CI/Program.cs
+++ b/Tools/CI/Program.cs
@@ -1,5 +1,6 @@
using NGO.Cookbook.Settings;
using RecipeEngine;
+using RecipeEngine.Modules.BuildAutomation;
using RecipeEngine.Modules.Wrench.Helpers;
@@ -8,13 +9,15 @@ public static class Program
{
public static int Main(string[] args)
{
- var settings = new NGOSettings();
+ var settings = new NgoWrenchSettings();
+ var buildAutomationSettings = new NgoBuildAutomationSettings();
// ReSharper disable once UnusedVariable
var engine = EngineFactory
.Create()
.ScanAll()
.WithWrenchModule(settings.Wrench)
+ .WithBuildAutomation(buildAutomationSettings.BuildAutomation)
.GenerateAsync().Result;
return engine;
}
diff --git a/Tools/CI/Settings/NgoBuildAutomationSettings.cs b/Tools/CI/Settings/NgoBuildAutomationSettings.cs
new file mode 100644
index 0000000000..a81474cdcd
--- /dev/null
+++ b/Tools/CI/Settings/NgoBuildAutomationSettings.cs
@@ -0,0 +1,40 @@
+using System.Collections.Generic;
+using RecipeEngine.Modules.BuildAutomation.Models;
+using RecipeEngine.Modules.BuildAutomation.Settings;
+
+namespace NGO.Cookbook.Settings
+{
+ public class NgoBuildAutomationSettings
+ {
+ public NgoBuildAutomationSettings()
+ {
+ BuildAutomation = new BuildAutomationSettings(
+ projects: new Dictionary
+ {
+ ["BossRoom"] = new(
+ GithubRepo: "https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop.git",
+ ProjectPath: ".",
+ DefaultSampleBranch: "ngo-playtest-update",
+ MinSupportedEditorBySample: "6000.3",
+ LocalTestedPackagesNames: new[] { "com.unity.netcode.gameobjects" },
+ LocalTestedPackagesPath: "."),
+ ["Asteroids"] = new(
+ GithubRepo: "https://github.cds.internal.unity3d.com/unity/Asteroids-CMB-NGO-Sample.git",
+ ProjectPath: ".",
+ DefaultSampleBranch: "main",
+ MinSupportedEditorBySample: "6000.3",
+ LocalTestedPackagesNames: new[] { "com.unity.netcode.gameobjects" },
+ LocalTestedPackagesPath: "."),
+ ["SocialHub"] = new(
+ GithubRepo: "https://github.com/Unity-Technologies/com.unity.multiplayer.samples.bitesize.git",
+ ProjectPath: "Basic/DistributedAuthoritySocialHub",
+ DefaultSampleBranch: "main",
+ MinSupportedEditorBySample: "6000.0",
+ LocalTestedPackagesNames: new[] { "com.unity.netcode.gameobjects" },
+ LocalTestedPackagesPath: "."),
+ });
+ }
+
+ public BuildAutomationSettings BuildAutomation { get; }
+ }
+}
diff --git a/Tools/CI/Settings/NGOSettings.cs b/Tools/CI/Settings/NgoWrenchSettings.cs
similarity index 84%
rename from Tools/CI/Settings/NGOSettings.cs
rename to Tools/CI/Settings/NgoWrenchSettings.cs
index aab47ee96b..a82cd79895 100644
--- a/Tools/CI/Settings/NGOSettings.cs
+++ b/Tools/CI/Settings/NgoWrenchSettings.cs
@@ -5,7 +5,7 @@
namespace NGO.Cookbook.Settings;
-public class NGOSettings : AnnotatedSettingsBase
+public class NgoWrenchSettings : AnnotatedSettingsBase
{
// Path from the root of the repository where packages are located.
readonly string[] packagesRootPaths = {"."};
@@ -24,12 +24,13 @@ public class NGOSettings : AnnotatedSettingsBase
new PackageOptions()
{
ReleaseOptions = new ReleaseOptions() { IsReleasing = true },
+ MaximumEditorVersion = "6000.6", // NGOv2.X will be deprecated in 6000.7+ so we won't run tests on higher editor versions
ValidationOptions = validationOptions
}
}
};
- public NGOSettings()
+ public NgoWrenchSettings()
{
Wrench = new WrenchSettings(packagesRootPaths, PackageOptions);
Wrench.PvpProfilesToCheck = new HashSet() { "supported" };
diff --git a/Tools/CI/scripts/BuildAutomation/BuilderScripts.cs b/Tools/CI/scripts/BuildAutomation/BuilderScripts.cs
new file mode 100644
index 0000000000..646a31d06f
--- /dev/null
+++ b/Tools/CI/scripts/BuildAutomation/BuilderScripts.cs
@@ -0,0 +1,164 @@
+///////////////////////////////////////////////////////////////////////////////
+// Auto-generated by RecipeEngine.Modules.BuildAutomation. DO NOT EDIT. //
+// You may override this file locally, but any changes will be overwritten //
+// the next time CI is regenerated. Permanent fixes must be made inside: //
+// RecipeEngine.Modules.BuildAutomation/EmbeddedScripts/ //
+///////////////////////////////////////////////////////////////////////////////
+
+using System;
+using System.Linq;
+using UnityEditor;
+using UnityEditor.Build;
+using UnityEngine;
+using UnityEngine.Rendering;
+
+///
+/// Main build script materialized into the sample project. It builds the player with ALL and ONLY the enabled
+/// scenes; to build a different scene set, branch off in the sample repo and clone from that branch.
+///
+public class BuilderScripts : MonoBehaviour
+{
+ static string[] GetEnabledScenes()
+ {
+ return EditorBuildSettings.scenes
+ .Where(scene => scene.enabled)
+ .Select(scene => scene.path)
+ .ToArray();
+ }
+
+ static void BuildPlayer(BuildConfig config)
+ {
+ PlayerSettings.SetScriptingBackend(config.NamedBuildTarget, config.ScriptingBackend);
+
+ if (config.GraphicsApis != null && config.GraphicsApis.Length > 0)
+ {
+ PlayerSettings.SetUseDefaultGraphicsAPIs(config.BuildTarget, false);
+ PlayerSettings.SetGraphicsAPIs(config.BuildTarget, config.GraphicsApis);
+ }
+
+ if (config.ApplicationId != null)
+ PlayerSettings.SetApplicationIdentifier(config.NamedBuildTarget, config.ApplicationId);
+
+ if (config.Architecture.HasValue)
+ PlayerSettings.SetArchitecture(config.NamedBuildTarget, config.Architecture.Value);
+
+ AssetDatabase.SaveAssets();
+
+ var buildOptions = new BuildPlayerOptions
+ {
+ locationPathName = config.OutputPath,
+ target = config.BuildTarget,
+ options = BuildOptions.Development,
+ scenes = GetEnabledScenes()
+ };
+
+ BuildPipeline.BuildPlayer(buildOptions);
+ }
+
+ struct BuildConfig
+ {
+ public NamedBuildTarget NamedBuildTarget;
+ public ScriptingImplementation ScriptingBackend;
+ public BuildTarget BuildTarget;
+ public GraphicsDeviceType[] GraphicsApis;
+ public string OutputPath;
+ // Not 'string?': materialized into projects with nullable disabled, where that annotation is a hard CS8632 error.
+ public string ApplicationId;
+ public int? Architecture;
+ }
+
+ [MenuItem("Tools/Builder/Build Development Windows Il2cpp")]
+ static void BuildWinIl2cpp() => BuildPlayer(new BuildConfig
+ {
+ NamedBuildTarget = NamedBuildTarget.Standalone,
+ ScriptingBackend = ScriptingImplementation.IL2CPP,
+ BuildTarget = BuildTarget.StandaloneWindows64,
+ GraphicsApis = new[] { GraphicsDeviceType.Vulkan, GraphicsDeviceType.Direct3D11, GraphicsDeviceType.Direct3D12 },
+ OutputPath = "./build/Windows_Il2cpp/PlaytestBuild.exe"
+ });
+
+ [MenuItem("Tools/Builder/Build Development Windows Mono")]
+ static void BuildWinMono() => BuildPlayer(new BuildConfig
+ {
+ NamedBuildTarget = NamedBuildTarget.Standalone,
+ ScriptingBackend = ScriptingImplementation.Mono2x,
+ BuildTarget = BuildTarget.StandaloneWindows64,
+ GraphicsApis = new[] { GraphicsDeviceType.Vulkan, GraphicsDeviceType.Direct3D11, GraphicsDeviceType.Direct3D12 },
+ OutputPath = "./build/Windows_Mono/PlaytestBuild.exe"
+ });
+
+ [MenuItem("Tools/Builder/Build Development Mac Mono")]
+ static void BuildMacMono() => BuildPlayer(new BuildConfig
+ {
+ NamedBuildTarget = NamedBuildTarget.Standalone,
+ ScriptingBackend = ScriptingImplementation.Mono2x,
+ BuildTarget = BuildTarget.StandaloneOSX,
+ GraphicsApis = new[] { GraphicsDeviceType.Metal },
+ OutputPath = "./build/macOS_Mono/PlaytestBuild.app"
+ });
+
+ [MenuItem("Tools/Builder/Build Development Mac Il2cpp")]
+ static void BuildMacIl2cpp() => BuildPlayer(new BuildConfig
+ {
+ NamedBuildTarget = NamedBuildTarget.Standalone,
+ ScriptingBackend = ScriptingImplementation.IL2CPP,
+ BuildTarget = BuildTarget.StandaloneOSX,
+ GraphicsApis = new[] { GraphicsDeviceType.Metal },
+ OutputPath = "./build/macOS_Il2cpp/PlaytestBuild.app"
+ });
+
+ [MenuItem("Tools/Builder/Build Development Android Il2cpp")]
+ static void BuildAndroidIl2cpp() => BuildPlayer(new BuildConfig
+ {
+ NamedBuildTarget = NamedBuildTarget.Android,
+ ScriptingBackend = ScriptingImplementation.IL2CPP,
+ BuildTarget = BuildTarget.Android,
+ GraphicsApis = new[] { GraphicsDeviceType.Vulkan },
+ OutputPath = "./build/Android_Il2cpp_Vulkan/PlaytestBuild.apk",
+ ApplicationId = "com.UnityTestRunner.UnityTestRunner",
+ Architecture = 1
+ });
+
+#if UNITY_6000_6_OR_NEWER
+ // ScriptingImplementation.CoreCLR is marked [Obsolete] ("work in progress"), so suppress CS0618 to compile under warnings-as-errors.
+#pragma warning disable CS0618
+ static ScriptingImplementation CoreClrBackend => ScriptingImplementation.CoreCLR;
+#pragma warning restore CS0618
+
+ [MenuItem("Tools/Builder/Build Development Windows CoreCLR")]
+ static void BuildWinCoreClr() => BuildPlayer(new BuildConfig
+ {
+ NamedBuildTarget = NamedBuildTarget.Standalone,
+ ScriptingBackend = CoreClrBackend,
+ BuildTarget = BuildTarget.StandaloneWindows64,
+ GraphicsApis = new[] { GraphicsDeviceType.Vulkan, GraphicsDeviceType.Direct3D11, GraphicsDeviceType.Direct3D12 },
+ OutputPath = "./build/Windows_CoreClr/PlaytestBuild.exe"
+ });
+
+ [MenuItem("Tools/Builder/Build Development Mac CoreCLR")]
+ static void BuildMacCoreClr() => BuildPlayer(new BuildConfig
+ {
+ NamedBuildTarget = NamedBuildTarget.Standalone,
+ ScriptingBackend = CoreClrBackend,
+ BuildTarget = BuildTarget.StandaloneOSX,
+ GraphicsApis = new[] { GraphicsDeviceType.Metal },
+ OutputPath = "./build/macOS_CoreClr/PlaytestBuild.app"
+ });
+
+ [MenuItem("Tools/Builder/Build Development Android CoreCLR")]
+ static void BuildAndroidCoreClr()
+ {
+ // CoreCLR on Android is 64-bit only; ARMv7 (32-bit) is unsupported, so force ARM64.
+ PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARM64;
+ BuildPlayer(new BuildConfig
+ {
+ NamedBuildTarget = NamedBuildTarget.Android,
+ ScriptingBackend = CoreClrBackend,
+ BuildTarget = BuildTarget.Android,
+ GraphicsApis = new[] { GraphicsDeviceType.Vulkan },
+ OutputPath = "./build/Android_CoreClr/PlaytestBuild.apk",
+ ApplicationId = "com.UnityTestRunner.UnityTestRunner"
+ });
+ }
+#endif
+}
diff --git a/Tools/scripts/BuildAutomation/Unity.ProjectBuild.Editor.asmdef b/Tools/CI/scripts/BuildAutomation/Unity.ProjectBuild.Editor.asmdef
similarity index 100%
rename from Tools/scripts/BuildAutomation/Unity.ProjectBuild.Editor.asmdef
rename to Tools/CI/scripts/BuildAutomation/Unity.ProjectBuild.Editor.asmdef
diff --git a/Tools/CI/scripts/BuildAutomation/extend_source_sparse_checkout.py b/Tools/CI/scripts/BuildAutomation/extend_source_sparse_checkout.py
new file mode 100644
index 0000000000..ccdfcc6eaa
--- /dev/null
+++ b/Tools/CI/scripts/BuildAutomation/extend_source_sparse_checkout.py
@@ -0,0 +1,65 @@
+###############################################################################
+### Auto-generated by RecipeEngine.Modules.BuildAutomation. DO NOT EDIT. ###
+### You may override this file locally, but any changes will be overwritten ###
+### the next time CI is regenerated. Permanent fixes must be made inside: ###
+### RecipeEngine.Modules.BuildAutomation/EmbeddedScripts/ ###
+###############################################################################
+
+"""
+Extends the job's own (source) sparse checkout to include the local tested-package folders named at
+runtime by LOCAL_TESTED_PACKAGES_NAMES.
+
+The generated rules file materializes a baseline set at checkout time, but the packages to test are read
+from the environment here so that a package added (or changed) via the LOCAL_TESTED_PACKAGES_NAMES trigger
+variable is checked out on demand rather than failing because it was absent from the pre-baked rules. Adding
+a path that does not exist in the repository materializes nothing and is not an error; validate_params.py is
+what reports a genuinely missing package.
+"""
+
+import argparse
+import os
+import subprocess
+import sys
+
+from package_parsing import parse_package_names
+
+ENV_LOCAL_TESTED_PACKAGES_NAMES = "LOCAL_TESTED_PACKAGES_NAMES"
+
+
+def parse_args():
+ parser = argparse.ArgumentParser(
+ description="Add local tested-package folders to the source repo's sparse checkout."
+ )
+ parser.add_argument("--source-dir", required=True, help="Absolute path to the job's source checkout (git repo root).")
+ parser.add_argument(
+ "--local-tested-packages-path",
+ required=True,
+ help="Repo-relative base directory containing the local packages (e.g. 'Packages').",
+ )
+ return parser.parse_args()
+
+
+def main():
+ args = parse_args()
+
+ package_names = parse_package_names(os.environ.get(ENV_LOCAL_TESTED_PACKAGES_NAMES, ""))
+ if not package_names:
+ print(f"[INFO] {ENV_LOCAL_TESTED_PACKAGES_NAMES} is empty; no source paths to add.")
+ return
+
+ base_path = args.local_tested_packages_path.strip().replace("\\", "/").strip("/")
+ paths = [f"{base_path}/{name}" for name in package_names]
+
+ result = subprocess.run(
+ ["git", "-C", args.source_dir, "sparse-checkout", "add", *paths],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False,
+ )
+ if result.returncode != 0:
+ print(f"Error extending source sparse checkout: {result.stderr.strip()}", file=sys.stderr)
+ sys.exit(1)
+
+ print(f"[INFO] Added to source sparse checkout: {paths}")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/Tools/CI/scripts/BuildAutomation/get_build_method.py b/Tools/CI/scripts/BuildAutomation/get_build_method.py
new file mode 100644
index 0000000000..5625861edd
--- /dev/null
+++ b/Tools/CI/scripts/BuildAutomation/get_build_method.py
@@ -0,0 +1,70 @@
+###############################################################################
+### Auto-generated by RecipeEngine.Modules.BuildAutomation. DO NOT EDIT. ###
+### You may override this file locally, but any changes will be overwritten ###
+### the next time CI is regenerated. Permanent fixes must be made inside: ###
+### RecipeEngine.Modules.BuildAutomation/EmbeddedScripts/ ###
+###############################################################################
+
+"""
+Helper script that determines the appropriate BuilderScripts method and
+runs Unity with the correct parameters.
+"""
+
+import argparse
+import os
+import subprocess
+import sys
+
+BUILD_CONFIGS = {
+ ("win64", "il2cpp"): {"method": "BuilderScripts.BuildWinIl2cpp", "buildTarget": "win64"},
+ ("win64", "mono"): {"method": "BuilderScripts.BuildWinMono", "buildTarget": "win64"},
+ ("win64", "coreclr"): {"method": "BuilderScripts.BuildWinCoreClr", "buildTarget": "win64"},
+ ("mac", "il2cpp"): {"method": "BuilderScripts.BuildMacIl2cpp", "buildTarget": "osx"},
+ ("mac", "mono"): {"method": "BuilderScripts.BuildMacMono", "buildTarget": "osx"},
+ ("mac", "coreclr"): {"method": "BuilderScripts.BuildMacCoreClr", "buildTarget": "osx"},
+ ("android", "il2cpp"): {"method": "BuilderScripts.BuildAndroidIl2cpp", "buildTarget": "android"},
+ ("android", "coreclr"): {"method": "BuilderScripts.BuildAndroidCoreClr", "buildTarget": "android"},
+}
+
+
+def resolve_backend():
+ return os.environ.get("SCRIPTING_BACKEND_(IL2CPP_MONO_CORECLR)", "").lower()
+
+def execute_unity_build(project_path, unity_path):
+ platform = os.environ.get("PLATFORM_(WIN64_MAC_ANDROID)", "").lower()
+ backend = resolve_backend()
+ config = BUILD_CONFIGS.get((platform, backend))
+ if not config:
+ print(f"ERROR: Invalid combination: platform={platform}, backend={backend}", file=sys.stderr)
+ sys.exit(1)
+
+ cmd = [
+ unity_path,
+ "-projectPath",
+ project_path,
+ "-buildTarget",
+ config["buildTarget"],
+ "-executeMethod",
+ config["method"],
+ "-batchmode",
+ "-logFile",
+ "./artifacts/UnityLog.txt",
+ "-automated",
+ "-crash-report-folder",
+ "./artifacts/CrashArtifacts",
+ "-quit",
+ ]
+ result = subprocess.run(cmd, check=False)
+ sys.exit(result.returncode)
+
+
+def main():
+ parser = argparse.ArgumentParser(description="Execute Unity build command.")
+ parser.add_argument("--project-path", required=True, help="Path to Unity project.")
+ parser.add_argument("--unity-path", default="C:/TestingEditor/Unity.exe", help="Path to Unity executable.")
+ args = parser.parse_args()
+ execute_unity_build(args.project_path, args.unity_path)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/Tools/CI/scripts/BuildAutomation/manifest_update.py b/Tools/CI/scripts/BuildAutomation/manifest_update.py
new file mode 100644
index 0000000000..6c712811cc
--- /dev/null
+++ b/Tools/CI/scripts/BuildAutomation/manifest_update.py
@@ -0,0 +1,154 @@
+###############################################################################
+### Auto-generated by RecipeEngine.Modules.BuildAutomation. DO NOT EDIT. ###
+### You may override this file locally, but any changes will be overwritten ###
+### the next time CI is regenerated. Permanent fixes must be made inside: ###
+### RecipeEngine.Modules.BuildAutomation/EmbeddedScripts/ ###
+###############################################################################
+
+"""
+Updates the cloned project's manifest.json to point tested packages at local file: sources, so the
+changes on the current branch are exercised against the sample project.
+
+!!! IMPORTANT !!! — UPM embedded package priority:
+Any package folder placed directly inside the project's Packages/ directory is treated as an
+embedded package and takes the absolute highest priority in UPM dependency resolution.
+
+To work around this, the script scans the Packages/ directory of the cloned project and removes any
+embedded package whose package.json declares a name matching a target package, before writing the
+local file: reference into the manifest.
+"""
+
+import argparse
+import json
+import os
+import shutil
+import sys
+
+from package_parsing import parse_package_names
+
+SEPARATOR = "=" * 80
+ENV_LOCAL_TESTED_PACKAGES_NAMES = "LOCAL_TESTED_PACKAGES_NAMES"
+
+
+def parse_args():
+ parser = argparse.ArgumentParser(description="Update a Unity project manifest to use local package versions.")
+ parser.add_argument("--manifest-path", required=True, help="Absolute path to project manifest.json file.")
+ parser.add_argument(
+ "--local-tested-packages-path",
+ required=True,
+ help="Absolute path to the local packages root directory (e.g. the source dir's Packages folder).",
+ )
+ return parser.parse_args()
+
+
+def remove_embedded_package(packages_dir, package_name):
+ """
+ Scans subfolders of packages_dir and removes any folder whose package.json
+ declares a 'name' matching package_name.
+ """
+ if not os.path.isdir(packages_dir):
+ return
+
+ for entry in os.scandir(packages_dir):
+ if not entry.is_dir():
+ continue
+ package_json_path = os.path.join(entry.path, "package.json")
+ if not os.path.isfile(package_json_path):
+ continue
+ try:
+ with open(package_json_path, "r", encoding="utf-8") as f:
+ name = json.load(f).get("name", "")
+ except Exception:
+ continue
+
+ if name == package_name:
+ shutil.rmtree(entry.path)
+ print(f"[INFO] Removed embedded package '{package_name}' from '{entry.path}'")
+ return
+
+
+def update_manifest(manifest_data, package_name, local_packages_root):
+ old_value = manifest_data.get("dependencies", {}).get(package_name, "")
+ local_package_path = os.path.join(local_packages_root, package_name)
+ local_path_normalized = local_package_path.replace(os.sep, "/")
+ manifest_data.setdefault("dependencies", {})[package_name] = f"file:{local_path_normalized}"
+ return old_value, f"file:{local_path_normalized}"
+
+
+def print_summary(manifest_data, substitutions):
+ print()
+ print(SEPARATOR)
+ print("TARGET PACKAGE SUBSTITUTION")
+ print(SEPARATOR)
+ for substitution in substitutions:
+ print(f"Package: {substitution['package_name']}")
+ print(f" Old value: {substitution['old_value']}")
+ print(f" New value: {substitution['new_value']}")
+ local_version = substitution["local_version"] or ""
+ print(f"Verified local '{substitution['package_name']}' version is: {local_version}")
+ print()
+ print(SEPARATOR)
+ print("FINAL MANIFEST CONTENT")
+ print(SEPARATOR)
+ dependencies = manifest_data.get("dependencies", {})
+ for dep_name, dep_value in sorted(dependencies.items()):
+ print(f" {dep_name}: {dep_value}")
+ print(SEPARATOR)
+ print()
+
+
+def get_package_version(package_path):
+ package_json_path = os.path.join(package_path, "package.json")
+ try:
+ with open(package_json_path, "r", encoding="utf-8") as f:
+ return json.load(f).get("version", "N/A")
+ except Exception:
+ return None
+
+
+def main():
+ args = parse_args()
+
+ try:
+ package_names = parse_package_names(os.environ.get(ENV_LOCAL_TESTED_PACKAGES_NAMES, ""))
+ # Clearing the variable at trigger time opts out of substitution; leave the manifest untouched (plain build).
+ if not package_names:
+ print(f"[INFO] {ENV_LOCAL_TESTED_PACKAGES_NAMES} is empty; skipping local package substitution.")
+ return
+
+ with open(args.manifest_path, "r", encoding="utf-8") as manifest_file:
+ manifest_data = json.load(manifest_file)
+
+ packages_dir = os.path.dirname(args.manifest_path)
+
+ substitutions = []
+ for package_name in package_names:
+ remove_embedded_package(packages_dir, package_name)
+
+ old_value, new_value = update_manifest(
+ manifest_data,
+ package_name,
+ args.local_tested_packages_path,
+ )
+ local_package_path = os.path.join(args.local_tested_packages_path, package_name)
+ local_version = get_package_version(local_package_path)
+ substitutions.append(
+ {
+ "package_name": package_name,
+ "old_value": old_value,
+ "new_value": new_value,
+ "local_version": local_version,
+ }
+ )
+
+ with open(args.manifest_path, "w", encoding="utf-8", newline="\n") as manifest_file:
+ json.dump(manifest_data, manifest_file, indent=4)
+
+ print_summary(manifest_data, substitutions)
+ except Exception as error:
+ print(f"Error updating manifest: {error}", file=sys.stderr)
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/Tools/CI/scripts/BuildAutomation/package_parsing.py b/Tools/CI/scripts/BuildAutomation/package_parsing.py
new file mode 100644
index 0000000000..8bd9183b9d
--- /dev/null
+++ b/Tools/CI/scripts/BuildAutomation/package_parsing.py
@@ -0,0 +1,23 @@
+###############################################################################
+### Auto-generated by RecipeEngine.Modules.BuildAutomation. DO NOT EDIT. ###
+### You may override this file locally, but any changes will be overwritten ###
+### the next time CI is regenerated. Permanent fixes must be made inside: ###
+### RecipeEngine.Modules.BuildAutomation/EmbeddedScripts/ ###
+###############################################################################
+
+"""
+Shared parsing for the LOCAL_TESTED_PACKAGES_NAMES variable, so every build-automation script splits it the
+same way. Package names may be separated by commas, semicolons, and/or whitespace in any combination, so
+values entered as "a,b", "a; b", or "a b" all yield the same list.
+"""
+
+import re
+
+_SEPARATORS = re.compile(r"[,;\s]+")
+
+
+def parse_package_names(raw_value):
+ """Split a LOCAL_TESTED_PACKAGES_NAMES value into package names on commas, semicolons, or whitespace."""
+ if not raw_value:
+ return []
+ return [name for name in _SEPARATORS.split(raw_value.strip()) if name]
diff --git a/Tools/CI/scripts/BuildAutomation/print_build_summary.py b/Tools/CI/scripts/BuildAutomation/print_build_summary.py
new file mode 100644
index 0000000000..4065b252ff
--- /dev/null
+++ b/Tools/CI/scripts/BuildAutomation/print_build_summary.py
@@ -0,0 +1,226 @@
+###############################################################################
+### Auto-generated by RecipeEngine.Modules.BuildAutomation. DO NOT EDIT. ###
+### You may override this file locally, but any changes will be overwritten ###
+### the next time CI is regenerated. Permanent fixes must be made inside: ###
+### RecipeEngine.Modules.BuildAutomation/EmbeddedScripts/ ###
+###############################################################################
+
+"""
+Prints a formatted build configuration summary table from Yamato environment variables.
+Emitted after the sample is cloned and unity-downloader-cli is installed, but before the slow editor
+download, so the configuration is visible early in the Yamato log while still being able to resolve the
+editor actually used by the build.
+"""
+
+import argparse
+import os
+import platform
+import re
+import subprocess
+
+from package_parsing import parse_package_names
+
+SEP = "=" * 72
+PLATFORM_MAC = "mac"
+ENV_SCRIPTING_BACKEND = "SCRIPTING_BACKEND_(IL2CPP_MONO_CORECLR)"
+ENV_PLATFORM = "PLATFORM_(WIN64_MAC_ANDROID)"
+ENV_SAMPLE_BRANCH = "SAMPLE_BRANCH"
+ENV_UNITY_VERSION = "UNITY_VERSION"
+ENV_LOCAL_TESTED_PACKAGES_NAMES = "LOCAL_TESTED_PACKAGES_NAMES"
+ENV_GIT_BRANCH = "GIT_BRANCH"
+
+# Friendly labels for the build agent OS the job ran on (the value passed by --build-machine-os).
+BUILD_MACHINE_DISPLAY = {"windows": "Windows"}
+
+# Length to truncate a full Git revision to, matching the form ProjectVersion.txt records (e.g.
+# "6000.5.0a5 (4928cd185deb)").
+SHORT_REVISION_LENGTH = 12
+
+
+def run_git(source_dir, *args, check=False):
+ try:
+ result = subprocess.run(
+ ["git", "-C", source_dir, *args],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ text=True,
+ check=check,
+ )
+ return result.stdout.strip() if result.stdout else ""
+ except Exception:
+ return ""
+
+
+def get_package_branch_info():
+ source_dir = os.environ.get("YAMATO_SOURCE_DIR", ".")
+ # Yamato checks the source out at a detached HEAD, so git can't report the branch; GIT_BRANCH carries the
+ # branch the job runs against (the PR source branch for PR-triggered jobs).
+ branch = os.environ.get(ENV_GIT_BRANCH, "").strip()
+ commit = run_git(source_dir, "rev-parse", "--short", "HEAD")
+ if branch and commit:
+ return f"{branch} ({commit})"
+ if branch:
+ return branch
+ if commit:
+ return f" ({commit})"
+ return "N/A"
+
+
+def get_sample_branch_commit(sample_repo_url, sample_branch):
+ try:
+ result = subprocess.run(
+ ["git", "ls-remote", sample_repo_url, f"refs/heads/{sample_branch}"],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False,
+ )
+ if result.returncode == 0 and result.stdout.strip():
+ full_sha = result.stdout.strip().split()[0]
+ return full_sha[:10]
+ except Exception:
+ pass
+ return None
+
+
+def get_editor_version_from_downloader(unity_version):
+ try:
+ # --fast resolves branch-style versions (e.g. "trunk") against cached builds; --wait falls back to a
+ # pending build when none is cached, so resolution does not flake. Mirrors the download/validate calls.
+ result = subprocess.run(
+ ["unity-downloader-cli", "--fast", "--wait", "-u", unity_version, "-c", "editor", "--skip-download"],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False,
+ )
+ combined = result.stderr + result.stdout
+ match = re.search(r"Grabbing unity release (\S+) which is revision: (\w+)", combined)
+ if match:
+ return f"{match.group(1)} ({match.group(2)})"
+ version_match = re.search(r"Version:\s*(\S+)", result.stderr)
+ sha = result.stdout.strip()
+ if version_match:
+ return f"{version_match.group(1)}{f' ({sha[:SHORT_REVISION_LENGTH]})' if sha else ''}"
+ except Exception:
+ pass
+ return unity_version
+
+
+def get_editor_version_from_project(project_path):
+ """Read the editor the cloned sample was authored with, preferring the version+revision form."""
+ try:
+ version_file = os.path.join(project_path, "ProjectSettings", "ProjectVersion.txt")
+ with open(version_file, "r", encoding="utf-8") as f:
+ content = f.read()
+ # e.g. "m_EditorVersionWithRevision: 6000.5.0a5 (4928cd185deb)"
+ match = re.search(r"^m_EditorVersionWithRevision:\s*(.+?)\s*$", content, re.MULTILINE)
+ if match:
+ return match.group(1).strip()
+ match = re.search(r"^m_EditorVersion:\s*(\S+)\s*$", content, re.MULTILINE)
+ if match:
+ return match.group(1)
+ except Exception:
+ pass
+ return "N/A"
+
+
+def get_updated_editor():
+ """Resolve the editor actually used by the build, as opposed to the one the sample was authored with."""
+ unity_version = os.environ.get(ENV_UNITY_VERSION)
+ if unity_version:
+ return get_editor_version_from_downloader(unity_version)
+ return None
+
+
+def print_mac_on_windows_note(target_platform):
+ """
+ A macOS player cross-compiled on a Windows agent loses its executable bit and carries a quarantine
+ attribute, so the .app may refuse to open on the Mac. Surface the recovery commands in the job log
+ when (and only when) a mac build is produced on a Windows host.
+ """
+ if target_platform.strip().lower() != PLATFORM_MAC or platform.system() != "Windows":
+ return
+
+ lines = [
+ "",
+ SEP,
+ " Note for Mac users (mac build produced on a Windows agent)",
+ SEP,
+ " If you are unable to open the build, run the following on the Mac:",
+ " xattr -c ",
+ " chmod -R +x ",
+ SEP,
+ "",
+ ]
+ print("\n".join(lines))
+
+
+def main():
+ parser = argparse.ArgumentParser(description="Print build configuration summary.")
+ parser.add_argument("--project-name", required=True, help="Project key used in CI.")
+ parser.add_argument(
+ "--sample-repo-url",
+ help="GitHub URL of sample repo, used to resolve sample branch commit.",
+ )
+ parser.add_argument(
+ "--project-path",
+ help="Path to the cloned Unity project root, used to read the sample's editor from ProjectVersion.txt.",
+ )
+ parser.add_argument(
+ "--build-machine-os",
+ choices=sorted(BUILD_MACHINE_DISPLAY.keys()),
+ help="OS of the build agent the job ran on; shown in the summary.",
+ )
+ args = parser.parse_args()
+
+ rows = [("Project Name", args.project_name)]
+
+ # Editor the sample was authored with vs. the editor the build actually uses.
+ original_editor = get_editor_version_from_project(args.project_path) if args.project_path else None
+ updated_editor = get_updated_editor()
+
+ git_package_branch = get_package_branch_info()
+
+ # The package under test is the job's own source checkout, so report its branch.
+ rows.append(("Package Branch", git_package_branch))
+
+ # SAMPLE_BRANCH env var holds the external project branch.
+ sample_branch = os.environ.get(ENV_SAMPLE_BRANCH, "").strip()
+ if sample_branch:
+ commit = get_sample_branch_commit(args.sample_repo_url, sample_branch) if args.sample_repo_url else None
+ branch_display = f"{sample_branch} ({commit})" if commit else sample_branch
+ else:
+ branch_display = f" resolved to {git_package_branch}"
+ rows.append(("Sample Branch", branch_display))
+
+ # Lead with the editor the build uses; note the project's authored editor (ProjectVersion.txt) when known.
+ project_editor = original_editor if original_editor and original_editor != "N/A" else None
+ if updated_editor and project_editor:
+ editor_display = f"{updated_editor} (project's ProjectVersion.txt: {project_editor})"
+ else:
+ editor_display = updated_editor or original_editor
+ if editor_display:
+ rows.append(("Editor Version", editor_display))
+
+ local_tested_packages = parse_package_names(os.environ.get(ENV_LOCAL_TESTED_PACKAGES_NAMES, ""))
+ if local_tested_packages:
+ rows.append(("Local Tested Packages", ", ".join(local_tested_packages)))
+
+ rows.append(("Scripting Backend", os.environ.get(ENV_SCRIPTING_BACKEND, "N/A")))
+
+ target_platform = os.environ.get(ENV_PLATFORM, "N/A")
+ rows.append(("Target Platform", target_platform))
+
+ # The agent OS the build ran on, distinct from the target platform (a Windows agent can cross-build a mac
+ # player). Best-effort: only shown when the recipe passed --build-machine-os.
+ if args.build_machine_os:
+ rows.append(("Build Machine", BUILD_MACHINE_DISPLAY[args.build_machine_os]))
+
+ label_width = max(len(label) for label, _ in rows)
+ lines = ["", SEP, " Build Configuration Summary", SEP]
+ for label, value in rows:
+ lines.append(f" {label:<{label_width}} : {value}")
+ lines += [SEP, ""]
+
+ print("\n".join(lines))
+
+ print_mac_on_windows_note(target_platform)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/Tools/CI/scripts/BuildAutomation/project-sparse-checkouts/Asteroids.patterns b/Tools/CI/scripts/BuildAutomation/project-sparse-checkouts/Asteroids.patterns
new file mode 100644
index 0000000000..52d79c4688
--- /dev/null
+++ b/Tools/CI/scripts/BuildAutomation/project-sparse-checkouts/Asteroids.patterns
@@ -0,0 +1,2 @@
+Tools/CI/scripts/BuildAutomation
+./com.unity.netcode.gameobjects
diff --git a/Tools/CI/scripts/BuildAutomation/project-sparse-checkouts/BossRoom.patterns b/Tools/CI/scripts/BuildAutomation/project-sparse-checkouts/BossRoom.patterns
new file mode 100644
index 0000000000..52d79c4688
--- /dev/null
+++ b/Tools/CI/scripts/BuildAutomation/project-sparse-checkouts/BossRoom.patterns
@@ -0,0 +1,2 @@
+Tools/CI/scripts/BuildAutomation
+./com.unity.netcode.gameobjects
diff --git a/Tools/CI/scripts/BuildAutomation/project-sparse-checkouts/SocialHub.patterns b/Tools/CI/scripts/BuildAutomation/project-sparse-checkouts/SocialHub.patterns
new file mode 100644
index 0000000000..52d79c4688
--- /dev/null
+++ b/Tools/CI/scripts/BuildAutomation/project-sparse-checkouts/SocialHub.patterns
@@ -0,0 +1,2 @@
+Tools/CI/scripts/BuildAutomation
+./com.unity.netcode.gameobjects
diff --git a/Tools/CI/scripts/BuildAutomation/resolve_sparse_file_references.py b/Tools/CI/scripts/BuildAutomation/resolve_sparse_file_references.py
new file mode 100644
index 0000000000..d529aaddcf
--- /dev/null
+++ b/Tools/CI/scripts/BuildAutomation/resolve_sparse_file_references.py
@@ -0,0 +1,165 @@
+###############################################################################
+### Auto-generated by RecipeEngine.Modules.BuildAutomation. DO NOT EDIT. ###
+### You may override this file locally, but any changes will be overwritten ###
+### the next time CI is regenerated. Permanent fixes must be made inside: ###
+### RecipeEngine.Modules.BuildAutomation/EmbeddedScripts/ ###
+###############################################################################
+
+"""
+Extends a sparse-checked-out sample clone to include the repo-relative package folders it
+references via UPM `file:` dependencies.
+
+A sample project is cloned with a blob-less partial clone whose working tree is restricted to
+ (see CloneProject). The project's /Packages/manifest.json can list
+`file:` dependencies whose paths (relative to the manifest's own Packages/ directory) resolve to
+folders OUTSIDE -- for example NetcodeSamples references the repo-root Packages/
+folder via "file:../../../Packages/com.unity.entities". Those folders are never materialized by the
+initial sparse checkout, so UPM cannot resolve the packages and the build fails.
+
+This script parses the cloned manifest, resolves each `file:` reference to a repo-relative
+directory, and `git sparse-checkout add`s the ones that fall outside . References that
+escape the repository root, that already live inside , or a missing manifest are
+skipped without failing the build.
+
+A single pass is sufficient -- no recursion is needed. The sample author lists every repo-local
+sibling package as a `file:` reference in the PROJECT manifest (NetcodeSamples lists
+entities/transport/netcode/URP there). A pulled-in package's own package.json declares its
+dependencies as registry version refs, not `file:` references into the monorepo, so transitive
+dependencies resolve from the package registry rather than via repo-local paths.
+
+This must run BEFORE manifest_update.py: that script rewrites the tested packages to
+`file:%YAMATO_SOURCE_DIR%/...` refs pointing at the source checkout (not the sample repo), so the
+resolver must see the sample's ORIGINAL manifest and act only on the sample repo's own internal refs.
+"""
+
+import argparse
+import json
+import posixpath
+import subprocess
+import sys
+
+SEPARATOR = "=" * 80
+
+
+def parse_args():
+ parser = argparse.ArgumentParser(
+ description="Add repo-relative file: package folders to a sample clone's sparse checkout."
+ )
+ parser.add_argument("--cloned-root", required=True, help="Absolute path to the cloned sample repo (e.g. C:/ClonedProject).")
+ parser.add_argument("--project-path", required=True, help="Repo-relative project path (e.g. Workspace/NetcodeSamples).")
+ parser.add_argument("--branch", required=True, help="Branch to re-checkout so newly included blobs are fetched.")
+ return parser.parse_args()
+
+
+def resolve_reference(project_path, target):
+ """
+ Resolves a manifest `file:` target (relative to /Packages) to a repo-relative,
+ forward-slash directory. Returns one of:
+ ("escape", combined) -- the path escapes the repository root; warn and skip.
+ ("inside", combined) -- the path is inside ; already checked out, skip.
+ ("candidate", combined) -- a repo-relative dir outside ; add to the checkout.
+ """
+ combined = posixpath.normpath(posixpath.join(project_path + "/Packages", target))
+
+ if combined == ".." or combined.startswith("../"):
+ return "escape", combined
+ if combined == project_path or combined.startswith(project_path + "/"):
+ return "inside", combined
+ return "candidate", combined
+
+
+def collect_candidates(dependencies, project_path):
+ candidates = []
+ skipped_inside = []
+ skipped_escape = []
+ seen = set()
+
+ for ref in dependencies.values():
+ if not str(ref).startswith("file:"):
+ continue
+
+ target = str(ref)[len("file:"):]
+ kind, combined = resolve_reference(project_path, target)
+ if kind == "escape":
+ skipped_escape.append(combined)
+ elif kind == "inside":
+ skipped_inside.append(combined)
+ elif combined not in seen:
+ seen.add(combined)
+ candidates.append(combined)
+
+ return candidates, skipped_inside, skipped_escape
+
+
+def print_summary(candidates, skipped_inside, skipped_escape):
+ print()
+ print(SEPARATOR)
+ print("SPARSE CHECKOUT FILE: REFERENCE RESOLUTION")
+ print(SEPARATOR)
+ print(f"Added (outside project): {candidates if candidates else ''}")
+ print(f"Skipped (already in project): {skipped_inside if skipped_inside else ''}")
+ print(f"Skipped (escapes repo root): {skipped_escape if skipped_escape else ''}")
+ print(SEPARATOR)
+ print()
+
+
+def main():
+ args = parse_args()
+
+ project_path = args.project_path.replace("\\", "/").strip("/")
+ if not project_path or project_path == ".":
+ print("[INFO] Project path is the repository root; no sparse checkout to extend.")
+ return
+
+ manifest_path = posixpath.join(args.cloned_root.replace("\\", "/"), project_path, "Packages/manifest.json")
+
+ try:
+ with open(manifest_path, "r", encoding="utf-8") as manifest_file:
+ manifest_data = json.load(manifest_file)
+ except FileNotFoundError:
+ print(f"[INFO] No manifest at '{manifest_path}'; nothing to resolve.")
+ return
+ except Exception as error:
+ print(f"Error reading manifest '{manifest_path}': {error}", file=sys.stderr)
+ sys.exit(1)
+
+ dependencies = manifest_data.get("dependencies", {})
+ candidates, skipped_inside, skipped_escape = collect_candidates(dependencies, project_path)
+
+ for escaped in skipped_escape:
+ print(f"[WARN] file: reference resolves outside the repository root and was skipped: '{escaped}'", file=sys.stderr)
+
+ if not candidates:
+ print("[INFO] No external file: references to add to the sparse checkout.")
+ print_summary(candidates, skipped_inside, skipped_escape)
+ return
+
+ add_result = subprocess.run(
+ ["git", "-C", args.cloned_root, "sparse-checkout", "add", *candidates],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ text=True,
+ check=False,
+ )
+ if add_result.returncode != 0:
+ print(f"Error adding paths to sparse checkout: {add_result.stderr.strip()}", file=sys.stderr)
+ sys.exit(1)
+
+ # The blob:none partial clone fetches the newly included blobs lazily on checkout, mirroring
+ # CloneProject's final checkout (robust across git versions).
+ checkout_result = subprocess.run(
+ ["git", "-C", args.cloned_root, "checkout", args.branch],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ text=True,
+ check=False,
+ )
+ if checkout_result.returncode != 0:
+ print(f"Error checking out '{args.branch}' after extending sparse checkout: {checkout_result.stderr.strip()}", file=sys.stderr)
+ sys.exit(1)
+
+ print_summary(candidates, skipped_inside, skipped_escape)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/Tools/CI/scripts/BuildAutomation/setup_build_scripts.py b/Tools/CI/scripts/BuildAutomation/setup_build_scripts.py
new file mode 100644
index 0000000000..6926e1341d
--- /dev/null
+++ b/Tools/CI/scripts/BuildAutomation/setup_build_scripts.py
@@ -0,0 +1,38 @@
+###############################################################################
+### Auto-generated by RecipeEngine.Modules.BuildAutomation. DO NOT EDIT. ###
+### You may override this file locally, but any changes will be overwritten ###
+### the next time CI is regenerated. Permanent fixes must be made inside: ###
+### RecipeEngine.Modules.BuildAutomation/EmbeddedScripts/ ###
+###############################################################################
+
+"""
+Helper script that copies build scripts into the cloned Unity project to execute build action from within
+"""
+
+import argparse
+import os
+import shutil
+
+
+def parse_args():
+ parser = argparse.ArgumentParser(description="Set up build scripts in cloned project.")
+ parser.add_argument("--project-path", required=True, help="Path to the cloned project root.")
+ return parser.parse_args()
+
+
+def main():
+ args = parse_args()
+ target_dir = os.path.join(args.project_path, "Assets", "CI", "Scripts", "Editor")
+ # BuilderScripts.cs and the asmdef are materialized into this script's own directory, so resolve them
+ # relative to __file__. This stays correct regardless of the consumer's configured ScriptsRelativeDir.
+ source_dir = os.path.dirname(os.path.abspath(__file__))
+ os.makedirs(target_dir, exist_ok=True)
+
+ for filename in ["Unity.ProjectBuild.Editor.asmdef", "BuilderScripts.cs"]:
+ source_path = os.path.join(source_dir, filename)
+ target_path = os.path.join(target_dir, filename)
+ shutil.copy(source_path, target_path)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/Tools/CI/scripts/BuildAutomation/validate_params.py b/Tools/CI/scripts/BuildAutomation/validate_params.py
new file mode 100644
index 0000000000..1d6c03ae38
--- /dev/null
+++ b/Tools/CI/scripts/BuildAutomation/validate_params.py
@@ -0,0 +1,366 @@
+###############################################################################
+### Auto-generated by RecipeEngine.Modules.BuildAutomation. DO NOT EDIT. ###
+### You may override this file locally, but any changes will be overwritten ###
+### the next time CI is regenerated. Permanent fixes must be made inside: ###
+### RecipeEngine.Modules.BuildAutomation/EmbeddedScripts/ ###
+###############################################################################
+
+"""
+Validates Yamato environment variables based on predefined rules.
+Checks always-required values and optional repo/feature-specific values.
+Exits with non-zero status if validation fails, halting the build process early.
+"""
+
+import argparse
+import os
+import re
+import subprocess
+import sys
+
+from package_parsing import parse_package_names
+
+ENV_SCRIPTING_BACKEND = "SCRIPTING_BACKEND_(IL2CPP_MONO_CORECLR)"
+ENV_PLATFORM = "PLATFORM_(WIN64_MAC_ANDROID)"
+ENV_SAMPLE_BRANCH = "SAMPLE_BRANCH"
+ENV_UNITY_VERSION = "UNITY_VERSION"
+ENV_LOCAL_TESTED_PACKAGES_NAMES = "LOCAL_TESTED_PACKAGES_NAMES"
+
+ALLOWED_SCRIPTING_BACKENDS = {"il2cpp", "mono", "coreclr"}
+ALLOWED_PLATFORMS = {"win64", "mac", "android"}
+
+CORECLR_BACKEND = "coreclr"
+# coreclr is only a supported scripting backend from this editor onward; older editors must use il2cpp/mono.
+MIN_CORECLR_EDITOR_VERSION = (6000, 6)
+MIN_CORECLR_EDITOR_VERSION_DISPLAY = "6000.6"
+
+BUILD_MACHINE_WINDOWS = "windows"
+ALLOWED_BUILD_MACHINE_OS = {BUILD_MACHINE_WINDOWS}
+
+# Platform/scripting-backend combinations that are invalid regardless of the build machine OS.
+INVALID_COMBINATIONS = [
+ (
+ "android",
+ "mono",
+ "Android platform with mono is not supported. "
+ "Mobile builds require the il2cpp or coreclr scripting backend.",
+ ),
+]
+
+# Combinations that depend on which OS the build agent runs. il2cpp produces a native player, so a Windows
+# IL2CPP player needs a Windows agent; a mac il2cpp player cannot be produced on the Windows agent (macOS
+# agents are a planned follow-up).
+INVALID_COMBINATIONS_BY_BUILD_MACHINE = {
+ BUILD_MACHINE_WINDOWS: [
+ (
+ "mac",
+ "il2cpp",
+ "Mac il2cpp players cannot be built on a Windows agent. "
+ "Use mono to cross-build mac on Windows.",
+ ),
+ ],
+}
+
+
+def validate_required_enum(var_name, allowed_values):
+ value = os.environ.get(var_name, "").strip().lower()
+ if not value:
+ return [f"ERROR: Missing required environment variable: {var_name}"]
+
+ if value not in allowed_values:
+ return [
+ f"ERROR: Invalid {var_name}: '{value}'. "
+ f"Allowed values: {sorted(list(allowed_values))}"
+ ]
+
+ return []
+
+
+def validate_core_variables():
+ errors = []
+ errors.extend(validate_required_enum(ENV_PLATFORM, ALLOWED_PLATFORMS))
+ errors.extend(validate_required_enum(ENV_SCRIPTING_BACKEND, ALLOWED_SCRIPTING_BACKENDS))
+ return errors
+
+
+def parse_major_minor(version):
+ """Parses the leading MAJOR.MINOR of a Unity version string (e.g. '6000.6.0a7' -> (6000, 6)).
+ Returns None when the two leading numeric components cannot be determined."""
+ parts = version.split(".")
+ if len(parts) < 2:
+ return None
+
+ numbers = []
+ for part in parts[:2]:
+ match = re.match(r"\d+", part.strip())
+ if not match:
+ return None
+ numbers.append(int(match.group()))
+ return tuple(numbers)
+
+
+def parse_version_tuple(version):
+ """Extracts the leading numeric MAJOR[.MINOR[.PATCH]] of a Unity version string as a tuple, padding
+ missing trailing components with 0 (e.g. '6000.5.0a5' -> (6000, 5, 0), '6000.6' -> (6000, 6, 0)).
+ Returns None when no leading major number is present."""
+ numbers = []
+ for part in str(version).strip().split(".")[:3]:
+ match = re.match(r"\d+", part.strip())
+ if not match:
+ break
+ numbers.append(int(match.group()))
+
+ if not numbers:
+ return None
+
+ while len(numbers) < 3:
+ numbers.append(0)
+ return tuple(numbers)
+
+
+def parse_resolved_release(downloader_output):
+ """Parses the editor version unity-downloader-cli reports it resolved to, from its combined output
+ (e.g. 'Grabbing unity release 6000.5.0a5 which is revision: ...'). Returns None when not present."""
+ match = re.search(r"Grabbing unity release (\S+)", downloader_output)
+ return match.group(1) if match else None
+
+
+def validate_min_supported_editor(unity_version, downloader_output, min_supported_editor):
+ """Fails when the editor unity-downloader-cli actually resolved is older than the sample's minimum
+ supported editor. Best-effort: if either version can't be parsed, warn and pass (the floor is advisory)."""
+ resolved = parse_resolved_release(downloader_output)
+ if not resolved:
+ print(
+ f"WARNING: could not determine the resolved editor version for {ENV_UNITY_VERSION} "
+ f"'{unity_version}'; skipping the minimum supported editor check.",
+ file=sys.stderr,
+ )
+ return []
+
+ resolved_parsed = parse_version_tuple(resolved)
+ min_parsed = parse_version_tuple(min_supported_editor)
+ if resolved_parsed is None or min_parsed is None:
+ print(
+ f"WARNING: could not compare resolved editor '{resolved}' against minimum supported "
+ f"'{min_supported_editor}'; skipping the minimum supported editor check.",
+ file=sys.stderr,
+ )
+ return []
+
+ if resolved_parsed < min_parsed:
+ return [
+ f"ERROR: resolved editor '{resolved}' (from {ENV_UNITY_VERSION} '{unity_version}') is older than "
+ f"the sample's minimum supported editor '{min_supported_editor}'."
+ ]
+ return []
+
+
+def coreclr_editor_error(editor_major_minor, editor_display):
+ """Returns an error when the coreclr backend is selected but the given editor MAJOR.MINOR is older than the
+ minimum. `editor_major_minor` is a (major, minor) tuple, or None to skip (undeterminable version)."""
+ scripting_backend = os.environ.get(ENV_SCRIPTING_BACKEND, "").strip().lower()
+ if scripting_backend != CORECLR_BACKEND or editor_major_minor is None:
+ return []
+
+ if editor_major_minor < MIN_CORECLR_EDITOR_VERSION:
+ return [
+ f"ERROR: coreclr scripting backend requires editor "
+ f"{MIN_CORECLR_EDITOR_VERSION_DISPLAY} or newer, but the editor is '{editor_display}'."
+ ]
+ return []
+
+
+def validate_coreclr_editor_version():
+ """coreclr is only supported from editor 6000.6 onward. Checked here against the *requested* UNITY_VERSION
+ when it is a concrete MAJOR.MINOR; branch-style values (e.g. "trunk", "6000.6/staging") can't be judged from
+ the env text, so they are deferred to the resolved-editor check in validate_unity_version. Skipped when
+ UNITY_VERSION is absent."""
+ scripting_backend = os.environ.get(ENV_SCRIPTING_BACKEND, "").strip().lower()
+ if scripting_backend != CORECLR_BACKEND:
+ return []
+
+ unity_version = os.environ.get(ENV_UNITY_VERSION, "").strip()
+ if not unity_version:
+ return []
+
+ parsed = parse_major_minor(unity_version)
+ if parsed is None:
+ # Branch-style version: the resolved-editor coreclr check in validate_unity_version handles it.
+ return []
+
+ return coreclr_editor_error(parsed, unity_version)
+
+
+def validate_combinations(build_machine_os):
+ errors = []
+ platform = os.environ.get(ENV_PLATFORM, "").strip().lower()
+ scripting_backend = os.environ.get(ENV_SCRIPTING_BACKEND, "").strip().lower()
+
+ combinations = INVALID_COMBINATIONS + INVALID_COMBINATIONS_BY_BUILD_MACHINE.get(build_machine_os, [])
+ for invalid_platform, invalid_backend, message in combinations:
+ if platform == invalid_platform and scripting_backend == invalid_backend:
+ errors.append(f"ERROR: Invalid Configuration: {message}")
+ return errors
+
+
+def validate_sample_branch(github_repo_url):
+ errors = []
+ sample_branch = os.environ.get(ENV_SAMPLE_BRANCH, "").strip()
+ if not sample_branch:
+ return [f"ERROR: Missing required environment variable: {ENV_SAMPLE_BRANCH}"]
+
+ result = subprocess.run(
+ ["git", "ls-remote", "--heads", "--exit-code", github_repo_url, sample_branch],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ text=True,
+ check=False,
+ )
+ if result.returncode != 0:
+ errors.append(
+ f"ERROR: Branch '{sample_branch}' was not found in repository '{github_repo_url}'."
+ )
+ return errors
+
+
+def validate_unity_version(min_supported_editor=None):
+ errors = []
+ unity_version = os.environ.get(ENV_UNITY_VERSION, "").strip()
+ if not unity_version:
+ return [f"ERROR: Missing required environment variable: {ENV_UNITY_VERSION}"]
+
+ try:
+ # --fast resolves branch-style versions (e.g. "trunk", "6000.6/staging") against already-cached builds;
+ # --wait is required alongside it because --fast alone exits non-zero when nothing is cached yet (trunk
+ # builds expire), which would spuriously reject a valid branch. Mirrors the download invocation
+ # (--fast --wait). --skip-download still resolves and prints the revision without fetching the editor.
+ result = subprocess.run(
+ ["unity-downloader-cli", "--fast", "--wait", "-u", unity_version, "-c", "editor", "--skip-download"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ text=True,
+ check=False,
+ )
+ except FileNotFoundError:
+ return [
+ "ERROR: unity-downloader-cli is not installed; "
+ f"cannot validate {ENV_UNITY_VERSION}. Install it before running this check."
+ ]
+ if result.returncode != 0:
+ errors.append(
+ f"ERROR: unity-downloader-cli does not recognize {ENV_UNITY_VERSION} '{unity_version}'."
+ )
+ return errors
+
+ resolved_revision = result.stdout.strip()
+ if not resolved_revision:
+ errors.append(
+ "ERROR: unity-downloader-cli did not return a resolved revision for "
+ f"{ENV_UNITY_VERSION} '{unity_version}'."
+ )
+
+ combined_output = result.stderr + result.stdout
+
+ # coreclr floor against the RESOLVED editor, so branch-style versions (e.g. "trunk", "6000.6/staging") that
+ # the raw env text can't reveal are still gated once the downloader resolves them.
+ resolved_release = parse_resolved_release(combined_output)
+ if resolved_release:
+ errors.extend(coreclr_editor_error(parse_major_minor(resolved_release), resolved_release))
+
+ if min_supported_editor:
+ errors.extend(
+ validate_min_supported_editor(unity_version, combined_output, min_supported_editor)
+ )
+ return errors
+
+
+def validate_local_tested_packages(base_path):
+ package_names = parse_package_names(os.environ.get(ENV_LOCAL_TESTED_PACKAGES_NAMES, ""))
+ errors = []
+
+ # Clearing the variable at trigger time opts out of substitution (plain build); nothing to validate.
+ if not package_names:
+ return []
+
+ for package_name in package_names:
+ package_dir = os.path.join(base_path, package_name)
+ package_json = os.path.join(package_dir, "package.json")
+
+ if not os.path.isdir(package_dir):
+ errors.append(
+ f"ERROR: Local tested package directory does not exist: '{package_dir}'"
+ )
+ continue
+
+ if not os.path.isfile(package_json):
+ errors.append(
+ f"ERROR: package.json was not found for local tested package '{package_name}' "
+ f"at '{package_json}'"
+ )
+
+ if errors:
+ errors.append(
+ f"HINT: {ENV_LOCAL_TESTED_PACKAGES_NAMES} was parsed as {package_names}. Separate package names "
+ "with a comma, semicolon, or space (e.g. 'com.unity.netcode,com.unity.entities'); each must be a "
+ f"folder under '{base_path}' that contains a package.json."
+ )
+
+ return errors
+
+
+def parse_args():
+ parser = argparse.ArgumentParser(description="Validate Yamato variables for build automation.")
+ parser.add_argument(
+ "--check-sample-branch",
+ dest="sample_branch_repo_url",
+ help="Validate that SAMPLE_BRANCH exists in this repository URL.",
+ )
+ parser.add_argument(
+ "--check-unity-version",
+ action="store_true",
+ help="Validate UNITY_VERSION by resolving it through unity-downloader-cli.",
+ )
+ parser.add_argument(
+ "--check-local-tested-packages",
+ dest="local_tested_packages_path",
+ help="Validate LOCAL_TESTED_PACKAGES_NAMES under this base package path.",
+ )
+ parser.add_argument(
+ "--min-supported-editor",
+ dest="min_supported_editor",
+ help="Sample's minimum supported editor; the editor resolved for UNITY_VERSION must be at least "
+ "this version (checked only with --check-unity-version).",
+ )
+ parser.add_argument(
+ "--build-machine-os",
+ choices=sorted(ALLOWED_BUILD_MACHINE_OS),
+ default=BUILD_MACHINE_WINDOWS,
+ help="OS of the build agent; gates platform/scripting-backend combinations (e.g. mac+il2cpp).",
+ )
+ return parser.parse_args()
+
+
+def main():
+ args = parse_args()
+ errors = []
+ errors.extend(validate_core_variables())
+ errors.extend(validate_combinations(args.build_machine_os))
+ errors.extend(validate_coreclr_editor_version())
+
+ if args.sample_branch_repo_url:
+ errors.extend(validate_sample_branch(args.sample_branch_repo_url))
+
+ if args.check_unity_version:
+ errors.extend(validate_unity_version(args.min_supported_editor))
+
+ if args.local_tested_packages_path:
+ errors.extend(validate_local_tested_packages(args.local_tested_packages_path))
+
+ if errors:
+ for error in errors:
+ print(error, file=sys.stderr)
+ print("\nOne or more parameters failed validation. Halting build.", file=sys.stderr)
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/Tools/CI/service.cmb/README.md b/Tools/CI/service.cmb/README.md
index e50f68b86b..97079d3393 100644
--- a/Tools/CI/service.cmb/README.md
+++ b/Tools/CI/service.cmb/README.md
@@ -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.
@@ -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 - [, , ]`. 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.
diff --git a/Tools/CI/service.cmb/run_cmb_service.sh b/Tools/CI/service.cmb/run_cmb_service.sh
index 4bcf8c7468..8dd26df88a 100755
--- a/Tools/CI/service.cmb/run_cmb_service.sh
+++ b/Tools/CI/service.cmb/run_cmb_service.sh
@@ -17,7 +17,7 @@
# Example usage:
# .//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.
@@ -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
diff --git a/Tools/scripts/BuildAutomation/BuilderScripts.cs b/Tools/scripts/BuildAutomation/BuilderScripts.cs
deleted file mode 100644
index 159dd619e9..0000000000
--- a/Tools/scripts/BuildAutomation/BuilderScripts.cs
+++ /dev/null
@@ -1,181 +0,0 @@
-using System.Collections.Generic;
-using UnityEditor;
-using UnityEditor.Build;
-using UnityEngine;
-using System;
-using System.Collections;
-using UnityEngine.Rendering;
-using UnityEngine.SceneManagement;
-
-// This script is used to automate the build process for different platforms.
-// When included in the project, it can be triggered from the script the game for teh given configuration.
-// Note that it's possible to have those as a button in the editor (see https://github.cds.internal.unity3d.com/unity/Megacity-Metro/blob/c3b1b16ff1f04f96fbfbcc3267696679ad4e8396/Megacity-Metro/Assets/Scripts/Utils/Editor/BuilderScript.cs)
-// Ideally we would like to pass scripting backend and platform as parameters instead of having different script per each combintation but the nature of calling this nmethod via script (via -executeMethod) is that it needs to be static and the parameters are not passed in a way that we can use them.
-// TODO: add iOS support
-public class BuilderScripts : MonoBehaviour
-{
- [MenuItem("Tools/Builder/Build Development Windows Il2cpp")]
- static void BuildWinIl2cpp()
- {
- // This part modifies Player Settings. We only use it (for our case) to modify scripting backend
- PlayerSettings.SetScriptingBackend(NamedBuildTarget.Standalone, ScriptingImplementation.IL2CPP);
- PlayerSettings.SetUseDefaultGraphicsAPIs(BuildTarget.StandaloneWindows64, false); // disable auto graphic to use our own custom list
- PlayerSettings.SetGraphicsAPIs(BuildTarget.StandaloneWindows64, new []{GraphicsDeviceType.Vulkan, GraphicsDeviceType.Direct3D11, GraphicsDeviceType.Direct3D12}); // We need to specify the graphics API for Android builds to ensure proper shader compilation. Vulkan is recommended for modern devices.
-
- // Below you can see additional settings that you can apply to the build:
- //PlayerSettings.SetGraphicsAPIs(BuildTarget.StandaloneWindows64, new []{GraphicsDeviceType.Direct3D12});
- //PlayerSettings.SetArchitecture(NamedBuildTarget.Standalone,0);
-
- // The settings that we applied above need to be saved.
- AssetDatabase.SaveAssets();
-
- // We want to build all scenes in build settings, so we collect them here.
- // If you want to build only specific scenes, then you could just use something like buildPlayerOptions.scenes = new[] { "Assets/Scenes/Menu.unity","Assets/Scenes/Main.unity" }; below.
- List scenesToAdd = new List();
- foreach (var scene in EditorBuildSettings.scenes)
- {
- if (scene.enabled)
- {
- Debug.Log("Adding scene to build: " + scene.path);
- scenesToAdd.Add(scene.path);
- }
- }
-
- // This is an equivalent of BuildPlayerOptions in the Unity Editor.
- // We want to choose development build, what platform are we targetting, where to save the build and which scenes to include.
- // Some of those options can be omitted when triggering this script from withing GUI since more implicit context is provided (targetGroup, subtarget)
- // subtarget = (int)StandaloneBuildSubtarget.Player
- // targetGroup = BuildTargetGroup.Standalone
- // extraScriptingDefines = new[] { "NETCODE_DEBUG", "UNITY_CLIENT" },
- var buildPlayerOptions = new BuildPlayerOptions
- {
- locationPathName = "./build/Windows_Il2cpp/PlaytestBuild.exe",
- target = BuildTarget.StandaloneWindows64,
- options = BuildOptions.Development,
- scenes = scenesToAdd.ToArray()
- };
-
- BuildPipeline.BuildPlayer(buildPlayerOptions);
- }
-
- [MenuItem("Tools/Builder/Build Development Windows Mono")]
- static void BuildWinMono()
- {
- PlayerSettings.SetScriptingBackend(NamedBuildTarget.Standalone, ScriptingImplementation.Mono2x);
- PlayerSettings.SetUseDefaultGraphicsAPIs(BuildTarget.StandaloneWindows64, false); // disable auto graphic to use our own custom list
- PlayerSettings.SetGraphicsAPIs(BuildTarget.StandaloneWindows64, new []{GraphicsDeviceType.Vulkan, GraphicsDeviceType.Direct3D11, GraphicsDeviceType.Direct3D12}); // We need to specify the graphics API for Android builds to ensure proper shader compilation. Vulkan is recommended for modern devices.
-
- AssetDatabase.SaveAssets();
-
- List scenesToAdd = new List();
- foreach (var scene in EditorBuildSettings.scenes)
- {
- if (scene.enabled)
- {
- Debug.Log("Adding scene to build: " + scene.path);
- scenesToAdd.Add(scene.path);
- }
- }
-
- var buildPlayerOptions = new BuildPlayerOptions
- {
- locationPathName = "./build/Windows_Mono/PlaytestBuild.exe",
- target = BuildTarget.StandaloneWindows64,
- options = BuildOptions.Development,
- scenes = scenesToAdd.ToArray()
- };
-
- BuildPipeline.BuildPlayer(buildPlayerOptions);
- }
-
- [MenuItem("Tools/Builder/Build Development Mac Mono")]
- static void BuildMacMono()
- {
- PlayerSettings.SetScriptingBackend(NamedBuildTarget.Standalone, ScriptingImplementation.Mono2x);
- PlayerSettings.SetUseDefaultGraphicsAPIs(BuildTarget.StandaloneOSX, false); // disable auto graphic to use our own custom list
- PlayerSettings.SetGraphicsAPIs(BuildTarget.StandaloneOSX, new []{GraphicsDeviceType.Metal}); // enforcing Metal Graphics API. Without this there will be shader errors in the final build.
-
- AssetDatabase.SaveAssets();
-
- List scenesToAdd = new List();
- foreach (var scene in EditorBuildSettings.scenes)
- {
- if (scene.enabled)
- {
- Debug.Log("Adding scene to build: " + scene.path);
- scenesToAdd.Add(scene.path);
- }
- }
-
- var buildPlayerOptions = new BuildPlayerOptions
- {
- locationPathName = "./build/macOS_Mono/PlaytestBuild.app",
- target = BuildTarget.StandaloneOSX,
- options = BuildOptions.Development,
- scenes = scenesToAdd.ToArray()
- };
-
- BuildPipeline.BuildPlayer(buildPlayerOptions);
- }
-
- [MenuItem("Tools/Builder/Build Development Mac Il2cpp")]
- static void BuildMacIl2cpp()
- {
- PlayerSettings.SetScriptingBackend(NamedBuildTarget.Standalone, ScriptingImplementation.IL2CPP);
- PlayerSettings.SetGraphicsAPIs(BuildTarget.StandaloneOSX, new []{GraphicsDeviceType.Metal}); // enforcing Metal Graphics API. Without this there will be shader errors in the final build.
-
- AssetDatabase.SaveAssets();
-
- List scenesToAdd = new List();
- foreach (var scene in EditorBuildSettings.scenes)
- {
- if (scene.enabled)
- {
- Debug.Log("Adding scene to build: " + scene.path);
- scenesToAdd.Add(scene.path);
- }
- }
-
- var buildPlayerOptions = new BuildPlayerOptions
- {
- locationPathName = "./build/macOS_Il2cpp/PlaytestBuild.app",
- target = BuildTarget.StandaloneOSX,
- options = BuildOptions.Development,
- scenes = scenesToAdd.ToArray()
- };
-
- BuildPipeline.BuildPlayer(buildPlayerOptions);
- }
-
- [MenuItem("Tools/Builder/Build Development Android Il2cpp")]
- static void BuildAndroidIl2cpp()
- {
- PlayerSettings.SetScriptingBackend(NamedBuildTarget.Android, ScriptingImplementation.IL2CPP);
- PlayerSettings.SetApplicationIdentifier(NamedBuildTarget.Android, "com.UnityTestRunner.UnityTestRunner"); // This is needed only for mobiles since by default the application identifier quite often contains invalid characters like spaces so we wan't to make sure that this has a valid value. It's needed only for mobile since that's an app store requirement
- PlayerSettings.SetUseDefaultGraphicsAPIs(BuildTarget.Android, false); // disable auto graphic to use our own custom list
- PlayerSettings.SetGraphicsAPIs(BuildTarget.Android, new []{GraphicsDeviceType.Vulkan}); // We need to specify the graphics API for Android builds to ensure proper shader compilation. Vulkan is recommended for modern devices.
- PlayerSettings.SetArchitecture(BuildTargetGroup.Android,1); // An integer value associated with the architecture of the build target. 0 - None, 1 - ARM64, 2 - Universal. most modern Android devices use the ARM64 architecture
-
- AssetDatabase.SaveAssets();
-
- List scenesToAdd = new List();
- foreach (var scene in EditorBuildSettings.scenes)
- {
- if (scene.enabled)
- {
- Debug.Log("Adding scene to build: " + scene.path);
- scenesToAdd.Add(scene.path);
- }
- }
-
- var buildPlayerOptions = new BuildPlayerOptions
- {
- locationPathName = "./build/Android_Il2cpp_Vulkan/PlaytestBuild.apk",
- target = BuildTarget.Android,
- options = BuildOptions.Development,
- scenes = scenesToAdd.ToArray()
- };
-
- BuildPipeline.BuildPlayer(buildPlayerOptions);
- }
-}
diff --git a/Tools/scripts/BuildAutomation/FileCopy.py b/Tools/scripts/BuildAutomation/FileCopy.py
deleted file mode 100644
index 5204fbb6b8..0000000000
--- a/Tools/scripts/BuildAutomation/FileCopy.py
+++ /dev/null
@@ -1,59 +0,0 @@
-import os
-import shutil
-import sys
-
-def main():
- """
- Cleans and prepares the 'Assets/Scripts/Editor' directory for build automation scripts.
- It deletes the directory if it exists, recreates it, and copies in the necessary
- assembly definition and C# script files.
- """
- # --- 1. Argument Validation ---
- if len(sys.argv) < 2:
- print("Error: Missing required argument.")
- print("Usage: python prepare_build_scripts.py ")
- sys.exit(1)
-
- project_root = sys.argv[1]
-
- # --- 2. Define File Paths ---
- # The target directory inside the Unity project
- target_dir = os.path.join(project_root, 'Assets', 'Scripts', 'Editor')
-
- # The source files for build automation
- source_asmdef = 'Tools/scripts/BuildAutomation/Unity.ProjectBuild.Editor.asmdef'
- source_script = 'Tools/scripts/BuildAutomation/BuilderScripts.cs'
-
- print(f"Preparing build scripts for project at: {project_root}")
- print(f"Target editor script directory: {target_dir}")
-
- # --- 3. Clean and Recreate Directory ---
- try:
- if os.path.exists(target_dir):
- print(f"Directory '{target_dir}' exists. Removing it.")
- shutil.rmtree(target_dir)
-
- print(f"Creating directory: {target_dir}")
- os.makedirs(target_dir)
-
- except OSError as e:
- print(f"Error managing directory: {e}")
- sys.exit(1)
-
- # --- 4. Copy Build Automation Files ---
- try:
- print(f"Copying '{source_asmdef}' to '{target_dir}'")
- shutil.copy(source_asmdef, target_dir)
-
- print(f"Copying '{source_script}' to '{target_dir}'")
- shutil.copy(source_script, target_dir)
-
- except IOError as e:
- print(f"Error copying files: {e}")
- sys.exit(1)
-
- print("\nSuccessfully prepared build automation scripts.")
-
-if __name__ == "__main__":
- main()
-
diff --git a/Tools/scripts/BuildAutomation/connect_services.py b/Tools/scripts/BuildAutomation/connect_services.py
deleted file mode 100644
index db11eeff13..0000000000
--- a/Tools/scripts/BuildAutomation/connect_services.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# This script modifies ProjectSettings.asset in order to connect the project to Services (like Relay). This is needed for Netcode related builds and can be probably skipped in other cases
-# As a Netcode team we usually use (during Playtesting) the following settings
-
-# Note that cloudProjectId, projectName and organizationId are defined as secrets
-
-# Notice that those parameters are included as defaults but in your yml file you can override them with your own values.
-
-import sys
-import re
-import argparse
-import os
-
-def parse_args():
- global args
- parser = argparse.ArgumentParser(description='Update ProjectSettings.asset in order to properly connect to services.')
- parser.add_argument('--project-settings-path', required=True, help='The absolute path to the project ProjectSettings.asset file that contains all of the services settings.')
- parser.add_argument('--cloud-project-ID', default=os.getenv("CLOUDPROJECTID"), help='ID of a cloud project to which we want to connect to.')
- parser.add_argument('--organization-ID', default=os.getenv("ORGANIZATIONID"), help="ID of the organization to which the cloud project belongs.")
- parser.add_argument('--project-name', default=os.getenv("PROJECTNAME"), help='Name of the project to which we want to connect to.')
- args = parser.parse_args()
-
-def main():
- """
- Modifies ProjectSettings.asset in order to connect the project to Services
- """
- parse_args()
-
- with open(args.project_settings_path, 'r') as f:
- content = f.read()
-
- # Use regex to replace the values. This is safer than simple string replacement.
- content = re.sub(r"cloudProjectId:.*", f"cloudProjectId: {args.cloud_project_ID}", content)
- content = re.sub(r"organizationId:.*", f"organizationId: {args.organization_ID}", content)
- content = re.sub(r"projectName:.*", f"projectName: {args.project_name}", content)
- # Ensure the project is marked as connected
- content = re.sub(r"cloudEnabled:.*", "cloudEnabled: 1", content)
-
- with open(args.project_settings_path, 'w', encoding='UTF-8', newline='\n') as f:
- f.write(content)
-
- print(f"[Linker] Successfully updated {args.project_settings_path} with Project ID: {args.cloud_project_ID}, Org ID: {args.organization_ID}, Project Name: {args.project_name}")
-
-if __name__ == "__main__":
- main()
-
-
diff --git a/Tools/scripts/BuildAutomation/disable-enable-burst.py b/Tools/scripts/BuildAutomation/disable-enable-burst.py
deleted file mode 100644
index d9cd0b29e6..0000000000
--- a/Tools/scripts/BuildAutomation/disable-enable-burst.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# An example usage would be "- python Tools/CI/Netcode/BuildAutomations/disable-enable-burst.py --project-path {{ project.path }} --platform WebGL"
-# This file aims to modify BurstAotSettings file which should be present under ProjectSettings folder.
-# Note that this requires Burst package to be installed as well as you need to specify the platform for which you are building since there are different settings for each. (this is taken from environment variable)
-# This script is not overriding existing settings file but completely replacing it
-
-import argparse
-import json
-import os
-
-# Function that parses arguments of the script
-def parse_args():
- global args
- parser = argparse.ArgumentParser(description="Enable or disable Burst compilation and specify Unity project details.")
-
- # Add the mutually exclusive group for --disable-burst and --enable-burst
- group = parser.add_mutually_exclusive_group(required=True)
- group.add_argument('--disable-burst', action='store_true', help='Disable Burst compilation.')
- group.add_argument('--enable-burst', action='store_true', help='Enable Burst compilation.')
-
- # Add additional arguments
- parser.add_argument('--project-path', required=True, help='Specify the location of the Unity project.')
-
- args = parser.parse_args()
-
-
-# This function creates a new burst settings file with default values. Notice that this should almost always not be used since assumption is that in our case we have projects with Burst preinstalled
-# For the "default" values I used values from NetcodeSamples project in DOTS-monorepo
-def create_config(settings_path):
- config_name = os.path.join(settings_path, 'BurstAotSettings_{}.json'.format(resolve_target()))
- monobehaviour = {
- 'Version': 4,
- 'EnableBurstCompilation': True,
- 'EnableOptimisations': True,
- 'EnableSafetyChecks': False,
- 'EnableDebugInAllBuilds': False,
- 'CpuMinTargetX32': 0,
- 'CpuMaxTargetX32': 0,
- 'CpuMinTargetX64': 0,
- 'CpuMaxTargetX64': 0,
- 'CpuTargetsX32': 6,
- 'CpuTargetsX64': 72,
- 'OptimizeFor': 0
- }
-
- data = {'MonoBehaviour': monobehaviour}
- with open(config_name, 'w', encoding='UTF-8', newline='\n') as f:
- json.dump(data, f)
- return config_name
-
-
-# Burst has specific files for each platform, so we need to resolve the target platform to get the correct settings file.
-# Note that this jobs uses environment variables to pass parameters to the script.
-def resolve_target():
- # Get the platform value from the environment variable
- platform_key = os.environ.get('PLATFORM_WIN64_MAC_ANDROID').lower()
-
- resolved_target = platform_key
- if 'win64' == platform_key:
- resolved_target = 'StandaloneWindows'
- elif 'mac' == platform_key:
- resolved_target = 'StandaloneOSX'
- elif 'android' == platform_key:
- resolved_target = 'Android'
- else:
- raise ValueError("Unsupported platform: {}".format(platform) + "Check if you are passing correct argument for one of the supported platforms: StandaloneWindows or StandaloneLinux")
-
- return resolved_target
-
-
-# This function either returns existing burst settings or creates new if a file was not found
-def get_or_create_burst_AOT_config():
- settings_path = os.path.join(args.project_path, 'ProjectSettings')
- if not os.path.isdir(settings_path):
- os.mkdir(settings_path)
- config_names = [os.path.join(settings_path, filename) for filename in os.listdir(settings_path) if filename.startswith("BurstAotSettings_{}".format(resolve_target()))]
- if not config_names:
- return [create_config(settings_path)]
- return config_names
-
-
-# Function that sets the AOT status in the burst settings file (essentially enables or disables burst compilation)
-def set_burst_AOT(config_file, status):
- config = None
- with open(config_file, 'r') as f:
- config = json.load(f)
-
- assert config is not None, 'AOT settings not found; did the burst-enabled build finish successfully?'
-
- config['MonoBehaviour']['EnableBurstCompilation'] = status
- with open(config_file, 'w', encoding='UTF-8', newline='\n') as f:
- json.dump(config, f)
-
-
-def main():
- parse_args()
- config_names = get_or_create_burst_AOT_config()
-
- platform_key = os.environ.get('PLATFORM_WIN64_MAC_ANDROID').lower()
- print(f"Burst compilation script: Unity project path is {args.project_path}")
- print(f"Burst compilation script: Target platform is {platform_key}")
-
- if args.disable_burst:
- print('BURST COMPILATION: DISABLED')
-
- for config_name in config_names:
- set_burst_AOT(config_name, False)
-
- elif args.enable_burst:
- print('BURST COMPILATION: ENABLED')
-
- for config_name in config_names:
- set_burst_AOT(config_name, True)
-
- else:
- sys.exit('BURST COMPILATION: unexpected value: {}'.format(args.enable_burst))
-
-
-
-if __name__ == '__main__':
- main()
diff --git a/Tools/scripts/BuildAutomation/manifest_update.py b/Tools/scripts/BuildAutomation/manifest_update.py
deleted file mode 100644
index 0ad8913b8e..0000000000
--- a/Tools/scripts/BuildAutomation/manifest_update.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# This script is used to replace a package from the project manifest.json with a local version.
-# The goal is that you will trigger the build process from your branch (for example release/1.2.3) and package from this branch will be use in the project manifest.1
-# Note that for now this script is assuming that such package already has an entry in the manifest
-# TODO: consider if it makes sense to just add new manifest entry (to test what?)
-
-import json
-import argparse
-import os
-
-def parse_args():
- global args
- parser = argparse.ArgumentParser(description='Update a Unity project manifest to point to the local package version.')
- parser.add_argument('--manifest-path', required=True, help='The absolute path to the project manifest.json file.')
- parser.add_argument('--package-name', default="com.unity.netcode.gameobjects", help="The name of the package to modify in the manifest.")
- parser.add_argument('--local-package-path', required=True, help='The absolute file path to the local package source directory.')
- args = parser.parse_args()
-
-def main():
- """
- Updates a project's manifest.json to use package under passed local-package-path,
- and then prints the version of that local package.
- """
- parse_args()
-
- # Update the target project's manifest
- try:
- with open(args.manifest_path, 'r') as f:
- manifest_data = json.load(f)
-
- local_path_normalized = args.local_package_path.replace(os.sep, '/')
- manifest_data["dependencies"][args.package_name] = f"file:{local_path_normalized}"
-
- with open(args.manifest_path, 'w', encoding='UTF-8', newline='\n') as f:
- json.dump(manifest_data, f, indent=4)
-
- print(f"Successfully updated manifest at '{args.manifest_path}'")
- print(f"Set '{args.package_name}' to use local package at '{args.local_package_path}'")
- except Exception as e:
- print(f"Error updating manifest: {e}")
- exit(1)
-
- # --- Read and report the local package's version for log confirmation---
- # This is only for debug purposes
- try:
- # Construct the path to the local package's package.json file
- local_package_json_path = os.path.join(args.local_package_path, 'package.json')
-
- with open(local_package_json_path, 'r') as f:
- local_package_data = json.load(f)
-
- # Extract the version, providing a default if not found
- local_package_version = local_package_data.get('version', 'N/A')
-
- print(f"--> Verified local '{args.package-name}' version is: {local_package_version}")
-
- except FileNotFoundError:
- print(f"Warning: Could not find package.json at '{local_package_json_path}'")
- except Exception as e:
- print(f"Error reading local package version: {e}")
-
-if __name__ == "__main__":
- main()
diff --git a/Tools/scripts/BuildAutomation/validate_params.py b/Tools/scripts/BuildAutomation/validate_params.py
deleted file mode 100644
index 4c105836cc..0000000000
--- a/Tools/scripts/BuildAutomation/validate_params.py
+++ /dev/null
@@ -1,58 +0,0 @@
-import os
-import sys
-
-# --- Configuration ---
-# A dictionary that maps each environment variable to a set of its allowed values.
-# This is the single source of truth for all validation.
-VALIDATION_RULES = {
- 'SCRIPTING_BACKEND_IL2CPP_MONO': {'il2cpp', 'mono'},
- 'BURST_ON_OFF': {'on', 'off'},
- 'PLATFORM_WIN64_MAC_ANDROID': {'win64', 'mac', 'android'}
-}
-
-def main():
- """
- Validates Yamato environment variables using a rule-based dictionary.
- Exits with 1 if any variable is invalid, otherwise exits with 0.
- """
- all_params_valid = True
-
- for var_name, allowed_values in VALIDATION_RULES.items():
- actual_value = os.environ.get(var_name, '').lower()
- allowed_values_lower = {v.lower() for v in allowed_values}
-
- if actual_value not in allowed_values_lower:
- print(
- f"ERROR: Invalid {var_name}: '{actual_value}'. "
- f"Allowed values are: {list(allowed_values)}",
- file=sys.stderr
- )
- all_params_valid = False
-
- platform = os.environ.get('PLATFORM_WIN64_MAC_ANDROID', '').lower()
- scripting_backend = os.environ.get('SCRIPTING_BACKEND_IL2CPP_MONO', '').lower()
-
- if platform == 'mac' and scripting_backend == 'il2cpp':
- print(
- "ERROR: Invalid Configuration: The 'mac' platform with the 'il2cpp' "
- "Note that for now windows machine is used for building project and it's a known limitation that mac builds (via windows machine) can be done only with mono",
- file=sys.stderr
- )
- all_params_valid = False
-
- if platform == 'android' and scripting_backend == 'mono':
- print(
- "ERROR: Invalid Configuration: The 'android' platform with the 'mono' "
- "Note that mobile builds are not supporting mono and need il2cpp scripting backend",
- file=sys.stderr
- )
- all_params_valid = False
-
- if not all_params_valid:
- print("\nOne or more parameters failed validation. Halting build.", file=sys.stderr)
- sys.exit(1)
-
- print("All parameters are valid. Proceeding with the build.")
-
-if __name__ == "__main__":
- main()
\ No newline at end of file
diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md
index 9d1075d0b3..72344cc2f9 100644
--- a/com.unity.netcode.gameobjects/CHANGELOG.md
+++ b/com.unity.netcode.gameobjects/CHANGELOG.md
@@ -29,6 +29,85 @@ Additional documentation and release notes are available at [Multiplayer Documen
### Obsolete
+## [3.1.0] - 2026-10-04
+
+### Fixed
+
+- Fixed an issue where mixed authority nested `NetworkTransform` instances could stop child/nested instances from updating because an authoritative `NetworkTransform` (root or otherwise) would remove the `NetworkObject` from the update group, preventing non-authoritative instances from updating their state on the authority side. (#4169)
+
+## [2.13.3] - 2026-09-14
+
+### Changed
+
+- Changed `NetworkTransform.UseHalfFloatPrecision` to synchronize position with a resolution of approximately 1mm regardless of how far an object has travelled. Previously the resolution could degrade to approximately 3cm. This does not increase bandwidth, but projects using `NetworkTransform.UseUnreliableDeltas` will send full precision position updates more often. (#4128)
+
+### Fixed
+
+- Fixed issue where scenes additively loaded before a session started were tracked as loaded on the server but had no scene handle entries, which caused `NetworkSceneManager.UnloadScene` to log an error and leave the scene registered as loaded even though it unloaded on all peers. (#4145)
+- Issue where `NetworkTransform` interpolated towards a point in time taken from the local clock rather than the server clock that state updates are stamped on, which starved the interpolator on clients and reduced interpolation to snapping between state updates. (#4133)
+- Issue where `NetworkTransform.GetTickLatencyInSeconds` returned an absolute network timestamp that grew for as long as the session ran, rather than the tick latency as a duration in seconds that it is documented to return. (#4133)
+- Issue where lerp smoothing was applied per frame instead of over time, which caused the `Lerp` and `SmoothDampening` interpolation types to smooth by different amounts at different frame rates. Results at 60fps are unchanged. (#4130)
+- Issue where setting a maximum interpolation time of 1.0 would stop a `NetworkTransform` from interpolating at all when using the `Lerp` or `SmoothDampening` interpolation types. (#4130)
+- Issue where objects using `NetworkTransform.UseHalfFloatPrecision` appeared to jitter on non-authority instances while they were stationary or coming to rest, even though the authority was not moving them. (#4128)
+
+## [2.13.2] - 2026-08-16
+
+### Fixed
+
+- Issue where in a distributed authority session changing a NetworkVariable prior to changing ownership in the same call-stack would result in the NetworkVariable not being synchronized. (#4107)
+- Resolved GC allocations in some hot paths. (#4119)
+- 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)
+
+
+## [2.13.1] - 2026-07-19
+
+### Added
+
+- Single player session section to provide users with information about `SinglePlayerTransport` and an example script of how to switch between single and multi player sessions. (#4062)
+
+### Fixed
+
+- Issue where `NetworkAnimator` did no bounds check on the parameter index read prior to obtaining a pointer to the location within the array. (#4090)
+- Issue where scene migration in a distributed authority session would throw an exception on clients migrating their owned `NetworkObject` instances to a different scene.(#4086)
+- Issue where migrating a dynamically spawned or in-scene placed `NetworkObject` into a different scene during awake could result in that spawned instance to not be synchronized. (#4086)
+- Issue where a NullReferenceException was thrown when a non-authority failed to spawn a NetworkObject. (#4067)
+- 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)
+- 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)
+- Issue where NetworkRigidbodyBase was not applying rotation correctly when using Rigidbody2D. (#4012)
+- 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)
+- Fixed AnticipatedNetworkTransform not respecting the InLocalSpace flag. (#3995)
+
+## [2.13.0] - 2026-06-21
+
+### Added
+
+- Added support for Unity's Fast Enter Play Mode with domain reload disabled. (#3956)
+- RPC messages now log any time they are not processed. (#3994)
+
+### Changed
+
+- Changed replaced define usages of `DEVELOPMENT_BUILD || UNITY_EDITOR` and a few niche uses of `DEVELOPMENT_BUILD` with `DEBUG`. (#4006)
+
+### Deprecated
+
+- Deprecated the nullable boolean `NetworkObject.IsSceneObject` and introduced `NetworkObject.InScenePlaced`. (#4000)
+
+## [2.12.0] - 2026-05-24
+
+### Added
+
+- Added a new variant of `UnityTransport.GetDefaultPipelineConfigurations` that takes a reference to the created `NetworkDriver`. This will register all pipeline stages that `UnityTransport` requires, removing the need to manually register them in your own custom driver constructor. (#3980)
+
+### Changed
+
+- `NetworkMetricsPipelineStage` is now defined even when the multiplayer tools package is not installed, removing the need to guard its registration behind a version define when using a custom driver in `UnityTransport`. (#3980)
+
+### Deprecated
+
+- Deprecated a number of methods that were no longer valid or being used. (#3987)
+
### [2.11.2] - 2026-05-01
### Fixed
diff --git a/com.unity.netcode.gameobjects/Documentation~/TableOfContents.md b/com.unity.netcode.gameobjects/Documentation~/TableOfContents.md
index e78e7192f6..24219a83e5 100644
--- a/com.unity.netcode.gameobjects/Documentation~/TableOfContents.md
+++ b/com.unity.netcode.gameobjects/Documentation~/TableOfContents.md
@@ -18,6 +18,7 @@
* [Connection approval](basics/connection-approval.md)
* [Max players](basics/maxnumberplayers.md)
* [Transports](advanced-topics/transports.md)
+ * [Single player sessions](advanced-topics/singleplayer.md)
* [Unity Relay](relay/relay.md)
* [Command-line arguments](command-line-arguments.md)
* [Network components](network-components.md)
@@ -70,15 +71,17 @@
* [Network update loop reference](advanced-topics/network-update-loop-system/network-update-loop-reference.md)
* [Network time and ticks](advanced-topics/networktime-ticks.md)
* [Serialization](serialization.md)
+ * [Serialization overview](advanced-topics/serialization/serialization-overview.md)
* [C# primitives](advanced-topics/serialization/cprimitives.md)
* [Unity primitives](advanced-topics/serialization/unity-primitives.md)
* [Enum types](advanced-topics/serialization/enum-types.md)
* [Arrays](advanced-topics/serialization/serialization-arrays.md)
- * [INetworkSerializable](advanced-topics/serialization/inetworkserializable.md)
- * [INetworkSerializeByMemcpy](advanced-topics/serialization/inetworkserializebymemcpy.md)
- * [Custom serialization](advanced-topics/custom-serialization.md)
- * [NetworkObject serialization](advanced-topics/serialization/networkobject-serialization.md)
+ * [Customize serializable types with INetworkSerializable](advanced-topics/serialization/inetworkserializable.md)
+ * [Serialize unmanaged structs with INetworkSerializeByMemcpy](advanced-topics/serialization/inetworkserializebymemcpy.md)
+ * [NetworkObject and NetworkBehaviour serialization](advanced-topics/serialization/networkobject-serialization.md)
* [FastBufferWriter and FastBufferReader](advanced-topics/fastbufferwriter-fastbufferreader.md)
+ * [BufferSerializer](advanced-topics/bufferserializer.md)
+ * [Custom serialization](advanced-topics/custom-serialization.md)
* [Scene management](scene-management.md)
* [Scene management overview](basics/scenemanagement/scene-management-overview.md)
* [Integrated management](integrated-management.md)
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/bufferserializer.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/bufferserializer.md
index 22375bccf5..0f5df51f15 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/bufferserializer.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/bufferserializer.md
@@ -1,5 +1,8 @@
# BufferSerializer
+> [!NOTE]
+> Read the [Serialization overview](./serialization/serialization-overview.md) page to understand the basics of serialization before learning how to use `BufferSerializer`.
+
`BufferSerializer` 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:
- Rather than writing separate methods for serializing and deserializing, `BufferSerializer` 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
- For performance, you can use `PreCheck(int amount)` followed by `SerializeValuePreChecked()` to perform bounds checking for multiple fields at once.
- 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`.
+
+## Serializing custom types
+
+`BufferSerializer` 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.
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/custom-serialization.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/custom-serialization.md
index 7a04e2f123..f1210fbc95 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/custom-serialization.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/custom-serialization.md
@@ -1,93 +1,71 @@
# Custom serialization
-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:
+> [!NOTE]
+> Read the [Serialization overview](./serialization/serialization-overview.md) page to understand the basics of serialization before learning how to customize serialization.
-``
-Custom Types => Built In Types => INetworkSerializable
-``
+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.
-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.
+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.
-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.
+Custom serialization is implemented slightly differently for RPCs and NetworkVariables. The examples on this page provide different ways to serialization a custom health struct.
-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.
+[!code-cs[](../../Tests/Editor/DocumentationCodeSamples/Serialization/SerializationCustomization.cs#HealthStruct)]
-### Serialize a type in a Remote Procedure Call (RPC)
+## FastBufferReader and FastBufferWriter
-> [!NOTE]
-> 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.
+[`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.
-To register a custom type, or override an already handled type, you need to create extension methods for `FastBufferReader.ReadValueSafe()` and `FastBufferWriter.WriteValueSafe()`:
+[!code-cs[](../../Tests/Editor/DocumentationCodeSamples/Serialization/SerializationCustomization.cs#FastBuffer)]
-```csharp
-// Tells the Netcode how to serialize and deserialize Url in the future.
-// The class name doesn't matter here.
-public static class SerializationExtensions
-{
- public static void ReadValueSafe(this FastBufferReader reader, out Url url)
- {
- reader.ReadValueSafe(out string val);
- url = new Url(val);
- }
-
- public static void WriteValueSafe(this FastBufferWriter writer, in Url url)
- {
- writer.WriteValueSafe(url.Value);
- }
-}
-```
+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)
-The code generation for RPCs will automatically pick up and use these functions, and they'll become available via `FastBufferWriter` and `FastBufferReader` directly.
+## BufferSerializer
-You can also optionally use the same method to add support for `BufferSerializer.SerializeValue()`, if you wish, which will make this type readily available within [`INetworkSerializable`](serialization/inetworkserializable.md) types:
+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):
-```csharp
-// The class name doesn't matter here.
-public static class SerializationExtensions
-{
- public static void SerializeValue(this BufferSerializer serializer, ref Url url) where TReaderWriter: IReaderWriter
- {
- if (serializer.IsReader)
- {
- url = new Url();
- }
- serializer.SerializeValue(ref url.Value);
- }
-}
-```
+[!code-cs[](../../Tests/Editor/DocumentationCodeSamples/Serialization/SerializationCustomization.cs#BufferSerializer)]
-Additionally, you can also add extensions for `FastBufferReader.ReadValue()`, `FastBufferWriter.WriteValue()`, and `BufferSerializer.SerializeValuePreChecked()` to provide more optimal implementations for manual serialization using `FastBufferReader.TryBeginRead()`, `FastBufferWriter.TryBeginWrite()`, and `BufferSerializer.PreCheck()`, respectively. However, none of these will be used for serializing RPCs - only `ReadValueSafe` and `WriteValueSafe` are used.
+## Remote procedure call (RPCs)
-### For NetworkVariable
+> [!NOTE]
+> 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.
-`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 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).
-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:
+The code generation for RPCs will automatically pick up and use these functions, as they'll become available via `FastBufferWriter` and `FastBufferReader` directly.
-```csharp
-UserNetworkVariableSerialization.WriteValue = SerializationExtensions.WriteValueSafe;
-UserNetworkVariableSerialization.ReadValue = SerializationExtensions.ReadValueSafe;
-```
+## NetworkVariable
+
+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.
-You can also use lambda expressions here:
+First you will need to create extension methods for `FastBufferReader.ReadValueSafe()` and `FastBufferWriter.WriteValueSafe()` as [outlined above](#fastbufferreader-and-fastbufferwriter).
+
+Secondly, somewhere in your application startup (before any `NetworkVariable`s using the affected types will be serialized), add the following:
```csharp
-UserNetworkVariableSerialization.WriteValue = (FastBufferWriter writer, in Url url) =>
-{
- writer.WriteValueSafe(url.Value);
-};
-
-UserNetworkVariableSerialization.ReadValue = (FastBufferReader reader, out Url url)
-{
- reader.ReadValueSafe(out string val);
- url = new Url(val);
-};
+UserNetworkVariableSerialization.WriteValue = SerializationExtensions.WriteValueSafe;
+UserNetworkVariableSerialization.ReadValue = SerializationExtensions.ReadValueSafe;
+UserNetworkVariableSerialization.DuplicateValue = (in Health value, ref Health duplicatedValue) => duplicatedValue = value;
```
-When you create an extension method in `NetworkVariable` you need to implement the following values:
+`DuplicateValue` should return a complete deep copy of the value that `NetworkVariable` 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.
+
+> [!NOTE]
+> `WriteValue`, `ReadValue` and `DuplicateValue` all need to be defined to customize your serialization.
+
+> [!NOTE]
+> `WriteValue` and `ReadValue` will not be used if a type implements `INetworkSerializable` or [`INetworkSerializeByMemcpy`](./serialization/inetworkserializebymemcpy.md).
+
+### Serializing delta updates
+
+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:
+
+- `WriteDelta`
+- `ReadDelta`
+
+> [!NOTE]
+> Both `WriteDelta` and `ReadDelta` need to be defined for either to be used.
-- `WriteValue`
-- `ReadValue`
-- `DuplicateValue`
+Here is a full implementation of a custom type with the methods needed for `UserNetworkVariableSerialization`
-`DuplicateValue` returns a complete deep copy of the value that `NetworkVariable` 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.
+[!code-cs[](../../Tests/Runtime/DocumentationCodeSamples/NetworkVariable/CustomSerializationDocsTests.cs#HealthExample)]
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/fastbufferwriter-fastbufferreader.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/fastbufferwriter-fastbufferreader.md
index 1ac9b0f9d3..7b9d5d65c3 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/fastbufferwriter-fastbufferreader.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/fastbufferwriter-fastbufferreader.md
@@ -1,5 +1,8 @@
# FastBufferWriter and FastBufferReader
+> [!NOTE]
+> Read the [Serialization overview](./serialization/serialization-overview.md) page to understand the basics of serialization before learning about `FastBufferWriter` and `FastBufferReader`.
+
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.
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.
@@ -79,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.
@@ -156,3 +159,7 @@ Packing values is done using the utility classes `BytePacker` and `ByteUnpacker`
| uint | 30 bits (0 to 1,073,741,824) |
| long | 60 bits + sign bit (-1,152,921,504,606,846,976 to 1,152,921,504,606,846,975) |
| ulong | 61 bits (0 to 2,305,843,009,213,693,952) |
+
+## Serializing custom types
+
+`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.
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/message-system/rpc-params.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/message-system/rpc-params.md
index 28d0607ef3..7c37bd606d 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/message-system/rpc-params.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/message-system/rpc-params.md
@@ -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
@@ -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.
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/message-system/rpc.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/message-system/rpc.md
index 1fb5c3dcc4..ac95d63bd7 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/message-system/rpc.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/message-system/rpc.md
@@ -328,3 +328,4 @@ void Update()
## Additional resources
* [RPC parameters](rpc-params.md)
+* [Customizing serialization](../custom-serialization.md#remote-procedure-call-rpcs)
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/network-prefab-handler.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/network-prefab-handler.md
index 6608534375..8eab667a68 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/network-prefab-handler.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/network-prefab-handler.md
@@ -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
@@ -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`).
@@ -55,7 +55,7 @@ public abstract class NetworkPrefabInstanceHandlerWithData : 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
@@ -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
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/network-update-loop-system/network-update-loop-reference.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/network-update-loop-system/network-update-loop-reference.md
index fd013937a4..72ec0db77c 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/network-update-loop-system/network-update-loop-reference.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/network-update-loop-system/network-update-loop-reference.md
@@ -6,7 +6,7 @@ The following diagrams provide insight into the Network Update Loop process and
-
+
@@ -14,6 +14,6 @@ The following diagrams provide insight into the Network Update Loop process and
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/networkobject-parenting.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/networkobject-parenting.md
index 435edf39a5..a2c6c755ea 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/networkobject-parenting.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/networkobject-parenting.md
@@ -26,7 +26,7 @@ If you aren't familiar with transform parenting in Unity, then it's recommended
### OnNetworkObjectParentChanged
-[`NetworkBehaviour.OnNetworkObjectParentChanged`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.html#Unity_Netcode_NetworkBehaviour_OnNetworkObjectParentChanged_Unity_Netcode_NetworkObject_) is a virtual method you can override to be notified when a NetworkObject component's parent has changed. The [`MonoBehaviour.OnTransformParentChanged()`](https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnTransformParentChanged.html) method is used by NetworkObject component to catch `transform.parent` changes and notify its associated NetworkBehaviour components.
+[`NetworkBehaviour.OnNetworkObjectParentChanged`](xref:Unity.Netcode.NetworkBehaviour.OnNetworkObjectParentChanged*) is a virtual method you can override to be notified when a NetworkObject component's parent has changed. The [`MonoBehaviour.OnTransformParentChanged()`](https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnTransformParentChanged.html) method is used by NetworkObject component to catch `transform.parent` changes and notify its associated NetworkBehaviour components.
```csharp
///
@@ -49,7 +49,7 @@ The [owner](../terms-concepts/ownership.md) of a NetworkObject can always parent
By default, only the [authority](../terms-concepts/authority.md) of a NetworkObject can parent a NetworkObject under a non-networked object. This means in a client-server game, only the server (or host) can control NetworkObject component parenting. In a distributed authority game the [owner](../terms-concepts/ownership.md) of the object can always parent the object.
-To allow the [owner](../terms-concepts/ownership.md) to parent their owned NetworkObject in a client-server game, use the [`NetworkObject.AllowOwnerToParent`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.html#Unity_Netcode_NetworkObject_AllowOwnerToParent) property.
+To allow the [owner](../terms-concepts/ownership.md) to parent their owned NetworkObject in a client-server game, use the [`NetworkObject.AllowOwnerToParent`](xref:Unity.Netcode.NetworkObject.AllowOwnerToParent) property.

@@ -78,7 +78,7 @@ If you plan on parenting in-scene placed NetworkObject components with a player
For more information, refer to:
- [Real World In-scene NetworkObject Parenting of Players Solution](inscene_parenting_player.md)
-- [Scene Event Notifications](../basics/scenemanagement/scene-events#scene-event-notifications)
+- [Scene Event Notifications](../basics/scenemanagement/scene-events.md#scene-event-notifications)
- [In-Scene NetworkObjects](../basics/scenemanagement/inscene-placed-networkobjects.md)
### WorldPositionStays usage
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/networktime-ticks.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/networktime-ticks.md
index 1742f87805..500b3d4b7c 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/networktime-ticks.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/networktime-ticks.md
@@ -183,6 +183,6 @@ For games with short play sessions casting the time to float is safe or `TimeAsF
> [!NOTE]
> The properties of the `NetworkTimeSystem` should be left untouched on the server/host. Changing the values on the client is sufficient to change the behavior of the time system.
-The way network time gets calculated can be configured in the `NetworkTimeSystem` if needed. Refer to the [API docs](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkTimeSystem.html) for information about the properties which can be modified. All properties can be safely adjusted at runtime. For instance, buffer values can be increased for a player with a bad connection.
+The way network time gets calculated can be configured in the `NetworkTimeSystem` if needed. Refer to the [API docs](xref:Unity.Netcode.NetworkTimeSystem) for information about the properties which can be modified. All properties can be safely adjusted at runtime. For instance, buffer values can be increased for a player with a bad connection.
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/physics.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/physics.md
index 8a309cca24..134a78cb43 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/physics.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/physics.md
@@ -34,7 +34,7 @@ Since PhysX has no concept of local space, it can be difficult to synchronize tw
## Using AttachableBehaviour or Joint
-The implementation of physics in a networked project differs from a single player project. This is especially true when you're using NetworkTransform and NetworkRigidbody components with [`NetworkRigidbody.UseRigidBodyForMotion`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.Components.NetworkRigidbodyBase.html#Unity_Netcode_Components_NetworkRigidbodyBase_UseRigidBodyForMotion) enabled. Deciding whether to use a Joint or an AttachableBehaviour component depends on your project's requirements.
+The implementation of physics in a networked project differs from a single player project. This is especially true when you're using NetworkTransform and NetworkRigidbody components with [`NetworkRigidbody.UseRigidBodyForMotion`](xref:Unity.Netcode.Components.NetworkRigidbodyBase.UseRigidBodyForMotion) enabled. Deciding whether to use a Joint or an AttachableBehaviour component depends on your project's requirements.
For example, if you want to create world items that players can pick up, you may have the following requirements:
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/inetworkserializable.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/inetworkserializable.md
index 36d83416ba..ab60e161c6 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/inetworkserializable.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/inetworkserializable.md
@@ -1,9 +1,14 @@
-# INetworkSerializable
+# Customize serializable types with INetworkSerializable
-You can use the `INetworkSerializable` interface to define custom serializable types.
+> [!NOTE]
+> Read the [Serialization overview](./serialization-overview.md) page to understand the basics of serialization before customizing serializable types with `INetworkSerializable`.
+
+You can use the `INetworkSerializable` interface to define custom serializable types. This interface has one function: `NetworkSerialize(BufferSerializer serializer)`, which ingests a bi-directional [`BufferSerializer`](../bufferserializer.md) that you can use to implement bi-directional custom serialization.
+
+`INetworkSerializable` can be implemented on both managed and unmanaged types, although serializing managed types isn't recommended because it can reduce your game's performance.
```csharp
-struct MyComplexStruct : INetworkSerializable
+struct SpawnPoint : INetworkSerializable
{
public Vector3 Position;
public Quaternion Rotation;
@@ -18,24 +23,20 @@ struct MyComplexStruct : INetworkSerializable
}
```
-Types implementing `INetworkSerializable` are supported by `NetworkSerializer`, `RPC` s and `NetworkVariable` s.
+Types implementing `INetworkSerializable` are supported by [`FastBufferReader` and `FastBufferWriter`](../fastbufferwriter-fastbufferreader.md), [`RPC`s'](../message-system/rpc.md), and [`NetworkVariable`s](../../basics/networkvariable.md).
```csharp
-
[Rpc(SendTo.Server)]
-void MyServerRpc(MyComplexStruct myStruct) { /* ... */ }
+void SpawnAtPointRpc(SpawnPoint spawnPoint) { /* ... */ }
-void Update()
+void DoSpawnHere()
{
- if (Input.GetKeyDown(KeyCode.P))
+ var spawnPoint = new SpawnPoint
{
- MyServerRpc(
- new MyComplexStruct
- {
- Position = transform.position,
- Rotation = transform.rotation
- }); // Client -> Server
- }
+ Position = transform.position,
+ Rotation = transform.rotation
+ };
+ SpawnAtPointRpc(spawnPoint); // Client -> Server
}
```
@@ -59,7 +60,7 @@ The following example explores a more advanced use case.
```csharp
-public struct MyMoveStruct : INetworkSerializable
+public struct SpawnWithMovement : INetworkSerializable
{
public Vector3 Position;
public Quaternion Rotation;
@@ -125,7 +126,7 @@ Review the following example:
```csharp
-public struct MyStructA : INetworkSerializable
+public struct SpawnPoint : INetworkSerializable
{
public Vector3 Position;
public Quaternion Rotation;
@@ -137,17 +138,17 @@ public struct MyStructA : INetworkSerializable
}
}
-public struct MyStructB : INetworkSerializable
+public struct SpawnInfo : INetworkSerializable
{
public int SomeNumber;
public string SomeText;
- public MyStructA StructA;
+ public SpawnPoint SpawnPoint;
void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter
{
serializer.SerializeValue(ref SomeNumber);
serializer.SerializeValue(ref SomeText);
- StructA.NetworkSerialize(serializer);
+ SpawnPoint.NetworkSerialize(serializer);
}
}
```
@@ -167,7 +168,7 @@ While you can have nested `INetworkSerializable` implementations (an `INetworkSe
```csharp
/// This isn't supported.
-public struct MyStructB : MyStructA
+public struct SpawnInfo : SpawnPoint
{
public int SomeNumber;
public string SomeText;
@@ -232,4 +233,4 @@ Then declare this network variable like so:
```csharp
NetworkVariable myVar = new NetworkVariable();
-```
\ No newline at end of file
+```
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/inetworkserializebymemcpy.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/inetworkserializebymemcpy.md
index 7a684dbaba..b79df9ff27 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/inetworkserializebymemcpy.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/inetworkserializebymemcpy.md
@@ -1,4 +1,7 @@
-# INetworkSerializeByMemcpy
+# Serialize unmanaged structs with INetworkSerializeByMemcpy
+
+> [!NOTE]
+> Read the [Serialization overview](./serialization-overview.md) page to understand the basics of serialization before using `INetworkSerializeByMemcpy` to serialize unmanaged structs.
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.
@@ -14,7 +17,7 @@ public struct MyStruct : INetworkSerializeByMemcpy
}
```
-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`.
+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](../message-system/rpc.md) and [`NetworkVariable`s](../../basics/networkvariable.md), as well as in other contexts such as with [`BufferSerializer<>`](../bufferserializer.md) or [`FastBufferReader`, and `FastBufferWriter`](../fastbufferwriter-fastbufferreader.md).
```csharp
public NetworkVariable> GuidVar;
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/networkobject-serialization.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/networkobject-serialization.md
index 9ca778028d..d3800a7b09 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/networkobject-serialization.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/networkobject-serialization.md
@@ -1,14 +1,18 @@
-# NetworkObject and NetworkBehaviour
+# NetworkObject and NetworkBehaviour serialization
-`GameObjects`, `NetworkObjects` and NetworkBehaviour aren't serializable types so they can't be used in `RPCs` or `NetworkVariables` by default.
+> [!NOTE]
+> Read the [Serialization overview](./serialization-overview.md) page to understand the basics of serialization before learning how to serialize `NetworkObjects` and `NetworkBehaviours`.
+
+`GameObject`, [`NetworkObject`](../../components/core/networkobject.md) and [`NetworkBehaviour`](../../components/core/networkbehaviour.md) aren't serializable types so they can't be used in [`RPC`s](../message-system/rpc.md) or [`NetworkVariable`s](../../basics/networkvariable.md) by default.
-There are two convenience wrappers which can be used to send a reference to a NetworkObject or a NetworkBehaviour over RPCs or `NetworkVariables`.
+There are two convenience wrappers which can be used to send a reference to a `NetworkObject` or a `NetworkBehaviour` over an `RPC` or in a `NetworkVariable`.
## NetworkObjectReference
-`NetworkObjectReference` can be used to serialize a reference to a NetworkObject. It can only be used on already spawned `NetworkObjects`.
+`NetworkObjectReference` can be used to serialize a reference to a `NetworkObject`. It can only be used on already spawned `NetworkObject`s.
Here is an example of using NetworkObject reference to send a target NetworkObject over an RPC:
+
```csharp
public class Weapon : NetworkBehaviour
{
@@ -36,6 +40,7 @@ public class Weapon : NetworkBehaviour
### Implicit Operators
There are also implicit operators which convert from/to `NetworkObject/GameObject` which can be used to simplify code. For instance the above example can also be written in the following way:
+
```csharp
public class Weapon : NetworkBehaviour
{
@@ -51,6 +56,7 @@ public class Weapon : NetworkBehaviour
}
}
```
+
> [!NOTE]
> The implicit conversion to NetworkObject / GameObject will result in `Null` if the reference can't be found.
@@ -85,6 +91,6 @@ public class Weapon : NetworkBehaviour
## How NetworkObjectReference & NetworkBehaviourReference work
-`NetworkObjectReference` and `NetworkBehaviourReference` are convenience wrappers which serialize the id of a NetworkObject when being sent and on the receiving end retrieve the corresponding ` ` with that id. `NetworkBehaviourReference` sends an additional index which is used to find the right NetworkBehaviour on the NetworkObject.
+`NetworkObjectReference` and `NetworkBehaviourReference` are convenience wrappers which serialize the id of a `NetworkObject` when being sent and on the receiving end retrieve the corresponding `NetworkObject` with that id. `NetworkBehaviourReference` sends an additional index which is used to find the right `NetworkBehaviour` on the `NetworkObject`.
-Both of them are structs implementing the `INetworkSerializable` interface.
+Both of them are structs implementing the [`INetworkSerializable`](./inetworkserializable.md) interface.
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/serialization-arrays.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/serialization-arrays.md
index c347f4c13e..3ecc26cb99 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/serialization-arrays.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/serialization-arrays.md
@@ -1,6 +1,9 @@
# Arrays and native containers
-Netcode for GameObjects has built-in serialization code for arrays of [C# value-type primitives](cprimitives.md), like `int[]`, and [Unity primitive types](unity-primitives.md). Any arrays of types that aren't handled by the built-in serialization code, such as `string[]`, need to be handled using a container class or structure that implements the [`INetworkSerializable`](inetworkserializable.md) interface.
+> [!NOTE]
+> Read the [Serialization overview](./serialization-overview.md) page to understand the basics of serialization before learning how to serialize arrays and native containers.
+
+Netcode for GameObjects has built-in serialization code for arrays of [C# value-type primitives](cprimitives.md), like `int[]`, and [Unity primitive types](unity-primitives.md). Any arrays of types that aren't handled by the built-in serialization code, such as custom types, need to be handled using a container class or structure that implements the [`INetworkSerializable`](inetworkserializable.md) interface.
## Performance considerations
@@ -17,37 +20,6 @@ Using built-in primitive types is fairly straightforward:
void HelloServerRpc(int[] scores, Color[] colors) { /* ... */ }
```
-## INetworkSerializable implementation example
-
-There are many ways to handle sending an array of managed types. The following example is a simple `string` container class that implements `INetworkSerializable` and can be used as an array of "StringContainers":
-
-```csharp
-[Rpc(SendTo.ClientsAndHost)]
-void SendMessagesClientRpc(StringContainer[] messages)
-{
- foreach (var stringContainer in stringContainers)
- {
- Debug.Log($"{stringContainer.SomeText}");
- }
-}
-
-public class StringContainer : INetworkSerializable
-{
- public string SomeText;
- public void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter
- {
- if (serializer.IsWriter)
- {
- serializer.GetFastBufferWriter().WriteValueSafe(SomeText);
- }
- else
- {
- serializer.GetFastBufferReader().ReadValueSafe(out SomeText);
- }
- }
-}
-```
-
## Native containers
Netcode for GameObjects supports `NativeArray` and `NativeList` native containers with built-in serialization, RPCs, and NetworkVariables. However, you can't nest either of these containers without causing a crash.
@@ -77,3 +49,7 @@ To serialize a `NativeList` container, you must:
> [!NOTE]
> When using `NativeLists` within `INetworkSerializable`, the list `ref` value must be a valid, initialized `NativeList`.
> NetworkVariables are similar that the value must be initialized before it can receive updates. For example, `public NetworkVariable> ByteListVar = new NetworkVariable>{Value = new NativeList(Allocator.Persistent)};`. RPCs do this automatically.
+
+## Generic collections
+
+For performance reasons, Netcode for GameObjects does not have built-in serialization code for C# generic collections. However, `NetworkVariable` does support [synchronizing generic collection types](../../basics/networkvariable.md#using-collections-with-networkvariables).
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/serialization-overview.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/serialization-overview.md
new file mode 100644
index 0000000000..ad7fcd4d21
--- /dev/null
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/serialization/serialization-overview.md
@@ -0,0 +1,36 @@
+# Serialization overview
+
+Netcode for GameObjects uses a default serialization pipeline when using [`RPC`](../../rpc-landing.md)'s, [`NetworkVariable`](../../networkvariables-landing.md)s, or any other Netcode-related tasks that require serialization. The serialization pipeline looks like this:
+
+``
+Custom types => Built-in types => INetworkSerializable
+``
+
+When Netcode for GameObjects first receives a type, it checks for any custom types that you have registered for serialization, then it checks if it's a built-in type, such as a Vector3 or a float. These are handled by default. Otherwise, it checks if the type inherits [`INetworkSerializable`](inetworkserializable.md), and if it does, it calls its write methods.
+
+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, for example), as well as any structs that contain only these basic types.
+
+Serialization and deserialization is done via the structs [`FastBufferWriter` and `FastBufferReader`](../fastbufferwriter-fastbufferreader.md). 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.
+
+`FastBufferWriter` and `FastBufferReader` also contain the functions `FastBufferWriter.WriteNetworkSerializable()` and `FastBufferReader.ReadNetworkSerializable` for writing and reading values that use the `INetworkSerializable` interface.
+
+## Built-in serialization
+
+* [C# primitives](./cprimitives.md)
+* [Unity primitives](./unity-primitives.md)
+* [Enum types](./enum-types.md)
+* [Arrays](./serialization-arrays.md)
+* [Collections](../../basics/networkvariable.md#using-collections-with-networkvariables)
+
+## Custom serialization
+
+* [INetworkSerializable](./inetworkserializable.md)
+* [INetworkSerializeByMemcpy](./inetworkserializebymemcpy.md)
+* [Customizing serialization](../custom-serialization.md)
+* [Custom NetworkVariable implementations](../../basics/custom-networkvariables.md)
+
+## Additional resources
+
+* [NetworkObject serialization](./networkobject-serialization.md)
+* [FastBufferWriter and FastBufferReader](../fastbufferwriter-fastbufferreader.md)
+* [BufferSerializer](../bufferserializer.md)
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/session-management.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/session-management.md
index 1f80a08d1a..614d2ce32b 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/session-management.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/session-management.md
@@ -19,7 +19,7 @@ You can also decide to clear all data when a session completes or add a timeout
# Reconnection
-The best way to reconnect players depends on your game. For example, if you use a [Player Object](../components/core/networkobject.md#player-objects), a new `Default Player Prefab` automatically spawns when a player connects to the game (including when they reconnect). You can use the player's earlier saved session data to update that object so that it returns to the same state before disconnecting. In those cases, you would need to keep all the important data that you want to restore and map it to the player using your identification system. You can save this data when a player disconnects or update it periodically. You can then use the `OnNetworkSpawn` event on the Player Object's `NetworkBehavior`(s) to get this data and apply it where needed.
+The best way to reconnect players depends on your game. For example, if you use a [Player Object](../components/core/playerobjects.md), a new `Default Player Prefab` automatically spawns when a player connects to the game (including when they reconnect). You can use the player's earlier saved session data to update that object so that it returns to the same state before disconnecting. In those cases, you would need to keep all the important data that you want to restore and map it to the player using your identification system. You can save this data when a player disconnects or update it periodically. You can then use the `OnNetworkSpawn` event on the Player Object's `NetworkBehavior`(s) to get this data and apply it where needed.
In cases where we don't use the Player Object approach and instead manually attribute client ownership to NetworkObject(s), we can keep the objects that a player owns when they disconnect, and set the reconnected player as their new owner. To accomplish this, the only data we would need to keep would be the mapping between those objects and their owning player's identifier, then when a player reconnects we can use this mapping to set them as the new owner. This mapping can be as simple as a dictionary mapping the player identifier with the `NetworkObjectId`(s) of the NetworkObject(s) they own. Then, in the `OnClientConnectedCallback` from the NetworkManager, the server can set the ownership of these objects.
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/singleplayer.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/singleplayer.md
new file mode 100644
index 0000000000..b0d54e88be
--- /dev/null
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/singleplayer.md
@@ -0,0 +1,18 @@
+# Single player sessions
+
+Netcode for GameObjects provides a [SinglePlayerTransport](xref:Unity.Netcode.Transports.SinglePlayer.SinglePlayerTransport) which derives from [NetworkTransport](xref:Unity.Netcode.NetworkTransport).
+
+This provides the ability to run a hosted session using the single player transport without having to modify your primary netcode script.
+
+## Adding the single player transport
+
+- Add the `SinglePlayerTransport` to your NetworkManager.
+- You can create a custom `MonoBehaviour` component to handle your connection flow or you can derive from `NetworkManager` and add additional methods/logic to handle starting a single player session or multiplayer session.
+ - When starting a single player session, prior to starting the NetworkManager as a host (_required_), you will want to assign the `SinglePlayerTransport` to the `NetworkManager.NetworkConfig.NetworkTransport`.
+ - When starting a multiplayer session, prior to starting the NetworkManager, you will want to assign the `UnityTransport` (_or any other `NetworkTransport` derived class that you might use for multiplayer sessions_) to the `NetworkManager.NetworkConfig.NetworkTransport`.
+
+## Example script
+
+Below is an example component script that provides a single method to start a single or multi player session:
+
+[!code-cs[](../../Tests/Runtime/DocumentationCodeSamples/Configuration/SinglePlayerSessions.cs#SinglePlayerTransportExample)]
diff --git a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/transports.md b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/transports.md
index 1939d8a0ea..783f0f633c 100644
--- a/com.unity.netcode.gameobjects/Documentation~/advanced-topics/transports.md
+++ b/com.unity.netcode.gameobjects/Documentation~/advanced-topics/transports.md
@@ -16,7 +16,7 @@ A transport layer can provide:
## Unity Transport package
-Netcode's default transport Unity Transport is an entire transport layer that you can use to add multiplayer and network features to your project with or without Netcode. See the Transport [documentation](../../../transport/current/about) for more information and how to [install](../../../transport/current/install).
+Netcode's default transport Unity Transport is an entire transport layer that you can use to add multiplayer and network features to your project with or without Netcode. Refer to the Transport [documentation](https://docs.unity3d.com/Packages/com.unity.transport@latest) for more information and how to [install](https://docs.unity3d.com/Packages/com.unity.transport@latest?subfolder=/manual/install.html).
## Unity's UNet Transport Layer API
diff --git a/com.unity.netcode.gameobjects/Documentation~/basics/custom-networkvariables.md b/com.unity.netcode.gameobjects/Documentation~/basics/custom-networkvariables.md
index c2c1f97286..7c6dd428a7 100644
--- a/com.unity.netcode.gameobjects/Documentation~/basics/custom-networkvariables.md
+++ b/com.unity.netcode.gameobjects/Documentation~/basics/custom-networkvariables.md
@@ -2,6 +2,9 @@
In addition to the standard [`NetworkVariable`s](networkvariable.md) available in Netcode for GameObjects, you can also create custom `NetworkVariable`s for advanced implementations. The `NetworkVariable` and `NetworkList` classes were created as `NetworkVariableBase` class implementation examples. While the `NetworkVariable` class is considered production ready, you might run into scenarios where you have a more advanced implementation in mind. In this case, you can create your own custom implementation.
+> [!NOTE]
+> Read the [Serialization overview](../advanced-topics/serialization/serialization-overview.md) page to understand how Netcode for GameObjects handles serialization.
+
To create your own `NetworkVariableBase`-derived container, you should:
1. Create a class deriving from `NetworkVariableBase`.
@@ -16,11 +19,14 @@ To create your own `NetworkVariableBase`-derived container, you should:
The way you read and write `NetworkVariable`s changes depending on the type you use.
-* Known, non-generic types: Use `FastBufferReader.ReadValue` to read from and `FastBufferWriter.WriteValue` to write to the `NetworkVariable` value.
-* Integer types: This type gives you the option to use `BytePacker` and `ByteUnpacker` to compress the `NetworkVariable` value. This process can save bandwidth but adds CPU processing time.
+* Known, non-generic types can use [`FastBufferWriter` and `FastBufferReader`](../advanced-topics/fastbufferwriter-fastbufferreader.md) to serialize the `NetworkVariable` value.
+* Integer types: This type gives you the option to use [`BytePacker` and `ByteUnpacker`](../advanced-topics/fastbufferwriter-fastbufferreader.md#packing) to compress the `NetworkVariable` value. This process can save bandwidth but adds CPU processing time.
* Generic types: Use serializers that Unity generates based on types discovered during a compile-time code generation process. This means you need to tell Unity's code generation algorithm which types to generate serializers for. To tell Unity which types to serialize, use the following methods:
* Use `GenerateSerializationForTypeAttribute` to serialize hard-coded types.
* Use `GenerateSerializationForGenericParameterAttribute` to serialize generic types.
+* Types implementing [`INetworkSerializable`](../advanced-topics/serialization/inetworkserializable.md) can also be serialized using `FastBufferWriter` and `FastBufferReader`.
+
+Read more about [custom serialization](../advanced-topics/custom-serialization.md) for more approaches to customizing serialization.
### Serialize a hard-coded type
@@ -66,175 +72,22 @@ For dynamically-allocated types with a value that isn't `null` (for example, man
You can use `AreEqual` to determine if a value is different from the value that `Duplicate` cached. This avoids sending the same value multiple times. You can also use the previous value that `Duplicate` cached to calculate deltas to use in `ReadDelta` and `WriteDelta`.
-The type you use must be serializable according to the [support types list above](#supported-types). Each type needs its own serializer instantiated, so this step tells the codegen which types to create serializers for. Unity's code generator assumes that all `NetworkVariable` types exist as fields inside NetworkBehaviour types. This means that Unity only inspects fields inside NetworkBehaviour types to identify the types to create serializers for.
+The type you use must be serializable according to the [supported types list](./networkvariable.md#supported-types). Each type needs its own serializer instantiated, so this step tells the codegen which types to create serializers for. Unity's code generator assumes that all `NetworkVariable` types exist as fields inside NetworkBehaviour types. This means that Unity only inspects fields inside NetworkBehaviour types to identify the types to create serializers for.
-## Custom NetworkVariable example
+> [!NOTE]
+> These attributes won't generate delta serialization. If you would like to customize how deltas are sent when a custom value has partially changed, refer to [`UserNetworkVariableSerialization`](../advanced-topics/custom-serialization.md#networkvariable).
+
+## Custom NetworkVariableBase example
This example shows a custom `NetworkVariable` type to help you understand how you might implement such a type. In the current version of Netcode for GameObjects, this example is possible without using a custom `NetworkVariable` type; however, for more complex situations that aren't natively supported, this basic example should help inform you of how to approach the implementation:
- ```csharp
- /// Using MyCustomNetworkVariable within a NetworkBehaviour
- public class TestMyCustomNetworkVariable : NetworkBehaviour
- {
- public MyCustomNetworkVariable CustomNetworkVariable = new MyCustomNetworkVariable();
- public MyCustomGenericNetworkVariable CustomGenericNetworkVariable = new MyCustomGenericNetworkVariable();
- public override void OnNetworkSpawn()
- {
- if (IsServer)
- {
- for (int i = 0; i < 4; i++)
- {
- var someData = new SomeData();
- someData.SomeFloatData = (float)i;
- someData.SomeIntData = i;
- someData.SomeListOfValues.Add((ulong)i + 1000000);
- someData.SomeListOfValues.Add((ulong)i + 2000000);
- someData.SomeListOfValues.Add((ulong)i + 3000000);
- CustomNetworkVariable.SomeDataToSynchronize.Add(someData);
- CustomNetworkVariable.SetDirty(true);
-
- CustomGenericNetworkVariable.SomeDataToSynchronize.Add(i);
- CustomGenericNetworkVariable.SetDirty(true);
- }
- }
- }
- }
-
- /// Bare minimum example of NetworkVariableBase derived class
- [Serializable]
- public class MyCustomNetworkVariable : NetworkVariableBase
- {
- /// Managed list of class instances
- public List SomeDataToSynchronize = new List();
-
- ///
- /// Writes the complete state of the variable to the writer
- ///
- /// The stream to write the state to
- public override void WriteField(FastBufferWriter writer)
- {
- // Serialize the data we need to synchronize
- writer.WriteValueSafe(SomeDataToSynchronize.Count);
- foreach (var dataEntry in SomeDataToSynchronize)
- {
- writer.WriteValueSafe(dataEntry.SomeIntData);
- writer.WriteValueSafe(dataEntry.SomeFloatData);
- writer.WriteValueSafe(dataEntry.SomeListOfValues.Count);
- foreach (var valueItem in dataEntry.SomeListOfValues)
- {
- writer.WriteValueSafe(valueItem);
- }
- }
- }
-
- ///
- /// Reads the complete state from the reader and applies it
- ///
- /// The stream to read the state from
- public override void ReadField(FastBufferReader reader)
- {
- // De-Serialize the data being synchronized
- var itemsToUpdate = (int)0;
- reader.ReadValueSafe(out itemsToUpdate);
- SomeDataToSynchronize.Clear();
- for (int i = 0; i < itemsToUpdate; i++)
- {
- var newEntry = new SomeData();
- reader.ReadValueSafe(out newEntry.SomeIntData);
- reader.ReadValueSafe(out newEntry.SomeFloatData);
- var itemsCount = (int)0;
- var tempValue = (ulong)0;
- reader.ReadValueSafe(out itemsCount);
- newEntry.SomeListOfValues.Clear();
- for (int j = 0; j < itemsCount; j++)
- {
- reader.ReadValueSafe(out tempValue);
- newEntry.SomeListOfValues.Add(tempValue);
- }
- SomeDataToSynchronize.Add(newEntry);
- }
- }
-
- public override void ReadDelta(FastBufferReader reader, bool keepDirtyDelta)
- {
- // Do nothing for this example
- }
-
- public override void WriteDelta(FastBufferWriter writer)
- {
- // Do nothing for this example
- }
- }
-
- /// Bare minimum example of generic NetworkVariableBase derived class
- [Serializable]
- [GenerateSerializationForGenericParameter(0)]
- public class MyCustomGenericNetworkVariable : NetworkVariableBase
- {
- /// Managed list of class instances
- public List SomeDataToSynchronize = new List();
-
- ///
- /// Writes the complete state of the variable to the writer
- ///
- /// The stream to write the state to
- public override void WriteField(FastBufferWriter writer)
- {
- // Serialize the data we need to synchronize
- writer.WriteValueSafe(SomeDataToSynchronize.Count);
- for (var i = 0; i < SomeDataToSynchronize.Count; ++i)
- {
- var dataEntry = SomeDataToSynchronize[i];
- // NetworkVariableSerialization is used for serializing generic types
- NetworkVariableSerialization.Write(writer, ref dataEntry);
- }
- }
-
- ///
- /// Reads the complete state from the reader and applies it
- ///
- /// The stream to read the state from
- public override void ReadField(FastBufferReader reader)
- {
- // De-Serialize the data being synchronized
- var itemsToUpdate = (int)0;
- reader.ReadValueSafe(out itemsToUpdate);
- SomeDataToSynchronize.Clear();
- for (int i = 0; i < itemsToUpdate; i++)
- {
- T newEntry = default;
- // NetworkVariableSerialization is used for serializing generic types
- NetworkVariableSerialization.Read(reader, ref newEntry);
- SomeDataToSynchronize.Add(newEntry);
- }
- }
-
- public override void ReadDelta(FastBufferReader reader, bool keepDirtyDelta)
- {
- // Do nothing for this example
- }
-
- public override void WriteDelta(FastBufferWriter writer)
- {
- // Do nothing for this example
- }
- }
-
- /// Example managed class used as the item type in the
- /// MyCustomNetworkVariable.SomeDataToSynchronize list
- [Serializable]
- public class SomeData
- {
- public int SomeIntData = default;
- public float SomeFloatData = default;
- public List SomeListOfValues = new List();
- }
- ```
+[!code-cs[](../../Tests/Runtime/DocumentationCodeSamples/NetworkVariable/CustomNetworkVariable.cs#TestMyCustomNetworkVariable)]
While the above example isn't the recommended way to synchronize a list where the number or order of elements in the list often changes, it's an example of how you can define your own rules using `NetworkVariableBase`.
You can test the code above by:
-- Using the above code with a project that includes Netcode for GameObjects v1.0 (or higher).
+
+- Using the above code with a project that includes Netcode for GameObjects.
- Adding the `TestMyCustomNetworkVariable` component to an in-scene placed NetworkObject.
- Creating a stand alone build and running that as a host or server.
- Running the same scene within the Editor and connecting as a client.
diff --git a/com.unity.netcode.gameobjects/Documentation~/basics/networkvariable.md b/com.unity.netcode.gameobjects/Documentation~/basics/networkvariable.md
index 0ea6c445e8..cfdd037143 100644
--- a/com.unity.netcode.gameobjects/Documentation~/basics/networkvariable.md
+++ b/com.unity.netcode.gameobjects/Documentation~/basics/networkvariable.md
@@ -148,43 +148,277 @@ The [synchronization and notification example](#synchronization-and-notification
The `OnValueChanged` example shows a simple server-authoritative `NetworkVariable` being used to track the state of a door (open or closed) using an RPC that's sent to the server. Each time the door is used by a client, the `Door.ToggleStateRpc` is invoked and the server-side toggles the state of the door. When the `Door.State.Value` changes, all connected clients are synchronized to the (new) current `Value` and the `OnStateChanged` method is invoked locally on each client.
```csharp
-public class Door : NetworkBehaviour
+using System.Runtime.CompilerServices;
+using Unity.Netcode;
+using UnityEngine;
+
+///
+/// Example of using a to drive changes
+/// in state.
+///
+///
+/// This is a simple state driven door example.
+/// This script was written with recommended usages patterns in mind.
+///
+public class Door : NetworkBehaviour, INetworkUpdateSystem
{
- public NetworkVariable State = new NetworkVariable();
+ ///
+ /// The two door states.
+ ///
+ public enum DoorStates
+ {
+ Closed,
+ Open
+ }
+ ///
+ /// Initializes the door to a specific state (server side) when first spawned.
+ ///
+ [Tooltip("Configures the door's initial state when 1st spawned.")]
+ public DoorStates InitialState = DoorStates.Closed;
+
+ ///
+ /// Used for example purposes.
+ /// When true, only the server can open and close the door.
+ /// Clients will receive a console log saying they could not open the door.
+ ///
+ public bool IsLocked;
+
+ ///
+ /// A simple door state where the server has write permissions and everyone has read permissions.
+ ///
+ private NetworkVariable m_State = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server);
+
+ ///
+ /// The current state of the door.
+ ///
+ public DoorStates CurrentState => m_State.Value;
+
+ ///
+ /// Invoked while the is in the process of
+ /// being spawned.
+ ///
public override void OnNetworkSpawn()
{
- State.OnValueChanged += OnStateChanged;
+ // The write authority (server) doesn't need to know about its
+ // own changes (for this example) since it's the "single point
+ // of truth" for the door instance.
+ if (IsServer)
+ {
+ // Host/Server:
+ // Applies the configurable state upon spawning.
+ m_State.Value = InitialState;
+ }
+ else
+ {
+ // Clients:
+ // Subscribe to changes in the door's state.
+ m_State.OnValueChanged += OnStateChanged;
+ }
}
- public override void OnNetworkDespawn()
+ ///
+ /// Invoked once the door and all associated components
+ /// have finished the spawn process.
+ ///
+ protected override void OnNetworkPostSpawn()
{
- State.OnValueChanged -= OnStateChanged;
+ // Everyone updates their door state when finished spawning the door
+ // to ensure the door reflects (visually) its current state.
+ UpdateFromState();
+
+ // Begin updating this NetworkBehaviour instance once all
+ // netcode related components have finished the spawn process.
+ NetworkUpdateLoop.RegisterNetworkUpdate(this, NetworkUpdateStage.Update);
+ base.OnNetworkPostSpawn();
}
- public void OnStateChanged(bool previous, bool current)
+ ///
+ /// Example of using the usage pattern
+ /// where it only updates while spawned.
+ ///
+ /// The current update stage being invoked.
+ public void NetworkUpdate(NetworkUpdateStage updateStage)
{
- // note: `State.Value` will be equal to `current` here
- if (State.Value)
+ switch (updateStage)
{
- // door is open:
- // - rotate door transform
- // - play animations, sound etc.
+ case NetworkUpdateStage.Update:
+ {
+ if (Input.GetKeyDown(KeyCode.Space))
+ {
+ Interact();
+ }
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Invoked just before this instance runs through its despawn
+ /// sequence. A good time to unsubscribe from things.
+ ///
+ public override void OnNetworkPreDespawn()
+ {
+ if (!IsServer)
+ {
+ m_State.OnValueChanged -= OnStateChanged;
+ }
+
+ // Stop updating this NetworkBehaviour instance prior to running
+ // through the despawn process.
+ NetworkUpdateLoop.RegisterNetworkUpdate(this, NetworkUpdateStage.Update);
+ base.OnNetworkPreDespawn();
+ }
+
+ ///
+ /// Server makes changes to the state.
+ /// Clients receive the changes in state.
+ ///
+ ///
+ /// When the previous state equals the current state, we are a client
+ /// that is doing its first synchronization of this door instance.
+ ///
+ /// The previous state.
+ /// The current state.
+ public void OnStateChanged(DoorStates previous, DoorStates current)
+ {
+ UpdateFromState();
+ }
+
+ ///
+ /// Invoke when the state is updated to apply the change
+ /// in door state to the door asset itself.
+ ///
+ private void UpdateFromState()
+ {
+ switch(m_State.Value)
+ {
+ case DoorStates.Closed:
+ {
+ // door is open:
+ // - rotate door transform
+ // - play animations, sound etc.
+ ///
+ /// Override to apply specific checks (like a player having the right
+ /// key to open the door) or make it a non-virtual class and add logic
+ /// directly to this method.
+ ///
+ /// The player attempting to open the door.
+ ///
+ protected virtual bool CanPlayerToggleState(NetworkObject player)
+ {
+ // For this example, if the door "is locked" then clients will
+ // not be able to open the door but the host-client's player can.
+ return !IsLocked || player.IsOwnedByServer;
+ }
+
+ ///
+ /// Invoked by either a host or clients to interact with the door.
+ ///
+ public void Interact()
+ {
+ // Optional:
+ // This is only if you want clients to be able to
+ // interact with doors. A dedicated server would not
+ // be able to do this since it does not have a player.
+ if (IsServer && !IsHost)
+ {
+ // Optional to log a warning about this.
+ return;
+ }
+
+ if (IsHost)
+ {
+ ToggleState(NetworkManager.LocalClientId);
+ }
+ else
+ {
+ // Clients send an RPC to server (write authority) who applies the
+ // change in state that will be synchronized with all client observers.
+ ToggleStateRpc();
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private DoorStates NextToggleState()
+ {
+ return m_State.Value == DoorStates.Open ? DoorStates.Closed : DoorStates.Open;
+ }
+
+ ///
+ /// Invoked only server-side
+ /// Primary method to handle toggling the door state.
+ ///
+ /// The client toggling the door state.
+ private void ToggleState(ulong clientId)
+ {
+ // Get the server-side client player instance
+ var playerObject = NetworkManager.SpawnManager.GetPlayerNetworkObject(clientId);
+ if (playerObject != null)
+ {
+ var nextToggleState = NextToggleState();
+ if (CanPlayerToggleState(playerObject))
+ {
+ // Host toggles the state
+ m_State.Value = nextToggleState;
+ UpdateFromState();
+ }
+ else
+ {
+ ToggleStateFailRpc(nextToggleState, RpcTarget.Single(clientId, RpcTargetUse.Temp));
+ }
}
else
{
- // door is closed:
- // - rotate door transform
- // - play animations, sound etc.
+ // Optional as to how you handle this. Since ToggleState is only invoked by
+ // sever-side only script, this could mean many things depending upon whether
+ // or not a client could interact with something and not have a player object.
+ // If that is the case, then don't even bother checking for a player object.
+ // If that is not the case, then there could be a timing issue between when
+ // something can be "interacted with" and when a player is about to be de-spawned.
+ // For this example, we just log a warning as this example was built with
+ // the requirement that a client has a spawned player object that is used for
+ // reference to determine if the client's player can toggle the state of the
+ // door or not.
+ NetworkLog.LogWarningServer($"Client-{clientId} has no spawned player object!");
}
}
- [Rpc(SendTo.Server)]
- public void ToggleStateRpc()
+ ///
+ /// Invoked by clients.
+ /// Re-directs to the common method.
+ ///
+ /// includes that is automatically populated for you.
+ [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
+ private void ToggleStateRpc(RpcParams rpcParams = default)
+ {
+ ToggleState(rpcParams.Receive.SenderClientId);
+ }
+
+ ///
+ /// Optional:
+ /// Handling when a player cannot open a door.
+ ///
+ /// includes that is automatically populated for you.
+ [Rpc(SendTo.SpecifiedInParams, InvokePermission = RpcInvokePermission.Server)]
+ private void ToggleStateFailRpc(DoorStates doorState, RpcParams rpcParams = default)
{
- // this will cause a replication over the network
- // and ultimately invoke `OnValueChanged` on receivers
- State.Value = !State.Value;
+ // Provide player feedback that toggling failed.
+ Debug.Log($"Failed to {doorState} the door!");
}
}
```
@@ -318,7 +552,7 @@ public class PlayerState : NetworkBehaviour
## Complex types
-Almost all of the examples on this page have been focused around numeric [value types](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types). Netcode for GameObjects also supports complex types and can support both unmanaged types *and* managed types (although avoiding managed types where possible will improve your game's performance).
+Any type that implements the [`INetworkSerializable`](../advanced-topics/serialization/inetworkserializable.md) interface can be used inside a `NetworkVariable`. To synchronize a custom type that is not supported by the default serialization provided by Netcode for GameObjects, implement this interface to allow it to be used inside a `NetworkVariable`.
### Synchronizing complex types example
@@ -348,7 +582,7 @@ public class PlayerState : NetworkBehaviour
void Awake()
{
//NetworkList can't be initialized at declaration time like NetworkVariable. It must be initialized in Awake instead.
- //If you do initialize at declaration, you will run into Memmory leak errors.
+ //If you do initialize at declaration, you will run into Memory leak errors.
TeamAreaWeaponBoosters = new NetworkList();
}
@@ -473,88 +707,12 @@ public struct AreaWeaponBooster : INetworkSerializable, System.IEquatable [!NOTE]
-> The `NetworkVariable` and `NetworkList` classes were created as `NetworkVariableBase` class implementation examples. While the `NetworkVariable` class is considered production ready, you might run into scenarios where you have a more advanced implementation in mind. In this case, we encourage you to create your own custom implementation.
-
-To create your own `NetworkVariableBase` derived container, you should:
-
-- Create a class deriving from `NetworkVariableBase`.
-
-- Assure the the following methods are overridden:
- - `void WriteField(FastBufferWriter writer)`
- - `void ReadField(FastBufferReader reader)`
- - `void WriteDelta(FastBufferWriter writer)`
- - `void ReadDelta(FastBufferReader reader, bool keepDirtyDelta)`
-- Depdending upon your custom `NetworkVariableBase` container, you might look at `NetworkVariable` or `NetworkList` to see how those two examples were implemented.
-
-
-
-#### NetworkVariableSerialization<T>
-
-The way you read and write network variables changes depending on the type you use.
-
-* Known, non-generic types: Use `FastBufferReader.ReadValue` to read from and `FastBufferWriter.WriteValue` to write to the network variable value.
-* Integer types: This type gives you the option to use `BytePacker` and `ByteUnpacker` to compress the network variable value. This process can save bandwidth but adds CPU processing time.
-* Generic types: Use serializers that Unity generates based on types discovered during a compile-time code generation process. This means you need to tell Unity's code generation algorithm which types to generate serializers for. To tell Unity which types to serialize, use the following methods:
- * Use `GenerateSerializationForTypeAttribute` to serialize hard-coded types.
- * Use `GenerateSerializationForGenericParameterAttribute` to serialize generic types.
- To learn how to use these methods, refer to [Network variable serialization](#network-variable-serialization).
-
-##### Tell Unity to serialize a hard-coded type
-The following code example uses `GenerateSerializationForTypeAttribute` to generate serialization for a specific hard-coded type:
-```csharp
-[GenerateSerializationForType(typeof(Foo))]
-public class MyNetworkVariableTypeUsingFoo : NetworkVariableBase {}
-```
-
-You can call a type that you know the name of with the `FastBufferReader` or `FastBufferWriter` methods. These methods don't work for Generic types because the name of the type is unknown.
-##### Tell Unity to serialize a generic type
-The following code example uses `GenerateSerializationForGenericParameterAttribute` to generate serialization for a specific Generic parameter in your `NetworkVariable` type:
-```csharp
-[GenerateSerializationForGenericParameter(0)]
-public class MyNetworkVariableType : NetworkVariableBase {}
-```
-
-This attribute accepts an integer that indicates which parameter in the type to generate serialization for. This value is 0-indexed, which means that the first type is 0, the second type is 1, and so on.
-The following code example places the attribute more than once on one class to generate serialization for multiple types, in this case,`TFirstType` and `TSecondType:
-
-```csharp
-[GenerateSerializationForGenericParameter(0)]
-[GenerateSerializationForGenericParameter(1)]
-public class MyNetworkVariableType : NetworkVariableBase {}
-```
-
-
-The `GenerateSerializationForGenericParameterAttribute` and `GenerateSerializationForTypeAttribute` attributes make Unity's code generation create the following methods:
-
-```csharp
-NetworkVariableSerialization.Write(FastBufferWriter writer, ref T value);
-NetworkVariableSerialization.Read(FastBufferWriter writer, ref T value);
-NetworkVariableSerialization.Duplicate(in T value, ref T duplicatedValue);
-NetworkVariableSerialization.AreEqual(in T a, in T b);
-```
-
-For dynamically allocated types with a value that isn't `null` (for example, managed types and collections like NativeArray and NativeList) call `Read` to read the value in the existing object and write data into it directy (in-place). This avoids more allocations.
-
-You can use `AreEqual` to determine if a value is different from the value that `Duplicate` cached. This avoids sending the same value multiple times. You can also use the previous value that `Duplicate` cached to calculate deltas to use in `ReadDelta` and `WriteDelta`.
-
-The type you use must be serializable according to the "Supported Types" list above. Each type needs its own serializer instantiated, so this step tells the codegen which types to create serializers for.
-
-> [!NOTE] Unity's code generator assumes that all `NetworkVariable` types exist as fields inside NetworkBehaviour types. This means that Unity only inspects fields inside NetworkBehaviour types to identify the types to create serializers for.
-
- ### Custom NetworkVariable Example
-
-This example shows a custom `NetworkVariable` type to help you understand how you might implement such a type. In the current version of Netcode for GameObjects, this example is possible without using a custom `NetworkVariable` type; however, for more complex situations that aren't natively supported, this basic example should help inform you of how to approach the implementation:
-
-Looking at the read and write segments of code within `AreaWeaponBooster.NetworkSerialize`, the nested complex type property `ApplyWeaponBooster` handles its own serialization and de-serialization. The `ApplyWeaponBooster`'s implemented `NetworkSerialize` method serializes and deserializes any `AreaWeaponBooster` type property. This design approach can help reduce code replication while providing a more modular foundation to build even more complex, nested types.
-
+Further information on customizing the serialization of complex types can be found in [custom serialization](../advanced-topics/custom-serialization.md#networkvariable).
## Strings
-While `NetworkVariable` does support managed `INetworkSerializable` types, strings aren't in the list of supported types. This is because strings in C# are immutable types, preventing them from being deserialized in-place, so every update to a `NetworkVariable` would cause a Garbage Collected allocation to create the new string, which may lead to performance problems.
+While `NetworkVariable` does support managed `INetworkSerializable` types, strings aren't in the [list of supported types](#supported-types). This is because strings in C# are immutable types, preventing them from being deserialized in-place, so every update to a `NetworkVariable` would cause a Garbage Collected allocation to create the new string, which may lead to performance problems.
-While it's technically possible to support strings using custom serialization through `UserNetworkVariableSerialization`, it isn't recommended to do so due to the performance implications that come with it. Instead, we recommend using one of the `Unity.Collections.FixedString` value types. In the below example, we used a `FixedString128Bytes` as the `NetworkVariable` value type. On the server side, it changes the string value each time you press the space bar on the server or host instance. Joining clients will be synchronized with the current value applied on the server side, and each time you hit the space bar on the server side, the client synchronizes with the changed string.
+While it's technically possible to support strings using custom serialization through [`UserNetworkVariableSerialization`](../advanced-topics/custom-serialization.md#networkvariable), it isn't recommended to do so due to the performance implications that come with it. Instead, it's recommended to use one of the `Unity.Collections.FixedString` value types. In the below example, a `FixedString128Bytes` is the `NetworkVariable` value type. On the server side, it changes the string value each time you press the space bar on the server or host instance. Joining clients will be synchronized with the current value applied on the server side, and each time you hit the space bar on the server side, the client synchronizes with the changed string.
> [!NOTE]
> `NetworkVariable` won't serialize the entire 128 bytes each time the `Value` is changed. Only the number of bytes that are actually used to store the string value will be sent, no matter which size of `FixedString` you use.
@@ -621,3 +779,9 @@ public class TestFixedString : NetworkBehaviour
> [!NOTE]
> The above example uses a pre-set list of strings to cycle through for example purposes only. If you have a predefined set of text strings as part of your actual design then you would not want to use a FixedString to handle synchronizing the changes to `m_TextString`. Instead, you would want to use a `uint` for the type `T` where the `uint` was the index of the string message to apply to `m_TextString`.
+
+### Delta updates
+
+To save bandwidth, `NetworkVariables` can send delta updates. A delta is a compact description of what changed since the last sync. By default, [collection types](#using-collections-with-networkvariables) all support sending delta updates. This means adding a single item to a large list doesn't need to send the entire list over the network. For complex types, it is often worth considering whether sending deltas will improve bandwidth. Delta serialization can be configured via [`UserNetworkVariableSerialization`](../advanced-topics/custom-serialization.md#serializing-delta-updates).
+
+When a NetworkObject is spawned or a late-joining client first sees it, every `NetworkVariable` will be serialized in full. This allows game clients to start receiving deltas from a known state.
diff --git a/com.unity.netcode.gameobjects/Documentation~/basics/object-spawning.md b/com.unity.netcode.gameobjects/Documentation~/basics/object-spawning.md
index 7fdd95ee4d..b72213f32e 100644
--- a/com.unity.netcode.gameobjects/Documentation~/basics/object-spawning.md
+++ b/com.unity.netcode.gameobjects/Documentation~/basics/object-spawning.md
@@ -30,7 +30,7 @@ When using a [server authoritative networking model](../terms-concepts/authority
To spawn a network prefab, you must first create an instance of the network prefab and then invoke the spawn method on the NetworkObject component of the instance you created. In most cases, you will want to keep the NetworkObject component attached to the root GameObject of the network prefab.
-Refer to [NetworkObject ownership](../advanced-topics/networkobject-ownership.md) for more information.
+Refer to [NetworkObject ownership](../components/core/networkobject-ownership.md) for more information.
The following is a basic example of how to spawn a network prefab instance:
diff --git a/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/custom-management.md b/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/custom-management.md
index dff54d2da4..ffb1cde762 100644
--- a/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/custom-management.md
+++ b/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/custom-management.md
@@ -39,7 +39,7 @@ Once you've registered your in-scene placed Network Prefabs with your `NetworkPr
> When a client first connects, it deletes any in-scene placed `NetworkObjects` in any of the scenes it has currently loaded. When using a custom scene management solution, in-scene placed NetworkObjects are actually dynamically spawned. This means any changes you make to your in-scene placed Network Prefabs will *not* be synchronized with clients automatically.
### Synchronizing In-Scene Placed Network Prefab Instances
-If you want to change an in-scene placed network prefab instance, you need to handle the serialization of these settings yourself. You can do this by overriding `NetworkBehaviour.OnSynchronize` and serializing any property updates you want to have synchronized with clients when they join. [Read More About OnSynchronize Here](../../components/core/networkbehaviour.md#prespawn-synchronization).
+If you want to change an in-scene placed network prefab instance, you need to handle the serialization of these settings yourself. You can do this by overriding `NetworkBehaviour.OnSynchronize` and serializing any property updates you want to have synchronized with clients when they join. [Read More About OnSynchronize Here](../../components/core/networkbehaviour-synchronize.md#prespawn-synchronization-with-onsynchronize).
## Starting a Netcode Enabled Game Session
The recommended way of starting session using your own scene management solution is to assure that when a client attempts to join a netcode game session it should already have (as best as possible) any scenes that the server might have loaded. While this does not assure that your newly connecting client will load any additional scenes that might have been loaded, using this approach initially will get you started so you can then come up with a strategy to handling:
diff --git a/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/inscene-placed-networkobjects.md b/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/inscene-placed-networkobjects.md
index 6bc209722b..617a8f5f36 100644
--- a/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/inscene-placed-networkobjects.md
+++ b/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/inscene-placed-networkobjects.md
@@ -78,6 +78,9 @@ private void Start()
> [!NOTE]
> Once migrated into the DDoL, migrating the in-scene placed NetworkObject back into a different scene after it has already been spawned will cause soft synchronization errors with late-joining clients. Once in the DDoL it should stay in the DDoL. This is only for scene switching. If you aren't using scene switching, then it's recommended to use an additively loaded scene and keep that scene loaded for as long as you wish to persist the in-scene placed NetworkObject(s) being used for state management purposes.
+> [!WARNING]
+> Manually calling `DontDestroyOnLoad(gameObject)` is only supported for the scene-switching manager scenario described above (that is, a single in-scene placed NetworkObject used for state management that's migrated into the DDoL and stays there). Marking ordinary in-scene placed NetworkObjects as `DontDestroyOnLoad` isn't supported and can cause the object's `GlobalObjectIdHash` to no longer resolve after a scene change, resulting in errors such as "NetworkPrefab hash was not found!". To persist in-scene placed NetworkObjects across scene changes, prefer keeping them in an additively loaded scene that stays loaded for the duration of the session rather than using `DontDestroyOnLoad`.
+
## Complex in-scene NetworkObjects
The most common mistake when using an in-scene placed NetworkObject is to try and use it like a dynamically spawned NetworkObject. When trying to decide if you should use an in-scene placed or dynamically spawned NetworkObject, you should ask yourself the following questions:
@@ -181,9 +184,13 @@ public class MyInSceneNetworkObjectBehaviour : NetworkBehaviour
> [!NOTE]
> You only need to enable the NetworkObject on the server-side to be able to respawn it. Netcode for GameObjects only enables a disabled in-scene placed NetworkObject on the client-side if the server-side spawns it. This **does not** apply to dynamically spawned `NetworkObjects`. Refer to [the object pooling page](../../advanced-topics/object-pooling.md) for an example of recycling dynamically spawned NetworkObjects.
+### Pre-disabled in-scene placed NetworkObjects
+
+To initialize an in-scene placed NetworkObject in a disabled state and spawn it later, set its GameObject to inactive in the Editor while the respective scene is open. Once a networked session begins, you can re-enable and spawn it at any time.
+
### Setting an in-scene placed NetworkObject to a despawned state when instantiating
-Since in-scene placed NetworkObjects are automatically spawned when their respective scene has finished loading during a network session, you might run into the scenario where you want it to start in a despawned state until a certain condition has been met. To do this, you need to add some additional code in the `OnNetworkSpawn` part of your NetworkBehaviour component:
+To programmatically disable an in-scene placed NetworkObject, add some additional code in the `OnNetworkSpawn` part of a NetworkBehaviour component:
```csharp
using UnityEngine;
@@ -225,7 +232,7 @@ The above example keeps track of whether the in-scene placed NetworkObject has s
### Synchronizing late-joining clients when an in-scene placed NetworkObject has been despawned and destroyed
-Referring back to the [section on complex in-scene NetworkObjects](#complex-in-scene-networkobjects), it's recommended to use dynamically spawned NetworkObjects if you intend to destroy the object when it's despawned. However, if either despawning but not destroying or using the [hybrid approach](#a-hybrid-approach-example) don't appear to be options for your project's needs, then there are two other possible (but not recommended) alternatives:
+Referring back to the [section on complex in-scene NetworkObjects](#complex-in-scene-networkobjects), it's recommended to use dynamically spawned NetworkObjects if you intend to destroy the object when it's despawned. However, if either despawning but not destroying or using the [hybrid approach](#hybrid-approach) don't appear to be options for your project's needs, then there are two other possible (but not recommended) alternatives:
- Have another in-scene placed NetworkObject track which in-scene placed NetworkObjects have been destroyed and upon a player late-joining (that is, `OnClientConnected`) you would need to send the newly-joined client the list of in-scene placed NetworkObjects that it should destroy. This adds an additional in-scene placed NetworkObject to your scene hierarchy and will consume memory keeping track of what was destroyed.
- Disable the visual and physics-related components (in Editor as a default) of the in-scene placed NetworkObject(s) in question and only enable them in `OnNetworkSpawn`. This doesn't delete/remove the in-scene placed NetworkObject(s) for the late-joining client and can be tricky to implement without running into edge case scenario bugs.
diff --git a/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/scene-events.md b/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/scene-events.md
index 817affd33f..c01ffa1df5 100644
--- a/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/scene-events.md
+++ b/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/scene-events.md
@@ -240,7 +240,7 @@ So, the big "take-away" from the above table is that you need to understand the
### SceneEventType Specific Notifications
There might be a time where you aren't interested in all of the details for each scene event type that occurs. As it just so happens, `NetworkSceneManager` includes a single delegate handler for each `SceneEventType` that is only triggered for the associated `SceneEventType`.
-You can explore the [NetworkSceneManager](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.SceneEventType.html) for a full listing of the corresponding single `SceneEventType` events.
+You can explore the [NetworkSceneManager](xref:Unity.Netcode.SceneEventType) for a full listing of the corresponding single `SceneEventType` events.
Some examples:
- NetworkSceneManager.OnLoad: Triggered when for `OnLoad` scene events.
- NetworkSceneManager.OnUnload: Triggered when for `OnUnload` scene events.
diff --git a/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/using-networkscenemanager.md b/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/using-networkscenemanager.md
index 5837249132..ac54460414 100644
--- a/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/using-networkscenemanager.md
+++ b/com.unity.netcode.gameobjects/Documentation~/basics/scenemanagement/using-networkscenemanager.md
@@ -19,7 +19,7 @@
> [!NOTE]
> In-Scene placed NetworkObjects can be used in many ways and are treated uniquely from that of dynamically spawned NetworkObjects. An in-scene placed NetworkObject is a GameObject with a NetworkObject and typically at least one NetworkBehaviour component attached to a child of or the same GameObject. it's recommended to read through all integrated scene management materials (this document, [Scene Events](scene-events.md), and [Timing Considerations](timing-considerations.md)) before learning about more advanced [In-Scene (placed) NetworkObjects](inscene-placed-networkobjects.md) topics.
-All of these scene management features (and more) are handled by the [`NetworkSceneManager`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkSceneManager.html).
+All of these scene management features (and more) are handled by the [`NetworkSceneManager`](xref:Unity.Netcode.NetworkSceneManager).
### Accessing `NetworkSceneManager`
The `NetworkSceneManager` lives within the NetworkManager and is instantiated when the NetworkManager is started.
@@ -122,7 +122,7 @@ The purpose behind the above outline is to show that a Scene Event can lead to o
#### Scene Event Notifications
You can be notified of scene events by registering in one of two ways:
1. Receive all scene event notification types: `NetworkSceneManager.OnSceneEvent`
-2. Receive only a specific scene event notification type: [`NetworkSceneManager`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkSceneManager.html#events) has one for each [`SceneEventType`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.SceneEventType.html)
+2. Receive only a specific scene event notification type: [`NetworkSceneManager`](xref:Unity.Netcode.NetworkSceneManager) has one for each [`SceneEventType`](xref:Unity.Netcode.SceneEventType)
> [!NOTE]
> Receiving (via subscribing to the associated event callback) only specific scene event notification types does not change how a server or client receives and processes notifications.
@@ -137,7 +137,7 @@ Typically, this is used with clients or components that might only need to be no
You might want to register for the `SceneEventType.LoadEventCompleted` scene event type to know, from a client perspective, that the server and all other clients have finished loading a scene. This notification lets you know when you can start performing other netcode related actions on the newly loaded and spawned NetworkObjects.
#### Scene Event Progress Status
-As we discussed in the earlier code example, it's important to check the status returned by `NetworkSceneManager.Load` to make sure your scene loading event has started. The following is a list of all [SceneEventProgressStatus](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.SceneEventProgressStatus.html) `enum` values with some additional helpful information:
+As we discussed in the earlier code example, it's important to check the status returned by `NetworkSceneManager.Load` to make sure your scene loading event has started. The following is a list of all [SceneEventProgressStatus](xref:Unity.Netcode.SceneEventProgressStatus) `enum` values with some additional helpful information:
- Started
- The scene event has started (success)
- SceneNotLoaded
diff --git a/com.unity.netcode.gameobjects/Documentation~/components/core/corecomponents.md b/com.unity.netcode.gameobjects/Documentation~/components/core/corecomponents.md
index 8c4c49d2d8..b07a4113cf 100644
--- a/com.unity.netcode.gameobjects/Documentation~/components/core/corecomponents.md
+++ b/com.unity.netcode.gameobjects/Documentation~/components/core/corecomponents.md
@@ -20,7 +20,7 @@ Learn about the three core components of Netcode for GameObjects: NetworkObject,
| **Topic** | **Description** |
| :------------------------------ | :------------------------------- |
-| **[NetworkBehaviour](networkbehaviour.md)** | [NetworkBehaviour](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.html) is an abstract class that derives from [MonoBehaviour](https://docs.unity3d.com/ScriptReference/MonoBehaviour.html) and is primarily used to create unique netcode or game logic. To replicate any netcode-aware properties or send and receive RPCs, a [GameObject](https://docs.unity3d.com/Manual/GameObjects.html) must have a [NetworkObject](networkobject.md) component and at least one NetworkBehaviour component. |
+| **[NetworkBehaviour](networkbehaviour.md)** | [NetworkBehaviour](xref:Unity.Netcode.NetworkBehaviour) is an abstract class that derives from [MonoBehaviour](https://docs.unity3d.com/ScriptReference/MonoBehaviour.html) and is primarily used to create unique netcode or game logic. To replicate any netcode-aware properties or send and receive RPCs, a [GameObject](https://docs.unity3d.com/Manual/GameObjects.html) must have a [NetworkObject](networkobject.md) component and at least one NetworkBehaviour component. |
| **[Synchronizing](networkbehaviour-synchronize.md)** | Understand a NetworkBehaviour component's order of operations when it comes to spawning, despawning, and adding custom synchronization data. |
diff --git a/com.unity.netcode.gameobjects/Documentation~/components/core/networkbehaviour-ownership.md b/com.unity.netcode.gameobjects/Documentation~/components/core/networkbehaviour-ownership.md
index 3511fd44f8..fee658cd12 100644
--- a/com.unity.netcode.gameobjects/Documentation~/components/core/networkbehaviour-ownership.md
+++ b/com.unity.netcode.gameobjects/Documentation~/components/core/networkbehaviour-ownership.md
@@ -1,25 +1,25 @@
# NetworkBehaviour ownership
-Before reading these docs, ensure you understand the concepts of [ownership](../terms-concepts/ownership.md) and [NetworkObject ownership](./networkobject-ownership.md). It's also important to be familiar with the [NetworkBehaviour](./networkbehaviour.md)
+Before reading these docs, ensure you understand the concepts of [ownership](../../terms-concepts/ownership.md) and [NetworkObject ownership](./networkobject-ownership.md). It's also important to be familiar with the [NetworkBehaviour](./networkbehaviour.md)
-The owner of each NetworkBehaviour in your game is decided by the owner of that NetworkBehaviour's NetworkObject. The NetworkObject is found as a property on the NetworkBehaviour: [`NetworkBehaviour.NetworkObject`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.html#Unity_Netcode_NetworkBehaviour_NetworkObject).
+The owner of each NetworkBehaviour in your game is decided by the owner of that NetworkBehaviour's NetworkObject. The NetworkObject is found as a property on the NetworkBehaviour: [`NetworkBehaviour.NetworkObject`](xref:Unity.Netcode.NetworkBehaviour.NetworkObject).
## Helpful properties
> [!NOTE]
-> The following properties are only valid if the NetworkBehaviour has been spawned. Use [`NetworkBehaviour.IsSpawned`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.html#Unity_Netcode_NetworkBehaviour_IsSpawned) to check the spawned status of the NetworkBehaviour
+> The following properties are only valid if the NetworkBehaviour has been spawned. Use [`NetworkBehaviour.IsSpawned`](xref:Unity.Netcode.NetworkBehaviour.IsSpawned) to check the spawned status of the NetworkBehaviour
-To identify whether the local client is the owner of a NetworkBehaviour, you can check the[`NetworkBehaviour.IsOwner`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.html#Unity_Netcode_NetworkBehaviour_IsOwner) property.
+To identify whether the local client is the owner of a NetworkBehaviour, you can check the[`NetworkBehaviour.IsOwner`](xref:Unity.Netcode.NetworkBehaviour.IsOwner) property.
-To identify whether the server owns a NetworkBehaviour, you can check the [`NetworkBehaviour.IsOwnedByServer`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.html#Unity_Netcode_NetworkBehaviour_IsOwnedByServer) property.
+To identify whether the server owns a NetworkBehaviour, you can check the [`NetworkBehaviour.IsOwnedByServer`](xref:Unity.Netcode.NetworkBehaviour.IsOwnedByServer) property.
-To identify whether the local client has authority of a NetworkBehaviour, you can check the[`NetworkBehaviour.HasAuthority`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.html#Unity_Netcode_NetworkBehaviour_HasAuthority) property.
+To identify whether the local client has authority of a NetworkBehaviour, you can check the[`NetworkBehaviour.HasAuthority`](xref:Unity.Netcode.NetworkBehaviour.HasAuthority) property.
## Detecting ownership changes
There are three functions that can be implemented to detect ownership changes on a NetworkBehaviour. These functions are invoked in the order they are listed here.
-### [OnLostOwnership](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.html#Unity_Netcode_NetworkBehaviour_OnLostOwnership)
+### [OnLostOwnership](xref:Unity.Netcode.NetworkBehaviour.OnLostOwnership)
When using a [client-server network topology](../../terms-concepts/client-server.md) `OnLostOwnership` is invoked on both the server any time a connected client loses ownership of this NetworkBehaviour. It is also invoked on the game client who just lost ownership.
@@ -34,7 +34,7 @@ void OnLostOwnership()
}
```
-### [OnGainedOwnership](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.html#Unity_Netcode_NetworkBehaviour_OnGainedOwnership)
+### [OnGainedOwnership](xref:Unity.Netcode.NetworkBehaviour.OnGainedOwnership)
When using a client-server network topology `OnGainedOwnership` is invoked on the server any time ownership is gained. It is also be invoked on the game client who just gained ownership.
@@ -52,7 +52,7 @@ void OnGainedOwnership()
}
```
-### [OnOwnershipChanged](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.html#Unity_Netcode_NetworkBehaviour_OnOwnershipChanged_System_UInt64_System_UInt64_)
+### [OnOwnershipChanged](xref:Unity.Netcode.NetworkBehaviour.OnOwnershipChanged*)
Whenever you want notification on any and all ownership changes, implement the `OnOwnershipChanged` method. `OnOwnershipChanged` is invoked on all connected game clients whenever the ownership of the NetworkBehaviour it is implemented on changes.
diff --git a/com.unity.netcode.gameobjects/Documentation~/components/core/networkbehaviour-synchronize.md b/com.unity.netcode.gameobjects/Documentation~/components/core/networkbehaviour-synchronize.md
index 166b69c4bc..e273296ea5 100644
--- a/com.unity.netcode.gameobjects/Documentation~/components/core/networkbehaviour-synchronize.md
+++ b/com.unity.netcode.gameobjects/Documentation~/components/core/networkbehaviour-synchronize.md
@@ -1,6 +1,6 @@
# NetworkBehaviour synchronization
-[NetworkBehaviour](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.html) is an abstract class that derives from [MonoBehaviour](https://docs.unity3d.com/ScriptReference/MonoBehaviour.html) and is primarily used to create unique netcode or game logic. To replicate any netcode-aware properties or send and receive RPCs, a [GameObject](https://docs.unity3d.com/Manual/GameObjects.html) must have a [NetworkObject](networkobject.md) component and at least one NetworkBehaviour component.
+[NetworkBehaviour](xref:Unity.Netcode.NetworkBehaviour) is an abstract class that derives from [MonoBehaviour](https://docs.unity3d.com/ScriptReference/MonoBehaviour.html) and is primarily used to create unique netcode or game logic. To replicate any netcode-aware properties or send and receive RPCs, a [GameObject](https://docs.unity3d.com/Manual/GameObjects.html) must have a [NetworkObject](networkobject.md) component and at least one NetworkBehaviour component.
You can use NetworkBehaviours to synchronize settings before, during, and after spawning NetworkObjects.
@@ -238,4 +238,4 @@ However, there is an additional check to assure that the total expected bytes to
## Serializing NetworkBehaviours
-NetworkBehaviours require the use of specialized [`NetworkBehaviourReference`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviourReference.html) structures to be serialized and used with RPCs and `NetworkVariable`s.
+NetworkBehaviours require the use of specialized [`NetworkBehaviourReference`](xref:Unity.Netcode.NetworkBehaviourReference) structures to be serialized and used with RPCs and `NetworkVariable`s.
diff --git a/com.unity.netcode.gameobjects/Documentation~/components/core/networkbehaviour.md b/com.unity.netcode.gameobjects/Documentation~/components/core/networkbehaviour.md
index 0922a6d35a..4b1f7e0b02 100644
--- a/com.unity.netcode.gameobjects/Documentation~/components/core/networkbehaviour.md
+++ b/com.unity.netcode.gameobjects/Documentation~/components/core/networkbehaviour.md
@@ -1,6 +1,6 @@
# NetworkBehaviour
-[NetworkBehaviour](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.html) is an abstract class that derives from [MonoBehaviour](https://docs.unity3d.com/ScriptReference/MonoBehaviour.html) and is primarily used to create unique netcode or game logic. To replicate any netcode-aware properties or send and receive RPCs, a [GameObject](https://docs.unity3d.com/Manual/GameObjects.html) must have a [NetworkObject](networkobject.md) component and at least one NetworkBehaviour component.
+[NetworkBehaviour](xref:Unity.Netcode.NetworkBehaviour) is an abstract class that derives from [MonoBehaviour](https://docs.unity3d.com/ScriptReference/MonoBehaviour.html) and is primarily used to create unique netcode or game logic. To replicate any netcode-aware properties or send and receive RPCs, a [GameObject](https://docs.unity3d.com/Manual/GameObjects.html) must have a [NetworkObject](networkobject.md) component and at least one NetworkBehaviour component.
A NetworkBehaviour requires a NetworkObject component on the same relative GameObject or on a parent of the GameObject with the NetworkBehaviour component assigned to it. If you add a NetworkBehaviour to a GameObject that doesn't have a NetworkObject (or any parent), then Netcode for GameObjects automatically adds a NetworkObject component to the GameObject in which the NetworkBehaviour was added.
diff --git a/com.unity.netcode.gameobjects/Documentation~/components/core/networkmanager.md b/com.unity.netcode.gameobjects/Documentation~/components/core/networkmanager.md
index aa59d87d89..7cd646a6ce 100644
--- a/com.unity.netcode.gameobjects/Documentation~/components/core/networkmanager.md
+++ b/com.unity.netcode.gameobjects/Documentation~/components/core/networkmanager.md
@@ -5,7 +5,7 @@ The NetworkManager is a required Netcode for GameObjects component that has all
## NetworkManager Inspector properties
- **LogLevel**: Sets the network logging level
-- **PlayerPrefab**: When a Prefab is assigned, the Prefab will be instantiated as the player object. For more information about player prefabs, refer to [Player NetworkObjects](networkobject.md#player-networkobjects).
+- **PlayerPrefab**: When a Prefab is assigned, the Prefab will be instantiated as the player object. For more information about player prefabs, refer to [Player NetworkObjects](playerobjects.md).
- **NetworkPrefabs**: Where you register your network prefabs. You can also create a single network Prefab override per registered network Prefab here.
- **Protocol Version**: Set this value to help distinguish between builds when the most current build has new assets that can cause issues with older builds connecting.
- **Network Transport**: Where your network specific settings and transport type is set. When using a [client-server topology](../../terms-concepts/client-server.md), This field accepts any INetworkTransport implementation. However, unless you have unique transport specific needs UnityTransport is the recommended transport to use with Netcode for GameObjects. For a [distributed authority topology](../../terms-concepts/distributed-authority.md), refer to the [distributed authority quickstart](../../learn/distributed-authority-quick-start.md).
@@ -19,6 +19,15 @@ The NetworkManager is a required Netcode for GameObjects component that has all
- **Enable Scene Management**: When checked, Netcode for GameObjects will handle scene management and client synchronization for you. When not checked, you will have to create your own scene management scripts and handle client synchronization.
- **Load Scene Time Out**: When Enable Scene Management is checked, this specifies the period of time the `NetworkSceneManager` will wait while a scene is being loaded asynchronously before `NetworkSceneManager` considers the load/unload scene event to have failed/timed out.
+### Distributed authority network topology
+
+> [!NOTE]
+> The distributed authority network topology requires Multiplayer Services. If the Multiplayer Services package is not installed, the **Network Topology** property will not be displayed.
+
+- **Network Topology**: Defines the network topology to use.
+ - **Client-Server**: Selects the client-server network topology.
+ - **Distributed authority**: Selects the distributed authority network topology.
+
## NetworkManager sub-systems
NetworkManager is also where you can find references to other Netcode related management systems:
@@ -68,7 +77,7 @@ NetworkManager.Singleton.StartClient();
When starting a Server or joining an already started session as client, the NetworkManager can spawn a "Player Object" belonging to the client. For more information about player prefabs, refer to:
- [NetworkObject Player Prefab Documentation](networkobject.md)
- - [Connection Approval](../../basics/connection-approval)
+ - [Connection Approval](../../basics/connection-approval.md)
## Connecting
@@ -135,7 +144,7 @@ The server-host attempts to wait for all client connections to close before it f
At times you might need to disconnect a client for various reasons without shutting down the server. To do this, you can call the `NetworkManager.DisconnectClient` method while passing the identifier of the client you wish to disconnect as the only parameter. The client identifier can be found within:
-- The `NetworkManager.ConnectedClients` dictionary that uses the client identifier as a key and the value as the [`NetworkClient`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkClient.html).
+- The `NetworkManager.ConnectedClients` dictionary that uses the client identifier as a key and the value as the [`NetworkClient`](xref:Unity.Netcode.NetworkClient).
- As a read only list of `NetworkClients` via the `NetworkManager.ConnectedClientsList`.
- A full list of all connected client identifiers can be accessed via `NetworkManager.ConnectedClientsIds`.
- The client identifier is passed as a parameter to all subscribers of the `NetworkManager.OnClientConnected` event.
@@ -261,16 +270,16 @@ public class ConnectionNotificationManager : MonoBehaviour
There are two static NetworkManager events you can use to be notified when a NetworkManager is instantiated or is about to be destroyed:
-- [`NetworkManager.OnInstantiated`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkManager.html#Unity_Netcode_NetworkManager_OnInstantiated): This is invoked when a NetworkManager is instantiated.
-- [`NetworkManager.OnDestroying`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkManager.html#Unity_Netcode_NetworkManager_OnDestroying): This is invoked when a NetworkManager is about to be destroyed.
+- [`NetworkManager.OnInstantiated`](xref:Unity.Netcode.NetworkManager.OnInstantiated): This is invoked when a NetworkManager is instantiated.
+- [`NetworkManager.OnDestroying`](xref:Unity.Netcode.NetworkManager.OnDestroying): This is invoked when a NetworkManager is about to be destroyed.
### When a NetworkManager is stopped
Knowing when a NetworkManager has stopped is useful for establishing when it's safe to transition back to a main menu scene, or other similar tasks. There are two events you can use to be notified that the NetworkManager has finished shutting down:
-- [`NetworkManager.OnClientStopped`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkManager.html#Unity_Netcode_NetworkManager_OnClientStopped): This is invoked on a host or client when the NetworkManager has completely shut down and is ready to be restarted.
-- [`NetworkManager.OnServerStopped`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkManager.html#Unity_Netcode_NetworkManager_OnServerStopped): This is invoked on a host or server when the NetworkManager has completely shut down and is ready to be restarted.
+- [`NetworkManager.OnClientStopped`](xref:Unity.Netcode.NetworkManager.OnClientStopped): This is invoked on a host or client when the NetworkManager has completely shut down and is ready to be restarted.
+- [`NetworkManager.OnServerStopped`](xref:Unity.Netcode.NetworkManager.OnServerStopped): This is invoked on a host or server when the NetworkManager has completely shut down and is ready to be restarted.
Since a host is both a client and a server, the event invocation order is:
@@ -283,4 +292,4 @@ Since a host is both a client and a server, the event invocation order is:
If you need to save the state of spawned objects before they're destroyed when the NetworkManager shuts down, you can use the following event notification:
-- [`NetworkManager.OnPreShutdown`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkManager.html#Unity_Netcode_NetworkManager_OnPreShutdown): This is invoked prior to finalizing the NetworkManager shut down process. Any remaining spawned objects will still be instantiated and spawned when this event is invoked.
+- [`NetworkManager.OnPreShutdown`](xref:Unity.Netcode.NetworkManager.OnPreShutdown): This is invoked prior to finalizing the NetworkManager shut down process. Any remaining spawned objects will still be instantiated and spawned when this event is invoked.
diff --git a/com.unity.netcode.gameobjects/Documentation~/components/core/networkobject-ownership.md b/com.unity.netcode.gameobjects/Documentation~/components/core/networkobject-ownership.md
index 81bad2dfff..f2975393e6 100644
--- a/com.unity.netcode.gameobjects/Documentation~/components/core/networkobject-ownership.md
+++ b/com.unity.netcode.gameobjects/Documentation~/components/core/networkobject-ownership.md
@@ -9,11 +9,11 @@ Read more about how to detect when ownership has changed in [NetworkBehaviour ow
## Helpful properties
> [!NOTE]
-> All NetworkObject properties are only valid while the NetworkObject is spawned. Use [`NetworkObject.IsSpawned`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.html#Unity_Netcode_NetworkObject_IsSpawned) to check the spawned status of the NetworkObject.
+> All NetworkObject properties are only valid while the NetworkObject is spawned. Use [`NetworkObject.IsSpawned`](xref:Unity.Netcode.NetworkObject.IsSpawned) to check the spawned status of the NetworkObject.
-To identify whether the local client is the owner of a NetworkObject, you can check the[`NetworkObject.IsOwner`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.IsOwner.html) or the [`NetworkBehaviour.IsOwner`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.IsOwner.html) property.
+To identify whether the local client is the owner of a NetworkObject, you can check the[`NetworkObject.IsOwner`](xref:Unity.Netcode.NetworkObject.IsOwner) or the [`NetworkBehaviour.IsOwner`](xref:Unity.Netcode.NetworkBehaviour.IsOwner) property.
-To identify whether the server owns a NetworkObject, you can check the [`NetworkObject.IsOwnedByServer`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.IsOwnedByServer.html) or the [`NetworkBehaviour.IsOwnedByServer`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.IsOwnedByServer.html) property.
+To identify whether the server owns a NetworkObject, you can check the [`NetworkObject.IsOwnedByServer`](xref:Unity.Netcode.NetworkObject.IsOwnedByServer) or the [`NetworkBehaviour.IsOwnedByServer`](xref:Unity.Netcode.NetworkBehaviour.IsOwnedByServer) property.
> [!NOTE]
> To assure a spawned NetworkObject persists after the owner leaves a session, set the `NetworkObject.DontDestroyWithOwner` property to true. This assures the client-owned NetworkObject doesn't get destroyed when the owning client leaves.
@@ -39,7 +39,7 @@ NetworkObject.SpawnWithOwnership(clientId);
> [!NOTE]
> Using `SpawnWithOwnership` can result in unexpected behavior when the spawning game client makes any other changes on the object immediately after spawning.
-Using `SpawnWithOwnership` and then editing the NetworkObject locally means that the client doing the spawning will behave as the spawn authority. The spawn authority has limited local [authority](../terms-concepts/authority.md) over the NetworkObject, but not [ownership](../terms-concepts/ownership.md) of the NetworkObject that's spawned. This means any owner-specific checks during the spawn sequence will not be invoked on the spawn authority side.
+Using `SpawnWithOwnership` and then editing the NetworkObject locally means that the client doing the spawning will behave as the spawn authority. The spawn authority has limited local [authority](../../terms-concepts/authority.md) over the NetworkObject, but not [ownership](../../terms-concepts/ownership.md) of the NetworkObject that's spawned. This means any owner-specific checks during the spawn sequence will not be invoked on the spawn authority side.
If you want to spawn a NetworkObject for another client and then immediately make adjustments to that NetworkObject, it's recommended to use the `Spawn` method. After adjusting, the spawn authority can immediately follow with a call to `ChangeOwnership`.
@@ -111,15 +111,18 @@ The authority of any NetworkObject can always change ownership, as outlined in [
### Ownership permission settings
-The following ownership permission settings, defined by [`NetworkObject.OwnershipStatus`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.OwnershipStatus.html), control how ownership of NetworkObjects can be changed during a distributed authority session:
+> [!NOTE]
+> Permissions are only valid when using the distributed authority network topology, which requires Multiplayer Services. If the Multiplayer Services package is not installed, the permissions setting will not be displayed.
+
+The following ownership permission settings, defined by [`NetworkObject.OwnershipStatus`](xref:Unity.Netcode.NetworkObject.OwnershipStatus), control how ownership of NetworkObjects can be changed during a distributed authority session:
|**Ownership setting**|Description|Related Property|Multi-select|
|-----|-----|-----|-----|
|`None`|Ownership of this NetworkObject can't be redistributed, requested, or transferred (a Player might have this, for example).||No|
-|`Distributable`|Ownership of this NetworkObject is automatically redistributed when a client joins or leaves, as long as ownership is not locked or a request is pending.|[`IsOwnershipDistributable`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.html#Unity_Netcode_NetworkObject_IsOwnershipDistributable)|**Yes**|
-|`Transferable`|Any client can change ownership of this NetworkObject at any time, as long as ownership is not locked or a request is pending.|[`IsOwnershipTransferable`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.html#Unity_Netcode_NetworkObject_IsOwnershipTransferable)|**Yes**|
-|`RequestRequired`|Ownership of this NetworkObject must be requested before ownership can be changed.|[`IsOwnershipRequestRequired`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.html#Unity_Netcode_NetworkObject_IsOwnershipRequestRequired), [`IsRequestInProgress`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.html#Unity_Netcode_NetworkObject_IsRequestInProgress)|**Yes**|
-|`SessionOwner`|This NetworkObject is always owned by the [session owner](distributed-authority.md#session-ownership) and can't be transferred or distributed. If the session owner changes, this NetworkObject is automatically transferred to the new session owner.|[`IsOwnershipSessionOwner`](Unity_Netcode_NetworkObject_IsOwnershipSessionOwner)|No|
+|`Distributable`|Ownership of this NetworkObject is automatically redistributed when a client joins or leaves, as long as ownership is not locked or a request is pending.|[`IsOwnershipDistributable`](xref:Unity.Netcode.NetworkObject.IsOwnershipDistributable)|**Yes**|
+|`Transferable`|Any client can change ownership of this NetworkObject at any time, as long as ownership is not locked or a request is pending.|[`IsOwnershipTransferable`](xref:Unity.Netcode.NetworkObject.IsOwnershipTransferable)|**Yes**|
+|`RequestRequired`|Ownership of this NetworkObject must be requested before ownership can be changed.|[`IsOwnershipRequestRequired`](xref:Unity.Netcode.NetworkObject.IsOwnershipRequestRequired), [`IsRequestInProgress`](xref:Unity.Netcode.NetworkObject.IsRequestInProgress)|**Yes**|
+|`SessionOwner`|This NetworkObject is always owned by the [session owner](../../terms-concepts/distributed-authority.md#session-ownership) and can't be transferred or distributed. If the session owner changes, this NetworkObject is automatically transferred to the new session owner.|[`IsOwnershipSessionOwner`](xref:Unity.Netcode.NetworkObject.IsOwnershipSessionOwner)|No|
Ownership permissions can be set in the editor using the **Ownership** dropdown.
@@ -127,7 +130,7 @@ Ownership permissions can be set in the editor using the **Ownership** dropdown.
They can also be set in script using
-You can also use `NetworkObject.SetOwnershipLock` to lock and unlock the permission settings of a NetworkObject for a period of time, preventing ownership changes on a temporary basis. The [`IsOwnershipLocked`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.html#Unity_Netcode_NetworkObject_IsOwnershipLocked) property can be used to detect if an object has locked ownership.
+You can also use `NetworkObject.SetOwnershipLock` to lock and unlock the permission settings of a NetworkObject for a period of time, preventing ownership changes on a temporary basis. The [`IsOwnershipLocked`](xref:Unity.Netcode.NetworkObject.IsOwnershipLocked) property can be used to detect if an object has locked ownership.
```csharp
// To lock an object from any ownership changes
@@ -148,7 +151,7 @@ NetworkObject.ChangeOwnership(clientId);
NetworkObject.ChangeOwnership(NetworkManager.LocalClientId);
```
-When a non-authoritative game client calls `ChangeOwnership`, the ownership change can fail. On a failed attempt to change ownership, the `OnOwnershipPermissionsFailure` callback will be invoked with a [`NetworkObject.OwnershipPermissionsFailureStatus`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.OwnershipPermissionsFailureStatus.html) to give information on the failure.
+When a non-authoritative game client calls `ChangeOwnership`, the ownership change can fail. On a failed attempt to change ownership, the `OnOwnershipPermissionsFailure` callback will be invoked with a [`NetworkObject.OwnershipPermissionsFailureStatus`](xref:Unity.Netcode.NetworkObject.OwnershipPermissionsFailureStatus) to give information on the failure.
```csharp
/*
@@ -200,9 +203,9 @@ When a NetworkObject is set with `OwnershipPermissions.RequestRequired` any clie
var requestStatus = NetworkObject.RequestOwnership();
```
-`RequestOwnership` returns an [`OwnershipRequestStatus`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.OwnershipRequestStatus.html) to indicate the initial status of the request. To view the result of the request, the `OnOwnershipRequestResponse` callback will be invoked with a [`NetworkObject.OwnershipRequestResponseStatus`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.OwnershipRequestResponseStatus.html).
+`RequestOwnership` returns an [`OwnershipRequestStatus`](xref:Unity.Netcode.NetworkObject.OwnershipRequestStatus) to indicate the initial status of the request. To view the result of the request, the `OnOwnershipRequestResponse` callback will be invoked with a [`NetworkObject.OwnershipRequestResponseStatus`](xref:Unity.Netcode.NetworkObject.OwnershipRequestResponseStatus).
-By default, any requests for ownership will automatically be approved. To control which client is approved for ownership, use the [`OnOwnershipRequested`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.html#Unity_Netcode_NetworkObject_OnOwnershipRequested) callback
+By default, any requests for ownership will automatically be approved. To control which client is approved for ownership, use the [`OnOwnershipRequested`](xref:Unity.Netcode.NetworkObject.OnOwnershipRequested) callback
```csharp
/*
@@ -264,8 +267,8 @@ public class RequestableOwnershipBehaviour : NetworkBehaviour
## Additional resources
-- [NetworkObject](../components/core/networkobject.md)
+- [NetworkObject](./networkobject.md)
- [NetworkBehaviour](./networkbehaviour.md)
- [NetworkBehaviour ownership](./networkbehaviour-ownership.md)
-- [Ownership](../terms-concepts/ownership.md)
-- [Authority](../terms-concepts/authority.md)
+- [Ownership](../../terms-concepts/ownership.md)
+- [Authority](../../terms-concepts/authority.md)
diff --git a/com.unity.netcode.gameobjects/Documentation~/components/core/networkobject.md b/com.unity.netcode.gameobjects/Documentation~/components/core/networkobject.md
index 56730e4c71..495bed2691 100644
--- a/com.unity.netcode.gameobjects/Documentation~/components/core/networkobject.md
+++ b/com.unity.netcode.gameobjects/Documentation~/components/core/networkobject.md
@@ -7,7 +7,7 @@ Netcode for GameObjects' high level components, [the RPC system](../../advanced-
1. NetworkObject
2. [NetworkBehaviour](networkbehaviour.md)
-NetworkObjects require the use of specialized [`NetworkObjectReference`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObjectReference.html) structures before you can serialize and use them with RPCs and `NetworkVariable`s
+NetworkObjects require the use of specialized [`NetworkObjectReference`](xref:Unity.Netcode.NetworkObjectReference) structures before you can serialize and use them with RPCs and `NetworkVariable`s
Netcode for GameObjects also has [PlayerObjects](playerobjects.md), an optional feature that you can use to assign a NetworkObject to a specific client.
@@ -19,6 +19,32 @@ When spawning a NetworkObject, the `NetworkObject.GlobalObjectIdHash` value init
You can use [NetworkBehaviours](networkbehaviour.md) to add your own custom Netcode logic to the associated NetworkObject.
+### What is a valid NetworkObject?
+
+There are two categories of NetworkObjects:
+* Dynamically instantiated
+* [In-scene placed](../../basics/scenemanagement/inscene-placed-networkobjects.md)
+
+The following provides the validity requirements for both types.
+
+#### Dynamically instantiated network prefabs
+
+Dynamically instantiated network prefabs must:
+
+* Be a valid [network prefab](./networkobject.md#network-prefabs) created within the Editor.
+* Be registered in a network prefab list that's assigned to your NetworkManager.
+
+#### In-scene placed network prefabs
+
+In-scene placed network prefabs must:
+
+* Be a valid network prefab instance within a scene.
+* Be a GameObject with a NetworkObject component created within the scene while in the Editor.
+
+### What is an invalid NetworkObject?
+
+GameObjects that have NetworkObject components added to them during runtime are **not supported** and will result in the NetworkObject's `GlobalObjectIdHash` being zero, which causes synchronization issues. In the event you make this mistake, a warning message will be logged and the NetworkObject won't be spawned.
+
### Component order
The order of components on a networked GameObject matters. When adding netcode components to a GameObject, ensure that the NetworkObject component is ordered before any NetworkBehaviour components.
@@ -65,7 +91,7 @@ Refer to the [NetworkSceneManager active scene synchronization](../../basics/sce

-Similar to [`NetworkObject.ActiveSceneSynchronization`](#active-scene-synchronization), [`NetworkObject.SceneMigrationSynchronization`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkObject.html#Unity_Netcode_NetworkObject_SceneMigrationSynchronization) automatically synchronizes client-side NetworkObject instances that are migrated to a scene via [`SceneManager.MoveGameObjectToScene`](https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.MoveGameObjectToScene.html) on the host or server side. This can be useful if you have a specific scene you wish to migrate NetworkObject instances to that is not the currently active scene.
+Similar to [`NetworkObject.ActiveSceneSynchronization`](#active-scene-synchronization), [`NetworkObject.SceneMigrationSynchronization`](xref:Unity.Netcode.NetworkObject.SceneMigrationSynchronization) automatically synchronizes client-side NetworkObject instances that are migrated to a scene via [`SceneManager.MoveGameObjectToScene`](https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.MoveGameObjectToScene.html) on the host or server side. This can be useful if you have a specific scene you wish to migrate NetworkObject instances to that is not the currently active scene.
`NetworkObject.ActiveSceneSynchronization` can be used with `NetworkObject.SceneMigrationSynchronization` as long as you take into consideration that if you migrate a NetworkObject into a non-active scene via `SceneManager.MoveGameObjectToScene` and later change the active scene, then the NetworkObject instance will be automatically migrated to the newly set active scene.
diff --git a/com.unity.netcode.gameobjects/Documentation~/components/core/playerobjects.md b/com.unity.netcode.gameobjects/Documentation~/components/core/playerobjects.md
index e7ae88353f..a679806c44 100644
--- a/com.unity.netcode.gameobjects/Documentation~/components/core/playerobjects.md
+++ b/com.unity.netcode.gameobjects/Documentation~/components/core/playerobjects.md
@@ -53,14 +53,14 @@ In addition to the [session-mode agnostic spawning methods](#session-mode-agnost
### Distributed authority contexts only
-In addition to the [session-mode agnostic spawning methods](#session-mode-agnostic-methods) above, you can use the [`OnFetchLocalPlayerPrefabToSpawn`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkManager.html#Unity_Netcode_NetworkManager_OnFetchLocalPlayerPrefabToSpawn) method to assign a unique player prefab on a per-client basis when in [distributed authority contexts](../../terms-concepts/distributed-authority.md).
+In addition to the [session-mode agnostic spawning methods](#session-mode-agnostic-methods) above, you can use the [`OnFetchLocalPlayerPrefabToSpawn`](xref:Unity.Netcode.NetworkManager.OnFetchLocalPlayerPrefabToSpawn) method to assign a unique player prefab on a per-client basis when in [distributed authority contexts](../../terms-concepts/distributed-authority.md).
To use `OnFetchLocalPlayerPrefabToSpawn` in your project, assign a callback handler to `OnFetchLocalPlayerPrefabToSpawn` and whatever the client script returns is what will be spawned for that client. Ensure that the prefab being spawned is in a NetworkPrefabList [registered with the NetworkManager](../../basics/object-spawning.md#registering-a-network-prefab).
If you don't assign a callback handler to `OnFetchLocalPlayerPrefabToSpawn`, then the default behavior is to return the `NetworkConfig.PlayerPrefab` (or null if neither are set).
:::note `AutoSpawnPlayerPrefabClientSide` required
-For `OnFetchLocalPlayerPrefabToSpawn` to work, [`AutoSpawnPlayerPrefabClientSide`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkManager.html#Unity_Netcode_NetworkManager_AutoSpawnPlayerPrefabClientSide) must be enabled.
+For `OnFetchLocalPlayerPrefabToSpawn` to work, [`AutoSpawnPlayerPrefabClientSide`](xref:Unity.Netcode.NetworkManager.AutoSpawnPlayerPrefabClientSide) must be enabled.
:::
## PlayerObject spawning timeline
diff --git a/com.unity.netcode.gameobjects/Documentation~/components/helper/componentcontroller.md b/com.unity.netcode.gameobjects/Documentation~/components/helper/componentcontroller.md
index 26465b9d6e..09136b095e 100644
--- a/com.unity.netcode.gameobjects/Documentation~/components/helper/componentcontroller.md
+++ b/com.unity.netcode.gameobjects/Documentation~/components/helper/componentcontroller.md
@@ -1,6 +1,6 @@
# ComponentController
-Use a [ComponentController](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.ComponentController.html) component to enable or disable one or more components depending on the authority state of the ComponentController and have those changes synchronized with non-authority instances.
+Use a [ComponentController](xref:Unity.Netcode.ComponentController) component to enable or disable one or more components depending on the authority state of the ComponentController and have those changes synchronized with non-authority instances.
For example, you can use a ComponentController to enable or disable a MeshRenderer component on the owner of the ComponentController instance, while disabling it for all other clients. This is useful for controlling visibility of objects that should only be visible to the owner, such as a player's avatar or a weapon they are holding.
diff --git a/com.unity.netcode.gameobjects/Documentation~/components/helper/helpercomponents.md b/com.unity.netcode.gameobjects/Documentation~/components/helper/helpercomponents.md
index 64df3f347b..d9515ebb47 100644
--- a/com.unity.netcode.gameobjects/Documentation~/components/helper/helpercomponents.md
+++ b/com.unity.netcode.gameobjects/Documentation~/components/helper/helpercomponents.md
@@ -6,8 +6,8 @@ Understand the helper components available to use in your Netcode for GameObject
| :------------------------------ | :------------------------------- |
| **[AttachableBehaviour](attachablebehaviour.md)**| Use the AttachableBehaviour component to manage [ComponentController](componentcontroller.md) components and to attach a child GameObject to an [AttachableNode](attachablenode.md). The AttachableBehaviour component provides an alternative to NetworkObject parenting, allowing you to attach and detach child objects dynamically during runtime. |
| **[AttachableNode](attachablenode.md)**| Use an AttachableNode component to provide an attachment point for an [AttachableBehaviour](attachablebehaviour.md) component. |
-| **[ComponentController](componentcontroller.md)**| Use a [ComponentController](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.ComponentController.html) component to enable or disable one or more components depending on the authority state of the ComponentController and have those changes synchronized with non-authority instances. |
+| **[ComponentController](componentcontroller.md)**| Use a [ComponentController](xref:Unity.Netcode.ComponentController) component to enable or disable one or more components depending on the authority state of the ComponentController and have those changes synchronized with non-authority instances. |
| **[NetworkAnimator](networkanimator.md)**| The NetworkAnimator component provides you with a fundamental example of how to synchronize animations during a network session. Animation states are synchronized with players joining an existing network session and any client already connected before the animation state changing. |
| **[NetworkRigidbody](networkrigidbody.md)**| NetworkRigidbody is a component that sets the Rigidbody of the GameObject into kinematic mode on all non-authoritative instances. |
-| **[NetworkTransform](networktransform.md)**| [NetworkTransform](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.Components.NetworkTransform.html) is a concrete class that inherits from [NetworkBehaviour](../core/networkbehaviour.md) and synchronizes [Transform](https://docs.unity3d.com/Manual/class-Transform.html) properties across the network, ensuring that the position, rotation, and scale of a [GameObject](https://docs.unity3d.com/Manual/working-with-gameobjects.html) are replicated to other clients. |
+| **[NetworkTransform](networktransform.md)**| [NetworkTransform](xref:Unity.Netcode.Components.NetworkTransform) is a concrete class that inherits from [NetworkBehaviour](../core/networkbehaviour.md) and synchronizes [Transform](https://docs.unity3d.com/Manual/class-Transform.html) properties across the network, ensuring that the position, rotation, and scale of a [GameObject](https://docs.unity3d.com/Manual/working-with-gameobjects.html) are replicated to other clients. |
| **[Physics](../../advanced-topics/physics.md)**| Netcode for GameObjects has a built in approach which allows for server-authoritative physics where the physics simulation only runs on the server. |
diff --git a/com.unity.netcode.gameobjects/Documentation~/components/helper/networkrigidbody.md b/com.unity.netcode.gameobjects/Documentation~/components/helper/networkrigidbody.md
index 8f412f7898..b931d59afb 100644
--- a/com.unity.netcode.gameobjects/Documentation~/components/helper/networkrigidbody.md
+++ b/com.unity.netcode.gameobjects/Documentation~/components/helper/networkrigidbody.md
@@ -12,7 +12,7 @@ When looking at a NetworkRigidbody in the Inspector view, there are three expose
- When enabled and using a [NetworkTransform](networktransform.md), the NetworkTransform uses the PhysX position and rotation to synchronize changes during the `FixedUpdate` loop update stage.
- __Auto Update Kinematic State__
- When enabled, NetworkRigidbody automatically determines whether the current instance should be kinematic or non-kinematic.
- - For custom solutions, you can opt to disable this field or derive from [NetworkRigidbodyBase](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@2.5/api/Unity.Netcode.Components.NetworkRigidbodyBase.html) and design your own custom networked Rigidbody handler.
+ - For custom solutions, you can opt to disable this field or derive from [NetworkRigidbodyBase](xref:Unity.Netcode.Components.NetworkRigidbodyBase) and design your own custom networked Rigidbody handler.
- __Auto Set Kinematic On Despawn__
- When enabled, this option makes the rigid body kinematic when despawned (which can be useful for [object pools](../../advanced-topics/object-pooling.md)).
@@ -25,7 +25,7 @@ Some collision events aren't fired when using NetworkRigidBody:
- You can adjust the __Contact Pairs Mode__ to use kinematic and non-kinematic by setting it to __Enable All Contact Pairs__.
> [!NOTE]
-> If there's a need for a gameplay event to happen on a collision, you can listen to the `OnCollisionEnter` function on the server and synchronize the event via `Rpc(SendTo.Everyone)` to all clients. If you plan on handling many collisions, then it's recommended to use the [RigidbodyContactEventManager component](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.Components.RigidbodyContactEventManager.html) to handle collision checking during a job (`OnCollisionenter` can become expensive from a processing perspective if you have enough instances colliding).
+> If there's a need for a gameplay event to happen on a collision, you can listen to the `OnCollisionEnter` function on the server and synchronize the event via `Rpc(SendTo.Everyone)` to all clients. If you plan on handling many collisions, then it's recommended to use the [RigidbodyContactEventManager component](xref:Unity.Netcode.Components.RigidbodyContactEventManager) to handle collision checking during a job (`OnCollisionenter` can become expensive from a processing perspective if you have enough instances colliding).
### NetworkRigidbody2D
diff --git a/com.unity.netcode.gameobjects/Documentation~/components/helper/networktransform.md b/com.unity.netcode.gameobjects/Documentation~/components/helper/networktransform.md
index b77c930647..8db6f66114 100644
--- a/com.unity.netcode.gameobjects/Documentation~/components/helper/networktransform.md
+++ b/com.unity.netcode.gameobjects/Documentation~/components/helper/networktransform.md
@@ -1,6 +1,6 @@
# NetworkTransform
-[NetworkTransform](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.Components.NetworkTransform.html) is a concrete class that inherits from [NetworkBehaviour](../core/networkbehaviour.md) and synchronizes [Transform](https://docs.unity3d.com/Manual/class-Transform.html) properties across the network, ensuring that the position, rotation, and scale of a [GameObject](https://docs.unity3d.com/Manual/working-with-gameobjects.html) are replicated to other clients.
+[NetworkTransform](xref:Unity.Netcode.Components.NetworkTransform) is a concrete class that inherits from [NetworkBehaviour](../core/networkbehaviour.md) and synchronizes [Transform](https://docs.unity3d.com/Manual/class-Transform.html) properties across the network, ensuring that the position, rotation, and scale of a [GameObject](https://docs.unity3d.com/Manual/working-with-gameobjects.html) are replicated to other clients.
The synchronization of a GameObject's Transform is a key netcode task, and usually proceeds in the following order:
@@ -39,7 +39,7 @@ Theoretically, you can have a NetworkTransform on every child object of a 100 le
When nesting NetworkTransforms, you should first determine if there are any alternative approaches to handling child object motion (such as synchronizing through animations or using an algorithm that uses the synchronized network time) to ensure you're not consuming unnecessary processing time and bandwidth.
-For example, if you use a [NetworkAnimator](networkanimator.md) component to synchronize animations (instead of nested NetworkTransforms), then you don't need to manage synchronizing each child node of the model because the animation system and NetworkAnimator handle it for you. Similarly, if you want a child object to orbit its parent object, you can use the server time ([`NetworkManager.ServerTime`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?sufolder=/api/Unity.Netcode.NetworkManager.html#Unity_Netcode_NetworkManager_ServerTime)) to feed into an algorithm that's used on all instances (local and remote). This removes the need to synchronize motion between child and parent because the algorithm is driven by a value that's already being synchronized on all clients.
+For example, if you use a [NetworkAnimator](networkanimator.md) component to synchronize animations (instead of nested NetworkTransforms), then you don't need to manage synchronizing each child node of the model because the animation system and NetworkAnimator handle it for you. Similarly, if you want a child object to orbit its parent object, you can use the server time ([`NetworkManager.ServerTime`](xref:Unity.Netcode.NetworkManager.ServerTime)) to feed into an algorithm that's used on all instances (local and remote). This removes the need to synchronize motion between child and parent because the algorithm is driven by a value that's already being synchronized on all clients.
> [!NOTE]
> Generally, unless you have some unique motion that needs to be applied to a child object and it can't be synchronized through an animation or an algorithm based on a synchronized value, then you shouldn't nest NetworkTransforms. However, nesting NetworkTransforms is more optimal then creating multiple individual single-node network prefabs with NetworkTransforms and parenting those once they're spawned.
@@ -58,13 +58,13 @@ Some NetworkTransform properties are automatically synchronized by the authorita
The following are a list of NetworkTransform properties that will cause a full state update (effectively a teleport) when changed during runtime by the authority instance:
-- [UseUnreliableDeltas](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@2.3/api/Unity.Netcode.Components.NetworkTransform.html#Unity_Netcode_Components_NetworkTransform_UseUnreliableDeltas)
-- [InLocalSpace](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@2.3/api/Unity.Netcode.Components.NetworkTransform.html#Unity_Netcode_Components_NetworkTransform_InLocalSpace)
-- [Interpolate](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@2.3/api/Unity.Netcode.Components.NetworkTransform.html#Unity_Netcode_Components_NetworkTransform_Interpolate)
-- [SlerpPosition](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@2.3/api/Unity.Netcode.Components.NetworkTransform.html#Unity_Netcode_Components_NetworkTransform_SlerpPosition)
-- [UseQuaternionSynchronization](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@2.3/api/Unity.Netcode.Components.NetworkTransform.html#Unity_Netcode_Components_NetworkTransform_UseQuaternionSynchronization)
-- [UseQuaternionCompression](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@2.3/api/Unity.Netcode.Components.NetworkTransform.html#Unity_Netcode_Components_NetworkTransform_UseQuaternionCompression)
-- [UseHalfFloatPrecision](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@2.3/api/Unity.Netcode.Components.NetworkTransform.html#Unity_Netcode_Components_NetworkTransform_UseHalfFloatPrecision)
+- [UseUnreliableDeltas](xref:Unity.Netcode.Components.NetworkTransform.UseUnreliableDeltas)
+- [InLocalSpace](xref:Unity.Netcode.Components.NetworkTransform.InLocalSpace)
+- [Interpolate](xref:Unity.Netcode.Components.NetworkTransform.Interpolate)
+- [SlerpPosition](xref:Unity.Netcode.Components.NetworkTransform.SlerpPosition)
+- [UseQuaternionSynchronization](xref:Unity.Netcode.Components.NetworkTransform.UseQuaternionSynchronization)
+- [UseQuaternionCompression](xref:Unity.Netcode.Components.NetworkTransform.UseQuaternionCompression)
+- [UseHalfFloatPrecision](xref:Unity.Netcode.Components.NetworkTransform.UseHalfFloatPrecision)
The following NetworkTransform properties can cause a full state update when changed during runtime by the authority instance:
diff --git a/com.unity.netcode.gameobjects/Documentation~/install.md b/com.unity.netcode.gameobjects/Documentation~/install.md
index 9fb1b54ef6..c3e5b597ec 100644
--- a/com.unity.netcode.gameobjects/Documentation~/install.md
+++ b/com.unity.netcode.gameobjects/Documentation~/install.md
@@ -7,7 +7,7 @@ Follow the instructions on this page to set up Netcode for GameObjects in your U
Before you begin, you need the following:
- An active Unity account with a valid license.
-- A supported version of Unity. Check [Netcode for GameObjects' requirements](#netcode-installation-requirements) for the specific version details.
+- A supported version of Unity. Check [Netcode for GameObjects' requirements](#compatibility) for the specific version details.
- An existing Unity project. If you're new to Unity, you can refer to the [get started](./tutorials/get-started-with-ngo.md) section for guidance.
### Compatibility
diff --git a/com.unity.netcode.gameobjects/Documentation~/learn/dealing-with-latency.md b/com.unity.netcode.gameobjects/Documentation~/learn/dealing-with-latency.md
index a14cc6d0da..e1c5b056ca 100644
--- a/com.unity.netcode.gameobjects/Documentation~/learn/dealing-with-latency.md
+++ b/com.unity.netcode.gameobjects/Documentation~/learn/dealing-with-latency.md
@@ -52,7 +52,7 @@ Note here an input from a client can be anything, from a user interacting with a
#### Issue: Reactivity
-An issue with server authority is you're waiting for your server to tell you to update your world. This means that if you send an input to the server and wait for the server to tell you your position change, you'll need to wait for a full **RTT** before you see the effect. There are [patterns](#patterns-to-solve-these-issues) you can use to solve this issue while still remaining server authoritative.
+An issue with server authority is you're waiting for your server to tell you to update your world. This means that if you send an input to the server and wait for the server to tell you your position change, you'll need to wait for a full **RTT** before you see the effect. There are [patterns](#patterns-to-solve-latency-issues-in-a-server-authoritative-game) you can use to solve this issue while still remaining server authoritative.
### Client authority
@@ -82,7 +82,7 @@ To avoid this, it's recommended to use client **owner** authority, which allows
Client authority is a pretty dangerous door to leave open on your server because any malicious player can forge messages to say "kill player a, b, c, d, e, f, g" and win the game. It's pretty useful though for reactivity. Since the client is making all the important gameplay decisions, it can display the result of user inputs as soon as they happen instead of waiting a few hundred milliseconds.
-When you don't think there's any reason for your players to cheat, client authority can be a great way to have reactivity without the complexity added with techniques like [input prediction](#prediction).
+When you don't think there's any reason for your players to cheat, client authority can be a great way to have reactivity without the complexity added with techniques like [input prediction](#client-side-prediction).
Another way of solving this issue in a client authoritative game is using soft validation server side. Instead of doing all simulation server side, the server only does basic validation. The server would, for example, do range checks to make sure a player isn't teleporting to places it shouldn't. Doing so is acceptable for most [PvE](https://en.wikipedia.org/wiki/Player_versus_environment) games. However, [PvP](https://en.wikipedia.org/wiki/Player_versus_player) games usually require server authority.
@@ -157,7 +157,7 @@ To do continuous client driven actions, there's a few more considerations to tak
- You then need to make sure you don't send RPCs to the server (containing your authoritative state) when no data has changed and do dirty checks.
- You'd need to send it on tick or at worst on FixedUpdate. Sending on Update() would spam your connection.
-A sample for a [ClientNetworkTransform](../components/helper/networktransform.md#clientnetworktransform) has been created, so you don't have to reimplement this yourself for transform updates. A [sample](https://github.com/Unity-Technologies/com.unity.multiplayer.samples.bitesize/tree/main/Basic/ClientDriven) has been created on how to use it. See [movement script](https://github.com/Unity-Technologies/com.unity.multiplayer.samples.bitesize/blob/v1.2.1/Basic/ClientDriven/Assets/Scripts/ClientPlayerMove.cs).
+A sample for a [ClientNetworkTransform](../components/helper/networktransform.md#client-vs-server-authority) has been created, so you don't have to reimplement this yourself for transform updates. A [sample](https://github.com/Unity-Technologies/com.unity.multiplayer.samples.bitesize/tree/main/Basic/ClientDriven) has been created on how to use it. See [movement script](https://github.com/Unity-Technologies/com.unity.multiplayer.samples.bitesize/blob/v1.2.1/Basic/ClientDriven/Assets/Scripts/ClientPlayerMove.cs).
> [!NOTE]
> A rule of thumb here is to ask yourself: "Can the server correct me on this?". If it can, use server authority.
diff --git a/com.unity.netcode.gameobjects/Documentation~/learn/listenserverhostarchitecture.md b/com.unity.netcode.gameobjects/Documentation~/learn/listenserverhostarchitecture.md
index e32e3858c8..d85764142b 100644
--- a/com.unity.netcode.gameobjects/Documentation~/learn/listenserverhostarchitecture.md
+++ b/com.unity.netcode.gameobjects/Documentation~/learn/listenserverhostarchitecture.md
@@ -33,7 +33,7 @@ In contrast to dedicated servers, listen servers are cheaper without the need to
## Connecting to a listen server
-Personal computers are hidden behind NATs (Network Address Translation devices) and routers to protect them from direct access. To connect to a listen server, you may choose an option such as [port forwarding](#port-forwarding), a [relay server](#relay-server), [NAT punch-through](#nat-punchthrough), or a [NAT punch with relay fallback](#nat-punch-and-relay-fallback).
+Personal computers are hidden behind NATs (Network Address Translation devices) and routers to protect them from direct access. To connect to a listen server, you may choose an option such as [port forwarding](#port-forwarding), a [relay server](#relay-server), [NAT punch-through](#nat-punch-through), or a [NAT punch with relay fallback](#nat-punch-and-relay-fallback).
### Port Forwarding
diff --git a/com.unity.netcode.gameobjects/Documentation~/learn/rpcvnetvar.md b/com.unity.netcode.gameobjects/Documentation~/learn/rpcvnetvar.md
index 0713cbab28..3d31914ddb 100644
--- a/com.unity.netcode.gameobjects/Documentation~/learn/rpcvnetvar.md
+++ b/com.unity.netcode.gameobjects/Documentation~/learn/rpcvnetvar.md
@@ -1,7 +1,7 @@
# RPC vs NetworkVariable
Choosing the wrong data syncing mechanism can create bugs, use too much bandwidth, and add too much complexity to your code.
-Netcode for GameObjects (Netcode) has two main ways of syncing information between players: RPCs ([Remote Procedure Calls](../advanced-topics/messaging-system.md)) and replicated states [(`NetworkVariable`s)](../basics/networkvariable). They both send messages over the network. The logic and your design around how they send messages is what will make you choose one over the other.
+Netcode for GameObjects (Netcode) has two main ways of syncing information between players: RPCs ([Remote Procedure Calls](../advanced-topics/messaging-system.md)) and replicated states [(`NetworkVariable`s)](../basics/networkvariable.md). They both send messages over the network. The logic and your design around how they send messages is what will make you choose one over the other.
## Choosing between `NetworkVariable`s or RPCs
diff --git a/com.unity.netcode.gameobjects/Documentation~/learn/ticks-and-update-rates.md b/com.unity.netcode.gameobjects/Documentation~/learn/ticks-and-update-rates.md
index 2ab45e73c2..dac2bc523a 100644
--- a/com.unity.netcode.gameobjects/Documentation~/learn/ticks-and-update-rates.md
+++ b/com.unity.netcode.gameobjects/Documentation~/learn/ticks-and-update-rates.md
@@ -16,7 +16,7 @@ When a server fails to process all incoming client data before the end of the cu
Update rate is a measure of how frequently the client sends and receives data to and from the server. It's also measured in hertz and, like tick rate, a higher update rate results in a more responsive game at the cost of increased processing and network demands on the client and server.
-
+
In addition to adding to perceived latency, low update rates can cause their own issues, such as multiple updates being bundled together and arriving at the same time, causing undesirable behavior.
@@ -24,7 +24,7 @@ In the example of 'super bullets': if an in-game gun is capable of shooting more
The diagram below illustrates the difference between a 10 Hz update rate and a 60 Hz update rate. With a 10 Hz update rate, the game sends updates to the server ten times a second, so a gun that can fire 600 rounds per minute (RPM), or ten times a second, will only ever send a single bullet per update. A gun that fires at 750 RPM, more than ten times a second, will end up running into the super bullet problem. A higher update rate of 60 Hz resolves this issue, ensuring that there are enough updates for each bullet to arrive separately in its own update.
-
+
### Discrepancy between tick rate and update rate
diff --git a/com.unity.netcode.gameobjects/Documentation~/migratingfromUNet.md b/com.unity.netcode.gameobjects/Documentation~/migratingfromUNet.md
index ee35801235..8d58a3366d 100644
--- a/com.unity.netcode.gameobjects/Documentation~/migratingfromUNet.md
+++ b/com.unity.netcode.gameobjects/Documentation~/migratingfromUNet.md
@@ -115,7 +115,7 @@ public class MyNetcodeExample : NetworkBehaviour
}
```
-Refer to [NetworkBehaviour](basics/networkbehaviour.md) for more information.
+Refer to [NetworkBehaviour](components/core/networkbehaviour.md) for more information.
## Replace SyncVar
@@ -343,7 +343,7 @@ Refer to [Object Spawning](basics/object-spawning.md) for more information.
## Custom Spawn Handlers
-Netcode has `Custom Spawn Handlers` to replace UNet's `Custom Spawn Functions`. See [Object Pooling](../advanced-topics/object-pooling) for more information.
+Netcode has `Custom Spawn Handlers` to replace UNet's `Custom Spawn Functions`. See [Object Pooling](advanced-topics/object-pooling.md) for more information.
## Replace `NetworkContextProperties`
diff --git a/com.unity.netcode.gameobjects/Documentation~/networkbehaviour-landing.md b/com.unity.netcode.gameobjects/Documentation~/networkbehaviour-landing.md
index c690759906..8d1cbeac17 100644
--- a/com.unity.netcode.gameobjects/Documentation~/networkbehaviour-landing.md
+++ b/com.unity.netcode.gameobjects/Documentation~/networkbehaviour-landing.md
@@ -5,5 +5,5 @@ Understand how to use NetworkBehaviour components in your project.
| **Topic** | **Description** |
| :------------------------------ | :------------------------------- |
-| **[NetworkBehaviour](components/core/networkbehaviour.md)** | [NetworkBehaviour](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.NetworkBehaviour.html) is an abstract class that derives from [MonoBehaviour](https://docs.unity3d.com/ScriptReference/MonoBehaviour.html) and is primarily used to create unique netcode or game logic. To replicate any netcode-aware properties or send and receive RPCs, a [GameObject](https://docs.unity3d.com/Manual/GameObjects.html) must have a [NetworkObject](components/core/networkobject.md) component and at least one NetworkBehaviour component. |
+| **[NetworkBehaviour](components/core/networkbehaviour.md)** | [NetworkBehaviour](xref:Unity.Netcode.NetworkBehaviour) is an abstract class that derives from [MonoBehaviour](https://docs.unity3d.com/ScriptReference/MonoBehaviour.html) and is primarily used to create unique netcode or game logic. To replicate any netcode-aware properties or send and receive RPCs, a [GameObject](https://docs.unity3d.com/Manual/GameObjects.html) must have a [NetworkObject](components/core/networkobject.md) component and at least one NetworkBehaviour component. |
| **[Synchronize](components/core/networkbehaviour-synchronize.md)** | You can use NetworkBehaviours to synchronize settings before, during, and after spawning NetworkObjects. |
\ No newline at end of file
diff --git a/com.unity.netcode.gameobjects/Documentation~/removed-tableofcontents.md b/com.unity.netcode.gameobjects/Documentation~/removed-tableofcontents.md
index e9eadb4428..224e9f2f47 100644
--- a/com.unity.netcode.gameobjects/Documentation~/removed-tableofcontents.md
+++ b/com.unity.netcode.gameobjects/Documentation~/removed-tableofcontents.md
@@ -10,7 +10,7 @@
* [Bitesize introduction](samples/bitesize/bitesize-introduction.md)
* [Bitesize space shooter](samples/bitesize/bitesize-spaceshooter.md)
* [Bitesize client driven](samples/bitesize/bitesize-clientdriven.md)
- * [Bitesize dynamic prefabs](samples/bitesize/bitesize-dynamicPrefabs.md)
+ * [Bitesize dynamic prefabs](samples/bitesize/bitesize-dynamicprefabs.md)
* [Bitesize social hub](samples/bitesize/bitesize-socialhub.md)
-->
\ No newline at end of file
diff --git a/com.unity.netcode.gameobjects/Documentation~/samples/bitesize/bitesize-landing.md b/com.unity.netcode.gameobjects/Documentation~/samples/bitesize/bitesize-landing.md
index 880fbb821e..1009a7343e 100644
--- a/com.unity.netcode.gameobjects/Documentation~/samples/bitesize/bitesize-landing.md
+++ b/com.unity.netcode.gameobjects/Documentation~/samples/bitesize/bitesize-landing.md
@@ -8,5 +8,5 @@ The Bite Size samples are small, focused examples that demonstrate specific feat
| **[Bitesize introduction](bitesize-introduction.md)** | The Bitesize Samples repository provides a series of sample code as modules to use in your games and better understand Netcode for GameObjects. |
| **[Bitesize space shooter](bitesize-spaceshooter.md)** | Learn more about physics movement and status effects using Netcode for GameObjects (Netcode) NetworkVariables and ObjectPooling. |
| **[Bitesize client driven](bitesize-clientdriven.md)** | Learn more about Client driven movements, networked physics, spawning vs statically placed objects, object reparenting. |
-| **[Bitesize dynamic prefabs](bitesize-dynamicPrefabs.md)** | Learn more about the dynamic Prefab system, which allows you to add new spawnable Prefabs at runtime. |
+| **[Bitesize dynamic prefabs](bitesize-dynamicprefabs.md)** | Learn more about the dynamic Prefab system, which allows you to add new spawnable Prefabs at runtime. |
| **[Bitesize social hub](bitesize-socialhub.md)** | The Distributed Authority Social Hub Sample is a project that demonstrates Distributed Authority's features and helps you integrate Distributed Authority into your own game projects. |
\ No newline at end of file
diff --git a/com.unity.netcode.gameobjects/Documentation~/samples/bitesize/bitesize-usecases.md b/com.unity.netcode.gameobjects/Documentation~/samples/bitesize/bitesize-usecases.md
index ebdbfc5705..a41c3d1238 100644
--- a/com.unity.netcode.gameobjects/Documentation~/samples/bitesize/bitesize-usecases.md
+++ b/com.unity.netcode.gameobjects/Documentation~/samples/bitesize/bitesize-usecases.md
@@ -16,11 +16,11 @@ The tutorials that open with each scene use the [Tutorial Framework package](htt
## The Anticipation scene
The Anticipation scene demonstrates the Client Anticipation feature of Netcode for GameObjects in the following use cases:
-- [`AnticipatedNetworkVariable`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@2.2/api/Unity.Netcode.AnticipatedNetworkVariable-1.html):
+- [`AnticipatedNetworkVariable`](xref:Unity.Netcode.AnticipatedNetworkVariable%601):
- Anticipate server actions based on player interaction to change NetworkVariables responsively.
- Compensate for latency that the server causes when it changes a value.
- Handle incorrect anticipation.
-- [`AnticipatedNetworkTransform`](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@2.2/api/Unity.Netcode.Components.AnticipatedNetworkTransform.html):
+- [`AnticipatedNetworkTransform`](xref:Unity.Netcode.Components.AnticipatedNetworkTransform):
- Responsive server-authoritative player movement.
- Smooth player movement across clients.
diff --git a/com.unity.netcode.gameobjects/Documentation~/samples/bossroom/getting-started-boss-room.md b/com.unity.netcode.gameobjects/Documentation~/samples/bossroom/getting-started-boss-room.md
index 096d7f72db..214a8fdae5 100644
--- a/com.unity.netcode.gameobjects/Documentation~/samples/bossroom/getting-started-boss-room.md
+++ b/com.unity.netcode.gameobjects/Documentation~/samples/bossroom/getting-started-boss-room.md
@@ -25,8 +25,8 @@ Join the multiplayer community on the Unity [Discord](https://discord.gg/mNgM2XR
### Contents and quick links
- [Boss Room Overview](#boss-room-overview)
-- [Install the Boss Room project](#getting-the-project)
- - [Install Git LFS to clone locally](#installing-git-lfs-to-clone-locally)
+- [Install the Boss Room project](#install-the-boss-room-project)
+ - [Install Git LFS to clone locally](#install-git-lfs-to-clone-locally)
- [Direct download](#direct-download)
- [Registering the project with Unity Gaming Services (UGS)](#registering-the-project-with-unity-gaming-services-ugs)
- [Opening the project for the first time](#opening-the-project-for-the-first-time)
diff --git a/com.unity.netcode.gameobjects/Documentation~/samples/bossroom/optimizing-bossroom.md b/com.unity.netcode.gameobjects/Documentation~/samples/bossroom/optimizing-bossroom.md
index 234830e4c0..ddde94a432 100644
--- a/com.unity.netcode.gameobjects/Documentation~/samples/bossroom/optimizing-bossroom.md
+++ b/com.unity.netcode.gameobjects/Documentation~/samples/bossroom/optimizing-bossroom.md
@@ -73,19 +73,19 @@ The Boss Room sample shows how to adapt some Unity Transport properties to fit i
### Disconnect Timeout {#disconnect-timeout}
-The [Disconnect Timeout property](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.Transports.UTP.UnityTransport.html#Unity_Netcode_Transports_UTP_UnityTransport_DisconnectTimeoutMS) controls how long the server (and the clients) wait before disconnecting. The Boss Room sample uses a Disconnect Timeout value of 10 seconds to prevent the server and the clients from hanging onto a connection for too long.
+The [Disconnect Timeout property](xref:Unity.Netcode.Transports.UTP.UnityTransport.DisconnectTimeoutMS) controls how long the server (and the clients) wait before disconnecting. The Boss Room sample uses a Disconnect Timeout value of 10 seconds to prevent the server and the clients from hanging onto a connection for too long.
### Max Connect Attempts {#max-connect-attempts}
-The [Max Connect Attempts property](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.Transports.UTP.UnityTransport.html#Unity_Netcode_Transports_UTP_UnityTransport_MaxConnectAttempts) controls the times a client tries to connect before declaring a connection failure. The Boss Room sample uses a Max Connect Attempts value of 10 to prevent clients from waiting too long before declaring a connection failure.
+The [Max Connect Attempts property](xref:Unity.Netcode.Transports.UTP.UnityTransport.MaxConnectAttempts) controls the times a client tries to connect before declaring a connection failure. The Boss Room sample uses a Max Connect Attempts value of 10 to prevent clients from waiting too long before declaring a connection failure.
### Connect Timeout {#connect-timeout}
-The [Connect Timeout property](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.Transports.UTP.UnityTransport.html#Unity_Netcode_Transports_UTP_UnityTransport_ConnectTimeoutMS) controls the number of times clients attempt to connect per second. The Boss Room sample uses a Connect Timeout value of 1 second, meaning that clients try to connect once per second. Having the Connect Timeout set to 1 second and the Max Connect Attempts set to 10 means that clients fail to connect after 10 seconds of waiting.
+The [Connect Timeout property](xref:Unity.Netcode.Transports.UTP.UnityTransport.ConnectTimeoutMS) controls the number of times clients attempt to connect per second. The Boss Room sample uses a Connect Timeout value of 1 second, meaning that clients try to connect once per second. Having the Connect Timeout set to 1 second and the Max Connect Attempts set to 10 means that clients fail to connect after 10 seconds of waiting.
### Max Packet Queue Size {#max-packet-queue-size}
-The [Max Packet Queue Size property](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest?subfolder=/api/Unity.Netcode.Transports.UTP.UnityTransport.html#Unity_Netcode_Transports_UTP_UnityTransport_MaxPacketQueueSize) defines the maximum number of packets that can be sent and received during a single frame.
+The [Max Packet Queue Size property](xref:Unity.Netcode.Transports.UTP.UnityTransport.MaxPacketQueueSize) defines the maximum number of packets that can be sent and received during a single frame.
The impact of surpassing the Max Packet Queue Size threshold varies depending on the packet direction (sending or receiving).
diff --git a/com.unity.netcode.gameobjects/Documentation~/serialization.md b/com.unity.netcode.gameobjects/Documentation~/serialization.md
index fb39fad334..51aee596eb 100644
--- a/com.unity.netcode.gameobjects/Documentation~/serialization.md
+++ b/com.unity.netcode.gameobjects/Documentation~/serialization.md
@@ -4,11 +4,14 @@ Netcode for GameObjects has built-in serialization support for C# and Unity prim
| **Topic** | **Description** |
| :------------------------------ | :------------------------------- |
+| **[Serialization overview](advanced-topics/serialization/serialization-overview.md)** | An overview of how Netcode for GameObjects handles serialization. |
| **[C# primitives](advanced-topics/serialization/cprimitives.md)** | C# primitive types are serialized by built-in serialization code. These types include `bool`, `char`, `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `float`, `double`, and `string`. |
| **[Unity primitives](advanced-topics/serialization/unity-primitives.md)** | Unity Primitive `Color`, `Color32`, `Vector2`, `Vector3`, `Vector4`, `Quaternion`, `Ray`, `Ray2D` types will be serialized by built-in serialization code. |
| **[Enum types](advanced-topics/serialization/enum-types.md)** | A user-defined enum type will be serialized by built-in serialization code (with underlying integer type). |
| **[Arrays](advanced-topics/serialization/serialization-arrays.md)** | Netcode for GameObjects has built-in serialization code for arrays of [C# value-type primitives](advanced-topics/serialization/cprimitives.md), like `int[]`, and [Unity primitive types](advanced-topics/serialization/unity-primitives.md). Any arrays of types that aren't handled by the built-in serialization code, such as `string[]`, need to be handled using a container class or structure that implements the [`INetworkSerializable`](advanced-topics/serialization/inetworkserializable.md) interface. |
-| **[INetworkSerializable](advanced-topics/serialization/inetworkserializable.md)** | You can use the `INetworkSerializable` interface to define custom serializable types. |
+| **[Customize serializable types with INetworkSerializable](advanced-topics/serialization/inetworkserializable.md)** | You can use the `INetworkSerializable` interface to define custom serializable types. |
+| **[Serialize unmanaged structs with INetworkSerializeByMemcpy](advanced-topics/serialization/inetworkserializebymemcpy.md)** | You can use the `INetworkSerializeByMemcpy` interface to mark an unmanaged struct type as being trivially serializable. |
| **[Custom serialization](advanced-topics/custom-serialization.md)** | Create custom serialization types. |
| **[NetworkObject serialization](advanced-topics/serialization/networkobject-serialization.md)** | `GameObjects`, `NetworkObjects` and NetworkBehaviour aren't serializable types so they can't be used in `RPCs` or `NetworkVariables` by default. There are two convenience wrappers which can be used to send a reference to a NetworkObject or a NetworkBehaviour over RPCs or `NetworkVariables`. |
-| **[FastBufferWriter and FastBufferReader](advanced-topics/fastbufferwriter-fastbufferreader.md)** | 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. |
\ No newline at end of file
+| **[FastBufferWriter and FastBufferReader](advanced-topics/fastbufferwriter-fastbufferreader.md)** | 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. |
+| **[BufferSerializer](advanced-topics/bufferserializer.md)** | A bi-directional serializer primarily used for serializing within [`INetworkSerializable`](advanced-topics/serialization/inetworkserializable.md) types. |
diff --git a/com.unity.netcode.gameobjects/Documentation~/terms-concepts/distributed-authority.md b/com.unity.netcode.gameobjects/Documentation~/terms-concepts/distributed-authority.md
index 74f49a39c8..17c1f8b77b 100644
--- a/com.unity.netcode.gameobjects/Documentation~/terms-concepts/distributed-authority.md
+++ b/com.unity.netcode.gameobjects/Documentation~/terms-concepts/distributed-authority.md
@@ -53,7 +53,7 @@ You can use this property to conditionally execute logic that should only run on
### Session owner NetworkObjects
-For game systems that should always be [owned](./ownership.md) by the session owner, you can set the NetworkObject to have the `OwnershipStatus.SessionOwner` [ownership permission](../advanced-topics/networkobject-ownership.md). This ensures that the NetworkObject always belongs to the current session owner. If that session owner disconnects or leaves the game, the ownership of that NetworkObject will be automatically moved to the newly selected session owner.
+For game systems that should always be [owned](./ownership.md) by the session owner, you can set the NetworkObject to have the `OwnershipStatus.SessionOwner` [ownership permission](../components/core/networkobject-ownership.md). This ensures that the NetworkObject always belongs to the current session owner. If that session owner disconnects or leaves the game, the ownership of that NetworkObject will be automatically moved to the newly selected session owner.
## NetworkObject distribution
diff --git a/com.unity.netcode.gameobjects/Documentation~/terms-concepts/ownership.md b/com.unity.netcode.gameobjects/Documentation~/terms-concepts/ownership.md
index 3d47f69024..56ff42526e 100644
--- a/com.unity.netcode.gameobjects/Documentation~/terms-concepts/ownership.md
+++ b/com.unity.netcode.gameobjects/Documentation~/terms-concepts/ownership.md
@@ -35,7 +35,7 @@ In [distributed authority](./distributed-authority.md) the owner of a NetworkObj

-When building your game you can use [ownership permissions](../advanced-topics/networkobject-ownership.md#ownership-permission-settings) to control how and when ownership of NetworkObjects can be transferred between clients.
+When building your game you can use [ownership permissions](../components/core/networkobject-ownership.md#ownership-permission-settings) to control how and when ownership of NetworkObjects can be transferred between clients.
NetworkObjects with the `OwnershipStatus.Distributable` permission will have their ownership automatically distributed between all connected game clients whenever a new client joins or an existing client leaves. This is the key mechanism in how the game simulation is distributed between clients in a distributed authority session.
@@ -48,4 +48,4 @@ The `IsOwner` property, which is available on both NetworkObjects and NetworkBeh
* [Authority](authority.md)
* [Client-server](client-server.md)
* [Distributed authority](distributed-authority.md)
-* [NetworkObject ownership](../advanced-topics/networkobject-ownership.md)
+* [NetworkObject ownership](../components/core/networkobject-ownership.md)
diff --git a/com.unity.netcode.gameobjects/Documentation~/tutorials/get-started-with-ngo.md b/com.unity.netcode.gameobjects/Documentation~/tutorials/get-started-with-ngo.md
index 4a80b3fd1a..bbd635c497 100644
--- a/com.unity.netcode.gameobjects/Documentation~/tutorials/get-started-with-ngo.md
+++ b/com.unity.netcode.gameobjects/Documentation~/tutorials/get-started-with-ngo.md
@@ -33,7 +33,7 @@ This section guides you through adding the essential components of a networked g
- [A NetworkManager component](#create-the-networkmanager-component)
- [A player object](#create-an-object-to-spawn-for-each-connected-player)
-- [A scene](#add-your-scene-to-the-build)
+- [A scene](#scene-management-and-the-scenes-in-build-list)
### Create the NetworkManager component
@@ -68,7 +68,7 @@ First, create the NetworkManager component:
### Create an object to spawn for each connected player
> [!NOTE]
-> When you drop the prefab into the **PlayerPrefab** slot, you're telling the library that when a client connects to the game, it automatically spawns this prefab as the character for the connecting client. Netcode for GameObjects won't spawn a player object if you don't have any prefab set as the **PlayerPrefab**. Refer to [Player Objects](../components/core/networkobject.md#finding-playerobjects).
+> When you drop the prefab into the **PlayerPrefab** slot, you're telling the library that when a client connects to the game, it automatically spawns this prefab as the character for the connecting client. Netcode for GameObjects won't spawn a player object if you don't have any prefab set as the **PlayerPrefab**. Refer to [Player Objects](../components/core/playerobjects.md#finding-playerobjects).
This section guides you through creating an object that spawns for each connected player.
@@ -111,7 +111,7 @@ Netcode for GameObjects comes with an integrated scene management solution that
Now that you have a **NetworkManager**, assigned a **PlayerPrefab**, and added your current scene to the scenes in build test, you can quickly verify everything is functioning/configured correctly via entering play mode in the Unity Editor. By starting a host, you are starting NetworkManager as both a server and a client at the same time.
-You can test your Hello World project using the Unity Editor or a command-line helper. If you choose the latter, refer to [Create a command line helper](../tutorials/command-line-helper/). Otherwise, refer to the following instructions to test using the Unity Editor. Only the Plane appears on the server until the first client connects. Then, Netcode for GameObjects spawns a new Player prefab for each connected client; however, they overlap in the Game view.
+You can test your Hello World project using the Unity Editor or a command-line helper. If you choose the latter, refer to [Create a command line helper](command-line-helper.md). Otherwise, refer to the following instructions to test using the Unity Editor. Only the Plane appears on the server until the first client connects. Then, Netcode for GameObjects spawns a new Player prefab for each connected client; however, they overlap in the Game view.
1. Select **Play** from the top of the Unity Editor to start the scene.
@@ -119,7 +119,7 @@ You can test your Hello World project using the Unity Editor or a command-line h
2. Select **NetworkManager** from the **Hierarchy** list.
-
+
3. With **NetworkManager** selected (in the Hierarchy tab), select **Start Host** from the **Inspector** tab. Alternatively, you can use the in-game GUI buttons.
@@ -239,7 +239,7 @@ The `HelloWorldManager.cs` script accomplishes this menu within the `StartButton
As seen in the earlier code snippet, the `HelloWorldManager.cs` script also uses the NetworkManager's instance via its singleton to grab properties like the `IsClient`, `IsServer`, and `IsLocalClient`. The `IsClient` and `IsServer` properties dictate the established connection state.
-The `HelloWorldManager.cs` script also introduces a new method called `SubmitNewPosition()` that the `HelloWorldPlayer` script uses to [create a simple RPC call](#add-simple-rpc-use).
+The `HelloWorldManager.cs` script also introduces a new method called `SubmitNewPosition()` that the `HelloWorldPlayer` script uses to [create a simple RPC call](#adding-rpcs-remote-procedure-calls).
## Adding RPCs (Remote Procedure Calls)
diff --git a/com.unity.netcode.gameobjects/Documentation~/tutorials/testing/techniques_and_tricks_for_debugging_multiplayer_games.md b/com.unity.netcode.gameobjects/Documentation~/tutorials/testing/techniques_and_tricks_for_debugging_multiplayer_games.md
index aadbec86b8..6f5bbcd88d 100644
--- a/com.unity.netcode.gameobjects/Documentation~/tutorials/testing/techniques_and_tricks_for_debugging_multiplayer_games.md
+++ b/com.unity.netcode.gameobjects/Documentation~/tutorials/testing/techniques_and_tricks_for_debugging_multiplayer_games.md
@@ -10,7 +10,7 @@ Below is a list of practices and techniques that we use daily when working on th
### Use ParrelSync clone-based workflow during development.
-[ParrelSync workflow](testing_locally.md#parrelsync) is faster than creating builds and it allows you to debug the separate editor instances via separate IDE debuggers.
+[ParrelSync workflow](testing_with_artificial_conditions.md#clone-based-workflow-parrelsync) is faster than creating builds and it allows you to debug the separate editor instances via separate IDE debuggers.
Use ParrelSync to run separate editor instances for your Host/Server and Client.
@@ -22,7 +22,7 @@ Unity engine has two debug rendering APIs that are useful for the purposes of mu
Both of these functions allow us to draw arbitrary debug lines that would be visible in the Scene view and in the Game view, provided Gizmo rendering is enabled (to enable Gizmo rendering in Game view you need to click on the `Gizmos` menu at the top of the Game view).
-The key trick here is to use different colors for different kinds of information and to make the lines stay long enough for visual inspection by setting `duration` parameter. This technique shines when it's combined with [screen recordings](#7-recording-the-video-of-gameplay) of [multiple peers running side by side in separate editor instances via ParrelSync](#1-use-parrelsync-workflow-during-development).
+The key trick here is to use different colors for different kinds of information and to make the lines stay long enough for visual inspection by setting `duration` parameter. This technique shines when it's combined with [screen recordings](#capturing-screen-recordings-of-the-game-instances) of [multiple peers running side by side in separate editor instances via ParrelSync](#use-parrelsync-clone-based-workflow-during-development).
The code below would render a green debug line that's 2 units tall at the position of the transform, and this line would stay on screen for 4 seconds:
`Debug.DrawLine(this.transform.position, this.transform.position + Vector3.UP * 2f, Color.green, duration: 4f);`
diff --git a/com.unity.netcode.gameobjects/Documentation~/tutorials/testing/testing_with_artificial_conditions.md b/com.unity.netcode.gameobjects/Documentation~/tutorials/testing/testing_with_artificial_conditions.md
index f3c0646638..634f84288a 100644
--- a/com.unity.netcode.gameobjects/Documentation~/tutorials/testing/testing_with_artificial_conditions.md
+++ b/com.unity.netcode.gameobjects/Documentation~/tutorials/testing/testing_with_artificial_conditions.md
@@ -11,11 +11,11 @@ This is challenging when we are [iterating on our game locally](testing_locally.
Thankfully there are a number of tools that can simulate adverse network conditions.
-For testing locally within the Editor, you can use the [Network Simulator tool](https://docs-multiplayer.unity3d.com/tools/current/tools-network-simulator/) along with [clone-based workflow via ParrelSync](testing_locally.md#parrelsync).
+For testing locally within the Editor, you can use the [Network Simulator tool](https://docs-multiplayer.unity3d.com/tools/current/tools-network-simulator/) along with [clone-based workflow via ParrelSync](#clone-based-workflow-parrelsync).
For testing development builds with built-in artificial latency we suggest using [Network Simulator tools with some custom code to inject artificial conditions into the build](#debug-builds).
-For testing release builds we suggest using [Clumsy](#clumsy-windows) if you're on Windows and Network Link Conditioner if you're on [macOS](#network-link-conditioner-mac-os) or [iOS](#network-link-conditioner-ios). A scriptable alternative to Network Link Conditioner on macOS is [dummynet](#dummynet-dnctl-and-pftcl-mac-os), which offers great control and comes packaged with the operating system.
+For testing release builds we suggest using [Clumsy](#clumsy-windows) if you're on Windows and Network Link Conditioner if you're on [macOS](#network-link-conditioner-macos) or [iOS](#network-link-conditioner-ios). A scriptable alternative to Network Link Conditioner on macOS is [dummynet](#dummynet-dnctl-and-pftcl-macos), which offers great control and comes packaged with the operating system.
> [!NOTE]
> While artificial latency is great for simulating network conditions during development - it won't accurately emulate real world conditions. We recommend to test your game often on the targeted platforms and real live networking conditions.
@@ -49,7 +49,7 @@ Adding packet loss, apart from introducing even more effective delay to our syst
### Different network conditions for different peers
-[Clumsy](#clumsy-on-windows), [Network Link Conditioner](#network-link-conditioner-mac-os) and [dummynet](#dummynet-dnctl-and-pftcl-mac-os) are introducing changes on OS level, thus all the instances of the game that we open on our local machine would run under the same network conditions.
+[Clumsy](#clumsy-windows), [Network Link Conditioner](#network-link-conditioner-macos) and [dummynet](#dummynet-dnctl-and-pftcl-macos) are introducing changes on OS level, thus all the instances of the game that we open on our local machine would run under the same network conditions.
Don't forget to disable it once you're done debugging, else your network connection will feel slow!
@@ -65,7 +65,7 @@ In this case we would want to have an ability to set artificial conditions on a
> ParallelSync is **not** supported by Unity. More information on its usage is available [here](https://github.com/VeriorPies/ParrelSync). Troubleshooting information can be found [here](https://github.com/VeriorPies/ParrelSync/wiki/Troubleshooting-&-FAQs)
-Simulator Tools effects only apply to editor instances and to [debug builds](#debug-builds), as such it matches well with [clone-based workflow via ParrelSync](testing_locally.md#parrelsync).
+Simulator Tools effects only apply to editor instances and to [debug builds](#debug-builds), as such it matches well with [clone-based workflow via ParrelSync](#clone-based-workflow-parrelsync).
Other tools should be used when testing release builds locally.
diff --git a/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs b/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs
index 04a72d7c9e..3794b976b0 100644
--- a/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs
+++ b/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs
@@ -2150,9 +2150,10 @@ private bool GetReadMethodForParameter(TypeReference paramType, out MethodRefere
{
typeMethod = GetFastBufferReaderReadMethod(k_ReadValueInPlaceMethodName, paramType);
}
- else
-#endif
+ else if (paramType.Resolve().FullName == "Unity.Collections.NativeArray`1")
+#else
if (paramType.Resolve().FullName == "Unity.Collections.NativeArray`1")
+#endif
{
typeMethod = GetFastBufferReaderReadMethod(k_ReadValueTempMethodName, paramType);
}
diff --git a/com.unity.netcode.gameobjects/Editor/CodeGen/RuntimeAccessModifiersILPP.cs b/com.unity.netcode.gameobjects/Editor/CodeGen/RuntimeAccessModifiersILPP.cs
index 57295be52e..18c73ed737 100644
--- a/com.unity.netcode.gameobjects/Editor/CodeGen/RuntimeAccessModifiersILPP.cs
+++ b/com.unity.netcode.gameobjects/Editor/CodeGen/RuntimeAccessModifiersILPP.cs
@@ -97,17 +97,23 @@ private void ProcessNetworkManager(TypeDefinition typeDefinition, string[] assem
{
foreach (var fieldDefinition in typeDefinition.Fields)
{
+#pragma warning disable CS0618 // Type or member is obsolete
if (fieldDefinition.Name == nameof(NetworkManager.__rpc_func_table))
+#pragma warning restore CS0618 // Type or member is obsolete
{
fieldDefinition.IsPublic = true;
}
+#pragma warning disable CS0618 // Type or member is obsolete
if (fieldDefinition.Name == nameof(NetworkManager.RpcReceiveHandler))
+#pragma warning restore CS0618 // Type or member is obsolete
{
fieldDefinition.IsPublic = true;
}
+#pragma warning disable CS0618 // Type or member is obsolete
if (fieldDefinition.Name == nameof(NetworkManager.__rpc_name_table))
+#pragma warning restore CS0618 // Type or member is obsolete
{
fieldDefinition.IsPublic = true;
}
@@ -115,7 +121,9 @@ private void ProcessNetworkManager(TypeDefinition typeDefinition, string[] assem
foreach (var nestedTypeDefinition in typeDefinition.NestedTypes)
{
+#pragma warning disable CS0618 // Type or member is obsolete
if (nestedTypeDefinition.Name == nameof(NetworkManager.RpcReceiveHandler))
+#pragma warning restore CS0618 // Type or member is obsolete
{
nestedTypeDefinition.IsNestedPublic = true;
}
@@ -151,7 +159,7 @@ private void ProcessNetworkBehaviour(TypeDefinition typeDefinition)
{
fieldDefinition.IsFamilyOrAssembly = true;
}
-#if MULTIPLAYER_TOOLS && (DEVELOPMENT_BUILD || UNITY_EDITOR || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE)
+#if MULTIPLAYER_TOOLS && (DEBUG || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE)
if (fieldDefinition.Name == nameof(NetworkBehaviour.__rpc_name_table))
{
fieldDefinition.IsFamilyOrAssembly = true;
diff --git a/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs b/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs
new file mode 100644
index 0000000000..8f66c3aa4f
--- /dev/null
+++ b/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs
@@ -0,0 +1,74 @@
+using Unity.Netcode.Logging;
+using UnityEditor;
+using UnityEditor.Build;
+using UnityEditor.Build.Reporting;
+using UnityEngine;
+using UnityEngine.SceneManagement;
+
+namespace Unity.Netcode.Editor
+{
+ ///
+ /// A that sets the property to true for all s in the scene.
+ /// Ensures that InScenePlaced is always true for all objects in the scene.
+ ///
+ ///
+ /// This will always run as the game enters the scene,
+ ///
+ internal class SetInScenePlaced : IProcessSceneWithReport
+ {
+ public int callbackOrder => 0;
+ public void OnProcessScene(Scene scene, BuildReport report)
+ {
+ var log = new ContextualLogger();
+ log.AddInfo(scene.name, scene.handle);
+ foreach (var networkObject in FindObjects.FromSceneByType(scene, true))
+ {
+ // Trap for users just creating things during runtime where this will be zero.
+ if (networkObject.GlobalObjectIdHash == 0)
+ {
+ log.Warning(new Context(LogLevel.Developer, $"{nameof(NetworkObject)}'s GlobalObjectIdHash value is zero! Runtime creating of {nameof(NetworkObject)}s is not supported. Skipping processing.").AddNetworkObject(networkObject));
+ continue;
+ }
+ if (networkObject.SceneOrigin.IsValid() && networkObject.SceneOrigin.handle != scene.handle)
+ {
+ log.Warning(new Context(LogLevel.Developer, $"{nameof(NetworkObject)}'s SceneOrigin doesn't match current scene being processed! Skipping processing.").AddInfo("SceneOrigin", networkObject.SceneOriginHandle).AddNetworkObject(networkObject));
+ continue;
+ }
+
+ if (networkObject.HasBeenSpawned)
+ {
+ log.Error(new Context(LogLevel.Normal, $"Processing {nameof(NetworkObject)} that has already been spawned! This should not be possible. Skipping processing.").AddNetworkObject(networkObject));
+ continue;
+ }
+
+ // If already marked, the do nothing.
+ if (networkObject.InScenePlaced)
+ {
+ continue;
+ }
+
+ networkObject.InScenePlaced = true;
+ // Will not be true when making a build and the values are serialized.
+ networkObject.InScenePlacedPostProcessorMarkedDuringRuntime = Application.isPlaying;
+ }
+ }
+ }
+
+ ///
+ /// An that sets the property to false for all s in prefabs.
+ /// Ensures that InScenePlaced is always false for all prefab objects.
+ /// This is important because when a prefab is instantiated in the scene, it should be treated as a dynamically spawned object.
+ ///
+ internal class InScenePlacedPrefabBuilder : AssetPostprocessor
+ {
+ public void OnPostprocessPrefab(GameObject root)
+ {
+ var networkObjects = root.GetComponentsInChildren(true);
+ foreach (var networkObject in networkObjects)
+ {
+ networkObject.InScenePlaced = false;
+ }
+ }
+ }
+}
diff --git a/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs.meta b/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs.meta
new file mode 100644
index 0000000000..784aa38575
--- /dev/null
+++ b/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: cda0fb70bdcd545a7983ca78f516bcff
\ No newline at end of file
diff --git a/com.unity.netcode.gameobjects/Editor/NetworkBehaviourEditor.cs b/com.unity.netcode.gameobjects/Editor/NetworkBehaviourEditor.cs
index 1312ff69e6..c2ce7da626 100644
--- a/com.unity.netcode.gameobjects/Editor/NetworkBehaviourEditor.cs
+++ b/com.unity.netcode.gameobjects/Editor/NetworkBehaviourEditor.cs
@@ -322,18 +322,13 @@ private void OnEnable()
}
///
- /// Recursively finds the root parent of a
+ /// Obsolete method to find root parent of a .
+ /// Use instead.
///
/// The current we are inspecting for a parent
/// the root parent for the first passed into the method
- public static Transform GetRootParentTransform(Transform transform)
- {
- if (transform.parent == null || transform.parent == transform)
- {
- return transform;
- }
- return GetRootParentTransform(transform.parent);
- }
+ [Obsolete("Use transform.root instead")]
+ public static Transform GetRootParentTransform(Transform transform) => transform.root;
///
/// Used to determine if a GameObject has one or more NetworkBehaviours but
@@ -358,7 +353,7 @@ public static void CheckForNetworkObject(GameObject gameObject, bool networkObje
}
// Now get the root parent transform to the current GameObject (or itself)
- var rootTransform = GetRootParentTransform(gameObject.transform);
+ var rootTransform = gameObject.transform.root;
if (!rootTransform.TryGetComponent(out var networkManager))
{
networkManager = rootTransform.GetComponentInChildren();
diff --git a/com.unity.netcode.gameobjects/Editor/NetworkManagerHelper.cs b/com.unity.netcode.gameobjects/Editor/NetworkManagerHelper.cs
index 5c7e554baf..66ddb2b6f0 100644
--- a/com.unity.netcode.gameobjects/Editor/NetworkManagerHelper.cs
+++ b/com.unity.netcode.gameobjects/Editor/NetworkManagerHelper.cs
@@ -195,9 +195,9 @@ public bool NotifyUserOfNestedNetworkManager(NetworkManager networkManager, bool
{
return isParented;
}
- else // If we are no longer a child, then we can remove ourself from this list
- if (transform.root == gameObject.transform)
+ else if (transform.root == gameObject.transform)
{
+ // If we are no longer a child, then we can remove ourself from this list
s_LastKnownNetworkManagerParents.Remove(networkManager);
}
}
diff --git a/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs b/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs
index 04e0d1f698..0335896784 100644
--- a/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs
+++ b/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs
@@ -67,14 +67,10 @@ public override void OnInspectorGUI()
EditorGUILayout.Toggle(nameof(NetworkObject.IsOwner), m_NetworkObject.IsOwner);
EditorGUILayout.Toggle(nameof(NetworkObject.IsOwnedByServer), m_NetworkObject.IsOwnedByServer);
EditorGUILayout.Toggle(nameof(NetworkObject.IsPlayerObject), m_NetworkObject.IsPlayerObject);
- if (m_NetworkObject.IsSceneObject.HasValue)
- {
- EditorGUILayout.Toggle(nameof(NetworkObject.IsSceneObject), m_NetworkObject.IsSceneObject.Value);
- }
- else
- {
- EditorGUILayout.TextField(nameof(NetworkObject.IsSceneObject), "null");
- }
+#pragma warning disable CS0618 // Type or member is obsolete
+ // TODO-3.x: Update name in 3.x branch
+ EditorGUILayout.Toggle(nameof(NetworkObject.IsSceneObject), m_NetworkObject.InScenePlaced);
+#pragma warning restore CS0618 // Type or member is obsolete
EditorGUILayout.Toggle(nameof(NetworkObject.DestroyWithScene), m_NetworkObject.DestroyWithScene);
EditorGUILayout.TextField(nameof(NetworkObject.NetworkManager), m_NetworkObject.NetworkManager == null ? "null" : m_NetworkObject.NetworkManager.gameObject.name);
GUI.enabled = guiEnabled;
diff --git a/com.unity.netcode.gameobjects/Runtime/Components/AnticipatedNetworkTransform.cs b/com.unity.netcode.gameobjects/Runtime/Components/AnticipatedNetworkTransform.cs
index ce277533c7..00bd431cbb 100644
--- a/com.unity.netcode.gameobjects/Runtime/Components/AnticipatedNetworkTransform.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Components/AnticipatedNetworkTransform.cs
@@ -161,8 +161,18 @@ public void AnticipateMove(Vector3 newPosition)
{
return;
}
- transform.position = newPosition;
+
+ if (InLocalSpace)
+ {
+ transform.localPosition = newPosition;
+ }
+ else
+ {
+ transform.position = newPosition;
+ }
+
m_AnticipatedTransform.Position = newPosition;
+
if (CanCommitToTransform)
{
m_AuthoritativeTransform.Position = newPosition;
@@ -187,7 +197,15 @@ public void AnticipateRotate(Quaternion newRotation)
{
return;
}
- transform.rotation = newRotation;
+
+ if (InLocalSpace)
+ {
+ transform.localRotation = newRotation;
+ }
+ else
+ {
+ transform.rotation = newRotation;
+ }
m_AnticipatedTransform.Rotation = newRotation;
if (CanCommitToTransform)
{
@@ -240,7 +258,14 @@ public void AnticipateState(TransformState newState)
return;
}
var transform_ = transform;
- transform_.SetPositionAndRotation(newState.Position, newState.Rotation);
+ if (InLocalSpace)
+ {
+ transform_.SetLocalPositionAndRotation(newState.Position, newState.Rotation);
+ }
+ else
+ {
+ transform_.SetPositionAndRotation(newState.Position, newState.Rotation);
+ }
transform_.localScale = newState.Scale;
m_AnticipatedTransform = newState;
if (CanCommitToTransform)
@@ -277,7 +302,17 @@ private void ProcessSmoothing()
m_PreviousAnticipatedTransform = m_AnticipatedTransform;
if (!CanCommitToTransform)
{
- transform_.SetPositionAndRotation(m_AnticipatedTransform.Position, m_AnticipatedTransform.Rotation);
+ if (InLocalSpace)
+ {
+ transform_.SetLocalPositionAndRotation(m_AnticipatedTransform.Position,
+ m_AnticipatedTransform.Rotation);
+ }
+ else
+ {
+ transform_.SetPositionAndRotation(m_AnticipatedTransform.Position,
+ m_AnticipatedTransform.Rotation);
+ }
+
transform_.localScale = m_AnticipatedTransform.Scale;
}
}
@@ -320,12 +355,25 @@ public void SetupForRender()
if (Transform.CanCommitToTransform)
{
var transform_ = Transform.transform;
- Transform.m_AuthoritativeTransform = new TransformState
+ if (Transform.InLocalSpace)
{
- Position = transform_.position,
- Rotation = transform_.rotation,
- Scale = transform_.localScale
- };
+ Transform.m_AuthoritativeTransform = new TransformState
+ {
+ Position = transform_.localPosition,
+ Rotation = transform_.localRotation,
+ Scale = transform_.localScale
+ };
+ }
+ else
+ {
+ Transform.m_AuthoritativeTransform = new TransformState
+ {
+ Position = transform_.position,
+ Rotation = transform_.rotation,
+ Scale = transform_.localScale
+ };
+ }
+
if (Transform.m_CurrentSmoothTime >= Transform.m_SmoothDuration)
{
// If we've had a call to Smooth() we'll continue interpolating.
@@ -334,7 +382,17 @@ public void SetupForRender()
Transform.m_AnticipatedTransform = Transform.m_AuthoritativeTransform;
}
- transform_.SetPositionAndRotation(Transform.m_AnticipatedTransform.Position, Transform.m_AnticipatedTransform.Rotation);
+ if (Transform.InLocalSpace)
+ {
+ transform_.SetLocalPositionAndRotation(Transform.m_AnticipatedTransform.Position,
+ Transform.m_AnticipatedTransform.Rotation);
+ }
+ else
+ {
+ transform_.SetPositionAndRotation(Transform.m_AnticipatedTransform.Position,
+ Transform.m_AnticipatedTransform.Rotation);
+ }
+
transform_.localScale = Transform.m_AnticipatedTransform.Scale;
}
}
@@ -344,7 +402,17 @@ public void SetupForUpdate()
if (Transform.CanCommitToTransform)
{
var transform_ = Transform.transform;
- transform_.SetPositionAndRotation(Transform.m_AuthoritativeTransform.Position, Transform.m_AuthoritativeTransform.Rotation);
+ if (Transform.InLocalSpace)
+ {
+ transform_.SetLocalPositionAndRotation(Transform.m_AuthoritativeTransform.Position,
+ Transform.m_AuthoritativeTransform.Rotation);
+ }
+ else
+ {
+ transform_.SetPositionAndRotation(Transform.m_AuthoritativeTransform.Position,
+ Transform.m_AuthoritativeTransform.Rotation);
+ }
+
transform_.localScale = Transform.m_AuthoritativeTransform.Scale;
}
}
@@ -367,12 +435,25 @@ public void ResetAnticipation()
private void ResetAnticipatedState()
{
var transform_ = transform;
- m_AuthoritativeTransform = new TransformState
+ if (InLocalSpace)
+ {
+ m_AuthoritativeTransform = new TransformState
+ {
+ Position = transform_.localPosition,
+ Rotation = transform_.localRotation,
+ Scale = transform_.localScale
+ };
+ }
+ else
{
- Position = transform_.position,
- Rotation = transform_.rotation,
- Scale = transform_.localScale
- };
+ m_AuthoritativeTransform = new TransformState
+ {
+ Position = transform_.position,
+ Rotation = transform_.rotation,
+ Scale = transform_.localScale
+ };
+ }
+
m_AnticipatedTransform = m_AuthoritativeTransform;
m_PreviousAnticipatedTransform = m_AnticipatedTransform;
@@ -439,7 +520,7 @@ public override void OnNetworkSpawn()
return;
}
m_OutstandingAuthorityChange = true;
- ApplyAuthoritativeState();
+ //ApplyAuthoritativeState();
ResetAnticipatedState();
m_AnticipatedObject = new AnticipatedObject { Transform = this };
@@ -491,7 +572,15 @@ public void Smooth(TransformState from, TransformState to, float durationSeconds
{
m_AnticipatedTransform = to;
m_PreviousAnticipatedTransform = m_AnticipatedTransform;
- transform_.SetPositionAndRotation(to.Position, to.Rotation);
+ if (InLocalSpace)
+ {
+ transform_.SetLocalPositionAndRotation(to.Position, to.Rotation);
+ }
+ else
+ {
+ transform_.SetPositionAndRotation(to.Position, to.Rotation);
+ }
+
transform_.localScale = to.Scale;
m_SmoothDuration = 0;
m_CurrentSmoothTime = 0;
@@ -502,7 +591,15 @@ public void Smooth(TransformState from, TransformState to, float durationSeconds
if (!CanCommitToTransform)
{
- transform_.SetPositionAndRotation(from.Position, from.Rotation);
+ if (InLocalSpace)
+ {
+ transform_.SetLocalPositionAndRotation(from.Position, from.Rotation);
+ }
+ else
+ {
+ transform_.SetPositionAndRotation(from.Position, from.Rotation);
+ }
+
transform_.localScale = from.Scale;
}
@@ -543,14 +640,30 @@ protected override void OnTransformUpdated()
var previousAnticipatedTransform = m_AnticipatedTransform;
// Update authority state to catch any possible interpolation data
- m_AuthoritativeTransform.Position = transform_.position;
- m_AuthoritativeTransform.Rotation = transform_.rotation;
- m_AuthoritativeTransform.Scale = transform_.localScale;
+ if (InLocalSpace)
+ {
+ m_AuthoritativeTransform.Position = transform_.localPosition;
+ m_AuthoritativeTransform.Rotation = transform_.localRotation;
+ m_AuthoritativeTransform.Scale = transform_.localScale;
+ }
+ else
+ {
+ m_AuthoritativeTransform.Position = transform_.position;
+ m_AuthoritativeTransform.Rotation = transform_.rotation;
+ m_AuthoritativeTransform.Scale = transform_.localScale;
+ }
if (!m_OutstandingAuthorityChange)
{
// Keep the anticipated value unchanged, we have no updates from the server at all.
- transform_.SetPositionAndRotation(previousAnticipatedTransform.Position, previousAnticipatedTransform.Rotation);
+ if (InLocalSpace)
+ {
+ transform_.SetLocalPositionAndRotation(previousAnticipatedTransform.Position, previousAnticipatedTransform.Rotation);
+ }
+ else
+ {
+ transform_.SetPositionAndRotation(previousAnticipatedTransform.Position, previousAnticipatedTransform.Rotation);
+ }
transform_.localScale = previousAnticipatedTransform.Scale;
return;
}
@@ -558,7 +671,17 @@ protected override void OnTransformUpdated()
if (StaleDataHandling == StaleDataHandling.Ignore && m_LastAnticipaionCounter > m_LastAuthorityUpdateCounter)
{
// Keep the anticipated value unchanged because it is more recent than the authoritative one.
- transform_.SetPositionAndRotation(previousAnticipatedTransform.Position, previousAnticipatedTransform.Rotation);
+ if (InLocalSpace)
+ {
+ transform_.SetLocalPositionAndRotation(previousAnticipatedTransform.Position,
+ previousAnticipatedTransform.Rotation);
+ }
+ else
+ {
+ transform_.SetPositionAndRotation(previousAnticipatedTransform.Position,
+ previousAnticipatedTransform.Rotation);
+ }
+
transform_.localScale = previousAnticipatedTransform.Scale;
return;
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Components/Interpolator/BufferedLinearInterpolator.cs b/com.unity.netcode.gameobjects/Runtime/Components/Interpolator/BufferedLinearInterpolator.cs
index 24eb580402..4cee25748e 100644
--- a/com.unity.netcode.gameobjects/Runtime/Components/Interpolator/BufferedLinearInterpolator.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Components/Interpolator/BufferedLinearInterpolator.cs
@@ -209,12 +209,23 @@ public void Reset(T currentValue)
internal bool LerpSmoothEnabled;
///
- /// Determines how much smoothing will be applied to the 2nd lerp when using the (i.e. lerping and not smooth dampening).
+ /// The frame rate that is relative to when lerp smoothing.
+ ///
+ private const float k_LerpSmoothReferenceFrameRate = 60.0f;
+
+ ///
+ /// Keeps a of 1.0f from retaining the entire delta each frame,
+ /// which would stop the value from ever advancing towards the target.
+ ///
+ private const float k_MaximumLerpSmoothRetention = 0.99f;
+
+ ///
+ /// Determines how much smoothing will be applied to the 2nd lerp.
///
///
- /// There's two factors affecting interpolation:
- /// - Buffering: Which can be adjusted in set in the .
- /// - Interpolation time: The divisor applied to delta time where the quotient is used as the lerp time.
+ /// Higher values are smoother, lower values are more precise. The amount of smoothing applied is
+ /// frame rate independent.
+ /// Buffering also affects interpolation and can be adjusted via .
///
[Range(0.016f, 1.0f)]
public float MaximumInterpolationTime = 0.1f;
@@ -420,6 +431,26 @@ internal void ResetCurrentState()
}
}
+ ///
+ /// Calculates the frame rate independent lerp smoothing "t" for the current frame.
+ ///
+ ///
+ /// Raising the retained portion to the number of reference frames elapsed makes the smoothing rate
+ /// a function of elapsed time rather than of how often this is called.
+ ///
+ /// The last frame time.
+ /// The lerp smoothing time to apply for this frame.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private float GetLerpSmoothTime(float deltaTime)
+ {
+ var retained = Mathf.Clamp01(MaximumInterpolationTime);
+ if (retained >= 1.0f)
+ {
+ retained = k_MaximumLerpSmoothRetention;
+ }
+ return 1.0f - Mathf.Pow(retained, deltaTime * k_LerpSmoothReferenceFrameRate);
+ }
+
///
/// Interpolation Update to use when smooth dampening is enabled on a .
///
@@ -459,7 +490,7 @@ internal T Update(float deltaTime, double tickLatencyAsTime, double minDeltaTime
if (LerpSmoothEnabled)
{
// Apply the smooth lerp to the target to help smooth the final value.
- InterpolateState.CurrentValue = Interpolate(InterpolateState.CurrentValue, InterpolateState.NextValue, Mathf.Clamp(1.0f - MaximumInterpolationTime, 0.0f, 1.0f));
+ InterpolateState.CurrentValue = Interpolate(InterpolateState.CurrentValue, InterpolateState.NextValue, GetLerpSmoothTime(deltaTime));
}
else
{
@@ -467,8 +498,8 @@ internal T Update(float deltaTime, double tickLatencyAsTime, double minDeltaTime
InterpolateState.CurrentValue = InterpolateState.NextValue;
}
}
- else // If the target is reached and we have no more state updates, we want to check to see if we need to reset.
- if (m_BufferQueue.Count == 0)
+ // If the target is reached and we have no more state updates, we want to check to see if we need to reset.
+ else if (m_BufferQueue.Count == 0)
{
// When the delta between the time sent and the current tick latency time-window is greater than the max delta time
// plus the minimum delta time (a rough estimate of time to wait before we consider rate of change equal to zero),
@@ -593,8 +624,8 @@ public T Update(float deltaTime, double renderTime, double serverTime)
// Determine if we have reached our target
InterpolateState.TargetReached = IsApproximately(InterpolateState.CurrentValue, InterpolateState.Target.Value.Item, GetPrecision());
}
- else // If the target is reached and we have no more state updates, we want to check to see if we need to reset.
- if (InterpolateState.TargetReached && m_BufferQueue.Count == 0)
+ // If the target is reached and we have no more state updates, we want to check to see if we need to reset.
+ else if (InterpolateState.TargetReached && m_BufferQueue.Count == 0)
{
// When the delta between the time sent and the current tick latency time-window is greater than the max delta time
// plus the minimum delta time (a rough estimate of time to wait before we consider rate of change equal to zero),
diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs
index 7d82872890..bf275ab3c3 100644
--- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs
@@ -14,8 +14,8 @@ namespace Unity.Netcode.Components
{
internal class NetworkAnimatorStateChangeHandler : INetworkUpdateSystem
{
- private NetworkAnimator m_NetworkAnimator;
- private bool m_IsServer;
+ private readonly NetworkAnimator m_NetworkAnimator;
+ private readonly bool m_IsServer;
///
/// This removes sending RPCs from within RPCs when the
@@ -132,14 +132,14 @@ private struct AnimationUpdate
public NetworkAnimator.AnimationMessage AnimationMessage;
}
- private List m_SendAnimationUpdates = new List();
+ private readonly List m_SendAnimationUpdates = new List();
///
/// Invoked when a server needs to forwarding an update to the animation state
///
internal void SendAnimationUpdate(NetworkAnimator.AnimationMessage animationMessage, RpcParams rpcParams = default)
{
- m_SendAnimationUpdates.Add(new AnimationUpdate() { RpcParams = rpcParams, AnimationMessage = animationMessage });
+ m_SendAnimationUpdates.Add(new AnimationUpdate { RpcParams = rpcParams, AnimationMessage = animationMessage });
}
private struct ParameterUpdate
@@ -148,17 +148,17 @@ private struct ParameterUpdate
public NetworkAnimator.ParametersUpdateMessage ParametersUpdateMessage;
}
- private List m_SendParameterUpdates = new List();
+ private readonly List m_SendParameterUpdates = new List();
///
/// Invoked when a server needs to forwarding an update to the parameter state
///
internal void SendParameterUpdate(NetworkAnimator.ParametersUpdateMessage parametersUpdateMessage, RpcParams rpcParams = default)
{
- m_SendParameterUpdates.Add(new ParameterUpdate() { RpcParams = rpcParams, ParametersUpdateMessage = parametersUpdateMessage });
+ m_SendParameterUpdates.Add(new ParameterUpdate { RpcParams = rpcParams, ParametersUpdateMessage = parametersUpdateMessage });
}
- private List m_ProcessParameterUpdates = new List();
+ private readonly List m_ProcessParameterUpdates = new List();
internal void ProcessParameterUpdate(NetworkAnimator.ParametersUpdateMessage parametersUpdateMessage)
{
m_ProcessParameterUpdates.Add(parametersUpdateMessage);
@@ -171,31 +171,31 @@ private struct TriggerUpdate
public NetworkAnimator.AnimationTriggerMessage AnimationTriggerMessage;
}
- private List m_SendTriggerUpdates = new List();
+ private readonly List m_SendTriggerUpdates = new List();
///
/// Invoked when a server needs to forward an update to a Trigger state
///
internal void QueueTriggerUpdateToClient(NetworkAnimator.AnimationTriggerMessage animationTriggerMessage, RpcParams clientRpcParams = default)
{
- m_SendTriggerUpdates.Add(new TriggerUpdate() { RpcParams = clientRpcParams, AnimationTriggerMessage = animationTriggerMessage });
+ m_SendTriggerUpdates.Add(new TriggerUpdate { RpcParams = clientRpcParams, AnimationTriggerMessage = animationTriggerMessage });
}
internal void QueueTriggerUpdateToServer(NetworkAnimator.AnimationTriggerMessage animationTriggerMessage)
{
- m_SendTriggerUpdates.Add(new TriggerUpdate() { AnimationTriggerMessage = animationTriggerMessage, SendToServer = true });
+ m_SendTriggerUpdates.Add(new TriggerUpdate { AnimationTriggerMessage = animationTriggerMessage, SendToServer = true });
}
internal void DeregisterUpdate()
{
- NetworkUpdateLoop.UnregisterNetworkUpdate(this, NetworkUpdateStage.PreUpdate);
+ this.UnregisterNetworkUpdate(NetworkUpdateStage.PreUpdate);
}
internal NetworkAnimatorStateChangeHandler(NetworkAnimator networkAnimator)
{
m_NetworkAnimator = networkAnimator;
m_IsServer = networkAnimator.LocalNetworkManager.IsServer;
- NetworkUpdateLoop.RegisterNetworkUpdate(this, NetworkUpdateStage.PreUpdate);
+ this.RegisterNetworkUpdate(NetworkUpdateStage.PreUpdate);
}
}
@@ -213,7 +213,7 @@ public class NetworkAnimator : NetworkBehaviour, ISerializationCallbackReceiver
#endif
[Serializable]
- internal class TransitionStateinfo
+ internal class TransitionStateInfo
{
public bool IsCrossFadeExit;
public int Layer;
@@ -260,11 +260,8 @@ public enum AuthorityModes
///
public Animator Animator
{
- get { return m_Animator; }
- set
- {
- m_Animator = value;
- }
+ get => m_Animator;
+ set => m_Animator = value;
}
///
@@ -272,11 +269,11 @@ public Animator Animator
///
[HideInInspector]
[SerializeField]
- internal List TransitionStateInfoList;
+ internal List TransitionStateInfoList;
// Used to get the associated transition information required to synchronize late joining clients with transitions
// [Layer][DestinationState][TransitionStateInfo]
- private Dictionary> m_DestinationStateToTransitioninfo = new Dictionary>();
+ private readonly Dictionary> m_DestinationStateToTransitionInfo = new Dictionary>();
// Named differently to avoid serialization conflicts with NetworkBehaviour
internal NetworkManager LocalNetworkManager;
@@ -284,21 +281,15 @@ public Animator Animator
internal bool DistributedAuthorityMode;
///
- /// Builds the m_DestinationStateToTransitioninfo lookup table
+ /// Builds the lookup table
///
private void BuildDestinationToTransitionInfoTable()
{
foreach (var entry in TransitionStateInfoList)
{
- if (!m_DestinationStateToTransitioninfo.ContainsKey(entry.Layer))
- {
- m_DestinationStateToTransitioninfo.Add(entry.Layer, new Dictionary());
- }
- var destinationStateTransitionInfo = m_DestinationStateToTransitioninfo[entry.Layer];
- if (!destinationStateTransitionInfo.ContainsKey(entry.DestinationState))
- {
- destinationStateTransitionInfo.Add(entry.DestinationState, entry);
- }
+ m_DestinationStateToTransitionInfo.TryAdd(entry.Layer, new Dictionary());
+ var destinationStateTransitionInfo = m_DestinationStateToTransitionInfo[entry.Layer];
+ destinationStateTransitionInfo.TryAdd(entry.DestinationState, entry);
}
}
@@ -323,14 +314,14 @@ internal class AnimatorParametersListContainer
[SerializeField]
internal AnimatorParametersListContainer AnimatorParameterEntries;
- internal Dictionary AnimatorParameterEntryTable = new Dictionary();
+ private readonly Dictionary m_AnimatorParameterEntryTable = new Dictionary();
#if UNITY_EDITOR
[HideInInspector]
[SerializeField]
internal bool AnimatorParametersExpanded;
- internal Dictionary ParameterToNameLookup = new Dictionary();
+ private readonly Dictionary m_ParameterToNameLookup = new Dictionary();
private void ParseStateMachineStates(int layerIndex, ref AnimatorController animatorController, ref AnimatorStateMachine stateMachine)
{
@@ -371,7 +362,7 @@ private void ParseStateMachineStates(int layerIndex, ref AnimatorController anim
}
else if (transition.destinationState != null)
{
- var transitionInfo = new TransitionStateinfo()
+ var transitionInfo = new TransitionStateInfo()
{
Layer = layerIndex,
OriginatingState = animatorState.nameHash,
@@ -408,7 +399,7 @@ private void BuildTransitionStateInfoList()
return;
}
- TransitionStateInfoList = new List();
+ TransitionStateInfoList = new List();
var animControllerType = m_Animator.runtimeAnimatorController.GetType();
var animatorController = (AnimatorController)null;
@@ -433,7 +424,7 @@ private void BuildTransitionStateInfoList()
}
}
- internal void ProcessParameterEntries()
+ private void ProcessParameterEntries()
{
if (!Animator)
{
@@ -462,18 +453,18 @@ internal void ProcessParameterEntries()
var parameters = animatorController.parameters;
var parametersToRemove = new List();
- ParameterToNameLookup.Clear();
+ m_ParameterToNameLookup.Clear();
foreach (var parameter in parameters)
{
- ParameterToNameLookup.Add(parameter.nameHash, parameter);
+ m_ParameterToNameLookup.Add(parameter.nameHash, parameter);
}
// Rebuild the parameter entry table for the inspector view
- AnimatorParameterEntryTable.Clear();
+ m_AnimatorParameterEntryTable.Clear();
foreach (var parameterEntry in AnimatorParameterEntries.ParameterEntries)
{
// Check for removed parameters.
- if (!ParameterToNameLookup.ContainsKey(parameterEntry.NameHash))
+ if (!m_ParameterToNameLookup.ContainsKey(parameterEntry.NameHash))
{
parametersToRemove.Add(parameterEntry);
// Skip this removed entry
@@ -481,12 +472,9 @@ internal void ProcessParameterEntries()
}
// Build the list of known parameters
- if (!AnimatorParameterEntryTable.ContainsKey(parameterEntry.NameHash))
- {
- AnimatorParameterEntryTable.Add(parameterEntry.NameHash, parameterEntry);
- }
+ m_AnimatorParameterEntryTable.TryAdd(parameterEntry.NameHash, parameterEntry);
- var parameter = ParameterToNameLookup[parameterEntry.NameHash];
+ var parameter = m_ParameterToNameLookup[parameterEntry.NameHash];
parameterEntry.name = parameter.name;
parameterEntry.ParameterType = parameter.type;
}
@@ -498,9 +486,9 @@ internal void ProcessParameterEntries()
}
// Update any newly added parameters
- foreach (var parameterLookUp in ParameterToNameLookup)
+ foreach (var parameterLookUp in m_ParameterToNameLookup)
{
- if (!AnimatorParameterEntryTable.ContainsKey(parameterLookUp.Value.nameHash))
+ if (!m_AnimatorParameterEntryTable.ContainsKey(parameterLookUp.Value.nameHash))
{
var animatorParameterEntry = new AnimatorParameterEntry()
{
@@ -510,7 +498,7 @@ internal void ProcessParameterEntries()
Synchronize = true,
};
AnimatorParameterEntries.ParameterEntries.Add(animatorParameterEntry);
- AnimatorParameterEntryTable.Add(parameterLookUp.Value.nameHash, animatorParameterEntry);
+ m_AnimatorParameterEntryTable.Add(parameterLookUp.Value.nameHash, animatorParameterEntry);
}
}
}
@@ -602,7 +590,7 @@ public void NetworkSerialize(BufferSerializer serializer) where T : IReade
serializer.SerializeValue(ref NormalizedTime);
serializer.SerializeValue(ref Weight);
- // Cross fading includes the duration of the cross fade.
+ // Cross-fading includes the duration of the cross-fade.
if (CrossFade)
{
serializer.SerializeValue(ref Duration);
@@ -680,7 +668,7 @@ public void NetworkSerialize(BufferSerializer serializer) where T : IReade
/// Determines whether the is or based on the field.
/// Optionally, you can still derive from and override the method.
///
- /// or
+ /// True if this is server authoritative, false otherwise
public bool IsServerAuthoritative()
{
return OnIsServerAuthoritative();
@@ -706,7 +694,6 @@ protected virtual bool OnIsServerAuthoritative()
private int[] m_TransitionHash;
private int[] m_AnimationHash;
private float[] m_LayerWeights;
- private static byte[] s_EmptyArray = new byte[] { };
private List m_ParametersToUpdate;
private RpcParams m_RpcParams;
private IGroupRpcTarget m_TargetGroup;
@@ -781,14 +768,14 @@ protected virtual void Awake()
if (!m_Animator)
{
#if !UNITY_EDITOR
- Debug.LogError($"{nameof(NetworkAnimator)} {name} does not have an {nameof(UnityEngine.Animator)} assigned to it. The {nameof(NetworkAnimator)} will not initialize properly.");
+ Debug.LogWarning($"{nameof(NetworkAnimator)} {name} does not have an {nameof(UnityEngine.Animator)} assigned to it. The {nameof(NetworkAnimator)} will not initialize properly.");
#endif
return;
}
foreach (var parameterEntry in AnimatorParameterEntries.ParameterEntries)
{
- AnimatorParameterEntryTable.TryAdd(parameterEntry.NameHash, parameterEntry);
+ m_AnimatorParameterEntryTable.TryAdd(parameterEntry.NameHash, parameterEntry);
}
int layers = m_Animator.layerCount;
@@ -814,10 +801,7 @@ protected virtual void Awake()
// AnimationMessage.
m_AnimationMessage.AnimationStates.Add(new AnimationState());
float layerWeightNow = m_Animator.GetLayerWeight(layer);
- if (layerWeightNow != m_LayerWeights[layer])
- {
- m_LayerWeights[layer] = layerWeightNow;
- }
+ m_LayerWeights[layer] = layerWeightNow;
}
// The total initialization size calculated for the m_ParameterWriter write buffer.
@@ -835,9 +819,9 @@ protected virtual void Awake()
{
var parameter = parameters[i];
var synchronizeParameter = true;
- if (AnimatorParameterEntryTable.ContainsKey(parameter.nameHash))
+ if (m_AnimatorParameterEntryTable.TryGetValue(parameter.nameHash, out var entry))
{
- synchronizeParameter = AnimatorParameterEntryTable[parameter.nameHash].Synchronize;
+ synchronizeParameter = entry.Synchronize;
}
var cacheParam = new AnimatorParamCache
@@ -863,8 +847,6 @@ protected virtual void Awake()
var valueBool = m_Animator.GetBool(cacheParam.Hash);
UnsafeUtility.WriteArrayElement(cacheParam.Value, 0, valueBool);
break;
- default:
- break;
}
}
@@ -986,12 +968,12 @@ private void WriteSynchronizationData(ref BufferSerializer serializer) whe
var normalizedTime = synchronizationStateInfo.normalizedTime;
var isInTransition = m_Animator.IsInTransition(layer);
- // Grab one of the available AnimationState entries so we can fill it with the current
+ // Grab one of the available AnimationState entries, so we can fill it with the current
// layer's animation state.
var animationState = m_AnimationMessage.AnimationStates[layer];
// Synchronizing transitions with trigger conditions for late joining clients is now
- // handled by cross fading between the late joining client's current layer's AnimationState
+ // handled by cross-fading between the late joining client's current layer's AnimationState
// and the transition's destination AnimationState.
if (isInTransition)
{
@@ -1013,16 +995,14 @@ private void WriteSynchronizationData(ref BufferSerializer serializer) whe
}
stateHash = nextState.fullPathHash;
- // Use the destination state to transition info lookup table to see if this is a transition we can
- // synchronize using cross fading
- if (m_DestinationStateToTransitioninfo.ContainsKey(layer))
+ // Check if this transition can be synchronized using cross-fading
+ if (m_DestinationStateToTransitionInfo.TryGetValue(layer, out var layerTransitions))
{
- if (m_DestinationStateToTransitioninfo[layer].ContainsKey(nextState.shortNameHash))
+ if (layerTransitions.TryGetValue(nextState.shortNameHash, out var transitionInfo))
{
- var destinationInfo = m_DestinationStateToTransitioninfo[layer][nextState.shortNameHash];
- stateHash = destinationInfo.OriginatingState;
- // Set the destination state to cross fade to from the originating state
- animationState.DestinationStateHash = destinationInfo.DestinationState;
+ stateHash = transitionInfo.OriginatingState;
+ // Set the destination state to cross-fade to from the originating state
+ animationState.DestinationStateHash = transitionInfo.DestinationState;
}
}
}
@@ -1070,7 +1050,7 @@ protected override void OnSynchronize(ref BufferSerializer serializer)
///
/// Checks for animation state changes in:
/// -Layer weights
- /// -Cross fades
+ /// -Cross-fades
/// -Transitions
/// -Layer AnimationStates
///
@@ -1104,7 +1084,7 @@ private void CheckForStateChange(int layer)
{
m_TransitionHash[layer] = nt.fullPathHash;
m_AnimationHash[layer] = 0;
- // Next state is the destination state for cross fade
+ // Next state is the destination state for cross-fade
animState.DestinationStateHash = nt.fullPathHash;
animState.CrossFade = true;
animState.Transition = true;
@@ -1113,12 +1093,13 @@ private void CheckForStateChange(int layer)
stateChangeDetected = true;
//Debug.Log($"[Cross-Fade] To-Hash: {nt.fullPathHash} | TI-Duration: ({tt.duration}) | TI-Norm: ({tt.normalizedTime}) | From-Hash: ({m_AnimationHash[layer]}) | SI-FPHash: ({st.fullPathHash}) | SI-Norm: ({st.normalizedTime})");
}
- // If we are not transitioned into the "any state" and the animator transition isn't a full path hash (layer to layer) and our pre-built destination state to transition does not contain the
- // current layer (i.e. transitioning into a state from another layer) =or= we do contain the layer and the layer contains state to transition to is contained within our pre-built destination
- // state then we can handle this transition as a non-cross fade state transition between layers.
- // Otherwise, if we don't enter into this then this is a "trigger transition to some state that is now being transitioned back to the Idle state via trigger" or "Dual Triggers" IDLE<-->State.
- else if (!tt.anyState && tt.fullPathHash != m_TransitionHash[layer] && (!m_DestinationStateToTransitioninfo.ContainsKey(layer) ||
- (m_DestinationStateToTransitioninfo.ContainsKey(layer) && m_DestinationStateToTransitioninfo[layer].ContainsKey(nt.fullPathHash))))
+ // Handle as a non-cross-fade transition when:
+ // - not an "any state" transition and this is a new transition on this layer
+ // - the layer is either absent from the lookup table (cross-layer transition) or its destination state is present
+ // Skipping this block means we are in a "dual trigger" scenario where a trigger transitions
+ // to a state that is immediately transitioned back via another trigger (e.g. IDLE <--> State).
+ else if (!tt.anyState && tt.fullPathHash != m_TransitionHash[layer] && (!m_DestinationStateToTransitionInfo.TryGetValue(layer, out var layerTransitions) ||
+ layerTransitions.ContainsKey(nt.fullPathHash)))
{
// first time in this transition for this layer
m_TransitionHash[layer] = tt.fullPathHash;
@@ -1128,7 +1109,7 @@ private void CheckForStateChange(int layer)
animState.CrossFade = false;
animState.Transition = true;
animState.NormalizedTime = tt.normalizedTime;
- if (m_DestinationStateToTransitioninfo.ContainsKey(layer) && m_DestinationStateToTransitioninfo[layer].ContainsKey(nt.fullPathHash))
+ if (layerTransitions != null)
{
animState.DestinationStateHash = nt.fullPathHash;
}
@@ -1189,9 +1170,6 @@ internal void CheckForAnimatorChanges()
// This sends updates only if a layer's state has changed
for (int layer = 0; layer < m_Animator.layerCount; layer++)
{
- AnimatorStateInfo st = m_Animator.GetCurrentAnimatorStateInfo(layer);
- var totalSpeed = st.speed * st.speedMultiplier;
- var adjustedNormalizedMaxTime = totalSpeed > 0.0f ? 1.0f / totalSpeed : 0.0f;
CheckForStateChange(layer);
}
@@ -1202,8 +1180,7 @@ internal void CheckForAnimatorChanges()
{
SendAnimStateRpc(m_AnimationMessage);
}
- else
- if (!IsServer && IsOwner)
+ else if (!IsServer && IsOwner)
{
SendServerAnimStateRpc(m_AnimationMessage);
}
@@ -1337,8 +1314,8 @@ private unsafe bool CheckParametersChanged()
}
///
- /// Writes all of the Animator's parameters
- /// This uses the m_ParametersToUpdate list to write out only
+ /// Writes all the Animator's parameters
+ /// This uses the list to write out only
/// the parameters that have changed
///
private unsafe void WriteParameters(ref FastBufferWriter writer)
@@ -1368,8 +1345,7 @@ private unsafe void WriteParameters(ref FastBufferWriter writer)
BytePacker.WriteValuePacked(writer, (uint)valueInt);
}
}
- else // Note: Triggers are treated like boolean values
- if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterBool)
+ else if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterBool)
{
var valueBool = m_Animator.GetBool(hash);
fixed (void* value = cacheValue.Value)
@@ -1401,6 +1377,13 @@ private unsafe void ReadParameters(FastBufferReader reader)
while (totalParametersRead < totalParametersToRead)
{
ByteUnpacker.ReadValuePacked(reader, out uint parameterIndex);
+
+ // Do bounds check prior to getting the element as a reference at that index.
+ if (parameterIndex >= m_CachedAnimatorParameters.Length)
+ {
+ NetworkManager.Log.ErrorServer(new Logging.Context(LogLevel.Error, $"[{nameof(NetworkAnimator)}][{name}] Invalid index of {parameterIndex} was received when there are only {m_CachedAnimatorParameters.Length} parameters. Ignoring the remainger of this {nameof(ParametersUpdateMessage)}!"));
+ return;
+ }
ref var cacheValue = ref UnsafeUtility.ArrayElementAsRef(m_CachedAnimatorParameters.GetUnsafePtr(), (int)parameterIndex);
var hash = cacheValue.Hash;
if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterInt)
@@ -1453,7 +1436,7 @@ internal unsafe void UpdateParameters(ref ParametersUpdateMessage parametersUpda
///
/// Applies the AnimationState state to the Animator
///
- internal void UpdateAnimationState(AnimationState animationState)
+ private void UpdateAnimationState(AnimationState animationState)
{
// Handle updating layer weights first.
if (animationState.Layer < m_LayerWeights.Length)
@@ -1475,21 +1458,17 @@ internal void UpdateAnimationState(AnimationState animationState)
// If it is a transition, then we are synchronizing transitions in progress when a client late joins
if (animationState.Transition && !animationState.CrossFade)
{
- // We should have all valid entries for any animation state transition update
- // Verify the AnimationState's assigned Layer exists
- if (m_DestinationStateToTransitioninfo.ContainsKey(animationState.Layer))
+ // At this point all entries in the lookup table should be valid.
+ // Look up the transition info for this layer and destination state.
+ if (m_DestinationStateToTransitionInfo.TryGetValue(animationState.Layer, out var layerTransitions))
{
- // Verify the inner-table has the destination AnimationState name hash
- if (m_DestinationStateToTransitioninfo[animationState.Layer].ContainsKey(animationState.DestinationStateHash))
+ if (layerTransitions.TryGetValue(animationState.DestinationStateHash, out var transitionInfo))
{
- // Make sure we are on the originating/starting state we are going to cross fade into
+ // Make sure we are on the originating/starting state we are going to cross-fade into
if (currentState.shortNameHash == animationState.StateHash)
{
- // Get the transition state information
- var transitionStateInfo = m_DestinationStateToTransitioninfo[animationState.Layer][animationState.DestinationStateHash];
-
- // Cross fade from the current to the destination state for the transitions duration while starting at the server's current normalized time of the transition
- m_Animator.CrossFade(transitionStateInfo.DestinationState, transitionStateInfo.TransitionDuration, transitionStateInfo.Layer, 0.0f, animationState.NormalizedTime);
+ // Cross-fade from the current to the destination state for the transitions duration while starting at the server's current normalized time of the transition
+ m_Animator.CrossFade(transitionInfo.DestinationState, transitionInfo.TransitionDuration, transitionInfo.Layer, 0.0f, animationState.NormalizedTime);
}
else if (LocalNetworkManager.LogLevel == LogLevel.Developer)
{
@@ -1526,7 +1505,7 @@ internal void UpdateAnimationState(AnimationState animationState)
/// The server sets its local parameters and then forwards the message to the remaining clients
///
[Rpc(SendTo.Server, AllowTargetOverride = true, InvokePermission = RpcInvokePermission.Owner)]
- private unsafe void SendServerParametersUpdateRpc(ParametersUpdateMessage parametersUpdate, RpcParams rpcParams = default)
+ private void SendServerParametersUpdateRpc(ParametersUpdateMessage parametersUpdate, RpcParams rpcParams = default)
{
if (IsServerAuthoritative())
{
@@ -1708,9 +1687,6 @@ internal void SendServerAnimTriggerRpc(AnimationTriggerMessage animationTriggerM
}
}
- ///
- /// See above
- ///
private void InternalSetTrigger(int hash, bool isSet = true)
{
m_Animator.SetBool(hash, isSet);
@@ -1721,6 +1697,7 @@ private void InternalSetTrigger(int hash, bool isSet = true)
/// to forward a trigger to a client
///
/// the payload containing the trigger data to apply
+ /// Defined as it's used to send the RPC to be invoked on this client
[Rpc(SendTo.NotAuthority, AllowTargetOverride = true, InvokePermission = RpcInvokePermission.Owner)]
internal void SendAnimTriggerRpc(AnimationTriggerMessage animationTriggerMessage, RpcParams rpcParams = default)
{
@@ -1732,7 +1709,7 @@ internal void SendAnimTriggerRpc(AnimationTriggerMessage animationTriggerMessage
/// a trigger to a client
///
/// the payload containing the trigger data to apply
- /// unused
+ /// used to send the RPC to be invoked on this client
[Rpc(SendTo.NotServer, AllowTargetOverride = true)]
internal void SendClientAnimTriggerRpc(AnimationTriggerMessage animationTriggerMessage, RpcParams rpcParams = default)
{
@@ -1775,13 +1752,11 @@ public void SetTrigger(int hash, bool setTrigger = true)
{
if (IsServer)
{
- /// as to why we queue
m_NetworkAnimatorStateChangeHandler.QueueTriggerUpdateToClient(animTriggerMessage);
InternalSetTrigger(hash, setTrigger);
}
else
{
- /// as to why we queue
m_NetworkAnimatorStateChangeHandler.QueueTriggerUpdateToServer(animTriggerMessage);
if (!IsServerAuthoritative())
{
diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkDeltaPosition.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkDeltaPosition.cs
index a780a07230..3bae7eded3 100644
--- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkDeltaPosition.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkDeltaPosition.cs
@@ -11,7 +11,14 @@ namespace Unity.Netcode.Components
[Serializable]
public struct NetworkDeltaPosition : INetworkSerializable
{
- internal const float MaxDeltaBeforeAdjustment = 64f;
+ ///
+ /// How far the delta may grow before it is folded into the base position.
+ ///
+ ///
+ /// This determines the transmitted position resolution, since a half float's step size grows with its
+ /// magnitude. Keeping the delta small keeps that step small: at 2 the coarsest step is roughly 1mm.
+ ///
+ internal const float MaxDeltaBeforeAdjustment = 2f;
///
/// The HalfVector3 used to synchronize the delta in position
@@ -138,14 +145,29 @@ public void UpdateFrom(ref Vector3 vector3, int networkTick)
{
CollapsedDeltaIntoBase = false;
NetworkTick = networkTick;
- DeltaPosition = (vector3 + PrecisionLossDelta) - CurrentBasePosition;
for (int i = 0; i < HalfVector3.Length; i++)
{
if (HalfVector3.AxisToSynchronize[i])
{
+ var rawDelta = vector3[i] - CurrentBasePosition[i];
+
+ // Adding the previous rounding loss back in keeps the average position accurate while the
+ // value is moving, but it also changes the value being sent. Once the value stops moving
+ // that is all it does, which makes a stationary object appear to oscillate.
+ var movedSinceLastSend = Mathf.Abs(vector3[i] - PreviousPosition[i]);
+ var applyPrecisionLoss = movedSinceLastSend >= HalfPrecisionQuantum(rawDelta);
+
+ DeltaPosition[i] = applyPrecisionLoss ? rawDelta + PrecisionLossDelta[i] : rawDelta;
+
HalfVector3.Axis[i] = math.half(DeltaPosition[i]);
HalfDeltaConvertedBack[i] = Mathf.HalfToFloat(HalfVector3.Axis[i].value);
- PrecisionLossDelta[i] = DeltaPosition[i] - HalfDeltaConvertedBack[i];
+
+ // Left unchanged when skipped so it is still applied once movement resumes.
+ if (applyPrecisionLoss)
+ {
+ PrecisionLossDelta[i] = DeltaPosition[i] - HalfDeltaConvertedBack[i];
+ }
+
if (Mathf.Abs(HalfDeltaConvertedBack[i]) >= MaxDeltaBeforeAdjustment)
{
CurrentBasePosition[i] += HalfDeltaConvertedBack[i];
@@ -165,6 +187,26 @@ public void UpdateFrom(ref Vector3 vector3, int networkTick)
}
}
+ ///
+ /// The smallest change a half float can represent at the magnitude of the value passed in.
+ ///
+ /// The value to get the step size for.
+ /// The distance to the next representable half float value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static float HalfPrecisionQuantum(float value)
+ {
+ // The step size is symmetric about zero, so the sign is dropped.
+ var magnitude = (ushort)(math.half(value).value & 0x7FFF);
+
+ // Guard only: stepping past the largest finite half float would give infinity.
+ if (magnitude >= 0x7BFF)
+ {
+ return MaxDeltaBeforeAdjustment;
+ }
+
+ return Mathf.HalfToFloat((ushort)(magnitude + 1)) - Mathf.HalfToFloat(magnitude);
+ }
+
///
/// Constructor
///
diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs
index 0d0de9afa8..7df6af4e59 100644
--- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs
@@ -2,6 +2,7 @@
using System.Runtime.CompilerServices;
using UnityEngine;
+
namespace Unity.Netcode.Components
{
///
@@ -571,7 +572,7 @@ private void InternalMoveRotation2D(Quaternion rotation)
{
var quaternion = Quaternion.identity;
var angles = quaternion.eulerAngles;
- angles.z = m_InternalRigidbody2D.rotation;
+ angles.z = rotation.z;
quaternion.eulerAngles = angles;
m_InternalRigidbody2D.MoveRotation(quaternion);
}
@@ -845,6 +846,28 @@ public void SetIsKinematic(bool isKinematic)
PostSetIsKinematic();
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private bool HasInterpolationTypeSet(InterpolationTypes interpolationType)
+ {
+#if COM_UNITY_MODULES_PHYSICS && COM_UNITY_MODULES_PHYSICS2D
+ if (m_IsRigidbody2D)
+ {
+ return interpolationType == InterpolationTypes.Extrapolate ? m_InternalRigidbody2D.interpolation == RigidbodyInterpolation2D.Extrapolate : m_InternalRigidbody2D.interpolation == RigidbodyInterpolation2D.Interpolate;
+ }
+ else
+ {
+ return interpolationType == InterpolationTypes.Extrapolate ? m_InternalRigidbody.interpolation == RigidbodyInterpolation.Extrapolate : m_InternalRigidbody.interpolation == RigidbodyInterpolation.Interpolate;
+ }
+#endif
+#if COM_UNITY_MODULES_PHYSICS && !COM_UNITY_MODULES_PHYSICS2D
+ return interpolationType == InterpolationTypes.Extrapolate ? m_InternalRigidbody.interpolation == RigidbodyInterpolation.Extrapolate : m_InternalRigidbody.interpolation == RigidbodyInterpolation.Interpolate;
+#endif
+#if !COM_UNITY_MODULES_PHYSICS && COM_UNITY_MODULES_PHYSICS2D
+ return interpolationType == InterpolationTypes.Extrapolate ? m_InternalRigidbody2D.interpolation == RigidbodyInterpolation2D.Extrapolate : m_InternalRigidbody2D.interpolation == RigidbodyInterpolation2D.Interpolate;
+#endif
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void PostSetIsKinematic()
{
@@ -853,26 +876,29 @@ private void PostSetIsKinematic()
{
return;
}
+
if (UseRigidBodyForMotion)
{
- // Only if the NetworkTransform is set to interpolate do we need to check for extrapolation
- if (NetworkTransform.Interpolate && m_OriginalInterpolation == InterpolationTypes.Extrapolate)
+ // Exit early if the original interpolation type is not set to extrapolate or NetworkTransform interpolate is disabled
+ if (m_OriginalInterpolation != InterpolationTypes.Extrapolate || !NetworkTransform.Interpolate)
{
- if (IsKinematic())
- {
- // If not already set to interpolate then set the Rigidbody to interpolate
- if (m_InternalRigidbody.interpolation == RigidbodyInterpolation.Extrapolate)
- {
- // Sleep until the next fixed update when switching from extrapolation to interpolation
- SleepRigidbody();
- SetInterpolation(InterpolationTypes.Interpolate);
- }
- }
- else
- {
- // Switch it back to the original interpolation if non-kinematic (doesn't require sleep).
- SetInterpolation(m_OriginalInterpolation);
- }
+ return;
+ }
+
+ // Otherwise, if this is the active physics object
+ if (!IsKinematic())
+ {
+ // switch it back to the original interpolation and exit early
+ SetInterpolation(m_OriginalInterpolation);
+ return;
+ }
+
+ // If the Rigidbody or Rigidbody2D is currently configured to extrapolate
+ if (HasInterpolationTypeSet(InterpolationTypes.Extrapolate))
+ {
+ // sleep until the next fixed update when switching from extrapolation to interpolation
+ SleepRigidbody();
+ SetInterpolation(InterpolationTypes.Interpolate);
}
}
else
diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs
index 3ca9093b34..9ac503a926 100644
--- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs
@@ -24,6 +24,18 @@ public class NetworkTransform : NetworkBehaviour
[HideInInspector]
[SerializeField]
internal bool NetworkTransformExpanded;
+
+ [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
+ private static void ResetStaticsOnLoad()
+ {
+ CurrentTick = 0;
+ TrackStateUpdateId = false;
+ AssignDefaultInterpolationType = false;
+ DefaultInterpolationType = default;
+ s_NetworkTickRegistration = new Dictionary();
+ InterpolationBufferTickOffset = 0;
+ s_TickSynchPosition = 0;
+ }
#endif
internal enum Axis { X, Y, Z }
@@ -1124,7 +1136,7 @@ public enum InterpolationTypes
/// Uses a 1 to 2 phase interpolation approach where:
///
/// The first phase lerps from the previous state update value to the next state update value.
- /// The second phase (optional) performs lerp smoothing where the current respective transform value is lerped towards the result of the first phase at a rate of 1.0 minus the respective maximum interpolation time.
+ /// The second phase (optional) performs lerp smoothing where the current respective transform value is lerped towards the result of the first phase at a frame rate independent rate determined by the respective maximum interpolation time.
///
///
///
@@ -1144,7 +1156,7 @@ public enum InterpolationTypes
/// Uses a 1 to 2 phase smooth dampening approach where:
///
/// The first phase smooth dampens towards the current tick state update being processed by the accumulated delta time relative to the time to target.
- /// The second phase (optional) performs lerp smoothing where the current respective transform value is lerped towards the result of the first phase at a rate of delta time divided by the respective max interpolation time.
+ /// The second phase (optional) performs lerp smoothing where the current respective transform value is lerped towards the result of the first phase at a frame rate independent rate determined by the respective maximum interpolation time.
///
///
///
@@ -1224,7 +1236,11 @@ public enum InterpolationTypes
/// Controls position interpolation smoothing.
///
///
- /// When enabled, the will apply a final lerping pass where the "t" parameter is calculated by dividing the frame time divided by the .
+ /// When enabled, the will apply a final lerping pass towards
+ /// the interpolated result at a rate determined by .
+ /// This smoothing pass is frame rate independent under and
+ /// . keeps its
+ /// original frame rate dependent smoothing, so the same value does not produce the same result there.
///
public bool PositionLerpSmoothing = true;
private bool m_PreviousPositionLerpSmoothing;
@@ -1245,7 +1261,11 @@ public enum InterpolationTypes
/// Controls rotation interpolation smoothing.
///
///
- /// When enabled, the will apply a final lerping pass where the "t" parameter is calculated by dividing the frame time divided by the .
+ /// When enabled, the will apply a final lerping pass towards
+ /// the interpolated result at a rate determined by .
+ /// This smoothing pass is frame rate independent under and
+ /// . keeps its
+ /// original frame rate dependent smoothing, so the same value does not produce the same result there.
///
public bool RotationLerpSmoothing = true;
private bool m_PreviousRotationLerpSmoothing;
@@ -1266,7 +1286,11 @@ public enum InterpolationTypes
/// Controls scale interpolation smoothing.
///
///
- /// When enabled, the will apply a final lerping pass where the "t" parameter is calculated by dividing the frame time divided by the .
+ /// When enabled, the will apply a final lerping pass towards
+ /// the interpolated result at a rate determined by .
+ /// This smoothing pass is frame rate independent under and
+ /// . keeps its
+ /// original frame rate dependent smoothing, so the same value does not produce the same result there.
///
public bool ScaleLerpSmoothing = true;
private bool m_PreviousScaleLerpSmoothing;
@@ -1361,7 +1385,7 @@ public enum AuthorityModes
///
/// When set each state update will contain a state identifier
///
- internal static bool TrackStateUpdateId = false;
+ internal static bool TrackStateUpdateId;
///
/// Enabled by default.
@@ -2062,19 +2086,6 @@ private void TryCommitTransform(bool synchronize = false, bool settingState = fa
childNetworkTransform.OnNetworkTick(true);
}
}
-
- // Synchronize any parented children with the parent's motion
- foreach (var child in m_ParentedChildren)
- {
- // Synchronize any nested NetworkTransforms of the child with the parent's
- foreach (var childNetworkTransform in child.NetworkTransforms)
- {
- if (childNetworkTransform.CanCommitToTransform)
- {
- childNetworkTransform.OnNetworkTick(true);
- }
- }
- }
}
}
}
@@ -2221,17 +2232,15 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, bool is
// values are applied.
var hasParentNetworkObject = false;
- var parentNetworkObject = (NetworkObject)null;
-
// If the NetworkObject belonging to this NetworkTransform instance has a parent
// (i.e. this handles nested NetworkTransforms under a parent at some layer above)
if (NetworkObject.transform.parent != null)
{
- parentNetworkObject = NetworkObject.transform.parent.GetComponent();
+ var parentNetworkObject = NetworkObject.transform.parent.GetComponent();
// In-scene placed NetworkObjects parented under a GameObject with no
// NetworkObject preserve their lossyScale when synchronizing.
- if (parentNetworkObject == null && NetworkObject.IsSceneObject != false)
+ if (parentNetworkObject == null && NetworkObject.InScenePlaced)
{
hasParentNetworkObject = true;
}
@@ -2518,8 +2527,8 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, bool is
}
}
}
- else // Just apply the full local scale when synchronizing
- if (SynchronizeScale)
+ // Just apply the full local scale when synchronizing
+ else if (SynchronizeScale)
{
var localScale = CachedTransform.localScale;
if (!UseHalfFloatPrecision)
@@ -3363,19 +3372,6 @@ private void OnNetworkStateChanged(NetworkTransformState oldState, NetworkTransf
childNetworkTransform.OnNetworkTick(true);
}
}
-
- // Synchronize any parented children with the parent's motion
- foreach (var child in m_ParentedChildren)
- {
- // Synchronize any nested NetworkTransforms of the child with the parent's
- foreach (var childNetworkTransform in child.NetworkTransforms)
- {
- if (childNetworkTransform.CanCommitToTransform)
- {
- childNetworkTransform.OnNetworkTick(true);
- }
- }
- }
}
// Provide notifications when the state has been updated
@@ -3504,8 +3500,8 @@ private void NonAuthorityFinalizeSynchronization()
child.InternalInitialization();
}
}
- else // Otherwise, just run through standard synchronization of this instance
- if (!CanCommitToTransform)
+ // Otherwise, just run through standard synchronization of this instance
+ else if (!CanCommitToTransform)
{
ApplySynchronization();
InternalInitialization();
@@ -3634,8 +3630,6 @@ internal override void InternalOnNetworkPreSpawn(ref NetworkManager networkManag
///
public override void OnNetworkSpawn()
{
- m_ParentedChildren.Clear();
-
Initialize();
if (CanCommitToTransform && !SwitchTransformSpaceWhenParented)
@@ -3647,7 +3641,6 @@ public override void OnNetworkSpawn()
private void CleanUpOnDestroyOrDespawn()
{
- m_ParentedChildren.Clear();
#if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D
var forUpdate = !m_UseRigidbodyForMotion;
#else
@@ -3722,6 +3715,38 @@ private void ResetInterpolatedStateToCurrentAuthoritativeState()
m_ScaleInterpolator.ResetTo(transform.parent, transform.localScale, serverTime);
}
+ ///
+ /// Determines if this has any instances that are non-authority and are updated during the same update stage.
+ ///
+ ///
+ /// See to better understand how the parameter is used to determine which update stage to check for non-authority instances.
+ ///
+ /// true to check the instances updated during the standard update and false to check the instances updated during the fixed update.
+ /// true if a non-authority NetworkTransform exists on this NetworkObject and false if there are none.
+ private bool HasNonAuthorityNetworkTransform(bool forUpdate)
+ {
+ var networkTransforms = NetworkObject.NetworkTransforms;
+ for (int i = 0; i < networkTransforms.Count; i++)
+ {
+ var networkTransform = networkTransforms[i];
+#if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D
+ // If the update stages don't match, then skip this instance.
+ // Reference:
+ // forUpdate is true for the standard update and false for the fixed update.
+ // m_UseRigidbodyForMotion is false for the standard update and true for the fixed update.
+ if (forUpdate == networkTransform.m_UseRigidbodyForMotion)
+ {
+ continue;
+ }
+#endif
+ if (!(networkTransform.IsServerAuthoritative() ? networkTransform.IsServer : networkTransform.IsOwner))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
///
/// The internal initialization method to allow for internal API adjustments
///
@@ -3784,8 +3809,12 @@ private void InternalInitialization(bool isOwnershipChange = false)
if (CanCommitToTransform)
{
- // Make sure authority doesn't get added to updates (no need to do this on the authority side)
- m_CachedNetworkManager.NetworkTransformRegistration(NetworkObject, forUpdate, false);
+ // If there are no non-authority NetworkTransform instances on this NetworkObject using this update, then remove this instance from the NetworkManager's update list.
+ // Otherwise, we need to keep it registered for updates so the non-authority instances will process their received state updates and apply them to the transform.
+ if (!HasNonAuthorityNetworkTransform(forUpdate))
+ {
+ m_CachedNetworkManager.NetworkTransformRegistration(NetworkObject, forUpdate, false);
+ }
if (UseHalfFloatPrecision)
{
m_HalfPositionState = new NetworkDeltaPosition(currentPosition, m_CachedNetworkManager.ServerTime.Tick, math.bool3(SyncPositionX, SyncPositionY, SyncPositionZ));
@@ -3861,7 +3890,6 @@ protected override void OnOwnershipChanged(ulong previous, ulong current)
}
internal bool IsNested;
- private List m_ParentedChildren = new List();
private bool m_IsFirstNetworkTransform;
@@ -4250,14 +4278,13 @@ internal BufferedLinearInterpolatorQuaternion GetRotationInterpolator()
// Non-Authority
private void UpdateInterpolation()
{
- // Use the local time because:
- // Client-Server:
- // Local time is server time on a host or server.
- // Local time on clients takes latency into consideration.
- // Distributed authority:
- // Local time is used by the authority.
- // Local time on non-authority takes latency into consid]eration.
- var timeSystem = m_CachedNetworkManager.LocalTime;
+ // Use the server time, since that is the clock the states being interpolated between are stamped on
+ // (a state's SentTime is derived from its NetworkTick). Deriving the render time from LocalTime
+ // subtracts the tick latency from a clock that already leads ServerTime by roughly that much, which
+ // leaves the render time at or ahead of the newest state that can exist and starves the interpolator.
+ // Measuring from ServerTime is also self correcting, as the tick latency grows with the round trip
+ // time. This is a no-op on a host or server, where both clocks are the same.
+ var timeSystem = m_CachedNetworkManager.ServerTime;
var currentTime = timeSystem.Time;
#if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D
var cachedDeltaTime = m_UseRigidbodyForMotion ? m_CachedNetworkManager.RealTimeProvider.FixedDeltaTime : m_CachedNetworkManager.RealTimeProvider.DeltaTime;
@@ -4694,7 +4721,7 @@ internal static void UpdateNetworkTick(NetworkManager networkManager)
/// The default value is 1 tick (plus the tick latency). When running on a local network, reducing this to 0 is recommended.
///
///
- public static int InterpolationBufferTickOffset = 0;
+ public static int InterpolationBufferTickOffset;
internal static float GetTickLatency(NetworkManager networkManager)
{
if (networkManager.IsListening)
@@ -4721,7 +4748,10 @@ internal static float GetTickLatencyInSeconds(NetworkManager networkManager)
{
if (networkManager.IsListening)
{
- return (float)networkManager.LocalTime.TimeTicksAgo(networkManager.NetworkTimeSystem.TickLatency + InterpolationBufferTickOffset).Time;
+ // The number of ticks the interpolators run behind, as a duration. This is not a point in time:
+ // it does not grow as the session runs.
+ var ticksBehind = networkManager.NetworkTimeSystem.TickLatency + InterpolationBufferTickOffset;
+ return (float)(ticksBehind * networkManager.ServerTime.FixedDeltaTimeAsDouble);
}
return 0f;
}
@@ -4799,6 +4829,7 @@ public NetworkTransformTickRegistration(NetworkManager networkManager)
}
}
}
+
private static int s_TickSynchPosition;
private int m_NextTickSync;
diff --git a/com.unity.netcode.gameobjects/Runtime/Components/QuaternionCompressor.cs b/com.unity.netcode.gameobjects/Runtime/Components/QuaternionCompressor.cs
index f4d9b25dd2..3c338a2a84 100644
--- a/com.unity.netcode.gameobjects/Runtime/Components/QuaternionCompressor.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Components/QuaternionCompressor.cs
@@ -4,7 +4,7 @@
namespace Unity.Netcode
{
///
- /// A Smallest Three Quaternion Compressor Implementation
+ /// The Smallest Three Quaternion Compressor Implementation
///
///
/// Explanation of why "The smallest three":
@@ -26,14 +26,14 @@ public static class QuaternionCompressor
// We can further improve the encoding compression by dividing k_SqrtTwoOverTwo into 1.0f and multiplying that
// by the precision mask (minor reduction of runtime calculations)
- private const float k_CompressionEcodingMask = (1.0f / k_SqrtTwoOverTwoEncoding) * k_PrecisionMask;
+ private const float k_CompressionEncodingMask = (1.0f / k_SqrtTwoOverTwoEncoding) * k_PrecisionMask;
// Used to shift the negative bit to the 10th bit position when compressing and encoding
private const ushort k_ShiftNegativeBit = 9;
// We can do the same for our decoding and decompression by dividing k_PrecisionMask into 1.0 and multiplying
// that by k_SqrtTwoOverTwo (minor reduction of runtime calculations)
- private const float k_DcompressionDecodingMask = (1.0f / k_PrecisionMask) * k_SqrtTwoOverTwoEncoding;
+ private const float k_DecompressionDecodingMask = (1.0f / k_PrecisionMask) * k_SqrtTwoOverTwoEncoding;
// The sign bit position (10th bit) used when decompressing and decoding
private const ushort k_NegShortBit = 0x200;
@@ -42,9 +42,6 @@ public static class QuaternionCompressor
private const ushort k_True = 1;
private const ushort k_False = 0;
- // Used to store the absolute value of the 4 quaternion elements
- private static Quaternion s_QuatAbsValues = Quaternion.identity;
-
///
/// Compresses a Quaternion into an unsigned integer
///
@@ -54,38 +51,31 @@ public static class QuaternionCompressor
public static uint CompressQuaternion(ref Quaternion quaternion)
{
// Store off the absolute value for each Quaternion element
- s_QuatAbsValues[0] = Mathf.Abs(quaternion[0]);
- s_QuatAbsValues[1] = Mathf.Abs(quaternion[1]);
- s_QuatAbsValues[2] = Mathf.Abs(quaternion[2]);
- s_QuatAbsValues[3] = Mathf.Abs(quaternion[3]);
+ var quatAbsValue0 = Mathf.Abs(quaternion[0]);
+ var quatAbsValue1 = Mathf.Abs(quaternion[1]);
+ var quatAbsValue2 = Mathf.Abs(quaternion[2]);
+ var quatAbsValue3 = Mathf.Abs(quaternion[3]);
// Get the largest element value of the quaternion to know what the remaining "Smallest Three" values are
- var quatMax = Mathf.Max(s_QuatAbsValues[0], s_QuatAbsValues[1], s_QuatAbsValues[2], s_QuatAbsValues[3]);
+ var quatMax = Mathf.Max(quatAbsValue0, quatAbsValue1, quatAbsValue2, quatAbsValue3);
- // Find the index of the largest element so we can skip that element while compressing and decompressing
- var indexToSkip = (ushort)(s_QuatAbsValues[0] == quatMax ? 0 : s_QuatAbsValues[1] == quatMax ? 1 : s_QuatAbsValues[2] == quatMax ? 2 : 3);
+ // Find the index of the largest element, so we can skip that element while compressing and decompressing
+ var indexToSkip = (ushort)(quatAbsValue0 == quatMax ? 0 : quatAbsValue1 == quatMax ? 1 : quatAbsValue2 == quatMax ? 2 : 3);
// Get the sign of the largest element which is all that is needed when calculating the sum of squares of a normalized quaternion.
-
var quatMaxSign = (quaternion[indexToSkip] < 0 ? k_True : k_False);
// Start with the index to skip which will be shifted to the highest two bits
var compressed = (uint)indexToSkip;
- // Step 1: Start with the first element
- var currentIndex = 0;
-
- // Step 2: If we are on the index to skip preserve the current compressed value, otherwise proceed to step 3 and 4
- // Step 3: Get the sign of the element we are processing. If it is the not the same as the largest value's sign bit then we set the bit
- // Step 4: Get the compressed and encoded value by multiplying the absolute value of the current element by k_CompressionEcodingMask and round that result up
- compressed = currentIndex != indexToSkip ? (compressed << 10) | (uint)((quaternion[currentIndex] < 0 ? k_True : k_False) != quatMaxSign ? k_True : k_False) << k_ShiftNegativeBit | (ushort)Mathf.Round(k_CompressionEcodingMask * s_QuatAbsValues[currentIndex]) : compressed;
- currentIndex++;
- // Repeat the last 3 steps for the remaining elements
- compressed = currentIndex != indexToSkip ? (compressed << 10) | (uint)((quaternion[currentIndex] < 0 ? k_True : k_False) != quatMaxSign ? k_True : k_False) << k_ShiftNegativeBit | (ushort)Mathf.Round(k_CompressionEcodingMask * s_QuatAbsValues[currentIndex]) : compressed;
- currentIndex++;
- compressed = currentIndex != indexToSkip ? (compressed << 10) | (uint)((quaternion[currentIndex] < 0 ? k_True : k_False) != quatMaxSign ? k_True : k_False) << k_ShiftNegativeBit | (ushort)Mathf.Round(k_CompressionEcodingMask * s_QuatAbsValues[currentIndex]) : compressed;
- currentIndex++;
- compressed = currentIndex != indexToSkip ? (compressed << 10) | (uint)((quaternion[currentIndex] < 0 ? k_True : k_False) != quatMaxSign ? k_True : k_False) << k_ShiftNegativeBit | (ushort)Mathf.Round(k_CompressionEcodingMask * s_QuatAbsValues[currentIndex]) : compressed;
+ // Step 1: If we are on the index to skip, preserve the current compressed value, otherwise proceed to step 2 and 3
+ // Step 2: Get the sign of the element we are processing. If it is not the same as the largest value's sign bit then we set the bit
+ // Step 3: Get the compressed and encoded value by multiplying the absolute value of the current element by k_CompressionEncodingMask and round that result up
+ compressed = 0 != indexToSkip ? (compressed << 10) | (uint)((quaternion[0] < 0 ? k_True : k_False) != quatMaxSign ? k_True : k_False) << k_ShiftNegativeBit | (ushort)Mathf.Round(k_CompressionEncodingMask * quatAbsValue0) : compressed;
+ // Repeat the 3 steps for the remaining elements
+ compressed = 1 != indexToSkip ? (compressed << 10) | (uint)((quaternion[1] < 0 ? k_True : k_False) != quatMaxSign ? k_True : k_False) << k_ShiftNegativeBit | (ushort)Mathf.Round(k_CompressionEncodingMask * quatAbsValue1) : compressed;
+ compressed = 2 != indexToSkip ? (compressed << 10) | (uint)((quaternion[2] < 0 ? k_True : k_False) != quatMaxSign ? k_True : k_False) << k_ShiftNegativeBit | (ushort)Mathf.Round(k_CompressionEncodingMask * quatAbsValue2) : compressed;
+ compressed = 3 != indexToSkip ? (compressed << 10) | (uint)((quaternion[3] < 0 ? k_True : k_False) != quatMaxSign ? k_True : k_False) << k_ShiftNegativeBit | (ushort)Mathf.Round(k_CompressionEncodingMask * quatAbsValue3) : compressed;
// Return the compress quaternion
return compressed;
@@ -111,7 +101,7 @@ public static void DecompressQuaternion(ref Quaternion quaternion, uint compress
continue;
}
// Check the negative bit and multiply that result with the decompressed and decoded value
- quaternion[i] = ((compressed & k_NegShortBit) > 0 ? -1.0f : 1.0f) * ((compressed & k_PrecisionMask) * k_DcompressionDecodingMask);
+ quaternion[i] = ((compressed & k_NegShortBit) > 0 ? -1.0f : 1.0f) * ((compressed & k_PrecisionMask) * k_DecompressionDecodingMask);
sumOfSquaredMagnitudes += quaternion[i] * quaternion[i];
compressed = compressed >> 10;
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Components/RigidbodyContactEventManager.cs b/com.unity.netcode.gameobjects/Runtime/Components/RigidbodyContactEventManager.cs
index bf54c4d964..3c94eae424 100644
--- a/com.unity.netcode.gameobjects/Runtime/Components/RigidbodyContactEventManager.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Components/RigidbodyContactEventManager.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using Unity.Collections;
using Unity.Jobs;
+using Unity.Netcode.Logging;
using Unity.Netcode.Runtime;
using UnityEngine;
@@ -20,7 +21,7 @@ public struct ContactEventHandlerInfo
///
public bool ProvideNonRigidBodyContactEvents;
///
- /// When set to true, the will prioritize invoking
+ /// When set to true, the will prioritize invoking
/// if it is the 2nd colliding body in the contact pair being processed. With distributed authority, setting this value to true when a is owned by the local client
/// will assure is only invoked on the authoritative side.
///
@@ -105,14 +106,16 @@ private struct JobResultStruct
private readonly Dictionary m_HandlerInfo = new Dictionary();
#endif
+ private ContextualLogger m_Log;
private void OnEnable()
{
+ m_Log = new ContextualLogger(this);
m_ResultsArray = new NativeArray(16, Allocator.Persistent);
Physics.ContactEvent += Physics_ContactEvent;
- if (Instance != null)
+ if (Instance != null && Instance != this)
{
- NetworkLog.LogError($"[Invalid][Multiple Instances] Found more than one instance of {nameof(RigidbodyContactEventManager)}: {name} and {Instance.name}");
- NetworkLog.LogError($"[Disable][Additional Instance] Disabling {name} instance!");
+ m_Log.Error(new Context(LogLevel.Error, $"Found more than one instance of {nameof(RigidbodyContactEventManager)}").AddTag("Invalid").AddTag("Multiple Instances").AddInfo("Instance 1", Instance.name).AddInfo("Instance 2", name));
+ m_Log.Error(new Context(LogLevel.Error, $"Disabling instance: ").AddTag("Disable").AddTag("Additional Instance").AddInfo("Instance", name));
gameObject.SetActive(false);
return;
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Configuration/CommandLineOptions.cs b/com.unity.netcode.gameobjects/Runtime/Configuration/CommandLineOptions.cs
index c6f9b4a222..67878b125a 100644
--- a/com.unity.netcode.gameobjects/Runtime/Configuration/CommandLineOptions.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Configuration/CommandLineOptions.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using UnityEngine;
namespace Unity.Netcode
{
@@ -13,6 +12,7 @@ public class CommandLineOptions
///
/// Command-line options singleton
///
+ [Obsolete("Not used anymore replaced by TryGetArg")]
public static CommandLineOptions Instance
{
get
@@ -30,34 +30,41 @@ private set
}
private static CommandLineOptions s_Instance;
- [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
- private static void RuntimeInitializeOnLoad() => Instance = new CommandLineOptions();
-
// Contains the current application instance domain's command line arguments
- internal static List CommandLineArguments = new List();
-
- // Invoked upon application start, after scene load
- [RuntimeInitializeOnLoadMethod]
- private static void ParseCommandLineArguments()
- {
- // Get all the command line arguments to be parsed later and/or modified
- // prior to being parsed (for testing purposes).
- CommandLineArguments = new List(Environment.GetCommandLineArgs());
- }
+ private static readonly List k_CommandLineArguments = new List(Environment.GetCommandLineArgs());
///
- /// Returns the value of an argument or null if there the argument is not present
+ /// Returns the value of an argument or null if the argument is not present
///
/// The name of the argument
/// Value of the command line argument passed in.
+ [Obsolete("Not used anymore replaced by TryGetArg")]
public string GetArg(string arg)
{
- var argIndex = CommandLineArguments.IndexOf(arg);
- if (argIndex >= 0 && argIndex < CommandLineArguments.Count - 1)
+ var argIndex = k_CommandLineArguments.IndexOf(arg);
+ if (argIndex >= 0 && argIndex < k_CommandLineArguments.Count - 1)
{
- return CommandLineArguments[argIndex + 1];
+ return k_CommandLineArguments[argIndex + 1];
}
return null;
}
+
+ ///
+ /// Returns true if the argument was found.
+ ///
+ /// The name of the argument to look up.
+ /// The argument's value, or if not found.
+ /// true if the argument was found; otherwise false.
+ public static bool TryGetArg(string arg, out string argValue)
+ {
+ var argIndex = k_CommandLineArguments.IndexOf(arg);
+ if (argIndex >= 0 && argIndex < k_CommandLineArguments.Count - 1)
+ {
+ argValue = k_CommandLineArguments[argIndex + 1];
+ return true;
+ }
+ argValue = null;
+ return false;
+ }
}
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConstants.cs b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConstants.cs
index b9eed28790..bc862c8fe2 100644
--- a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConstants.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConstants.cs
@@ -5,6 +5,6 @@ namespace Unity.Netcode
///
internal static class NetworkConstants
{
- internal const string PROTOCOL_VERSION = "15.0.0";
+ internal const string PROTOCOL_VERSION = "15.1.0";
}
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs
index c6f30d2835..b1c071e705 100644
--- a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs
@@ -166,6 +166,22 @@ public bool Validate(int index = -1)
return false;
}
+ if (networkObject.InScenePlaced)
+ {
+ if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
+ {
+ NetworkLog.LogWarning($"{NetworkPrefabHandler.PrefabDebugHelper(this)} InScenePlaced {nameof(NetworkObject)} is being registered as a Prefab. This can cause issues!");
+ }
+ }
+
+ if (networkObject.IsSpawned)
+ {
+ if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
+ {
+ NetworkLog.LogWarning($"{NetworkPrefabHandler.PrefabDebugHelper(this)} Currently spawned {nameof(NetworkObject)} is being registered as a Prefab. This can cause issues!");
+ }
+ }
+
return true;
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefabs.cs b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefabs.cs
index 45d93ad9d7..303055174f 100644
--- a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefabs.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefabs.cs
@@ -47,22 +47,110 @@ public class NetworkPrefabs
[NonSerialized]
private List m_Prefabs = new List();
+ ///
+ /// Returns the last registered prefab.
+ ///
+ internal NetworkPrefab GetLastRegisteredPrefab()
+ {
+ if (m_Prefabs.Count == 0)
+ {
+ return null;
+ }
+ return m_Prefabs[m_Prefabs.Count - 1];
+ }
+
+ ///
+ /// Applies a network prefab at a specific index
+ ///
+ /// index to apply
+ /// network prefab to be applied
+ ///
+ internal bool AssignPrefabAtIndex(int index, NetworkPrefab networkPrefab)
+ {
+ if (index >= m_Prefabs.Count)
+ {
+ NetworkManager.Singleton.Log.Error(new Logging.Context(LogLevel.Normal, $"[{nameof(NetworkPrefabs)}][{nameof(AssignPrefabAtIndex)}] Cannot apply prefab to index {index} when the {nameof(m_Prefabs)} count is only {m_Prefabs.Count}!"));
+ return false;
+ }
+ m_Prefabs[index] = networkPrefab;
+ return true;
+ }
+
+ [NonSerialized]
+ private Dictionary m_PrefabHashIds = new Dictionary();
+
[NonSerialized]
private List m_RuntimeAddedPrefabs = new List();
- private void AddTriggeredByNetworkPrefabList(NetworkPrefab networkPrefab)
+ private bool InternalAddPrefab(NetworkPrefab networkPrefab)
{
if (AddPrefabRegistration(networkPrefab))
{
// Don't add this to m_RuntimeAddedPrefabs
// This prefab is now in the PrefabList, so if we shutdown and initialize again, we'll pick it up from there.
m_Prefabs.Add(networkPrefab);
+
+ // We are not getting all potential overrides but just determining if the prefab has been registered.
+ if (!m_PrefabHashIds.ContainsKey(networkPrefab.SourcePrefabGlobalObjectIdHash))
+ {
+ m_PrefabHashIds.Add(networkPrefab.SourcePrefabGlobalObjectIdHash, networkPrefab);
+ }
+ if (!m_PrefabHashIds.ContainsKey(networkPrefab.TargetPrefabGlobalObjectIdHash))
+ {
+ m_PrefabHashIds.Add(networkPrefab.TargetPrefabGlobalObjectIdHash, networkPrefab);
+ }
+ return true;
}
+ return false;
}
- private void RemoveTriggeredByNetworkPrefabList(NetworkPrefab networkPrefab)
+ private void InternalRemovePrefab(NetworkPrefab networkPrefab)
{
m_Prefabs.Remove(networkPrefab);
+ m_PrefabHashIds.Remove(networkPrefab.SourcePrefabGlobalObjectIdHash);
+ }
+
+ internal bool IsBasedOnRegisteredPrefab(NetworkObject networkObject)
+ {
+
+
+ return m_PrefabHashIds.ContainsKey(networkObject.GlobalObjectIdHash);
+ }
+
+ internal bool IsActualPrefabAsset(NetworkObject networkObject)
+ {
+ var isActualPrefabAsset = false;
+ if (m_PrefabHashIds.TryGetValue(networkObject.GlobalObjectIdHash, out NetworkPrefab networkPrefab))
+ {
+ switch (networkPrefab.Override)
+ {
+ case NetworkPrefabOverride.Prefab:
+ case NetworkPrefabOverride.None:
+ {
+ isActualPrefabAsset = networkPrefab.Prefab != null && networkObject.gameObject == networkPrefab.Prefab;
+ break;
+ }
+ case NetworkPrefabOverride.Hash:
+ {
+ isActualPrefabAsset = networkPrefab.SourceHashToOverride == networkObject.GlobalObjectIdHash;
+ break;
+ }
+ }
+ }
+ return isActualPrefabAsset;
+ }
+
+ private void AddTriggeredByNetworkPrefabList(NetworkPrefab networkPrefab)
+ {
+ // Don't add this to m_RuntimeAddedPrefabs
+ // This prefab is now in the PrefabList, so if we shutdown and initialize again, we'll pick it up from there.
+ InternalAddPrefab(networkPrefab);
+ // Log warning if this returns false?
+ }
+
+ private void RemoveTriggeredByNetworkPrefabList(NetworkPrefab networkPrefab)
+ {
+ InternalRemovePrefab(networkPrefab);
}
///
@@ -93,6 +181,7 @@ internal void Shutdown()
/// When true, logs warnings about invalid prefabs that are removed during initialization
public void Initialize(bool warnInvalid = true)
{
+ m_PrefabHashIds.Clear();
m_Prefabs.Clear();
NetworkPrefabsLists.RemoveAll(x => x == null);
foreach (var list in NetworkPrefabsLists)
@@ -113,7 +202,7 @@ public void Initialize(bool warnInvalid = true)
prefabs.AddRange(list.PrefabList);
}
}
-
+ m_PrefabHashIds = new Dictionary();
m_Prefabs = new List();
List removeList = null;
@@ -124,11 +213,7 @@ public void Initialize(bool warnInvalid = true)
foreach (var networkPrefab in prefabs)
{
- if (AddPrefabRegistration(networkPrefab))
- {
- m_Prefabs.Add(networkPrefab);
- }
- else
+ if (!InternalAddPrefab(networkPrefab))
{
removeList?.Add(networkPrefab);
}
@@ -136,11 +221,7 @@ public void Initialize(bool warnInvalid = true)
foreach (var networkPrefab in m_RuntimeAddedPrefabs)
{
- if (AddPrefabRegistration(networkPrefab))
- {
- m_Prefabs.Add(networkPrefab);
- }
- else
+ if (!InternalAddPrefab(networkPrefab))
{
removeList?.Add(networkPrefab);
}
@@ -171,14 +252,12 @@ public void Initialize(bool warnInvalid = true)
///
public bool Add(NetworkPrefab networkPrefab)
{
- if (AddPrefabRegistration(networkPrefab))
+ var added = InternalAddPrefab(networkPrefab);
+ if (added)
{
- m_Prefabs.Add(networkPrefab);
m_RuntimeAddedPrefabs.Add(networkPrefab);
- return true;
}
-
- return false;
+ return added;
}
///
@@ -197,8 +276,7 @@ public void Remove(NetworkPrefab prefab)
{
throw new ArgumentNullException(nameof(prefab));
}
-
- m_Prefabs.Remove(prefab);
+ InternalRemovePrefab(prefab);
m_RuntimeAddedPrefabs.Remove(prefab);
OverrideToNetworkPrefab.Remove(prefab.TargetPrefabGlobalObjectIdHash);
NetworkPrefabOverrideLinks.Remove(prefab.SourcePrefabGlobalObjectIdHash);
@@ -294,14 +372,12 @@ private bool AddPrefabRegistration(NetworkPrefab networkPrefab)
uint source = networkPrefab.SourcePrefabGlobalObjectIdHash;
uint target = networkPrefab.TargetPrefabGlobalObjectIdHash;
-
// Make sure the prefab isn't already registered.
if (NetworkPrefabOverrideLinks.ContainsKey(source))
{
- var networkObject = networkPrefab.Prefab.GetComponent();
-
+ var nameOrHashOverride = networkPrefab.Override == NetworkPrefabOverride.Hash ? $"Hash: {networkPrefab.SourcePrefabGlobalObjectIdHash}" : networkPrefab.Prefab?.name;
// This should never happen, but in the case it somehow does log an error and remove the duplicate entry
- Debug.LogError($"{nameof(NetworkPrefab)} ({networkObject.name}) has a duplicate {nameof(NetworkObject.GlobalObjectIdHash)} source entry value of: {source}!");
+ Debug.LogError($"{nameof(NetworkPrefab)} ({nameOrHashOverride}) has a duplicate {nameof(NetworkObject.GlobalObjectIdHash)} source entry value of: {source}!");
return false;
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs
index aaeb67f4db..3ff131131f 100644
--- a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs
@@ -96,7 +96,7 @@ public struct ConnectionEventData
///
public sealed class NetworkConnectionManager
{
-#if DEVELOPMENT_BUILD || UNITY_EDITOR
+#if DEBUG
private static ProfilerMarker s_TransportPollMarker = new ProfilerMarker($"{nameof(NetworkManager)}.TransportPoll");
private static ProfilerMarker s_TransportConnect = new ProfilerMarker($"{nameof(NetworkManager)}.TransportConnect");
private static ProfilerMarker s_HandleIncomingData = new ProfilerMarker($"{nameof(NetworkManager)}.{nameof(NetworkMessageManager.HandleIncomingData)}");
@@ -438,7 +438,7 @@ private ulong GetServerTransportId()
internal void PollAndHandleNetworkEvents()
{
-#if DEVELOPMENT_BUILD || UNITY_EDITOR
+#if DEBUG
s_TransportPollMarker.Begin();
#endif
NetworkEvent networkEvent;
@@ -453,7 +453,7 @@ internal void PollAndHandleNetworkEvents()
// Only do another iteration if: there are no more messages AND (there is no limit to max events or we have processed less than the maximum)
} while (NetworkManager.IsListening && networkEvent != NetworkEvent.Nothing);
-#if DEVELOPMENT_BUILD || UNITY_EDITOR
+#if DEBUG
s_TransportPollMarker.End();
#endif
}
@@ -501,7 +501,7 @@ internal void HandleNetworkEvent(NetworkEvent networkEvent, ulong transportClien
///
internal void ConnectEventHandler(ulong transportId)
{
-#if DEVELOPMENT_BUILD || UNITY_EDITOR
+#if DEBUG
s_TransportConnect.Begin();
#endif
// Assumptions:
@@ -522,6 +522,9 @@ internal void ConnectEventHandler(ulong transportId)
{
NetworkLog.LogError($"[TransportApproval][Server] TransportId {transportId} is already connected to this server!");
}
+#if DEBUG
+ s_TransportConnect.End();
+#endif
return;
}
@@ -536,6 +539,9 @@ internal void ConnectEventHandler(ulong transportId)
{
NetworkLog.LogError("[TransportApproval][Client] Client received a transport connection event after already connecting!");
}
+#if DEBUG
+ s_TransportConnect.End();
+#endif
return;
}
@@ -571,7 +577,7 @@ internal void ConnectEventHandler(ulong transportId)
StartClientApprovalCoroutine(clientId);
}
-#if DEVELOPMENT_BUILD || UNITY_EDITOR
+#if DEBUG
s_TransportConnect.End();
#endif
}
@@ -581,7 +587,7 @@ internal void ConnectEventHandler(ulong transportId)
///
internal void DataEventHandler(ulong transportClientId, ref ArraySegment payload, float receiveTime)
{
-#if DEVELOPMENT_BUILD || UNITY_EDITOR
+#if DEBUG
s_HandleIncomingData.Begin();
#endif
var (clientId, isConnectedClient) = TransportIdToClientId(transportClientId);
@@ -590,7 +596,7 @@ internal void DataEventHandler(ulong transportClientId, ref ArraySegment p
MessageManager.HandleIncomingData(clientId, payload, receiveTime);
}
-#if DEVELOPMENT_BUILD || UNITY_EDITOR
+#if DEBUG
s_HandleIncomingData.End();
#endif
}
@@ -633,7 +639,7 @@ internal void DisconnectEventHandler(ulong transportClientId)
return;
}
-#if DEVELOPMENT_BUILD || UNITY_EDITOR
+#if DEBUG
s_TransportDisconnect.Begin();
#endif
@@ -692,7 +698,7 @@ internal void DisconnectEventHandler(ulong transportClientId)
NetworkManager.Shutdown(true);
}
}
-#if DEVELOPMENT_BUILD || UNITY_EDITOR
+#if DEBUG
s_TransportDisconnect.End();
#endif
}
@@ -961,8 +967,7 @@ internal void ProcessClientsToDisconnect()
{
return (true, playerPrefabHash.Value);
}
- else
- if (NetworkManager.NetworkConfig.PlayerPrefab != null)
+ else if (NetworkManager.NetworkConfig.PlayerPrefab != null)
{
var networkObject = NetworkManager.NetworkConfig.PlayerPrefab.GetComponent();
if (networkObject != null)
@@ -1184,7 +1189,11 @@ internal void CreateAndSpawnPlayer(ulong ownerId)
return;
}
- networkObject.IsSceneObject = false;
+#pragma warning disable CS0618 // Type or member is obsolete
+ // Obsolete with warning means we need the underlying behaviour to keep existing
+ // TODO: remove in the 3.x branch
+ networkObject.SetSceneObjectStatus(false);
+#pragma warning restore CS0618 // Type or member is obsolete
networkObject.NetworkManagerOwner = NetworkManager;
networkObject.SpawnAsPlayerObject(ownerId, networkObject.DestroyWithScene);
}
@@ -1208,7 +1217,7 @@ internal void ApprovedPlayerSpawn(ulong clientId, uint playerPrefabHash)
var message = new CreateObjectMessage
{
- ObjectInfo = ConnectedClients[clientId].PlayerObject.Serialize(clientPair.Key),
+ ObjectInfo = ConnectedClients[clientId].PlayerObject.SerializeSpawnedObject(clientPair.Key),
IncludesSerializedObject = true,
};
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/ComponentFactory.cs b/com.unity.netcode.gameobjects/Runtime/Core/ComponentFactory.cs
index 52945c4e46..6733429ee2 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/ComponentFactory.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/ComponentFactory.cs
@@ -14,6 +14,10 @@ internal static class ComponentFactory
internal delegate object CreateObjectDelegate(NetworkManager networkManager);
private static Dictionary s_Delegates = new Dictionary();
+#if UNITY_EDITOR
+ [UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)]
+ private static void ResetStaticsOnLoad() => s_Delegates = new Dictionary();
+#endif
///
/// Instantiates an instance of a given interface
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/FindObjects.cs b/com.unity.netcode.gameobjects/Runtime/Core/FindObjects.cs
index a283cabe52..109d40f4d3 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/FindObjects.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/FindObjects.cs
@@ -1,7 +1,8 @@
-#if NGO_FINDOBJECTS_NOSORTING
using System;
-#endif
+using System.Collections;
+using System.Collections.Generic;
using System.Runtime.CompilerServices;
+using UnityEngine.SceneManagement;
using Object = UnityEngine.Object;
namespace Unity.Netcode
@@ -11,14 +12,14 @@ namespace Unity.Netcode
///
///
/// It is intentional that we do not include the UnityEngine namespace in order to avoid
- /// over-complicatd define wrapping between versions that do or don't support FindObjectsSortMode.
+ /// over-complicated define wrapping between versions that do or don't support FindObjectsSortMode.
///
internal static class FindObjects
{
///
/// Replaces to have one place where these changes are applied.
///
- ///
+ /// The type of object to find. Must be a reference type derived from
/// When true, inactive objects will be included.
/// When true, the array returned will be sorted by identifier.
/// Results as an of type T
@@ -39,5 +40,90 @@ public static T[] ByType(bool includeInactive = false, bool orderByIdentifier
#endif
return results;
}
+
+ ///
+ /// Returns an enumerator that enumerates over all the components of a given type in a scene.
+ ///
+ /// The scene to use for searching
+ /// When true, inactive objects will be included.
+ /// Type of to get from the scene
+ /// a generator that yields successive NetworkObjects in the current scene
+ public static IEnumerable FromSceneByType(Scene scene, bool includeInactive) where T : UnityEngine.Component
+ {
+ return new ObjectsInSceneEnumerator(scene, includeInactive);
+ }
+
+ ///
+ /// An Enumerator that enumerates over each component of type in the given scene.
+ ///
+ /// Type of to get from the scene
+ private struct ObjectsInSceneEnumerator : IEnumerable, IEnumerator where T : UnityEngine.Component
+ {
+ private readonly UnityEngine.GameObject[] m_RootObjects;
+ private int m_RootIndex;
+ private T[] m_CurrentChildObjects;
+ private int m_CurrentChildIndex;
+
+ private readonly bool m_IncludeInactive;
+
+ internal ObjectsInSceneEnumerator(Scene scene, bool includeInactive)
+ {
+ m_IncludeInactive = includeInactive;
+ // If the scene is invalid, use an empty array.
+ m_RootObjects = scene.IsValid() ? scene.GetRootGameObjects() : new UnityEngine.GameObject[0];
+ m_RootIndex = 0;
+ m_CurrentChildObjects = null;
+ m_CurrentChildIndex = 0;
+ Current = null;
+ }
+
+ public void Dispose() { }
+
+ public bool MoveNext()
+ {
+ while (m_CurrentChildObjects == null && m_RootIndex < m_RootObjects.Length)
+ {
+ m_CurrentChildObjects = m_RootObjects[m_RootIndex].GetComponentsInChildren(m_IncludeInactive);
+ m_RootIndex++;
+
+ if (m_CurrentChildObjects.Length == 0)
+ {
+ m_CurrentChildObjects = null;
+ }
+ }
+
+ if (m_CurrentChildObjects != null && m_CurrentChildIndex < m_CurrentChildObjects.Length)
+ {
+ Current = m_CurrentChildObjects[m_CurrentChildIndex];
+ m_CurrentChildIndex++;
+
+ if (m_CurrentChildIndex >= m_CurrentChildObjects.Length)
+ {
+ m_CurrentChildIndex = 0;
+ m_CurrentChildObjects = null;
+ }
+ return true;
+ }
+
+ Current = null;
+ return false;
+ }
+
+ public void Reset()
+ {
+ m_RootIndex = 0;
+ m_CurrentChildObjects = null;
+ m_CurrentChildIndex = 0;
+ Current = null;
+ }
+
+ object IEnumerator.Current => Current;
+
+ public T Current { get; private set; }
+
+ public IEnumerator GetEnumerator() => this;
+
+ IEnumerator IEnumerable.GetEnumerator() => this;
+ }
}
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs
index 59f9e637b6..16b6d3be62 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs
@@ -43,7 +43,7 @@ public abstract class NetworkBehaviour : MonoBehaviour
internal static readonly Dictionary> __rpc_func_table = new Dictionary>();
internal static readonly Dictionary> __rpc_permission_table = new Dictionary>();
-#if MULTIPLAYER_TOOLS && (DEVELOPMENT_BUILD || UNITY_EDITOR || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE)
+#if MULTIPLAYER_TOOLS && (DEBUG || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE)
// RuntimeAccessModifiersILPP will make this `public`
internal static readonly Dictionary> __rpc_name_table = new Dictionary>();
#endif
@@ -145,7 +145,7 @@ internal void __endSendServerRpc(ref FastBufferWriter bufferWriter, uint rpcMeth
bufferWriter.Dispose();
-#if MULTIPLAYER_TOOLS && (DEVELOPMENT_BUILD || UNITY_EDITOR || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE)
+#if MULTIPLAYER_TOOLS && (DEBUG || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE)
TrackRpcMetricsSend(ref serverRpcMessage, rpcMethodId, rpcWriteSize);
#endif
}
@@ -269,7 +269,7 @@ internal void __endSendClientRpc(ref FastBufferWriter bufferWriter, uint rpcMeth
}
bufferWriter.Dispose();
-#if MULTIPLAYER_TOOLS && (DEVELOPMENT_BUILD || UNITY_EDITOR || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE)
+#if MULTIPLAYER_TOOLS && (DEBUG || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE)
if (!ValidateRpcMessageMetrics(GetType()))
{
return;
@@ -1002,12 +1002,12 @@ internal void __registerRpc(uint hash, RpcReceiveHandler handler, string rpcMeth
var rpcType = GetType();
__rpc_func_table[rpcType][hash] = handler;
__rpc_permission_table[rpcType][hash] = permission;
-#if MULTIPLAYER_TOOLS && (DEVELOPMENT_BUILD || UNITY_EDITOR || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE)
+#if MULTIPLAYER_TOOLS && (DEBUG || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE)
__rpc_name_table[rpcType][hash] = rpcMethodName;
#endif
}
-#if MULTIPLAYER_TOOLS && (DEVELOPMENT_BUILD || UNITY_EDITOR || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE)
+#if MULTIPLAYER_TOOLS && (DEBUG || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool ValidateRpcMessageMetrics(Type type)
{
@@ -1125,7 +1125,7 @@ internal void InitializeVariables()
{
__rpc_func_table[GetType()] = new Dictionary();
__rpc_permission_table[GetType()] = new Dictionary();
-#if MULTIPLAYER_TOOLS && (DEVELOPMENT_BUILD || UNITY_EDITOR || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE)
+#if MULTIPLAYER_TOOLS && (DEBUG || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE)
__rpc_name_table[GetType()] = new Dictionary();
#endif
__initializeRpcs();
@@ -1299,8 +1299,6 @@ internal void NetworkVariableUpdate(ulong targetClientId, bool forceSend = false
}
}
- internal static bool LogSentVariableUpdateMessage;
-
private bool CouldHaveDirtyNetworkVariables()
{
// TODO: There should be a better way by reading one dirty variable vs. 'n'
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviourUpdater.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviourUpdater.cs
index 4f12bca033..871c8afb7d 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviourUpdater.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviourUpdater.cs
@@ -27,7 +27,7 @@ public class NetworkBehaviourUpdater
///
private HashSet m_PendingDirtyNetworkObjects = new HashSet();
-#if DEVELOPMENT_BUILD || UNITY_EDITOR
+#if DEBUG
private ProfilerMarker m_NetworkBehaviourUpdate = new ProfilerMarker($"{nameof(NetworkBehaviour)}.{nameof(NetworkBehaviourUpdate)}");
#endif
@@ -190,7 +190,7 @@ internal void ProcessDirtyObject(NetworkObject networkObject, bool forceSend)
/// Refer to the definition.
internal void NetworkBehaviourUpdate(bool forceSend = false)
{
-#if DEVELOPMENT_BUILD || UNITY_EDITOR
+#if DEBUG
m_NetworkBehaviourUpdate.Begin();
#endif
try
@@ -214,7 +214,7 @@ internal void NetworkBehaviourUpdate(bool forceSend = false)
}
finally
{
-#if DEVELOPMENT_BUILD || UNITY_EDITOR
+#if DEBUG
m_NetworkBehaviourUpdate.End();
#endif
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
index b9a2c15789..453f10b88f 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
@@ -21,6 +21,20 @@ namespace Unity.Netcode
[HelpURL(HelpUrls.NetworkManager)]
public class NetworkManager : MonoBehaviour, INetworkUpdateSystem
{
+#if UNITY_EDITOR
+ [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
+ private static void ResetStaticsOnLoad()
+ {
+ Singleton = null;
+ OnInstantiated = null;
+ OnDestroying = null;
+ OnSingletonReady = null;
+ OnNetworkManagerReset = null;
+ IsDistributedAuthority = false;
+ s_SerializedType = new List();
+ DisableNotOptimizedSerializedType = false;
+ }
+#endif
///
/// Subscribe to this static event to get notifications when a instance has been instantiated.
///
@@ -31,7 +45,6 @@ public class NetworkManager : MonoBehaviour, INetworkUpdateSystem
///
public static event Action OnDestroying;
-
#if UNITY_EDITOR
// Inspector view expand/collapse settings for this derived child class
[HideInInspector]
@@ -44,17 +57,20 @@ public class NetworkManager : MonoBehaviour, INetworkUpdateSystem
#pragma warning disable IDE1006 // disable naming rule violation check
// RuntimeAccessModifiersILPP will make this `public`
+ [Obsolete("This field is no longer used and will be removed in a future version.")]
internal delegate void RpcReceiveHandler(NetworkBehaviour behaviour, FastBufferReader reader, __RpcParams parameters);
// RuntimeAccessModifiersILPP will make this `public`
+ [Obsolete("This field is no longer used and will be removed in a future version.")]
internal static readonly Dictionary __rpc_func_table = new Dictionary();
// RuntimeAccessModifiersILPP will make this `public` (legacy table should be removed in v3.x.x)
+ [Obsolete("This field is no longer used and will be removed in a future version.")]
internal static readonly Dictionary __rpc_name_table = new Dictionary();
#pragma warning restore IDE1006 // restore naming rule violation check
-#if DEVELOPMENT_BUILD || UNITY_EDITOR
+#if DEBUG
private static List s_SerializedType = new List();
// This is used to control the serialized type not optimized messaging for integration test purposes
internal static bool DisableNotOptimizedSerializedType;
@@ -1013,7 +1029,7 @@ internal bool NetworkManagerCheckForParent(bool ignoreNetworkManagerCache = fals
var isParented = transform.root != transform;
if (isParented)
{
- throw new Exception(GenerateNestedNetworkManagerMessage(transform));
+ Log.Error(new Context(LogLevel.Error, GenerateNestedNetworkManagerMessage(transform)));
}
#endif
return isParented;
@@ -1160,7 +1176,7 @@ public int MaximumFragmentedMessageSize
internal void Initialize(bool server)
{
-#if DEVELOPMENT_BUILD || UNITY_EDITOR
+#if DEBUG
if (!DisableNotOptimizedSerializedType)
{
s_SerializedType.Clear();
@@ -1223,7 +1239,7 @@ internal void Initialize(bool server)
MessageManager.Hook(new NetworkManagerHooks(this));
-#if DEVELOPMENT_BUILD || UNITY_EDITOR
+#if DEBUG
if (NetworkConfig.NetworkProfilingMetrics)
{
MessageManager.Hook(new ProfilingHooks());
@@ -1641,7 +1657,7 @@ internal void ShutdownInternal()
// place (i.e. sending any last state updates or the like).
SpawnManager?.DespawnAndDestroyNetworkObjects();
- SpawnManager?.ServerResetShudownStateForSceneObjects();
+ SpawnManager?.ServerResetShutdownStateForSceneObjects();
////
RpcTarget?.Dispose();
@@ -1797,6 +1813,10 @@ internal abstract class NetcodeAnalytics
internal static ResetNetworkManagerDelegate OnNetworkManagerReset;
+
+ ///
+ /// This is called by the Unity Editor reset button. See which is handled in "NetworkManagerHelper.cs".
+ ///
private void Reset()
{
OnNetworkManagerReset?.Invoke(this);
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
index d2f5aa5869..4c42f83a30 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
@@ -1,17 +1,15 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using Unity.Netcode.Components;
+using Unity.Netcode.Logging;
using Unity.Netcode.Runtime;
#if UNITY_EDITOR
using UnityEditor;
-#if UNITY_2021_2_OR_NEWER
using UnityEditor.SceneManagement;
-#else
-using UnityEditor.Experimental.SceneManagement;
-#endif
#endif
using UnityEngine;
using UnityEngine.SceneManagement;
@@ -105,6 +103,9 @@ public uint PrefabIdHash
///
public NetworkObject CurrentParent { get; private set; }
+ private int m_SpawnCount;
+ internal bool HasBeenSpawned => m_SpawnCount > 0;
+
#if UNITY_EDITOR
private const string k_GlobalIdTemplate = "GlobalObjectId_V1-{0}-{1}-{2}-{3}";
@@ -128,9 +129,6 @@ public uint PrefabIdHash
// The InContext or InIsolation edit mode network prefab scene instance of the prefab asset (s_PrefabAsset).
private static NetworkObject s_PrefabInstance;
- private static bool s_DebugPrefabIdGeneration;
-
-
[ContextMenu("Refresh In-Scene Prefab Instances")]
internal void RefreshAllPrefabInstances()
{
@@ -291,7 +289,7 @@ internal void OnValidate()
if (GlobalObjectIdHash != oldValue)
{
// Check if this is an in-scnee placed NetworkObject (Special Case for In-Scene Placed).
- if (IsSceneObject.HasValue && IsSceneObject.Value)
+ if (InScenePlaced)
{
// Sanity check to make sure this is a scene placed object.
if (globalId.identifierType != k_SceneObjectType)
@@ -327,7 +325,7 @@ internal void OnValidate()
///
private void CheckForInScenePlaced()
{
- if (gameObject.scene.IsValid() && gameObject.scene.isLoaded && gameObject.scene.buildIndex >= 0)
+ if (gameObject.scene.IsValid() && gameObject.scene.buildIndex >= 0)
{
if (PrefabUtility.IsPartOfAnyPrefab(this))
{
@@ -340,14 +338,43 @@ private void CheckForInScenePlaced()
EditorUtility.SetDirty(this);
}
}
- IsSceneObject = true;
+
+#pragma warning disable CS0618 // Type or member is obsolete
+ // Obsolete with warning means we need the underlying behaviour to keep existing
+ // TODO-3.x: remove in the 3.x branch
+ SetSceneObjectStatus(true);
+#pragma warning restore CS0618 // Type or member is obsolete
+
+ // We go ahead and set this for "typical in-scene placed" usage patterns so this is serialized
+ InScenePlaced = true;
// Default scene migration synchronization to false for in-scene placed NetworkObjects
SceneMigrationSynchronization = false;
+
+ // Set our disabled in-scene placed flag for spawning initially disabled in-scene placed objects.
+ m_InScenePlacedDisabledByDefault = !gameObject.activeInHierarchy;
}
}
#endif // UNITY_EDITOR
+ ///
+ /// This is intentionally private since this is a sealed class.
+ ///
+ private void Awake()
+ {
+ SetCachedParent(transform.parent);
+ SceneOrigin = gameObject.scene;
+ }
+
+ ///
+ /// Used to provide support for initially disabled in-scene placed objects.
+ /// This is only ever set on in-scene placed objects that are already disabled
+ /// in the scene asset itself.
+ ///
+ [HideInInspector]
+ [SerializeField]
+ private bool m_InScenePlacedDisabledByDefault;
+
///
/// Gets the NetworkManager that owns this NetworkObject instance
///
@@ -411,7 +438,7 @@ public void DeferDespawn(int tickOffset, bool destroy = true)
return;
}
- if (!HasAuthority)
+ if (!m_HasAuthority)
{
if (NetworkManagerOwner.LogLevel <= LogLevel.Error)
{
@@ -628,7 +655,7 @@ public bool SetOwnershipLock(bool lockOwnership = true)
}
// If we don't have authority exit early
- if (!HasAuthority)
+ if (!m_HasAuthority)
{
if (NetworkManager.LogLevel <= LogLevel.Error)
{
@@ -904,7 +931,7 @@ internal void OwnershipRequest(ulong clientRequestingOwnership)
// This action is always authorized as long as the client still has authority.
// We need to pass in that this is a request approval ownership change.
- NetworkManagerOwner.SpawnManager.ChangeOwnership(this, clientRequestingOwnership, HasAuthority, true);
+ NetworkManagerOwner.SpawnManager.ChangeOwnership(this, clientRequestingOwnership, m_HasAuthority, true);
}
else
{
@@ -1150,14 +1177,9 @@ public bool HasOwnershipStatus(OwnershipStatus status)
///
/// When in client-server mode, authority should is not considered the same as ownership.
///
- public bool HasAuthority => InternalHasAuthority();
+ public bool HasAuthority => IsSpawned ? m_HasAuthority : !NetworkManager.DistributedAuthorityMode && NetworkManager.IsServer;
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private bool InternalHasAuthority()
- {
- var networkManager = NetworkManager;
- return networkManager.DistributedAuthorityMode ? OwnerClientId == networkManager.LocalClientId : networkManager.IsServer;
- }
+ private bool m_HasAuthority;
///
/// The NetworkManager that owns this NetworkObject.
@@ -1225,15 +1247,51 @@ private bool InternalHasAuthority()
public bool IsSpawned { get; internal set; }
///
- /// Gets if the object is a SceneObject, null if it's not yet spawned but is a scene object.
+ /// Gets if the object is a SceneObject.
///
+ ///
+ /// This method is marked for deprecation.
+ /// Use instead.
+ ///
+ [Obsolete("Use InScenePlaced instead")]
public bool? IsSceneObject { get; internal set; }
- //DANGOEXP TODO: Determine if we want to keep this
+
+ ///
+ /// The serialized value.
+ ///
+ [field: HideInInspector]
+ [field: SerializeField]
+ private bool m_InScenePlaced;
+
+ ///
+ /// True if this object is placed in a scene; false otherwise.
+ ///
+ public bool InScenePlaced
+ {
+ get
+ {
+ return m_InScenePlaced;
+ }
+ internal set
+ {
+ m_InScenePlaced = value;
+ }
+ }
+
+ ///
+ /// This provides a means to determine if the post processing had applied
+ /// the in-scene placed status or if it was already serialized. This is used
+ /// when determining if the thing being spawned is a valid thing to spawn.
+ ///
+ internal bool InScenePlacedPostProcessorMarkedDuringRuntime;
+
///
/// Sets whether this NetworkObject was instantiated as part of a scene
///
+ /// Only use this when using custom scene loading
/// When true, marks this as a scene-instantiated object; when false, marks it as runtime-instantiated
+ [Obsolete("SetSceneObjectStatus is now calculated during the build.")]
public void SetSceneObjectStatus(bool isSceneObject = false)
{
IsSceneObject = isSceneObject;
@@ -1434,19 +1492,20 @@ public bool IsNetworkVisibleTo(ulong clientId)
///
internal Scene SceneOrigin
{
- get
- {
- return m_SceneOrigin;
- }
+ get => m_SceneOrigin;
set
{
+ if (SceneOriginHandle.IsEmpty() && value.IsValid() && value.isLoaded)
+ {
+ SceneOriginHandle = value.handle;
+ }
+
// The scene origin should only be set once.
// Once set, it should never change.
- if (SceneOriginHandle.IsEmpty() && value.IsValid() && value.isLoaded)
+ if (!m_SceneOrigin.IsValid())
{
m_SceneOrigin = value;
- SceneOriginHandle = value.handle;
}
}
}
@@ -1457,13 +1516,8 @@ internal Scene SceneOrigin
///
internal NetworkSceneHandle GetSceneOriginHandle()
{
- if (SceneOriginHandle.IsEmpty() && IsSpawned && IsSceneObject != false)
- {
- if (NetworkManager.LogLevel <= LogLevel.Error)
- {
- NetworkLog.LogErrorServer($"{nameof(GetSceneOriginHandle)} called when {nameof(SceneOriginHandle)} is still zero but the {nameof(NetworkObject)} is already spawned!");
- }
- }
+ NetworkLog.InternalAssert(!(IsSpawned && InScenePlaced && SceneOriginHandle.IsEmpty()), $"Spawned in scene placed NetworkObject {name} should always have a valid SceneOriginHandle");
+
return !SceneOriginHandle.IsEmpty() ? SceneOriginHandle : gameObject.scene.handle;
}
@@ -1492,7 +1546,7 @@ public void NetworkShow(ulong clientId)
return;
}
- if (!HasAuthority)
+ if (!m_HasAuthority)
{
if (NetworkManagerOwner.DistributedAuthorityMode)
{
@@ -1587,7 +1641,7 @@ public void NetworkHide(ulong clientId)
return;
}
- if (!HasAuthority)
+ if (!m_HasAuthority)
{
if (NetworkManagerOwner.DistributedAuthorityMode)
{
@@ -1622,7 +1676,7 @@ public void NetworkHide(ulong clientId)
var message = new DestroyObjectMessage
{
NetworkObjectId = NetworkObjectId,
- DestroyGameObject = !IsSceneObject.Value,
+ DestroyGameObject = !InScenePlaced,
IsDistributedAuthority = NetworkManagerOwner.DistributedAuthorityMode,
IsTargetedDestroy = NetworkManagerOwner.DistributedAuthorityMode,
TargetClientId = clientId, // Just always populate this value whether we write it or not
@@ -1727,6 +1781,8 @@ internal void SetIsDestroying()
private void OnDestroy()
{
+ SceneManager.activeSceneChanged -= CurrentlyActiveSceneChanged;
+
// Apply the is destroying flag
SetIsDestroying();
@@ -1744,13 +1800,13 @@ private void OnDestroy()
{
// An authorized destroy is when done by the authority instance or done due to a scene event and the NetworkObject
// was marked as destroy pending scene event (which means the destroy with scene property was set).
- var isAuthorityDestroy = HasAuthority || NetworkManager.DAHost || DestroyPendingSceneEvent;
+ var isAuthorityDestroy = m_HasAuthority || NetworkManager.DAHost || DestroyPendingSceneEvent;
// If the NetworkObject's GameObject is still valid and the scene is still valid and loaded, then we are still valid
var isStillValid = gameObject != null && gameObject.scene.IsValid() && gameObject.scene.isLoaded;
// If we're not the authority and everything is valid and dynamically spawned, then the destroy is not valid.
- if (!isAuthorityDestroy && IsSceneObject == false && isStillValid)
+ if (!isAuthorityDestroy && !InScenePlaced && isStillValid)
{
if (networkManager.LogLevel <= LogLevel.Error)
{
@@ -1778,7 +1834,7 @@ private void OnDestroy()
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void SpawnInternal(bool destroyWithScene, ulong ownerClientId, bool playerObject)
+ private void SpawnInternal(bool destroyWithScene, ulong ownerClientId, bool playerObject)
{
if (NetworkManagerOwner == null)
{
@@ -1849,7 +1905,37 @@ internal void SpawnInternal(bool destroyWithScene, ulong ownerClientId, bool pla
}
}
- if (!NetworkManagerOwner.SpawnManager.AuthorityLocalSpawn(this, NetworkManagerOwner.SpawnManager.GetNetworkObjectId(), IsSceneObject.HasValue && IsSceneObject.Value, playerObject, ownerClientId, destroyWithScene))
+ // Trap for runtime generated instances as this is not valid
+ if (GlobalObjectIdHash == 0)
+ {
+ NetworkManager.Log.ErrorServer(new Context(LogLevel.Error, $"Detected {nameof(NetworkObject)} {nameof(GlobalObjectIdHash)} value of 0!" +
+ $"This is typically a sign of runtime generated network prefab assets which are not supported.").AddNetworkObject(this));
+ return;
+ }
+
+ // Calculate the legacy IsSceneObject value as the public field is obsolete with warning
+ // We can't break the public behavior of the field.
+#pragma warning disable CS0618 // Type or member is obsolete
+ var legacyIsSceneObject = IsSceneObject.HasValue && IsSceneObject.Value;
+#pragma warning restore CS0618 // Type or member is obsolete
+
+ // If the initial state of the GameObject was disabled and InScenePlaced is marked,
+ // then spawn it as in-scene placed.
+ // Otherwise:
+ // If we are marked as in-scene place, have never been spawned, and the root GameObject
+ // was not disabled upon being instantiated, then treat this as a dynamically spawned
+ // instance.
+ if (InScenePlaced && !m_InScenePlacedDisabledByDefault && !HasBeenSpawned)
+ {
+ if (NetworkManagerOwner.NetworkConfig.EnableSceneManagement && NetworkManagerOwner.LogLevel <= LogLevel.Normal)
+ {
+ Debug.LogWarning($"[{name}][SceneOrigin={SceneOriginHandle}] Dynamically spawning InScenePlaced network object. This can cause issues!", this);
+ }
+
+ InScenePlaced = false;
+ }
+
+ if (!NetworkManagerOwner.SpawnManager.AuthorityLocalSpawn(this, NetworkManagerOwner.SpawnManager.GetNetworkObjectId(), legacyIsSceneObject, playerObject, ownerClientId, destroyWithScene))
{
if (NetworkManagerOwner.LogLevel <= LogLevel.Normal)
{
@@ -1989,8 +2075,7 @@ public NetworkObject InstantiateAndSpawn(NetworkManager networkManager, ulong ow
/// Should the object be destroyed when the scene is changed
public void Spawn(bool destroyWithScene = false)
{
- var networkManager = NetworkManager;
- var clientId = networkManager.DistributedAuthorityMode ? networkManager.LocalClientId : NetworkManager.ServerClientId;
+ var clientId = NetworkManager.DistributedAuthorityMode ? NetworkManager.LocalClientId : NetworkManager.ServerClientId;
SpawnInternal(destroyWithScene, clientId, false);
}
@@ -2042,10 +2127,72 @@ public void Despawn(bool destroy = true)
NetworkManagerOwner.SpawnManager.DespawnObject(this, destroy);
}
+ internal void SetupOnSpawn(ulong networkId, bool isPlayerObject, ulong ownerClientId, bool destroyWithScene)
+ {
+ NetworkObjectId = networkId;
+ IsPlayerObject = isPlayerObject;
+ OwnerClientId = ownerClientId;
+ // When spawned, previous owner is always the first assigned owner
+ PreviousOwnerId = ownerClientId;
+ m_HasAuthority = NetworkManagerOwner.DistributedAuthorityMode ? OwnerClientId == NetworkManagerOwner.LocalClientId : NetworkManagerOwner.IsServer;
+ m_SpawnCount++;
+ IsSpawned = true;
+
+ // If this is the player, and the client is the owner, then lock ownership by default
+ if (NetworkManagerOwner.DistributedAuthorityMode && NetworkManagerOwner.LocalClientId == ownerClientId && isPlayerObject)
+ {
+ AddOwnershipExtended(OwnershipStatusExtended.Locked);
+ }
+
+ if (IsSpawnAuthority)
+ {
+ SetupObservers();
+ }
+
+ /*
+ * Setup scene related settings
+ */
+ DestroyWithScene = InScenePlaced || destroyWithScene;
+ if (InScenePlaced)
+ {
+ // Always check to make sure our scene of origin is properly set for in-scene placed NetworkObjects
+ // Note: Always check SceneOriginHandle directly at this specific location.
+ if (SceneOriginHandle.IsEmpty())
+ {
+ SceneOrigin = gameObject.scene;
+ }
+
+ // If we are an in-scene placed NetworkObject and our InScenePlacedSourceGlobalObjectIdHash is set
+ // then assign this to the PrefabGlobalObjectIdHash
+ if (InScenePlacedSourceGlobalObjectIdHash != 0)
+ {
+ PrefabGlobalObjectIdHash = InScenePlacedSourceGlobalObjectIdHash;
+ }
+ }
+ else if (ActiveSceneSynchronization)
+ {
+ // Just in case it is a recycled NetworkObject, unsubscribe first
+ SceneManager.activeSceneChanged -= CurrentlyActiveSceneChanged;
+ SceneManager.activeSceneChanged += CurrentlyActiveSceneChanged;
+ }
+ }
+
+ ///
+ /// Resets this NetworkObject at the end of a session.
+ /// Ensures scene objects are ready to be reused
+ ///
+ internal void ResetOnShutdown()
+ {
+ NetworkLog.InternalAssert(NetworkManager.ShutdownInProgress, "This method should only be called while the NetworkManager is shutting down");
+ m_SpawnCount = 0;
+ ResetOnDespawn();
+ }
+
internal void ResetOnDespawn()
{
// Always clear out the observers list when despawned
Observers.Clear();
+ m_HasAuthority = false;
IsSpawnAuthority = false;
IsSpawned = false;
DeferredDespawnTick = 0;
@@ -2053,6 +2200,62 @@ internal void ResetOnDespawn()
RemoveOwnershipExtended(OwnershipStatusExtended.Locked | OwnershipStatusExtended.Requested);
}
+ internal void SetupObservers()
+ {
+ NetworkLog.InternalAssert(IsSpawnAuthority, "This function should only be called on the authority.");
+
+ if (!SpawnWithObservers)
+ {
+ if (NetworkManagerOwner.DistributedAuthorityMode)
+ {
+ // Always add the owner/authority in DA mode even if SpawnWithObservers is false
+ // (authority should not take into consideration networkObject.CheckObjectVisibility when SpawnWithObservers is false)
+ AddObserver(OwnerClientId);
+ }
+
+ return;
+ }
+
+ // If running as a server only, then make sure to always add the server's client identifier
+ if (NetworkManagerOwner.IsServer && !NetworkManagerOwner.IsHost)
+ {
+ AddObserver(NetworkManager.ServerClientId);
+ }
+
+ // If SpawnWithObservers is set,
+ // then add all connected clients as observers
+ foreach (var clientId in NetworkManagerOwner.ConnectedClientsIds)
+ {
+ // If CheckObjectVisibility has a callback, then allow that method determine who the observers are.
+ if (CheckObjectVisibility != null && !CheckObjectVisibility(clientId))
+ {
+ continue;
+ }
+ AddObserver(clientId);
+ }
+
+ // Intentionally checking as opposed to just assigning in order to generate notification.
+ if (!Observers.Contains(OwnerClientId))
+ {
+ // The owner only needs to always be included in DA mode.
+ if (NetworkManagerOwner.DistributedAuthorityMode)
+ {
+ if (NetworkManager.LogLevel <= LogLevel.Error)
+ {
+ NetworkLog.LogError($"Client-{OwnerClientId} is the owner of {name} but is not an observer! Adding owner as an observer!");
+ }
+ AddObserver(OwnerClientId);
+ }
+ else
+ {
+ if (NetworkManager.LogLevel <= LogLevel.Developer)
+ {
+ NetworkLog.LogWarning($"Client-{OwnerClientId} is the owner of {name} but is not an observer! This may cause issues");
+ }
+ }
+ }
+ }
+
///
/// Removes all ownership of an object from any client. Can only be called from server
///
@@ -2083,7 +2286,7 @@ public void ChangeOwnership(ulong newOwnerClientId)
}
return;
}
- NetworkManagerOwner.SpawnManager.ChangeOwnership(this, newOwnerClientId, HasAuthority);
+ NetworkManagerOwner.SpawnManager.ChangeOwnership(this, newOwnerClientId, m_HasAuthority);
}
///
@@ -2092,20 +2295,18 @@ public void ChangeOwnership(ulong newOwnerClientId)
///
internal void InvokeBehaviourOnOwnershipChanged(ulong originalOwnerClientId, ulong newOwnerClientId)
{
- if (!IsSpawned)
- {
- if (NetworkManager.LogLevel <= LogLevel.Error)
- {
- NetworkLog.LogErrorServer($"[{name}][Attempted behavior invoke on ownership changed before {nameof(NetworkObject)} was spawned]");
- }
- return;
- }
+ NetworkLog.InternalAssert(IsSpawned, "[{name}][Attempted behavior invoke on ownership changed before {nameof(NetworkObject)} was spawned]");
var distributedAuthorityMode = NetworkManagerOwner.DistributedAuthorityMode;
var isServer = NetworkManagerOwner.IsServer;
var isPreviousOwner = originalOwnerClientId == NetworkManagerOwner.LocalClientId;
var isNewOwner = newOwnerClientId == NetworkManagerOwner.LocalClientId;
+ if (distributedAuthorityMode)
+ {
+ m_HasAuthority = isNewOwner;
+ }
+
if (distributedAuthorityMode || isPreviousOwner)
{
NetworkManagerOwner.SpawnManager.UpdateOwnershipTable(this, originalOwnerClientId, true);
@@ -2318,7 +2519,7 @@ public bool TrySetParent(NetworkObject parent, bool worldPositionStays = true)
// DANGO-TODO: Do we want to worry about ownership permissions here?
// It wouldn't make sense to not allow parenting, but keeping this note here as a reminder.
- var isAuthority = HasAuthority || (AllowOwnerToParent && IsOwner);
+ var isAuthority = m_HasAuthority || (AllowOwnerToParent && IsOwner);
// If we don't have authority and we are not shutting down, then don't allow any parenting.
// If we are shutting down and don't have authority then allow it.
@@ -2393,7 +2594,7 @@ private void OnTransformParentChanged()
// With distributed authority, we need to track "valid authoritative" parenting changes.
// So, either the authority or AuthorityAppliedParenting is considered a "valid parenting change".
- var isParentingAuthority = HasAuthority || AuthorityAppliedParenting || (AllowOwnerToParent && IsOwner);
+ var isParentingAuthority = m_HasAuthority || AuthorityAppliedParenting || (AllowOwnerToParent && IsOwner);
// If we are spawned and don't have authority; reset the parent back to the cached parent and exit
if (!isParentingAuthority)
{
@@ -2506,6 +2707,10 @@ private void OnTransformParentChanged()
// If you couldn't find your parent, we put you into OrphanChildren set and every time we spawn another NetworkObject locally due to replication,
// we call CheckOrphanChildren() method and quickly iterate over OrphanChildren set and see if we can reparent/adopt one.
internal static HashSet OrphanChildren = new HashSet();
+#if UNITY_EDITOR
+ [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
+ private static void ResetStaticsOnLoad() => OrphanChildren = new HashSet();
+#endif
internal bool ApplyNetworkParenting(bool removeParent = false, bool ignoreNotSpawned = false, bool orphanedChildPass = false, bool enableNotification = true)
{
@@ -2528,8 +2733,7 @@ internal bool ApplyNetworkParenting(bool removeParent = false, bool ignoreNotSpa
// Handle the first in-scene placed NetworkObject parenting scenarios. Once the m_LatestParent
// has been set, this will not be entered into again (i.e. the later code will be invoked and
// users will get notifications when the parent changes).
- var isInScenePlaced = IsSceneObject.HasValue && IsSceneObject.Value;
- if (transform.parent != null && !removeParent && !m_LatestParent.HasValue && isInScenePlaced)
+ if (transform.parent != null && !removeParent && !m_LatestParent.HasValue && InScenePlaced)
{
var parentNetworkObject = transform.parent.GetComponent();
@@ -2544,8 +2748,8 @@ internal bool ApplyNetworkParenting(bool removeParent = false, bool ignoreNotSpa
m_CachedWorldPositionStays = false;
return true;
}
- else // If the parent still isn't spawned add this to the orphaned children and return false
- if (!parentNetworkObject.IsSpawned)
+ // If the parent still isn't spawned add this to the orphaned children and return false
+ else if (!parentNetworkObject.IsSpawned)
{
OrphanChildren.Add(this);
return false;
@@ -2644,8 +2848,6 @@ internal void InvokeBehaviourNetworkPreSpawn()
internal void InvokeBehaviourNetworkSpawn()
{
- NetworkManagerOwner.SpawnManager.UpdateOwnershipTable(this, OwnerClientId);
-
// Always invoke all InternalOnNetworkSpawn methods on each child NetworkBehaviour
// ** before ** invoking OnNetworkSpawn.
// This assures all NetworkVariables and RPC related tables have been initialized
@@ -2806,17 +3008,31 @@ internal void SynchronizeOwnerNetworkVariables(ulong originalOwnerId, ulong orig
childBehaviour.MarkOwnerReadDirtyAndCheckOwnerWriteIsDirty();
}
+ // If the spawn authority of a distributed authority network topology has invoked a change in ownership,
+ // then we want to invoke the NetworkBehaviourUpdate prior to changing the owner back.
+ if (NetworkManager.DistributedAuthorityMode)
+ {
+ // Force send a state update for all owner read NetworkVariables and any currently dirty
+ // owner write NetworkVariables.
+ NetworkManagerOwner.BehaviourUpdater.NetworkBehaviourUpdate(true);
+ }
+
// Now set the new owner and previous owner identifiers back to their original new values
- // before we run the NetworkBehaviourUpdate. For owner read only permissions this order of
- // operations is **particularly important** as we need to first (above) mark things as dirty
- // from the context of the original owner and then second (below) we need to send the messages
- // which requires the new owner to be set for owner read permission NetworkVariables.
+ // after we run the NetworkBehaviourUpdate.
OwnerClientId = currentOwnerId;
PreviousOwnerId = originalOwnerId;
- // Force send a state update for all owner read NetworkVariables and any currently dirty
- // owner write NetworkVariables.
- NetworkManagerOwner.BehaviourUpdater.NetworkBehaviourUpdate(true);
+ // For owner read only permissions this order of operations is **particularly important** as
+ // we need to first (above) mark things as dirty from the context of the original owner and
+ // then second (below) we need to send the messages which requires the new owner to be set.
+ // Note: Owner read only NetworkVariables do not make sense in a distributed authority topology
+ // since the only instance that can write is the owner.
+ if (!NetworkManager.DistributedAuthorityMode)
+ {
+ // Force send a state update for all owner read NetworkVariables and any currently dirty
+ // owner write NetworkVariables.
+ NetworkManagerOwner.BehaviourUpdater.NetworkBehaviourUpdate(true);
+ }
}
// NGO currently guarantees that the client will receive spawn data for all objects in one network tick.
@@ -3262,7 +3478,12 @@ internal void SynchronizeNetworkBehaviours(ref BufferSerializer serializer
}
}
- internal SerializedObject Serialize(ulong targetClientId = NetworkManager.ServerClientId, bool syncObservers = false)
+ ///
+ /// Creates a on an authority client.
+ /// Used to synchronize state to a non-authority client.
+ ///
+ /// This function is the authority mirror of
+ internal SerializedObject SerializeSpawnedObject(ulong targetClientId = NetworkManager.ServerClientId, bool syncObservers = false)
{
var obj = new SerializedObject
{
@@ -3271,7 +3492,7 @@ internal SerializedObject Serialize(ulong targetClientId = NetworkManager.Server
NetworkObjectId = NetworkObjectId,
OwnerClientId = OwnerClientId,
IsPlayerObject = IsPlayerObject,
- IsSceneObject = IsSceneObject ?? true,
+ IsSceneObject = InScenePlaced,
DestroyWithScene = DestroyWithScene,
DontDestroyWithOwner = DontDestroyWithOwner,
HasOwnershipFlags = NetworkManagerOwner.DistributedAuthorityMode,
@@ -3337,25 +3558,23 @@ internal SerializedObject Serialize(ulong targetClientId = NetworkManager.Server
}
///
- /// Used to deserialize a serialized which occurs
- /// when the client is approved or during a scene transition
+ /// Does a non-authority local spawn of a given .
+ /// This occurs when the client is approved, a new object is spawned by an authority, or during a scene transition.
///
- /// Deserialized scene object data
- /// FastBufferReader for the NetworkVariable data
- /// NetworkManager instance
+ /// This function is the non-authority mirror of
+ /// Deserialized data received from the authority for this
+ /// FastBufferReader for any additional data sent with this object on spawn.
+ /// NetworkManager instance.
/// will be true if invoked by CreateObjectMessage
/// The deserialized NetworkObject or null if deserialization failed
- internal static NetworkObject Deserialize(in SerializedObject serializedObject, FastBufferReader reader, NetworkManager networkManager, bool invokedByMessage = false)
+ [return: MaybeNull]
+ internal static NetworkObject DeserializeAndSpawnObject(in SerializedObject serializedObject, FastBufferReader reader, NetworkManager networkManager, bool invokedByMessage = false)
{
var endOfSynchronizationData = reader.Position + serializedObject.SynchronizationDataSize;
if (serializedObject.NetworkObjectId == default)
{
- if (networkManager.LogLevel <= LogLevel.Error)
- {
- NetworkLog.LogErrorServer($"[{nameof(GlobalObjectIdHash)}={serializedObject.Hash}] Received spawn request with invalid {nameof(NetworkObjectId)} {serializedObject.NetworkObjectId}. This should not happen!");
- }
-
+ NetworkLog.LogErrorServer(new Context(LogLevel.Error, $"Received spawn request with invalid {nameof(NetworkObjectId)}. This should not happen!").AddInfo(nameof(NetworkObjectId), serializedObject.NetworkObjectId).AddInfo(nameof(GlobalObjectIdHash), serializedObject.Hash));
reader.Seek(endOfSynchronizationData);
return null;
}
@@ -3372,7 +3591,8 @@ internal static NetworkObject Deserialize(in SerializedObject serializedObject,
{
if (networkManager.LogLevel <= LogLevel.Normal)
{
- NetworkLog.LogWarning($"[{networkObject.name}][Deserialize][{nameof(NetworkBehaviour)}Synchronization][Size mismatch] Expected: {endOfSynchronizationData} Currently At: {reader.Position}!");
+ var networkObjectName = networkObject != null ? networkObject.name : "null";
+ NetworkLog.LogWarning($"[{networkObjectName}][Deserialize][{nameof(NetworkBehaviour)}Synchronization][Size mismatch] Expected: {endOfSynchronizationData} Currently At: {reader.Position}!");
}
reader.Seek(endOfSynchronizationData);
}
@@ -3446,34 +3666,18 @@ internal static NetworkObject Deserialize(in SerializedObject serializedObject,
return networkObject;
}
- ///
- /// Subscribes to changes in the currently active scene
- ///
- ///
- /// Only for dynamically spawned NetworkObjects
- ///
- internal void SubscribeToActiveSceneForSynch()
- {
- if (ActiveSceneSynchronization)
- {
- if (IsSceneObject.HasValue && !IsSceneObject.Value)
- {
- // Just in case it is a recycled NetworkObject, unsubscribe first
- SceneManager.activeSceneChanged -= CurrentlyActiveSceneChanged;
- SceneManager.activeSceneChanged += CurrentlyActiveSceneChanged;
- }
- }
- }
-
///
/// If AutoSynchActiveScene is enabled, then this is the callback that handles updating
/// a NetworkObject's scene information.
///
+ ///
+ /// Should only be used for dynamically spawned NetworkObjects
+ ///
private void CurrentlyActiveSceneChanged(Scene current, Scene next)
{
// Early exit if the NetworkObject is not spawned, is an in-scene placed NetworkObject,
// or the NetworkManager is shutting down.
- if (!IsSpawned || IsSceneObject != false || NetworkManagerOwner.ShutdownInProgress)
+ if (!IsSpawned || NetworkManagerOwner.ShutdownInProgress || InScenePlaced)
{
return;
}
@@ -3483,7 +3687,7 @@ private void CurrentlyActiveSceneChanged(Scene current, Scene next)
{
// Only dynamically spawned NetworkObjects that are not already in the newly assigned active scene will migrate
// and update their scene handles
- if (IsSceneObject.HasValue && !IsSceneObject.Value && gameObject.scene != next && gameObject.transform.parent == null)
+ if (gameObject.scene != next && gameObject.transform.parent == null)
{
SceneManager.MoveGameObjectToScene(gameObject, next);
SceneChangedUpdate(next);
@@ -3502,20 +3706,20 @@ internal void SceneChangedUpdate(Scene scene, bool notify = false)
return;
}
+ // Don't create notification if there is a scene event in progress.
if (NetworkManagerOwner.SceneManager.IsSceneEventInProgress())
{
return;
}
- var isAuthority = HasAuthority;
SceneOriginHandle = scene.handle;
// non-authority needs to update the NetworkSceneHandle
- if (!isAuthority && NetworkManagerOwner.SceneManager.ClientSceneHandleToServerSceneHandle.ContainsKey(SceneOriginHandle))
+ if (!m_HasAuthority && NetworkManagerOwner.SceneManager.ClientSceneHandleToServerSceneHandle.ContainsKey(SceneOriginHandle))
{
NetworkSceneHandle = NetworkManagerOwner.SceneManager.ClientSceneHandleToServerSceneHandle[SceneOriginHandle];
}
- else if (isAuthority)
+ else if (m_HasAuthority)
{
// Since the authority is the source of truth for the NetworkSceneHandle,
// the NetworkSceneHandle is the same as the SceneOriginHandle.
@@ -3528,8 +3732,8 @@ internal void SceneChangedUpdate(Scene scene, bool notify = false)
NetworkSceneHandle = SceneOriginHandle;
}
}
- else // Otherwise, the client did not find the client to server scene handle
- if (NetworkManagerOwner.LogLevel <= LogLevel.Developer)
+ // Otherwise, the client did not find the client to server scene handle
+ else if (NetworkManagerOwner.LogLevel <= LogLevel.Developer)
{
// There could be a scenario where a user has some client-local scene loaded that they migrate the NetworkObject
// into, but that scenario seemed very edge case and under most instances a user should be notified that this
@@ -3542,17 +3746,13 @@ internal void SceneChangedUpdate(Scene scene, bool notify = false)
OnMigratedToNewScene?.Invoke();
// Only the authority side will notify clients of non-parented NetworkObject scene changes
- if (isAuthority && notify && !transform.parent)
+ if (m_HasAuthority && notify && !transform.parent)
{
NetworkManagerOwner.SceneManager.NotifyNetworkObjectSceneChanged(this);
}
}
- private void Awake()
- {
- SetCachedParent(transform.parent);
- SceneOrigin = gameObject.scene;
- }
+
///
/// Update
@@ -3571,7 +3771,7 @@ internal bool UpdateForSceneChanges()
// the NetworkManager is shutting down, the NetworkObject is not spawned, it is an in-scene placed
// NetworkObject, or the GameObject's current scene handle is the same as the SceneOriginHandle
if (!SceneMigrationSynchronization || !IsSpawned || NetworkManagerOwner.ShutdownInProgress ||
- !NetworkManagerOwner.NetworkConfig.EnableSceneManagement || IsSceneObject != false || !gameObject)
+ !NetworkManagerOwner.NetworkConfig.EnableSceneManagement || InScenePlaced || !gameObject)
{
// Stop checking for a scene migration
return false;
@@ -3606,7 +3806,7 @@ internal uint CheckForGlobalObjectIdHashOverride()
// If scene management is disabled and this is an in-scene placed NetworkObject then go ahead
// and send the InScenePlacedSourcePrefab's GlobalObjectIdHash value (i.e. what to dynamically spawn)
- if (!networkManager.NetworkConfig.EnableSceneManagement && IsSceneObject.Value && InScenePlacedSourceGlobalObjectIdHash != 0)
+ if (!networkManager.NetworkConfig.EnableSceneManagement && InScenePlaced && InScenePlacedSourceGlobalObjectIdHash != 0)
{
return InScenePlacedSourceGlobalObjectIdHash;
}
@@ -3614,7 +3814,7 @@ internal uint CheckForGlobalObjectIdHashOverride()
// If the PrefabGlobalObjectIdHash is a non-zero value and the GlobalObjectIdHash value is
// different from the PrefabGlobalObjectIdHash value, then the NetworkObject instance is
// an override for the original network prefab (i.e. PrefabGlobalObjectIdHash)
- if (!IsSceneObject.Value && GlobalObjectIdHash != PrefabGlobalObjectIdHash)
+ if (!InScenePlaced && GlobalObjectIdHash != PrefabGlobalObjectIdHash)
{
// If the PrefabGlobalObjectIdHash is already populated (i.e. InstantiateAndSpawn used), then return this
if (PrefabGlobalObjectIdHash != 0)
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkUpdateLoop.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkUpdateLoop.cs
index c48dea0333..5ac60e2cd4 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkUpdateLoop.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkUpdateLoop.cs
@@ -70,19 +70,19 @@ public enum NetworkUpdateStage : byte
///
public static class NetworkUpdateLoop
{
- private static Dictionary> s_UpdateSystem_Sets;
- private static Dictionary s_UpdateSystem_Arrays;
- private const int k_UpdateSystem_InitialArrayCapacity = 1024;
+ private static Dictionary> s_UpdateSystemSets;
+ private static Dictionary s_UpdateSystemArrays;
+ private const int k_UpdateSystemInitialArrayCapacity = 1024;
static NetworkUpdateLoop()
{
- s_UpdateSystem_Sets = new Dictionary>();
- s_UpdateSystem_Arrays = new Dictionary();
+ s_UpdateSystemSets = new Dictionary>();
+ s_UpdateSystemArrays = new Dictionary();
foreach (NetworkUpdateStage updateStage in Enum.GetValues(typeof(NetworkUpdateStage)))
{
- s_UpdateSystem_Sets.Add(updateStage, new HashSet());
- s_UpdateSystem_Arrays.Add(updateStage, new INetworkUpdateSystem[k_UpdateSystem_InitialArrayCapacity]);
+ s_UpdateSystemSets.Add(updateStage, new HashSet());
+ s_UpdateSystemArrays.Add(updateStage, new INetworkUpdateSystem[k_UpdateSystemInitialArrayCapacity]);
}
}
@@ -105,19 +105,19 @@ public static void RegisterAllNetworkUpdates(this INetworkUpdateSystem updateSys
/// The being registered for the implementation
public static void RegisterNetworkUpdate(this INetworkUpdateSystem updateSystem, NetworkUpdateStage updateStage = NetworkUpdateStage.Update)
{
- var sysSet = s_UpdateSystem_Sets[updateStage];
+ var sysSet = s_UpdateSystemSets[updateStage];
if (!sysSet.Contains(updateSystem))
{
sysSet.Add(updateSystem);
int setLen = sysSet.Count;
- var sysArr = s_UpdateSystem_Arrays[updateStage];
+ var sysArr = s_UpdateSystemArrays[updateStage];
int arrLen = sysArr.Length;
if (setLen > arrLen)
{
// double capacity
- sysArr = s_UpdateSystem_Arrays[updateStage] = new INetworkUpdateSystem[arrLen *= 2];
+ sysArr = s_UpdateSystemArrays[updateStage] = new INetworkUpdateSystem[arrLen *= 2];
}
sysSet.CopyTo(sysArr);
@@ -149,13 +149,13 @@ public static void UnregisterAllNetworkUpdates(this INetworkUpdateSystem updateS
/// The to be deregistered from the implementation
public static void UnregisterNetworkUpdate(this INetworkUpdateSystem updateSystem, NetworkUpdateStage updateStage = NetworkUpdateStage.Update)
{
- var sysSet = s_UpdateSystem_Sets[updateStage];
+ var sysSet = s_UpdateSystemSets[updateStage];
if (sysSet.Contains(updateSystem))
{
sysSet.Remove(updateSystem);
int setLen = sysSet.Count;
- var sysArr = s_UpdateSystem_Arrays[updateStage];
+ var sysArr = s_UpdateSystemArrays[updateStage];
int arrLen = sysArr.Length;
sysSet.CopyTo(sysArr);
@@ -177,7 +177,7 @@ internal static void RunNetworkUpdateStage(NetworkUpdateStage updateStage)
{
UpdateStage = updateStage;
- var sysArr = s_UpdateSystem_Arrays[updateStage];
+ var sysArr = s_UpdateSystemArrays[updateStage];
int arrLen = sysArr.Length;
for (int curIdx = 0; curIdx < arrLen; curIdx++)
{
@@ -291,6 +291,17 @@ public static PlayerLoopSystem CreateLoopSystem()
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void Initialize()
{
+#if UNITY_EDITOR
+ // Reset statics
+ s_UpdateSystemSets = new Dictionary>();
+ s_UpdateSystemArrays = new Dictionary();
+ foreach (NetworkUpdateStage updateStage in Enum.GetValues(typeof(NetworkUpdateStage)))
+ {
+ s_UpdateSystemSets.Add(updateStage, new HashSet());
+ s_UpdateSystemArrays.Add(updateStage, new INetworkUpdateSystem[k_UpdateSystemInitialArrayCapacity]);
+ }
+ UpdateStage = default;
+#endif
UnregisterLoopSystems();
RegisterLoopSystems();
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Logging/ContextualLogger.cs b/com.unity.netcode.gameobjects/Runtime/Logging/ContextualLogger.cs
index 006f919ce1..3141a2a3bf 100644
--- a/com.unity.netcode.gameobjects/Runtime/Logging/ContextualLogger.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Logging/ContextualLogger.cs
@@ -60,7 +60,7 @@ public ContextualLogger(Object inspectorObject, [NotNull] NetworkManager network
}
/// Used for the NetworkLog
- internal ContextualLogger(NetworkManager networkManager, bool useCompatibilityMode)
+ internal ContextualLogger(NetworkManager networkManager, bool useCompatibilityMode = false)
{
m_UseCompatibilityMode = useCompatibilityMode;
m_ManagerContext = new LogContextNetworkManager(networkManager);
@@ -89,7 +89,7 @@ internal DisposableContext AddDisposableInfo(string key, object value)
[Conditional(k_CompilationCondition)]
internal void RemoveInfo(string key)
{
- m_LoggerContext.ClearInfo(key);
+ m_LoggerContext.RemoveInfo(key);
}
[HideInCallstack]
@@ -125,6 +125,19 @@ public void Exception(Exception exception)
{
Debug.unityLogger.LogException(exception, m_Object);
}
+ [HideInCallstack]
+ public void Exception(Exception exception, Context context)
+ {
+ // Don't act if the LogLevel is higher than the level of this log
+ if (m_ManagerContext.LogLevel > context.Level)
+ {
+ return;
+ }
+
+ var message = BuildLog(context);
+ Debug.unityLogger.LogException(new Exception(message, exception), context.RelevantObjectOverride ?? m_Object);
+ }
+
[HideInCallstack]
private void Log(LogType logType, Context context)
diff --git a/com.unity.netcode.gameobjects/Runtime/Logging/LogBuilder.cs b/com.unity.netcode.gameobjects/Runtime/Logging/LogBuilder.cs
index 0c59e10bd4..c8f8c1ba25 100644
--- a/com.unity.netcode.gameobjects/Runtime/Logging/LogBuilder.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Logging/LogBuilder.cs
@@ -31,6 +31,7 @@ public void AppendInfo(object key, object value)
}
public void Append(string value) => m_Builder.Append(value);
+ public void AppendLine(string value) => m_Builder.AppendLine(value);
public string Build() => m_Builder.ToString();
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Logging/LogContext.cs b/com.unity.netcode.gameobjects/Runtime/Logging/LogContext.cs
deleted file mode 100644
index 8c6cbd0bf1..0000000000
--- a/com.unity.netcode.gameobjects/Runtime/Logging/LogContext.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-using System.Runtime.CompilerServices;
-using Object = UnityEngine.Object;
-
-namespace Unity.Netcode.Logging
-{
- internal interface ILogContext
- {
- public void AppendTo(LogBuilder builder)
- {
- }
- }
-
- internal struct Context : ILogContext
- {
- public readonly LogLevel Level;
- private readonly string m_CallingFunction;
- internal readonly string Message;
- internal Object RelevantObjectOverride;
-
- private readonly GenericContext m_Other;
-
- public Context(LogLevel level, string msg, [CallerMemberName] string memberName = "")
- {
- Level = level;
- Message = msg;
- m_CallingFunction = memberName;
-
- m_Other = GenericContext.Create();
- RelevantObjectOverride = null;
- }
-
- internal Context(LogLevel level, string msg, bool noCaller)
- {
- Level = level;
- Message = msg;
- m_CallingFunction = null;
-
- m_Other = GenericContext.Create();
- RelevantObjectOverride = null;
- }
-
- public void AppendTo(LogBuilder builder)
- {
- // [CallingFunction]
- if (!string.IsNullOrEmpty(m_CallingFunction))
- {
- builder.AppendTag(m_CallingFunction);
- }
-
- // [SomeContext][SomeName:SomeValue]
- m_Other.AppendTo(builder);
-
- // Human-readable log message
- builder.Append(" ");
- builder.Append(Message);
- }
-
- public Context AddInfo(object key, object value)
- {
- m_Other.StoreInfo(key, value);
- return this;
- }
-
- public Context AddTag(string msg)
- {
- m_Other.StoreTag(msg);
- return this;
- }
-
- public Context AddObject(Object obj)
- {
- RelevantObjectOverride = obj;
- return this;
- }
- }
-}
diff --git a/com.unity.netcode.gameobjects/Runtime/Logging/LogContext.meta b/com.unity.netcode.gameobjects/Runtime/Logging/LogContext.meta
new file mode 100644
index 0000000000..7c7f21c305
--- /dev/null
+++ b/com.unity.netcode.gameobjects/Runtime/Logging/LogContext.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 1a57adef9bcf4768866c1e922dff4ad1
+timeCreated: 1779217887
\ No newline at end of file
diff --git a/com.unity.netcode.gameobjects/Runtime/Logging/LogContext/CollectionContext.cs b/com.unity.netcode.gameobjects/Runtime/Logging/LogContext/CollectionContext.cs
new file mode 100644
index 0000000000..70c493950d
--- /dev/null
+++ b/com.unity.netcode.gameobjects/Runtime/Logging/LogContext/CollectionContext.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+
+namespace Unity.Netcode.Logging
+{
+ internal delegate string LogCollectionBuilder(TItem item);
+ internal readonly struct CollectionContext : ILogContext
+ {
+ private readonly LogCollectionBuilder m_Delegate;
+ private readonly IEnumerable m_Collection;
+
+ public CollectionContext(IEnumerable collection, LogCollectionBuilder builder)
+ {
+ m_Delegate = builder;
+ m_Collection = collection;
+ }
+
+ public void AppendTo(LogBuilder builder)
+ {
+ foreach (var item in m_Collection)
+ {
+ builder.AppendLine(m_Delegate(item));
+ }
+ }
+ }
+}
diff --git a/com.unity.netcode.gameobjects/Runtime/Logging/LogContext/CollectionContext.cs.meta b/com.unity.netcode.gameobjects/Runtime/Logging/LogContext/CollectionContext.cs.meta
new file mode 100644
index 0000000000..5323a6eda2
--- /dev/null
+++ b/com.unity.netcode.gameobjects/Runtime/Logging/LogContext/CollectionContext.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: f64de1e86c70433e96280f0c8af6e8f6
+timeCreated: 1779214517
\ No newline at end of file
diff --git a/com.unity.netcode.gameobjects/Runtime/Logging/GenericContext.cs b/com.unity.netcode.gameobjects/Runtime/Logging/LogContext/GenericContext.cs
similarity index 78%
rename from com.unity.netcode.gameobjects/Runtime/Logging/GenericContext.cs
rename to com.unity.netcode.gameobjects/Runtime/Logging/LogContext/GenericContext.cs
index 47d198f447..643ec30324 100644
--- a/com.unity.netcode.gameobjects/Runtime/Logging/GenericContext.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Logging/LogContext/GenericContext.cs
@@ -5,20 +5,20 @@ namespace Unity.Netcode.Logging
{
internal readonly struct GenericContext : ILogContext, IDisposable
{
- private readonly List m_Contexts;
+ private readonly List m_Tags;
private readonly Dictionary